1.概述
如下图所示,Linux内核中USB主机体系结构由五部分组成,分别为Application Software、USB Class Driver、USB Core(USB Driver)、USB Host Controller Driver、USB Host Controller。应用程序处于用户空间,通过系统调用访问Class Driver,从而间接的访问USB设备,如主机端的应用程序aplay、arecord可以访问USB音频设备。Class Driver是某一类设备驱动,不同类设备会匹配不同的Class Driver,如USB音频设备会匹配Audio驱动,USB存储设备会匹配Mass Storage驱动,鼠标和键盘会匹配HID驱动。USB Core(USB Driver)是内核设计的一个抽象层,目的是将Class Driver和USB Host Controller Driver分隔开,使两者都依赖一个稳定的中间层;USB Core(USB Driver)向上提供通信接口,向下统一管理USB设备,同时完成USB设备和USB Class Driver的匹配工作。USB Host Controller目前有4种不同的硬件级接口标准,分别为OHCI、UHCI、EHCI、xHCI,OHCI和UHCI实现了USB1.1,EHCI实现了USB2.0,xHCI实现了USB3.2,不同的接口标准都有对应的USB Host Controller Driver,如xHCI对应于xhci-hcd驱动,向下兼容OHCI和EHCI。最底层是USB Host Controller硬件。下面将分别介绍Linux内核中USB主机体系结构USB Class Driver、USB Core(USB Driver)、USB Host Controller Driver四个部分。
2. USB子系统结构
USBcore源码位于./drivers/usb/core,usbcore这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块,它就是USB子系统。USB Core(USB Driver)有三个功能,第一是向USB Class Driver提供通信接口,第二是匹配驱动,第三是管理USB Device。
在./drivers/usb/core/usb.c里实现了初始化,源代码如下,
static int __init usb_init(void)
{
retval = bus_register(&usb_bus_type); //注册USB总线,也就是USB子系统
retval = usb_hub_init(); //usb hub初始化
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册一个USB设备(不是接口)驱动程序
}
usbcore注册了USB总线,USB文件系统,USBHub以及USB的设备驱动usb generic driver等。
2.1 usb总线的注册
struct bus_type usb_bus_type = {
.name = "usb", //总线名
.match = usb_device_match, //匹配方法,应该用于usb驱动id_table的匹配
.uevent = usb_uevent, //事件处理
};
USB Class Driver和USB设备接口、USB设备和USB Core(USB Driver)都是通过struct usb_device_id中的信息进行匹配。struct usb_device_id定义了4中匹配方式,第一种是产品信息匹配,通常情况使用VID和PID;第二种是根据设备类信息进行匹配;第三种根据接口的类信息进行匹配,第四种根据厂家自定义的接口进行匹配。具体使用那种匹配方式,由match_flags决定,内核定义了USB_DEVICE_ID_xx开头的宏,用来设置match_flags。USB Class Driver和USB设备接口、USB设备和USB Core(USB Driver)的匹配工作由usb_bus_type中的usb_device_match函数完成,该函数会进一步调用usb_match_id进行匹配。
2.2 usb注册通用设备驱动
int usb_register_device_driver(struct usb_device_driver *new_udriver,struct module *owner)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_udriver->drvwrap.for_devices = 1; //usb设备
new_udriver->drvwrap.driver.name = (char *) new_udriver->name; //设备名
new_udriver->drvwrap.driver.bus = &usb_bus_type; //总线类型
new_udriver->drvwrap.driver.probe = usb_probe_device; //probe方法
new_udriver->drvwrap.driver.remove = usb_unbind_device; //remove方法
new_udriver->drvwrap.driver.owner = owner; //模块所有者
retval = driver_register(&new_udriver->drvwrap.driver); //注册设备驱动
if (!retval) {
pr_info("%s: registered new device driver %s\n",usbcore_name, new_udriver->name);
usbfs_update_special();
} else {
printk(KERN_ERR "%s: error %d registering device driver %s\n",usbcore_name, retval, new_udriver->name);
}
return retval;
}
usb_device_driver结构体是usb_driver的简化版本,这里注册的是usb设备(非接口)驱动。
struct usb_driver定义的USB Class Driver驱动和USB设备的接口匹配,而struct usb_device_driver定义的驱动和USB设备匹配,使用usb_register_device_driver和usb_deregister_device_driver函数注册和注销struct usb_device_driver。内核提供了通用的struct usb_device_driver,即usb_generic_driver,在USB子系统初始化的时候注册到系统中,通常情况下USB Class Driver无需再提供struct usb_device_driver。
usb总线的match方法对usb设备和usb接口做了区分处理,针对usb设备,直接match的,(分析match时候再细化)
然后调用usb设备驱动的probe方法
static int usb_probe_device(struct device *dev)
{
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
struct usb_device *udev = to_usb_device(dev);
int error = 0;
dev_dbg(dev, "%s\n", __func__);
if (!udriver->supports_autosuspend) //条件成立
error = usb_autoresume_device(udev);
if (!error)
error = udriver->probe(udev); //调用usb_device_driver的probe方法
return error;
}
接着调用usb_generic_driver的probe方法
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
注册根hub设备后,由于在usb子系统初始化函数中注册了usb通用设备驱动usb_generic_driver,这样就会执行usb_generic_driver的probe函数,即generic_probe:流程会转入到generic_probe().代码如下:
static int generic_probe(struct usb_device *udev)
{
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
if (udev->authorized == 0) //至于udev->authorized,在root hub的初始化中,是会将其初始化为1的.后面的逻辑就更简单了.为root hub 选择一个配置然后再设定这个配置.
dev_err(&udev->dev, "Device is not authorized for usage\n");
else {
c = usb_choose_configuration(udev); //Usb2.0 spec上规定,对于hub设备,只能有一个config,一个interface,一个endpoint.实际上,在这里,对hub的选择约束不大,反正就一个配置,不管怎么样,选择和设定都是这个配置.
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err && err != -ENODEV) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
return 0;
}
usb_set_configuration定义在drivers/usb/core/message.c
int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_host_config *cp = NULL;
struct usb_interface **new_interfaces = NULL;
struct usb_hcd *hcd = bus_to_hcd(dev->bus);
int n, nintf;
if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { // 遍历每一个配置
if (dev->config[i].desc.bConfigurationValue == // 从配置描述符中获取配置值,配置值保存的是该配置在dev->config中的索引
configuration) {
cp = &dev->config[i]; // 获取当前指定的配置
break;
}
}
}
if ((!cp && configuration != 0))
return -EINVAL;
......
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
* claim() any interfaces not yet bound. Many class drivers
* need that: CDC, audio, video, etc.
*/
for (i = 0; i < nintf; ++i) { // 遍历当前配置的每一个接口
struct usb_interface *intf = cp->interface[i];
if (intf->dev.of_node &&
!of_device_is_available(intf->dev.of_node)) {
dev_info(&dev->dev, "skipping disabled interface %d\n",
intf->cur_altsetting->desc.bInterfaceNumber);
continue;
}
dev_dbg(&dev->dev,
"adding %s (config #%d, interface %d)\n",
dev_name(&intf->dev), configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
device_enable_async_suspend(&intf->dev);
ret = device_add(&intf->dev); // 注册当前接口设备到内核
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d\n",
dev_name(&intf->dev), ret);
continue;
}
create_intf_ep_devs(intf);
}
usb_autosuspend_device(dev);
return 0;
}
在usb_set_configuration的尾部,会将usb_device设备指定配置里的每一个接口设备注册到内核中。
在执行device_add后导致总线的匹配函数usb_device_match再次被调用,这次由于是接口设备,设备类型为usb_if_device_type,那么匹配的一定是接口驱动,于是会执行usb_device_match的else分支,去匹配接口驱动。
然后调用device_add将设备加入到设备链表中,在执行device_add后,将执行总线的匹配函数usb_device_match:
device_add
bus_probe_devic
device_attach
bus_for_each_drv
__device_attach
driver_match_device
drv->bus->match(dev, drv)
usb_device_match
3. USB总线
下面总结下USB设备和驱动匹配的全过程,
USB子系统初始化的时候就会注册usb_generic_driver,它的结构体类型是usb_device_driver,它是USB世界里唯一的一个USB设备驱动,区别于struct usb_driver USB驱动。
·USB设备驱动(usb device driver)就只有一个,即usb_generice_driver这个对象,所有USB设备都要绑定到usb_generic_driver上,它的使命可以概括为:为USB设备选择一个合适的配置,让设备进入configured状态。
·USB驱动(usb driver)就是USB设备的接口驱动程序,比如adb驱动程序,u盘驱动程序,鼠标驱动程序等等。
Linux启动时注册USB驱动,在xxx_init()里通过usb_register()将USB驱动提交个设备模型,添加到USB总线的驱动链表里。
USB设备连接在Hub上,Hub检测到有设备连接进来,为设备分配一个struct usb_device结构体对象,并将设备添加到USB总线的设备列表里。
USB设备各个配置的详细信息在USB core里的漫漫旅途中已经被获取并存放在相关的几个成员里。
usb_generic_driver得到了USB设备的详细信息,然后把准备好的接口送给设备模型,Linux设备模型将接口添加到设备链表里,然后去轮询USB总线另外一条驱动链表,针对每个找到的驱动去调用USB总线的match函数,完成匹配。
4. 总结