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

posted @ 2020-07-11 11:32  Action_er  阅读(4580)  评论(0编辑  收藏  举报