urb分析,usb_fill_bulk_urb函數理解

usb request block,簡稱urb。事實上,可以打一個這樣的比喻,usb總線就像一條高速公路,貨物、人流之類的可以看成是系統與設備交互的數據,而urb就可以看成是汽車。在一開始對USB規範細節的介紹,我們就說過USBendpoint4種不同類型,也就是說能在這條高速公路上流動的數據就有四種。但是這對汽車是沒有要求的,所以urb可以運載四種數據,不過你要先告訴司機你要運什麼,目的地是什麼。我們現在就看看struct urb的具體內容。它的內容很多,爲了不讓我的理解誤導各位,大家最好還是看一看內核源碼的註釋,具體內容參見源碼樹下include/linux/usb.h
int status
     當一個urb把數據送到設備時,這個urb會由系統返回給驅動程序,並調用驅動程序的urb完成回調函數處理。這時,status記錄了這次數據傳輸的有關狀態,例如傳送成功與否。成功的話會是0。(urb->status)
   要能夠運貨當然首先要有車,所以第一步當然要創建urb
    struct urb *usb_alloc_urb(int isoc_packets, int mem_flags);
     第一個參數是等時包的數量,如果不是乘載等時包,應該爲0,第二個參數與kmalloc的標誌相同。
    參考:http://lxr.free-electrons.com/source/drivers/usb/core/urb.c#L301
    usb_alloc_urb函數實現分析:http://blog.csdn.net/fudan_abc/article/details/1825017
  1. 48 /** 
  2. 49  * usb_alloc_urb - creates a new urb for a USB driver to use 
  3. 50  * @iso_packets: number of iso packets for this urb 
  4. 51  * @mem_flags: the type of memory to allocate, see kmalloc() for a list of 
  5. 52  *      valid options for this. 
  6. 53  * 
  7. 54  * Creates an urb for the USB driver to use, initializes a few internal 
  8. 55  * structures, incrementes the usage counter, and returns a pointer to it. 
  9. 56  * 
  10. 57  * If no memory is available, NULL is returned. 
  11. 58  * 
  12. 59  * If the driver want to use this urb for interrupt, control, or bulk 
  13. 60  * endpoints, pass '' as the number of iso packets. 
  14. 61  * 
  15. 62  * The driver must call usb_free_urb() when it is finished with the urb. 
  16. 63  */  
  17. 64 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)  
  18. 65 {  
  19. 66         struct urb *urb;  
  20. 67   
  21. 68         urb = kmalloc(sizeof(struct urb) +  
  22. 69                 iso_packets * sizeof(struct usb_iso_packet_descriptor),  
  23. 70                 mem_flags);  
  24. 71         if (!urb) {  
  25. 72                 printk(KERN_ERR "alloc_urb: kmalloc failed\n");  
  26. 73                 return NULL;  
  27. 74         }  
  28. 75         usb_init_urb(urb);  
  29. 76         return urb;  
  30. 77 }  
     要釋放一個urb可以用:
       void usb_free_urb(struct urb *urb);
     要承載數據,還要告訴司機目的地信息跟要運的貨物,對於不同的數據,系統提供了不同的函數。
