struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* kref,urb 的引用计数 ,每多一个使用者,它的这个引用计数就加1,
每减少一个使用者,引用计数就减一,如果连最后一个使用者都释放了
这个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
//还记得每个端点都会有的那个urb 队列么?那个队列就是由这里的
//urb_list 一个一个的链接起来的。HCD 每收到一个urb,就会将它添加到这个urb 指定的
//那个端点的urb 队列里去
* current owner 它表示的是urb 要去的那个usb 设备*/
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.
//urb 到达端点之前,需要经过一个通往端点的管道,就是这个pipe。管道有两端,一端是主机上的缓冲区,一端是设备上的端点,既 //然有两端,总要有个方向吧,确定一条管道至少要知道两端的地址、方向和类型了,这个整型值的构成,bit7 用来表示方向,bit8~ //14 表示设备地址,bit15~18 表示端点号,早先说过,设备地址用7 位来表示,端点号用4 位来表示,剩下来的bit30~31 表示管 //道类型。*/
unsigned int stream_id; /* (in) stream ID */
int status; /* (return) non-ISO status //urb 的当前状态*/
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_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 通信都要经历哪些阶段,首先,驱动程序发现自己有与usb 设备通信的需要,于是创建一个urb,并指定它的目的地是设备上的哪个端点,
然后提交给usb core,usb core 将它修修补补的做些美化之后再移交给主机控制器的驱动程序HCD,HCD 会去解析这个urb,了解它的目的是什么,并与usb 设备进行相应的
交流,在交流结束,urb 的目的达到之后,HCD 再把这个urb 的所有权移交回驱动程序.
urb 驱动也创建了,提交也提交了,HCD 正处理着那,可驱动反悔了,它不想再继续这次通信了,想将这个urb 给终止掉。
一种是驱动只想通过usb core 告诉HCD 一声,说这个urb 我想终止掉,您就别费心再处理了,然后它不想在那里等着HCD 的处理,想忙别的事去,这就是俗称的异步,对应的是usb_unlink_urb 函数。当然对应的还有种同步的,驱动会在那里苦苦等候着HCD 的处理结果,等待着urb 被终止,对应的是usb_kill_urb 函数。而HCD 将这次通信终止后,同样会将urb 的所有权移交回驱动。那么驱动通过什么判断HCD 已经终止了这次通信?就是通过这里的use_count,驱动会在usb_kill_urb
里面一直等待着这个值变为0。
在include/linux/kref.h 里定义
struct kref {
atomic_t refcount;
};
void kref_init(struct kref *kref)
{
atomic_set(&kref->refcount, 1);
smp_mb();
}
void usb_init_urb(struct urb *urb)
{
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
struct urb *usb_get_urb(struct urb *urb)
{
if (urb)
kref_get(&urb->kref);
return urb;
}
void usb_free_urb(struct urb *urb)
{
if (urb)
kref_put(&urb->kref, urb_destroy);
}
usb_init_urb、usb_get_urb、usb_free_urb 这三个函数分别调用了前面看到的structkref 结构的三个操作函数来进行引用计数的初始化、加1、减一.
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref); //先调用了to_urb,实际上就是一个container_of 来获得引用计数关联的那个urb,然后使用kfree 将它销毁。
if (urb->transfer_flags & URB_FREE_BUFFER)
kfree(urb->transfer_buffer);
kfree(urb);
}
void usb_kill_urb(struct urb *urb)
{
might_sleep();//因为usb_kill_urb函数要一直等候着HCD将urb终止掉,它必须是可以休眠的
if (!(urb && urb->dev && urb->ep))//这里就是判断一下urb,urb 要去的那个设备,还有那个设备在的总线有没有,如
//果哪个不存在,就还是返回吧。
return;
atomic_inc(&urb->reject);
usb_hcd_unlink_urb(urb, -ENOENT);//里告诉HCD驱动要终止这个urb了,usb_hcd_unlink_urb函数也只是告诉HCD
//一声,然后不管HCD怎么处理就返回了
//上面的usb_hcd_unlink_urb是返回了,但并不代表HCD已经将urb给终止了,
//HCD可能没那么快,所以这里usb_kill_urb要休息休息,等人通知它。这里使用了
//wait_event宏来实现休眠
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
atomic_dec(&urb->reject);
}