您的位置:首页 > 运维架构 > Linux

linux usb core

2013-11-28 16:49 281 查看
linux usb core是针对usb host,对于做手机的我而言,更加关注的是usb gadget,毕竟手机更多的作为usb外设而存在,不过随着越来越多的otg需求,这块就难以避免了

花点时间研究了下,usb gadget下次再谈

从init开始

1006 static int __init usb_init(void)
1007 {
1008     int retval;
1009     if (nousb) {
1010         pr_info("%s: USB support disabled\n", usbcore_name);
1011         return 0;
1012     }
1013
1014     retval = usb_debugfs_init();
1015     if (retval)
1016         goto out;
1017
1018     retval = bus_register(&usb_bus_type);
1019     if (retval)
1020         goto bus_register_failed;
1021     retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
1022     if (retval)
1023         goto bus_notifier_failed;
1024     retval = usb_major_init();
1025     if (retval)
1026         goto major_init_failed;
1027     retval = usb_register(&usbfs_driver);
1028     if (retval)
1029         goto driver_register_failed;
1030     retval = usb_devio_init();
1031     if (retval)
1032         goto usb_devio_init_failed;
1033     retval = usbfs_init();
1034     if (retval)
1035         goto fs_init_failed;
1036     retval = usb_hub_init();
1037     if (retval)
1038         goto hub_init_failed;
1039     retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
1040     if (!retval)
1041         goto out;


usb_init是整个usb core的入口,略过前面debugfs之类的函数,注意到bus_register(&usb_bus_type),用来注册usb bus

接下来一个重要的调用就是usb_hub_init

3864 int usb_hub_init(void)
3865 {
3866     if (usb_register(&hub_driver) < 0) {
3867         printk(KERN_ERR "%s: can't register hub driver\n",
3868             usbcore_name);
3869         return -1;
3870     }
3871
3872     khubd_task = kthread_run(hub_thread, NULL, "khubd");
3873     if (!IS_ERR(khubd_task))
3874         return 0;
3875
3876     /* Fall through if kernel_thread failed */
3877     usb_deregister(&hub_driver);
3878     printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
3879
3880     return -1;
3881 }


这个函数很简短,主要功能有两块,注册interface driver:hub,启动守护进程khubd。
注册interface driver, 调用usb_register(&hub_driver),usb_register用来注册usb interface driver, 对应的还有一个函数用来注册usb device driver: usb_register_device_driver,这个接下来会提到,需要搞清的一个概念是,USB是一个层次结构,每一个设备都有一个或多个config,每一个config又有一个或多个interface(class),每一个interface都有多个endpoint。
启动守护进程khubd,这个守护进程后面再谈

接下来调用 usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
这里注册了一个通用的usb device driver: usb_generic_driver

这里需要搞清的一个概念是,无论hub还是外设,凡是插入usb的设备都是device,都会用一个device来描述,host相对特殊一些,会建立一个roothub的device,所有的这些device加入进来的时候都会调用usb_generic_driver的probe函数。

usb_init至此也就完成了,不过看到这里对usb core还是云里雾里,怎么和host controller结合起来呢?怎么枚举外设呢?

针对这两个问题,下面我们来看看加载host的关键函数

int usb_add_hcd(struct usb_hcd *hcd,         unsigned int irqnum, unsigned long irqflags)

这个函数很长,这里不全部列出,核心调用如下:

usb_register_bus(&hcd->self)),注册一个usb bus,一个usb controller对应一个usb bus
rhdev = usb_alloc_dev(NULL, &hcd->self, 0)),分配一个usb device, 这里是root hub
retval = hcd->driver->start(hcd); 调用host controller的start函数启动host
register_root_hub(hcd),注册root hub,这是个关键函数,从这里开始也就和上面的usb core产生了关系,这个函数主要调用的是usb_new_device (usb_dev), usb_new_device主要做两件事:枚举设备,主要是get descriptor;调用device_add注册第二步中分配的root hub,熟悉linux device driver的话,应该能够看出这一步会产生什么效果,还记得前面提到的usb_generic_driver么?没错,添加设备之后,会调用usb_generic_driver的probe函数

usb_generic_driver  generic_probe

156 static int generic_probe(struct usb_device *udev)
157 {
158     int err, c;
159
160     /* Choose and set the configuration.  This registers the interfaces
161      * with the driver core and lets interface drivers bind to them.
162      */
163     if (usb_device_is_owned(udev))
164         ;       /* Don't configure if the device is owned */
165     else if (udev->authorized == 0)
166         dev_err(&udev->dev, "Device is not authorized for usage\n");
167     else {
168         c = usb_choose_configuration(udev);
169         if (c >= 0) {
170             err = usb_set_configuration(udev, c);
171             if (err) {
172                 dev_err(&udev->dev, "can't set config #%d, error %d\n",
173                     c, err);
174                 /* This need not be fatal.  The user can try to
175                  * set other configurations. */
176             }
177         }
178     }
179     /* USB device state == configured ... usable */
180     usb_notify_add_device(udev);
181
182     return 0;
183 }


