- Linux那些事儿之我是USB
- 肖林甫 肖季东 任桥伟
- 2472字
- 2020-08-27 00:52:24
33.驱动的生命线(三)
现在查看第二阶段的重头戏,查看设备是怎么从Address进入Configured的。1501行,如果已经处于Configured状态了,则退回到Address状态。仔细研究message.c里的usb_disable_device函数。
1034 void usb_disable_device(struct usb_device *dev, int skip_ep0) 1035 { 1036 int i; 1037 1038 dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__, 1039 skip_ep0 ? "non-ep0" : "all"); 1040 for (i = skip_ep0; i < 16; ++i) { 1041 usb_disable_endpoint(dev, i); 1042 usb_disable_endpoint(dev, i + USB_DIR_IN); 1043 } 1044 dev->toggle[0] = dev->toggle[1] = 0; 1045 1046 /* getting rid of interfaces will disconnect 1047 * any drivers bound to them (a key side effect) 1048 */ 1049 if (dev->actconfig) { 1050 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { 1051 struct usb_interface *interface; 1052 1053 /* remove this interface if it has been registered */ 1054 interface = dev->actconfig->interface[i]; 1055 if (!device_is_registered(&interface->dev)) 1056 continue; 1057 dev_dbg (&dev->dev, "unregistering interface %s\n", 1058 interface->dev.bus_id); 1059 usb_remove_sysfs_intf_files(interface); 1060 device_del (&interface->dev); 1061 } 1062 1063 /* Now that the interfaces are unbound, nobody should 1064 * try to access them. 1065 */ 1066 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { 1067 put_device (&dev->actconfig->interface[i]->dev); 1068 dev->actconfig->interface[i] = NULL; 1069 } 1070 dev->actconfig = NULL; 1071 if (dev->state == USB_STATE_CONFIGURED) 1072 usb_set_device_state(dev, USB_STATE_ADDRESS); 1073 } 1074 }
经过研究我们可以发现,usb_disable_device函数的工作主要有两部分:一是将设备中所有端点给删除掉,另一个是将设备当前配置使用的每个接口都从系统里给unregister掉,也就是将接口和它对应的驱动给分开。
先说第二部分的工作,1049行,actconfig表示设备当前激活的配置,只有它不为空时才有接下来清理的必要。
1050行到1061行这个for循环就是将这个配置的每个接口从设备模型的体系中删除掉,将它们和对应的接口驱动分开,没有驱动了,这些接口也就丧失了能力,当然也就什么作用都发挥不了了,这也是名字里那个disable的真正含义所在。
1066行到1070行,将actconfig的interface数组置为空,然后再将actconfig置为空,这里你可能会有的一个疑问,为什么只是置为空,既然要清理actconfig,为什么不直接将它占用的内存给释放掉?你应该注意到actconfig只是一个指针,一个地址,你应该首先弄清楚这个地址里保存的是什么东西再决定是不是将它给释放掉,那这个指针指向哪儿?它指向设备struct usb_device结构的config数组里的其中一项,当前被激活的是哪一个配置,它就指向config数组里的哪一项。你这里只是不想让设备当前激活任何一个配置而已,没必要将actconfig指向的那个配置给释放掉。
那另一个问题就出来了,既然actconfig指向了config里的一项,那为什么要把interface数组给置为空,这不是修改了配置的内容,从而也修改了config数组的内容吗?先别着急,在设备生命线那里取配置描述符,解析返回的那堆数据时,只是把每个配置里的cache数组,也就是intf_cache数组初始化了,并没有为interface数组充实任何的内容,这里做清理工作的目的就是要恢复原状,当然要将它置为空了。那么配置的interface数组又在哪里被充实了呢?在usb_set_configuration函数中第二个高潮阶段之后不是还有个第三个阶段吗,就在那里,激活了哪个配置,就为哪个配置的interface数组,填了点儿东西。
1071行,如果这个设备此时确实是在CONFIGURED状态,就让它回到Address。
现在回头来说说第一部分的清理工作。这个部分主要就是为每个端点调用了usb_disable_endpoint函数,将挂在它们上面的urb取消掉。为什么要这么做?你想一想,能调用到usb_disable_device这个函数,一般来说设备的状态要发生变化了,设备的状态都改变了,那设备的端点状态是不是也要改变?还有挂在它们上面的那些urb需不需要给取消掉?这些是很显然的事情,就拿现在让设备从Configured回到Address来说吧,在Address时,你只能通过默认管道也就是端点0对应的管道与设备进行通信的,但是在“Configured”时,设备的所有端点都是能够使用的,它们上面可能已经挂了一些urb正在处理或者将要处理,那么这时让设备要从CONFIGURED变到ADDRESS,是不是应该先将这些urb取消掉?
参数skip_ep0是什么意思?这里for循环的i从skip_ep0开始算起,也就是说skip_ep0为1的话,就不需要对端点0调用usb_disable_endpoint函数了。按常理来说,设备状态改变了,是需要把每个端点上面的urb取消掉的,这里面当然也要包括端点0。但是写代码的人在这里创建出一个skip_ep0自然有他们的玄机,usb_set_configuration()调用这个函数时参数skip_ep0的值是什么?是1,因为这时候是从Configured回到Address,这个过程中,其他端点是从能够使用变成了不能使用,但端点0却是一直都很强势,虽说是设备发生了状态的变化,但在这两个状态里它都是要正常使用的,所以就没必要disable它了。
什么时候需要disable端点0?在目前版本的内核中我只发现了两种情况,一种是设备要断开时,另一种是设备从Default进化到Address时。虽说不管是Default还是Address,端点0都是需要能够正常使用的,但因为地址发生改变了,毫无疑问,你需要将挂在它上面的urb清除掉。当时讲设备生命线时,在设置完设备地址,设备进入Address后,第二种情况的这个步骤给忽略了,主要是当时也不影响理解,现在既然遇到了,就讲一讲吧。
在设备生命线的过程中,设置完设备地址,让设备进入Address状态后,立马就调用了hub.c里一个名叫ep0_reinit的函数。
2066 static void ep0_reinit(struct usb_device *udev) 2067 { 2068 usb_disable_endpoint(udev, 0 + USB_DIR_IN); 2069 usb_disable_endpoint(udev, 0 + USB_DIR_OUT); 2070 udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; 2071 }
这个函数中只对端点0调用了usb_disable_endpoint(),但是端点0接下来还是要使用的,不然你就取不到设备那些描述符了,所以接着重新将ep0赋给ep_in[0]和ep_out[0]。多说无益,还是到usb_disable_endpoint()里面去查看吧。
987 void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) 988 { 989 unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; 990 struct usb_host_endpoint *ep; 991 992 if (!dev) 993 return; 994 995 if (usb_endpoint_out(epaddr)) { 996 ep = dev->ep_out[epnum]; 997 dev->ep_out[epnum] = NULL; 998 } else { 999 ep = dev->ep_in[epnum]; 1000 dev->ep_in[epnum] = NULL; 1001 } 1002 if (ep && dev->bus) 1003 usb_hcd_endpoint_disable(dev, ep); 1004 }
这个函数先获得端点号和端点的方向,然后从ep_in或ep_out两个数组里取出端点的struct usb_host_endpoint结构体,并将数组里的对应项置为空,要注意的是这里同样不是释放掉数组里对应项的内存而是置为空。这两个数组里的ep_in[0]和ep_out[0]是早就被赋值了,至于剩下的那些项是在什么时候被赋值的,又是指向了什么东西,就是usb_set_configuration函数第三个阶段的事了。
最后1003行调用了一个usb_hcd_endpoint_disable函数,主要的工作还得它来做,不过这已经深入HCD的腹地了,就不多说了,还是回到usb_disable_device()吧。在为每个端点都调用了usb_disable_endpoint()之后,还有一个小步骤要做,就是将设备struct usb_device结构体的toggle数组置为0。至于toggle数组有什么用,为什么要被初始化为0,还是回首到设备那节去看吧。我要直接讲usb_set_configuration()了。
1504行,又一次与usb_control_ msg()相遇了,每当我们需要向设备发送请求时它就会适时出现。
usb_control_ msg这次出现的目的当然是为了SET_CONFIGURATION请求,这里只说它的那堆参数,看如图1.33.1所示的这张表。
图1.33.1 SET_CONFIGURATION请求
SET_CONFIGURATION请求不需要DATA transaction,而且还是协议中规定所有设备都要支持的标准请求,也不是针对端点或者接口,而是针对设备的,所以bRequestType只能为0x80,就是图1.33.1所示的00000000B,也就是1505行的第一个0。wValue表示配置的bConfiguration Value,就是1505行的configuration。
1514行,将激活的配置的地址赋给actconfig。如果cp为空,重新设置设备的状态为Address,并将之前准备的那些struct usb_interface结构体和new_interfaces释放掉,然后返回。看前面的代码,cp有三种可能为空,一种是参数configuration为-1,一种是参数configuration为0,而且从设备的config数组里拿出来的就为空,还有一种是SET_CONFIGURATION清除了问题。不管怎么说,到了1515行,cp还是空的,你就要准备返回了。
1520行,事情在这里发展到了高潮的顶端,设置设备的状态为configured。