Linux那些事儿 之 戏说USB(32)驱动的生命线(四)

来源:互联网 发布:windows bitlocke解密r 编辑:程序博客网 时间:2024/05/17 22:05
设备自从有了Address,拿到了各种描述符,就在那儿看usb_generic_driver忙活了,不过还算没白忙,设备总算是幸福的进入Configured了。
Address有点像你合几代人之力辛辛苦苦才弄到的一套新房子,你还得想办法去装修它,Configured就像是已经装修好的,下面咱就看看usb_generic_driver又对设备做了些什么。
109行,nintf就是配置里接口的数目,那么这个for循环显然就是在对配置里的每个接口做处理。
114行,这里要明白的是,cp里的两个数组interface和intf_cache,一个是没有初始化的,一个是已经动过手术很饱满的。正像前面提到的,这里需要为interface动手术,拿intf_cache的内容去充实它。
120行,获得这个接口的0号设置。咱们已经知道,因为某些厂商有特殊的癖好,导致了struct usb_host_config结构里的数组interface并不一定是按照接口号的顺序存储的,你必须使用usb_ifnum_to_if 来获得指定接口号对应的struct usb_interface结构体。现在咱们需要再多知道一点,接口里的altsetting数组也不一定是按照设置编号来顺序存储的,你必须使用usb_altnum_to_altsetting()来获得接口里的指定设置。它在drivers/usb/core/usb.c里定义()
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,unsigned int altnum){int i;for (i = 0; i < intf->num_altsetting; i++) {if (intf->altsetting[i].desc.bAlternateSetting == altnum)return &intf->altsetting[i];}return NULL;}
这个函数依靠一个for循环来解决问题,就是轮询接口里的每个设置,比较它们的编号与你指定的编号是不是一样。原理简单,操作也简单,有点不简单的是前面调用它的时候为什么指定编号0,也就是获得0号设置。这还要归咎于spec里说了这么一句,接口的默认设置总是0号设置,所以这里的目的就是获得接口的默认设置,如果没有拿到设置0,接下来就在128行拿altsetting数组里的第一项来充数。
132行,指定刚刚拿到的设置为当前要使用的设置。
133行,前边儿遇到过device和endpoint的disable函数,这里遇到个interface的enable函数,同样在message.c里定义

这个函数同样也是靠一个for循环来解决问题,轮询前面获得的那个接口设置使用到的每个端点,调用message.c里的usb_enable_endpoint()将它们统统enable。
void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,bool reset_ep){int epnum = usb_endpoint_num(&ep->desc);int is_out = usb_endpoint_dir_out(&ep->desc);int is_control = usb_endpoint_xfer_control(&ep->desc);if (reset_ep)usb_hcd_reset_endpoint(dev, ep);if (is_out || is_control)dev->ep_out[epnum] = ep;if (!is_out || is_control)dev->ep_in[epnum] = ep;ep->enabled = 1;}
这个函数的前边儿几行没什么好说的,分别获得端点地址,端点号,还有是不是控制端点。稍微有那么点嚼头儿的是后面的两个if,它们分别根据端点的方向来初始化设备的ep_in和ep_out数组。
现在看看为什么两个if语句里都出现有is_control。控制传输使用的是message管道,message管道必须对应两个相同号码的端点,一个用来in,一个用来out。这里使用两个if,而不是if-else组合,目的就是塞进去一个is_control,表示只要是控制端点,就将它的端点号对应的IN和OUT两个方向上的toggle位还有ep_int和ep_out都给初始化了。当然,所谓的控制端点一般也就是指端点0。
endpoint的enable函数要比disable函数清爽的多,disable的时候还要深入到HCD的腹地去撤销挂在它上面的各个urb,而enable的时候就是简单设置一下toggle位还有那两个数组就好了,要知道它的urb队列urb_list是早在从设备那里获取配置描述符并去解析那一大堆数据的时候就初始化好了的。enable之后,接口里的各个端点便都处于了欣欣向荣的可用状态,你就可以在驱动里向指定的端点提交urb了。当然,到目前这个时候接口还仍然是接口,驱动(接口驱动)还仍然是驱动,它们中间还缺少那根著名的红线。
然后看看跟在usb_enable_interface()后面的那几行,接口所属的总线类型仍然为usb_bus_type,设备类型变为usb_if_device_type,dma_mask被设置为你的设备的dma_mask,而你设备的dma_mask很早以前就被设置为了host controller的dma_mask。
142行,device_initialize在初始化设备struct usb_device结构体的时候遇到过一次,这里初始化接口的时候又遇到了。
148行,for循环结束了,new_interfaces的历史使命也就结束了。我想你应该会明白的是,这里的kfree释放的只是new_interfaces指针数组的内存,而不包括它里面各个指针所指向的内存,至于那些数据,都已经在前面被赋给配置里的interface数组了。
179行,获得配置的字符串描述符,怎么获得?先飘过去把剩下的说了再说它。
194行,这个for循环结束,usb_set_configuration()的三个阶段也就算结束了,设备和大美女usb_generic_driver上上下下忙活了这么久也都很累了,接下来就该接口和接口驱动去忙活了。
这个for循环将前面那个for循环准备好的每个接口送给设备模型,Linux设备模型会根据总线类型usb_bus_type将接口添加到usb总线的那条有名的设备链表里,然后去轮询usb总线的另外一条有名的驱动链表,针对每个找到的驱动去调用usb总线的match函数,也就是usb_device_match,去为接口寻找另一个匹配的半圆。你说这个时候设备和接口两条路它应该走哪条?它的类型已经设置成usb_if_device_type了,设备那条路把门儿的根本就不会让它进,所以它必须得去走接口那条路。
0 0