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