盡管 USB 本身所屬設備驅動的結構與其不掛在 USB 總線上時完全相同,但是在訪問方式上卻發生了很大的變化,例如,對於字符設備而言,盡管仍然是 write()、read()、ioctl()這些函數,但是在這些函數中,與 USB 設備通信時不再是 I/O 內存和 I/O 端口的訪問,而是URB 即USB 請求塊。
USB 請求塊(USB request block,urb)是 USB 設備驅動中用來描述與 USB 設備通信所用的基本載體和核心數據結構,非常類似於網絡設備驅動中的 sk_buff 結構體。
1 urb結構體
定義位於:include\linux\usb.h
1 struct urb { 2 /* private: usb core and host controller only fields in the urb */ 3 struct kref kref; /*urb 引用計數 */ 4 void *hcpriv; /* 主機控制器私有數據 */ 5 atomic_t use_count; /* 當前提交的總數*/ 6 atomic_t reject; /* submissions will fail */ 7 int unlinked; /* unlink error code */ 8 9 /* public: documented fields in the urb that can be used by drivers */ 10 struct list_head urb_list; /* urb鏈表頭 11 * current owner */ 12 struct list_head anchor_list; /* the URB may be anchored */ 13 struct usb_anchor *anchor; 14 struct usb_device *dev; /*關聯的 USB 設備 */ 15 struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */ 16 unsigned int pipe; /* 管道 */ 17 unsigned int stream_id; /* (in) stream ID */ 18 int status; /* urb的狀態 */ 19 unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ 20 void *transfer_buffer; /*發送數據到設備或從設備接收數據的緩沖區*/ 21 dma_addr_t transfer_dma; /* 用來以 DMA 方式向設備傳輸數據的緩沖區*/ 22 struct scatterlist *sg; /* (in) scatter gather buffer list */ 23 int num_mapped_sgs; /* (internal) mapped sg entries */ 24 int num_sgs; /* (in) number of entries in the sg list */ 25 u32 transfer_buffer_length; /* transfer_buffer 或 transfer_dma 指向緩沖區的大小 */ 26 u32 actual_length; /*URB 結束后,發送或接收數據的實際長度 */ 27 unsigned char *setup_packet; /*指向控制 URB 的設置數據包的指針*/ 28 dma_addr_t setup_dma; /*控制 URB 的設置數據包的 DMA 緩沖區*/ 29 int start_frame; /* 等時傳輸中用於設置或返回初始幀 */ 30 int number_of_packets; /* 等時傳輸中等時緩沖區數據 */ 31 int interval; /*URB 被輪詢到的時間間隔(對中斷和等時 urb 有效)*/ 32 int error_count; /* 等時傳輸錯誤數量 */ 33 void *context; /* completion 函數上下文 */ 34 usb_complete_t complete; /*當 URB 被完全傳輸或發生錯誤時,被調用 */ 35 struct usb_iso_packet_descriptor iso_frame_desc[0]; 36 /*單個 URB 一次可定義多個等時傳輸時,描述各個等時傳輸 */ 37 }
當 transfer_flags 標志中的 URB_NO_TRANSFER_DMA_MAP 被置位時,USB 核心將使用 transfer_dma指向的緩沖區而非 transfer_buffer指向的緩沖區,意味着即將傳輸 DMA緩沖區。
當 transfer_flags 標志中的 URB_NO_SETUP_DMA_MAP 被置位時,對於有 DMA緩沖區的控制 urb而言,USB核心將使用 setup_dma指向的緩沖區而非 setup_packet指向的緩沖區。
2 URB處理流程
USB 設備中的每個端點都處理一個 urb 隊列。
一個 urb 的典型生命周期如下:
(1)被一個 USB 設備驅動創建。
(2)初始化,被安排給一個特定 USB 設備的特定端點。
(3)被 USB 設備驅動提交給 USB 核心。
(4)提交由 USB 核心指定的 USB 主機控制器驅動。
(5)被 USB 主機控制器處理,進行一次到 USB 設備的傳送。
第(4)~(5)步由 USB 核心和主機控制器完成,不受 USB 設備驅動的控制。
(6)當 urb 完成,USB 主機控制器驅動通知 USB 設備驅動。
3 urb的創建函數usb_alloc_urb
定義位於:drivers\usb\core\urb.c
1 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) 2 { 3 struct urb *urb; 4 5 urb = kmalloc(sizeof(struct urb) + 6 iso_packets * sizeof(struct usb_iso_packet_descriptor),//分配urb 7 mem_flags); 8 if (!urb) { 9 printk(KERN_ERR "alloc_urb: kmalloc failed\n"); 10 return NULL; 11 } 12 usb_init_urb(urb); 13 return urb; 14 }
3.1 函數usb_init_urb
初始化urb中部分成員
1 void usb_init_urb(struct urb *urb) 2 { 3 if (urb) { 4 memset(urb, 0, sizeof(*urb)); 5 kref_init(&urb->kref);//初始化urb的引用計數 6 INIT_LIST_HEAD(&urb->anchor_list);//初始化鏈表 7 } 8 }
iso_packets 是這個 urb 應當包含的等時數據包的數目,若為 0 表示不創建等時數據包。mem_flags 參數是分配內存的標志,和 kmalloc()函數的分配標志參數含義相同。如果分配成功,該函數返回一個 urb 結構體指針,否則返回 0。
urb 結構體在驅動中不能靜態創建,因為這可能破壞 USB 核心給 urb 使用的引用計數方法。
釋放由 usb_alloc_urb()分配的 urb 結構體時用函數void usb_free_urb(struct urb *urb)。
4 urb的初始化
定義位於:\include\linux\usb.h
4.1 中斷 urb
對於中斷 urb,使用usb_fill_int_urb()函數來初始化 urb。
1 static inline void usb_fill_int_urb(struct urb *urb, 2 struct usb_device *dev, 3 unsigned int pipe, 4 void *transfer_buffer, 5 int buffer_length, 6 usb_complete_t complete_fn, 7 void *context, 8 int interval) 9 { 10 urb->dev = dev; 11 urb->pipe = pipe; 12 urb->transfer_buffer = transfer_buffer; 13 urb->transfer_buffer_length = buffer_length; 14 urb->complete = complete_fn; 15 urb->context = context; 16 if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) 17 urb->interval = 1 << (interval - 1); 18 else 19 urb->interval = interval; 20 urb->start_frame = -1; 21 }
urb 參數指向要被初始化的 urb 的指針;
dev 指向這個 urb 要被發送到的 USB 設備;
pipe是這個 urb要被發送到的 USB設備的特定端點;
transfer_buffer是指向發送數據或接收數據的緩沖區的指針,和 urb一樣,它也不能是靜態緩沖區,必須使用 kmalloc()來分配;
buffer_length是 transfer_buffer指針所指向緩沖區的大小;
complete指針指向當這個 urb完成時被調用的完成處理函數;
context是完成處理函數的“上下文”;
interval是這個 urb應當被調度的間隔。
(int)pipe的創建:使用usb_sndintpipe()或 usb_rcvintpipe()函數
4.2 批量urb
對於批量urb,使用 usb_fill_bulk_urb()函數來初始化 urb。
1 static inline void usb_fill_bulk_urb(struct urb *urb, 2 struct usb_device *dev, 3 unsigned int pipe, 4 void *transfer_buffer, 5 int buffer_length, 6 usb_complete_t complete_fn, 7 void *context) 8 { 9 urb->dev = dev; 10 urb->pipe = pipe; 11 urb->transfer_buffer = transfer_buffer; 12 urb->transfer_buffer_length = buffer_length; 13 urb->complete = complete_fn; 14 urb->context = context; 15 }
沒有interval參數,(bulk) pipe的創建:使用 usb_sndbulkpipe()或者 usb_rcvbulkpipe()函數。
4.3 等時urb
對於等時urb,只能手動地初始化urb,而后提交給USB核心。
1 實例(from drivers/usb/media/usbvideo.c) 2 for (i = 0; i < USBVIDEO_NUMSBUF; i++) 3 { 4 int j, k; 5 struct urb *urb = uvd->sbuf[i].urb; 6 urb->dev = dev; 7 urb->context = uvd; 8 urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); 9 urb->interval = 1; 10 urb->transfer_flags = URB_ISO_ASAP; /*urb 被調度*/ 11 urb->transfer_buffer = uvd->sbuf[i].data;/*傳輸 buffer*/ 12 urb->complete = usbvideo_IsocIrq; /* 完成函數 */ 13 urb->number_of_packets = FRAMES_PER_DESC; /*urb 中的等時傳輸數量*/ 14 urb->transfer_buffer_length = uvd->iso_packet_len *FRAMES_PER_DESC; 15 16 for (j = k = 0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) 17 18 { 19 urb->iso_frame_desc[j].offset = k; 20 urb->iso_frame_desc[j].length = uvd->iso_packet_len; 21 } 22 23 }
5 urb的提交
提交給usb核心。定義位於:drivers\usb\core\urb.c
如果 usb_submit_urb()調用成功,即urb 的控制權被移交給 USB 核心,該函數返回 0;否則,返回錯誤號。在提交 urb 到 USB 核心后,直到完成函數被調用之前,不要訪問 urb 中的任何成員。
1 int usb_submit_urb(struct urb *urb, gfp_t mem_flags) 2 { 3 int xfertype, max; 4 struct usb_device *dev; 5 struct usb_host_endpoint *ep; 6 int is_out; 7 8 if (!urb || !urb->complete) 9 return -EINVAL; 10 if (urb->hcpriv) { 11 WARN_ONCE(1, "URB %p submitted while active\n", urb); 12 return -EBUSY; 13 } 14 15 dev = urb->dev; 16 if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) 17 return -ENODEV; 18 19 /* For now, get the endpoint from the pipe. Eventually drivers 20 * will be required to set urb->ep directly and we will eliminate 21 * urb->pipe. 22 */ 23 ep = usb_pipe_endpoint(dev, urb->pipe); 24 if (!ep) 25 return -ENOENT; 26 27 urb->ep = ep; 28 urb->status = -EINPROGRESS; 29 urb->actual_length = 0; 30 31 /* Lots of sanity checks, so HCDs can rely on clean data 32 * and don't need to duplicate tests 33 */ 34 xfertype = usb_endpoint_type(&ep->desc); 35 if (xfertype == USB_ENDPOINT_XFER_CONTROL) { 36 struct usb_ctrlrequest *setup = 37 (struct usb_ctrlrequest *) urb->setup_packet; 38 39 if (!setup) 40 return -ENOEXEC; 41 is_out = !(setup->bRequestType & USB_DIR_IN) || 42 !setup->wLength; 43 } else { 44 is_out = usb_endpoint_dir_out(&ep->desc); 45 } 46 47 /* Clear the internal flags and cache the direction for later use */ 48 urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE | 49 URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL | 50 URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL | 51 URB_DMA_SG_COMBINED); 52 urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN); 53 54 if (xfertype != USB_ENDPOINT_XFER_CONTROL && 55 dev->state < USB_STATE_CONFIGURED) 56 return -ENODEV; 57 58 max = usb_endpoint_maxp(&ep->desc); 59 if (max <= 0) { 60 dev_dbg(&dev->dev, 61 "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", 62 usb_endpoint_num(&ep->desc), is_out ? "out" : "in", 63 __func__, max); 64 return -EMSGSIZE; 65 } 66 67 /* periodic transfers limit size per frame/uframe, 68 * but drivers only control those sizes for ISO. 69 * while we're checking, initialize return status. 70 */ 71 if (xfertype == USB_ENDPOINT_XFER_ISOC) { 72 int n, len; 73 74 /* SuperSpeed isoc endpoints have up to 16 bursts of up to 75 * 3 packets each 76 */ 77 if (dev->speed == USB_SPEED_SUPER) { 78 int burst = 1 + ep->ss_ep_comp.bMaxBurst; 79 int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes); 80 max *= burst; 81 max *= mult; 82 } 83 84 /* "high bandwidth" mode, 1-3 packets/uframe? */ 85 if (dev->speed == USB_SPEED_HIGH) { 86 int mult = 1 + ((max >> 11) & 0x03); 87 max &= 0x07ff; 88 max *= mult; 89 } 90 91 if (urb->number_of_packets <= 0) 92 return -EINVAL; 93 for (n = 0; n < urb->number_of_packets; n++) { 94 len = urb->iso_frame_desc[n].length; 95 if (len < 0 || len > max) 96 return -EMSGSIZE; 97 urb->iso_frame_desc[n].status = -EXDEV; 98 urb->iso_frame_desc[n].actual_length = 0; 99 } 100 } 101 102 /* the I/O buffer must be mapped/unmapped, except when length=0 */ 103 if (urb->transfer_buffer_length > INT_MAX) 104 return -EMSGSIZE; 105 106 #ifdef DEBUG 107 /* stuff that drivers shouldn't do, but which shouldn't 108 * cause problems in HCDs if they get it wrong. 109 */ 110 { 111 unsigned int allowed; 112 static int pipetypes[4] = { 113 PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT 114 }; 115 116 /* Check that the pipe's type matches the endpoint's type */ 117 if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) 118 dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", 119 usb_pipetype(urb->pipe), pipetypes[xfertype]); 120 121 /* Check against a simple/standard policy */ 122 allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK | 123 URB_FREE_BUFFER); 124 switch (xfertype) { 125 case USB_ENDPOINT_XFER_BULK: 126 if (is_out) 127 allowed |= URB_ZERO_PACKET; 128 /* FALLTHROUGH */ 129 case USB_ENDPOINT_XFER_CONTROL: 130 allowed |= URB_NO_FSBR; /* only affects UHCI */ 131 /* FALLTHROUGH */ 132 default: /* all non-iso endpoints */ 133 if (!is_out) 134 allowed |= URB_SHORT_NOT_OK; 135 break; 136 case USB_ENDPOINT_XFER_ISOC: 137 allowed |= URB_ISO_ASAP; 138 break; 139 } 140 allowed &= urb->transfer_flags; 141 142 /* warn if submitter gave bogus flags */ 143 if (allowed != urb->transfer_flags) 144 dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n", 145 urb->transfer_flags, allowed); 146 } 147 #endif 148 /* 149 * Force periodic transfer intervals to be legal values that are 150 * a power of two (so HCDs don't need to). 151 * 152 * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC 153 * supports different values... this uses EHCI/UHCI defaults (and 154 * EHCI can use smaller non-default values). 155 */ 156 switch (xfertype) { 157 case USB_ENDPOINT_XFER_ISOC: 158 case USB_ENDPOINT_XFER_INT: 159 /* too small? */ 160 switch (dev->speed) { 161 case USB_SPEED_WIRELESS: 162 if (urb->interval < 6) 163 return -EINVAL; 164 break; 165 default: 166 if (urb->interval <= 0) 167 return -EINVAL; 168 break; 169 } 170 /* too big? */ 171 switch (dev->speed) { 172 case USB_SPEED_SUPER: /* units are 125us */ 173 /* Handle up to 2^(16-1) microframes */ 174 if (urb->interval > (1 << 15)) 175 return -EINVAL; 176 max = 1 << 15; 177 break; 178 case USB_SPEED_WIRELESS: 179 if (urb->interval > 16) 180 return -EINVAL; 181 break; 182 case USB_SPEED_HIGH: /* units are microframes */ 183 /* NOTE usb handles 2^15 */ 184 if (urb->interval > (1024 * 8)) 185 urb->interval = 1024 * 8; 186 max = 1024 * 8; 187 break; 188 case USB_SPEED_FULL: /* units are frames/msec */ 189 case USB_SPEED_LOW: 190 if (xfertype == USB_ENDPOINT_XFER_INT) { 191 if (urb->interval > 255) 192 return -EINVAL; 193 /* NOTE ohci only handles up to 32 */ 194 max = 128; 195 } else { 196 if (urb->interval > 1024) 197 urb->interval = 1024; 198 /* NOTE usb and ohci handle up to 2^15 */ 199 max = 1024; 200 } 201 break; 202 default: 203 return -EINVAL; 204 } 205 if (dev->speed != USB_SPEED_WIRELESS) { 206 /* Round down to a power of 2, no more than max */ 207 urb->interval = min(max, 1 << ilog2(urb->interval)); 208 } 209 } 210 211 return usb_hcd_submit_urb(urb, mem_flags); 212 }
usb_submit_urb()在原子上下文和進程上下文中都可以被調用,mem_flags 變量需根據調用環境進行相應的設置,如下所示:
GFP_ATOMIC:在中斷處理函數、底半部、tasklet、定時器處理函數以及 urb
完成函數中,在調用者持有自旋鎖或者讀寫鎖時以及當驅動將 current->state修改為非 TASK_ RUNNING時,應使用此標志。
GFP_NOIO:在存儲設備的塊 I/O 和錯誤處理路徑中,應使用此標志。
GFP_KERNEL:如果沒有任何理由使用 GFP_ATOMIC 和 GFP_NOIO,就使
用 GFP_ KERNEL。
USB核心:提交由 USB 核心指定的 USB 主機控制器驅動
USB 主機控制器:進行一次到 USB 設備的傳送
當 urb 完成,USB 主機控制器驅動通知 USB 設備驅動。
以下情況下,urb完成函數將被調用
(1)urb 被成功發送給設備,並且設備返回正確的確認。如果urb->status 為 0,意味着對於一個輸出 urb,數據被成功發送;對於一個輸入urb,請求的數據被成功收到。
(2)如果發送數據到設備或從設備接收數據時發生了錯誤,urb->status 將記錄錯誤值。
(3)urb 被從 USB 核心“去除連接”,這發生在驅動通過 usb_unlink_urb()或usb_kill_urb()函數取消 urb,或 urb雖已提交,而 USB 設備被拔出的情況下。
對 usb_unlink_urb() 而 言,如 果 urb 結 構 體中的URB_ASYNC_UNLINK(即異步 unlink)的標志被置位,則對該 urb 的 usb_unlink_urb()調用將立即返回,具體的 unlink 動作將在后台進行。否則,此函數一直等到 urb 被解開鏈接或結束時才返回。
usb_kill_urb()會徹底終止 urb 的生命周期,它通常在設備的disconnect()函數中被調用。
當 urb生命結束時(處理完成或被解除鏈接),通過 urb結構體的 status成員可以獲知其原因,如 0表示傳輸成功,-ENOENT 表示被 usb_kill_urb()殺死,-ECONNRESET表示被 usb_unlink_urb()殺死, -EPROTO 表示傳輸中發生了 bitstuff錯誤或者硬件未能及時收到響應數據包,-ENODEV 表示 USB設備已被移除,-EXDEV 表示等時傳輸僅完成了一部分等。
簡單的批量與控制 URB
(1)usb_bulk_msg()函數
(2)usb_control_msg()函數
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
usb_bulk_msg()函數創建一個 USB 批量 urb 並將它發送到特定設備,這個函數是同步的,它一直等待 urb 完成后才返回。
usb_dev 參數為批量消息要發送的 USB 設備的指針,pipe 為批量消息要發送到的USB設備的端點,data參數為指向要發送或接收的數據緩沖區的指針,len參數為 data參數所指向的緩沖區的長度,actual_length用於返回實際發送或接收的字節數,timeout是發送超時,以 jiffies為單位,0意味着永遠等待。如果函數調用成功,返回 0;否則,返回1 個負的錯誤值。
int usb_control_msg(struct usb_device *dev, unsigned int pipe, _ _u8 request, _ _u8 requesttype, _ _u16 value, _ _u16 index, void *data, _ _u16 size, int timeout);
dev 指向控制消息發往的 USB 設備,pipe 是控制消息要發往的 USB 設備的端點,request 是這個控制消息的 USB 請求值,requesttype 是這個控制消息的 USB 請求類型,value 是這個控制消息的 USB 消息值,index 是這個控制消息的 USB 消息索引值,data指向要發送或接收的數據緩沖區,size 是 data 參數所指向的緩沖區的大小,timeout是發送超時,以 jiffies 為單位,0 意味着永遠等待。參數 request、requesttype、value 和 index 與 USB 規范中定義的 USB 控制消息直接對應。
如果函數調用成功,該函數返回發送到設備或從設備接收到的字節數;否則,返回一個負的錯誤值.
對 usb_bulk_msg()和 usb_control_msg()函數的使用要特別慎重,它們是同步的,因此不能在中斷上下文和持有自旋鎖的情況下使用。而且,該函數也不能被任何其他函數取消,因此,務必要使得驅動程序的 disconnect()函數掌握足夠的信息,以判斷和等待該調用的結束。
參考博文:https://blog.csdn.net/Blazar/java/article/details/79129210