]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
Add missing SocketIdentifier for Memory Topology table in ACPI5.0.
[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
766 gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
767 UsbHubAckHubStatus (HubIf->Device);\r
768 }\r
769\r
e237e7ae 770 //\r
771 // Create an event to enumerate the hub's port. On\r
772 //\r
773 Status = gBS->CreateEvent (\r
774 EVT_NOTIFY_SIGNAL,\r
775 TPL_CALLBACK,\r
776 UsbHubEnumeration,\r
777 HubIf,\r
778 &HubIf->HubNotify\r
779 );\r
780\r
781 if (EFI_ERROR (Status)) {\r
d2577026 782 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",\r
e237e7ae 783 HubDev->Address, Status));\r
784\r
785 return Status;\r
786 }\r
787\r
788 //\r
789 // Create AsyncInterrupt to query hub port change endpoint\r
790 // periodically. If the hub ports are changed, hub will return\r
791 // changed port map from the interrupt endpoint. The port map\r
792 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for\r
793 // host change status).\r
794 //\r
795 UsbIo = &HubIf->UsbIo;\r
796 Status = UsbIo->UsbAsyncInterruptTransfer (\r
797 UsbIo,\r
798 EpDesc->Desc.EndpointAddress,\r
799 TRUE,\r
800 USB_HUB_POLL_INTERVAL,\r
801 HubIf->NumOfPort / 8 + 1,\r
802 UsbOnHubInterrupt,\r
803 HubIf\r
804 );\r
805\r
806 if (EFI_ERROR (Status)) {\r
d2577026 807 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",\r
e237e7ae 808 HubDev->Address, Status));\r
809\r
810 gBS->CloseEvent (HubIf->HubNotify);\r
811 HubIf->HubNotify = NULL;\r
812\r
813 return Status;\r
814 }\r
815\r
d2577026 816 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));\r
e237e7ae 817 return Status;\r
818}\r
819\r
820\r
821\r
822/**\r
823 Get the port status. This function is required to\r
824 ACK the port change bits although it will return\r
825 the port changes in PortState. Bus enumeration code\r
826 doesn't need to ACK the port change bits.\r
827\r
8616fc4c 828 @param HubIf The hub interface.\r
829 @param Port The port of the hub to get state.\r
830 @param PortState Variable to return the port state.\r
e237e7ae 831\r
8616fc4c 832 @retval EFI_SUCCESS The port status is successfully returned.\r
833 @retval Others Failed to return the status.\r
e237e7ae 834\r
835**/\r
e237e7ae 836EFI_STATUS\r
837UsbHubGetPortStatus (\r
838 IN USB_INTERFACE *HubIf,\r
839 IN UINT8 Port,\r
840 OUT EFI_USB_PORT_STATUS *PortState\r
841 )\r
842{\r
843 EFI_STATUS Status;\r
844\r
845 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);\r
846\r
847 return Status;\r
848}\r
849\r
850\r
851\r
852/**\r
853 Clear the port change status.\r
854\r
8616fc4c 855 @param HubIf The hub interface.\r
856 @param Port The hub port.\r
e237e7ae 857\r
e237e7ae 858**/\r
e237e7ae 859VOID\r
860UsbHubClearPortChange (\r
861 IN USB_INTERFACE *HubIf,\r
862 IN UINT8 Port\r
863 )\r
864{\r
865 EFI_USB_PORT_STATUS PortState;\r
866 USB_CHANGE_FEATURE_MAP *Map;\r
867 UINTN Index;\r
868 EFI_STATUS Status;\r
869\r
870 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
871\r
872 if (EFI_ERROR (Status)) {\r
873 return;\r
874 }\r
875\r
876 //\r
877 // OK, get the usb port status, now ACK the change bits.\r
878 // Don't return error when failed to clear the change bits.\r
879 // It may lead to extra port state report. USB bus should\r
880 // be able to handle this.\r
881 //\r
92870c98 882 for (Index = 0; Index < sizeof (mHubFeatureMap) / sizeof (mHubFeatureMap[0]); Index++) {\r
e237e7ae 883 Map = &mHubFeatureMap[Index];\r
884\r
885 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
23c326c2 886 UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);\r
e237e7ae 887 }\r
888 }\r
889}\r
890\r
891\r
892\r
893/**\r
8616fc4c 894 Function to set the port feature for non-root hub.\r
e237e7ae 895\r
8616fc4c 896 @param HubIf The hub interface.\r
897 @param Port The port of the hub.\r
898 @param Feature The feature of the port to set.\r
e237e7ae 899\r
8616fc4c 900 @retval EFI_SUCCESS The hub port feature is set.\r
901 @retval Others Failed to set the port feature.\r
e237e7ae 902\r
903**/\r
e237e7ae 904EFI_STATUS\r
905UsbHubSetPortFeature (\r
906 IN USB_INTERFACE *HubIf,\r
907 IN UINT8 Port,\r
908 IN EFI_USB_PORT_FEATURE Feature\r
909 )\r
910{\r
911 EFI_STATUS Status;\r
912\r
c52fa98c 913 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 914\r
915 return Status;\r
916}\r
917\r
918\r
919/**\r
8616fc4c 920 Interface function to clear the port feature for non-root hub.\r
e237e7ae 921\r
8616fc4c 922 @param HubIf The hub interface.\r
923 @param Port The port of the hub to clear feature for.\r
924 @param Feature The feature to clear.\r
e237e7ae 925\r
8616fc4c 926 @retval EFI_SUCCESS The port feature is cleared.\r
927 @retval Others Failed to clear the port feature.\r
e237e7ae 928\r
929**/\r
e237e7ae 930EFI_STATUS\r
931UsbHubClearPortFeature (\r
932 IN USB_INTERFACE *HubIf,\r
933 IN UINT8 Port,\r
934 IN EFI_USB_PORT_FEATURE Feature\r
935 )\r
936{\r
937 EFI_STATUS Status;\r
938\r
c52fa98c 939 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 940\r
941 return Status;\r
942}\r
943\r
944\r
945/**\r
d17371e8 946 Interface function to reset the port.\r
e237e7ae 947\r
8616fc4c 948 @param HubIf The hub interface.\r
949 @param Port The port to reset.\r
e237e7ae 950\r
8616fc4c 951 @retval EFI_SUCCESS The hub port is reset.\r
952 @retval EFI_TIMEOUT Failed to reset the port in time.\r
953 @retval Others Failed to reset the port.\r
e237e7ae 954\r
955**/\r
e237e7ae 956EFI_STATUS\r
957UsbHubResetPort (\r
958 IN USB_INTERFACE *HubIf,\r
959 IN UINT8 Port\r
960 )\r
961{\r
962 EFI_USB_PORT_STATUS PortState;\r
963 UINTN Index;\r
964 EFI_STATUS Status;\r
965\r
c52fa98c 966 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);\r
e237e7ae 967\r
968 if (EFI_ERROR (Status)) {\r
969 return Status;\r
970 }\r
971\r
972 //\r
973 // Drive the reset signal for at least 10ms. Check USB 2.0 Spec\r
974 // section 7.1.7.5 for timing requirements.\r
975 //\r
41e8ff27 976 gBS->Stall (USB_SET_PORT_RESET_STALL);\r
e237e7ae 977\r
978 //\r
979 // USB hub will clear RESET bit if reset is actually finished.\r
980 //\r
981 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
982\r
41e8ff27 983 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 984 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
985\r
986 if (!EFI_ERROR (Status) &&\r
987 !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
988\r
989 return EFI_SUCCESS;\r
990 }\r
991\r
41e8ff27 992 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 993 }\r
994\r
995 return EFI_TIMEOUT;\r
996}\r
997\r
998\r
999/**\r
8616fc4c 1000 Release the hub's control of the interface.\r
e237e7ae 1001\r
8616fc4c 1002 @param HubIf The hub interface.\r
e237e7ae 1003\r
8616fc4c 1004 @retval EFI_SUCCESS The interface is release of hub control.\r
e237e7ae 1005\r
1006**/\r
e237e7ae 1007EFI_STATUS\r
1008UsbHubRelease (\r
1009 IN USB_INTERFACE *HubIf\r
1010 )\r
1011{\r
1012 EFI_USB_IO_PROTOCOL *UsbIo;\r
1013 EFI_STATUS Status;\r
1014\r
1015 UsbIo = &HubIf->UsbIo;\r
1016 Status = UsbIo->UsbAsyncInterruptTransfer (\r
1017 UsbIo,\r
1018 HubIf->HubEp->Desc.EndpointAddress,\r
1019 FALSE,\r
1020 USB_HUB_POLL_INTERVAL,\r
1021 0,\r
1022 NULL,\r
1023 0\r
1024 );\r
1025\r
1026 if (EFI_ERROR (Status)) {\r
1027 return Status;\r
1028 }\r
1029\r
1030 gBS->CloseEvent (HubIf->HubNotify);\r
1031\r
1032 HubIf->IsHub = FALSE;\r
1033 HubIf->HubApi = NULL;\r
1034 HubIf->HubEp = NULL;\r
1035 HubIf->HubNotify = NULL;\r
1036\r
d2577026 1037 DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));\r
e237e7ae 1038 return EFI_SUCCESS;\r
1039}\r
1040\r
1041\r
1042\r
1043/**\r
8616fc4c 1044 Initialize the interface for root hub.\r
e237e7ae 1045\r
8616fc4c 1046 @param HubIf The root hub interface.\r
e237e7ae 1047\r
d17371e8 1048 @retval EFI_SUCCESS The interface is initialized for root hub.\r
8616fc4c 1049 @retval Others Failed to initialize the hub.\r
e237e7ae 1050\r
1051**/\r
e237e7ae 1052EFI_STATUS\r
1053UsbRootHubInit (\r
1054 IN USB_INTERFACE *HubIf\r
1055 )\r
1056{\r
1057 EFI_STATUS Status;\r
1058 UINT8 MaxSpeed;\r
1059 UINT8 NumOfPort;\r
1060 UINT8 Support64;\r
1061\r
1062 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);\r
1063\r
1064 if (EFI_ERROR (Status)) {\r
1065 return Status;\r
1066 }\r
1067\r
0e549d5b 1068 DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",\r
e237e7ae 1069 HubIf, MaxSpeed, NumOfPort));\r
1070\r
1071 HubIf->IsHub = TRUE;\r
1072 HubIf->HubApi = &mUsbRootHubApi;\r
1073 HubIf->HubEp = NULL;\r
1074 HubIf->MaxSpeed = MaxSpeed;\r
1075 HubIf->NumOfPort = NumOfPort;\r
1076 HubIf->HubNotify = NULL;\r
1077\r
1078 //\r
1079 // Create a timer to poll root hub ports periodically\r
1080 //\r
1081 Status = gBS->CreateEvent (\r
1082 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1083 TPL_CALLBACK,\r
1084 UsbRootHubEnumeration,\r
1085 HubIf,\r
1086 &HubIf->HubNotify\r
1087 );\r
1088\r
1089 if (EFI_ERROR (Status)) {\r
1090 return Status;\r
1091 }\r
1092\r
d2577026 1093 //\r
1094 // It should signal the event immediately here, or device detection\r
1095 // by bus enumeration might be delayed by the timer interval.\r
1096 //\r
1097 gBS->SignalEvent (HubIf->HubNotify);\r
1098\r
e237e7ae 1099 Status = gBS->SetTimer (\r
1100 HubIf->HubNotify,\r
1101 TimerPeriodic,\r
1102 USB_ROOTHUB_POLL_INTERVAL\r
1103 );\r
1104\r
1105 if (EFI_ERROR (Status)) {\r
1106 gBS->CloseEvent (HubIf->HubNotify);\r
1107 }\r
1108\r
1109 return Status;\r
1110}\r
1111\r
1112\r
e237e7ae 1113/**\r
1114 Get the port status. This function is required to\r
1115 ACK the port change bits although it will return\r
1116 the port changes in PortState. Bus enumeration code\r
1117 doesn't need to ACK the port change bits.\r
1118\r
8616fc4c 1119 @param HubIf The root hub interface.\r
1120 @param Port The root hub port to get the state.\r
1121 @param PortState Variable to return the port state.\r
e237e7ae 1122\r
8616fc4c 1123 @retval EFI_SUCCESS The port state is returned.\r
1124 @retval Others Failed to retrieve the port state.\r
e237e7ae 1125\r
1126**/\r
e237e7ae 1127EFI_STATUS\r
1128UsbRootHubGetPortStatus (\r
1129 IN USB_INTERFACE *HubIf,\r
1130 IN UINT8 Port,\r
1131 OUT EFI_USB_PORT_STATUS *PortState\r
1132 )\r
1133{\r
1134 USB_BUS *Bus;\r
1135 EFI_STATUS Status;\r
1136\r
1137 Bus = HubIf->Device->Bus;\r
1138 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);\r
1139\r
1140 return Status;\r
1141}\r
1142\r
1143\r
1144/**\r
1145 Clear the port change status.\r
1146\r
8616fc4c 1147 @param HubIf The root hub interface.\r
1148 @param Port The root hub port.\r
e237e7ae 1149\r
e237e7ae 1150**/\r
e237e7ae 1151VOID\r
1152UsbRootHubClearPortChange (\r
1153 IN USB_INTERFACE *HubIf,\r
1154 IN UINT8 Port\r
1155 )\r
1156{\r
1157 EFI_USB_PORT_STATUS PortState;\r
1158 USB_CHANGE_FEATURE_MAP *Map;\r
1159 UINTN Index;\r
1160 EFI_STATUS Status;\r
1161\r
1162 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);\r
1163\r
1164 if (EFI_ERROR (Status)) {\r
1165 return;\r
1166 }\r
1167\r
1168 //\r
1169 // OK, get the usb port status, now ACK the change bits.\r
1170 // Don't return error when failed to clear the change bits.\r
1171 // It may lead to extra port state report. USB bus should\r
1172 // be able to handle this.\r
1173 //\r
92870c98 1174 for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {\r
e237e7ae 1175 Map = &mRootHubFeatureMap[Index];\r
1176\r
1177 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
c52fa98c 1178 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);\r
e237e7ae 1179 }\r
1180 }\r
1181}\r
1182\r
1183\r
e237e7ae 1184/**\r
8616fc4c 1185 Set the root hub port feature.\r
e237e7ae 1186\r
8616fc4c 1187 @param HubIf The Usb hub interface.\r
1188 @param Port The hub port.\r
1189 @param Feature The feature to set.\r
e237e7ae 1190\r
8616fc4c 1191 @retval EFI_SUCCESS The root hub port is set with the feature.\r
1192 @retval Others Failed to set the feature.\r
e237e7ae 1193\r
1194**/\r
e237e7ae 1195EFI_STATUS\r
1196UsbRootHubSetPortFeature (\r
1197 IN USB_INTERFACE *HubIf,\r
1198 IN UINT8 Port,\r
1199 IN EFI_USB_PORT_FEATURE Feature\r
1200 )\r
1201{\r
1202 EFI_STATUS Status;\r
1203\r
1204 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1205\r
1206 return Status;\r
1207}\r
1208\r
1209\r
1210/**\r
8616fc4c 1211 Clear the root hub port feature.\r
e237e7ae 1212\r
8616fc4c 1213 @param HubIf The root hub interface.\r
1214 @param Port The root hub port.\r
1215 @param Feature The feature to clear.\r
e237e7ae 1216\r
8616fc4c 1217 @retval EFI_SUCCESS The root hub port is cleared of the feature.\r
1218 @retval Others Failed to clear the feature.\r
e237e7ae 1219\r
1220**/\r
e237e7ae 1221EFI_STATUS\r
1222UsbRootHubClearPortFeature (\r
1223 IN USB_INTERFACE *HubIf,\r
1224 IN UINT8 Port,\r
1225 IN EFI_USB_PORT_FEATURE Feature\r
1226 )\r
1227{\r
1228 EFI_STATUS Status;\r
1229\r
1230 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1231\r
1232 return Status;\r
1233}\r
1234\r
1235\r
1236/**\r
d17371e8 1237 Interface function to reset the root hub port.\r
e237e7ae 1238\r
8616fc4c 1239 @param RootIf The root hub interface.\r
1240 @param Port The port to reset.\r
e237e7ae 1241\r
8616fc4c 1242 @retval EFI_SUCCESS The hub port is reset.\r
1243 @retval EFI_TIMEOUT Failed to reset the port in time.\r
1244 @retval EFI_NOT_FOUND The low/full speed device connected to high speed.\r
1245 root hub is released to the companion UHCI.\r
1246 @retval Others Failed to reset the port.\r
e237e7ae 1247\r
1248**/\r
e237e7ae 1249EFI_STATUS\r
1250UsbRootHubResetPort (\r
1251 IN USB_INTERFACE *RootIf,\r
1252 IN UINT8 Port\r
1253 )\r
1254{\r
1255 USB_BUS *Bus;\r
1256 EFI_STATUS Status;\r
1257 EFI_USB_PORT_STATUS PortState;\r
1258 UINTN Index;\r
1259\r
1260 //\r
1261 // Notice: although EHCI requires that ENABLED bit be cleared\r
1262 // when reset the port, we don't need to care that here. It\r
1263 // should be handled in the EHCI driver.\r
1264 //\r
1265 Bus = RootIf->Device->Bus;\r
1266 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1267\r
1268 if (EFI_ERROR (Status)) {\r
d2577026 1269 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));\r
e237e7ae 1270 return Status;\r
1271 }\r
1272\r
1273 //\r
1274 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
1275 // section 7.1.7.5 for timing requirements.\r
1276 //\r
41e8ff27 1277 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);\r
e237e7ae 1278\r
1279 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1280\r
1281 if (EFI_ERROR (Status)) {\r
d2577026 1282 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));\r
e237e7ae 1283 return Status;\r
1284 }\r
1285\r
41e8ff27 1286 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);\r
e237e7ae 1287\r
1288 //\r
1289 // USB host controller won't clear the RESET bit until\r
1290 // reset is actually finished.\r
1291 //\r
1292 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
1293\r
41e8ff27 1294 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 1295 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
1296\r
1297 if (EFI_ERROR (Status)) {\r
1298 return Status;\r
1299 }\r
1300\r
1301 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
1302 break;\r
1303 }\r
1304\r
41e8ff27 1305 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1306 }\r
1307\r
41e8ff27 1308 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
1309 DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));\r
e237e7ae 1310 return EFI_TIMEOUT;\r
1311 }\r
1312\r
1313 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {\r
1314 //\r
1315 // OK, the port is reset. If root hub is of high speed and\r
1316 // the device is of low/full speed, release the ownership to\r
1317 // companion UHCI. If root hub is of full speed, it won't\r
1318 // automatically enable the port, we need to enable it manually.\r
1319 //\r
1320 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {\r
d2577026 1321 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));\r
e237e7ae 1322\r
1323 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);\r
1324 return EFI_NOT_FOUND;\r
1325\r
1326 } else {\r
1327\r
1328 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);\r
1329\r
1330 if (EFI_ERROR (Status)) {\r
d2577026 1331 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));\r
e237e7ae 1332 return Status;\r
1333 }\r
1334\r
41e8ff27 1335 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);\r
e237e7ae 1336 }\r
1337 }\r
1338\r
1339 return EFI_SUCCESS;\r
1340}\r
1341\r
1342\r
1343/**\r
8616fc4c 1344 Release the root hub's control of the interface.\r
e237e7ae 1345\r
8616fc4c 1346 @param HubIf The root hub interface.\r
e237e7ae 1347\r
1348 @retval EFI_SUCCESS The root hub's control of the interface is\r
1349 released.\r
1350\r
1351**/\r
e237e7ae 1352EFI_STATUS\r
1353UsbRootHubRelease (\r
1354 IN USB_INTERFACE *HubIf\r
1355 )\r
1356{\r
0e549d5b 1357 DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));\r
e237e7ae 1358\r
1359 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);\r
1360 gBS->CloseEvent (HubIf->HubNotify);\r
1361\r
1362 return EFI_SUCCESS;\r
1363}\r
1364\r
1365USB_HUB_API mUsbHubApi = {\r
1366 UsbHubInit,\r
1367 UsbHubGetPortStatus,\r
1368 UsbHubClearPortChange,\r
1369 UsbHubSetPortFeature,\r
1370 UsbHubClearPortFeature,\r
1371 UsbHubResetPort,\r
1372 UsbHubRelease\r
1373};\r
1374\r
1375USB_HUB_API mUsbRootHubApi = {\r
1376 UsbRootHubInit,\r
1377 UsbRootHubGetPortStatus,\r
1378 UsbRootHubClearPortChange,\r
1379 UsbRootHubSetPortFeature,\r
1380 UsbRootHubClearPortFeature,\r
1381 UsbRootHubResetPort,\r
1382 UsbRootHubRelease\r
1383};\r