3.特别的爱给特别的Root Hub
不懂Hub是怎么工作的就等于不知道USB设备驱动是怎么工作的。这句话一点没错,因为USB设备的初始化都是Hub这边发起的,通常我们写USB设备驱动程序都是在已经得到了一个struct usb_interface指针的情况下开始probe工作。可是我要问你,你的struct usb_interface从哪来的?老实说,要想知道从USB设备插入USB口的那一刻开始,这个世界发生了什么,你必须知道Hub是怎么工作的,Linux中Hub驱动程序是怎么工作的。
要说USB Hub,那得从Root Hub说起。什么是Root Hub?不管你的计算机里连了多少个USB设备,它们最终是有根的。所有的USB设备最终都是连接到了一个叫做Root Hub的设备上,或者说所有的根源都是从这里开始的。
Root Hub上可以连接别的设备,可以连接U盘,可以连接USB鼠标,同样也可以连接另一个Hub。所谓Hub,就是用来级联。但是普通的Hub,它一头接上级Hub,另一头可以有多个口,多个口就可以连多个设备,也可以只有一个口。而Root Hub呢?它比较特殊,它当然也是一种USB设备,但是它属于一人之下万人之上的角色,它只属于主机控制器,换而言之,通常做芯片的人会把主机控制器和Root Hub集成在一起。特别是PC主机上,通常你就只能看到接口,看不到Root Hub,因为它在主机控制器里,正如图2.3.1所示。
当然,我们应该更加准确地评价主机和Root Hub的关系。
别扯远了,继续回来,既然Root Hub享有如此特殊的地位,那么很显然,整个USB子系统得特别对待它,一开始就会要初始化Hub。所以我们从USB子系统的初始化代码开始看起,也就是usb_init函数,来自drivers/usb/core/usb.c:
图2.3.1 USB拓扑结构 |
在众多名叫*init*的函数之中,是有一个属于Hub的,它在这里初始化,换而言之,随着USB Core的初始化,Hub也就开始了它的初始化之路,usb_hub_init()函数得到调用,这个函数来自drivers/usb/core/hub.c:
- 863 static int __init usb_init(void)
- 864 {
- ⋯⋯
- 890 if (retval)
- 891 goto fs_init_failed;
- 892 retval = usb_hub_init();
- ⋯⋯
- 916 }
- 2854 int usb_hub_init(void)
- 2855 {
- 2856 if (usb_register(&hub_driver) < 0) {
- 2857 printk(KERN_ERR "%s: can't register hub driver\n",
- 2858 usbcore_name);
- 2859 return -1;
- 2860 }
- 2861
- 2862 khubd_task = kthread_run(hub_thread, NULL, "khubd");
- 2863 if (!IS_ERR(khubd_task))
- 2864 return 0;
- 2865
- 2866 /* Fall through if kernel_thread failed */
- 2867 usb_deregister(&hub_driver);
- 2868 printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
- 2869
- 2870 return -1;
- 2871 }
一路走来的兄弟们不会对这样一段代码陌生,是不是有一种似曾相识的感觉?