urb数据结构【转】
轉自:http://blog.csdn.net/myarrow/article/details/7025065
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
目錄(?)[-]
?
?
?
?
一、?transfer_flags
/*
?* urb->transfer_flags:
?*
?* Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
?*/
#define URB_SHORT_NOT_OK?0x0001?? /* report short reads as errors */
#define URB_ISO_ASAP??0x0002??????????? /* iso-only, urb->start_frame ignored */
#define URB_NO_TRANSFER_DMA_MAP?0x0004??? /* urb->transfer_dma valid on submit */
#define URB_NO_SETUP_DMA_MAP?0x0008???? /* urb->setup_dma valid on submit */
#define URB_NO_FSBR??0x0020???? ?/* UHCI-specific */
#define URB_ZERO_PACKET??0x0040??? /* Finish bulk OUT with short packet */
#define URB_NO_INTERRUPT?0x0080?? /* HINT: no non-error interrupt? needed */
#define URB_FREE_BUFFER??0x0100?? /* Free transfer buffer with the URB */
#define URB_DIR_IN??0x0200????? ?/* Transfer from device to host */
#define URB_HCD_DRIVER_TEST?0xFFFF?? /* Do NOT hand back or free this URB */
#define URB_DIR_OUT??0
#define URB_DIR_MASK??URB_DIR_IN
?
1. URB_SHORT_NOT_OK
這個標記只對用來從IN 端點讀取數據的urb 有效,意思就是說如果從一個IN 端點那里讀取了一個比較短的數據包,就可以認為是錯誤的。那么這里的
short 究竟short 到什么程度?之前說到端點的時候,就知道端點描述符里有一個叫wMaxPacketSize 這樣的東東,指明了端點一次能夠處理的最大字節數。每個端點描述符里的wMaxPacketSize 所表示的最大字節數都包括了哪些部分?是整個packet的長度么?我可以負責任的告訴你,它只包括了Data 包里面數據字段,俗稱datapayload,其它那些七大姑八大姨什么的都是協議本身需要的信息,和TCP/IP 里的報頭差不多。
wMaxPacketSize 與short 有什么關系? 關系還不小, short 不short 就是與wMaxPacketSize 相比的,如果從IN 端點那兒收到了一個比wMaxPacketSize 要短的包,同時也設置了URB_SHORT_NOT_OK 這個標志,那么就可以認為傳輸出錯了。本來如果收到一個比較短的包是意味著這次傳輸到此為止就結束了,你想想data payload 的長度最
大必須為wMaxPacketSize 這個規定是不可違背的了,但是如果端點想給你的數據不止那么多,怎么辦?就需要分成多個wMaxPacketSize 大小的data payload 來傳輸,事情有時不會那么湊巧,剛好能平分成多個整份,這時,最后一個data payload 的長度就會比wMaxPacketSize 要小,這種情況本來意味著端點已經傳完了它想傳的,釋放完了自己的需求,這次傳輸就該結束了,不過如果你設置了URB_SHORT_NOT_OK 標志,HCD 這邊就會認為錯誤發生了。
?
2. URB_ISO_ASAP
這個標志只是為了方便等時傳輸用的。等時傳輸和中斷傳輸在spec 里都被認為是periodic transfers,也就是周期傳輸,咱們都知道在usb 的世界里都是主機占主導地位,設備是沒多少發言權的,但是對于等時傳輸和中斷傳輸,端點可以對主機表達自己一種美好的期望,希望主機能夠隔多長時間訪問自己一次,這個期望的時間就是這里說的周期。當然,期望與現實是有一段距離的,如果期望的都能成為現實,咱們還研究usb干嗎。端點的這個期望能不能得到滿足,要看主機控制器答應不答應。對于等時傳輸,一般來說也就一幀(微幀)一次,主機那兒也很忙,再多也抽不出空兒來。那么如果你有個用于等時傳輸的urb,你提交給HCD 的時候,就得告訴HCD 它應該從哪一幀開始的,就要對下面要說的那個start_frame 賦值,也就是說告訴HCD 等時傳輸開始的那一幀(微幀)的幀號,如果你留心,應該還會記得前面說過在每幀或微幀(Mircoframe)的開始都會有個SOF Token 包,這個包里就含有個幀號字段,記錄了那一幀的編號。這樣的話,一是比較煩,還要去設置這個start_frame,你說煩不煩,二是到你設置的那一幀的時候,如果主機控制器沒空開始等時傳輸,你說怎么辦,要知道usb 的世界里它可是老大。于是,就出現了URB_ISO_ASAP,它的意思就是告訴HCD 啥時候不忙就啥時候開始,就不用指定什么開始的幀號了,是不是感覺特輕松?所以說,你如果想進行等時傳輸,又不想標新立異的話,就還是把它給設置了吧。
?
3. URB_NO_TRANSFER_DMA_MAP & URB_NO_SETUP_DMA_MAP
這兩個標志都是有關DMA 的,什么是DMA?就是外設,比如咱們的usb 攝像頭,和內存之間直接進行數據交換,把CPU 給撇一邊兒了。
一般來說,都是驅動里提供了kmalloc 等分配的緩沖區,HCD 做一定的DMA 映射處理,DMA 映射是干嗎的?外設和內存之間進行數據交換,總要互相認識吧,外設是通過各種總線連到主機里邊兒的,使用的是總線地址,而內存使用的是虛擬地址,它們之間本來就是兩條互不相交的平行線,要讓它們中間產生連接點,必須得將一個地址轉化為另一個地址,這樣才能找得到對方,才能互通有無,而DMA 映射就是干這個的。為了分擔點HCD 的壓力,于是就有了這里的兩個標志,告訴HCD 不要再自己做DMA 映射了,驅動提供的urb 里已經提供有DMA 緩沖區地址,為領導分憂解難是咱們這些小百姓應該做的事情。具體提供了哪些DMA 緩沖區?就涉及到下面的transfer_buffer,transfer_dma,還有setup_packet,setup_dma 這兩對兒了。
?
4. URB_ZERO_PACKET
這個標志表示批量的OUT 傳輸必須使用一個short packet 來結束。批量傳輸的數據大于批量端點的wMaxPacketSize 時,需要分成多個Data 包來傳輸,最后一個data payload 的長度可能等于wMaxPacketSize,也可能小于,當等于wMaxPacketSize 時,如果同時設置了URB_ZERO_PACKET 標志,就需要再發送一個長度為0 的數據包來結束這次傳輸,如果小于wMaxPacketSize 就沒必要多此一舉了。你要問,當批量傳輸的數據小于wMaxPacketSize 時那?也沒必要再發送0 長的數據包,因為此時發送的這個數據包本身就是一個short packet。
?
5. URB_NO_INTERRUPT
這個標志用來告訴HCD,在URB 完成后,不要請求一個硬件中斷,當然這就意味著你的結束處理函數可能不會在urb 完成后立即被調用,而是在之后的某個時間被調用,咱們的usb core 會保證為每個urb 調用一次結束處理函數。
?
二、transfer_buffer & transfer_dma & transfer_buffer_length
管道的一端是主機上的緩沖區,一端是設備上的端點,這三個家伙就是描述主機上的那個緩沖區的。transfer_buffer 是使用kmalloc 分配的緩沖區,transfer_dma 是使用usb_buffer_alloc分配的dma 緩沖區,HCD 不會同時使用它們兩個,如果你的urb 自帶了transfer_dma,就要同時設置URB_NO_TRANSFER_DMA_MAP 來告訴HCD 一聲,不用它再費心做DMA 映射了。transfer_buffer 是必須要設置的,因為不是所有的主機控制器都能夠使用DMA 的,萬一遇到這樣的情況,也好有個備用。transfer_buffer_length指的就是transfer_buffer 或transfer_dma 的長度。
?
三、setup_packet & setup_dma
同樣是兩個緩沖區,一個是kmalloc分配的,一個是用usb_buffer_alloc分配的,不過,這兩個緩沖區是控制傳輸專用的,記得struct usb_ctrlrequest不?它們保存的就是一個struct usb_ctrlrequest結構體,如果你的urb設置了setup_dma,同樣要設置URB_NO_SETUP_DMA_MAP標志來告訴HCD。如果進行的是控制傳輸,setup_packet是必須要設置的,也是為了防止出現主機控制器不能使用DMA的情況。
?
四、start_frame
如果你沒有指定URB_ISO_ASAP 標志,就必須自己設置start_frame,指定等時傳輸在哪幀或微幀開始。如果指定了URB_ISO_ASAP,urb 結束時會使用這個值返回實際的開始幀號。
?
五、interval
等時和中斷傳輸專用。interval 間隔時間的意思,什么的間隔時間?就是上面說的端點希望主機輪詢自己的時間間隔。這個值和端點描述符里的bInterval 是一樣的,你不能隨便兒的指定一個,協議里對你能指定的值是有范圍限制的,對于中斷傳輸,全速時,這個范圍為1~255ms,低速是為10~255ms,高速時為1~16,這個1~16 只是bInterval 可以取的值,實際的間隔時間需要計算一下,為2 的(bInterval-1)次方乘以125 微妙,也就是2 的(bInterval-1)次方個微幀。對于等時傳輸,沒有低速了,等時傳輸根本就不是低速端點負擔得起的,有多大能耐就做多大事,人有多大膽地有多大產的時代早就已經過去了,對于全速和高速,這個范圍也是為1~16,間隔時間由2 的(bInterval-1)次方算出來,單位為幀或微幀。這樣看來,每一幀或微幀里,你最多只能期望有一次等時和中斷傳輸,不能再多了,你只能期望房價漲的慢點,要是希望它跌下去,那要求就太過分了,它可是經濟的柱子,要是倒了,那不是陷國人的生活于困境么,所以咱們要愛國啊,要送錢給ZF 還有任小強們啊同志們。
??
六、context
驅動設置了給下面的結束處理函數用的。比如可以將自己驅動里描述自己設備的結構體放在里邊兒,在結束處理函數里就可以取出來。
complete
一個指向結束處理函數的指針,傳輸成功完成,或者中間發生錯誤的時候就會調用它,驅動可以在這里邊兒檢查urb 的狀態,并做一些處理,比如可以釋放這個urb,或者重新提交給HCD。就說攝像頭吧,你向HCD 提交了個等時的urb 從攝像頭那里讀取視頻數據,傳輸完成的時候調用了你指定的這個結束處理函數,并在里面取出了urb 里面獲得的數據進行解碼等處理,然后怎么著?總不會這一個urb 讀取的數據就夠你向mm 表白了吧,你的愛慕之情可是猶如滔滔江水連綿不絕,所以需要獲得更多的數據,那你也總不會再去創建、初始化一個等時的urb 吧,即使再窮極無聊的人也不會那么做,明顯剛剛的那個可以繼續用的,只要將它再次提交給HCD 就可以了。這個函數指針的定義在include/linux/usb.h
typedef void (*usb_complete_t)(struct urb *);
【作者】張昺華 【出處】http://www.cnblogs.com/sky-heaven/ 【博客園】 http://www.cnblogs.com/sky-heaven/ 【新浪博客】 http://blog.sina.com.cn/u/2049150530 【知乎】 http://www.zhihu.com/people/zhang-bing-hua 【我的作品---旋轉倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【我的作品---自平衡自動循跡車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【新浪微博】 張昺華--sky 【twitter】 @sky2030_ 【facebook】 張昺華 zhangbinghua 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的urb数据结构【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分片与分区的区别
- 下一篇: [bzoj 1954]Pku3764 T