3.特别的爱给特别的Root Hub

时间:2022-01-15 15:57:42

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:

3.特别的爱给特别的Root Hub 
图2.3.1  USB拓扑结构

  
  
 
 
  1. 863 static int __init usb_init(void)  
  2. 864 {  
  3.         ⋯⋯  
  4. 890     if (retval)  
  5. 891         goto fs_init_failed;  
  6. 892     retval = usb_hub_init();  
  7.         ⋯⋯  
  8. 916 }  

在众多名叫*init*的函数之中,是有一个属于Hub的,它在这里初始化,换而言之,随着USB Core的初始化,Hub也就开始了它的初始化之路,usb_hub_init()函数得到调用,这个函数来自drivers/usb/core/hub.c:
  
  
 
 
  1. 2854 int usb_hub_init(void)  
  2. 2855 {  
  3. 2856        if (usb_register(&hub_driver) < 0) {  
  4. 2857        printk(KERN_ERR "%s: can't register hub driver\n",  
  5. 2858                         usbcore_name);  
  6. 2859        return -1;  
  7. 2860    }  
  8. 2861  
  9. 2862    khubd_task = kthread_run(hub_thread, NULL, "khubd");  
  10. 2863        if (!IS_ERR(khubd_task))  
  11. 2864        return 0;  
  12. 2865  
  13. 2866        /* Fall through if kernel_thread failed */  
  14. 2867    usb_deregister(&hub_driver);  
  15. 2868    printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);  
  16. 2869  
  17. 2870    return -1;  
  18. 2871 }  

一路走来的兄弟们不会对这样一段代码陌生,是不是有一种似曾相识的感觉?