參考:http://lxr.free-electrons.com/source/drivers/usb/core/urb.c#L301
usb_alloc_urb函數實現分析:http://blog.csdn.net/fudan_abc/article/details/1825017
- 48 /**
- 49 * usb_alloc_urb - creates a new urb for a USB driver to use
- 50 * @iso_packets: number of iso packets for this urb
- 51 * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
- 52 * valid options for this.
- 53 *
- 54 * Creates an urb for the USB driver to use, initializes a few internal
- 55 * structures, incrementes the usage counter, and returns a pointer to it.
- 56 *
- 57 * If no memory is available, NULL is returned.
- 58 *
- 59 * If the driver want to use this urb for interrupt, control, or bulk
- 60 * endpoints, pass '' as the number of iso packets.
- 61 *
- 62 * The driver must call usb_free_urb() when it is finished with the urb.
- 63 */
- 64 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
- 65 {
- 66 struct urb *urb;
- 67
- 68 urb = kmalloc(sizeof(struct urb) +
- 69 iso_packets * sizeof(struct usb_iso_packet_descriptor),
- 70 mem_flags);
- 71 if (!urb) {
- 72 printk(KERN_ERR "alloc_urb: kmalloc failed\n");
- 73 return NULL;
- 74 }
- 75 usb_init_urb(urb);
- 76 return urb;
- 77 }
對於中斷urb,我們用
- /**
- * usb_fill_bulk_urb - macro to help initialize a bulk urb
- * @urb: pointer to the urb to initialize.
- * @dev: pointer to the struct usb_device for this urb.
- * @pipe: the endpoint pipe
- * @transfer_buffer: pointer to the transfer buffer
- * @buffer_length: length of the transfer buffer
- * @complete_fn: pointer to the usb_complete_t function
- * @context: what to set the urb context to.
- *
- * Initializes a bulk urb with the proper information needed to submit it
- * to a device.
- */
- static inline 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_fn,
- void *context)
- {
- urb->dev = dev;
- urb->pipe = pipe;
- urb->transfer_buffer = transfer_buffer;
- urb->transfer_buffer_length = buffer_length;
- urb->complete = complete_fn;
- urb->context = context;
- }
urb參數指向要被初始化的urb的指針;
dev指向這個urb要被髮送到哪個USB設備,即目標設備;
pipe是這個urb要被髮送到的USB設備的特定端點,pipe使用usb_sndbulkpipe()或者usb_rcvbulkpipe()函數來創建。
- unsigned int pipe
- 一個管道號碼,該管道記錄了目標設備的端點以及管道的類型。每個管道只有一種類型和一個方向,它與他的目標設備的端點相對應,我們可以通過以下幾個函數來獲得管道號並設置管道類型:
- unsigned int usb_sndctrlpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一個控制OUT端點。
- unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一個控制IN端點。
- unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定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;">*/</span>
- unsigned int usb_rcvbulkpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一個批量IN端點。
- unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一箇中斷OUT端點。
- unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一箇中斷IN端點。
- unsigned int usb_sndisocpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定USB設備的指定端點設置爲一個等時OUT端點。
- unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int endpoint)
- 把指定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- /* initialize the urb properly */
- usb_fill_bulk_urb(urb, dev->udev,
- usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
- buf, writesize, skel_write_bulk_callback, dev);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- /* send the data out the bulk port */
- retval = usb_submit_urb(urb, GFP_KERNEL);
- /*當urb被成功傳輸到USB設備之後,urb回調函數將被USB核心調用,在我們的例子中,我們初始化urb,使它指向skel_write_bulk_callback函數*/
- static void skel_write_bulk_callback(struct urb *urb)
- {
- struct usb_skel *dev;
- dev = (struct usb_skel *)urb->context;
- /* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
- err("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
- }
- / * free up our allocated buffer */
- usb_buffer_free(urb->dev, urb->transfer_buffer_length,
- urb->transfer_buffer, urb->transfer_dma);
- up(&dev->limit_sem);
- }
對於驅動來說,usb_submit_urb是異步的,也就是說不用等傳輸完全完成就返回了,只要usb_submit_urb的返回值表示爲0,就表示已經提交成功了,你的urb已經被core和HCD認可了,接下來core和HCD怎麼處理就是它們的事了,驅動該幹嗎幹嗎去 只要你提交成功了,不管是中間出了差錯還是順利完成,你指定的結束處理函數總是會調用,只有到這個時候,你才能夠重新拿到urb的控制權,檢查它是不是出錯了,需要不需要釋放或者是重新提交。