3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Usb bus enumeration support
29 Return the endpoint descriptor in this interface
31 @param UsbIf The interface to search in
32 @param EpAddr The address of the endpoint to return
34 @return The endpoint descriptor or NULL
39 IN USB_INTERFACE
*UsbIf
,
43 USB_ENDPOINT_DESC
*EpDesc
;
46 for (Index
= 0; Index
< UsbIf
->IfSetting
->Desc
.NumEndpoints
; Index
++) {
47 EpDesc
= UsbIf
->IfSetting
->Endpoints
[Index
];
49 if (EpDesc
->Desc
.EndpointAddress
== EpAddr
) {
59 Free the resource used by USB interface
61 @param UsbIf The USB interface to free
69 IN USB_INTERFACE
*UsbIf
72 UsbCloseHostProtoByChild (UsbIf
->Device
->Bus
, UsbIf
->Handle
);
74 gBS
->UninstallMultipleProtocolInterfaces (
76 &gEfiDevicePathProtocolGuid
,
78 &gEfiUsbIoProtocolGuid
,
83 if (UsbIf
->DevicePath
!= NULL
) {
84 gBS
->FreePool (UsbIf
->DevicePath
);
87 gBS
->FreePool (UsbIf
);
92 Create an interface for the descriptor IfDesc. Each
93 device's configuration can have several interfaces.
95 @param Device The device has the interface descriptor
96 @param IfDesc The interface descriptor
98 @return The created USB interface for the descriptor, or NULL.
104 IN USB_DEVICE
*Device
,
105 IN USB_INTERFACE_DESC
*IfDesc
108 USB_DEVICE_PATH UsbNode
;
109 USB_INTERFACE
*UsbIf
;
110 USB_INTERFACE
*HubIf
;
113 UsbIf
= AllocateZeroPool (sizeof (USB_INTERFACE
));
119 UsbIf
->Signature
= USB_INTERFACE_SIGNATURE
;
120 UsbIf
->Device
= Device
;
121 UsbIf
->IfDesc
= IfDesc
;
122 UsbIf
->IfSetting
= IfDesc
->Settings
[IfDesc
->ActiveIndex
];
123 UsbIf
->UsbIo
= mUsbIoProtocol
;
126 // Install protocols for USBIO and device path
128 UsbNode
.Header
.Type
= MESSAGING_DEVICE_PATH
;
129 UsbNode
.Header
.SubType
= MSG_USB_DP
;
130 UsbNode
.ParentPortNumber
= Device
->ParentPort
;
131 UsbNode
.InterfaceNumber
= UsbIf
->IfSetting
->Desc
.InterfaceNumber
;
133 SetDevicePathNodeLength (&UsbNode
.Header
, sizeof (UsbNode
));
135 HubIf
= Device
->ParentIf
;
136 ASSERT (HubIf
!= NULL
);
138 UsbIf
->DevicePath
= AppendDevicePathNode (HubIf
->DevicePath
, &UsbNode
.Header
);
140 if (UsbIf
->DevicePath
== NULL
) {
141 USB_ERROR (("UsbCreateInterface: failed to create device path\n"));
143 Status
= EFI_OUT_OF_RESOURCES
;
147 Status
= gBS
->InstallMultipleProtocolInterfaces (
149 &gEfiDevicePathProtocolGuid
,
151 &gEfiUsbIoProtocolGuid
,
156 if (EFI_ERROR (Status
)) {
157 USB_ERROR (("UsbCreateInterface: failed to install UsbIo - %r\n", Status
));
162 // Open USB Host Controller Protocol by Child
164 Status
= UsbOpenHostProtoByChild (Device
->Bus
, UsbIf
->Handle
);
166 if (EFI_ERROR (Status
)) {
167 gBS
->UninstallMultipleProtocolInterfaces (
169 &gEfiDevicePathProtocolGuid
,
171 &gEfiUsbIoProtocolGuid
,
176 USB_ERROR (("UsbCreateInterface: failed to open host for child - %r\n", Status
));
183 if (UsbIf
->DevicePath
) {
184 gBS
->FreePool (UsbIf
->DevicePath
);
187 gBS
->FreePool (UsbIf
);
193 Free the resource used by this USB device
195 @param Device The USB device to free
203 IN USB_DEVICE
*Device
206 if (Device
->DevDesc
!= NULL
) {
207 UsbFreeDevDesc (Device
->DevDesc
);
210 gBS
->FreePool (Device
);
215 Create a device which is on the parent's ParentPort port.
217 @param ParentIf The parent HUB interface
218 @param ParentPort The port on the HUB this device is connected to
220 @return Created USB device
226 IN USB_INTERFACE
*ParentIf
,
232 ASSERT (ParentIf
!= NULL
);
234 Device
= AllocateZeroPool (sizeof (USB_DEVICE
));
236 if (Device
== NULL
) {
240 Device
->Bus
= ParentIf
->Device
->Bus
;
241 Device
->MaxPacket0
= 8;
242 Device
->ParentAddr
= ParentIf
->Device
->Address
;
243 Device
->ParentIf
= ParentIf
;
244 Device
->ParentPort
= ParentPort
;
250 Connect the USB interface with its driver. EFI USB bus will
251 create a USB interface for each seperate interface descriptor.
253 @param UsbIf The interface to connect driver to
255 @return EFI_SUCCESS : Interface is managed by some driver
256 @return Others : Failed to locate a driver for this interface
262 IN USB_INTERFACE
*UsbIf
268 Status
= EFI_SUCCESS
;
271 // Hub is maintained by the USB bus driver. Otherwise try to
272 // connect drivers with this interface
274 if (UsbIsHubInterface (UsbIf
)) {
275 USB_DEBUG (("UsbConnectDriver: found a hub device\n"));
276 Status
= mUsbHubApi
.Init (UsbIf
);
280 // This function is called in both UsbIoControlTransfer and
281 // the timer callback in hub enumeration. So, at least it is
282 // called at TPL_CALLBACK. Some driver sitting on USB has
283 // twisted TPL used. It should be no problem for us to connect
284 // or disconnect at CALLBACK.
286 OldTpl
= UsbGetCurrentTpl ();
287 USB_DEBUG (("UsbConnectDriver: TPL before connect is %d\n", OldTpl
));
289 gBS
->RestoreTPL (TPL_CALLBACK
);
291 Status
= gBS
->ConnectController (UsbIf
->Handle
, NULL
, NULL
, TRUE
);
292 UsbIf
->IsManaged
= (BOOLEAN
)!EFI_ERROR (Status
);
294 USB_DEBUG (("UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));
295 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK
);
297 gBS
->RaiseTPL (OldTpl
);
305 Select an alternate setting for the interface.
306 Each interface can have several mutually exclusive
307 settings. Only one setting is active. It will
308 also reset its endpoints' toggle to zero.
310 @param IfDesc The interface descriptor to set
311 @param Alternate The alternate setting number to locate
313 @retval EFI_NOT_FOUND There is no setting with this alternate index
314 @retval EFI_SUCCESS The interface is set to Alternate setting.
319 IN USB_INTERFACE_DESC
*IfDesc
,
323 USB_INTERFACE_SETTING
*Setting
;
327 // Locate the active alternate setting
331 for (Index
= 0; Index
< IfDesc
->NumOfSetting
; Index
++) {
332 Setting
= IfDesc
->Settings
[Index
];
334 if (Setting
->Desc
.AlternateSetting
== Alternate
) {
339 if (Index
== IfDesc
->NumOfSetting
) {
340 return EFI_NOT_FOUND
;
343 IfDesc
->ActiveIndex
= Index
;
345 USB_DEBUG (("UsbSelectSetting: setting %d selected for interface %d\n",
346 Alternate
, Setting
->Desc
.InterfaceNumber
));
349 // Reset the endpoint toggle to zero
351 for (Index
= 0; Index
< Setting
->Desc
.NumEndpoints
; Index
++) {
352 Setting
->Endpoints
[Index
]->Toggle
= 0;
360 Select a new configuration for the device. Each
361 device may support several configurations.
363 @param Device The device to select configuration
364 @param ConfigValue The index of the configuration ( != 0)
366 @retval EFI_NOT_FOUND There is no configuration with the index
367 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource
368 @retval EFI_SUCCESS The configuration is selected.
373 IN USB_DEVICE
*Device
,
377 USB_DEVICE_DESC
*DevDesc
;
378 USB_CONFIG_DESC
*ConfigDesc
;
379 USB_INTERFACE_DESC
*IfDesc
;
380 USB_INTERFACE
*UsbIf
;
385 // Locate the active config, then set the device's pointer
387 DevDesc
= Device
->DevDesc
;
390 for (Index
= 0; Index
< DevDesc
->Desc
.NumConfigurations
; Index
++) {
391 ConfigDesc
= DevDesc
->Configs
[Index
];
393 if (ConfigDesc
->Desc
.ConfigurationValue
== ConfigValue
) {
398 if (Index
== DevDesc
->Desc
.NumConfigurations
) {
399 return EFI_NOT_FOUND
;
402 Device
->ActiveConfig
= ConfigDesc
;
404 USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n",
405 ConfigValue
, Device
->Address
));
408 // Create interfaces for each USB interface descriptor.
410 for (Index
= 0; Index
< ConfigDesc
->Desc
.NumInterfaces
; Index
++) {
412 // First select the default interface setting, and reset
413 // the endpoint toggles to zero for its endpoints.
415 IfDesc
= ConfigDesc
->Interfaces
[Index
];
416 UsbSelectSetting (IfDesc
, IfDesc
->Settings
[0]->Desc
.AlternateSetting
);
419 // Create a USB_INTERFACE and install USB_IO and other protocols
421 UsbIf
= UsbCreateInterface (Device
, ConfigDesc
->Interfaces
[Index
]);
424 return EFI_OUT_OF_RESOURCES
;
427 Device
->Interfaces
[Index
] = UsbIf
;
430 // Connect the device to drivers, if it failed, ignore
431 // the error. Don't let the unsupported interfaces to block
432 // the supported interfaces.
434 Status
= UsbConnectDriver (UsbIf
);
436 if (EFI_ERROR (Status
)) {
437 USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status
));
441 Device
->NumOfInterface
= Index
;
449 Disconnect the USB interface with its driver.
451 @param UsbIf The interface to disconnect driver from
458 UsbDisconnectDriver (
459 IN USB_INTERFACE
*UsbIf
465 // Release the hub if it's a hub controller, otherwise
466 // disconnect the driver if it is managed by other drivers.
469 UsbIf
->HubApi
->Release (UsbIf
);
471 } else if (UsbIf
->IsManaged
) {
473 // This function is called in both UsbIoControlTransfer and
474 // the timer callback in hub enumeration. So, at least it is
475 // called at TPL_CALLBACK. Some driver sitting on USB has
476 // twisted TPL used. It should be no problem for us to connect
477 // or disconnect at CALLBACK.
479 OldTpl
= UsbGetCurrentTpl ();
480 USB_DEBUG (("UsbDisconnectDriver: old TPL is %d\n", OldTpl
));
482 gBS
->RestoreTPL (TPL_CALLBACK
);
484 gBS
->DisconnectController (UsbIf
->Handle
, NULL
, NULL
);
485 UsbIf
->IsManaged
= FALSE
;
487 USB_DEBUG (("UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));
488 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK
);
490 gBS
->RaiseTPL (OldTpl
);
497 Remove the current device configuration
499 @param Device The USB device to remove configuration from
506 IN USB_DEVICE
*Device
509 USB_INTERFACE
*UsbIf
;
513 // Remove each interface of the device
515 for (Index
= 0; Index
< Device
->NumOfInterface
; Index
++) {
516 UsbIf
= Device
->Interfaces
[Index
];
522 UsbDisconnectDriver (UsbIf
);
523 UsbFreeInterface (UsbIf
);
524 Device
->Interfaces
[Index
] = NULL
;
527 Device
->ActiveConfig
= NULL
;
528 Device
->NumOfInterface
= 0;
534 Remove the device and all its children from the bus.
536 @param Device The device to remove
538 @retval EFI_SUCCESS The device is removed
543 IN USB_DEVICE
*Device
554 // Remove all the devices on its downstream ports. Search from devices[1].
555 // Devices[0] is the root hub.
557 for (Index
= 1; Index
< USB_MAX_DEVICES
; Index
++) {
558 Child
= Bus
->Devices
[Index
];
560 if ((Child
== NULL
) || (Child
->ParentAddr
!= Device
->Address
)) {
564 Status
= UsbRemoveDevice (Child
);
566 if (EFI_ERROR (Status
)) {
567 USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n"));
568 Bus
->Devices
[Index
] = NULL
;
572 UsbRemoveConfig (Device
);
574 USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device
->Address
));
576 Bus
->Devices
[Device
->Address
] = NULL
;
577 UsbFreeDevice (Device
);
584 Find the child device on the hub's port
586 @param HubIf The hub interface
587 @param Port The port of the hub this child is connected to
589 @return The device on the hub's port, or NULL if there is none
595 IN USB_INTERFACE
*HubIf
,
603 Bus
= HubIf
->Device
->Bus
;
606 // Start checking from device 1, device 0 is the root hub
608 for (Index
= 1; Index
< USB_MAX_DEVICES
; Index
++) {
609 Device
= Bus
->Devices
[Index
];
611 if ((Device
!= NULL
) && (Device
->ParentAddr
== HubIf
->Device
->Address
) &&
612 (Device
->ParentPort
== Port
)) {
624 Enumerate and configure the new device on the port of this HUB interface.
626 @param HubIf The HUB that has the device connected
627 @param Port The port index of the hub (started with zero)
629 @retval EFI_SUCCESS The device is enumerated (added or removed)
630 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
631 @retval Others Failed to enumerate the device
637 IN USB_INTERFACE
*HubIf
,
645 EFI_USB_PORT_STATUS PortState
;
650 Address
= USB_MAX_DEVICES
;
651 Parent
= HubIf
->Device
;
653 HubApi
= HubIf
->HubApi
;
657 // Wait at least 100 ms for the power on port to stable
659 gBS
->Stall (100 * USB_STALL_1_MS
);
662 // Hub resets the device for at least 10 milliseconds.
663 // Host learns device speed. If device is of low/full speed
664 // and the hub is a EHCI root hub, ResetPort will release
665 // the device to its companion UHCI and return an error.
667 Status
= HubApi
->ResetPort (HubIf
, Port
);
669 if (EFI_ERROR (Status
)) {
670 USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port
, Status
));
675 USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port
));
677 Child
= UsbCreateDevice (HubIf
, Port
);
680 return EFI_OUT_OF_RESOURCES
;
684 // OK, now identify the device speed. After reset, hub
685 // fully knows the actual device speed.
687 Status
= HubApi
->GetPortStatus (HubIf
, Port
, &PortState
);
689 if (EFI_ERROR (Status
)) {
690 USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port
));
694 if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_LOW_SPEED
)) {
695 Child
->Speed
= EFI_USB_SPEED_LOW
;
697 } else if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_HIGH_SPEED
)) {
698 Child
->Speed
= EFI_USB_SPEED_HIGH
;
701 Child
->Speed
= EFI_USB_SPEED_FULL
;
704 USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child
->Speed
));
706 if (Child
->Speed
!= EFI_USB_SPEED_HIGH
) {
708 // If the child isn't a high speed device, it is necessary to
709 // set the transaction translator. This is quite simple:
710 // 1. if parent is of high speed, then parent is our translator
711 // 2. otherwise use parent's translator.
713 if (Parent
->Speed
== EFI_USB_SPEED_HIGH
) {
714 Child
->Translator
.TranslatorHubAddress
= Parent
->Address
;
715 Child
->Translator
.TranslatorPortNumber
= Port
;
718 Child
->Translator
= Parent
->Translator
;
721 USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n",
722 Child
->Translator
.TranslatorHubAddress
,
723 Child
->Translator
.TranslatorPortNumber
));
727 // After port is reset, hub establishes a signal path between
728 // the device and host (DEFALUT state). Device¡¯s registers are
729 // reset, use default address 0 (host enumerates one device at
730 // a time) , and ready to respond to control transfer at EP 0.
734 // Host sends a Get_Descriptor request to learn the max packet
735 // size of default pipe (only part of the device¡¯s descriptor).
737 Status
= UsbGetMaxPacketSize0 (Child
);
739 if (EFI_ERROR (Status
)) {
740 USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status
));
744 USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child
->MaxPacket0
));
747 // Host assigns an address to the device. Device completes the
748 // status stage with default address, then switches to new address.
749 // ADDRESS state. Address zero is reserved for root hub.
751 for (Address
= 1; Address
< USB_MAX_DEVICES
; Address
++) {
752 if (Bus
->Devices
[Address
] == NULL
) {
757 if (Address
== USB_MAX_DEVICES
) {
758 USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port
));
760 Status
= EFI_ACCESS_DENIED
;
764 Bus
->Devices
[Address
] = Child
;
765 Status
= UsbSetAddress (Child
, Address
);
766 Child
->Address
= Address
;
768 if (EFI_ERROR (Status
)) {
769 USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status
));
774 // Wait 20ms for set address to complete
776 gBS
->Stall (20 * USB_STALL_1_MS
);
778 USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address
));
781 // Host learns about the device¡¯s abilities by requesting device's
782 // entire descriptions.
784 Status
= UsbBuildDescTable (Child
);
786 if (EFI_ERROR (Status
)) {
787 USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status
));
792 // Select a default configuration: UEFI must set the configuration
793 // before the driver can connect to the device.
795 Config
= Child
->DevDesc
->Configs
[0]->Desc
.ConfigurationValue
;
796 Status
= UsbSetConfig (Child
, Config
);
798 if (EFI_ERROR (Status
)) {
799 USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config
, Status
));
803 USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address
));
806 // Host assigns and loads a device driver.
808 Status
= UsbSelectConfig (Child
, Config
);
810 if (EFI_ERROR (Status
)) {
811 USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status
));
818 if (Address
!= USB_MAX_DEVICES
) {
819 Bus
->Devices
[Address
] = NULL
;
823 UsbFreeDevice (Child
);
832 Process the events on the port.
834 @param HubIf The HUB that has the device connected
835 @param Port The port index of the hub (started with zero)
837 @retval EFI_SUCCESS The device is enumerated (added or removed)
838 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
839 @retval Others Failed to enumerate the device
845 IN USB_INTERFACE
*HubIf
,
851 EFI_USB_PORT_STATUS PortState
;
855 HubApi
= HubIf
->HubApi
;
858 // Host learns of the new device by polling the hub for port changes.
860 Status
= HubApi
->GetPortStatus (HubIf
, Port
, &PortState
);
862 if (EFI_ERROR (Status
)) {
863 USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port
));
867 if (PortState
.PortChangeStatus
== 0) {
871 USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n",
872 Port
, PortState
.PortStatus
, PortState
.PortChangeStatus
));
875 // This driver only process two kinds of events now: over current and
876 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
877 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
879 Status
= EFI_SUCCESS
;
881 if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_OVERCURRENT
)) {
883 // If overcurrent condition is cleared, enable the port again
885 if (!USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_OVERCURRENT
)) {
886 HubApi
->SetPortFeature (HubIf
, Port
, USB_HUB_PORT_POWER
);
889 } else if (USB_BIT_IS_SET (PortState
.PortChangeStatus
, USB_PORT_STAT_C_CONNECTION
)) {
891 // Device connected or disconnected. Either way, if there is
892 // already a device present in the bus, need to remove it.
894 Child
= UsbFindChild (HubIf
, Port
);
897 USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port
));
898 UsbRemoveDevice (Child
);
901 if (USB_BIT_IS_SET (PortState
.PortStatus
, USB_PORT_STAT_CONNECTION
)) {
903 // Now, new device connected, enumerate and configure the device
905 USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port
));
906 Status
= UsbEnumerateNewDev (HubIf
, Port
);
909 USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port
));
913 HubApi
->ClearPortChange (HubIf
, Port
);
919 Enumerate all the changed hub ports
921 @param Event The event that is triggered
922 @param Context The context to the event
933 USB_INTERFACE
*HubIf
;
940 HubIf
= (USB_INTERFACE
*) Context
;
942 if (HubIf
->ChangeMap
== NULL
) {
947 // HUB starts its port index with 1.
952 for (Index
= 0; Index
< HubIf
->NumOfPort
; Index
++) {
953 if (USB_BIT_IS_SET (HubIf
->ChangeMap
[Byte
], USB_BIT (Bit
))) {
954 UsbEnumeratePort (HubIf
, Index
);
957 USB_NEXT_BIT (Byte
, Bit
);
960 UsbHubAckHubStatus (HubIf
->Device
);
962 gBS
->FreePool (HubIf
->ChangeMap
);
963 HubIf
->ChangeMap
= NULL
;
969 Enumerate all the changed hub ports
971 @param Event The event that is triggered
972 @param Context The context to the event
978 UsbRootHubEnumeration (
983 USB_INTERFACE
*RootHub
;
986 RootHub
= (USB_INTERFACE
*) Context
;
988 for (Index
= 0; Index
< RootHub
->NumOfPort
; Index
++) {
989 UsbEnumeratePort (RootHub
, Index
);