linux设备驱动(29)usb驱动-urb详解

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

posted @ 2020-07-12 23:01  Action_er  阅读(2100)  评论(0编辑  收藏  举报