`
javatome
  • 浏览: 822643 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

设备自从有了Address,拿到了各种描述符,就在那儿看usb_generic_driver忙活了,不过还算没白忙,设备总算是幸福的进入Configured了。从设备这儿咱们应该学到点幸福生活的秘诀,就是找到你所喜欢的事,然后找到愿意为你来做这件事的人。

Address有点像你合几代人之力辛辛苦苦才弄到的一套新房子,如果不装修,它对你来说的意义也就是你的户口可以从人才中心挪过去了,可以对人说你的地址是哪儿哪儿了,可实际上你在里边儿什么也干不了,你还得想办法去装修它,Configured就像是已经装修好的,装修好了,你和你老婆才能够在里边儿想干做什么就干什么,下面咱就看看usb_generic_driver又对设备做了些什么。
1525行,nintf就是配置里接口的数目,那么这个for循环显然就是在对配置里的每个接口做处理。
1530行,这里要明白的是,cp里的两个数组interface和intf_cache,一个是没有初始化的,一个是已经动过手术很饱满的。正像前面提到的,这里需要为interface动手术,拿intf_cache的内容去充实它。
1536行,获得这个接口的0号设置。咱们已经知道,因为某些厂商有特殊的癖好,导致了struct usb_host_config结构里的数组interface并不一定是按照接口号的顺序存储的,你必须使用usb_ifnum_to_if来获得指定接口号对应的struct usb_interface结构体。现在咱们需要再多知道一点,接口里的altsetting数组也不一定是按照设置编号来顺序存储的,你必须使用usb_altnum_to_altsetting()来获得接口里的指定设置。它在usb.c里定义()
100 /**
101* usb_altnum_to_altsetting - get the altsetting structure with a given
102* alternate setting number.
103* @intf: the interface containing the altsetting in question
104* @altnum: the desired alternate setting number
106* This searches the altsetting array of the specified interface for
107* an entry with the correct bAlternateSetting value and returns a pointer
108* to that entry, or null.
110* Note that altsettings need not be stored sequentially by number, so
111* it would be incorrect to assume that the first altsetting entry in
112* the array corresponds to altsetting zero.This routine helps device
113* drivers avoid such mistakes.
115* Don't call this function unless you are bound to the intf interface
116* or you have locked the device!
117*/
119 unsigned int altnum)
120 {
121 int i;
123 for (i = 0; i < intf->num_altsetting; i++) {
124 if (intf->altsetting[i].desc.bAlternateSetting == altnum)
125 return &intf->altsetting[i];
126 }
127 return NULL;
128 }
这个函数依靠一个for循环来解决问题,就是轮询接口里的每个设置,比较它们的编号与你指定的编号是不是一样。原理简单,操作也简单,有点不简单的是前面调用它的时候为什么指定编号0,也就是获得0号设置。这还要归咎于spec里说了这么一句,接口的默认设置总是0号设置,所以这里的目的就是获得接口的默认设置,如果没有拿到设置0,接下来就在1544行拿altsetting数组里的第一项来充数。范伟说了,没有IP卡,IQ卡也成。
1546行,指定刚刚拿到的设置为当前要使用的设置。
1547行,前边儿遇到过device和endpoint的disable函数,这里遇到个interface的enable函数,同样在message.c里定义
1104 /*
1105* usb_enable_interface - Enable all the endpoints for an interface
1106* @dev: the device whose interface is being enabled
1107* @intf: pointer to the interface descriptor
1109* Enables all the endpoints for the interface's current altsetting.
1112 struct usb_interface *intf)
1114 struct usb_host_interface *alt = intf->cur_altsetting;
1115 int i;
1117 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
这个函数同样也是靠一个for循环来解决问题,轮询前面获得的那个接口设置使用到的每个端点,调用message.c里的usb_enable_endpoint()将它们统统enable。
1077 /*
1078* usb_enable_endpoint - Enable an endpoint for USB communications
1079* @dev: the device whose interface is being enabled
1080* @ep: the endpoint
1082* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
1083* For control endpoints, both the input and output sides are handled.
1085 static void
1088 unsigned int epaddr = ep->desc.bEndpointAddress;
1089 unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
1090 int is_control;
1092 is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1094 if (usb_endpoint_out(epaddr) || is_control) {
1096 dev->ep_out[epnum] = ep;
1098 if (!usb_endpoint_out(epaddr) || is_control) {
1100 dev->ep_in[epnum] = ep;
这个函数的前边儿几行没什么好说的,分别获得端点地址,端点号,还有是不是控制端点。稍微有那么点嚼头儿的是后面的两个if,它们分别根据端点的方向来初始化设备的ep_in和ep_out数组,还有就是调用了include/linux/usb.h里的一个叫usb_settoggle的宏。
1424 /*The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
1425 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
1426 #define usb_dotoggle(dev, ep, out)((dev)->toggle[out] ^= (1 << (ep)))
1427 #define usb_settoggle(dev, ep, out, bit) /
1428 ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | /
1429 ((bit) << (ep)))
这三个宏都是用来处理端点的toggle位的,也就是struct usb_device里的数组toggle[2]。toggle[0]对应的是IN端点,toggle[1]对应的是OUT端点,上面宏参数里的out用来指定端点是IN还是OUT,ep指的不是端点的结构体,而仅仅是端点号。usb_gettoggle用来得到端点对应的toggle值,usb_dotoggle用来将端点的toggle位取反,也就是原来为1就置为0,原来为0就置为1,usb_settoggle看起来就要复杂点,意思是如果bit为0,则将ep 所对应的那个toggle 位reset 成0,如果bit为1,则reset为1。((dev)->toggle[out] & ~(1<<(ep)))就是把1 左移ep 位,比如ep 为3,那么就是得到了1000,然后取反,得到0111,(当然高位还有更多个1),然后(dev)->toggle[out]和0111 相与,这就是使得toggle[out]的第3 位清零而其它位都不变。咱们这里调用usb_settoggle的时候,bit传递的是0,用来将端点的toggle位清零,原因早先也提到过,就是对于批量传输、控制传输和中断传输来说,数据包最开始都是被初始化为DATA0的,然后才一次传DATA0,一次传DATA1。
现在看看为什么两个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。
1553行,device_initialize在初始化设备struct usb_device结构体的时候遇到过一次,这里初始化接口的时候又遇到了。
1554行,将接口的is_active标志初始化为0,表示它还没有与任何驱动绑定,就是还没有找到另一半儿。mark_quiesced在usb.h里定义
105 static inline void mark_quiesced(struct usb_interface *f)
106 {
108 }
1559行,for循环结束了,new_interfaces的历史使命也就结束了。我想你应该会明白的是,这里的kfree释放的只是new_interfaces指针数组的内存,而不包括它里面各个指针所指向的内存,至于那些数据,都已经在前面被赋给配置里的interface数组了。
1561行,获得配置的字符串描述符,怎么获得?先飘过去把剩下的说了再说它。
1570行,这个for循环结束,usb_set_configuration()的三个阶段也就算结束了,设备和大美女usb_generic_driver上上下下忙活了这么久也都很累了,接下来就该接口和接口驱动去忙活了。
这个for循环将前面那个for循环准备好的每个接口送给设备模型,Linux设备模型会根据总线类型usb_bus_type将接口添加到usb总线的那条有名的设备链表里,然后去轮询usb总线的另外一条有名的驱动链表,针对每个找到的驱动去调用usb总线的match函数,也就是usb_device_match,去为接口寻找另一个匹配的半圆。你说这个时候设备和接口两条路它应该走哪条?它的类型已经设置成usb_if_device_type了,设备那条路把门儿的根本就不会让它进,所以它必须得去走接口那条路。()
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics