- Linux那些事儿之我是USB
- 肖林甫 肖季东 任桥伟
- 3055字
- 2020-08-27 00:52:23
22.设备的生命线(三)
137行,函数usb_control_ msg调用了usb_internal_control_ msg之后就去一边儿睡大觉,脏活儿累活儿全部留给usb_internal_control_ msg去做了。
71 static int usb_internal_control_ msg(struct usb_device *usb_dev, 72 unsigned int pipe, 73 struct usb_ctrlrequest *cmd, 74 void *data, int len, int timeout) 75 { 76 struct urb *urb; 77 int retv; 78 int length; 79 80 urb = usb_alloc_urb(0, GFP_NOIO); 81 if (!urb) 82 return -ENOMEM; 83 84 usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, 85 len, usb_api_blocking_completion, NULL); 86 87 retv = usb_start_wait_urb(urb, timeout, &length); 88 if (retv < 0) 89 return retv; 90 else 91 return length; 92 }
这个函数粗看过去可以概括为:以一个struct urb结构体为中心,以usb_alloc_urb、usb_fill_control_urb、usb_start_wait_urb三个函数为基本点。
● 一个中心:struct urb结构体,就是前面多次提到又多次忽略的,只闻其名不见其形的传说中的urb,全称usb request block,USB通信靠的就是它了。
● 第一个基本点:usb_alloc_urb函数,创建一个urb,struct urb结构体只能使用它来创建。
● 第二个基本点:usb_fill_control_urb函数,进行初始化控制urb,urb被创建之后,在使用之前必须要正确被初始化。
● 第三个基本点:usb_start_wait_urb函数,将urb提交给USB Core,以便分配给特定的主机控制器驱动进行处理,然后默默地等待处理结果,或者超时。
1126 struct urb 1127 { 1128 /* private: usb core and host controller only fields in the urb */ 1129 struct kref kref; /* reference count of the URB */ 1130 spinlock_t lock; /* lock for the URB */ 1131 void *hcpriv; /* private data for host controller */ 1132 atomic_t use_count; /* concurrent submissions counter */ 1133 u8 reject; /* submissions will fail */ 1134 1135 /* public: documented fields in the urb that can be used by drivers */ 1136 struct list_head urb_list; /* list head for use by the urb's 1137 * current owner */ 1138 struct usb_device *dev; /* (in) pointer to associated device */ 1139 unsigned int pipe; /* (in) pipe information */ 1140 int status; /* (return) non-ISO status */ 1141 unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ 1142 void *transfer_buffer; /* (in) associated data buffer */ 1143 dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ 1144 int transfer_buffer_length; /* (in) data buffer length */ 1145 int actual_length; /* (return) actual transfer length */ 1146 unsigned char *setup_packet;/*(in) setup packet (control only)*/ 1147 dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ 1148 int start_frame; /* (modify) start frame (ISO) */ 1149 int number_of_packets; /* (in) number of ISO packets */ 1150 int interval; /* (modify) transfer interval 1151 * (INT/ISO) */ 1152 int error_count; /* (return) number of ISO errors */ 1153 void *context; /* (in) context for completion */ 1154 usb_complete_t complete; /* (in) completion routine */ 1155 struct usb_iso_packet_descriptor iso_frame_desc[0]; 1156 /* (in) ISO ONLY */ 1157 };
1129行,kref,urb的引用计数。别看它是隐藏在urb内部的一个不起眼的小角色,但小角色做大事情,它决定了一个urb的生死存亡。一个urb有用没用,是继续委以重任还是无情销毁,都要看它的脸色。那为什么urb的生死要掌握在这个小小的引用计数手里?
前面说过,主机与设备之间通过管道来传输数据,管道的一端是主机上的一个缓冲区,另一端是设备上的端点。管道之中流动的数据,在主机控制器和设备看来是一个个packets,在咱们看来就是urb。因而,端点之中就有一个叫urb的队列。不过,这并不代表一个urb只能发配给一个端点,它可能通过不同的管道发配给不同的端点,那么这样一来,我们如何知道这个urb正在被多少个端点使用,如何判断这个urb的生命已经结束?如果没有任何一个端点在使用它,而我们又无法判断这种情况,它就会永远地飘荡在USB的世界里。我们需要寻求某种办法在这种情况下给它们一个好的归宿,这就是引用计数。每多一个使用者,它的引用计数就加1,每减少一个使用者,引用计数就减1,如果连最后一个使用者都释放了这个urb,宣称不再使用它了,那它的生命周期就走到了尽头,会自动销毁。
如何来表示这个神奇的引用计数?其实它是一个struct kref结构体,在include/linux/kref.h中定义。
23 struct kref { 24 atomic_t refcount; 25 };
这个结构与struct urb相比简约到极点了。不过别看它简单,内核中就是使用它来判断一个对象有没有用。它里边儿只包括了一个原子变量,为什么是原子变量?既然都使用引用计数了,那就说明可能同时有多个地方在使用这个对象,总要考虑它们同时修改这个计数的可能性吧,也就是俗称的并发访问,那怎么办?加一个锁?就这么一个整数值专门加一个锁未免也大材小用了,所以就使用了原子变量。围绕这个结构,内核中还定义了几个专门操作引用计数的函数,它们在lib/kref.c中定义。
21 void kref_init(struct kref *kref) 22 { 23 atomic_set(&kref->refcount,1); 24 smp_mb(); 25 } 26 31 void kref_get(struct kref *kref) 32 { 33 WARN_ON(!atomic_read(&kref->refcount)); 34 atomic_inc(&kref->refcount); 35 smp_mb__after_atomic_inc(); 36 } 37 52 int kref_put(struct kref *kref, void (*release)(struct kref *kref)) 53 { 54 WARN_ON(release == NULL); 55 WARN_ON(release == (void (*)(struct kref *))kfree); 56 57 if (atomic_dec_and_test(&kref->refcount)) { 58 release(kref); 59 return 1; 60 } 61 return 0; 62 }
整个kref.c文件就定义了这么三个函数,kref_init初始化,kref_get将引用计数加1,kref_put将引用计数减1并判断是不是为0,如果为0的话就调用参数中release函数指针指向的函数把对象销毁掉。它们对refcount的操作都是通过原子变量特有的操作函数,原子变量当然要使用专门的操作函数了,编译器还能做一些优化,否则直接使用一般的变量就可以了。如果你直接像对待一般整型值一样对待它,编译器也会看不过去你的行为,直接给你一个error。
提醒,kref_init初始化时,是把refcount的值初始化为1,而不是0。还有一点要说的是kref_put参数中的那个函数指针,你不能传递一个NULL过去,否则这个引用计数就只是计数,而背离了最初的目的。要记住,我们需要在这个计数减到为0时将销毁嵌入这个引用计数struct kref结构体的对象,所以这个函数指针也不能为kfree,因为这样就只是把这个struct kref结构体给销毁了,而不是整个对象。
第三个问题,如何使用struct kref结构来为我们的对象计数?当然我们需要把这样一个结构嵌入到你希望计数的对象里,不然你根本无法对对象在它整个生命周期里的使用情况做出判断。但是我们是几乎见不到内核中直接使用上面那几个函数来给对象计数的,而是每种对象又定义了自己专用的引用计数函数,比如这里的urb,在drivers/usb/core/urb.c中定义。
31 void usb_init_urb(struct urb *urb) 32 { 33 if (urb) { 34 me mset(urb, 0, sizeof(*urb)); 35 kref_init(&urb->kref); 36 spin_lock_init(&urb->lock); 37 } 38 } 39 81 void usb_free_urb(struct urb *urb) 82 { 83 if (urb) 84 kref_put(&urb->kref, urb_destroy); 85 } 86 97 struct urb * usb_get_urb(struct urb *urb) 98 { 99 if (urb) 100 kref_get(&urb->kref); 101 return urb; 102 }
usb_init_urb,usb_get_urb,usb_free_urb这三个函数分别调用了前面的struct kref结构的三个操作函数来进行引用计数的初始化、加1、减1。什么叫封装?这就叫封装。usb_free_urb里给kref_put传递的那个函数urb_destroy,它也在urb.c中定义。
9 #define to_urb(d) container_of(d, struct urb, kref) 10 11 static void urb_destroy(struct kref *kref) 12 { 13 struct urb *urb = to_urb(kref); 14 kfree(urb); 15 }
这个urb_destroy函数首先调用了to_urb,实际上就是一个container_of来获得引用计数关联的urb,然后使用kfree函数将它销毁。
回到函数1130行,lock,一把自旋锁。每个urb都有一把自旋锁。
1131行,hcpriv,走到今天,你应该明白这个urb最终还是要提交给主机控制器驱动的,这个字段就是urb里主机控制器驱动的自留地。
1132行,use_count,这里又是一个计数,不过此计数非彼计数,它与上面那个用来追踪urb生命周期的kref一点儿关系也没有。那它是用来做什么的?
先了解使用urb来完成一次完整的USB通信都要经历哪些阶段。首先,驱动程序发现自己有与USB设备通信的需要,于是创建一个urb,并指定它的目的地是设备上的哪个端点,然后提交给USB Core,USB Core将它修修补补进行一些美化之后再移交给主机控制器的驱动程序HCD,HCD会去解析这个urb,了解它的目的是什么,并与USB设备进行相应的交流,在交流结束,urb的目的达到之后,HCD再把这个urb的所有权移交回驱动程序。
这里的use_count就是在USB Core将urb移交给HCD,办理移交手续时,插上了一脚,每当走到这一步,它的值就会加1。什么时候减1?在HCD重新将urb的所有权移交回驱动程序时。只要HCD拥有这个urb的所有权,那么此urb的use_count就不会为0。这么一说,似乎use_count也有一点追踪urb生命周期的味道了,当它的值大于0时,就表示当前有HCD正在处理它,和上面的kref概念上有部分的重叠,不过,显然它们之间是有区别的,没区别的话,这里干吗要用两个计数?
上面的那个kref实现方式是内核中统一的引用计数机制,当计数减为0时,urb对象就被urb_destroy给销毁了。这里的use_count只是用来统计当前这个urb是不是正在被哪个HCD处理,即使它的值为0,也只是说明没有HCD在使用它而已,并不代表就得把它给销毁掉。比方说,HCD利用完了urb,把它还给了驱动,这时驱动还可以对这个urb进行检修,再提交给哪个HCD去使用。
下面的问题就是既然它不会平白无故地多出来,那它究竟是用来干什么的?还要从刚提到的那几个阶段说起。urb驱动也创建了,该提交的也提交了,HCD正处理着,可驱动反悔了,它不想再继续这次通信了,想将这个urb给终止掉,善解人意的USB Core当然会给驱动提供这样的接口来满足这样的需要。不过这个需要被细分为两种方式,一种是驱动只想通过USB Core告诉HCD这个urb想终止掉,不用再处理了,然后它不想在那里等着HCD的处理,想忙别的事去,这就是俗称的“异步”,对应的函数是usb_unlink_urb。当然对应的还有另一种同步,驱动会在那里苦苦等候着HCD的处理结果,等待着urb被终止,对应的函数是usb_kill_urb。而HCD将这次通信终止后,同样会将urb的所有权移交回驱动。那么驱动通过什么判断HCD已经终止了这次通信?就是通过这里的use_count,驱动会在usb_kill_urb里面一直等待着这个值变为0。
1133行,reject,拒绝,拒绝什么?又是被谁拒绝?
在目前版本的内核中,只有usb_kill_urb函数有特权对它进行修改,那么显然reject就与上面说的urb终止有关了。那就看一看drivers/usb/core/urb.c中定义的这个函数。
464 void usb_kill_urb(struct urb *urb) 465 { 466 might_sleep(); 467 if (!(urb && urb->dev && urb->dev->bus)) 468 return; 469 spin_lock_irq(&urb->lock); 470 ++urb->reject; 471 spin_unlock_irq(&urb->lock); 472 473 usb_hcd_unlink_urb(urb, -ENOENT); 474 wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); 475 476 spin_lock_irq(&urb->lock); 477 --urb->reject; 478 spin_unlock_irq(&urb->lock); 479 }
466行,因为usb_kill_urb函数要一直等候着HCD将urb终止掉,它必须是可以休眠的。所以说usb_kill_urb函数不能用于中断上下文,它必须能够休眠将自己占的资源给让出来。
might_sleep函数,用来判断usb_kill_urb函数是不是处在能够休眠的情况,如果不是,就会打印出一大堆的堆栈信息,比如你在中断上下文调用了这个函数时。不过,它也就是基于调试的目的用一用,方便日后找错,并不能强制哪个函数改变自己的上下文。
467行,这里就是判断urb要去的那个设备,还有那个设备现在的总线有没有,如果不存在,还是返回吧。
469行,去获得每个urb都有的那把锁,然后将reject加1。加1有什么用?其实目前版本的内核中只有两个地方用到了这个值进行判断。第一个地方是在USB Core将urb提交给HCD,正在办移交手续时,如果reject大于0,就不再接着移交了,也就是说这个urb被HCD给拒绝了。这是为了防止这边儿正在终止这个urb,那边儿的某个地方却又妄想将这个urb重新提交给HCD。
473行,这里告诉HCD驱动要终止这个urb了,usb_hcd_unlink_urb函数也只是告诉HCD一声,然后不管HCD怎么处理就返回了。
474行,上面的usb_hcd_unlink_urb是返回了,但并不代表HCD已经将urb给终止了,HCD可能没那么快,所以这里usb_kill_urb要休息一下,等人通知它。这里使用了wait_event这个宏来实现休眠,usb_kill_urb_queue是在/drivers/usb/core/hcd.h中定义的一个等待队列,专门给usb_kill_urb休息用的。需要注意的是,这里的唤醒条件use_count必须等于0。
在哪里能唤醒正在睡大觉的usb_kill_urb?这牵扯到了第二个使用reject来做判断的地方。在HCD将urb的所有权返还给驱动时,会对reject进行判断,如果reject大于0,就调用wake_up唤醒在usb_kill_urb_queue上休息的usb_kill_urb。这也好理解,HCD都要将urb的所有权返回给驱动了,那当然就是已经处理完了,放在这里就是已经将这个urb终止了,usb_kill_urb等的就是这一天的到来,当然就要醒过来继续往下走了。
476行,再次获得urb的那把锁,将reject刚才增加的1减掉。urb都已经终止了,也没人再会去拒绝它了。
与usb_kill_urb相比,usb_unlink_urb函数就简单多了。
435 int usb_unlink_urb(struct urb *urb) 436 { 437 if (!urb) 438 return -EINVAL; 439 if (!(urb->dev && urb->dev->bus)) 440 return -ENODEV; 441 return usb_hcd_unlink_urb(urb, -ECONNRESET); 442 }
usb_unlink_urb函数只是把自己的意愿告诉HCD,然后就返回了。
struct urb结构中的前面这几个函数,只是USB Core和主机控制器驱动需要关心的,实际的驱动里根本用不着也管不着,它们就是USB和HCD的后花园,想种点什么不种点什么都由写这块儿代码的人决定,它们在里面怎么为所欲为都不关写驱动的人什么事。USB在linux里起起伏伏这么多年,前边儿的这些内容早就变过多少次,说不定你今天还能看到谁,到接下来的哪天就看不到了,不过,变化的是形式,不变的是道理。
而驱动要做的只是创建一个urb,然后初始化,再把它提交给USB Core就可以了,使用不使用引用计数,加不加锁之类的事都不用去操心。感谢David Brownell,感谢Alan Stern,感谢……没有他们就没有USB在Linux里的今天。