1.    内核何时去识别一个新的usb设备
    内核运行
hub_thread线程,hub_thread等待hub_events_list不为空时调用hub_events函数,在Hub_events当中查询usb端口的状态,如状态发生变化就根据情况添加usb设备。

  1. usb_init()->usb_hub_init()                                               drivers/usb/core/usb.c
  2. usb_hub_init()->kthread_run(hub_thread……);                               drivers/usb/core/hub.c
  3. hub_thread->hub_events();                                                drivers/usb/core/hub.c
  4. hub_events->hub_port_status();                                           drivers/usb/core/hub.c
    hub_events->hub_port_connect_change();                                   drivers/usb/core/hub.c

    hub_events检测端口状态,添加usb新设备代码如下:

  1. /* deal with port status changes */
  2. for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
  3.     if (test_bit(i, hub->busy_bits))
  4.        continue;
  5.     connect_change = test_bit(i, hub->change_bits);
  6.     if (!test_and_clear_bit(i, hub->event_bits) &&
  7.         !connect_change)
  8.         continue;

  9.     ret = hub_port_status(hub, i,
  10.         &portstatus, &portchange);
  11.     ......省略
  12.     ......
  13.     if (connect_change)
  14.     hub_port_connect_change(hub, i,
  15.         portstatus, portchange);
  16. }
        hub_events的调用依赖于hub_events_list不为空,代码如下:
  1. static int hub_thread(void *__unused)
  2. {
  3.     /* khubd needs to be freezable to avoid intefering with USB-PERSIST
  4.      * port handover. Otherwise it might see that a full-speed device
  5.      * was gone before the EHCI controller had handed its port over to
  6.      * the companion full-speed controller.
  7.      */
  8.     set_freezable();

  9.     do { 
  10.         hub_events();
  11.         wait_event_freezable(khubd_wait,
  12.                 !list_empty(&hub_event_list) ||
  13.                 kthread_should_stop());
  14.     } while (!kthread_should_stop() || !list_empty(&hub_event_list));

  15.     pr_debug("%s: khubd exiting\n", usbcore_name);
  16.     return 0;
  17. }
        触发hub_events的执行就是往hub_events_list添加事件,这里指出hub_irq完成这个事情:
  1. Hub_irq()->kick_khubd(hub)                                              drivers/usb/core/hub.c
  2. kick_khubd(hub)->list_add_tail(&hub->event_list, &hub_event_list)     drivers/usb/core/hub.c

        Kick_khubd添加事件代码如下:

  1. static void kick_khubd(struct usb_hub *hub)
  2. {
  3.     unsigned long flags;

  4.     spin_lock_irqsave(&hub_event_lock, flags);
  5.     if (!hub->disconnected && list_empty(&hub->event_list)) {
  6.         list_add_tail(&hub->event_list, &hub_event_list);

  7.         /* Suppress autosuspend until khubd runs */
  8.         usb_autopm_get_interface_no_resume(
  9.                 to_usb_interface(hub->intfdev));
  10.         wake_up(&khubd_wait);
  11.     }
  12.     spin_unlock_irqrestore(&hub_event_lock, flags);
  13. }

    那么Hub_irq又是在什么时候调用的。

2.    Hub_irq是在何时被调用

    Hub_irq作为hub->urb的回调函数:usb_fill_int_urb(hub->urb......hub_irq),是在usb控制器驱动程序调用usb_add_hcd添加一个hub之后,完成usb总线匹配进而调用hub_probe来调用一系列函数之后完成回调的。

  1. Hub_probe->Hub_configure();                                              drivers/usb/core/hub.c
  2. Hub_configure()->hub_activate()                                          drivers/usb/core/hub.c
  3. Hub_activate()->usb_submit_urb(hub->urb……)                               drivers/usb/core/hub.c
  4. usb_submit_urb-> usb_hcd_submit_urb                                      drivers/usb/core/hub.c
  5. usb_hcd_submit_urb-> rh_urb_enqueue                                      drivers/usb/core/hcd.c
  6. rh_urb_enqueue-> rh_queue_status                                         drivers/usb/core/hcd.c
  7. rh_queue_status ->usb_hcd_poll_rh_status                                 drivers/usb/core/hcd.c
  8. usb_hcd_poll_rh_status ->usb_hcd_giveback_urb                            drivers/usb/core/hcd.c
  9. usb_hcd_giveback_urb->(urb->complete=hub_irq)                            drivers/usb/core/hcd.c

    在usb_hcd_poll_rh_status当中不是马上完成对usb_hcd_give_back_urb的调用的,而是在一直调用控制器提供的hub_status_data接口获取usb端口的状态,直到获取端口状态发生改变才会执行回调函数。

  1. void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
  2. {
  3.     struct urb *urb;
  4.     int length;
  5.     unsigned long flags;
  6.     char buffer[6]; /* Any root hubs with > 31 ports? */

  7.     if (unlikely(!hcd->rh_pollable))
  8.         return;
  9.     if (!hcd->uses_new_polling && !hcd->status_urb)
  10.         return;

  11.     length = hcd->driver->hub_status_data(hcd, buffer);
  12.     if (length > 0) {

  13.         /* try to complete the status urb */
  14.         spin_lock_irqsave(&hcd_root_hub_lock, flags);
  15.         urb = hcd->status_urb;
  16.         if (urb) {
  17.             clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
  18.             hcd->status_urb = NULL;
  19.             urb->actual_length = length;
  20.             memcpy(urb->transfer_buffer, buffer, length);

  21.             usb_hcd_unlink_urb_from_ep(hcd, urb);
  22.             spin_unlock(&hcd_root_hub_lock);
  23.             usb_hcd_giveback_urb(hcd, urb, 0)

3.    总结

    从整个过程来看是内核移植在等待一个事件,这个事件产生条件是:控制器驱动调用usb_add_hcd添加一个hub,触发hub_probe函数,进而submit一个urb请求,在这个请求中会间隔轮询usb的状态,一旦usb的状态发生变化则产生事件。这个事件被内核识别到,最后来获取usb相关信息,为内核添加一个usb设备。

12-04 05:55