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