linux設備驅動(27)usb驅動-熱插拔詳解


1 熱插拔的基本概念

1.1 usb熱插拔的硬件原理

在USB集線器(hub)的每個下游端口的D+和D-上,分別接了一個15K歐姆的下拉電阻到地。這樣,在集線器的端口懸空時,就被這兩個下拉電阻拉到了低電平。

而在USB設備端,在D+或者D-上接了1.5K歐姆上拉電阻。對於全速和高速設備,上拉電阻是接在D+上;而低速設備則是上拉電阻接在D-上。這樣,當設備插入到集線器時,由1.5K的上拉電阻和15K的下拉電阻分壓,結果就將差分數據線中的一條拉高了。集線器檢測到這個狀態后,它就報告給USB主控制器(或者通過它上一層的集線器報告給USB主控制器),這樣就檢測到設備的插入了。USB高速設備先是被識別為全速設備,然后通過HOST和DEVICE兩者之間的確認,再切換到高速模式的。在高速模式下,是電流傳輸模式,這時將D+上的上拉電阻斷開。

1.2 熱插拔的概念

     熱插拔(hot-plugging或Hot Swap)即帶電插拔,熱插拔功能就是允許用戶在不關閉系統,不切斷電源的情況下取出和更換損壞的硬盤、電源或板卡等部件,從而提高了系統對災難的及時恢復能力、擴展性和靈活性等,例如一些面向高端應用的磁盤鏡像系統都可以提供磁盤的熱插拔功能。具體用學術的說法就是:熱替換(Hot replacement)、熱添加(hot expansion)和熱升級(hot upgrade)

1.3 熱插拔的優點

在系統開機情況下將損壞的模塊移除,還可以在開機情況下做更新或擴容而不影響系統操作。由於熱插拔零件的可靠度提升,還可以將它們用做斷電器,而且因為熱插拔能夠自動恢復,有很多熱插拔芯片為系統提供線路供電情況的信號,以便系統做故障分析,因此減少了成本。

2 熱插拔的實現

2.1 Linux下USB HUB的驅動的實現和分析:

在系統初始化的時候在usb_init函數中調用usb_hub_init函數,就進入了hub的初始化。

在usb_hub_init函數中完成了注冊hub驅動,並且利用函數kthread_run創建一個內核線程。該線程用來管理監視hub的狀態,所有的情況都通過該線程來報告。

USB設備是熱插拔,這就和PCI設備不同,PCI設備是在系統啟動的時候都固定了,因此PCI設備只需要初始化進行枚舉就可以了,采用遞歸算法即可。而USB設備需要熱插拔,因此在hub_probe函數中調用hub_configure函數來配置hub,在這個函數中主要是利用函數usb_alloc_urb函數來分配一個urb,利用usb_fill_int_urb來初始化這個urb結構,包括hub的中斷服務程序hub_irq的,查詢的周期等。

每當有設備連接到USB接口時,USB總線在查詢hub狀態信息的時候會觸發hub的中斷服務程序hub_irq,在該函數中利用kick_khubd將hub結構通過event_list添加到khubd的隊列hub_event_list,然后喚醒khubd。進入hub_events函數,該函數用來處理khubd事件隊列,從khubd的hub_event_list中的每個usb_hub數據結構。該函數中首先判斷hub是否出錯,然后通過一個for循環來檢測每個端口的狀態信息。利用usb_port_status獲取端口信息,如果發生變化就調用hub_port_connect_change函數來配置端口等。

2.2 軟件層次分析

這里我們先講講USB熱插拔事件的處理工作。---Khubd守護進程。

-Khubd守護進程它是一個守護進程,來檢查usb port的事件通知HCD和usb core,然后做相應的處理。

主要分析khub的工作原理: 硬件層次是hub的工作,如何和host及其設備間通信及相應事件。

2.3 初始化函數

定義位於:drivers\usb\core\hub.c

 1 int usb_hub_init(void)
 2 {
 3     if (usb_register(&hub_driver) < 0) {//usb驅動注冊
 4         printk(KERN_ERR "%s: can't register hub driver\n",
 5             usbcore_name);
 6         return -1;
 7     }
 8 
 9     khubd_task = kthread_run(hub_thread, NULL, "khubd");//建立usb hub線程
10     if (!IS_ERR(khubd_task))
11         return 0;
12 
13     /* Fall through if kernel_thread failed */
14     usb_deregister(&hub_driver);
15     printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
16 
17     return -1;
18 }

2.4 usb hub線程處理函數

 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 
10     do {
11         hub_events();//執行一次hub事件函數,要想執行hub_events(),都要等待khubd_wait這個中斷喚醒才行
12         wait_event_freezable(khubd_wait,//每次執行一次hub事件,都會進入一次等待事件中斷函數
13                 !list_empty(&hub_event_list) ||
14                 kthread_should_stop());
15     } while (!kthread_should_stop() || !list_empty(&hub_event_list));//如果有事件就加入hub_event_list
16 
17     pr_debug("%s: khubd exiting\n", usbcore_name);
18     return 0;
19 }

從上面函數中得到, 要想執行hub_events(),都要等待khubd_wait這個中斷喚醒才行。

