Linux USB 3.0驱动分析(四)—— USB Core分析
一.拓扑结构
·之所以要规定这个树形拓扑结构是为了避免环形连接。
·一条USB总线有且只有一个USBHost,对应一个RootHub
·USB设备分为两类,Hub和Functions,Hub通过端口Port连接更多USB设备,Functions即USB外接从设备。
·层次最多7层,且第7层不能有Hub,只能有functions。
·CompoundDevice-一个Hub上接多个设备组成一个小设备。
·CompositeDevice-一个USB外接设备具有多个复用功能。
二.USBCore
1.USB子系统结构
HCD(Host Controller Device): USB主控制器设备
协议里说,HCD提供主控制器驱动的硬件抽象,它只对USBCore一个负责,USBCore将用户的请求映射到相关的HCD,用户不能直接访问HCD。换句话说,USBCore就是HCD与USB设备唯一的桥梁。
2.USB子系统的初始化
USBcore源码位于./drivers/usb/core,其中的Makefile摘要如下,
usbcore这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块,它就是USB子系统。
在./drivers/usb/core/usb.c里实现了初始化,源代码如下,
static int __init usb_init(void)
{
retval = usb_debugfs_init(); //1.usb debugfs初始化
if (retval)
goto out;
retval = bus_register(&usb_bus_type); //注册USB总线,也就是USB子系统
if (retval)
goto bus_register_failed;
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); //注册内核通知链,用于设备和接口注册的通知
if (retval)
goto bus_notifier_failed;
retval = usb_major_init(); //usb主设备号初始化
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver); //注册usb文件系统
if (retval)
goto driver_register_failed;
retval = usb_devio_init(); //usb设备字符设备初始化
if (retval)
goto usb_devio_init_failed;
retval = usb_hub_init(); //usb hub初始化
if (retval)
goto hub_init_failed;
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册一个USB设备(不是接口)驱动程序
if (!retval)
goto out;
}
usbcore注册了USB总线,USB文件系统,USBHub以及USB的设备驱动usb generic driver等。
3. usb_debugfs_init --usb debugfs初始化
static int usb_debugfs_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL); //创建"$(debugfs)/usb"
if (!usb_debug_root)
return -ENOENT;
//创建"$(debugfs)/usb/device",捆绑usbfs_devices_fops结构体,位置 /sys/kernel/debug/usb/device,打印所有总线下的设备
usb_debug_devices = debugfs_create_file("devices", 0444,usb_debug_root, NULL,&usbfs_devices_fops);
}
4.usb总线的注册
struct bus_type usb_bus_type = {
.name = "usb", //总线名
.match = usb_device_match, //匹配方法,应该用于usb驱动id_table的匹配
.uevent = usb_uevent, //事件处理
};
5.注册usb总线通知链
int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
{
return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
}
当总线添加删除设备的时候会调用usb_bus_nb指定的notifier_cal方法,既usb_bus_notify
static int usb_bus_notify(struct notifier_block *nb, unsigned long action,void *data)
{
struct device *dev = data;
switch (action) {
case BUS_NOTIFY_ADD_DEVICE: //添加设备
if (dev->type == &usb_device_type) //usb设备
(void) usb_create_sysfs_dev_files(to_usb_device(dev)); //生成sysfs节点/sys/devices/platform/soc@0/38100000.usb/xhci-hcd.0.auto/usb1
else if (dev->type == &usb_if_device_type) //usb接口
(void) usb_create_sysfs_intf_files(to_usb_interface(dev));
break;
case BUS_NOTIFY_DEL_DEVICE: //删除设备
if (dev->type == &usb_device_type) //usb设备
usb_remove_sysfs_dev_files(to_usb_device(dev));
else if (dev->type == &usb_if_device_type) //usb接口
usb_remove_sysfs_intf_files(to_usb_interface(dev));
break;
}
return 0;
}
6.初始化usb主控器字符设备,USB_MAJOR=180
int usb_major_init(void)
{
int error;
error = register_chrdev(USB_MAJOR, "usb", &usb_fops); //注册usb控制器字符设备,捆绑usb_fops
if (error)
printk(KERN_ERR "Unable to get major %d for usb devices\n",USB_MAJOR);
return error;
}
捆绑usb_fops
static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
.llseek = noop_llseek,
};
7.注册usbfs_driver
usb_register(&usbfs_driver); //通过usb_register()将usbfs驱动提交个设备模型,添加到USB总线的驱动链表里。
/* use a define to avoid include chaining to get THIS_MODULE & friends */
//其实是调用usb_register_driver,注册一个usb接口驱动
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
struct usb_driver usbfs_driver = {
.name = "usbfs", //在/sys/bus/usb/drivers/usbfs
.probe = driver_probe,
.disconnect = driver_disconnect,
.suspend = driver_suspend,
.resume = driver_resume,
};
8.usb_devio_init USB_DEVICE_DEV=189
//用于应用程序直接访问usb设备
int __init usb_devio_init(void)
{
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device"); //分配设备号
if (retval) {
printk(KERN_ERR "Unable to register minors for usb_device\n");
goto out;
}
cdev_init(&usb_device_cdev, &usbdev_file_operations); //字符设备初始化
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); //添加字符设备
if (retval) {
printk(KERN_ERR "Unable to get usb_device major %d\n",
USB_DEVICE_MAJOR);
goto error_cdev;
}
usb_register_notify(&usbdev_nb); //注册设备通知链
}
usb注册的通知链
void usb_register_notify(struct notifier_block *nb)
{
blocking_notifier_chain_register(&usb_notifier_list, nb);
}
usb通知链表头为usb_notifier_list
在/drivers/usb/core/notify.c文件中,有四个函数()对usb_notifier_list中发送通知,这四个函数如下:
usb_notify_add_device //有设备添加
usb_notify_remove_device //有设备移除
usb_notify_add_bus //总线添加
usb_notify_remove_bus //总线移除
当这些事件发生后会调用usbdev_nb指定的notifier_cal方法,既usbdev_notify
static int usbdev_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
break;
}
return NOTIFY_OK;
}
9. 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设备(非接口)驱动。
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,
};
对应到root hub,流程会转入到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总线
注册USB总线通过bus_register(&usb_bus_type);
struct bus_type usb_bus_type={
.name="usb",
.match=usb_device_match,//这是个很重要的函数,用来匹配USB设备和驱动。
.uevent=usb_uevent,.pm=&usb_bus_pm_ops,
};
下面总结下USB设备和驱动匹配的全过程,
->step1-usb device driver
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盘驱动程序,鼠标驱动程序等等。
->step2-usb driver
Linux启动时注册USB驱动,在xxx_init()里通过usb_register()将USB驱动提交个设备模型,添加到USB总线的驱动链表里。
->step3-usb device
USB设备连接在Hub上,Hub检测到有设备连接进来,为设备分配一个struct usb_device结构体对象,并将设备添加到USB总线的设备列表里。
->step4-usb interface
USB设备各个配置的详细信息在USB core里的漫漫旅途中已经被获取并存放在相关的几个成员里。
usb_generic_driver得到了USB设备的详细信息,然后把准备好的接口送给设备模型,Linux设备模型将接口添加到设备链表里,然后去轮询USB总线另外一条驱动链表,针对每个找到的驱动去调用USB总线的match函数,完成匹配。
参考:
二、usb子系统初始化_jixianghao的博客-CSDN博客
USB在Linux里的结构框架是什么样的?USB Core和Hub是什么?
Linux设备驱动之USB hub驱动_cosmoslhf的专栏-CSDN博客