3 Usb bus enumeration support.
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Return the endpoint descriptor in this interface.
15 @param UsbIf The interface to search in.
16 @param EpAddr The address of the endpoint to return.
18 @return The endpoint descriptor or NULL.
23 IN USB_INTERFACE
*UsbIf
,
27 USB_ENDPOINT_DESC
*EpDesc
;
31 NumEndpoints
= UsbIf
->IfSetting
->Desc
.NumEndpoints
;
33 for (Index
= 0; Index
< NumEndpoints
; Index
++) {
34 EpDesc
= UsbIf
->IfSetting
->Endpoints
[Index
];
36 if (EpDesc
->Desc
.EndpointAddress
== EpAddr
) {
45 Free the resource used by USB interface.
47 @param UsbIf The USB interface to free.
49 @retval EFI_ACCESS_DENIED The interface is still occupied.
50 @retval EFI_SUCCESS The interface is freed.
54 IN USB_INTERFACE
*UsbIf
59 UsbCloseHostProtoByChild (UsbIf
->Device
->Bus
, UsbIf
->Handle
);
61 Status
= gBS
->UninstallMultipleProtocolInterfaces (
63 &gEfiDevicePathProtocolGuid
,
65 &gEfiUsbIoProtocolGuid
,
69 if (!EFI_ERROR (Status
)) {
70 if (UsbIf
->DevicePath
!= NULL
) {
71 FreePool (UsbIf
->DevicePath
);
76 UsbOpenHostProtoByChild (UsbIf
->Device
->Bus
, UsbIf
->Handle
);
83 Create an interface for the descriptor IfDesc. Each
84 device's configuration can have several interfaces.
86 @param Device The device has the interface descriptor.
87 @param IfDesc The interface descriptor.
89 @return The created USB interface for the descriptor, or NULL.
94 IN USB_DEVICE
*Device
,
95 IN USB_INTERFACE_DESC
*IfDesc
98 USB_DEVICE_PATH UsbNode
;
100 USB_INTERFACE
*HubIf
;
103 UsbIf
= AllocateZeroPool (sizeof (USB_INTERFACE
));
109 UsbIf
->Signature
= USB_INTERFACE_SIGNATURE
;
110 UsbIf
->Device
= Device
;
111 UsbIf
->IfDesc
= IfDesc
;
112 ASSERT (IfDesc
->ActiveIndex
< USB_MAX_INTERFACE_SETTING
);
113 UsbIf
->IfSetting
= IfDesc
->Settings
[IfDesc
->ActiveIndex
];
118 sizeof (EFI_USB_IO_PROTOCOL
)
122 // Install protocols for USBIO and device path
124 UsbNode
.Header
.Type
= MESSAGING_DEVICE_PATH
;
125 UsbNode
.Header
.SubType
= MSG_USB_DP
;
126 UsbNode
.ParentPortNumber
= Device
->ParentPort
;
127 UsbNode
.InterfaceNumber
= UsbIf
->IfSetting
->Desc
.InterfaceNumber
;
129 SetDevicePathNodeLength (&UsbNode
.Header
, sizeof (UsbNode
));
131 HubIf
= Device
->ParentIf
;
132 ASSERT (HubIf
!= NULL
);
134 UsbIf
->DevicePath
= AppendDevicePathNode (HubIf
->DevicePath
, &UsbNode
.Header
);
136 if (UsbIf
->DevicePath
== NULL
) {
137 DEBUG ((DEBUG_ERROR
, "UsbCreateInterface: failed to create device path\n"));
139 Status
= EFI_OUT_OF_RESOURCES
;
143 Status
= gBS
->InstallMultipleProtocolInterfaces (
145 &gEfiDevicePathProtocolGuid
,
147 &gEfiUsbIoProtocolGuid
,
152 if (EFI_ERROR (Status
)) {
153 DEBUG ((DEBUG_ERROR
, "UsbCreateInterface: failed to install UsbIo - %r\n", Status
));
158 // Open USB Host Controller Protocol by Child
160 Status
= UsbOpenHostProtoByChild (Device
->Bus
, UsbIf
->Handle
);
162 if (EFI_ERROR (Status
)) {
163 gBS
->UninstallMultipleProtocolInterfaces (
165 &gEfiDevicePathProtocolGuid
,
167 &gEfiUsbIoProtocolGuid
,
172 DEBUG ((DEBUG_ERROR
, "UsbCreateInterface: failed to open host for child - %r\n", Status
));
179 if (UsbIf
->DevicePath
!= NULL
) {
180 FreePool (UsbIf
->DevicePath
);
188 Free the resource used by this USB device.
190 @param Device The USB device to free.
195 IN USB_DEVICE
*Device
198 if (Device
->DevDesc
!= NULL
) {
199 UsbFreeDevDesc (Device
->DevDesc
);
202 gBS
->FreePool (Device
);
206 Create a device which is on the parent's ParentPort port.
208 @param ParentIf The parent HUB interface.
209 @param ParentPort The port on the HUB this device is connected to.
211 @return Created USB device, Or NULL.
216 IN USB_INTERFACE
*ParentIf
,
222 ASSERT (ParentIf
!= NULL
);
224 Device
= AllocateZeroPool (sizeof (USB_DEVICE
));
226 if (Device
== NULL
) {
230 Device
->Bus
= ParentIf
->Device
->Bus
;
231 Device
->MaxPacket0
= 8;
232 Device
->ParentAddr
= ParentIf
->Device
->Address
;
233 Device
->ParentIf
= ParentIf
;
234 Device
->ParentPort
= ParentPort
;
235 Device
->Tier
= (UINT8
)(ParentIf
->Device
->Tier
+ 1);
240 Connect the USB interface with its driver. EFI USB bus will
241 create a USB interface for each separate interface descriptor.
243 @param UsbIf The interface to connect driver to.
245 @return EFI_SUCCESS Interface is managed by some driver.
246 @return Others Failed to locate a driver for this interface.
251 IN USB_INTERFACE
*UsbIf
257 Status
= EFI_SUCCESS
;
260 // Hub is maintained by the USB bus driver. Otherwise try to
261 // connect drivers with this interface
263 if (UsbIsHubInterface (UsbIf
)) {
264 DEBUG ((DEBUG_INFO
, "UsbConnectDriver: found a hub device\n"));
265 Status
= mUsbHubApi
.Init (UsbIf
);
268 // This function is called in both UsbIoControlTransfer and
269 // the timer callback in hub enumeration. So, at least it is
270 // called at TPL_CALLBACK. Some driver sitting on USB has
271 // twisted TPL used. It should be no problem for us to connect
272 // or disconnect at CALLBACK.
276 // Only recursively wanted usb child device
278 if (UsbBusIsWantedUsbIO (UsbIf
->Device
->Bus
, UsbIf
)) {
279 OldTpl
= UsbGetCurrentTpl ();
280 DEBUG ((DEBUG_INFO
, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32
)OldTpl
, UsbIf
->Handle
));
282 gBS
->RestoreTPL (TPL_CALLBACK
);
284 Status
= gBS
->ConnectController (UsbIf
->Handle
, NULL
, NULL
, TRUE
);
285 UsbIf
->IsManaged
= (BOOLEAN
) !EFI_ERROR (Status
);
287 DEBUG ((DEBUG_INFO
, "UsbConnectDriver: TPL after connect is %d\n", (UINT32
)UsbGetCurrentTpl ()));
288 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK
);
290 gBS
->RaiseTPL (OldTpl
);
298 Select an alternate setting for the interface.
299 Each interface can have several mutually exclusive
300 settings. Only one setting is active. It will
301 also reset its endpoints' toggle to zero.
303 @param IfDesc The interface descriptor to set.
304 @param Alternate The alternate setting number to locate.
306 @retval EFI_NOT_FOUND There is no setting with this alternate index.
307 @retval EFI_SUCCESS The interface is set to Alternate setting.
312 IN USB_INTERFACE_DESC
*IfDesc
,
316 USB_INTERFACE_SETTING
*Setting
;
320 // Locate the active alternate setting
324 for (Index
= 0; Index
< IfDesc
->NumOfSetting
; Index
++) {
325 ASSERT (Index
< USB_MAX_INTERFACE_SETTING
);
326 Setting
= IfDesc
->Settings
[Index
];
328 if (Setting
->Desc
.AlternateSetting
== Alternate
) {
333 if (Index
== IfDesc
->NumOfSetting
) {
334 return EFI_NOT_FOUND
;
337 IfDesc
->ActiveIndex
= Index
;
339 ASSERT (Setting
!= NULL
);
342 "UsbSelectSetting: setting %d selected for interface %d\n",
344 Setting
->Desc
.InterfaceNumber
348 // Reset the endpoint toggle to zero
350 for (Index
= 0; Index
< Setting
->Desc
.NumEndpoints
; Index
++) {
351 Setting
->Endpoints
[Index
]->Toggle
= 0;
358 Select a new configuration for the device. Each
359 device may support several configurations.
361 @param Device The device to select configuration.
362 @param ConfigValue The index of the configuration ( != 0).
364 @retval EFI_NOT_FOUND There is no configuration with the index.
365 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
366 @retval EFI_SUCCESS The configuration is selected.
371 IN USB_DEVICE
*Device
,
375 USB_DEVICE_DESC
*DevDesc
;
376 USB_CONFIG_DESC
*ConfigDesc
;
377 USB_INTERFACE_DESC
*IfDesc
;
378 USB_INTERFACE
*UsbIf
;
383 // Locate the active config, then set the device's pointer
385 DevDesc
= Device
->DevDesc
;
388 for (Index
= 0; Index
< DevDesc
->Desc
.NumConfigurations
; Index
++) {
389 ConfigDesc
= DevDesc
->Configs
[Index
];
391 if (ConfigDesc
->Desc
.ConfigurationValue
== ConfigValue
) {
396 if (Index
== DevDesc
->Desc
.NumConfigurations
) {
397 return EFI_NOT_FOUND
;
400 Device
->ActiveConfig
= ConfigDesc
;
404 "UsbSelectConfig: config %d selected for device %d\n",
410 // Create interfaces for each USB interface descriptor.
412 for (Index
= 0; Index
< ConfigDesc
->Desc
.NumInterfaces
; Index
++) {
414 // First select the default interface setting, and reset
415 // the endpoint toggles to zero for its endpoints.
417 IfDesc
= ConfigDesc
->Interfaces
[Index
];
418 UsbSelectSetting (IfDesc
, IfDesc
->Settings
[0]->Desc
.AlternateSetting
);
421 // Create a USB_INTERFACE and install USB_IO and other protocols
423 UsbIf
= UsbCreateInterface (Device
, ConfigDesc
->Interfaces
[Index
]);
426 Device
->NumOfInterface
= Index
;
427 return EFI_OUT_OF_RESOURCES
;
430 ASSERT (Index
< USB_MAX_INTERFACE
);
431 Device
->Interfaces
[Index
] = UsbIf
;
434 // Connect the device to drivers, if it failed, ignore
435 // the error. Don't let the unsupported interfaces to block
436 // the supported interfaces.
438 Status
= UsbConnectDriver (UsbIf
);
440 if (EFI_ERROR (Status
)) {
443 "UsbSelectConfig: failed to connect driver - %r, ignored\n",
449 Device
->NumOfInterface
= Index
;
455 Disconnect the USB interface with its driver.
457 @param UsbIf The interface to disconnect driver from.
461 UsbDisconnectDriver (
462 IN USB_INTERFACE
*UsbIf
469 // Release the hub if it's a hub controller, otherwise
470 // disconnect the driver if it is managed by other drivers.
472 Status
= EFI_SUCCESS
;
474 Status
= UsbIf
->HubApi
->Release (UsbIf
);
475 } else if (UsbIf
->IsManaged
) {
477 // This function is called in both UsbIoControlTransfer and
478 // the timer callback in hub enumeration. So, at least it is
479 // called at TPL_CALLBACK. Some driver sitting on USB has
480 // twisted TPL used. It should be no problem for us to connect
481 // or disconnect at CALLBACK.
483 OldTpl
= UsbGetCurrentTpl ();
484 DEBUG ((DEBUG_INFO
, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32
)OldTpl
, UsbIf
->Handle
));
486 gBS
->RestoreTPL (TPL_CALLBACK
);
488 Status
= gBS
->DisconnectController (UsbIf
->Handle
, NULL
, NULL
);
489 if (!EFI_ERROR (Status
)) {
490 UsbIf
->IsManaged
= FALSE
;
493 DEBUG ((DEBUG_INFO
, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32
)UsbGetCurrentTpl (), Status
));
494 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK
);
496 gBS
->RaiseTPL (OldTpl
);
503 Remove the current device configuration.
505 @param Device The USB device to remove configuration from.
510 IN USB_DEVICE
*Device
513 USB_INTERFACE
*UsbIf
;
516 EFI_STATUS ReturnStatus
;
519 // Remove each interface of the device
521 ReturnStatus
= EFI_SUCCESS
;
522 for (Index
= 0; Index
< Device
->NumOfInterface
; Index
++) {
523 ASSERT (Index
< USB_MAX_INTERFACE
);
524 UsbIf
= Device
->Interfaces
[Index
];
530 Status
= UsbDisconnectDriver (UsbIf
);
531 if (!EFI_ERROR (Status
)) {
532 Status
= UsbFreeInterface (UsbIf
);
533 if (EFI_ERROR (Status
)) {
534 UsbConnectDriver (UsbIf
);
538 if (!EFI_ERROR (Status
)) {
539 Device
->Interfaces
[Index
] = NULL
;
541 ReturnStatus
= Status
;
545 Device
->ActiveConfig
= NULL
;
550 Remove the device and all its children from the bus.
552 @param Device The device to remove.
554 @retval EFI_SUCCESS The device is removed.
559 IN USB_DEVICE
*Device
565 EFI_STATUS ReturnStatus
;
571 // Remove all the devices on its downstream ports. Search from devices[1].
572 // Devices[0] is the root hub.
574 ReturnStatus
= EFI_SUCCESS
;
575 for (Index
= 1; Index
< Bus
->MaxDevices
; Index
++) {
576 Child
= Bus
->Devices
[Index
];
578 if ((Child
== NULL
) || (Child
->ParentAddr
!= Device
->Address
)) {
582 Status
= UsbRemoveDevice (Child
);
584 if (!EFI_ERROR (Status
)) {
585 Bus
->Devices
[Index
] = NULL
;
587 Bus
->Devices
[Index
]->DisconnectFail
= TRUE
;
588 ReturnStatus
= Status
;
589 DEBUG ((DEBUG_INFO
, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child
, Device
));
593 if (EFI_ERROR (ReturnStatus
)) {
597 Status
= UsbRemoveConfig (Device
);
599 if (!EFI_ERROR (Status
)) {
600 DEBUG ((DEBUG_INFO
, "UsbRemoveDevice: device %d removed\n", Device
->Address
));
602 ASSERT (Device
->Address
< Bus
->MaxDevices
);
603 Bus
->Devices
[Device
->Address
] = NULL
;
604 UsbFreeDevice (Device
);
606 Bus
->Devices
[Device
->Address
]->DisconnectFail
= TRUE
;
613 Find the child device on the hub's port.
615 @param HubIf The hub interface.
616 @param Port The port of the hub this child is connected to.
618 @return The device on the hub's port, or NULL if there is none.
623 IN USB_INTERFACE
*HubIf
,
631 Bus
= HubIf
->Device
->Bus
;
634 // Start checking from device 1, device 0 is the root hub
636 for (Index
= 1; Index
< Bus
->MaxDevices
; Index
++) {
637 Device
= Bus
->Devices
[Index
];
639 if ((Device
!= NULL
) && (Device
->ParentAddr
== HubIf
->Device
->Address
) &&
640 (Device
->ParentPort
== Port
))
650 Enumerate and configure the new device on the port of this HUB interface.
652 @param HubIf The HUB that has the device connected.
653 @param Port The port index of the hub (started with zero).
654 @param ResetIsNeeded The boolean to control whether skip the reset of the port.
656 @retval EFI_SUCCESS The device is enumerated (added or removed).
657 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.
658 @retval Others Failed to enumerate the device.
663 IN USB_INTERFACE
*HubIf
,
665 IN BOOLEAN ResetIsNeeded
672 EFI_USB_PORT_STATUS PortState
;
677 Parent
= HubIf
->Device
;
679 HubApi
= HubIf
->HubApi
;
680 Address
= Bus
->MaxDevices
;
682 gBS
->Stall (USB_WAIT_PORT_STABLE_STALL
);
685 // Hub resets the device for at least 10 milliseconds.
686 // Host learns device speed. If device is of low/full speed
687 // and the hub is a EHCI root hub, ResetPort will release
688 // the device to its companion UHCI and return an error.
691 Status
= HubApi
->ResetPort (HubIf
, Port
);
692 if (EFI_ERROR (Status
)) {
693 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port
, Status
));
698 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: hub port %d is reset\n", Port
));
700 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: hub port %d reset is skipped\n", Port
));
703 Child
= UsbCreateDevice (HubIf
, Port
);
706 return EFI_OUT_OF_RESOURCES
;
710 // OK, now identify the device speed. After reset, hub
711 // fully knows the actual device speed.
713 Status
= HubApi
->GetPortStatus (HubIf
, Port
, &PortState
);
715 if (EFI_ERROR (Status
)) {
716 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port
));
720 if (!USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_CONNECTION
)) {
721 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: No device present at port %d\n", Port
));
722 Status
= EFI_NOT_FOUND
;
724 } else if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_SUPER_SPEED
)) {
725 Child
->Speed
= EFI_USB_SPEED_SUPER
;
726 Child
->MaxPacket0
= 512;
727 } else if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_HIGH_SPEED
)) {
728 Child
->Speed
= EFI_USB_SPEED_HIGH
;
729 Child
->MaxPacket0
= 64;
730 } else if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_LOW_SPEED
)) {
731 Child
->Speed
= EFI_USB_SPEED_LOW
;
732 Child
->MaxPacket0
= 8;
734 Child
->Speed
= EFI_USB_SPEED_FULL
;
735 Child
->MaxPacket0
= 8;
738 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: device is of %d speed\n", Child
->Speed
));
740 if (((Child
->Speed
== EFI_USB_SPEED_LOW
) || (Child
->Speed
== EFI_USB_SPEED_FULL
)) &&
741 (Parent
->Speed
== EFI_USB_SPEED_HIGH
))
744 // If the child is a low or full speed device, it is necessary to
745 // set the transaction translator. Port TT is 1-based.
746 // This is quite simple:
747 // 1. if parent is of high speed, then parent is our translator
748 // 2. otherwise use parent's translator.
750 Child
->Translator
.TranslatorHubAddress
= Parent
->Address
;
751 Child
->Translator
.TranslatorPortNumber
= (UINT8
)(Port
+ 1);
753 Child
->Translator
= Parent
->Translator
;
758 "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
759 Child
->Translator
.TranslatorHubAddress
,
760 Child
->Translator
.TranslatorPortNumber
764 // After port is reset, hub establishes a signal path between
765 // the device and host (DEFAULT state). Device's registers are
766 // reset, use default address 0 (host enumerates one device at
767 // a time) , and ready to respond to control transfer at EP 0.
771 // Host assigns an address to the device. Device completes the
772 // status stage with default address, then switches to new address.
773 // ADDRESS state. Address zero is reserved for root hub.
775 ASSERT (Bus
->MaxDevices
<= 256);
776 for (Address
= 1; Address
< Bus
->MaxDevices
; Address
++) {
777 if (Bus
->Devices
[Address
] == NULL
) {
782 if (Address
>= Bus
->MaxDevices
) {
783 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: address pool is full for port %d\n", Port
));
785 Status
= EFI_ACCESS_DENIED
;
789 Status
= UsbSetAddress (Child
, (UINT8
)Address
);
790 Child
->Address
= (UINT8
)Address
;
791 Bus
->Devices
[Address
] = Child
;
793 if (EFI_ERROR (Status
)) {
794 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to set device address - %r\n", Status
));
798 gBS
->Stall (USB_SET_DEVICE_ADDRESS_STALL
);
800 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address
));
803 // Host sends a Get_Descriptor request to learn the max packet
804 // size of default pipe (only part of the device's descriptor).
806 Status
= UsbGetMaxPacketSize0 (Child
);
808 if (EFI_ERROR (Status
)) {
809 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status
));
813 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child
->MaxPacket0
));
816 // Host learns about the device's abilities by requesting device's
817 // entire descriptions.
819 Status
= UsbBuildDescTable (Child
);
821 if (EFI_ERROR (Status
)) {
822 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status
));
827 // Select a default configuration: UEFI must set the configuration
828 // before the driver can connect to the device.
830 Config
= Child
->DevDesc
->Configs
[0]->Desc
.ConfigurationValue
;
831 Status
= UsbSetConfig (Child
, Config
);
833 if (EFI_ERROR (Status
)) {
834 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config
, Status
));
838 DEBUG ((DEBUG_INFO
, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address
));
841 // Host assigns and loads a device driver.
843 Status
= UsbSelectConfig (Child
, Config
);
845 if (EFI_ERROR (Status
)) {
846 DEBUG ((DEBUG_ERROR
, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status
));
851 // Report Status Code to indicate USB device has been detected by hotplug
853 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
855 (EFI_IO_BUS_USB
| EFI_IOB_PC_HOTPLUG
),
862 // If reach here, it means the enumeration process on a given port is interrupted due to error.
863 // The s/w resources, including the assigned address(Address) and the allocated usb device data
864 // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when
865 // the device is unplugged from the port or DriverBindingStop() is invoked.
867 // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.
868 // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine
869 // to keep track of the mapping between actual address and request address. If the request address
870 // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI
871 // host controller driver will have wrong information, which will cause further transaction error.
873 // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.
879 Process the events on the port.
881 @param HubIf The HUB that has the device connected.
882 @param Port The port index of the hub (started with zero).
884 @retval EFI_SUCCESS The device is enumerated (added or removed).
885 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.
886 @retval Others Failed to enumerate the device.
891 IN USB_INTERFACE
*HubIf
,
897 EFI_USB_PORT_STATUS PortState
;
901 HubApi
= HubIf
->HubApi
;
904 // Host learns of the new device by polling the hub for port changes.
906 Status
= HubApi
->GetPortStatus (HubIf
, Port
, &PortState
);
908 if (EFI_ERROR (Status
)) {
909 DEBUG ((DEBUG_ERROR
, "UsbEnumeratePort: failed to get state of port %d\n", Port
));
914 // Only handle connection/enable/overcurrent/reset change.
915 // Usb super speed hub may report other changes, such as warm reset change. Ignore them.
917 if ((PortState
.PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
923 "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
925 PortState
.PortStatus
,
926 PortState
.PortChangeStatus
,
931 // This driver only process two kinds of events now: over current and
932 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
933 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
936 if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_OVERCURRENT
)) {
937 if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_OVERCURRENT
)) {
940 // Both OverCurrent and OverCurrentChange set, means over current occurs,
941 // which probably is caused by short circuit. It has to wait system hardware
942 // to perform recovery.
944 DEBUG ((DEBUG_ERROR
, "UsbEnumeratePort: Critical Over Current (port %d)\n", Port
));
945 return EFI_DEVICE_ERROR
;
950 // Only OverCurrentChange set, means system has been recoveried from
951 // over current. As a result, all ports are nearly power-off, so
952 // it's necessary to detach and enumerate all ports again.
954 DEBUG ((DEBUG_ERROR
, "UsbEnumeratePort: 2.0 device Recovery Over Current (port %d)\n", Port
));
957 if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_ENABLE
)) {
960 // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart
961 // on 2.0 roothub does. When over-current has influence on 1.1 device, the port
962 // would be disabled, so it's also necessary to detach and enumerate again.
964 DEBUG ((DEBUG_ERROR
, "UsbEnumeratePort: 1.1 device Recovery Over Current (port %d)\n", Port
));
967 if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_CONNECTION
)) {
970 // Device connected or disconnected normally.
972 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: Device Connect/Disconnect Normally (port %d)\n", Port
));
976 // Following as the above cases, it's safety to remove and create again.
978 Child
= UsbFindChild (HubIf
, Port
);
981 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port
, HubIf
));
982 UsbRemoveDevice (Child
);
985 if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_CONNECTION
)) {
987 // Now, new device connected, enumerate and configure the device
989 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: new device connected at port %d\n", Port
));
990 if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_RESET
)) {
991 Status
= UsbEnumerateNewDev (HubIf
, Port
, FALSE
);
993 Status
= UsbEnumerateNewDev (HubIf
, Port
, TRUE
);
996 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: device disconnected event on port %d\n", Port
));
999 HubApi
->ClearPortChange (HubIf
, Port
);
1004 Enumerate all the changed hub ports.
1006 @param Event The event that is triggered.
1007 @param Context The context to the event.
1017 USB_INTERFACE
*HubIf
;
1023 ASSERT (Context
!= NULL
);
1025 HubIf
= (USB_INTERFACE
*)Context
;
1027 for (Index
= 0; Index
< HubIf
->NumOfPort
; Index
++) {
1028 Child
= UsbFindChild (HubIf
, Index
);
1029 if ((Child
!= NULL
) && (Child
->DisconnectFail
== TRUE
)) {
1030 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index
, HubIf
));
1031 UsbRemoveDevice (Child
);
1035 if (HubIf
->ChangeMap
== NULL
) {
1040 // HUB starts its port index with 1.
1045 for (Index
= 0; Index
< HubIf
->NumOfPort
; Index
++) {
1046 if (USB_BIT_IS_SET (HubIf
->ChangeMap
[Byte
], USB_BIT (Bit
))) {
1047 UsbEnumeratePort (HubIf
, Index
);
1050 USB_NEXT_BIT (Byte
, Bit
);
1053 UsbHubAckHubStatus (HubIf
->Device
);
1055 gBS
->FreePool (HubIf
->ChangeMap
);
1056 HubIf
->ChangeMap
= NULL
;
1061 Enumerate all the changed hub ports.
1063 @param Event The event that is triggered.
1064 @param Context The context to the event.
1069 UsbRootHubEnumeration (
1074 USB_INTERFACE
*RootHub
;
1078 RootHub
= (USB_INTERFACE
*)Context
;
1080 for (Index
= 0; Index
< RootHub
->NumOfPort
; Index
++) {
1081 Child
= UsbFindChild (RootHub
, Index
);
1082 if ((Child
!= NULL
) && (Child
->DisconnectFail
== TRUE
)) {
1083 DEBUG ((DEBUG_INFO
, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index
, RootHub
));
1084 UsbRemoveDevice (Child
);
1087 UsbEnumeratePort (RootHub
, Index
);