2.5 usb hub事件函數

  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, wakeup_change;
 14 
 15     /*
 16      *  We restart the list every time to avoid a deadlock with
 17      * deleting hubs downstream from this one. This should be
 18      * safe since we delete the hub from the event list.
 19      * Not the most efficient, but avoids deadlocks.
 20      */
 21     while (1) {
 22 
 23         /* Grab the first entry at the beginning of the list */
 24         spin_lock_irq(&hub_event_lock);
 25         if (list_empty(&hub_event_list)) {
 26             spin_unlock_irq(&hub_event_lock);
 27             break;
 28         }
 29 
 30         tmp = hub_event_list.next;
 31         list_del_init(tmp);
 32 
 33         hub = list_entry(tmp, struct usb_hub, event_list);
 34         kref_get(&hub->kref);
 35         hdev = hub->hdev;
 36         usb_get_dev(hdev);
 37         spin_unlock_irq(&hub_event_lock);
 38 
 39         hub_dev = hub->intfdev;
 40         intf = to_usb_interface(hub_dev);
 41         dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
 42                 hdev->state, hub->descriptor
 43                     ? hub->descriptor->bNbrPorts
 44                     : 0,
 45                 /* NOTE: expects max 15 ports... */
 46                 (u16) hub->change_bits[0],
 47                 (u16) hub->event_bits[0]);
 48 
 49         /* Lock the device, then check to see if we were
 50          * disconnected while waiting for the lock to succeed. */
 51         usb_lock_device(hdev);
 52         if (unlikely(hub->disconnected))
 53             goto loop_disconnected;
 54 
 55         /* If the hub has died, clean up after it */
 56         if (hdev->state == USB_STATE_NOTATTACHED) {
 57             hub->error = -ENODEV;
 58             hub_quiesce(hub, HUB_DISCONNECT);
 59             goto loop;
 60         }
 61 
 62         /* Autoresume */
 63         ret = usb_autopm_get_interface(intf);
 64         if (ret) {
 65             dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
 66             goto loop;
 67         }
 68 
 69         /* If this is an inactive hub, do nothing */
 70         if (hub->quiescing)
 71             goto loop_autopm;
 72 
 73         if (hub->error) {
 74             dev_dbg (hub_dev, "resetting for error %d\n",
 75                 hub->error);
 76 
 77             ret = usb_reset_device(hdev);
 78             if (ret) {
 79                 dev_dbg (hub_dev,
 80                     "error resetting hub: %d\n", ret);
 81                 goto loop_autopm;
 82             }
 83 
 84             hub->nerrors = 0;
 85             hub->error = 0;
 86         }
 87 
 88         /* deal with port status changes */
 89         for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
 90             if (test_bit(i, hub->busy_bits))
 91                 continue;
 92             connect_change = test_bit(i, hub->change_bits);
 93             wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
 94             if (!test_and_clear_bit(i, hub->event_bits) &&
 95                     !connect_change && !wakeup_change)
 96                 continue;
 97 
 98             ret = hub_port_status(hub, i,
 99                     &portstatus, &portchange);
