设备自从有了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了,设备那条路把门儿的根本就不会让它进,所以它必须得去走接口那条路。

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

  1. Linux那些事儿 之 戏说USB(29)驱动的生命线(一)

    现在开始就沿着usb_generic_driver的成名之路走一走,设备的生命线你可以想当然的认为是从你的usb设备连接到hub的某个端口时开始,驱动的生命线就必须得回溯到usb子系统的初始化函数us ...

  2. Linux那些事儿 之 戏说USB(31)驱动的生命线(三)

    准备工作该做的都做了,别嫌太麻烦,什么事情都要经过这么一个阶段,大家都明白.现在看看第二阶段的重头戏,看看设备是怎么从Address进入Configured的.1501行,如果已经在Configure ...

  3. Linux那些事儿 之 戏说USB(30)驱动的生命线(二)

    core配置设备使用的是message.c里的usb_set_configuration函数 int usb_set_configuration(struct usb_device *dev, int ...

  4. Linux那些事儿 之 戏说USB(25)设备的生命线(四)

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1819919 洗澡是屁股享福,脑袋吃苦:看电影是脑袋享福,屁股吃苦:看内核代码是脑袋.屁股都吃 ...

  5. Linux那些事儿 之 戏说USB(28)设备的生命线(十一)

    现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都彼此的挤在一起,所以得想 ...

  6. Linux那些事儿 之 戏说USB(25)设备的生命线(八)

    回到struct usb_hcd,继续努力的往下看. 7行,又见kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看drivers/usb/core/hcd ...

  7. Linux那些事儿 之 戏说USB(22)设备的生命线(五)

    下面接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义. struct ur ...

  8. Linux那些事儿 之 戏说USB(27)设备的生命线(十)

    跟着设备的生命线走到现在,我算是明白了,什么东西的发展都是越往后越高级越复杂.再给张小表,看看现在和上次那张表出现的时候有什么变化. state        USB_STATE_ADDRESS sp ...

  9. Linux那些事儿 之 戏说USB(24)设备的生命线(七)

    算是进入了HCD的片儿区,这里的老大不是帮派头目也不是巡逻片儿警,而是几个结构.在HCD这个片儿区,这个山头儿,王中之王就是include/linux/usb/hcd.h里定义的struct usb_ ...

最新文章

  1. Android模拟自定义浏览器和打开另一个Ativity(06)
  2. junit rule_使用JUnit的ExpectedException和@Rule测试自定义异常
  3. matlab怎让3d旋转,如何在MATLAB中平滑旋转3D绘图?
  4. c语言时间错误的是什么意思,C语言中,如何验证输入日期的正确性!~
  5. 黑龙江工程学院计算机系有几个门,黑龙江工程学院本科专业设置一览表
  6. 孩子学python_教孩子学编程 Python
  7. 如何使用电脑的切屏快捷键
  8. android 图片拍照,Android拍照及图片处理类应用盘点
  9. 全民小镇ios越狱用户叉叉助手辅助刷金币攻略
  10. 基本数学概念——数列
  11. Java众神之路(2)-标志符
  12. SQL语句练习——查询
  13. doccano在linux系统的安装流程
  14. 第十五届全国大学生智能汽车竞赛 基础四轮组总结
  15. vue.js:597 [Vue warn]: Error in callback for watcher dat: TypeError: Cannot read property 'call'
  16. Jira、confluence和crowd安装文档
  17. CNAME(cname)
  18. ARM、MCU、DSP、FPGA、SOC各是什么?区别是什么?(转)
  19. 常见密码pojie工具
  20. linux翻译成中文,快速更正linux的翻译错误

热门文章

  1. Loadrunner安装使用入门
  2. 获取DOM节点的几种方式
  3. RabbitMQ 入门系列(7)— 如何保证 RabbitMQ 高可用性
  4. Atitit.java jna  调用c  c++ dll的原理与实践  总结  v2  q27
  5. jQuery的Tab插件 Tabtastic
  6. ae编程语言as_AE开发 入门教程
  7. python读取csv文件第一行_尝试读取CSV文件的第一行返回['/']
  8. Java每日一讲讲什么好_撩课-Java每天10道面试题第1天
  9. java 是怎么在中删除下拉列表_删除在一个下拉列表字段中选择的选项,并且不显示在该行中存在的其他下拉列表中不工作-jquery...
  10. php中mysql_PHP中MySQL操作