7.最熟悉的陌生人--probe

7.最熟悉的陌生人--probe

话说因为Hub驱动无所事事,所以hub_thread()进入了睡眠,直到某一天,hub_probe被调用。所以我们来看hub_probe(),这个函数来自drivers/usb/hub.c,其作用就如同当初我们在usb-storage中遇到的那个storage_probe()函数一样。

 
 
  1. 887 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)  
  2. 888 {  
  3. 889         struct usb_host_interface *desc;  
  4. 890     struct usb_endpoint_descriptor *endpoint;  
  5. 891     struct usb_device *hdev;  
  6. 892     struct usb_hub *hub;  
  7. 893  
  8. 894     desc = intf->cur_altsetting;  
  9. 895     hdev = interface_to_usbdev(intf);  
  10. 896  
  11. 897 #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB  
  12. 898     if (hdev->parent) {  
  13. 899         dev_warn(&intf->dev, "ignoring external hub\n");  
  14. 900             return -ENODEV;  
  15. 901     }  
  16. 902 #endif  
  17. 903  
  18. 904     /* Some hubs have a subclass of 1, which AFAICT according to the */  
  19. 905     /*  specs is not defined, but it works */  
  20. 906     if ((desc->desc.bInterfaceSubClass != 0) &&  
  21. 907             (desc->desc.bInterfaceSubClass != 1)) {  
  22. 908 descriptor_error:  
  23. 909             dev_err (&intf->dev, "bad descriptor, ignoring hub\n");  
  24. 910             return -EIO;  
  25. 911     }  
  26. 912  
  27. 913     /* Multiple endpoints? What kind of mutant ninja-hub is this? */  
  28. 914     if (desc->desc.bNumEndpoints != 1)  
  29. 915             goto descriptor_error;  
  30. 916  
  31. 917     endpoint = &desc->endpoint[0].desc;  
  32. 918  
  33. 919     /* If it's not an interrupt in endpoint, we'd better punt! */  
  34. 920     if (!usb_endpoint_is_int_in(endpoint))  
  35. 921             goto descriptor_error;  
  36. 922  
  37. 923     /* We found a hub */  
  38. 924     dev_info (&intf->dev, "USB hub found\n");  
  39. 925  
  40. 926     hub = kzalloc(sizeof(*hub), GFP_KERNEL);  
  41. 927     if (!hub) {  
  42. 928         dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");  
  43. 929             return -ENOMEM;  
  44. 930     }  
  45. 931  
  46. 932     INIT_LIST_HEAD(&hub->event_list);  
  47. 933     hub->intfdev = &intf->dev;  
  48. 934     hub->hdevhdev = hdev;  
  49. 935         INIT_DELAYED_WORK(&hub->leds, led_work);  
  50. 936  
  51. 937         usb_set_intfdata (intf, hub);  
  52. 938     intf->needs_remote_wakeup = 1;  
  53. 939  
  54. 940     if (hdev->speed == USB_SPEED_HIGH)  
  55. 941             highspeed_hubs++;  
  56. 942  
  57. 943     if (hub_configure(hub, endpoint) >= 0)  
  58. 944             return 0;  
  59. 945  
  60. 946     hub_disconnect (intf);  
  61. 947         return -ENODEV;  
  62. 948 }  

幸运的是这个函数还不是很长。894行,desc,是这个函数中定义的一个struct usb_host_ interface结构体指针,其实这就相当于struct usb_interface结构中的那个altsetting,只是换了一个名字。

同样895行这个赋值我们也很眼熟, interface_to_usbdev()这个宏就是为了从一个struct usb_interface的结构体指针得到那个与它相关的struct usb_device结构体指针。这里等号右边的intf自不必说,而左边的hdev正是我们这里为了Hub而定义的一个struct usb_device结构体指针。

