]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
MdeModulePkg/UsbBus&XhciDxe: Solve a bug that 2 or more tiers SS hubs with SS devices...
[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
c3f44a77
FT
971 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
972\r
973 if (EFI_ERROR (Status)) {\r
974 return Status;\r
975 } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
976 DEBUG (( EFI_D_INFO, "UsbHubResetPort: skip reset on hub %p port %d\n", HubIf, Port));\r
977 return EFI_SUCCESS;\r
978 }\r
979\r
c52fa98c 980 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);\r
e237e7ae 981\r
982 if (EFI_ERROR (Status)) {\r
983 return Status;\r
984 }\r
985\r
986 //\r
71619ac2 987 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
e237e7ae 988 // section 7.1.7.5 for timing requirements.\r
989 //\r
41e8ff27 990 gBS->Stall (USB_SET_PORT_RESET_STALL);\r
e237e7ae 991\r
992 //\r
71619ac2 993 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
e237e7ae 994 //\r
995 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
996\r
41e8ff27 997 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 998 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
999\r
127884c5
FT
1000 if (EFI_ERROR (Status)) {\r
1001 return Status;\r
1002 }\r
1003\r
e237e7ae 1004 if (!EFI_ERROR (Status) &&\r
71619ac2 1005 USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
1006 gBS->Stall (USB_SET_PORT_RECOVERY_STALL);\r
e237e7ae 1007 return EFI_SUCCESS;\r
1008 }\r
1009\r
41e8ff27 1010 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1011 }\r
1012\r
1013 return EFI_TIMEOUT;\r
1014}\r
1015\r
1016\r
1017/**\r
8616fc4c 1018 Release the hub's control of the interface.\r
e237e7ae 1019\r
8616fc4c 1020 @param HubIf The hub interface.\r
e237e7ae 1021\r
8616fc4c 1022 @retval EFI_SUCCESS The interface is release of hub control.\r
e237e7ae 1023\r
1024**/\r
e237e7ae 1025EFI_STATUS\r
1026UsbHubRelease (\r
1027 IN USB_INTERFACE *HubIf\r
1028 )\r
1029{\r
1030 EFI_USB_IO_PROTOCOL *UsbIo;\r
1031 EFI_STATUS Status;\r
1032\r
1033 UsbIo = &HubIf->UsbIo;\r
1034 Status = UsbIo->UsbAsyncInterruptTransfer (\r
1035 UsbIo,\r
1036 HubIf->HubEp->Desc.EndpointAddress,\r
1037 FALSE,\r
1038 USB_HUB_POLL_INTERVAL,\r
1039 0,\r
1040 NULL,\r
1041 0\r
1042 );\r
1043\r
1044 if (EFI_ERROR (Status)) {\r
1045 return Status;\r
1046 }\r
1047\r
1048 gBS->CloseEvent (HubIf->HubNotify);\r
1049\r
1050 HubIf->IsHub = FALSE;\r
1051 HubIf->HubApi = NULL;\r
1052 HubIf->HubEp = NULL;\r
1053 HubIf->HubNotify = NULL;\r
1054\r
d2577026 1055 DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));\r
e237e7ae 1056 return EFI_SUCCESS;\r
1057}\r
1058\r
1059\r
1060\r
1061/**\r
8616fc4c 1062 Initialize the interface for root hub.\r
e237e7ae 1063\r
8616fc4c 1064 @param HubIf The root hub interface.\r
e237e7ae 1065\r
d17371e8 1066 @retval EFI_SUCCESS The interface is initialized for root hub.\r
8616fc4c 1067 @retval Others Failed to initialize the hub.\r
e237e7ae 1068\r
1069**/\r
e237e7ae 1070EFI_STATUS\r
1071UsbRootHubInit (\r
1072 IN USB_INTERFACE *HubIf\r
1073 )\r
1074{\r
1075 EFI_STATUS Status;\r
1076 UINT8 MaxSpeed;\r
1077 UINT8 NumOfPort;\r
1078 UINT8 Support64;\r
1079\r
1080 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);\r
1081\r
1082 if (EFI_ERROR (Status)) {\r
1083 return Status;\r
1084 }\r
1085\r
0e549d5b 1086 DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",\r
e237e7ae 1087 HubIf, MaxSpeed, NumOfPort));\r
1088\r
1089 HubIf->IsHub = TRUE;\r
1090 HubIf->HubApi = &mUsbRootHubApi;\r
1091 HubIf->HubEp = NULL;\r
1092 HubIf->MaxSpeed = MaxSpeed;\r
1093 HubIf->NumOfPort = NumOfPort;\r
1094 HubIf->HubNotify = NULL;\r
1095\r
1096 //\r
1097 // Create a timer to poll root hub ports periodically\r
1098 //\r
1099 Status = gBS->CreateEvent (\r
1100 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1101 TPL_CALLBACK,\r
1102 UsbRootHubEnumeration,\r
1103 HubIf,\r
1104 &HubIf->HubNotify\r
1105 );\r
1106\r
1107 if (EFI_ERROR (Status)) {\r
1108 return Status;\r
1109 }\r
1110\r
d2577026 1111 //\r
1112 // It should signal the event immediately here, or device detection\r
1113 // by bus enumeration might be delayed by the timer interval.\r
1114 //\r
1115 gBS->SignalEvent (HubIf->HubNotify);\r
1116\r
e237e7ae 1117 Status = gBS->SetTimer (\r
1118 HubIf->HubNotify,\r
1119 TimerPeriodic,\r
1120 USB_ROOTHUB_POLL_INTERVAL\r
1121 );\r
1122\r
1123 if (EFI_ERROR (Status)) {\r
1124 gBS->CloseEvent (HubIf->HubNotify);\r
1125 }\r
1126\r
1127 return Status;\r
1128}\r
1129\r
1130\r
e237e7ae 1131/**\r
1132 Get the port status. This function is required to\r
1133 ACK the port change bits although it will return\r
1134 the port changes in PortState. Bus enumeration code\r
1135 doesn't need to ACK the port change bits.\r
1136\r
8616fc4c 1137 @param HubIf The root hub interface.\r
1138 @param Port The root hub port to get the state.\r
1139 @param PortState Variable to return the port state.\r
e237e7ae 1140\r
8616fc4c 1141 @retval EFI_SUCCESS The port state is returned.\r
1142 @retval Others Failed to retrieve the port state.\r
e237e7ae 1143\r
1144**/\r
e237e7ae 1145EFI_STATUS\r
1146UsbRootHubGetPortStatus (\r
1147 IN USB_INTERFACE *HubIf,\r
1148 IN UINT8 Port,\r
1149 OUT EFI_USB_PORT_STATUS *PortState\r
1150 )\r
1151{\r
1152 USB_BUS *Bus;\r
1153 EFI_STATUS Status;\r
1154\r
1155 Bus = HubIf->Device->Bus;\r
1156 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);\r
1157\r
1158 return Status;\r
1159}\r
1160\r
1161\r
1162/**\r
1163 Clear the port change status.\r
1164\r
8616fc4c 1165 @param HubIf The root hub interface.\r
1166 @param Port The root hub port.\r
e237e7ae 1167\r
e237e7ae 1168**/\r
e237e7ae 1169VOID\r
1170UsbRootHubClearPortChange (\r
1171 IN USB_INTERFACE *HubIf,\r
1172 IN UINT8 Port\r
1173 )\r
1174{\r
1175 EFI_USB_PORT_STATUS PortState;\r
1176 USB_CHANGE_FEATURE_MAP *Map;\r
1177 UINTN Index;\r
1178 EFI_STATUS Status;\r
1179\r
1180 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);\r
1181\r
1182 if (EFI_ERROR (Status)) {\r
1183 return;\r
1184 }\r
1185\r
1186 //\r
1187 // OK, get the usb port status, now ACK the change bits.\r
1188 // Don't return error when failed to clear the change bits.\r
1189 // It may lead to extra port state report. USB bus should\r
1190 // be able to handle this.\r
1191 //\r
92870c98 1192 for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {\r
e237e7ae 1193 Map = &mRootHubFeatureMap[Index];\r
1194\r
1195 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
c52fa98c 1196 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);\r
e237e7ae 1197 }\r
1198 }\r
1199}\r
1200\r
1201\r
e237e7ae 1202/**\r
8616fc4c 1203 Set the root hub port feature.\r
e237e7ae 1204\r
8616fc4c 1205 @param HubIf The Usb hub interface.\r
1206 @param Port The hub port.\r
1207 @param Feature The feature to set.\r
e237e7ae 1208\r
8616fc4c 1209 @retval EFI_SUCCESS The root hub port is set with the feature.\r
1210 @retval Others Failed to set the feature.\r
e237e7ae 1211\r
1212**/\r
e237e7ae 1213EFI_STATUS\r
1214UsbRootHubSetPortFeature (\r
1215 IN USB_INTERFACE *HubIf,\r
1216 IN UINT8 Port,\r
1217 IN EFI_USB_PORT_FEATURE Feature\r
1218 )\r
1219{\r
1220 EFI_STATUS Status;\r
1221\r
1222 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1223\r
1224 return Status;\r
1225}\r
1226\r
1227\r
1228/**\r
8616fc4c 1229 Clear the root hub port feature.\r
e237e7ae 1230\r
8616fc4c 1231 @param HubIf The root hub interface.\r
1232 @param Port The root hub port.\r
1233 @param Feature The feature to clear.\r
e237e7ae 1234\r
8616fc4c 1235 @retval EFI_SUCCESS The root hub port is cleared of the feature.\r
1236 @retval Others Failed to clear the feature.\r
e237e7ae 1237\r
1238**/\r
e237e7ae 1239EFI_STATUS\r
1240UsbRootHubClearPortFeature (\r
1241 IN USB_INTERFACE *HubIf,\r
1242 IN UINT8 Port,\r
1243 IN EFI_USB_PORT_FEATURE Feature\r
1244 )\r
1245{\r
1246 EFI_STATUS Status;\r
1247\r
1248 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1249\r
1250 return Status;\r
1251}\r
1252\r
1253\r
1254/**\r
d17371e8 1255 Interface function to reset the root hub port.\r
e237e7ae 1256\r
8616fc4c 1257 @param RootIf The root hub interface.\r
1258 @param Port The port to reset.\r
e237e7ae 1259\r
8616fc4c 1260 @retval EFI_SUCCESS The hub port is reset.\r
1261 @retval EFI_TIMEOUT Failed to reset the port in time.\r
1262 @retval EFI_NOT_FOUND The low/full speed device connected to high speed.\r
1263 root hub is released to the companion UHCI.\r
1264 @retval Others Failed to reset the port.\r
e237e7ae 1265\r
1266**/\r
e237e7ae 1267EFI_STATUS\r
1268UsbRootHubResetPort (\r
1269 IN USB_INTERFACE *RootIf,\r
1270 IN UINT8 Port\r
1271 )\r
1272{\r
1273 USB_BUS *Bus;\r
1274 EFI_STATUS Status;\r
1275 EFI_USB_PORT_STATUS PortState;\r
1276 UINTN Index;\r
1277\r
1278 //\r
1279 // Notice: although EHCI requires that ENABLED bit be cleared\r
1280 // when reset the port, we don't need to care that here. It\r
1281 // should be handled in the EHCI driver.\r
1282 //\r
1283 Bus = RootIf->Device->Bus;\r
c3f44a77
FT
1284\r
1285 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
1286\r
1287 if (EFI_ERROR (Status)) {\r
1288 return Status;\r
1289 } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
1290 DEBUG (( EFI_D_INFO, "UsbRootHubResetPort: skip reset on root port %d\n", Port));\r
1291 return EFI_SUCCESS;\r
1292 }\r
1293\r
e237e7ae 1294 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1295\r
1296 if (EFI_ERROR (Status)) {\r
d2577026 1297 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));\r
e237e7ae 1298 return Status;\r
1299 }\r
1300\r
1301 //\r
1302 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
1303 // section 7.1.7.5 for timing requirements.\r
1304 //\r
41e8ff27 1305 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);\r
e237e7ae 1306\r
1307 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1308\r
1309 if (EFI_ERROR (Status)) {\r
d2577026 1310 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));\r
e237e7ae 1311 return Status;\r
1312 }\r
1313\r
41e8ff27 1314 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);\r
e237e7ae 1315\r
1316 //\r
1317 // USB host controller won't clear the RESET bit until\r
1318 // reset is actually finished.\r
1319 //\r
1320 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
1321\r
41e8ff27 1322 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 1323 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
1324\r
1325 if (EFI_ERROR (Status)) {\r
1326 return Status;\r
1327 }\r
1328\r
1329 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
1330 break;\r
1331 }\r
1332\r
41e8ff27 1333 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1334 }\r
1335\r
41e8ff27 1336 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
1337 DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));\r
e237e7ae 1338 return EFI_TIMEOUT;\r
1339 }\r
1340\r
1341 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {\r
1342 //\r
1343 // OK, the port is reset. If root hub is of high speed and\r
1344 // the device is of low/full speed, release the ownership to\r
1345 // companion UHCI. If root hub is of full speed, it won't\r
1346 // automatically enable the port, we need to enable it manually.\r
1347 //\r
1348 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {\r
d2577026 1349 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));\r
e237e7ae 1350\r
1351 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);\r
1352 return EFI_NOT_FOUND;\r
1353\r
1354 } else {\r
1355\r
1356 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);\r
1357\r
1358 if (EFI_ERROR (Status)) {\r
d2577026 1359 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));\r
e237e7ae 1360 return Status;\r
1361 }\r
1362\r
41e8ff27 1363 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);\r
e237e7ae 1364 }\r
1365 }\r
1366\r
1367 return EFI_SUCCESS;\r
1368}\r
1369\r
1370\r
1371/**\r
8616fc4c 1372 Release the root hub's control of the interface.\r
e237e7ae 1373\r
8616fc4c 1374 @param HubIf The root hub interface.\r
e237e7ae 1375\r
1376 @retval EFI_SUCCESS The root hub's control of the interface is\r
1377 released.\r
1378\r
1379**/\r
e237e7ae 1380EFI_STATUS\r
1381UsbRootHubRelease (\r
1382 IN USB_INTERFACE *HubIf\r
1383 )\r
1384{\r
0e549d5b 1385 DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));\r
e237e7ae 1386\r
1387 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);\r
1388 gBS->CloseEvent (HubIf->HubNotify);\r
1389\r
1390 return EFI_SUCCESS;\r
1391}\r
1392\r
1393USB_HUB_API mUsbHubApi = {\r
1394 UsbHubInit,\r
1395 UsbHubGetPortStatus,\r
1396 UsbHubClearPortChange,\r
1397 UsbHubSetPortFeature,\r
1398 UsbHubClearPortFeature,\r
1399 UsbHubResetPort,\r
1400 UsbHubRelease\r
1401};\r
1402\r
1403USB_HUB_API mUsbRootHubApi = {\r
1404 UsbRootHubInit,\r
1405 UsbRootHubGetPortStatus,\r
1406 UsbRootHubClearPortChange,\r
1407 UsbRootHubSetPortFeature,\r
1408 UsbRootHubClearPortFeature,\r
1409 UsbRootHubResetPort,\r
1410 UsbRootHubRelease\r
1411};\r