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 }