可以看出,这个函数是在处理usb的configuration,熟悉usb枚举过程的应该明白,这个是usb枚举的最后一步了

1681 int usb_set_configuration(struct usb_device *dev, int configuration)
{
...
1848     for (i = 0; i < nintf; ++i) {
1849         struct usb_interface *intf = cp->interface[i];
1850
1851         dev_dbg(&dev->dev,
1852             "adding %s (config #%d, interface %d)\n",
1853             dev_name(&intf->dev), configuration,
1854             intf->cur_altsetting->desc.bInterfaceNumber);
1855         device_enable_async_suspend(&intf->dev);
1856         ret = device_add(&intf->dev);
1857         if (ret != 0) {
1858             dev_err(&dev->dev, "device_add(%s) --> %d\n",
1859                 dev_name(&intf->dev), ret);
1860             continue;
1861         }
1862         create_intf_ep_devs(intf);
1863     }
1864
1865     usb_autosuspend_device(dev);
1866     return 0;
1867 }


从上面这段截取的code中可以看出usb_set_configuration会取出设备的每一个interface然后调用device_add创建interface device,由于host只有一个interface:hub,所以这里只加了hub。还得的前面在usb_hub_init里面注册了的interface driver:hub 么?没错,这里hub加进来会触发hub interface driver的hub_probe

hub_probe --> hub_configure --> hub_activate --> kick_khubd

kick_khubd是一个关键函数,在这之前,hub的枚举已经全部完成,这意味着hub可以开始服务,检测是否有外设插入进来,kick_khubd给了hub这个机会,

392 static void kick_khubd(struct usb_hub *hub)
393 {
394     unsigned long   flags;
395
396     spin_lock_irqsave(&hub_event_lock, flags);
397     if (!hub->disconnected && list_empty(&hub->event_list)) {
398         list_add_tail(&hub->event_list, &hub_event_list);
399
400         /* Suppress autosuspend until khubd runs */
401         usb_autopm_get_interface_no_resume(
402                 to_usb_interface(hub->intfdev));
403         wake_up(&khubd_wait);
404     }
405     spin_unlock_irqrestore(&hub_event_lock, flags);
406 }


这个函数将hub->event_list加入到了hub_event_list,代表有一个hub可以开始工作,剩下的任务就由usb core层来负责了。

到这里我们看到了如何将host加入到usb core,下面我们来回答之前提出的第二个问题:怎么枚举外设?

这部分工作由前面usb_init创建的守护进程khubd完成

3820 static int hub_thread(void *__unused)
3821 {
3822     /* khubd needs to be freezable to avoid intefering with USB-PERSIST
3823      * port handover.  Otherwise it might see that a full-speed device
3824      * was gone before the EHCI controller had handed its port over to
3825      * the companion full-speed controller.
3826      */
3827     set_freezable();
3828
3829     do {
3830         hub_events();
3831         wait_event_freezable(khubd_wait,
3832                 !list_empty(&hub_event_list) ||
3833                 kthread_should_stop());
3834     } while (!kthread_should_stop() || !list_empty(&hub_event_list));
3835
3836     pr_debug("%s: khubd exiting\n", usbcore_name);
3837     return 0;
3838 }


可以看出hub_thread里主要调用的是hub_events

3580 static void hub_events(void)
3581 {
...
3600     while (1) {
3601
3602         /* Grab the first entry at the beginning of the list */
3603         spin_lock_irq(&hub_event_lock);
3604         if (list_empty(&hub_event_list)) {
3605             spin_unlock_irq(&hub_event_lock);
3606             break;
3607         }
3608
3609         tmp = hub_event_list.next;
3610         list_del_init(tmp);
3611
3612         hub = list_entry(tmp, struct usb_hub, event_list);
3613         kref_get(&hub->kref);
3614         spin_unlock_irq(&hub_event_lock);
3615


这一部分是从hub_event_list中取出需要操作的hub,没错,这个正是前面在kick_khubd 中加进来的那个hub

3667         for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
3668             if (test_bit(i, hub->busy_bits))
3669                 continue;
3670             connect_change = test_bit(i, hub->change_bits);
3671             wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
3672             if (!test_and_clear_bit(i, hub->event_bits) &&
3673                     !connect_change && !wakeup_change)
3674                 continue;
3675
3676             ret = hub_port_status(hub, i,
3677                     &portstatus, &portchange);


接下来去取每一个port的status,如果状态有改变,会设置connect_change标志

3770             if (connect_change)
3771                 hub_port_connect_change(hub, i,
3772                         portstatus, portchange);


然后调用hub_port_connect_change,做的操作和host刚加进来会注册root hub类似,也是加一个usb device(例如:U盘),触发generic_probe完成枚举,在set_configuration中加入每一个interface device,对于u盘而言,只有一个interface: mass storage,于是会调用interface: mass storage的probe函数:storage_probe。
至此外设连接完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  usb linux kernel