USB Core三

 

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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值