TianoCore EDK2 master
Loading...
Searching...
No Matches
UsbHub.c
Go to the documentation of this file.
1
10#include "UsbBus.h"
11
12//
13// Array that maps the change bit to feature value which is
14// used to clear these change bit. USB HUB API will clear
15// these change bit automatically. For non-root hub, these
16// bits determine whether hub will report the port in changed
17// bit maps.
18//
19USB_CHANGE_FEATURE_MAP mHubFeatureMap[] = {
20 { USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange },
21 { USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange },
22 { USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange },
23 { USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange },
24 { USB_PORT_STAT_C_RESET, EfiUsbPortResetChange }
25};
26
27USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[] = {
28 { USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange },
29 { USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange },
30 { USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange },
31 { USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange },
32 { USB_PORT_STAT_C_RESET, EfiUsbPortResetChange },
33};
34
35//
36// USB hub class specific requests. Although USB hub
37// is related to an interface, these requests are sent
38// to the control endpoint of the device.
39//
40
53 IN USB_DEVICE *HubDev,
54 IN UINT16 Depth
55 )
56{
57 EFI_STATUS Status;
58
59 Status = UsbCtrlRequest (
60 HubDev,
61 EfiUsbNoData,
62 USB_REQ_TYPE_CLASS,
63 USB_HUB_TARGET_HUB,
64 USB_HUB_REQ_SET_DEPTH,
65 Depth,
66 0,
67 NULL,
68 0
69 );
70
71 return Status;
72}
73
86 IN USB_DEVICE *HubDev,
87 IN UINT16 Feature
88 )
89{
90 EFI_STATUS Status;
91
92 Status = UsbCtrlRequest (
93 HubDev,
94 EfiUsbNoData,
95 USB_REQ_TYPE_CLASS,
96 USB_HUB_TARGET_HUB,
97 USB_HUB_REQ_CLEAR_FEATURE,
98 Feature,
99 0,
100 NULL,
101 0
102 );
103
104 return Status;
105}
106
120 IN USB_DEVICE *HubDev,
121 IN UINT8 Port,
122 IN UINT16 Feature
123 )
124{
125 EFI_STATUS Status;
126
127 //
128 // In USB bus, all the port index starts from 0. But HUB
129 // indexes its port from 1. So, port number is added one.
130 //
131 Status = UsbCtrlRequest (
132 HubDev,
133 EfiUsbNoData,
134 USB_REQ_TYPE_CLASS,
135 USB_HUB_TARGET_PORT,
136 USB_HUB_REQ_CLEAR_FEATURE,
137 Feature,
138 (UINT16)(Port + 1),
139 NULL,
140 0
141 );
142
143 return Status;
144}
145
165 IN USB_DEVICE *HubDev,
166 IN UINT8 Port,
167 IN UINT16 DevAddr,
168 IN UINT16 EpNum,
169 IN UINT16 EpType
170 )
171{
172 EFI_STATUS Status;
173 UINT16 Value;
174
175 //
176 // Check USB2.0 spec page 424 for wValue's encoding
177 //
178 Value = (UINT16)((EpNum & 0x0F) | (DevAddr << 4) |
179 ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
180
181 Status = UsbCtrlRequest (
182 HubDev,
183 EfiUsbNoData,
184 USB_REQ_TYPE_CLASS,
185 USB_HUB_TARGET_PORT,
186 USB_HUB_REQ_CLEAR_TT,
187 Value,
188 (UINT16)(Port + 1),
189 NULL,
190 0
191 );
192
193 return Status;
194}
195
209 IN USB_DEVICE *HubDev,
210 OUT VOID *Buf,
211 IN UINTN Len
212 )
213{
214 EFI_STATUS Status;
215 UINT8 DescType;
216
217 DescType = (HubDev->Speed == EFI_USB_SPEED_SUPER) ?
218 USB_DESC_TYPE_HUB_SUPER_SPEED :
219 USB_DESC_TYPE_HUB;
220
221 Status = UsbCtrlRequest (
222 HubDev,
223 EfiUsbDataIn,
224 USB_REQ_TYPE_CLASS,
225 USB_HUB_TARGET_HUB,
226 USB_HUB_REQ_GET_DESC,
227 (UINT16)(DescType << 8),
228 0,
229 Buf,
230 Len
231 );
232
233 return Status;
234}
235
248 IN USB_DEVICE *HubDev,
249 OUT UINT32 *State
250 )
251{
252 EFI_STATUS Status;
253
254 Status = UsbCtrlRequest (
255 HubDev,
256 EfiUsbDataIn,
257 USB_REQ_TYPE_CLASS,
258 USB_HUB_TARGET_HUB,
259 USB_HUB_REQ_GET_STATUS,
260 0,
261 0,
262 State,
263 4
264 );
265
266 return Status;
267}
268
282 IN USB_DEVICE *HubDev,
283 IN UINT8 Port,
284 OUT VOID *State
285 )
286{
287 EFI_STATUS Status;
288
289 //
290 // In USB bus, all the port index starts from 0. But HUB
291 // indexes its port from 1. So, port number is added one.
292 // No need to convert the hub bit to UEFI definition, they
293 // are the same
294 //
295 Status = UsbCtrlRequest (
296 HubDev,
297 EfiUsbDataIn,
298 USB_REQ_TYPE_CLASS,
299 USB_HUB_TARGET_PORT,
300 USB_HUB_REQ_GET_STATUS,
301 0,
302 (UINT16)(Port + 1),
303 State,
304 4
305 );
306
307 return Status;
308}
309
323 IN USB_DEVICE *HubDev,
324 IN UINT8 Port,
325 IN UINT8 Feature
326 )
327{
328 EFI_STATUS Status;
329
330 //
331 // In USB bus, all the port index starts from 0. But HUB
332 // indexes its port from 1. So, port number is added one.
333 //
334 Status = UsbCtrlRequest (
335 HubDev,
336 EfiUsbNoData,
337 USB_REQ_TYPE_CLASS,
338 USB_HUB_TARGET_PORT,
339 USB_HUB_REQ_SET_FEATURE,
340 Feature,
341 (UINT16)(Port + 1),
342 NULL,
343 0
344 );
345
346 return Status;
347}
348
363 IN USB_DEVICE *HubDev,
365 )
366{
367 EFI_STATUS Status;
368
369 //
370 // First get the hub descriptor length
371 //
372 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
373
374 if (EFI_ERROR (Status)) {
375 return Status;
376 }
377
378 //
379 // Get the whole hub descriptor
380 //
381 return UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
382}
383
396 IN USB_DEVICE *HubDev
397 )
398{
399 EFI_USB_PORT_STATUS HubState;
400 EFI_STATUS Status;
401
402 Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *)&HubState);
403
404 if (EFI_ERROR (Status)) {
405 return Status;
406 }
407
408 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
409 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
410 }
411
412 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
413 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
414 }
415
416 return EFI_SUCCESS;
417}
418
428BOOLEAN
430 IN USB_INTERFACE *UsbIf
431 )
432{
434
435 //
436 // If the hub is a high-speed hub with multiple TT,
437 // the hub will has a default setting of single TT.
438 //
439 Setting = &UsbIf->IfSetting->Desc;
440
441 if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
442 (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE))
443 {
444 return TRUE;
445 }
446
447 return FALSE;
448}
449
465EFIAPI
467 IN VOID *Data,
468 IN UINTN DataLength,
469 IN VOID *Context,
470 IN UINT32 Result
471 )
472{
473 USB_INTERFACE *HubIf;
474 EFI_USB_IO_PROTOCOL *UsbIo;
476 EFI_STATUS Status;
477
478 HubIf = (USB_INTERFACE *)Context;
479 UsbIo = &(HubIf->UsbIo);
480 EpDesc = &(HubIf->HubEp->Desc);
481
482 if (Result != EFI_USB_NOERROR) {
483 //
484 // If endpoint is stalled, clear the stall. Use UsbIo to access
485 // the control transfer so internal status are maintained.
486 //
487 if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
489 UsbIo,
490 USB_TARGET_ENDPOINT,
491 USB_FEATURE_ENDPOINT_HALT,
492 EpDesc->EndpointAddress
493 );
494 }
495
496 //
497 // Delete and submit a new async interrupt
498 //
499 Status = UsbIo->UsbAsyncInterruptTransfer (
500 UsbIo,
501 EpDesc->EndpointAddress,
502 FALSE,
503 0,
504 0,
505 NULL,
506 NULL
507 );
508
509 if (EFI_ERROR (Status)) {
510 DEBUG ((DEBUG_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
511 return Status;
512 }
513
514 Status = UsbIo->UsbAsyncInterruptTransfer (
515 UsbIo,
516 EpDesc->EndpointAddress,
517 TRUE,
518 USB_HUB_POLL_INTERVAL,
519 HubIf->NumOfPort / 8 + 1,
521 HubIf
522 );
523
524 if (EFI_ERROR (Status)) {
525 DEBUG ((DEBUG_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
526 }
527
528 return Status;
529 }
530
531 if ((DataLength == 0) || (Data == NULL)) {
532 return EFI_SUCCESS;
533 }
534
535 //
536 // OK, actually something is changed, save the change map
537 // then signal the HUB to do enumeration. This is a good
538 // practise since UsbOnHubInterrupt is called in the context
539 // of host controller's AsyncInterrupt monitor.
540 //
541 HubIf->ChangeMap = AllocateZeroPool (DataLength);
542
543 if (HubIf->ChangeMap == NULL) {
544 return EFI_OUT_OF_RESOURCES;
545 }
546
547 CopyMem (HubIf->ChangeMap, Data, DataLength);
548 gBS->SignalEvent (HubIf->HubNotify);
549
550 return EFI_SUCCESS;
551}
552
564 IN USB_INTERFACE *HubIf
565 )
566{
567 UINT8 HubDescBuffer[256];
568 EFI_USB_HUB_DESCRIPTOR *HubDesc;
569 USB_ENDPOINT_DESC *EpDesc;
570 USB_INTERFACE_SETTING *Setting;
571 EFI_USB_IO_PROTOCOL *UsbIo;
572 USB_DEVICE *HubDev;
573 EFI_STATUS Status;
574 UINT8 Index;
575 UINT8 NumEndpoints;
576 UINT16 Depth;
577
578 //
579 // Locate the interrupt endpoint for port change map
580 //
581 HubIf->IsHub = FALSE;
582 Setting = HubIf->IfSetting;
583 HubDev = HubIf->Device;
584 EpDesc = NULL;
585 NumEndpoints = Setting->Desc.NumEndpoints;
586
587 for (Index = 0; Index < NumEndpoints; Index++) {
588 ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
589
590 EpDesc = Setting->Endpoints[Index];
591
592 if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
593 (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT))
594 {
595 break;
596 }
597 }
598
599 if (Index == NumEndpoints) {
600 DEBUG ((DEBUG_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
601 return EFI_DEVICE_ERROR;
602 }
603
604 //
605 // The length field of descriptor is UINT8 type, so the buffer
606 // with 256 bytes is enough to hold the descriptor data.
607 //
608 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)HubDescBuffer;
609 Status = UsbHubReadDesc (HubDev, HubDesc);
610
611 if (EFI_ERROR (Status)) {
612 DEBUG ((DEBUG_ERROR, "UsbHubInit: failed to read HUB descriptor - %r\n", Status));
613 return Status;
614 }
615
616 HubIf->NumOfPort = HubDesc->NumPorts;
617
618 DEBUG ((DEBUG_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address, HubIf->NumOfPort));
619
620 //
621 // OK, set IsHub to TRUE. Now usb bus can handle this device
622 // as a working HUB. If failed earlier, bus driver will not
623 // recognize it as a hub. Other parts of the bus should be able
624 // to work.
625 //
626 HubIf->IsHub = TRUE;
627 HubIf->HubApi = &mUsbHubApi;
628 HubIf->HubEp = EpDesc;
629
630 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
631 Depth = (UINT16)(HubIf->Device->Tier - 1);
632 DEBUG ((DEBUG_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
633 UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
634
635 for (Index = 0; Index < HubDesc->NumPorts; Index++) {
636 UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
637 }
638 } else {
639 //
640 // Feed power to all the hub ports. It should be ok
641 // for both gang/individual powered hubs.
642 //
643 for (Index = 0; Index < HubDesc->NumPorts; Index++) {
644 UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE)USB_HUB_PORT_POWER);
645 }
646
647 //
648 // Update for the usb hub has no power on delay requirement
649 //
650 if (HubDesc->PwrOn2PwrGood > 0) {
651 gBS->Stall (HubDesc->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
652 }
653
654 UsbHubAckHubStatus (HubIf->Device);
655 }
656
657 //
658 // Create an event to enumerate the hub's port. On
659 //
660 Status = gBS->CreateEvent (
661 EVT_NOTIFY_SIGNAL,
662 TPL_CALLBACK,
664 HubIf,
665 &HubIf->HubNotify
666 );
667
668 if (EFI_ERROR (Status)) {
669 DEBUG ((
670 DEBUG_ERROR,
671 "UsbHubInit: failed to create signal for hub %d - %r\n",
672 HubDev->Address,
673 Status
674 ));
675
676 return Status;
677 }
678
679 //
680 // Create AsyncInterrupt to query hub port change endpoint
681 // periodically. If the hub ports are changed, hub will return
682 // changed port map from the interrupt endpoint. The port map
683 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
684 // host change status).
685 //
686 UsbIo = &HubIf->UsbIo;
687 Status = UsbIo->UsbAsyncInterruptTransfer (
688 UsbIo,
689 EpDesc->Desc.EndpointAddress,
690 TRUE,
691 USB_HUB_POLL_INTERVAL,
692 HubIf->NumOfPort / 8 + 1,
694 HubIf
695 );
696
697 if (EFI_ERROR (Status)) {
698 DEBUG ((
699 DEBUG_ERROR,
700 "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
701 HubDev->Address,
702 Status
703 ));
704
705 gBS->CloseEvent (HubIf->HubNotify);
706 HubIf->HubNotify = NULL;
707
708 return Status;
709 }
710
711 DEBUG ((DEBUG_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
712 return Status;
713}
714
731 IN USB_INTERFACE *HubIf,
732 IN UINT8 Port,
733 OUT EFI_USB_PORT_STATUS *PortState
734 )
735{
736 EFI_STATUS Status;
737
738 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
739
740 return Status;
741}
742
750VOID
752 IN USB_INTERFACE *HubIf,
753 IN UINT8 Port
754 )
755{
756 EFI_USB_PORT_STATUS PortState;
758 UINTN Index;
759 EFI_STATUS Status;
760
761 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
762
763 if (EFI_ERROR (Status)) {
764 return;
765 }
766
767 //
768 // OK, get the usb port status, now ACK the change bits.
769 // Don't return error when failed to clear the change bits.
770 // It may lead to extra port state report. USB bus should
771 // be able to handle this.
772 //
773 for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {
774 Map = &mHubFeatureMap[Index];
775
776 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
777 UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16)Map->Feature);
778 }
779 }
780}
781
795 IN USB_INTERFACE *HubIf,
796 IN UINT8 Port,
798 )
799{
800 EFI_STATUS Status;
801
802 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8)Feature);
803
804 return Status;
805}
806
820 IN USB_INTERFACE *HubIf,
821 IN UINT8 Port,
823 )
824{
825 EFI_STATUS Status;
826
827 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8)Feature);
828
829 return Status;
830}
831
845 IN USB_INTERFACE *HubIf,
846 IN UINT8 Port
847 )
848{
849 EFI_USB_PORT_STATUS PortState;
850 UINTN Index;
851 EFI_STATUS Status;
852
853 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE)USB_HUB_PORT_RESET);
854
855 if (EFI_ERROR (Status)) {
856 return Status;
857 }
858
859 //
860 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
861 // section 7.1.7.5 for timing requirements.
862 //
863 gBS->Stall (USB_SET_PORT_RESET_STALL);
864
865 //
866 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
867 //
868 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
869
870 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
871 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
872
873 if (EFI_ERROR (Status)) {
874 return Status;
875 }
876
877 if (!EFI_ERROR (Status) &&
878 USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET))
879 {
880 gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
881 return EFI_SUCCESS;
882 }
883
884 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
885 }
886
887 return EFI_TIMEOUT;
888}
889
900 IN USB_INTERFACE *HubIf
901 )
902{
903 EFI_USB_IO_PROTOCOL *UsbIo;
904 EFI_STATUS Status;
905
906 UsbIo = &HubIf->UsbIo;
907 Status = UsbIo->UsbAsyncInterruptTransfer (
908 UsbIo,
909 HubIf->HubEp->Desc.EndpointAddress,
910 FALSE,
911 USB_HUB_POLL_INTERVAL,
912 0,
913 NULL,
914 0
915 );
916
917 if (EFI_ERROR (Status)) {
918 return Status;
919 }
920
921 gBS->CloseEvent (HubIf->HubNotify);
922
923 HubIf->IsHub = FALSE;
924 HubIf->HubApi = NULL;
925 HubIf->HubEp = NULL;
926 HubIf->HubNotify = NULL;
927
928 DEBUG ((DEBUG_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
929 return EFI_SUCCESS;
930}
931
943 IN USB_INTERFACE *HubIf
944 )
945{
946 EFI_STATUS Status;
947 UINT8 MaxSpeed;
948 UINT8 NumOfPort;
949 UINT8 Support64;
950
951 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
952
953 if (EFI_ERROR (Status)) {
954 return Status;
955 }
956
957 DEBUG ((
958 DEBUG_INFO,
959 "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
960 HubIf,
961 MaxSpeed,
962 NumOfPort
963 ));
964
965 HubIf->IsHub = TRUE;
966 HubIf->HubApi = &mUsbRootHubApi;
967 HubIf->HubEp = NULL;
968 HubIf->MaxSpeed = MaxSpeed;
969 HubIf->NumOfPort = NumOfPort;
970 HubIf->HubNotify = NULL;
971
972 //
973 // Create a timer to poll root hub ports periodically
974 //
975 Status = gBS->CreateEvent (
976 EVT_TIMER | EVT_NOTIFY_SIGNAL,
977 TPL_CALLBACK,
979 HubIf,
980 &HubIf->HubNotify
981 );
982
983 if (EFI_ERROR (Status)) {
984 return Status;
985 }
986
987 //
988 // It should signal the event immediately here, or device detection
989 // by bus enumeration might be delayed by the timer interval.
990 //
991 gBS->SignalEvent (HubIf->HubNotify);
992
993 Status = gBS->SetTimer (
994 HubIf->HubNotify,
996 USB_ROOTHUB_POLL_INTERVAL
997 );
998
999 if (EFI_ERROR (Status)) {
1000 gBS->CloseEvent (HubIf->HubNotify);
1001 }
1002
1003 return Status;
1004}
1005
1022 IN USB_INTERFACE *HubIf,
1023 IN UINT8 Port,
1024 OUT EFI_USB_PORT_STATUS *PortState
1025 )
1026{
1027 USB_BUS *Bus;
1028 EFI_STATUS Status;
1029
1030 Bus = HubIf->Device->Bus;
1031 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
1032
1033 return Status;
1034}
1035
1043VOID
1045 IN USB_INTERFACE *HubIf,
1046 IN UINT8 Port
1047 )
1048{
1049 EFI_USB_PORT_STATUS PortState;
1051 UINTN Index;
1052 EFI_STATUS Status;
1053
1054 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
1055
1056 if (EFI_ERROR (Status)) {
1057 return;
1058 }
1059
1060 //
1061 // OK, get the usb port status, now ACK the change bits.
1062 // Don't return error when failed to clear the change bits.
1063 // It may lead to extra port state report. USB bus should
1064 // be able to handle this.
1065 //
1066 for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {
1067 Map = &mRootHubFeatureMap[Index];
1068
1069 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
1070 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE)Map->Feature);
1071 }
1072 }
1073}
1074
1088 IN USB_INTERFACE *HubIf,
1089 IN UINT8 Port,
1090 IN EFI_USB_PORT_FEATURE Feature
1091 )
1092{
1093 EFI_STATUS Status;
1094
1095 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1096
1097 return Status;
1098}
1099
1113 IN USB_INTERFACE *HubIf,
1114 IN UINT8 Port,
1115 IN EFI_USB_PORT_FEATURE Feature
1116 )
1117{
1118 EFI_STATUS Status;
1119
1120 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1121
1122 return Status;
1123}
1124
1140 IN USB_INTERFACE *RootIf,
1141 IN UINT8 Port
1142 )
1143{
1144 USB_BUS *Bus;
1145 EFI_STATUS Status;
1146 EFI_USB_PORT_STATUS PortState;
1147 UINTN Index;
1148
1149 //
1150 // Notice: although EHCI requires that ENABLED bit be cleared
1151 // when reset the port, we don't need to care that here. It
1152 // should be handled in the EHCI driver.
1153 //
1154 Bus = RootIf->Device->Bus;
1155
1156 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1157
1158 if (EFI_ERROR (Status)) {
1159 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
1160 return Status;
1161 }
1162
1163 //
1164 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1165 // section 7.1.7.5 for timing requirements.
1166 //
1167 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
1168
1169 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1170
1171 if (EFI_ERROR (Status)) {
1172 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
1173 return Status;
1174 }
1175
1176 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
1177
1178 //
1179 // USB host controller won't clear the RESET bit until
1180 // reset is actually finished.
1181 //
1182 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
1183
1184 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1185 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
1186
1187 if (EFI_ERROR (Status)) {
1188 return Status;
1189 }
1190
1191 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
1192 break;
1193 }
1194
1195 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
1196 }
1197
1198 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1199 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
1200 return EFI_TIMEOUT;
1201 }
1202
1203 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
1204 //
1205 // OK, the port is reset. If root hub is of high speed and
1206 // the device is of low/full speed, release the ownership to
1207 // companion UHCI. If root hub is of full speed, it won't
1208 // automatically enable the port, we need to enable it manually.
1209 //
1210 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
1211 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
1212
1213 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
1214 return EFI_NOT_FOUND;
1215 } else {
1216 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
1217
1218 if (EFI_ERROR (Status)) {
1219 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
1220 return Status;
1221 }
1222
1223 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
1224 }
1225 }
1226
1227 return EFI_SUCCESS;
1228}
1229
1241 IN USB_INTERFACE *HubIf
1242 )
1243{
1244 DEBUG ((DEBUG_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
1245
1246 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
1247 gBS->CloseEvent (HubIf->HubNotify);
1248
1249 return EFI_SUCCESS;
1250}
1251
1252USB_HUB_API mUsbHubApi = {
1253 UsbHubInit,
1260};
1261
1262USB_HUB_API mUsbRootHubApi = {
1270};
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_USB_PORT_FEATURE
#define USB_PORT_STAT_C_CONNECTION
#define EFI_USB_SPEED_SUPER
4.8 Gb/s, USB 3.0 XHCI HC.
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerPeriodic
Definition: UefiSpec.h:535
EFI_STATUS UsbIoClearFeature(IN EFI_USB_IO_PROTOCOL *UsbIo, IN UINTN Target, IN UINT16 Feature, IN UINT16 Index)
Definition: UsbDesc.c:983
EFI_STATUS UsbCtrlRequest(IN USB_DEVICE *UsbDev, IN EFI_USB_DATA_DIRECTION Direction, IN UINTN Type, IN UINTN Target, IN UINTN Request, IN UINT16 Value, IN UINT16 Index, IN OUT VOID *Buf, IN UINTN Length)
Definition: UsbDesc.c:451
VOID EFIAPI UsbHubEnumeration(IN EFI_EVENT Event, IN VOID *Context)
Definition: UsbEnumer.c:1012
VOID EFIAPI UsbRootHubEnumeration(IN EFI_EVENT Event, IN VOID *Context)
Definition: UsbEnumer.c:1069
EFI_STATUS UsbRootHubResetPort(IN USB_INTERFACE *RootIf, IN UINT8 Port)
Definition: UsbHub.c:1139
EFI_STATUS UsbHubCtrlClearTTBuffer(IN USB_DEVICE *HubDev, IN UINT8 Port, IN UINT16 DevAddr, IN UINT16 EpNum, IN UINT16 EpType)
Definition: UsbHub.c:164
EFI_STATUS UsbHubInit(IN USB_INTERFACE *HubIf)
Definition: UsbHub.c:563
EFI_STATUS EFIAPI UsbOnHubInterrupt(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Result)
Definition: UsbHub.c:466
EFI_STATUS UsbRootHubClearPortFeature(IN USB_INTERFACE *HubIf, IN UINT8 Port, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbHub.c:1112
EFI_STATUS UsbHubResetPort(IN USB_INTERFACE *HubIf, IN UINT8 Port)
Definition: UsbHub.c:844
EFI_STATUS UsbHubCtrlSetPortFeature(IN USB_DEVICE *HubDev, IN UINT8 Port, IN UINT8 Feature)
Definition: UsbHub.c:322
EFI_STATUS UsbHubCtrlClearPortFeature(IN USB_DEVICE *HubDev, IN UINT8 Port, IN UINT16 Feature)
Definition: UsbHub.c:119
EFI_STATUS UsbHubClearPortFeature(IN USB_INTERFACE *HubIf, IN UINT8 Port, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbHub.c:819
EFI_STATUS UsbRootHubGetPortStatus(IN USB_INTERFACE *HubIf, IN UINT8 Port, OUT EFI_USB_PORT_STATUS *PortState)
Definition: UsbHub.c:1021
EFI_STATUS UsbHubCtrlGetPortStatus(IN USB_DEVICE *HubDev, IN UINT8 Port, OUT VOID *State)
Definition: UsbHub.c:281
EFI_STATUS UsbHubRelease(IN USB_INTERFACE *HubIf)
Definition: UsbHub.c:899
EFI_STATUS UsbHubAckHubStatus(IN USB_DEVICE *HubDev)
Definition: UsbHub.c:395
EFI_STATUS UsbHubCtrlSetHubDepth(IN USB_DEVICE *HubDev, IN UINT16 Depth)
Definition: UsbHub.c:52
EFI_STATUS UsbRootHubInit(IN USB_INTERFACE *HubIf)
Definition: UsbHub.c:942
EFI_STATUS UsbHubGetPortStatus(IN USB_INTERFACE *HubIf, IN UINT8 Port, OUT EFI_USB_PORT_STATUS *PortState)
Definition: UsbHub.c:730
VOID UsbRootHubClearPortChange(IN USB_INTERFACE *HubIf, IN UINT8 Port)
Definition: UsbHub.c:1044
EFI_STATUS UsbHubSetPortFeature(IN USB_INTERFACE *HubIf, IN UINT8 Port, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbHub.c:794
EFI_STATUS UsbRootHubRelease(IN USB_INTERFACE *HubIf)
Definition: UsbHub.c:1240
EFI_STATUS UsbHubCtrlGetHubDesc(IN USB_DEVICE *HubDev, OUT VOID *Buf, IN UINTN Len)
Definition: UsbHub.c:208
EFI_STATUS UsbHubCtrlGetHubStatus(IN USB_DEVICE *HubDev, OUT UINT32 *State)
Definition: UsbHub.c:247
EFI_STATUS UsbHubReadDesc(IN USB_DEVICE *HubDev, OUT EFI_USB_HUB_DESCRIPTOR *HubDesc)
Definition: UsbHub.c:362
EFI_STATUS UsbHubCtrlClearHubFeature(IN USB_DEVICE *HubDev, IN UINT16 Feature)
Definition: UsbHub.c:85
BOOLEAN UsbIsHubInterface(IN USB_INTERFACE *UsbIf)
Definition: UsbHub.c:429
EFI_STATUS UsbRootHubSetPortFeature(IN USB_INTERFACE *HubIf, IN UINT8 Port, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbHub.c:1087
VOID UsbHubClearPortChange(IN USB_INTERFACE *HubIf, IN UINT8 Port)
Definition: UsbHub.c:751
EFI_STATUS UsbHcGetRootHubPortStatus(IN USB_BUS *UsbBus, IN UINT8 PortIndex, OUT EFI_USB_PORT_STATUS *PortStatus)
Definition: UsbUtility.c:95
EFI_STATUS UsbHcClearRootHubPortFeature(IN USB_BUS *UsbBus, IN UINT8 PortIndex, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbUtility.c:153
EFI_STATUS UsbHcSetRootHubPortFeature(IN USB_BUS *UsbBus, IN UINT8 PortIndex, IN EFI_USB_PORT_FEATURE Feature)
Definition: UsbUtility.c:124
EFI_STATUS UsbHcGetCapability(IN USB_BUS *UsbBus, OUT UINT8 *MaxSpeed, OUT UINT8 *NumOfPort, OUT UINT8 *Is64BitCapable)
Definition: UsbUtility.c:57
UINT16 PortChangeStatus
Contains current port status change bitmap.
UINT16 PortStatus
Contains current port status bitmap.