100             if (ret < 0)
101                 continue;
102 
103             if (portchange & USB_PORT_STAT_C_CONNECTION) {
104                 usb_clear_port_feature(hdev, i,
105                     USB_PORT_FEAT_C_CONNECTION);
106                 connect_change = 1;
107             }
108 
109             if (portchange & USB_PORT_STAT_C_ENABLE) {
110                 if (!connect_change)
111                     dev_dbg (hub_dev,
112                         "port %d enable change, "
113                         "status %08x\n",
114                         i, portstatus);
115                 usb_clear_port_feature(hdev, i,
116                     USB_PORT_FEAT_C_ENABLE);
117 
118                 /*
119                  * EM interference sometimes causes badly
120                  * shielded USB devices to be shutdown by
121                  * the hub, this hack enables them again.
122                  * Works at least with mouse driver. 
123                  */
124                 if (!(portstatus & USB_PORT_STAT_ENABLE)
125                     && !connect_change
126                     && hub->ports[i - 1]->child) {
127                     dev_err (hub_dev,
128                         "port %i "
129                         "disabled by hub (EMI?), "
130                         "re-enabling...\n",
131                         i);
132                     connect_change = 1;
133                 }
134             }
135 
136             if (hub_handle_remote_wakeup(hub, i,
137                         portstatus, portchange))
138                 connect_change = 1;
139 
140             if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
141                 u16 status = 0;
142                 u16 unused;
143 
144                 dev_dbg(hub_dev, "over-current change on port "
145                     "%d\n", i);
146                 usb_clear_port_feature(hdev, i,
147                     USB_PORT_FEAT_C_OVER_CURRENT);
148                 msleep(100);    /* Cool down */
149                 hub_power_on(hub, true);
150                 hub_port_status(hub, i, &status, &unused);
151                 if (status & USB_PORT_STAT_OVERCURRENT)
152                     dev_err(hub_dev, "over-current "
153                         "condition on port %d\n", i);
154             }
155 
156             if (portchange & USB_PORT_STAT_C_RESET) {
157                 dev_dbg (hub_dev,
158                     "reset change on port %d\n",
159                     i);
160                 usb_clear_port_feature(hdev, i,
161                     USB_PORT_FEAT_C_RESET);
162             }
163             if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
164                     hub_is_superspeed(hub->hdev)) {
165                 dev_dbg(hub_dev,
166                     "warm reset change on port %d\n",
167                     i);
168                 usb_clear_port_feature(hdev, i,
169                     USB_PORT_FEAT_C_BH_PORT_RESET);
170             }
171             if (portchange & USB_PORT_STAT_C_LINK_STATE) {
172                 usb_clear_port_feature(hub->hdev, i,
173                         USB_PORT_FEAT_C_PORT_LINK_STATE);
174             }
175             if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
176                 dev_warn(hub_dev,
177                     "config error on port %d\n",
178                     i);
179                 usb_clear_port_feature(hub->hdev, i,
180                         USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
181             }
182 
183             /* Warm reset a USB3 protocol port if it's in
184              * SS.Inactive state.
185              */
186             if (hub_port_warm_reset_required(hub, portstatus)) {
187                 int status;
188                 struct usb_device *udev =
189                     hub->ports[i - 1]->child;
190 
191                 dev_dbg(hub_dev, "warm reset port %d\n", i);
192                 if (!udev ||
193                     !(portstatus & USB_PORT_STAT_CONNECTION) ||
194                     udev->state == USB_STATE_NOTATTACHED) {
195                     status = hub_port_reset(hub, i,
196                             NULL, HUB_BH_RESET_TIME,
197                             true);
198                     if (status < 0)
199                         hub_port_disable(hub, i, 1);
200                 } else {
201                     usb_lock_device(udev);
202                     status = usb_reset_device(udev);
203                     usb_unlock_device(udev);
204                     connect_change = 0;
205                 }
206             }
207 
208             if (connect_change)//檢測到port狀態變化,調用以下的函數連接端口
209                 hub_port_connect_change(hub, i,
210                         portstatus, portchange);
211         } /* end for i */
212 
213         /* deal with hub status changes */
214         if (test_and_clear_bit(0, hub->event_bits) == 0)
215             ;    /* do nothing */
216         else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
217             dev_err (hub_dev, "get_hub_status failed\n");
218         else {
219             if (hubchange & HUB_CHANGE_LOCAL_POWER) {
220                 dev_dbg (hub_dev, "power change\n");
221                 clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
222                 if (hubstatus & HUB_STATUS_LOCAL_POWER)
223                     /* FIXME: Is this always true? */
224                     hub->limited_power = 1;
225                 else
226                     hub->limited_power = 0;
227             }
228             if (hubchange & HUB_CHANGE_OVERCURRENT) {
229                 u16 status = 0;
230                 u16 unused;
231 
232                 dev_dbg(hub_dev, "over-current change\n");
233                 clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
234                 msleep(500);    /* Cool down */
235                             hub_power_on(hub, true);
236                 hub_hub_status(hub, &status, &unused);
237                 if (status & HUB_STATUS_OVERCURRENT)
238                     dev_err(hub_dev, "over-current "
239                         "condition\n");
240             }
241         }
242 
243  loop_autopm:
244         /* Balance the usb_autopm_get_interface() above */
245         usb_autopm_put_interface_no_suspend(intf);
246  loop:
247         /* Balance the usb_autopm_get_interface_no_resume() in
248          * kick_khubd() and allow autosuspend.
249          */
250         usb_autopm_put_interface(intf);
251  loop_disconnected:
252         usb_unlock_device(hdev);
253         usb_put_dev(hdev);
254         kref_put(&hub->kref, hub_release);
255 
256         } /* end while (1) */
257 }

2.6 函數hub_port_connect_change

