尽管 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