1. 程式人生 > >linux usb列舉過程分析

linux usb列舉過程分析

當守護程式第一次執行或usb port上狀態發生變化,守護程序被喚醒都會執行hub_events函式,這個函式在usb系統中處理核心位置,usb的列舉過程就是由它完成,usb列舉過程流程圖如圖1所示;


圖1 usb列舉流程圖

         由於hub_events函式比較長這裡分幾個部分進行講解:

  1. static void hub_events(void)  
  2. {  
  3.     struct list_head *tmp;  
  4.     struct usb_device *hdev;  
  5.     struct usb_interface *intf;  
  6.     struct usb_hub *hub;  
  7.     struct device *hub_dev;  
  8.     u16 hubstatus;  
  9.     u16 hubchange;  
  10.     u16 portstatus;  
  11.     u16 portchange;  
  12.     int i, ret;  
  13.     int connect_change;  
  14.     /*  
  15.      *  We restart the list every time to avoid a deadlock with  
  16.      * deleting hubs downstream from this one. This should be  
  17.      * safe since we delete the hub from the event list.  
  18.      * Not the most efficient, but avoids deadlocks.  
  19.      */  
  20.     while (1) {  
  21.         /* Grab the first entry at the beginning of the list */  
  22.         spin_lock_irq(&hub_event_lock);  
  23.         if (list_empty(&hub_event_list)) {  
  24.             spin_unlock_irq(&hub_event_lock);  
  25.             break;  
  26.         }  
  27.         tmp = hub_event_list.next;  
  28.         list_del_init(tmp);  
  29.         hub = list_entry(tmp, struct usb_hub, event_list);  
  30.         kref_get(&hub->kref);  
  31.         spin_unlock_irq(&hub_event_lock);  
  32.         hdev = hub->hdev;  
  33.         hub_dev = hub->intfdev;  
  34.         intf = to_usb_interface(hub_dev);  
  35.         dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",  
  36.                 hdev->state, hub->descriptor  
  37.                     ? hub->descriptor->bNbrPorts  
  38.                     : 0,  
  39.                 /* NOTE: expects max 15 ports... */  
  40.                 (u16) hub->change_bits[0],  
  41.                 (u16) hub->event_bits[0]);  
  42.         /* Lock the device, then check to see if we were  
  43.          * disconnected while waiting for the lock to succeed. */  
  44.         usb_lock_device(hdev);  
  45.         if (unlikely(hub->disconnected))  
  46.             goto loop_disconnected;  
  47.         /* If the hub has died, clean up after it */  
  48.         if (hdev->state == USB_STATE_NOTATTACHED) {  
  49.             hub->error = -ENODEV;  
  50.             hub_quiesce(hub, HUB_DISCONNECT);  
  51.             goto loop;  
  52.         }  
  53.         /* Autoresume */  
  54.         ret = usb_autopm_get_interface(intf);  
  55.         if (ret) {  
  56.             dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);  
  57.             goto loop;  
  58.         }  
  59.         /* If this is an inactive hub, do nothing */  
  60.         if (hub->quiescing)  
  61.             goto loop_autopm;  
  62.         if (hub->error) {  
  63.             dev_dbg (hub_dev, "resetting for error %d\n",  
  64.                 hub->error);  
  65.             ret = usb_reset_device(hdev);  
  66.             if (ret) {  
  67.                 dev_dbg (hub_dev,  
  68.                     "error resetting hub: %d\n", ret);  
  69.                 goto loop_autopm;  
  70.             }  
  71.             hub->nerrors = 0;  
  72.             hub->error = 0;  
  73.         }  

hub_events本身也是一個死迴圈,只要條件滿足它便會一直執行。 

25-28行,判斷hub_event_list是否為空,如果為空,則跳出迴圈,hub_events執行結束,會進入休眠狀態;

31-35行,從hub_event_list列表中取出某一項,並把它從hub_event_list中刪除,通過list_entry來獲取event_list所對應的hub,並增加hub使用計數;

51-85行,做了一些邏輯判斷,判斷hub是否連線,hub上是否有錯誤,如果有錯誤就重啟hub,如果沒有錯誤,接下來就對hub 上的每個port進行掃描,判斷各個port是否發生狀態變化;

  1. for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {  
  2.             if (test_bit(i, hub->busy_bits))  
  3.                 continue;  
  4.             connect_change = test_bit(i, hub->change_bits);  
  5.             if (!test_and_clear_bit(i, hub->event_bits) &&  
  6.                     !connect_change)  
  7.                 continue;  
  8.             ret = hub_port_status(hub, i,  
  9.                     &portstatus, &portchange);  
  10.             if (ret < 0)  
  11.                 continue;  
  12.             if (portchange & USB_PORT_STAT_C_CONNECTION) {  
  13.                 clear_port_feature(hdev, i,  
  14.                     USB_PORT_FEAT_C_CONNECTION);  
  15.                 connect_change = 1;  
  16.             }  
  17.             if (portchange & USB_PORT_STAT_C_ENABLE) {  
  18.                 if (!connect_change)  
  19.                     dev_dbg (hub_dev,  
  20.                         "port %d enable change, "  
  21.                         "status %08x\n",  
  22.                         i, portstatus);  
  23.                 clear_port_feature(hdev, i,  
  24.                     USB_PORT_FEAT_C_ENABLE);  
  25.                 /*  
  26.                  * EM interference sometimes causes badly  
  27.                  * shielded USB devices to be shutdown by  
  28.                  * the hub, this hack enables them again.  
  29.                  * Works at least with mouse driver.   
  30.                  */  
  31.                 if (!(portstatus & USB_PORT_STAT_ENABLE)  
  32.                     && !connect_change  
  33.                     && hdev->children[i-1]) {  
  34.                     dev_err (hub_dev,  
  35.                         "port %i "  
  36.                         "disabled by hub (EMI?), "  
  37.                         "re-enabling...\n",  
  38.                         i);  
  39.                     connect_change = 1;  
  40.                 }  
  41.             }  
  42.             if (portchange & USB_PORT_STAT_C_SUSPEND) {  
  43.                 struct usb_device *udev;  
  44.                 clear_port_feature(hdev, i,  
  45.                     USB_PORT_FEAT_C_SUSPEND);  
  46.                 udev = hdev->children[i-1];  
  47.                 if (udev) {  
  48.                     /* TRSMRCY = 10 msec */  
  49.                     msleep(10);  
  50.                     usb_lock_device(udev);  
  51.                     ret = usb_remote_wakeup(hdev->  
  52.                             children[i-1]);  
  53.                     usb_unlock_device(udev);  
  54.                     if (ret < 0)  
  55.                         connect_change = 1;  
  56.                 } else {  
  57.                     ret = -ENODEV;  
  58.                     hub_port_disable(hub, i, 1);  
  59.                 }  
  60.                 dev_dbg (hub_dev,  
  61. 相關推薦

    no