作用是連接端口。

  1 static void hub_port_connect_change(struct usb_hub *hub, int port1,
  2                     u16 portstatus, u16 portchange)
  3 {
  4     struct usb_device *hdev = hub->hdev;
  5     struct device *hub_dev = hub->intfdev;
  6     struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
  7     unsigned wHubCharacteristics =
  8             le16_to_cpu(hub->descriptor->wHubCharacteristics);
  9     struct usb_device *udev;
 10     int status, i;
 11     unsigned unit_load;
 12 
 13     dev_dbg (hub_dev,
 14         "port %d, status %04x, change %04x, %s\n",
 15         port1, portstatus, portchange, portspeed(hub, portstatus));
 16 
 17     if (hub->has_indicators) {
 18         set_port_led(hub, port1, HUB_LED_AUTO);
 19         hub->indicator[port1-1] = INDICATOR_AUTO;
 20     }
 21 
 22 #ifdef    CONFIG_USB_OTG
 23     /* during HNP, don't repeat the debounce */
 24     if (hdev->bus->is_b_host)
 25         portchange &= ~(USB_PORT_STAT_C_CONNECTION |
 26                 USB_PORT_STAT_C_ENABLE);
 27 #endif
 28 
 29     /* Try to resuscitate an existing device */
 30     udev = hub->ports[port1 - 1]->child;
 31     if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
 32             udev->state != USB_STATE_NOTATTACHED) {
 33         usb_lock_device(udev);
 34         if (portstatus & USB_PORT_STAT_ENABLE) {
 35             status = 0;        /* Nothing to do */
 36 
 37 #ifdef CONFIG_PM_RUNTIME
 38         } else if (udev->state == USB_STATE_SUSPENDED &&
 39                 udev->persist_enabled) {
 40             /* For a suspended device, treat this as a
 41              * remote wakeup event.
 42              */
 43             status = usb_remote_wakeup(udev);
 44 #endif
 45 
 46         } else {
 47             status = -ENODEV;    /* Don't resuscitate */
 48         }
 49         usb_unlock_device(udev);
 50 
 51         if (status == 0) {
 52             clear_bit(port1, hub->change_bits);
 53             return;
 54         }
 55     }
 56 
 57     /* Disconnect any existing devices under this port */
 58     if (udev) {
 59         if (hcd->phy && !hdev->parent &&
 60                 !(portstatus & USB_PORT_STAT_CONNECTION))
 61             usb_phy_notify_disconnect(hcd->phy, udev->speed);
 62         usb_disconnect(&hub->ports[port1 - 1]->child);
 63     }
 64     clear_bit(port1, hub->change_bits);
 65 
 66     /* We can forget about a "removed" device when there's a physical
 67      * disconnect or the connect status changes.
 68      */
 69     if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
 70             (portchange & USB_PORT_STAT_C_CONNECTION))
 71         clear_bit(port1, hub->removed_bits);
 72 
 73     if (portchange & (USB_PORT_STAT_C_CONNECTION |
 74                 USB_PORT_STAT_C_ENABLE)) {
 75         status = hub_port_debounce_be_stable(hub, port1);
 76         if (status < 0) {
 77             if (status != -ENODEV && printk_ratelimit())
 78                 dev_err(hub_dev, "connect-debounce failed, "
 79                         "port %d disabled\n", port1);
 80             portstatus &= ~USB_PORT_STAT_CONNECTION;
 81         } else {
 82             portstatus = status;
 83         }
 84     }
 85 
 86     /* Return now if debouncing failed or nothing is connected or
 87      * the device was "removed".
 88      */
 89     if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
 90             test_bit(port1, hub->removed_bits)) {
 91 
 92         /* maybe switch power back on (e.g. root hub was reset) */
 93         if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
 94                 && !port_is_power_on(hub, portstatus))
 95             set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 96 
 97         if (portstatus & USB_PORT_STAT_ENABLE)
 98               goto done;
 99         return;
100     }
101     if (hub_is_superspeed(hub->hdev))
102         unit_load = 150;
103     else
104         unit_load = 100;
105 
106     status = 0;
107     for (i = 0; i < SET_CONFIG_TRIES; i++) {
108 
109         /* reallocate for each attempt, since references
110          * to the previous one can escape in various ways
111          */
112         udev = usb_alloc_dev(hdev, hdev->bus, port1);//注冊一個usb_device,然后會放在usb總線上
113         if (!udev) {
114             dev_err (hub_dev,
115                 "couldn't allocate port %d usb_device\n",
116                 port1);
117             goto done;
118         }
119 
120         usb_set_device_state(udev, USB_STATE_POWERED);//設置注冊的USB設備的狀態標志
121          udev->bus_mA = hub->mA_per_port;
122         udev->level = hdev->level + 1;
123         udev->wusb = hub_is_wusb(hub);
124 
125         /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
126         if (hub_is_superspeed(hub->hdev))
127             udev->speed = USB_SPEED_SUPER;
128         else
129             udev->speed = USB_SPEED_UNKNOWN;
130 
131         choose_devnum(udev);
132         if (udev->devnum <= 0) {
133             status = -ENOTCONN;    /* Don't retry */
134             goto loop;
135         }
136 
137         /* reset (non-USB 3.0 devices) and get descriptor */
138         status = hub_port_init(hub, udev, port1, i);//初始化端口,與USB設備建立連接
139         if (status < 0)
140             goto loop;
141 
142         usb_detect_quirks(udev);
143         if (udev->quirks & USB_QUIRK_DELAY_INIT)
144             msleep(1000);
145 
146         /* consecutive bus-powered hubs aren't reliable; they can
147          * violate the voltage drop budget.  if the new child has
148          * a "powered" LED, users should notice we didn't enable it
149          * (without reading syslog), even without per-port LEDs
150          * on the parent.
151          */
152         if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
153                 && udev->bus_mA <= unit_load) {
154             u16    devstat;
155 
156             status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
157                     &devstat);
158             if (status < 2) {
159                 dev_dbg(&udev->dev, "get status %d ?\n", status);
160                 goto loop_disable;
161             }
162             le16_to_cpus(&devstat);
163             if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
164                 dev_err(&udev->dev,
165                     "can't connect bus-powered hub "
166                     "to this port\n");
167                 if (hub->has_indicators) {
168                     hub->indicator[port1-1] =
169                         INDICATOR_AMBER_BLINK;
170                     schedule_delayed_work (&hub->leds, 0);
171                 }
172                 status = -ENOTCONN;    /* Don't retry */
173                 goto loop_disable;
174             }
175         }
176  
177         /* check for devices running slower than they could */
178         if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
179                 && udev->speed == USB_SPEED_FULL
180                 && highspeed_hubs != 0)
181             check_highspeed (hub, udev, port1);
182 
183         /* Store the parent's children[] pointer.  At this point
184          * udev becomes globally accessible, although presumably
185          * no one will look at it until hdev is unlocked.
186          */
187         status = 0;
188 
189         /* We mustn't add new devices if the parent hub has
190          * been disconnected; we would race with the
191          * recursively_mark_NOTATTACHED() routine.
192          */
193         spin_lock_irq(&device_state_lock);
194         if (hdev->state == USB_STATE_NOTATTACHED)
195             status = -ENOTCONN;
196         else
197             hub->ports[port1 - 1]->child = udev;
198         spin_unlock_irq(&device_state_lock);
199 
200         /* Run it through the hoops (find a driver, etc) */
201         if (!status) {
202             status = usb_new_device(udev);//創建USB設備,與USB設備驅動連接
203             if (status) {
204                 spin_lock_irq(&device_state_lock);
205                 hub->ports[port1 - 1]->child = NULL;
206                 spin_unlock_irq(&device_state_lock);
207             }
208         }
209 
210         if (status)
211             goto loop_disable;
212 
213         status = hub_power_remaining(hub);
214         if (status)
215             dev_dbg(hub_dev, "%dmA power budget left\n", status);
216 
217         return;
218 
219 loop_disable:
220         hub_port_disable(hub, port1, 1);
221 loop:
222         usb_ep0_reinit(udev);
223         release_devnum(udev);
224         hub_free_dev(udev);
225         usb_put_dev(udev);
226         if ((status == -ENOTCONN) || (status == -ENOTSUPP))
227             break;
228     }
229     if (hub->hdev->parent ||
230             !hcd->driver->port_handed_over ||
231             !(hcd->driver->port_handed_over)(hcd, port1)) {
232         if (status != -ENOTCONN && status != -ENODEV)
233             dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
234                     port1);
235     }
236  
237 done:
238     hub_port_disable(hub, port1, 1);
239     if (hcd->driver->relinquish_port && !hub->hdev->parent)
240         hcd->driver->relinquish_port(hcd, port1);
241 }

