- 浏览: 916806 次
文章分类
最新评论
-
wmaizai163:
有源码文件么 可调试的那种 发我邮箱可以么 3906902 ...
java文件传输 -
shenselongge:
排版能否改改
Mina2.0框架源码剖析(一) -
grandry:
谢谢!这是一个困扰我多时的问题
delphi的tclientdataset的中文过滤使用注意事项 -
LongXiTianXia:
我不知道哪里下载那个组件
基于朴素贝叶斯分类器的文本分类算法(下) -
LongXiTianXia:
可以说一下分词组件怎么使用吗?
基于朴素贝叶斯分类器的文本分类算法(下)
Linux那些事儿之我是UHCI(18)Root Hub的控制传输(二)
医生,请把孩子取出来之后,顺便给我吸吸脂.
——广州一妇女在剖腹产手术前对医生说.
对于控制传输,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函数取得了空前绝后的圆满成功.
相关推荐
Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我...
linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿...
写一下UHCI吧,也顺便怀念一下Intel,以及Intel的那几个女同事们,好久没联系了,你们可好? UHCI是 Intel提出来的.虽然离开 Intel一年多了,但我总觉得也许有一天我还会回到 Intel.所 以关于 Intel的东西,我多少会关注...
Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是USB core.pdf Linux 那些...
》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...
Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之...
Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是PCI Linux那些事儿之我是Hub Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层
Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...
本人整理的fudan_abc的专栏中以完结的文章,在此向原作者表示感谢,给...内容包括:linux那些事儿之我是U盘,linux那些事儿之我是USB,linux那些事儿之我是HUB,linux那些事儿之我是UHCI,linux那些事儿之我是Sysfs。
Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs,UHCI,usb core,U盘,此处,先...
Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析
Linux那些事儿之我是Hub Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘 Linux那些事之我是HUB1
里面包含Linux那些事的九个文档,Block层,ECHI主机控制,HUB,PCI,SCSI硬盘,Sysfs,UHCI,USB+core,U盘等九个文档,内容详细,而且全面都有书签,适合系统学习!
Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...
2 Linux那些事儿之我是EHCI主机控制器 3 Linux那些事儿之我是HUB 4 Linux那些事儿之我是PCI 5 Linux那些事儿之我是SCSI硬盘 6 Linux那些事儿之我是Sysfs 7 Linux那些事儿之我是UHCI 8 Linux那些事儿之我是USB+core 9...
我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核
一个很经典的东东,里面的很多东西都很有启发性,值得看看
我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 其中我是U盘属于基础性的.这一阶段会遇到一些问题.比如urb提交之后究竟怎么处理的?用户空间究竟是如何访问U盘的?DMA究竟怎么回事. 这之后可以开始看Hub.这一阶段你会明白一...
linux那些事儿,Block层,EHCI主机控制器,Hub,PCI,SCSI硬盘,Sysfs,UHCI,USB core,U盘等文档。