URB定义:
usb 请求块(usb request block, urb)是usb设备驱动中用来描述与usb设备通信所用的基本载体和核心数据结构,非常类似于网络设备驱动中的sk_buff结构体,是usb主机与设备通信的电波。
- struct urb {
- /* private: usb core and host controller only fields in the urb */
- struct kref kref; /* URB引用计数 */
- void *hcpriv; /* host控制器的私有数据 */
- atomic_t use_count; /* 当前提交计数 */
- atomic_t reject; /* 提交失败计数 */
- int unlinked; /* 连接失败代码 */
- /* public: documented fields in the urb that can be used by drivers */
- struct list_head urb_list; /* list head for use by the urb's
- * current owner */
- struct list_head anchor_list; /* the URB may be anchored */
- struct usb_anchor *anchor;
- struct usb_device *dev; /* 指向这个 urb 要发送的目标 struct usb_device 的指针,这个变量必须在这个 urb 被发送到 USB 核心之前被 USB 驱动初始化.*/
- struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
- unsigned int pipe;
- int status;
- unsigned int transfer_flags; /* 传输设置*/
- void *transfer_buffer; /* 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区指针。为了主机控制器驱动正确访问这个缓冲, 它必须使用 kmalloc 调用来创建, 不是在堆栈或者静态内存中。 对控制端点, 这个缓冲区用于数据中转*/
- dma_addr_t transfer_dma; /* 用于以 DMA 方式传送数据到 USB 设备的缓冲区*/
- int transfer_buffer_length; /* transfer_buffer 或者 transfer_dma 变量指向的缓冲区大小。如果这是 0, 传送缓冲没有被 USB 核心所使用。对于一个 OUT 端点, 如果这个端点大小比这个变量指定的值小, 对这个 USB 设备的传输将被分成更小的块,以正确地传送数据。这种大的传送以连续的 USB 帧进行。在一个 urb 中提交一个大块数据, 并且使 USB 主机控制器去划分为更小的块, 比以连续地顺序发送小缓冲的速度快得多*/
- int actual_length; /* 当这个 urb 完成后, 该变量被设置为这个 urb (对于 OUT urb)发送或(对于 IN urb)接受数据的真实长度.对于 IN urb, 必须是用此变量而非 transfer_buffer_length , 因为接收的数据可能比整个缓冲小*/
- unsigned char *setup_packet; /* 指向控制urb的设置数据包指针.它在传送缓冲中的数据之前被传送(用于控制 urb)*/
- dma_addr_t setup_dma; /* 控制 urb 用于设置数据包的 DMA 缓冲区地址,它在传送普通缓冲区中的数据之前被传送(用于控制 urb)*/
- int start_frame; /* 设置或返回初始的帧数量(用于等时urb) */
- int number_of_packets;
- int interval;
- int error_count; /* 等时urb的错误计数,由USB核心设置 */
- void *context; /* 指向一个可以被USB驱动模块设置的数据块. 当 urb 被返回到驱动时,可在结束处理例程中使用. */
- usb_complete_t complete; /* 结束处理例程函数指针, 当 urb 被完全传送或发生错误,它将被 USB 核心调用. 此函数检查这个 urb, 并决定释放它或重新提交给另一个传输中*/
- struct usb_iso_packet_descriptor iso_frame_desc[0];
- };
URB 处理流程
1, usb设备驱动程序创建并初始化一个访问特定usb设备特定端点的urb,并提交给usb core
2, usb core提交该urb到usb主控制器驱动程序
3, usb主控制器驱动程序根据urb描述的信息,来访问usb设备
4,当设备访问结束后,usb主控制器驱动程序通知usb core(调用这个函数usb_complete_t complete;)然后其再通知usb设备驱动程序
创建URB
struct urb *usb_alloc_urb(int iso_packets, int mem_flags) 参数:iso_packets: urb 所包含的等时数据包的个数,若不是等时传输,则为0.
mem_flags: 内存分配标识(如GFP_KERNEL),参考kmalloc
不同的传递方式有不同的URB,如:controll, out, in;
初始化URB
对于中断urb,使用usb_fill_int_urb函数来初始化:
static inline void usb_fill_int_urb (struct urb *urb,要初始化的urb指针。
struct usb_device *dev,所要访问的设备
unsigned int pipe,要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建
void *transfer_buffer,要传输的数据缓冲区
int buffer_length,缓冲区长度
usb_complete_t complete_fn,当完成该urb所请求的操作时,要调用的回调函数
void *context,complet_fn函数所需的上下文,通常取值为dev
int interval)urb被调度的时间间隔
管道:驱动程序的数据缓冲区与一个端点的连接,它代表了一种在两者之间移动数据的能力
对于批量urb,使用usb_fill_bulk_urb函数来初始化。
对于控制urb,使用usb_fill_control_urb函数来初始化。
等时urb没有像中断,控制和批量urb那样的初始化函数,我们只能手动的初始化urb。
提交URB
在完成urb的创建和初始化后,urb便可以通过usb_submit_urb函数来提交给usb核心:
int usb_submit_urb(struct urb *urb,gfp_t mem_flags)
参数:
urb:指向urb的指针;
mem_flags:内存分配标识,它用于告知usb核心如何分配内存缓冲区。
处理URB:
URB被提交到USB核心后,usb核心指定usb主控制器驱动程序来处理该urb,在3种情况下,urb会被认为处理完成:
1 urb被成功发送给设备,并且设备返回成功确认。如果urb->status为0,意味着对于一个输出urb,数据被成功发送;对于一个输入urb,请求的数据被成功收到。
2如果发送数据到设备或从设备接受数据时发生了错误,urb->status将记录错误值。
3 urb被“取消”,这发生在驱动通过usb_unlink_urb()或usb_kill_urb()函数取消urb,或urb虽已提交,而usb设备被拔出的情况下
当urb处理完成后,urb完成函数将被调用。