2.7 函數usb_alloc_dev

分配usb設備,詳解見:linux設備驅動(26)usb驅動-基本數據和api 2.3節

2.8 函數hub_port_init

初始化端口,與設備連接

  1 static int
  2 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
  3         int retry_counter)
  4 {
  5     static DEFINE_MUTEX(usb_address0_mutex);
  6 
  7     struct usb_device    *hdev = hub->hdev;
  8     struct usb_hcd        *hcd = bus_to_hcd(hdev->bus);
  9     int            i, j, retval;
 10     unsigned        delay = HUB_SHORT_RESET_TIME;
 11     enum usb_device_speed    oldspeed = udev->speed;
 12     const char        *speed;
 13     int            devnum = udev->devnum;
 14 
 15     /* root hub ports have a slightly longer reset period
 16      * (from USB 2.0 spec, section 7.1.7.5)
 17      */
 18     if (!hdev->parent) {
 19         delay = HUB_ROOT_RESET_TIME;
 20         if (port1 == hdev->bus->otg_port)
 21             hdev->bus->b_hnp_enable = 0;
 22     }
 23 
 24     /* Some low speed devices have problems with the quick delay, so */
 25     /*  be a bit pessimistic with those devices. RHbug #23670 */
 26     if (oldspeed == USB_SPEED_LOW)
 27         delay = HUB_LONG_RESET_TIME;
 28 
 29     mutex_lock(&usb_address0_mutex);
 30 
 31     /* Reset the device; full speed may morph to high speed */
 32     /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
 33     retval = hub_port_reset(hub, port1, udev, delay, false);
 34     if (retval < 0)        /* error or disconnect */
 35         goto fail;
 36     /* success, speed is known */
 37 
 38     retval = -ENODEV;
 39 
 40     if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
 41         dev_dbg(&udev->dev, "device reset changed speed!\n");
 42         goto fail;
 43     }
 44     oldspeed = udev->speed;
 45 
 46     /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 47      * it's fixed size except for full speed devices.
 48      * For Wireless USB devices, ep0 max packet is always 512 (tho
 49      * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
 50      */
 51     switch (udev->speed) {
 52     case USB_SPEED_SUPER:
 53     case USB_SPEED_WIRELESS:    /* fixed at 512 */
 54         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
 55         break;
 56     case USB_SPEED_HIGH:        /* fixed at 64 */
 57         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
 58         break;
 59     case USB_SPEED_FULL:        /* 8, 16, 32, or 64 */
 60         /* to determine the ep0 maxpacket size, try to read
 61          * the device descriptor to get bMaxPacketSize0 and
 62          * then correct our initial guess.
 63          */
 64         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
 65         break;
 66     case USB_SPEED_LOW:        /* fixed at 8 */
 67         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
 68         break;
 69     default:
 70         goto fail;
 71     }
 72 
 73     if (udev->speed == USB_SPEED_WIRELESS)
 74         speed = "variable speed Wireless";
 75     else
 76         speed = usb_speed_string(udev->speed);
 77 
 78     if (udev->speed != USB_SPEED_SUPER)
 79         dev_info(&udev->dev,
 80                 "%s %s USB device number %d using %s\n",
 81                 (udev->config) ? "reset" : "new", speed,
 82                 devnum, udev->bus->controller->driver->name);
 83 
 84     /* Set up TT records, if needed  */
 85     if (hdev->tt) {
 86         udev->tt = hdev->tt;
 87         udev->ttport = hdev->ttport;
 88     } else if (udev->speed != USB_SPEED_HIGH
 89             && hdev->speed == USB_SPEED_HIGH) {
 90         if (!hub->tt.hub) {
 91             dev_err(&udev->dev, "parent hub has no TT\n");
 92             retval = -EINVAL;
 93             goto fail;
 94         }
 95         udev->tt = &hub->tt;
 96         udev->ttport = port1;
 97     }
 98  
 99     /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
100      * Because device hardware and firmware is sometimes buggy in
101      * this area, and this is how Linux has done it for ages.
102      * Change it cautiously.
103      *
104      * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing
105      * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,
106      * so it may help with some non-standards-compliant devices.
107      * Otherwise we start with SET_ADDRESS and then try to read the
108      * first 8 bytes of the device descriptor to get the ep0 maxpacket
109      * value.
110      */
111     for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
112         if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
113             struct usb_device_descriptor *buf;
114             int r = 0;
115 
116 #define GET_DESCRIPTOR_BUFSIZE    64
117             buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
118             if (!buf) {
119                 retval = -ENOMEM;
120                 continue;
121             }
122 
123             /* Retry on all errors; some devices are flakey.
124              * 255 is for WUSB devices, we actually need to use
125              * 512 (WUSB1.0[4.8.1]).
126              */
127             for (j = 0; j < 3; ++j) {
128                 buf->bMaxPacketSize0 = 0;
129                 r = usb_control_msg(udev, usb_rcvaddr0pipe(),
130                     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
131                     USB_DT_DEVICE << 8, 0,
132                     buf, GET_DESCRIPTOR_BUFSIZE,
133                     initial_descriptor_timeout);
134                 switch (buf->bMaxPacketSize0) {
135                 case 8: case 16: case 32: case 64: case 255:
136                     if (buf->bDescriptorType ==
137                             USB_DT_DEVICE) {
138                         r = 0;
139                         break;
140                     }
141                     /* FALL THROUGH */
142                 default:
143                     if (r == 0)
144                         r = -EPROTO;
145                     break;
146                 }
147                 if (r == 0)
148                     break;
149             }
150             udev->descriptor.bMaxPacketSize0 =
151                     buf->bMaxPacketSize0;
152             kfree(buf);
153 
154             retval = hub_port_reset(hub, port1, udev, delay, false);
155             if (retval < 0)        /* error or disconnect */
156                 goto fail;
157             if (oldspeed != udev->speed) {
158                 dev_dbg(&udev->dev,
159                     "device reset changed speed!\n");
160                 retval = -ENODEV;
161                 goto fail;
162             }
163             if (r) {
164                 if (r != -ENODEV)
165                     dev_err(&udev->dev, "device descriptor read/64, error %d\n",
166                             r);
167                 retval = -EMSGSIZE;
168                 continue;
169             }
170 #undef GET_DESCRIPTOR_BUFSIZE
171         }
172 
173          /*
174           * If device is WUSB, we already assigned an
175           * unauthorized address in the Connect Ack sequence;
176           * authorization will assign the final address.
177           */
178         if (udev->wusb == 0) {
179             for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
180                 retval = hub_set_address(udev, devnum);//設置地址,告訴USB設備新的地址編號
181                 if (retval >= 0)
182                     break;
183                 msleep(200);
184             }
185             if (retval < 0) {
186                 if (retval != -ENODEV)
187                     dev_err(&udev->dev, "device not accepting address %d, error %d\n",
188                             devnum, retval);
189                 goto fail;
190             }
191             if (udev->speed == USB_SPEED_SUPER) {
192                 devnum = udev->devnum;
193                 dev_info(&udev->dev,
194                         "%s SuperSpeed USB device number %d using %s\n",
195                         (udev->config) ? "reset" : "new",
196                         devnum, udev->bus->controller->driver->name);
197             }
198 
199             /* cope with hardware quirkiness:
200              *  - let SET_ADDRESS settle, some device hardware wants it
201              *  - read ep0 maxpacket even for high and low speed,
202              */
203             msleep(10);
204             if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
205                 break;
206           }
207 
208         retval = usb_get_device_descriptor(udev, 8);//獲得USB設備描述符前8個字節
209         if (retval < 8) {
210             if (retval != -ENODEV)
211                 dev_err(&udev->dev,
212                     "device descriptor read/8, error %d\n",
213                     retval);
214             if (retval >= 0)
215                 retval = -EMSGSIZE;
216         } else {
217             retval = 0;
218             break;
219         }
220     }
221     if (retval)
222         goto fail;
223 
224     if (hcd->phy && !hdev->parent)
225         usb_phy_notify_connect(hcd->phy, udev->speed);
226 
227     /*
228      * Some superspeed devices have finished the link training process
229      * and attached to a superspeed hub port, but the device descriptor
230      * got from those devices show they aren't superspeed devices. Warm
231      * reset the port attached by the devices can fix them.
232      */
233     if ((udev->speed == USB_SPEED_SUPER) &&
234             (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
235         dev_err(&udev->dev, "got a wrong device descriptor, "
236                 "warm reset device\n");
237         hub_port_reset(hub, port1, udev,
238                 HUB_BH_RESET_TIME, true);
239         retval = -EINVAL;
240         goto fail;
241     }
242 
243     if (udev->descriptor.bMaxPacketSize0 == 0xff ||
244             udev->speed == USB_SPEED_SUPER)
245         i = 512;
246     else
247         i = udev->descriptor.bMaxPacketSize0;
248     if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
249         if (udev->speed == USB_SPEED_LOW ||
250                 !(i == 8 || i == 16 || i == 32 || i == 64)) {
251             dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
252             retval = -EMSGSIZE;
253             goto fail;
254         }
255         if (udev->speed == USB_SPEED_FULL)
256             dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
257         else
258             dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
259         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
260         usb_ep0_reinit(udev);
261     }
262   
263     retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);//重新獲取設備描述符信息
264     if (retval < (signed)sizeof(udev->descriptor)) {
265         if (retval != -ENODEV)
266             dev_err(&udev->dev, "device descriptor read/all, error %d\n",
267                     retval);
268         if (retval >= 0)
269             retval = -ENOMSG;
270         goto fail;
271     }
272 
273     if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
274         retval = usb_get_bos_descriptor(udev);
275         if (!retval) {
276             udev->lpm_capable = usb_device_supports_lpm(udev);
277             usb_set_lpm_parameters(udev);
278         }
279     }
280 
281     retval = 0;
282     /* notify HCD that we have a device connected and addressed */
283     if (hcd->driver->update_device)
284         hcd->driver->update_device(hcd, udev);
285 fail:
286     if (retval) {
287         hub_port_disable(hub, port1, 0);
288         update_devnum(udev, devnum);    /* for disconnect processing */
289     }
290     mutex_unlock(&usb_address0_mutex);
291     return retval;
292 }