對於中斷
urb,我們用
    void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
                   void *transfer_buffer, int buffer_length,
                   usb_complete_t complete, void *context, int interval);
     這裏要解釋一下,transfer_buffer是一個要送/收的數據的緩衝,buffer_length是它的長度,completeurb完成回調函數的入口context由用戶定義,可能會在回調函數中使用的數據,interval就是urb被調度的間隔。
     對於批量urb和控制urb,我們用:
    void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
                                    void *transfer_buffer, int buffer_length, usb_complete_t complete,
                                   void *context);
    void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
                                    unsigned char* setup_packet,void *transfer_buffer,
                    int buffer_length, usb_complete_t complete,void *context);
     控制包有一個特殊參數setup_packet,它指向即將被髮送到端點的設置數據報的數據。
     其中,usb_fill_bulk_urb()定義於include/linux/usb.h:
  1. /** 
  2.  * usb_fill_bulk_urb - macro to help initialize a bulk urb 
  3.  * @urb: pointer to the urb to initialize. 
  4.  * @dev: pointer to the struct usb_device for this urb. 
  5.  * @pipe: the endpoint pipe 
  6.  * @transfer_buffer: pointer to the transfer buffer 
  7.  * @buffer_length: length of the transfer buffer 
  8.  * @complete_fn: pointer to the usb_complete_t function 
  9.  * @context: what to set the urb context to. 
  10.  * 
  11.  * Initializes a bulk urb with the proper information needed to submit it 
  12.  * to a device. 
  13.  */  
  14. static inline void usb_fill_bulk_urb(struct urb *urb,  
  15.                      struct usb_device *dev,  
  16.                      unsigned int pipe,  
  17.                      void *transfer_buffer,  
  18.                      int buffer_length,  
  19.                      usb_complete_t complete_fn,  
  20.                      void *context)  
  21. {  
  22.     urb->dev = dev;  
  23.     urb->pipe = pipe;  
  24.     urb->transfer_buffer = transfer_buffer;  
  25.     urb->transfer_buffer_length = buffer_length;  
  26.     urb->complete = complete_fn;  
  27.     urb->context = context;  
  28. }  

    urb參數指向要被初始化的urb的指針;

    dev指向這個urb要被髮送到哪個USB設備,即目標設備;

    pipe是這個urb要被髮送到的USB設備的特定端點,pipe使用usb_sndbulkpipe()或者usb_rcvbulkpipe()函數來創建。

  1. unsigned int pipe  
  2.      一個管道號碼,該管道記錄了目標設備的端點以及管道的類型。每個管道只有一種類型和一個方向,它與他的目標設備的端點相對應,我們可以通過以下幾個函數來獲得管道號並設置管道類型:  
  3.      unsigned int usb_sndctrlpipe(struct usb_device *dev, unsigned int endpoint)  
  4.            把指定USB設備的指定端點設置爲一個控制OUT端點。  
  5.      unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int endpoint)  
  6.            把指定USB設備的指定端點設置爲一個控制IN端點。  
  7.      unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int endpoint)  
  8.            把指定USB設備的指定端點設置爲一個批量OUT端點。 /* <span style="font-family:宋體;">把數據從批量</span><span style="font-family:Times New Roman;">OUT</span><span style="font-family:宋體;">端口發出 </span><span style="font-family:Times New Roman;"&gt;*/</span>  
  9.      unsigned int usb_rcvbulkpipe(struct usb_device *dev, unsigned int endpoint)  
  10.            把指定USB設備的指定端點設置爲一個批量IN端點。  
  11.      unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int endpoint)  
  12.          把指定USB設備的指定端點設置爲一箇中斷OUT端點。  
  13.      unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int endpoint)  
  14.            把指定USB設備的指定端點設置爲一箇中斷IN端點。  
  15.      unsigned int usb_sndisocpipe(struct usb_device *dev, unsigned int endpoint)  
  16.            把指定USB設備的指定端點設置爲一個等時OUT端點。  
  17.      unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int endpoint)  
  18.            把指定USB設備的指定端點設置爲一個等時IN端點。   

    transfer_buffer是指向發送數據或接收數據的緩衝區的指針,和urb一樣,它也不能是靜態緩衝區,必須使用kmalloc()來分配;

    buffer_length是transfer_buffer指針所指向緩衝區的大小;

    complete指針指向當這個 urb完成時被調用的完成處理函數;

    context是完成處理函數的“上下文”;

    函數主要完成:初始化urb,被安排給一個特定USB設備的特定端點。然後可通過函數usb_submit_urb()提交給usb核心。

詳細可參考:http://book.51cto.com/art/200803/66930.htm

有了汽車,有了司機,下一步就是要開始運貨了,我們可以用下面的函數來提交urb
    int usb_submit_urb(struct urb *urb, int mem_flags);
    mem_flags有幾種:GFP_ATOMICGFP_NOIOGFP_KERNEL,通常在中斷上下文環境我們會用GFP_ATOMIC
    當我們的卡車運貨之後,系統會把它調回來,並調用urb完成回調函數,並把這輛車作爲函數傳遞給驅動程序。我們應該在回調函數裏面檢查status字段,以確定數據的成功傳輸與否。下面是用urb來傳送數據的細節。
  1. /* initialize the urb properly */  
  2. usb_fill_bulk_urb(urb, dev->udev,  
  3.                     usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),  
  4.                    buf, writesize, skel_write_bulk_callback, dev);  
  5. urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  
  6. /* send the data out the bulk port */  
  7. retval = usb_submit_urb(urb, GFP_KERNEL);   
     這裏skel_write_bulk_callback就是一個完成回調函數,而他做的主要事情就是檢查數據傳輸狀態和釋放urb

  1. /*當urb被成功傳輸到USB設備之後,urb回調函數將被USB核心調用,在我們的例子中,我們初始化urb,使它指向skel_write_bulk_callback函數*/  
  2.   
  3. static void skel_write_bulk_callback(struct urb *urb)  
  4.   
  5. {  
  6.         struct usb_skel *dev;  
  7.         dev = (struct usb_skel *)urb->context;  
  8.   
  9.         /* sync/async unlink faults aren't errors */  
  10.         if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {  
  11.                 err("%s - nonzero write bulk status received: %d",  
  12.                  __FUNCTION__, urb->status);  
  13.         }  
  14.   
  15.         / * free up our allocated buffer */  
  16.         usb_buffer_free(urb->dev, urb->transfer_buffer_length,  
  17.         urb->transfer_buffer, urb->transfer_dma);  
  18.         up(&dev->limit_sem);  
  19. }  

    對於驅動來說,usb_submit_urb是異步的,也就是說不用等傳輸完全完成就返回了,只要usb_submit_urb的返回值表示爲0,就表示已經提交成功了,你的urb已經被core和HCD認可了,接下來core和HCD怎麼處理就是它們的事了,驅動該幹嗎幹嗎去   只要你提交成功了,不管是中間出了差錯還是順利完成,你指定的結束處理函數總是會調用,只有到這個時候,你才能夠重新拿到urb的控制權,檢查它是不是出錯了,需要不需要釋放或者是重新提交。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章