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