2.9 函數hub_set_address

主要是用來告訴USB設備新的地址編號, hub_set_address()函數如下:

 1 static int hub_set_address(struct usb_device *udev, int devnum)
 2 {
 3     int retval;
 4     struct usb_hcd *hcd = bus_to_hcd(udev->bus);
 5 
 6     /*
 7      * The host controller will choose the device address,
 8      * instead of the core having chosen it earlier
 9      */
10     if (!hcd->driver->address_device && devnum <= 1)
11         return -EINVAL;
12     if (udev->state == USB_STATE_ADDRESS)
13         return 0;
14     if (udev->state != USB_STATE_DEFAULT)
15         return -EINVAL;
16     if (hcd->driver->address_device)
17         retval = hcd->driver->address_device(hcd, udev);
18     else
19         retval = usb_contrl_msg(udev, usb_sndaddr0pipe(),、//等待傳輸完成
20                 USB_REQ_SET_ADDRESS, 0, devnum, 0,
21                 NULL, 0, USB_CTRL_SET_TIMEOUT);
22     if (retval == 0) {//設置新的地址,傳輸完成,返回0
23         update_devnum(udev, devnum);
24         /* Device now using proper address. */
25         usb_set_device_state(udev, USB_STATE_ADDRESS);//設置狀態標志
26         usb_ep0_reinit(udev);
27     }
28     return retval;
29 }

 usb_control_msg()函數就是用來讓USB主機控制器把一個控制報文發給USB設備,如果傳輸完成就返回0.其中參數udev表示目標設備;使用的管道為usb_sndaddr0pipe(),也就是默認的地址0加上控制端點號0; USB_REQ_SET_ADDRESS表示命令碼,既設置地址; udev->devnum表示要設置目標設備的設備號;允許等待傳輸完成的時間為5秒,因為USB_CTRL_SET_TIMEOUT定義為5000。