897行到902行,这是为OTG而准备的,为了简化问题,在这里我做一个假设,即假设我们不支持OTG。在内核编译选项中有一个叫做CONFIG_USB_OTG的选项,OTG就是"On The Go"(正在进行中)的意思,随着USB传输协议的诞生,以及它的迅速走红,人们不再满足于以前那种一个设备要么就是主设备,要么就是从设备的现状,也就是说要么是Host(或者叫主设备);要么是外设(也叫Slave,或者叫从设备)。在那个年代里,只有当一台Host与一台Slave连接时才能实现数据的传输,而后来开发人员们又公布了USB OTG规范,于是出现了OTG设备,即既可以充当Host,亦能充当Slave的设备。也就是说如果你有一台数码相机和一台打印机,它们各有一个USB接口,把这两个口连接起来,就可以把你的照片打印出来了。所以我只能假设我们不打开支持OTG的编译开关,而这里我们看到的CONFIG_USB_OTG_ BLACKLIST_HUB,其实就是CONFIG_OTG下面的子选项,不选后者根本就见不到前者。

904行到911行,这没什么可说的了,每一个USB设备它属于哪个类,以及哪个子类这都是定好的,比如Hub的子类就是0,即desc->desc这个interface描述符里边的bInterfaceSubClass就应该是0。所以这里是判断如果bInterfaceSubClass不为0那就出错了,那就不往下走了,返回值是-EIO。

914行和915行,其实干的事情是差不多的,针对接口描述符再做一次判断,这次是判断这个Hub有几个端点。spec规定了Hub只有一个端点(除去端点0)也就是中断端点,因为Hub的传输是中断传输。当然还有控制传输,但是因为控制传输是每一个设备都必须支持的,即每一个USB设备都会有一个控制端点,所以在desc->desc.bNumEndpoints中是不包含那个大家都有的控制端点的。因此如果这个值不为1,那么就说明又出错了,仍然只能是返回。

917行,得到这个唯一的端点所对应的端点描述符,920行和921行就是判断这个端点是不是中断端点,如果不是,那还是一样,返回报错吧。

如果以上几种常见的错误都没有出现,这个时候我们才开始正式地去做一些事情,让我们继续。

924行,打印调试信息。

926行,申请Hub的数据结构struct usb_hub。不过926行有一个很新的函数,kzalloc()。其实这个函数就是原来的两个函数的整合,即原来我们每次申请内存时都会这么做,先是用kmalloc()申请空间,然后用me mset()来初始化,而现在一步到位,直接调用kzalloc()函数,效果等同于原来那两个函数,所有申请的元素都被初始化为0。

其实对于写驱动的人来说,知道现在应该用kzalloc()函数代替原来的kmalloc()和me mset()函数就可以了,这是内核中内存管理部分做出的改变,确切地说是改进。负责内存管理那部分程序的目标无非就是让内核跑起来更快一些,而从kmalloc/me mset到kzalloc的改变确实也是为了实现这方面的优化。所以自从2005年底内核中引入kzalloc之后,整个内核代码的许多模块里面都先后把原来的kmalloc/me mset统统换成了kzalloc()。咱们这里就是其中一处。927行到930行不用说了,如果没申请成功那就返回ENOMEM。

932行,还记得之前说的总分的结构,一个总的事件队列,hub_event_list,然后各个Hub都有一个分的事件队列,就是这里的hub->event_list,前面已经初始化了全局的hub_event_list,而这里咱们针对单个Hub就得为其初始化一个event_list。

933行和934行,struct usb_hub中的两个成员:struct device *intfdev;struct usb_device *hdev,干什么用的想必不用多说了吧,第一个,不管你是USB设备也好,PCI设备也好,SCSI设备也好,Linux内核中都为你准备一个struct device结构体来描述,所以intfdev就是和Hub相关联的struct device指针;第二个,不管是Hub也好,U盘也好,移动硬盘也好,USB鼠标也好,USB Core都准备一个struct usb_device来描述,所以hdev将是与这个Hub相对应的struct usb_device指针。

而这些在我们调用hub_probe之前就已经建立好了,都在参数struct usb_interface *intf中,具体怎么得到的,对于Root Hub来说,这涉及主机控制器的驱动程序,现在先忽略。但对于一个普通的外接的Hub,后面会看到如何得到它的struct usb_interface,因为建立并初始化一个USB设备的struct usb_interface正是Hub驱动里做的事情,其实也就是我们对Hub驱动最好奇的地方。因为找到了这个问题的答案,我们就知道了对于一个USB设备驱动,其probe指针是在什么情况下被调用的,比如这里的hub_probe对于普通Hub来说是谁调用的?比如之前的usb-storage中函数storage_probe()究竟是谁调用的?这正是我们想知道的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值