医生,请把孩子取出来之后,顺便给我吸吸脂.
——广州一妇女在剖腹产手术前对医生说.
对于控制传输,rh_call_control会被调用.我也特别希望能有人给这个函数吸吸脂,我们的上下文是为了获取设备描述符,即当初那个usb_get_device_descriptor领着我们来到了这个函数,为了完成这件事情,实际上只需要很少的代码,但是rh_call_control这个函数涉及了所有的Root Hub相关的控制传输,以至于我们除了把孩子取出来之外,还不得不顺便看看其它的代码.当然了,既然是顺便,那么我们也就不会详细的去讲解每一行.这个函数定义于drivers/usb/core/hcd.c:
343 /* Root hub control transfers execute synchronously */
344 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
345 {
346 struct usb_ctrlrequest *cmd;
347 u16 typeReq, wValue, wIndex, wLength;
348 u8 *ubuf = urb->transfer_buffer;
349 u8 tbuf [sizeof (struct usb_hub_descriptor)]
350 __attribute__((aligned(4)));
351 const u8 *bufp = tbuf;
352 int len = 0;
353 int patch_wakeup = 0;
354 unsigned long flags;
355 int status = 0;
356 int n;
357
358 cmd = (struct usb_ctrlrequest *) urb->setup_packet;
359 typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
360 wValue = le16_to_cpu (cmd->wValue);
361 wIndex = le16_to_cpu (cmd->wIndex);
362 wLength = le16_to_cpu (cmd->wLength);
363
364 if (wLength > urb->transfer_buffer_length)
365 goto error;
366
367 urb->actual_length = 0;
368 switch (typeReq) {
369
370 /* DEVICE REQUESTS */
371
372 /* The root hub's remote wakeup enable bit is implemented using
373 * driver model wakeup flags. If this system supports wakeup
374 * through USB, userspace may change the default "allow wakeup"
375 * policy through sysfs or these calls.
376 *
377 * Most root hubs support wakeup from downstream devices, for
378 * runtime power management (disabling USB clocks and reducing
379 * VBUS power usage). However, not all of them do so; silicon,
380 * board, and BIOS bugs here are not uncommon, so these can't
381 * be treated quite like external hubs.
382 *
383 * Likewise, not all root hubs will pass wakeup events upstream,
384 * to wake up the whole system. So don't assume root hub and
385 * controller capabilities are identical.
386 */
387
388 case DeviceRequest | USB_REQ_GET_STATUS:
389 tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
390 << USB_DEVICE_REMOTE_WAKEUP)
391 | (1 << USB_DEVICE_SELF_POWERED);
392 tbuf [1] = 0;
393 len = 2;
394 break;
395 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
396 if (wValue == USB_DEVICE_REMOTE_WAKEUP)
397 device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
398 else
399 goto error;
400 break;
401 case DeviceOutRequest | USB_REQ_SET_FEATURE:
402 if (device_can_wakeup(&hcd->self.root_hub->dev)
403 && wValue == USB_DEVICE_REMOTE_WAKEUP)
404 device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
405 else
406 goto error;
407 break;
408 case DeviceRequest | USB_REQ_GET_CONFIGURATION:
409 tbuf [0] = 1;
410 len = 1;
411 /* FALLTHROUGH */
412 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
413 break;
414 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
415 switch (wValue & 0xff00) {
416 case USB_DT_DEVICE << 8:
417 if (hcd->driver->flags & HCD_USB2)
418 bufp = usb2_rh_dev_descriptor;
419 else if (hcd->driver->flags & HCD_USB11)
420 bufp = usb11_rh_dev_descriptor;
421 else
422 goto error;
423 len = 18;
424 break;
425 case USB_DT_CONFIG << 8:
426 if (hcd->driver->flags & HCD_USB2) {
427 bufp = hs_rh_config_descriptor;
428 len = sizeof hs_rh_config_descriptor;
429 } else {
430 bufp = fs_rh_config_descriptor;
431 len = sizeof fs_rh_config_descriptor;
432 }
433 if (device_can_wakeup(&hcd->self.root_hub->dev))
434 patch_wakeup = 1;
435 break;
436 case USB_DT_STRING << 8:
437 n = rh_string (wValue & 0xff, hcd, ubuf, wLength);
438 if (n < 0)
439 goto error;
440 urb->actual_length = n;
441 break;
442 default:
443 goto error;
444 }
445 break;
446 case DeviceRequest | USB_REQ_GET_INTERFACE:
447 tbuf [0] = 0;
448 len = 1;
449 /* FALLTHROUGH */
450 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
451 break;
452 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
453 // wValue == urb->dev->devaddr
454 dev_dbg (hcd->self.controller, "root hub device address %d/n",
455 wValue);
456 break;
457
458 /* INTERFACE REQUESTS (no defined feature/status flags) */
459
460 /* ENDPOINT REQUESTS */
461
462 case EndpointRequest | USB_REQ_GET_STATUS:
463 // ENDPOINT_HALT flag
464 tbuf [0] = 0;
465 tbuf [1] = 0;
466 len = 2;
467 /* FALLTHROUGH */
468 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
469 case EndpointOutRequest | USB_REQ_SET_FEATURE:
470 dev_dbg (hcd->self.controller, "no endpoint features yet/n");
471 break;
472
473 /* CLASS REQUESTS (and errors) */
474
475 default:
476 /* non-generic request */
477 switch (typeReq) {
478 case GetHubStatus:
479 case GetPortStatus:
480 len = 4;
481 break;
482 case GetHubDescriptor:
483 len = sizeof (struct usb_hub_descriptor);
484 break;
485 }
486 status = hcd->driver->hub_control (hcd,
487 typeReq, wValue, wIndex,
488 tbuf, wLength);
489 break;
490 error:
491 /* "protocol stall" on error */
492 status = -EPIPE;
493 }
494
495 if (status) {
496 len = 0;
497 if (status != -EPIPE) {
498 dev_dbg (hcd->self.controller,
499 "CTRL: TypeReq=0x%x val=0x%x "
500 "idx=0x%x len=%d ==> %d/n",
501 typeReq, wValue, wIndex,
502 wLength, status);
503 }
504 }
505 if (len) {
506 if (urb->transfer_buffer_length < len)
507 len = urb->transfer_buffer_length;
508 urb->actual_length = len;
509 // always USB_DIR_IN, toward host
510 memcpy (ubuf, bufp, len);
511
512 /* report whether RH hardware supports remote wakeup */
513 if (patch_wakeup &&
514 len > offsetof (struct usb_config_descriptor,
515 bmAttributes))
516 ((struct usb_config_descriptor *)ubuf)->bmAttributes
517 |= USB_CONFIG_ATT_WAKEUP;
518 }
519
520 /* any errors get returned through the urb completion */
521 local_irq_save (flags);
522 spin_lock (&urb->lock);
523 if (urb->status == -EINPROGRESS)
524 urb->status = status;
525 spin_unlock (&urb->lock);
526 usb_hcd_giveback_urb (hcd, urb);
527 local_irq_restore (flags);
528 return 0;
529 }
看到这样近200行的函数,真是有一种叫天天不灵叫地地不应的感觉.不幸中的万幸,这个函数的结构还是很清晰的.自上而下的看过来就可以了.
对于控制传输,首先要获得它的setup_packet,来自urb结构体,正如我们当初在usb-storage中看到的那样.这里把这个setup_packet赋给cmd指针.然后把其中的各个成员都给取出来,分别放在临时变量typeReq,wValue,wIndex,wLength中,然后来判断这个typeReq.
如果是设备请求并且方向是IN,而且是USB_REQ_GET_STATUS,则,设置len为2.
如果是设备请求并且方向是OUT,而且是USB_REQ_CLEAR_FEATURE,则如何如何.
如果是设备请求并且方向是OUT,而且是USB_REQ_SET_FEATURE,则如何如何.
如果是设备请求并且方向是IN,而且是USB_REQ_GET_CONFIGURATION,则设置len为1.
如果是设备请求并且方向是OUT,而且是USB_REQ_SET_CONFIGURATION,则啥也不做.
如果是设备请求并且方向是IN,而且是USB_REQ_GET_DESCRIPTOR,则继续判断,wValue到底是什么来决定究竟是要获得什么描述符.如果是USB_DT_DEVICE,则说明要获得的是设备描述符,这正是咱们的上下文,而整个这段函数中其它的内容就只相当于顺便看看.(咱们传递给usb_get_descriptor的第二个参数就是USB_DT_DEVICE,传递给usb_control_msg的第三个参数正是USB_REQ_GET_DESCRIPTOR.)如果是USB_DT_CONFIG,则说明要获得的是配置描述符,如果是USB_DT_STRING,则说明要获得的是字符串描述符.实际上,对于Root Hub来说,这些东西都是一样的,咱们在drivers/usb/core/hcd.c中都预先定义好了,usb2_rh_dev_descriptor是针对usb 2.0的,而usb11_rh_dev_descriptor是针对usb 1.1的,咱们的uhci driver里面设置了flags的HCD_USB11.
108 /*-------------------------------------------------------------------------*/
109
110 /*
111 * Sharable chunks of root hub code.
112 */
113
114 /*-------------------------------------------------------------------------*/
115
116 #define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)
117 #define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
118
119 /* usb 2.0 root hub device descriptor */
120 static const u8 usb2_rh_dev_descriptor [18] = {
121 0x12, /* __u8 bLength; */
122 0x01, /* __u8 bDescriptorType; Device */
123 0x00, 0x02, /* __le16 bcdUSB; v2.0 */
124
125 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
126 0x00, /* __u8 bDeviceSubClass; */
127 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
128 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
129
130 0x00, 0x00, /* __le16 idVendor; */
131 0x00, 0x00, /* __le16 idProduct; */
132 KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
133
134 0x03, /* __u8 iManufacturer; */
135 0x02, /* __u8 iProduct; */
136 0x01, /* __u8 iSerialNumber; */
137 0x01 /* __u8 bNumConfigurations; */
138 };
139
140 /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
141
142 /* usb 1.1 root hub device descriptor */
143 static const u8 usb11_rh_dev_descriptor [18] = {
144 0x12, /* __u8 bLength; */
145 0x01, /* __u8 bDescriptorType; Device */
146 0x10, 0x01, /* __le16 bcdUSB; v1.1 */
147
148 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
149 0x00, /* __u8 bDeviceSubClass; */
150 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
151 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
152
153 0x00, 0x00, /* __le16 idVendor; */
154 0x00, 0x00, /* __le16 idProduct; */
155 KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
156
157 0x03, /* __u8 iManufacturer; */
158 0x02, /* __u8 iProduct; */
159 0x01, /* __u8 iSerialNumber; */
160 0x01 /* __u8 bNumConfigurations; */
161 };
162
163
164 /*-------------------------------------------------------------------------*/
165
166 /* Configuration descriptors for our root hubs */
167
168 static const u8 fs_rh_config_descriptor [] = {
169
170 /* one configuration */
171 0x09, /* __u8 bLength; */
172 0x02, /* __u8 bDescriptorType; Configuration */
173 0x19, 0x00, /* __le16 wTotalLength; */
174 0x01, /* __u8 bNumInterfaces; (1) */
175 0x01, /* __u8 bConfigurationValue; */
176 0x00, /* __u8 iConfiguration; */
177 0xc0, /* __u8 bmAttributes;
178 Bit 7: must be set,
179 6: Self-powered,
180 5: Remote wakeup,
181 4..0: resvd */
182 0x00, /* __u8 MaxPower; */
183
184 /* USB 1.1:
185 * USB 2.0, single TT organization (mandatory):
186 * one interface, protocol 0
187 *
188 * USB 2.0, multiple TT organization (optional):
189 * two interfaces, protocols 1 (like single TT)
190 * and 2 (multiple TT mode) ... config is
191 * sometimes settable
192 * NOT IMPLEMENTED
193 */
194
195 /* one interface */
196 0x09, /* __u8 if_bLength; */
197 0x04, /* __u8 if_bDescriptorType; Interface */
198 0x00, /* __u8 if_bInterfaceNumber; */
199 0x00, /* __u8 if_bAlternateSetting; */
200 0x01, /* __u8 if_bNumEndpoints; */
201 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
202 0x00, /* __u8 if_bInterfaceSubClass; */
203 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
204 0x00, /* __u8 if_iInterface; */
205
206 /* one endpoint (status change endpoint) */
207 0x07, /* __u8 ep_bLength; */
208 0x05, /* __u8 ep_bDescriptorType; Endpoint */
209 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
210 0x03, /* __u8 ep_bmAttributes; Interrupt */
211 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
212 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
213 };
214
215 static const u8 hs_rh_config_descriptor [] = {
216
217 /* one configuration */
218 0x09, /* __u8 bLength; */
219 0x02, /* __u8 bDescriptorType; Configuration */
220 0x19, 0x00, /* __le16 wTotalLength; */
221 0x01, /* __u8 bNumInterfaces; (1) */
222 0x01, /* __u8 bConfigurationValue; */
223 0x00, /* __u8 iConfiguration; */
224 0xc0, /* __u8 bmAttributes;
225 Bit 7: must be set,
226 6: Self-powered,
227 5: Remote wakeup,
228 4..0: resvd */
229 0x00, /* __u8 MaxPower; */
230
231 /* USB 1.1:
232 * USB 2.0, single TT organization (mandatory):
233 * one interface, protocol 0
234 *
235 * USB 2.0, multiple TT organization (optional):
236 * two interfaces, protocols 1 (like single TT)
237 * and 2 (multiple TT mode) ... config is
238 * sometimes settable
239 * NOT IMPLEMENTED
240 */
241
242 /* one interface */
243 0x09, /* __u8 if_bLength; */
244 0x04, /* __u8 if_bDescriptorType; Interface */
245 0x00, /* __u8 if_bInterfaceNumber; */
246 0x00, /* __u8 if_bAlternateSetting; */
247 0x01, /* __u8 if_bNumEndpoints; */
248 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
249 0x00, /* __u8 if_bInterfaceSubClass; */
250 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
251 0x00, /* __u8 if_iInterface; */
252
253 /* one endpoint (status change endpoint) */
254 0x07, /* __u8 ep_bLength; */
255 0x05, /* __u8 ep_bDescriptorType; Endpoint */
256 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
257 0x03, /* __u8 ep_bmAttributes; Interrupt */
258 /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
259 * see hub.c:hub_configure() for details. */
260 (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
261 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
262 };
如果是设备请求且方向为IN,而且是USB_REQ_GET_INTERFACE,则设置len为1
如果是设备请求且方向为OUT,而且是USB_REQ_SET_INTERFACE,则如何如何.
如果是设备请求且方向为OUT,而且是USB_REQ_SET_ADDRESS,则如何如何.
如果是端点请求且方向为IN,而且是USB_REQ_GET_STATUS,则如何如何.
如果是端点请求且方向为OUT,而且是USB_REQ_CLEAR_FEATURE或者USB_REQ_SET_FEATURE,则如何如何.
以上这些设置,统统是和usb spec中规定的东西相匹配的.
如果是Hub特定的类请求,而且是GetHubStatus或者是GetPortStatus,则设置len为4.
如果是Hub特定的类请求,而且是GetHubDescriptor,则设置len为usb_hub_descriptor结构体的大小.
最后对于Hub特定的类请求需要调用主机控制器驱动程序的hub_control函数,对于uhci_driver来说,这个指针被赋值为uhci_hub_control,来自drivers/usb/host/uhci-hub.c:
238 /* size of returned buffer is part of USB spec */
239 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
240 u16 wIndex, char *buf, u16 wLength)
241 {
242 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
243 int status, lstatus, retval = 0, len = 0;
244 unsigned int port = wIndex - 1;
245 unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
246 u16 wPortChange, wPortStatus;
247 unsigned long flags;
248
249 if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
250 return -ETIMEDOUT;
251
252 spin_lock_irqsave(&uhci->lock, flags);
253 switch (typeReq) {
254
255 case GetHubStatus:
256 *(__le32 *)buf = cpu_to_le32(0);
257 OK(4); /* hub power */
258 case GetPortStatus:
259 if (port >= uhci->rh_numports)
260 goto err;
261
262 uhci_check_ports(uhci);
263 status = inw(port_addr);
264
265 /* Intel controllers report the OverCurrent bit active on.
266 * VIA controllers report it active off, so we'll adjust the
267 * bit value. (It's not standardized in the UHCI spec.)
268 */
269 if (to_pci_dev(hcd->self.controller)->vendor ==
270 PCI_VENDOR_ID_VIA)
271 status ^= USBPORTSC_OC;
272
273 /* UHCI doesn't support C_RESET (always false) */
274 wPortChange = lstatus = 0;
275 if (status & USBPORTSC_CSC)
276 wPortChange |= USB_PORT_STAT_C_CONNECTION;
277 if (status & USBPORTSC_PEC)
278 wPortChange |= USB_PORT_STAT_C_ENABLE;
279 if ((status & USBPORTSC_OCC) && !ignore_oc)
280 wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
281
282 if (test_bit(port, &uhci->port_c_suspend)) {
283 wPortChange |= USB_PORT_STAT_C_SUSPEND;
284 lstatus |= 1;
285 }
286 if (test_bit(port, &uhci->resuming_ports))
287 lstatus |= 4;
288
289 /* UHCI has no power switching (always on) */
290 wPortStatus = USB_PORT_STAT_POWER;
291 if (status & USBPORTSC_CCS)
292 wPortStatus |= USB_PORT_STAT_CONNECTION;
293 if (status & USBPORTSC_PE) {
294 wPortStatus |= USB_PORT_STAT_ENABLE;
295 if (status & SUSPEND_BITS)
296 wPortStatus |= USB_PORT_STAT_SUSPEND;
297 }
298 if (status & USBPORTSC_OC)
299 wPortStatus |= USB_PORT_STAT_OVERCURRENT;
300 if (status & USBPORTSC_PR)
301 wPortStatus |= USB_PORT_STAT_RESET;
302 if (status & USBPORTSC_LSDA)
303 wPortStatus |= USB_PORT_STAT_LOW_SPEED;
304
305 if (wPortChange)
306 dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x/n",
307 wIndex, status, lstatus);
308
309 *(__le16 *)buf = cpu_to_le16(wPortStatus);
310 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
311 OK(4);
312 case SetHubFeature: /* We don't implement these */
313 case ClearHubFeature:
314 switch (wValue) {
315 case C_HUB_OVER_CURRENT:
316 case C_HUB_LOCAL_POWER:
317 OK(0);
318 default:
319 goto err;
320 }
321 break;
322 case SetPortFeature:
323 if (port >= uhci->rh_numports)
324 goto err;
325
326 switch (wValue) {
327 case USB_PORT_FEAT_SUSPEND:
328 SET_RH_PORTSTAT(USBPORTSC_SUSP);
329 OK(0);
330 case USB_PORT_FEAT_RESET:
331 SET_RH_PORTSTAT(USBPORTSC_PR);
332
333 /* Reset terminates Resume signalling */
334 uhci_finish_suspend(uhci, port, port_addr);
335
336 /* USB v2.0 7.1.7.5 */
337 uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
338 OK(0);
339 case USB_PORT_FEAT_POWER:
340 /* UHCI has no power switching */
341 OK(0);
342 default:
343 goto err;
344 }
345 break;
346 case ClearPortFeature:
347 if (port >= uhci->rh_numports)
348 goto err;
349
350 switch (wValue) {
351 case USB_PORT_FEAT_ENABLE:
352 CLR_RH_PORTSTAT(USBPORTSC_PE);
353
354 /* Disable terminates Resume signalling */
355 uhci_finish_suspend(uhci, port, port_addr);
356 OK(0);
357 case USB_PORT_FEAT_C_ENABLE:
358 CLR_RH_PORTSTAT(USBPORTSC_PEC);
359 OK(0);
360 case USB_PORT_FEAT_SUSPEND:
361 if (!(inw(port_addr) & USBPORTSC_SUSP)) {
362
363 /* Make certain the port isn't suspended */
364 uhci_finish_suspend(uhci, port, port_addr);
365 } else if (!test_and_set_bit(port,
366 &uhci->resuming_ports)) {
367 SET_RH_PORTSTAT(USBPORTSC_RD);
368
369 /* The controller won't allow RD to be set
370 * if the port is disabled. When this happens
371 * just skip the Resume signalling.
372 */
373 if (!(inw(port_addr) & USBPORTSC_RD))
374 uhci_finish_suspend(uhci, port,
375 port_addr);
376 else
377 /* USB v2.0 7.1.7.7 */
378 uhci->ports_timeout = jiffies +
379 msecs_to_jiffies(20);
380 }
381 OK(0);
382 case USB_PORT_FEAT_C_SUSPEND:
383 clear_bit(port, &uhci->port_c_suspend);
384 OK(0);
385 case USB_PORT_FEAT_POWER:
386 /* UHCI has no power switching */
387 goto err;
388 case USB_PORT_FEAT_C_CONNECTION:
389 CLR_RH_PORTSTAT(USBPORTSC_CSC);
390 OK(0);
391 case USB_PORT_FEAT_C_OVER_CURRENT:
392 CLR_RH_PORTSTAT(USBPORTSC_OCC);
393 OK(0);
394 case USB_PORT_FEAT_C_RESET:
395 /* this driver won't report these */
396 OK(0);
397 default:
398 goto err;
399 }
400 break;
401 case GetHubDescriptor:
402 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
403 memcpy(buf, root_hub_hub_des, len);
404 if (len > 2)
405 buf[2] = uhci->rh_numports;
406 OK(len);
407 default:
408 err:
409 retval = -EPIPE;
410 }
411 spin_unlock_irqrestore(&uhci->lock, flags);
412
413 return retval;
414 }
服了,彻底服了,变态的函数一个接着一个.莫非这群混蛋写一个200行的函数就跟我写一个20行的函数一样随便?
249行,struct usb_hcd结构体的成员unsigned long flags,咱们当初在usb_add_hcd中调用set_bit函数设置了这么一个flag,HCD_FLAG_HW_ACCESSIBLE,基本上这个flag在咱们的故事中是被设置了的.另外,struct uhci_hcd结构体有一个成员unsigned int dead,它如果为1就表明控制器挂了.
然后用一个switch来处理hub特定的类请求.OK居然也是一个宏,定义于drivers/usb/host/uhci-hub.c:
78 #define OK(x) len = (x); break
所以如果请求是GetHubStatus,则设置len为4.
如果请求是GetPortStatus,则调用uhci_check_ports.然后读端口寄存器.USBPORTSC_CSC表示端口连接有变化,USBPORTSC_PEC表示Port Enable有变化.USBPORTSC_OCC表示Over Current有变化,struct uhci_hcd的两个成员,port_c_suspend和resuming_ports都是电源管理相关的.
但无论如何,以上所做的这些都是为了获得两个东西,wPortStatus和wPortChange.以此来响应GetPortStatus这个请求.
接下来,SetHubFeature和ClearHubFeature咱们没啥好说的,不需要做什么.
但是SetPortFeature就有事情要做了.wValue表明具体是什么特征.
SET_RH_PORTSTAT这个宏就是专门用于设置Root Hub的端口特征的.
80 #define CLR_RH_PORTSTAT(x) /
81 status = inw(port_addr); /
82 status &= ~(RWC_BITS|WZ_BITS); /
83 status &= ~(x); /
84 status |= RWC_BITS & (x); /
85 outw(status, port_addr)
86
87 #define SET_RH_PORTSTAT(x) /
88 status = inw(port_addr); /
89 status |= (x); /
90 status &= ~(RWC_BITS|WZ_BITS); /
91 outw(status, port_addr)
对于USB_PORT_FEAT_RESET,还需要调用uhci_finish_suspend.
如果是USB_PORT_FEAT_POWER,则什么也不做,因为UHCI不吃这一套.
如果请求是ClearPortFeature,基本上也是一样的做法.除了调用的宏变成了CLR_RH_PORTSTAT.
如果请求是GetHubDescriptor,那就满足它呗.root_hub_hub_des是早就在drivers/usb/host/uhci-hub.c中定义好的:
15 static __u8 root_hub_hub_des[] =
16 {
17 0x09, /* __u8 bLength; */
18 0x29, /* __u8 bDescriptorType; Hub-descriptor */
19 0x02, /* __u8 bNbrPorts; */
20 0x0a, /* __u16 wHubCharacteristics; */
21 0x00, /* (per-port OC, no power switching) */
22 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
23 0x00, /* __u8 bHubContrCurrent; 0 mA */
24 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
25 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
26 };
回到rh_call_control,switch结束了,下面是判断status和len.
然后调用usb_hcd_giveback_urb().来自drivers/usb/core/hcd.c:
1373 /**
1374 * usb_hcd_giveback_urb - return URB from HCD to device driver
1375 * @hcd: host controller returning the URB
1376 * @urb: urb being returned to the USB device driver.
1377 * Context: in_interrupt()
1378 *
1379 * This hands the URB from HCD to its USB device driver, using its
1380 * completion function. The HCD has freed all per-urb resources
1381 * (and is done using urb->hcpriv). It also released all HCD locks;
1382 * the device driver won't cause problems if it frees, modifies,
1383 * or resubmits this URB.
1384 */
1385 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1386 {
1387 int at_root_hub;
1388
1389 at_root_hub = (urb->dev == hcd->self.root_hub);
1390 urb_unlink (urb);
1391
1392 /* lower level hcd code should use *_dma exclusively if the
1393 * host controller does DMA */
1394 if (hcd->self.uses_dma && !at_root_hub) {
1395 if (usb_pipecontrol (urb->pipe)
1396 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
1397 dma_unmap_single (hcd->self.controller, urb->setup_dma,
1398 sizeof (struct usb_ctrlrequest),
1399 DMA_TO_DEVICE);
1400 if (urb->transfer_buffer_length != 0
1401 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
1402 dma_unmap_single (hcd->self.controller,
1403 urb->transfer_dma,
1404 urb->transfer_buffer_length,
1405 usb_pipein (urb->pipe)
1406 ? DMA_FROM_DEVICE
1407 : DMA_TO_DEVICE);
1408 }
1409
1410 usbmon_urb_complete (&hcd->self, urb);
1411 /* pass ownership to the completion handler */
1412 urb->complete (urb);
1413 atomic_dec (&urb->use_count);
1414 if (unlikely (urb->reject))
1415 wake_up (&usb_kill_urb_queue);
1416 usb_put_urb (urb);
1417 }
1418 EXPORT_SYMBOL (usb_hcd_giveback_urb);
这里最重要最有意义的一行当然就是1412行,调用urb的complete函数,这正是我们在usb-storage里期待的那个函数.从此rh_call_control函数也该返回了,以后设备驱动又获得了控制权.事实上令人欣喜的是对于Root Hub,1394行开始的这一段if是不会被执行的,因为at_root_hub显然是为真.不过就算这段要执行也没什么可怕的,无非就是把之前为这个urb建立的dma映射给取消掉.而另一方面,对于Root Hub来说,complete函数基本上是什么也不做,只不过是让咱们再次回到usb_start_wait_urb去,而控制传输需要的数据也已经copy到了urb->transfer_buffer中去了. 至此,Root Hub的控制传输就算结束了,即我们的usb_get_device_descriptor函数取得了空前绝后的圆满成功.