usb_get_device_descriptor()函數主要是獲取目標設備描述符前8個字節,為什么先只開始讀取8個字節?是因為開始時還不知道對方所支持的信包容量,這8個字節是每個設備都有的,后面再根據設備的數據,通過usb_get_device_descriptor()重讀一次目標設備的設備描述結構.。

2.10 函數usb_new_device()

來創建USB設備的

 1 int usb_new_device(struct usb_device *udev)
 2 {
 3     int err;
 4 
 5     if (udev->parent) {
 6         /* Initialize non-root-hub device wakeup to disabled;
 7          * device (un)configuration controls wakeup capable
 8          * sysfs power/wakeup controls wakeup enabled/disabled
 9          */
10         device_init_wakeup(&udev->dev, 0);
11     }
12 
13     /* Tell the runtime-PM framework the device is active */
14     pm_runtime_set_active(&udev->dev);
15     pm_runtime_get_noresume(&udev->dev);
16     pm_runtime_use_autosuspend(&udev->dev);
17     pm_runtime_enable(&udev->dev);
18 
19     /* By default, forbid autosuspend for all devices.  It will be
20      * allowed for hubs during binding.
21      */
22     usb_disable_autosuspend(udev);
23 
24     err = usb_enumerate_device(udev);    /* Read descriptors *///讀取usb設備配置
25     if (err < 0)
26         goto fail;
27     dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
28             udev->devnum, udev->bus->busnum,
29             (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
30     /* export the usbdev device-node for libusb */
31     udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
32             (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
33 
34     /* Tell the world! */
35     announce_device(udev);
36 
37     if (udev->serial)
38         add_device_randomness(udev->serial, strlen(udev->serial));
39     if (udev->product)
40         add_device_randomness(udev->product, strlen(udev->product));
41     if (udev->manufacturer)
42         add_device_randomness(udev->manufacturer,
43                       strlen(udev->manufacturer));
44 
45     device_enable_async_suspend(&udev->dev);
46 
47     /*
48      * check whether the hub marks this port as non-removable. Do it
49      * now so that platform-specific data can override it in
50      * device_add()
51      */
52     if (udev->parent)
53         set_usb_port_removable(udev);
54 
55     /* Register the device.  The device driver is responsible
56      * for configuring the device and invoking the add-device
57      * notifier chain (used by usbfs and possibly others).
58      */
59     err = device_add(&udev->dev);//添加usb設備
60     if (err) {
61         dev_err(&udev->dev, "can't device_add, error %d\n", err);
62         goto fail;
63     }
64 
65     /* Create link files between child device and usb port device. */
66     if (udev->parent) {
67         struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
68         struct usb_port    *port_dev = hub->ports[udev->portnum - 1];
69 
70         err = sysfs_create_link(&udev->dev.kobj,
71                 &port_dev->dev.kobj, "port");
72         if (err)
73             goto fail;
74 
75         err = sysfs_create_link(&port_dev->dev.kobj,
76                 &udev->dev.kobj, "device");
77         if (err) {
78             sysfs_remove_link(&udev->dev.kobj, "port");
79             goto fail;
80         }
81 
82         pm_runtime_get_sync(&port_dev->dev);
83     }
84 
85     (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
86     usb_mark_last_busy(udev);
87     pm_runtime_put_sync_autosuspend(&udev->dev);
88     return err;
89 
90 fail:
91     usb_set_device_state(udev, USB_STATE_NOTATTACHED);
92     pm_runtime_disable(&udev->dev);
93     pm_runtime_set_suspended(&udev->dev);
94     return err;
95 }

2.11 函數usb_enumerate_device

 1 static int usb_enumerate_device(struct usb_device *udev)
 2 {
 3     int err;
 4 
 5     if (udev->config == NULL) {
 6         err = usb_get_configuration(udev);//獲取配置描述符,具體定義位於drivers\usb\core\config.c
 7         if (err < 0) {
 8             if (err != -ENODEV)
 9                 dev_err(&udev->dev, "can't read configurations, error %d\n",
10                         err);
11             return err;
12         }
13     }
14 
15     /* read the standard strings and cache them if present */
16     udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
17     udev->manufacturer = usb_cache_string(udev,
18                           udev->descriptor.iManufacturer);
19     udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
20 
21     err = usb_enumerate_device_otg(udev);
22     if (err < 0)
23         return err;
24 
25     usb_detect_interface_quirks(udev);
26 
27     return 0;
28 }

2.12 函數usb_get_configuration

就是獲取配置描述符

 1 int   usb_get_configuration(struct usb_device *dev)
 2 {
 3   ... ...
 4   /* USB_MAXCONFIG 定義為8,表示設備描述塊下有最多不能超過8個配置描述塊 */
 5   /*ncfg表示 設備描述塊下 有多少個配置描述塊 */
 6 if (ncfg > USB_MAXCONFIG) {
 7               dev_warn(ddev, "too many configurations: %d, "
 8                   "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
 9               dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
10        }
11   ... ...
12   for (cfgno = 0; cfgno < ncfg; cfgno++)   //for循環,從USB設備里依次讀入所有配置描述塊
13   {
14       result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,buffer, USB_DT_CONFIG_SIZE);
15                               //每次先讀取USB_DT_CONFIG_SIZE個字節,也就是9個字節,暫放到buffer中
16       ... ...
17 
18       length = max((int) le16_to_cpu(desc->wTotalLength),USB_DT_CONFIG_SIZE);
19                   //通過wTotalLength,知道實際數據大小
20 
21       bigbuffer = kmalloc(length, GFP_KERNEL);  //然后再來分配足夠大的空間
22       ... ...
23 
24       result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,bigbuffer, length);
25                              //在調用一次usb_get_descriptor,把整個配置描述塊讀出來,放到bigbuffer中
26       ... ...
27 
28       dev->rawdescriptors[cfgno] = bigbuffer;   //再將bigbuffer地址放在rawdescriptors所指的指針數組中
29 
30       result = usb_parse_configuration(&dev->dev, cfgno,&dev->config[cfgno],
31 
32     bigbuffer, length);         //最后在解析每個配置塊
33 
34 }
35   ... ...
36 }

參考博文:https://blog.csdn.net/zqixiao_09/article/details/51056903

https://www.cnblogs.com/lifexy/p/7631900.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM