]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
Enabling usb3.0 XHCI support.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbHub.c
CommitLineData
e237e7ae 1/** @file\r
2\r
8616fc4c 3 Unified interface for RootHub and Hub.\r
4\r
cd5ebaa0
HT
5Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR> \r
6This program and the accompanying materials\r
e237e7ae 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
e237e7ae 14**/\r
15\r
16#include "UsbBus.h"\r
17\r
aa79b0b3 18//\r
19// Array that maps the change bit to feature value which is\r
20// used to clear these change bit. USB HUB API will clear\r
21// these change bit automatically. For non-root hub, these\r
22// bits determine whether hub will report the port in changed\r
23// bit maps.\r
24//\r
92870c98 25USB_CHANGE_FEATURE_MAP mHubFeatureMap[] = {\r
aa79b0b3 26 {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},\r
27 {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},\r
28 {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},\r
29 {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
92870c98 30 {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange}\r
aa79b0b3 31};\r
32\r
92870c98 33USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[] = {\r
aa79b0b3 34 {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},\r
35 {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},\r
36 {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},\r
37 {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
38 {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange},\r
39};\r
40\r
e237e7ae 41//\r
42// USB hub class specific requests. Although USB hub\r
43// is related to an interface, these requests are sent\r
44// to the control endpoint of the device.\r
45//\r
92870c98 46/**\r
47 USB hub control transfer to set the hub depth.\r
48\r
49 @param HubDev The device of the hub.\r
50 @param Depth The depth to set.\r
51\r
52 @retval EFI_SUCCESS Depth of the hub is set.\r
53 @retval Others Failed to set the depth.\r
54\r
55**/\r
56EFI_STATUS\r
57UsbHubCtrlSetHubDepth (\r
58 IN USB_DEVICE *HubDev,\r
59 IN UINT16 Depth\r
60 )\r
61{\r
62 EFI_STATUS Status;\r
e237e7ae 63\r
92870c98 64 Status = UsbCtrlRequest (\r
65 HubDev,\r
66 EfiUsbNoData,\r
67 USB_REQ_TYPE_CLASS,\r
68 USB_HUB_TARGET_HUB,\r
69 USB_HUB_REQ_SET_DEPTH,\r
70 Depth,\r
71 0,\r
72 NULL,\r
73 0\r
74 );\r
75\r
76 return Status;\r
77}\r
e237e7ae 78\r
79/**\r
8616fc4c 80 USB hub control transfer to clear the hub feature.\r
e237e7ae 81\r
8616fc4c 82 @param HubDev The device of the hub.\r
83 @param Feature The feature to clear.\r
e237e7ae 84\r
8616fc4c 85 @retval EFI_SUCCESS Feature of the hub is cleared.\r
86 @retval Others Failed to clear the feature.\r
e237e7ae 87\r
88**/\r
e237e7ae 89EFI_STATUS\r
90UsbHubCtrlClearHubFeature (\r
91 IN USB_DEVICE *HubDev,\r
92 IN UINT16 Feature\r
93 )\r
94{\r
95 EFI_STATUS Status;\r
96\r
97 Status = UsbCtrlRequest (\r
98 HubDev,\r
99 EfiUsbNoData,\r
100 USB_REQ_TYPE_CLASS,\r
101 USB_HUB_TARGET_HUB,\r
102 USB_HUB_REQ_CLEAR_FEATURE,\r
103 Feature,\r
104 0,\r
105 NULL,\r
106 0\r
107 );\r
108\r
109 return Status;\r
110}\r
111\r
112\r
113/**\r
8616fc4c 114 Clear the feature of the device's port.\r
e237e7ae 115\r
8616fc4c 116 @param HubDev The hub device.\r
117 @param Port The port to clear feature.\r
118 @param Feature The feature to clear.\r
e237e7ae 119\r
120 @retval EFI_SUCCESS The feature of the port is cleared.\r
121 @retval Others Failed to clear the feature.\r
122\r
123**/\r
e237e7ae 124EFI_STATUS\r
125UsbHubCtrlClearPortFeature (\r
126 IN USB_DEVICE *HubDev,\r
127 IN UINT8 Port,\r
128 IN UINT16 Feature\r
129 )\r
130{\r
131 EFI_STATUS Status;\r
132\r
133 //\r
134 // In USB bus, all the port index starts from 0. But HUB\r
135 // indexes its port from 1. So, port number is added one.\r
136 //\r
137 Status = UsbCtrlRequest (\r
138 HubDev,\r
139 EfiUsbNoData,\r
140 USB_REQ_TYPE_CLASS,\r
141 USB_HUB_TARGET_PORT,\r
142 USB_HUB_REQ_CLEAR_FEATURE,\r
143 Feature,\r
c52fa98c 144 (UINT16) (Port + 1),\r
e237e7ae 145 NULL,\r
146 0\r
147 );\r
148\r
149 return Status;\r
150}\r
151\r
152\r
e237e7ae 153/**\r
154 Clear the transaction translate buffer if full/low\r
155 speed control/bulk transfer failed and the transfer\r
156 uses this hub as translator.Remember to clear the TT\r
157 buffer of transaction translator, not that of the\r
158 parent.\r
159\r
8616fc4c 160 @param HubDev The hub device.\r
161 @param Port The port of the hub.\r
162 @param DevAddr Address of the failed transaction.\r
163 @param EpNum The endpoint number of the failed transaction.\r
164 @param EpType The type of failed transaction.\r
e237e7ae 165\r
8616fc4c 166 @retval EFI_SUCCESS The TT buffer is cleared.\r
167 @retval Others Failed to clear the TT buffer.\r
e237e7ae 168\r
169**/\r
170EFI_STATUS\r
171UsbHubCtrlClearTTBuffer (\r
172 IN USB_DEVICE *HubDev,\r
173 IN UINT8 Port,\r
174 IN UINT16 DevAddr,\r
175 IN UINT16 EpNum,\r
176 IN UINT16 EpType\r
177 )\r
178{\r
179 EFI_STATUS Status;\r
180 UINT16 Value;\r
181\r
182 //\r
183 // Check USB2.0 spec page 424 for wValue's encoding\r
184 //\r
c52fa98c 185 Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |\r
186 ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));\r
e237e7ae 187\r
188 Status = UsbCtrlRequest (\r
189 HubDev,\r
190 EfiUsbNoData,\r
191 USB_REQ_TYPE_CLASS,\r
192 USB_HUB_TARGET_PORT,\r
193 USB_HUB_REQ_CLEAR_TT,\r
194 Value,\r
c52fa98c 195 (UINT16) (Port + 1),\r
e237e7ae 196 NULL,\r
197 0\r
198 );\r
199\r
200 return Status;\r
201}\r
202\r
92870c98 203/**\r
204 Usb hub control transfer to get the super speed hub descriptor.\r
205\r
206 @param HubDev The hub device.\r
207 @param Buf The buffer to hold the descriptor.\r
208 @param Len The length to retrieve.\r
209\r
210 @retval EFI_SUCCESS The hub descriptor is retrieved.\r
211 @retval Others Failed to retrieve the hub descriptor.\r
212\r
213**/\r
214EFI_STATUS\r
215UsbHubCtrlGetSuperSpeedHubDesc (\r
216 IN USB_DEVICE *HubDev,\r
217 OUT VOID *Buf\r
218 )\r
219{\r
220 EFI_STATUS Status;\r
221 \r
222 Status = EFI_INVALID_PARAMETER;\r
223 \r
224 Status = UsbCtrlRequest (\r
225 HubDev,\r
226 EfiUsbDataIn,\r
227 USB_REQ_TYPE_CLASS,\r
228 USB_HUB_TARGET_HUB,\r
229 USB_HUB_REQ_GET_DESC,\r
230 (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),\r
231 0,\r
232 Buf,\r
233 32\r
234 );\r
235\r
236 return Status;\r
237}\r
e237e7ae 238\r
239/**\r
8616fc4c 240 Usb hub control transfer to get the hub descriptor.\r
e237e7ae 241\r
8616fc4c 242 @param HubDev The hub device.\r
243 @param Buf The buffer to hold the descriptor.\r
244 @param Len The length to retrieve.\r
e237e7ae 245\r
8616fc4c 246 @retval EFI_SUCCESS The hub descriptor is retrieved.\r
247 @retval Others Failed to retrieve the hub descriptor.\r
e237e7ae 248\r
249**/\r
e237e7ae 250EFI_STATUS\r
251UsbHubCtrlGetHubDesc (\r
252 IN USB_DEVICE *HubDev,\r
253 OUT VOID *Buf,\r
254 IN UINTN Len\r
255 )\r
256{\r
257 EFI_STATUS Status;\r
258\r
259 Status = UsbCtrlRequest (\r
260 HubDev,\r
261 EfiUsbDataIn,\r
262 USB_REQ_TYPE_CLASS,\r
263 USB_HUB_TARGET_HUB,\r
264 USB_HUB_REQ_GET_DESC,\r
265 (UINT16) (USB_DESC_TYPE_HUB << 8),\r
266 0,\r
267 Buf,\r
268 Len\r
269 );\r
270\r
271 return Status;\r
272}\r
273\r
274\r
275/**\r
8616fc4c 276 Usb hub control transfer to get the hub status.\r
e237e7ae 277\r
8616fc4c 278 @param HubDev The hub device.\r
279 @param State The variable to return the status.\r
e237e7ae 280\r
8616fc4c 281 @retval EFI_SUCCESS The hub status is returned in State.\r
282 @retval Others Failed to get the hub status.\r
e237e7ae 283\r
284**/\r
e237e7ae 285EFI_STATUS\r
286UsbHubCtrlGetHubStatus (\r
287 IN USB_DEVICE *HubDev,\r
288 OUT UINT32 *State\r
289 )\r
290{\r
291 EFI_STATUS Status;\r
292\r
293 Status = UsbCtrlRequest (\r
294 HubDev,\r
295 EfiUsbDataIn,\r
296 USB_REQ_TYPE_CLASS,\r
297 USB_HUB_TARGET_HUB,\r
298 USB_HUB_REQ_GET_STATUS,\r
299 0,\r
300 0,\r
301 State,\r
302 4\r
303 );\r
304\r
305 return Status;\r
306}\r
307\r
308\r
309/**\r
8616fc4c 310 Usb hub control transfer to get the port status.\r
e237e7ae 311\r
8616fc4c 312 @param HubDev The hub device.\r
313 @param Port The port of the hub.\r
314 @param State Variable to return the hub port state.\r
e237e7ae 315\r
8616fc4c 316 @retval EFI_SUCCESS The port state is returned in State.\r
d17371e8 317 @retval Others Failed to retrieve the port state.\r
e237e7ae 318\r
319**/\r
e237e7ae 320EFI_STATUS\r
321UsbHubCtrlGetPortStatus (\r
322 IN USB_DEVICE *HubDev,\r
323 IN UINT8 Port,\r
324 OUT VOID *State\r
325 )\r
326{\r
327 EFI_STATUS Status;\r
328\r
329 //\r
330 // In USB bus, all the port index starts from 0. But HUB\r
331 // indexes its port from 1. So, port number is added one.\r
332 // No need to convert the hub bit to UEFI definition, they\r
333 // are the same\r
334 //\r
335 Status = UsbCtrlRequest (\r
336 HubDev,\r
337 EfiUsbDataIn,\r
338 USB_REQ_TYPE_CLASS,\r
339 USB_HUB_TARGET_PORT,\r
340 USB_HUB_REQ_GET_STATUS,\r
341 0,\r
c52fa98c 342 (UINT16) (Port + 1),\r
e237e7ae 343 State,\r
344 4\r
345 );\r
346\r
347 return Status;\r
348}\r
349\r
350\r
351/**\r
8616fc4c 352 Usb hub control transfer to reset the TT (Transaction Transaltor).\r
e237e7ae 353\r
8616fc4c 354 @param HubDev The hub device.\r
355 @param Port The port of the hub.\r
e237e7ae 356\r
8616fc4c 357 @retval EFI_SUCCESS The TT of the hub is reset.\r
358 @retval Others Failed to reset the port.\r
e237e7ae 359\r
360**/\r
e237e7ae 361EFI_STATUS\r
362UsbHubCtrlResetTT (\r
363 IN USB_DEVICE *HubDev,\r
364 IN UINT8 Port\r
365 )\r
366{\r
367 EFI_STATUS Status;\r
368\r
369 Status = UsbCtrlRequest (\r
370 HubDev,\r
371 EfiUsbNoData,\r
372 USB_REQ_TYPE_CLASS,\r
373 USB_HUB_TARGET_HUB,\r
374 USB_HUB_REQ_RESET_TT,\r
375 0,\r
c52fa98c 376 (UINT16) (Port + 1),\r
e237e7ae 377 NULL,\r
378 0\r
379 );\r
380\r
381 return Status;\r
382}\r
383\r
384\r
385/**\r
8616fc4c 386 Usb hub control transfer to set the hub feature.\r
e237e7ae 387\r
8616fc4c 388 @param HubDev The hub device.\r
389 @param Feature The feature to set.\r
e237e7ae 390\r
8616fc4c 391 @retval EFI_SUCESS The feature is set for the hub.\r
392 @retval Others Failed to set the feature.\r
e237e7ae 393\r
394**/\r
e237e7ae 395EFI_STATUS\r
396UsbHubCtrlSetHubFeature (\r
397 IN USB_DEVICE *HubDev,\r
398 IN UINT8 Feature\r
399 )\r
400{\r
401 EFI_STATUS Status;\r
402\r
403 Status = UsbCtrlRequest (\r
404 HubDev,\r
405 EfiUsbNoData,\r
406 USB_REQ_TYPE_CLASS,\r
407 USB_HUB_TARGET_HUB,\r
408 USB_HUB_REQ_SET_FEATURE,\r
409 Feature,\r
410 0,\r
411 NULL,\r
412 0\r
413 );\r
414\r
415 return Status;\r
416}\r
417\r
418\r
419/**\r
8616fc4c 420 Usb hub control transfer to set the port feature.\r
e237e7ae 421\r
8616fc4c 422 @param HubDev The Usb hub device.\r
423 @param Port The Usb port to set feature for.\r
424 @param Feature The feature to set.\r
e237e7ae 425\r
8616fc4c 426 @retval EFI_SUCCESS The feature is set for the port.\r
427 @retval Others Failed to set the feature.\r
e237e7ae 428\r
429**/\r
e237e7ae 430EFI_STATUS\r
431UsbHubCtrlSetPortFeature (\r
432 IN USB_DEVICE *HubDev,\r
433 IN UINT8 Port,\r
434 IN UINT8 Feature\r
435 )\r
436{\r
437 EFI_STATUS Status;\r
438\r
439 //\r
440 // In USB bus, all the port index starts from 0. But HUB\r
441 // indexes its port from 1. So, port number is added one.\r
442 //\r
443 Status = UsbCtrlRequest (\r
444 HubDev,\r
445 EfiUsbNoData,\r
446 USB_REQ_TYPE_CLASS,\r
447 USB_HUB_TARGET_PORT,\r
448 USB_HUB_REQ_SET_FEATURE,\r
449 Feature,\r
c52fa98c 450 (UINT16) (Port + 1),\r
e237e7ae 451 NULL,\r
452 0\r
453 );\r
454\r
455 return Status;\r
456}\r
457\r
458\r
459/**\r
460 Read the whole usb hub descriptor. It is necessary\r
461 to do it in two steps because hub descriptor is of\r
8616fc4c 462 variable length.\r
e237e7ae 463\r
8616fc4c 464 @param HubDev The hub device.\r
465 @param HubDesc The variable to return the descriptor.\r
e237e7ae 466\r
8616fc4c 467 @retval EFI_SUCCESS The hub descriptor is read.\r
468 @retval Others Failed to read the hub descriptor.\r
e237e7ae 469\r
470**/\r
e237e7ae 471EFI_STATUS\r
472UsbHubReadDesc (\r
473 IN USB_DEVICE *HubDev,\r
474 OUT EFI_USB_HUB_DESCRIPTOR *HubDesc\r
475 )\r
476{\r
477 EFI_STATUS Status;\r
478\r
92870c98 479 if (HubDev->Speed == EFI_USB_SPEED_SUPER) {\r
480 //\r
481 // Get the super speed hub descriptor\r
482 //\r
483 Status = UsbHubCtrlGetSuperSpeedHubDesc (HubDev, HubDesc);\r
484 } else {\r
e237e7ae 485\r
92870c98 486 //\r
487 // First get the hub descriptor length\r
488 //\r
489 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);\r
e237e7ae 490\r
92870c98 491 if (EFI_ERROR (Status)) {\r
492 return Status;\r
493 }\r
494\r
495 //\r
496 // Get the whole hub descriptor\r
497 //\r
498 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
499 }\r
e237e7ae 500\r
501 return Status;\r
502}\r
503\r
504\r
505\r
506/**\r
507 Ack the hub change bits. If these bits are not ACKed, Hub will\r
508 always return changed bit map from its interrupt endpoint.\r
509\r
8616fc4c 510 @param HubDev The hub device.\r
e237e7ae 511\r
8616fc4c 512 @retval EFI_SUCCESS The hub change status is ACKed.\r
513 @retval Others Failed to ACK the hub status.\r
e237e7ae 514\r
515**/\r
516EFI_STATUS\r
517UsbHubAckHubStatus (\r
518 IN USB_DEVICE *HubDev\r
519 )\r
520{\r
521 EFI_USB_PORT_STATUS HubState;\r
522 EFI_STATUS Status;\r
523\r
524 Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);\r
525\r
526 if (EFI_ERROR (Status)) {\r
527 return Status;\r
528 }\r
529\r
530 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {\r
531 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);\r
532 }\r
533\r
534 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {\r
535 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);\r
536 }\r
537\r
538 return EFI_SUCCESS;\r
539}\r
540\r
541\r
542/**\r
543 Test whether the interface is a hub interface.\r
544\r
8616fc4c 545 @param UsbIf The interface to test.\r
e237e7ae 546\r
8616fc4c 547 @retval TRUE The interface is a hub interface.\r
548 @retval FALSE The interface isn't a hub interface.\r
e237e7ae 549\r
550**/\r
551BOOLEAN\r
552UsbIsHubInterface (\r
553 IN USB_INTERFACE *UsbIf\r
554 )\r
555{\r
556 EFI_USB_INTERFACE_DESCRIPTOR *Setting;\r
557\r
558 //\r
559 // If the hub is a high-speed hub with multiple TT,\r
560 // the hub will has a default setting of single TT.\r
561 //\r
562 Setting = &UsbIf->IfSetting->Desc;\r
563\r
564 if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&\r
565 (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {\r
566\r
567 return TRUE;\r
568 }\r
569\r
570 return FALSE;\r
571}\r
572\r
573\r
574/**\r
575 The callback function to the USB hub status change\r
576 interrupt endpoint. It is called periodically by\r
577 the underlying host controller.\r
578\r
8616fc4c 579 @param Data The data read.\r
580 @param DataLength The length of the data read.\r
581 @param Context The context.\r
582 @param Result The result of the last interrupt transfer.\r
e237e7ae 583\r
8616fc4c 584 @retval EFI_SUCCESS The process is OK.\r
585 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
e237e7ae 586\r
587**/\r
e237e7ae 588EFI_STATUS\r
6d3ea23f 589EFIAPI\r
e237e7ae 590UsbOnHubInterrupt (\r
591 IN VOID *Data,\r
592 IN UINTN DataLength,\r
593 IN VOID *Context,\r
594 IN UINT32 Result\r
595 )\r
596{\r
597 USB_INTERFACE *HubIf;\r
598 EFI_USB_IO_PROTOCOL *UsbIo;\r
599 EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
600 EFI_STATUS Status;\r
601\r
602 HubIf = (USB_INTERFACE *) Context;\r
603 UsbIo = &(HubIf->UsbIo);\r
604 EpDesc = &(HubIf->HubEp->Desc);\r
605\r
606 if (Result != EFI_USB_NOERROR) {\r
607 //\r
608 // If endpoint is stalled, clear the stall. Use UsbIo to access\r
609 // the control transfer so internal status are maintained.\r
610 //\r
611 if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {\r
612 UsbIoClearFeature (\r
613 UsbIo,\r
614 USB_TARGET_ENDPOINT,\r
615 USB_FEATURE_ENDPOINT_HALT,\r
616 EpDesc->EndpointAddress\r
617 );\r
618 }\r
619\r
620 //\r
621 // Delete and submit a new async interrupt\r
622 //\r
623 Status = UsbIo->UsbAsyncInterruptTransfer (\r
624 UsbIo,\r
625 EpDesc->EndpointAddress,\r
626 FALSE,\r
627 0,\r
628 0,\r
629 NULL,\r
630 NULL\r
631 );\r
632\r
633 if (EFI_ERROR (Status)) {\r
d2577026 634 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));\r
e237e7ae 635 return Status;\r
636 }\r
637\r
638 Status = UsbIo->UsbAsyncInterruptTransfer (\r
639 UsbIo,\r
640 EpDesc->EndpointAddress,\r
641 TRUE,\r
642 USB_HUB_POLL_INTERVAL,\r
643 HubIf->NumOfPort / 8 + 1,\r
644 UsbOnHubInterrupt,\r
645 HubIf\r
646 );\r
647\r
648 if (EFI_ERROR (Status)) {\r
d2577026 649 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));\r
e237e7ae 650 }\r
651\r
652 return Status;\r
653 }\r
654\r
655 if ((DataLength == 0) || (Data == NULL)) {\r
656 return EFI_SUCCESS;\r
657 }\r
658\r
659 //\r
660 // OK, actually something is changed, save the change map\r
661 // then signal the HUB to do enumeration. This is a good\r
662 // practise since UsbOnHubInterrupt is called in the context\r
663 // of host contrller's AsyncInterrupt monitor.\r
664 //\r
665 HubIf->ChangeMap = AllocateZeroPool (DataLength);\r
666\r
667 if (HubIf->ChangeMap == NULL) {\r
668 return EFI_OUT_OF_RESOURCES;\r
669 }\r
670\r
671 CopyMem (HubIf->ChangeMap, Data, DataLength);\r
672 gBS->SignalEvent (HubIf->HubNotify);\r
673\r
674 return EFI_SUCCESS;\r
675}\r
676\r
e237e7ae 677\r
678\r
679\r
680/**\r
8616fc4c 681 Initialize the device for a non-root hub.\r
e237e7ae 682\r
8616fc4c 683 @param HubIf The USB hub interface.\r
e237e7ae 684\r
8616fc4c 685 @retval EFI_SUCCESS The hub is initialized.\r
686 @retval EFI_DEVICE_ERROR Failed to initialize the hub.\r
e237e7ae 687\r
688**/\r
e237e7ae 689EFI_STATUS\r
690UsbHubInit (\r
691 IN USB_INTERFACE *HubIf\r
692 )\r
693{\r
694 EFI_USB_HUB_DESCRIPTOR HubDesc;\r
695 USB_ENDPOINT_DESC *EpDesc;\r
696 USB_INTERFACE_SETTING *Setting;\r
697 EFI_USB_IO_PROTOCOL *UsbIo;\r
698 USB_DEVICE *HubDev;\r
699 EFI_STATUS Status;\r
700 UINT8 Index;\r
d17371e8 701 UINT8 NumEndpoints;\r
92870c98 702 UINT16 Depth;\r
e237e7ae 703\r
704 //\r
705 // Locate the interrupt endpoint for port change map\r
706 //\r
707 HubIf->IsHub = FALSE;\r
708 Setting = HubIf->IfSetting;\r
709 HubDev = HubIf->Device;\r
710 EpDesc = NULL;\r
d17371e8 711 NumEndpoints = Setting->Desc.NumEndpoints;\r
e237e7ae 712\r
d17371e8 713 for (Index = 0; Index < NumEndpoints; Index++) {\r
e237e7ae 714 ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));\r
715\r
716 EpDesc = Setting->Endpoints[Index];\r
717\r
718 if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&\r
719 (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {\r
720 break;\r
721 }\r
722 }\r
723\r
d17371e8 724 if (Index == NumEndpoints) {\r
d2577026 725 DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));\r
e237e7ae 726 return EFI_DEVICE_ERROR;\r
727 }\r
728\r
729 Status = UsbHubReadDesc (HubDev, &HubDesc);\r
730\r
731 if (EFI_ERROR (Status)) {\r
d2577026 732 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));\r
e237e7ae 733 return Status;\r
734 }\r
735\r
736 HubIf->NumOfPort = HubDesc.NumPorts;\r
737\r
d2577026 738 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));\r
e237e7ae 739\r
92870c98 740 //\r
741 // OK, set IsHub to TRUE. Now usb bus can handle this device\r
742 // as a working HUB. If failed eariler, bus driver will not\r
743 // recognize it as a hub. Other parts of the bus should be able\r
744 // to work.\r
745 //\r
746 HubIf->IsHub = TRUE;\r
747 HubIf->HubApi = &mUsbHubApi;\r
748 HubIf->HubEp = EpDesc;\r
749\r
750 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
751 Depth = (UINT16)(HubIf->Device->Tier - 1);\r
752 DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));\r
753 UsbHubCtrlSetHubDepth (HubIf->Device, Depth);\r
754 \r
755 for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
756 UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);\r
757 } \r
758 } else {\r
759 //\r
760 // Feed power to all the hub ports. It should be ok\r
761 // for both gang/individual powered hubs.\r
762 //\r
763 for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
764 UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
765 }\r
766\r
767 gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
768 UsbHubAckHubStatus (HubIf->Device);\r
769 }\r
770\r
e237e7ae 771 //\r
772 // Create an event to enumerate the hub's port. On\r
773 //\r
774 Status = gBS->CreateEvent (\r
775 EVT_NOTIFY_SIGNAL,\r
776 TPL_CALLBACK,\r
777 UsbHubEnumeration,\r
778 HubIf,\r
779 &HubIf->HubNotify\r
780 );\r
781\r
782 if (EFI_ERROR (Status)) {\r
d2577026 783 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",\r
e237e7ae 784 HubDev->Address, Status));\r
785\r
786 return Status;\r
787 }\r
788\r
789 //\r
790 // Create AsyncInterrupt to query hub port change endpoint\r
791 // periodically. If the hub ports are changed, hub will return\r
792 // changed port map from the interrupt endpoint. The port map\r
793 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for\r
794 // host change status).\r
795 //\r
796 UsbIo = &HubIf->UsbIo;\r
797 Status = UsbIo->UsbAsyncInterruptTransfer (\r
798 UsbIo,\r
799 EpDesc->Desc.EndpointAddress,\r
800 TRUE,\r
801 USB_HUB_POLL_INTERVAL,\r
802 HubIf->NumOfPort / 8 + 1,\r
803 UsbOnHubInterrupt,\r
804 HubIf\r
805 );\r
806\r
807 if (EFI_ERROR (Status)) {\r
d2577026 808 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",\r
e237e7ae 809 HubDev->Address, Status));\r
810\r
811 gBS->CloseEvent (HubIf->HubNotify);\r
812 HubIf->HubNotify = NULL;\r
813\r
814 return Status;\r
815 }\r
816\r
d2577026 817 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));\r
e237e7ae 818 return Status;\r
819}\r
820\r
821\r
822\r
823/**\r
824 Get the port status. This function is required to\r
825 ACK the port change bits although it will return\r
826 the port changes in PortState. Bus enumeration code\r
827 doesn't need to ACK the port change bits.\r
828\r
8616fc4c 829 @param HubIf The hub interface.\r
830 @param Port The port of the hub to get state.\r
831 @param PortState Variable to return the port state.\r
e237e7ae 832\r
8616fc4c 833 @retval EFI_SUCCESS The port status is successfully returned.\r
834 @retval Others Failed to return the status.\r
e237e7ae 835\r
836**/\r
e237e7ae 837EFI_STATUS\r
838UsbHubGetPortStatus (\r
839 IN USB_INTERFACE *HubIf,\r
840 IN UINT8 Port,\r
841 OUT EFI_USB_PORT_STATUS *PortState\r
842 )\r
843{\r
844 EFI_STATUS Status;\r
845\r
846 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);\r
847\r
92870c98 848 //\r
849 // Mark the USB_PORT_STAT_SUPER_SPEED bit if SuperSpeed\r
850 //\r
851 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
852 PortState->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
853 } \r
e237e7ae 854 return Status;\r
855}\r
856\r
857\r
858\r
859/**\r
860 Clear the port change status.\r
861\r
8616fc4c 862 @param HubIf The hub interface.\r
863 @param Port The hub port.\r
e237e7ae 864\r
e237e7ae 865**/\r
e237e7ae 866VOID\r
867UsbHubClearPortChange (\r
868 IN USB_INTERFACE *HubIf,\r
869 IN UINT8 Port\r
870 )\r
871{\r
872 EFI_USB_PORT_STATUS PortState;\r
873 USB_CHANGE_FEATURE_MAP *Map;\r
874 UINTN Index;\r
875 EFI_STATUS Status;\r
876\r
877 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
878\r
879 if (EFI_ERROR (Status)) {\r
880 return;\r
881 }\r
882\r
883 //\r
884 // OK, get the usb port status, now ACK the change bits.\r
885 // Don't return error when failed to clear the change bits.\r
886 // It may lead to extra port state report. USB bus should\r
887 // be able to handle this.\r
888 //\r
92870c98 889 for (Index = 0; Index < sizeof (mHubFeatureMap) / sizeof (mHubFeatureMap[0]); Index++) {\r
e237e7ae 890 Map = &mHubFeatureMap[Index];\r
891\r
892 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
23c326c2 893 UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);\r
e237e7ae 894 }\r
895 }\r
896}\r
897\r
898\r
899\r
900/**\r
8616fc4c 901 Function to set the port feature for non-root hub.\r
e237e7ae 902\r
8616fc4c 903 @param HubIf The hub interface.\r
904 @param Port The port of the hub.\r
905 @param Feature The feature of the port to set.\r
e237e7ae 906\r
8616fc4c 907 @retval EFI_SUCCESS The hub port feature is set.\r
908 @retval Others Failed to set the port feature.\r
e237e7ae 909\r
910**/\r
e237e7ae 911EFI_STATUS\r
912UsbHubSetPortFeature (\r
913 IN USB_INTERFACE *HubIf,\r
914 IN UINT8 Port,\r
915 IN EFI_USB_PORT_FEATURE Feature\r
916 )\r
917{\r
918 EFI_STATUS Status;\r
919\r
c52fa98c 920 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 921\r
922 return Status;\r
923}\r
924\r
925\r
926/**\r
8616fc4c 927 Interface function to clear the port feature for non-root hub.\r
e237e7ae 928\r
8616fc4c 929 @param HubIf The hub interface.\r
930 @param Port The port of the hub to clear feature for.\r
931 @param Feature The feature to clear.\r
e237e7ae 932\r
8616fc4c 933 @retval EFI_SUCCESS The port feature is cleared.\r
934 @retval Others Failed to clear the port feature.\r
e237e7ae 935\r
936**/\r
e237e7ae 937EFI_STATUS\r
938UsbHubClearPortFeature (\r
939 IN USB_INTERFACE *HubIf,\r
940 IN UINT8 Port,\r
941 IN EFI_USB_PORT_FEATURE Feature\r
942 )\r
943{\r
944 EFI_STATUS Status;\r
945\r
c52fa98c 946 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 947\r
948 return Status;\r
949}\r
950\r
951\r
952/**\r
d17371e8 953 Interface function to reset the port.\r
e237e7ae 954\r
8616fc4c 955 @param HubIf The hub interface.\r
956 @param Port The port to reset.\r
e237e7ae 957\r
8616fc4c 958 @retval EFI_SUCCESS The hub port is reset.\r
959 @retval EFI_TIMEOUT Failed to reset the port in time.\r
960 @retval Others Failed to reset the port.\r
e237e7ae 961\r
962**/\r
e237e7ae 963EFI_STATUS\r
964UsbHubResetPort (\r
965 IN USB_INTERFACE *HubIf,\r
966 IN UINT8 Port\r
967 )\r
968{\r
969 EFI_USB_PORT_STATUS PortState;\r
970 UINTN Index;\r
971 EFI_STATUS Status;\r
972\r
c52fa98c 973 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);\r
e237e7ae 974\r
975 if (EFI_ERROR (Status)) {\r
976 return Status;\r
977 }\r
978\r
979 //\r
980 // Drive the reset signal for at least 10ms. Check USB 2.0 Spec\r
981 // section 7.1.7.5 for timing requirements.\r
982 //\r
41e8ff27 983 gBS->Stall (USB_SET_PORT_RESET_STALL);\r
e237e7ae 984\r
985 //\r
986 // USB hub will clear RESET bit if reset is actually finished.\r
987 //\r
988 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
989\r
41e8ff27 990 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 991 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
992\r
993 if (!EFI_ERROR (Status) &&\r
994 !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
995\r
996 return EFI_SUCCESS;\r
997 }\r
998\r
41e8ff27 999 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1000 }\r
1001\r
1002 return EFI_TIMEOUT;\r
1003}\r
1004\r
1005\r
1006/**\r
8616fc4c 1007 Release the hub's control of the interface.\r
e237e7ae 1008\r
8616fc4c 1009 @param HubIf The hub interface.\r
e237e7ae 1010\r
8616fc4c 1011 @retval EFI_SUCCESS The interface is release of hub control.\r
e237e7ae 1012\r
1013**/\r
e237e7ae 1014EFI_STATUS\r
1015UsbHubRelease (\r
1016 IN USB_INTERFACE *HubIf\r
1017 )\r
1018{\r
1019 EFI_USB_IO_PROTOCOL *UsbIo;\r
1020 EFI_STATUS Status;\r
1021\r
1022 UsbIo = &HubIf->UsbIo;\r
1023 Status = UsbIo->UsbAsyncInterruptTransfer (\r
1024 UsbIo,\r
1025 HubIf->HubEp->Desc.EndpointAddress,\r
1026 FALSE,\r
1027 USB_HUB_POLL_INTERVAL,\r
1028 0,\r
1029 NULL,\r
1030 0\r
1031 );\r
1032\r
1033 if (EFI_ERROR (Status)) {\r
1034 return Status;\r
1035 }\r
1036\r
1037 gBS->CloseEvent (HubIf->HubNotify);\r
1038\r
1039 HubIf->IsHub = FALSE;\r
1040 HubIf->HubApi = NULL;\r
1041 HubIf->HubEp = NULL;\r
1042 HubIf->HubNotify = NULL;\r
1043\r
d2577026 1044 DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));\r
e237e7ae 1045 return EFI_SUCCESS;\r
1046}\r
1047\r
1048\r
1049\r
1050/**\r
8616fc4c 1051 Initialize the interface for root hub.\r
e237e7ae 1052\r
8616fc4c 1053 @param HubIf The root hub interface.\r
e237e7ae 1054\r
d17371e8 1055 @retval EFI_SUCCESS The interface is initialized for root hub.\r
8616fc4c 1056 @retval Others Failed to initialize the hub.\r
e237e7ae 1057\r
1058**/\r
e237e7ae 1059EFI_STATUS\r
1060UsbRootHubInit (\r
1061 IN USB_INTERFACE *HubIf\r
1062 )\r
1063{\r
1064 EFI_STATUS Status;\r
1065 UINT8 MaxSpeed;\r
1066 UINT8 NumOfPort;\r
1067 UINT8 Support64;\r
1068\r
1069 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);\r
1070\r
1071 if (EFI_ERROR (Status)) {\r
1072 return Status;\r
1073 }\r
1074\r
0e549d5b 1075 DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",\r
e237e7ae 1076 HubIf, MaxSpeed, NumOfPort));\r
1077\r
1078 HubIf->IsHub = TRUE;\r
1079 HubIf->HubApi = &mUsbRootHubApi;\r
1080 HubIf->HubEp = NULL;\r
1081 HubIf->MaxSpeed = MaxSpeed;\r
1082 HubIf->NumOfPort = NumOfPort;\r
1083 HubIf->HubNotify = NULL;\r
1084\r
1085 //\r
1086 // Create a timer to poll root hub ports periodically\r
1087 //\r
1088 Status = gBS->CreateEvent (\r
1089 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1090 TPL_CALLBACK,\r
1091 UsbRootHubEnumeration,\r
1092 HubIf,\r
1093 &HubIf->HubNotify\r
1094 );\r
1095\r
1096 if (EFI_ERROR (Status)) {\r
1097 return Status;\r
1098 }\r
1099\r
d2577026 1100 //\r
1101 // It should signal the event immediately here, or device detection\r
1102 // by bus enumeration might be delayed by the timer interval.\r
1103 //\r
1104 gBS->SignalEvent (HubIf->HubNotify);\r
1105\r
e237e7ae 1106 Status = gBS->SetTimer (\r
1107 HubIf->HubNotify,\r
1108 TimerPeriodic,\r
1109 USB_ROOTHUB_POLL_INTERVAL\r
1110 );\r
1111\r
1112 if (EFI_ERROR (Status)) {\r
1113 gBS->CloseEvent (HubIf->HubNotify);\r
1114 }\r
1115\r
1116 return Status;\r
1117}\r
1118\r
1119\r
e237e7ae 1120/**\r
1121 Get the port status. This function is required to\r
1122 ACK the port change bits although it will return\r
1123 the port changes in PortState. Bus enumeration code\r
1124 doesn't need to ACK the port change bits.\r
1125\r
8616fc4c 1126 @param HubIf The root hub interface.\r
1127 @param Port The root hub port to get the state.\r
1128 @param PortState Variable to return the port state.\r
e237e7ae 1129\r
8616fc4c 1130 @retval EFI_SUCCESS The port state is returned.\r
1131 @retval Others Failed to retrieve the port state.\r
e237e7ae 1132\r
1133**/\r
e237e7ae 1134EFI_STATUS\r
1135UsbRootHubGetPortStatus (\r
1136 IN USB_INTERFACE *HubIf,\r
1137 IN UINT8 Port,\r
1138 OUT EFI_USB_PORT_STATUS *PortState\r
1139 )\r
1140{\r
1141 USB_BUS *Bus;\r
1142 EFI_STATUS Status;\r
1143\r
1144 Bus = HubIf->Device->Bus;\r
1145 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);\r
1146\r
1147 return Status;\r
1148}\r
1149\r
1150\r
1151/**\r
1152 Clear the port change status.\r
1153\r
8616fc4c 1154 @param HubIf The root hub interface.\r
1155 @param Port The root hub port.\r
e237e7ae 1156\r
e237e7ae 1157**/\r
e237e7ae 1158VOID\r
1159UsbRootHubClearPortChange (\r
1160 IN USB_INTERFACE *HubIf,\r
1161 IN UINT8 Port\r
1162 )\r
1163{\r
1164 EFI_USB_PORT_STATUS PortState;\r
1165 USB_CHANGE_FEATURE_MAP *Map;\r
1166 UINTN Index;\r
1167 EFI_STATUS Status;\r
1168\r
1169 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);\r
1170\r
1171 if (EFI_ERROR (Status)) {\r
1172 return;\r
1173 }\r
1174\r
1175 //\r
1176 // OK, get the usb port status, now ACK the change bits.\r
1177 // Don't return error when failed to clear the change bits.\r
1178 // It may lead to extra port state report. USB bus should\r
1179 // be able to handle this.\r
1180 //\r
92870c98 1181 for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {\r
e237e7ae 1182 Map = &mRootHubFeatureMap[Index];\r
1183\r
1184 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
c52fa98c 1185 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);\r
e237e7ae 1186 }\r
1187 }\r
1188}\r
1189\r
1190\r
e237e7ae 1191/**\r
8616fc4c 1192 Set the root hub port feature.\r
e237e7ae 1193\r
8616fc4c 1194 @param HubIf The Usb hub interface.\r
1195 @param Port The hub port.\r
1196 @param Feature The feature to set.\r
e237e7ae 1197\r
8616fc4c 1198 @retval EFI_SUCCESS The root hub port is set with the feature.\r
1199 @retval Others Failed to set the feature.\r
e237e7ae 1200\r
1201**/\r
e237e7ae 1202EFI_STATUS\r
1203UsbRootHubSetPortFeature (\r
1204 IN USB_INTERFACE *HubIf,\r
1205 IN UINT8 Port,\r
1206 IN EFI_USB_PORT_FEATURE Feature\r
1207 )\r
1208{\r
1209 EFI_STATUS Status;\r
1210\r
1211 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1212\r
1213 return Status;\r
1214}\r
1215\r
1216\r
1217/**\r
8616fc4c 1218 Clear the root hub port feature.\r
e237e7ae 1219\r
8616fc4c 1220 @param HubIf The root hub interface.\r
1221 @param Port The root hub port.\r
1222 @param Feature The feature to clear.\r
e237e7ae 1223\r
8616fc4c 1224 @retval EFI_SUCCESS The root hub port is cleared of the feature.\r
1225 @retval Others Failed to clear the feature.\r
e237e7ae 1226\r
1227**/\r
e237e7ae 1228EFI_STATUS\r
1229UsbRootHubClearPortFeature (\r
1230 IN USB_INTERFACE *HubIf,\r
1231 IN UINT8 Port,\r
1232 IN EFI_USB_PORT_FEATURE Feature\r
1233 )\r
1234{\r
1235 EFI_STATUS Status;\r
1236\r
1237 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1238\r
1239 return Status;\r
1240}\r
1241\r
1242\r
1243/**\r
d17371e8 1244 Interface function to reset the root hub port.\r
e237e7ae 1245\r
8616fc4c 1246 @param RootIf The root hub interface.\r
1247 @param Port The port to reset.\r
e237e7ae 1248\r
8616fc4c 1249 @retval EFI_SUCCESS The hub port is reset.\r
1250 @retval EFI_TIMEOUT Failed to reset the port in time.\r
1251 @retval EFI_NOT_FOUND The low/full speed device connected to high speed.\r
1252 root hub is released to the companion UHCI.\r
1253 @retval Others Failed to reset the port.\r
e237e7ae 1254\r
1255**/\r
e237e7ae 1256EFI_STATUS\r
1257UsbRootHubResetPort (\r
1258 IN USB_INTERFACE *RootIf,\r
1259 IN UINT8 Port\r
1260 )\r
1261{\r
1262 USB_BUS *Bus;\r
1263 EFI_STATUS Status;\r
1264 EFI_USB_PORT_STATUS PortState;\r
1265 UINTN Index;\r
1266\r
1267 //\r
1268 // Notice: although EHCI requires that ENABLED bit be cleared\r
1269 // when reset the port, we don't need to care that here. It\r
1270 // should be handled in the EHCI driver.\r
1271 //\r
1272 Bus = RootIf->Device->Bus;\r
1273 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1274\r
1275 if (EFI_ERROR (Status)) {\r
d2577026 1276 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));\r
e237e7ae 1277 return Status;\r
1278 }\r
1279\r
1280 //\r
1281 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
1282 // section 7.1.7.5 for timing requirements.\r
1283 //\r
41e8ff27 1284 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);\r
e237e7ae 1285\r
1286 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1287\r
1288 if (EFI_ERROR (Status)) {\r
d2577026 1289 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));\r
e237e7ae 1290 return Status;\r
1291 }\r
1292\r
41e8ff27 1293 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);\r
e237e7ae 1294\r
1295 //\r
1296 // USB host controller won't clear the RESET bit until\r
1297 // reset is actually finished.\r
1298 //\r
1299 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
1300\r
41e8ff27 1301 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 1302 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
1303\r
1304 if (EFI_ERROR (Status)) {\r
1305 return Status;\r
1306 }\r
1307\r
1308 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
1309 break;\r
1310 }\r
1311\r
41e8ff27 1312 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1313 }\r
1314\r
41e8ff27 1315 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
1316 DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));\r
e237e7ae 1317 return EFI_TIMEOUT;\r
1318 }\r
1319\r
1320 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {\r
1321 //\r
1322 // OK, the port is reset. If root hub is of high speed and\r
1323 // the device is of low/full speed, release the ownership to\r
1324 // companion UHCI. If root hub is of full speed, it won't\r
1325 // automatically enable the port, we need to enable it manually.\r
1326 //\r
1327 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {\r
d2577026 1328 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));\r
e237e7ae 1329\r
1330 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);\r
1331 return EFI_NOT_FOUND;\r
1332\r
1333 } else {\r
1334\r
1335 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);\r
1336\r
1337 if (EFI_ERROR (Status)) {\r
d2577026 1338 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));\r
e237e7ae 1339 return Status;\r
1340 }\r
1341\r
41e8ff27 1342 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);\r
e237e7ae 1343 }\r
1344 }\r
1345\r
1346 return EFI_SUCCESS;\r
1347}\r
1348\r
1349\r
1350/**\r
8616fc4c 1351 Release the root hub's control of the interface.\r
e237e7ae 1352\r
8616fc4c 1353 @param HubIf The root hub interface.\r
e237e7ae 1354\r
1355 @retval EFI_SUCCESS The root hub's control of the interface is\r
1356 released.\r
1357\r
1358**/\r
e237e7ae 1359EFI_STATUS\r
1360UsbRootHubRelease (\r
1361 IN USB_INTERFACE *HubIf\r
1362 )\r
1363{\r
0e549d5b 1364 DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));\r
e237e7ae 1365\r
1366 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);\r
1367 gBS->CloseEvent (HubIf->HubNotify);\r
1368\r
1369 return EFI_SUCCESS;\r
1370}\r
1371\r
1372USB_HUB_API mUsbHubApi = {\r
1373 UsbHubInit,\r
1374 UsbHubGetPortStatus,\r
1375 UsbHubClearPortChange,\r
1376 UsbHubSetPortFeature,\r
1377 UsbHubClearPortFeature,\r
1378 UsbHubResetPort,\r
1379 UsbHubRelease\r
1380};\r
1381\r
1382USB_HUB_API mUsbRootHubApi = {\r
1383 UsbRootHubInit,\r
1384 UsbRootHubGetPortStatus,\r
1385 UsbRootHubClearPortChange,\r
1386 UsbRootHubSetPortFeature,\r
1387 UsbRootHubClearPortFeature,\r
1388 UsbRootHubResetPort,\r
1389 UsbRootHubRelease\r
1390};\r