(1)
“urb”,全称USB Request Block。USB设备需要通信,要传递数据,就需要使用urb,确切地说,应该是USB设备驱动程序使用urb。实际上,作为USB设备驱动,它本身并不能直接操纵数据的传输,在USB这个大观园里,外接设备永远都是配角,真正的核心只是USB Core,而真正负责调度的是USB主机控制。这个通常看不见的USB主机控制器芯片,俨然是USB大观园中的大管家。设备驱动要发送信息,所需要做的是建立一个urb数据结构,并把这个数据结构交给核心层,而核心层会为所有设备统一完成调度,而设备在提交了urb之后需要做的,只是等待
“urb”,全称USB Request Block。USB设备需要通信,要传递数据,就需要使用urb,确切地说,应该是USB设备驱动程序使用urb。实际上,作为USB设备驱动,它本身并不能直接操纵数据的传输,在USB这个大观园里,外接设备永远都是配角,真正的核心只是USB Core,而真正负责调度的是USB主机控制。这个通常看不见的USB主机控制器芯片,俨然是USB大观园中的大管家。设备驱动要发送信息,所需要做的是建立一个urb数据结构,并把这个数据结构交给核心层,而核心层会为所有设备统一完成调度,而设备在提交了urb之后需要做的,只是等待
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us)
{
int p;
struct task_struct *th;
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
//等号左边us->current_urb,等号右边usb_alloc_urb()函数被调用。如果说struct us_data是usb mass storage中的主角,那么struct urb将毫无争议地成为整个USB子系统中的主角
if (!us->current_urb) {
usb_stor_dbg(us, "URB allocation failed\n");
return -ENOMEM;
}
/* Just before we start our control thread, initialize
* the device if it needs initialization */
if (us->unusual_dev->initFunction) {
p = us->unusual_dev->initFunction(us);
if (p)
return p;
}
//有些设备需要一些初始化函数,它就定义在unusual_devs.h文件中,而我们通过UNUSUAL_DEV的定义已经把这些初始化函数赋给了us->unusual_dev的initFunction指针了。
/* Start up our control thread */
th = kthread_run(usb_stor_control_thread, us, "usb-storage");
if (IS_ERR(th)) {
dev_warn(&us->pusb_intf->dev,
"Unable to start control thread\n");
return PTR_ERR(th);
}
us->ctl_thread = th;
return 0;
}
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
atomic_t reject; /* submissions will fail */
int unlinked; /* unlink error code */
/* 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; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
unsigned int stream_id; /* (in) stream ID */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
struct scatterlist *sg; /* (in) scatter gather buffer list */
int num_mapped_sgs; /* (internal) mapped sg entries */
int num_sgs; /* (in) number of entries in the sg list */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
int start_frame; /* (modify) start frame (ISO) */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* (modify) transfer interval
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};
一个urb包含了执行USB传输所需要的所有信息。而作为驱动程序,要通信就必须创建这么一个数据结构,并且赋值,显然不同类型的传输,需要对urb赋不同的值,然后将她提交给底层,完了底层的USB Core会找到相应的USB主机控制器,从而具体实现数据的传输。传输完了之后,USB主机控制器会通知设备驱动程序。
调用usb_alloc_urb()申请了一个struct urb结构体。usb_alloc_urb()这个函数,它是USB Core所提供的一个函数,来自drivers/usb/core/urb.c,USB开发人员的确是给足了urb的面子,专门把和这个数据结构相关的代码整理在这么一个文件中了。
extern struct urb *usb_alloc_urb(intiso_packets, gfp_t mem_flags);
//为一个urb结构体申请内存。它有两个参数,其中第一个iso_packets用来在等时传输的方式下指定你需要传输多少个包,对于非等时模式来说,这个参数直接使用0。另一个参数mem_flags就是一个flag,表示申请内存的方式,这个flag将最终传递给kmalloc函数,我们这里传递的是GFP_KERNEL,usb_alloc_urb最终将返回一个urb指针,而us的成员current_urb也是一个struct urb的指针,所以就赋给它了。不过需要记住,usb_alloc_urb除了申请内存以外,还对结构体做了初始化,结构体urb被初始化为0,struct urb中还有一个引用计数,以及一个自旋锁,这些也同样被初始化了
那么设备和主机控制器的分工又是如何呢?在Linux中,设备驱动程序只要为每一次请求准备一个urb结构体变量,把它填充好(就是说赋上该赋的值),然后它调用USB Core提供的函数,把这个urb传递给主机控制器,主机控制器就会把各个设备驱动程序所提交的urb统一规划,去执行每一个操作。而这期间,USB设备驱动程序通常会进入睡眠,而一旦主机控制器把urb要做的事情给做完了,它会调用一个函数去唤醒USB设备驱动程序,然后USB设备驱动程序就可以继续往下走了。