usbip:(二)从linux内核了解usb

一、前言

  1、首先了解一下EHCI、UHCI和OHCI。

  从硬件上来说,usb 设备要想工作,除了外设本身,必须依赖于 usb host controller.一般来说,一个电脑里有一个 usb host controller就可以了,她就可以控制很多个设备了,比如 u 盘,比如 usb 键盘,比如 usb 鼠标.所 有  的外设都把自己的请求提交给usb host controller.然后让 usb host controller 统一来调度.
  现在一般的USB桥接器模块有两种类型,UHCI和OHCI。在决定插入那一个桥接器模块时,可以察看/proc/pci文件来决定。一般而言,UHCI类型的桥接器它的插入模块是uhci或usb-uhci(由内核版本决定);而对于OHCI类型的桥接器它的插入模块是ohci或usb-ohci。


  uhci(universal host controller interface): Intel用在自家芯片组上的usb 1.1主控制器(host controller)的硬件实例
  ehci(enhanced host controller interface): usb 2.0的主控制器标准接口。
  ohci(open host controller inferface):一个不仅仅是usb用的主控制器接口标准。主要是遵循csr (configuration space register)标准。是其他厂商在设计usb host controller时遵循的标准,如via, nec, ali, 包括nvidia等等。
  ehci是满足usb 2.0 specification里面对usb host controller (high speed)的要求的硬件设计。

 

  就是主机控制器的接口。从硬件上来说,USB 设备要想工作,除了外设本身,必须还有一个 USB 主机控制器。一般来说,一个电脑里有一个 USB 主机控制器就可以了,它就可以控制很多个设备了,比如 U 盘,USB 键盘,USB 鼠标。所有的外设都把自己的请求提交给 USB主机控制器。然后让 USB 主机控制器统一来调度。而设备怎么连到主机控制器上?哎,这就是我们故事的主角,Hub,“乳名”叫做集线器。

  2、准备工作

  linux内核源码下载,可以根据自己喜好选择对应的版本。

  wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.145.tar.gz

  以usb_hub,来了解usb工作

  localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # wc -l hub.c

 

二、API

  1、Root_Hub

   

  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、usb_init

  综上所述,整个USB子系统在初始化的时候,会先执行初始化Root Hub。

  来自drivers/usb/core/usb.c:

 982 static int __init usb_init(void)  983 {             ...... 1007     if (retval) 1008         goto usb_devio_init_failed; 1009     retval = usb_hub_init();             ...... 1032 }

  在众多名叫*init*的函数之中,是有一个属于 Hub 的,它在这里初始化,换言之,随着 USB Core 的初
始化,Hub 也就开始了它的初始化之路,usb_hub_init()函数得到调用。

  来自drivers/usb/core/hub.c:

5600 int usb_hub_init(void) 5601 {    5602     if (usb_register(&hub_driver) < 0) { 5603         printk(KERN_ERR %s: can't register hub driver\n, 5604             usbcore_name); 5605         return -1; 5606     } 5607      5608     /* 5609      * The workqueue needs to be freezable to avoid interfering with 5610      * USB-PERSIST port handover. Otherwise it might see that a full-speed 5611      * device was gone before the EHCI controller had handed its port 5612      * over to the companion full-speed controller. 5613      */ 5614     hub_wq = alloc_workqueue(usb_hub_wq, WQ_FREEZABLE, 0); 5615     if (hub_wq) 5616         return 0; 5617      5618     /* Fall through if kernel_thread failed */ 5619     usb_deregister(&hub_driver); 5620     pr_err(%s: can't allocate workqueue for usb hub\n, usbcore_name); 5621  5622     return -1; 5623 }