/** @file | |
Usb Bus Driver Binding and Bus IO Protocol. | |
Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "UsbBus.h" | |
EFI_USB_IO_PROTOCOL mUsbIoProtocol = { | |
UsbIoControlTransfer, | |
UsbIoBulkTransfer, | |
UsbIoAsyncInterruptTransfer, | |
UsbIoSyncInterruptTransfer, | |
UsbIoIsochronousTransfer, | |
UsbIoAsyncIsochronousTransfer, | |
UsbIoGetDeviceDescriptor, | |
UsbIoGetActiveConfigDescriptor, | |
UsbIoGetInterfaceDescriptor, | |
UsbIoGetEndpointDescriptor, | |
UsbIoGetStringDescriptor, | |
UsbIoGetSupportedLanguages, | |
UsbIoPortReset | |
}; | |
EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = { | |
UsbBusControllerDriverSupported, | |
UsbBusControllerDriverStart, | |
UsbBusControllerDriverStop, | |
0xa, | |
NULL, | |
NULL | |
}; | |
/** | |
USB_IO function to execute a control transfer. This | |
function will execute the USB transfer. If transfer | |
successes, it will sync the internal state of USB bus | |
with device state. | |
@param This The USB_IO instance | |
@param Request The control transfer request | |
@param Direction Direction for data stage | |
@param Timeout The time to wait before timeout | |
@param Data The buffer holding the data | |
@param DataLength Then length of the data | |
@param UsbStatus USB result | |
@retval EFI_INVALID_PARAMETER The parameters are invalid | |
@retval EFI_SUCCESS The control transfer succeeded. | |
@retval Others Failed to execute the transfer | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoControlTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN EFI_USB_DEVICE_REQUEST *Request, | |
IN EFI_USB_DATA_DIRECTION Direction, | |
IN UINT32 Timeout, | |
IN OUT VOID *Data, OPTIONAL | |
IN UINTN DataLength, OPTIONAL | |
OUT UINT32 *UsbStatus | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
USB_ENDPOINT_DESC *EpDesc; | |
EFI_TPL OldTpl; | |
EFI_STATUS Status; | |
if (UsbStatus == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
Status = UsbHcControlTransfer ( | |
Dev->Bus, | |
Dev->Address, | |
Dev->Speed, | |
Dev->MaxPacket0, | |
Request, | |
Direction, | |
Data, | |
&DataLength, | |
(UINTN) Timeout, | |
&Dev->Translator, | |
UsbStatus | |
); | |
if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) { | |
// | |
// Clear TT buffer when CTRL/BULK split transaction failes | |
// Clear the TRANSLATOR TT buffer, not parent's buffer | |
// | |
ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices); | |
if (Dev->Translator.TranslatorHubAddress != 0) { | |
UsbHubCtrlClearTTBuffer ( | |
Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress], | |
Dev->Translator.TranslatorPortNumber, | |
Dev->Address, | |
0, | |
USB_ENDPOINT_CONTROL | |
); | |
} | |
goto ON_EXIT; | |
} | |
// | |
// Some control transfer will change the device's internal | |
// status, such as Set_Configuration and Set_Interface. | |
// We must synchronize the bus driver's status with that in | |
// device. We ignore the Set_Descriptor request because it's | |
// hardly used by any device, especially in pre-boot environment | |
// | |
// | |
// Reset the endpoint toggle when endpoint stall is cleared | |
// | |
if ((Request->Request == USB_REQ_CLEAR_FEATURE) && | |
(Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, | |
USB_TARGET_ENDPOINT)) && | |
(Request->Value == USB_FEATURE_ENDPOINT_HALT)) { | |
EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index); | |
if (EpDesc != NULL) { | |
EpDesc->Toggle = 0; | |
} | |
} | |
// | |
// Select a new configuration. This is a dangerous action. Upper driver | |
// should stop use its current UsbIo after calling this driver. The old | |
// UsbIo will be uninstalled and new UsbIo be installed. We can't use | |
// ReinstallProtocol since interfaces in different configuration may be | |
// completely irrelevant. | |
// | |
if ((Request->Request == USB_REQ_SET_CONFIG) && | |
(Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, | |
USB_TARGET_DEVICE))) { | |
// | |
// Don't re-create the USB interfaces if configuration isn't changed. | |
// | |
if ((Dev->ActiveConfig != NULL) && | |
(Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) { | |
goto ON_EXIT; | |
} | |
DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n")); | |
if (Dev->ActiveConfig != NULL) { | |
UsbRemoveConfig (Dev); | |
} | |
if (Request->Value != 0) { | |
Status = UsbSelectConfig (Dev, (UINT8) Request->Value); | |
} | |
// | |
// Exit now, Old USB_IO is invalid now | |
// | |
goto ON_EXIT; | |
} | |
// | |
// A new alternative setting is selected for the interface. | |
// No need to reinstall UsbIo in this case because only | |
// underlying communication endpoints are changed. Functionality | |
// should remains the same. | |
// | |
if ((Request->Request == USB_REQ_SET_INTERFACE) && | |
(Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, | |
USB_TARGET_INTERFACE)) && | |
(Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber)) { | |
Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value); | |
if (!EFI_ERROR (Status)) { | |
ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING); | |
UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex]; | |
} | |
} | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Execute a bulk transfer to the device endpoint. | |
@param This The USB IO instance. | |
@param Endpoint The device endpoint. | |
@param Data The data to transfer. | |
@param DataLength The length of the data to transfer. | |
@param Timeout Time to wait before timeout. | |
@param UsbStatus The result of USB transfer. | |
@retval EFI_SUCCESS The bulk transfer is OK. | |
@retval EFI_INVALID_PARAMETER Some parameters are invalid. | |
@retval Others Failed to execute transfer, reason returned in | |
UsbStatus. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoBulkTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 Endpoint, | |
IN OUT VOID *Data, | |
IN OUT UINTN *DataLength, | |
IN UINTN Timeout, | |
OUT UINT32 *UsbStatus | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
USB_ENDPOINT_DESC *EpDesc; | |
UINT8 BufNum; | |
UINT8 Toggle; | |
EFI_TPL OldTpl; | |
EFI_STATUS Status; | |
if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) || | |
(UsbStatus == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint); | |
if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) { | |
Status = EFI_INVALID_PARAMETER; | |
goto ON_EXIT; | |
} | |
BufNum = 1; | |
Toggle = EpDesc->Toggle; | |
Status = UsbHcBulkTransfer ( | |
Dev->Bus, | |
Dev->Address, | |
Endpoint, | |
Dev->Speed, | |
EpDesc->Desc.MaxPacketSize, | |
BufNum, | |
&Data, | |
DataLength, | |
&Toggle, | |
Timeout, | |
&Dev->Translator, | |
UsbStatus | |
); | |
EpDesc->Toggle = Toggle; | |
if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) { | |
// | |
// Clear TT buffer when CTRL/BULK split transaction failes. | |
// Clear the TRANSLATOR TT buffer, not parent's buffer | |
// | |
ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices); | |
if (Dev->Translator.TranslatorHubAddress != 0) { | |
UsbHubCtrlClearTTBuffer ( | |
Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress], | |
Dev->Translator.TranslatorPortNumber, | |
Dev->Address, | |
0, | |
USB_ENDPOINT_BULK | |
); | |
} | |
} | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Execute a synchronous interrupt transfer. | |
@param This The USB IO instance. | |
@param Endpoint The device endpoint. | |
@param Data The data to transfer. | |
@param DataLength The length of the data to transfer. | |
@param Timeout Time to wait before timeout. | |
@param UsbStatus The result of USB transfer. | |
@retval EFI_SUCCESS The synchronous interrupt transfer is OK. | |
@retval EFI_INVALID_PARAMETER Some parameters are invalid. | |
@retval Others Failed to execute transfer, reason returned in | |
UsbStatus. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoSyncInterruptTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 Endpoint, | |
IN OUT VOID *Data, | |
IN OUT UINTN *DataLength, | |
IN UINTN Timeout, | |
OUT UINT32 *UsbStatus | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
USB_ENDPOINT_DESC *EpDesc; | |
EFI_TPL OldTpl; | |
UINT8 Toggle; | |
EFI_STATUS Status; | |
if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) || | |
(UsbStatus == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint); | |
if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) { | |
Status = EFI_INVALID_PARAMETER; | |
goto ON_EXIT; | |
} | |
Toggle = EpDesc->Toggle; | |
Status = UsbHcSyncInterruptTransfer ( | |
Dev->Bus, | |
Dev->Address, | |
Endpoint, | |
Dev->Speed, | |
EpDesc->Desc.MaxPacketSize, | |
Data, | |
DataLength, | |
&Toggle, | |
Timeout, | |
&Dev->Translator, | |
UsbStatus | |
); | |
EpDesc->Toggle = Toggle; | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Queue a new asynchronous interrupt transfer, or remove the old | |
request if (IsNewTransfer == FALSE). | |
@param This The USB_IO instance. | |
@param Endpoint The device endpoint. | |
@param IsNewTransfer Whether this is a new request, if it's old, remove | |
the request. | |
@param PollInterval The interval to poll the transfer result, (in ms). | |
@param DataLength The length of perodic data transfer. | |
@param Callback The function to call periodicaly when transfer is | |
ready. | |
@param Context The context to the callback. | |
@retval EFI_SUCCESS New transfer is queued or old request is removed. | |
@retval EFI_INVALID_PARAMETER Some parameters are invalid. | |
@retval Others Failed to queue the new request or remove the old | |
request. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoAsyncInterruptTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 Endpoint, | |
IN BOOLEAN IsNewTransfer, | |
IN UINTN PollInterval, OPTIONAL | |
IN UINTN DataLength, OPTIONAL | |
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, OPTIONAL | |
IN VOID *Context OPTIONAL | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
USB_ENDPOINT_DESC *EpDesc; | |
EFI_TPL OldTpl; | |
UINT8 Toggle; | |
EFI_STATUS Status; | |
if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint); | |
if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) { | |
Status = EFI_INVALID_PARAMETER; | |
goto ON_EXIT; | |
} | |
Toggle = EpDesc->Toggle; | |
Status = UsbHcAsyncInterruptTransfer ( | |
Dev->Bus, | |
Dev->Address, | |
Endpoint, | |
Dev->Speed, | |
EpDesc->Desc.MaxPacketSize, | |
IsNewTransfer, | |
&Toggle, | |
PollInterval, | |
DataLength, | |
&Dev->Translator, | |
Callback, | |
Context | |
); | |
EpDesc->Toggle = Toggle; | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Execute a synchronous isochronous transfer. | |
@param This The USB IO instance. | |
@param DeviceEndpoint The device endpoint. | |
@param Data The data to transfer. | |
@param DataLength The length of the data to transfer. | |
@param UsbStatus The result of USB transfer. | |
@retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoIsochronousTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 DeviceEndpoint, | |
IN OUT VOID *Data, | |
IN UINTN DataLength, | |
OUT UINT32 *Status | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Queue an asynchronous isochronous transfer. | |
@param This The USB_IO instance. | |
@param DeviceEndpoint The device endpoint. | |
@param Data The data to transfer. | |
@param DataLength The length of perodic data transfer. | |
@param IsochronousCallBack The function to call periodicaly when transfer is | |
ready. | |
@param Context The context to the callback. | |
@retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoAsyncIsochronousTransfer ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 DeviceEndpoint, | |
IN OUT VOID *Data, | |
IN UINTN DataLength, | |
IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, | |
IN VOID *Context OPTIONAL | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Retrieve the device descriptor of the device. | |
@param This The USB IO instance. | |
@param Descriptor The variable to receive the device descriptor. | |
@retval EFI_SUCCESS The device descriptor is returned. | |
@retval EFI_INVALID_PARAMETER The parameter is invalid. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetDeviceDescriptor ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
EFI_TPL OldTpl; | |
if (Descriptor == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR)); | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
} | |
/** | |
Return the configuration descriptor of the current active configuration. | |
@param This The USB IO instance. | |
@param Descriptor The USB configuration descriptor. | |
@retval EFI_SUCCESS The active configuration descriptor is returned. | |
@retval EFI_INVALID_PARAMETER Some parameter is invalid. | |
@retval EFI_NOT_FOUND Currently no active configuration is selected. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetActiveConfigDescriptor ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
if (Descriptor == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = EFI_SUCCESS; | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
if (Dev->ActiveConfig == NULL) { | |
Status = EFI_NOT_FOUND; | |
goto ON_EXIT; | |
} | |
CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR)); | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Retrieve the active interface setting descriptor for this USB IO instance. | |
@param This The USB IO instance. | |
@param Descriptor The variable to receive active interface setting. | |
@retval EFI_SUCCESS The active interface setting is returned. | |
@retval EFI_INVALID_PARAMETER Some parameter is invalid. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetInterfaceDescriptor ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor | |
) | |
{ | |
USB_INTERFACE *UsbIf; | |
EFI_TPL OldTpl; | |
if (Descriptor == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
} | |
/** | |
Retrieve the endpoint descriptor from this interface setting. | |
@param This The USB IO instance. | |
@param Index The index (start from zero) of the endpoint to | |
retrieve. | |
@param Descriptor The variable to receive the descriptor. | |
@retval EFI_SUCCESS The endpoint descriptor is returned. | |
@retval EFI_INVALID_PARAMETER Some parameter is invalid. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetEndpointDescriptor ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT8 Index, | |
OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor | |
) | |
{ | |
USB_INTERFACE *UsbIf; | |
EFI_TPL OldTpl; | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
if ((Descriptor == NULL) || (Index > 15)) { | |
gBS->RestoreTPL (OldTpl); | |
return EFI_INVALID_PARAMETER; | |
} | |
if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) { | |
gBS->RestoreTPL (OldTpl); | |
return EFI_NOT_FOUND; | |
} | |
CopyMem ( | |
Descriptor, | |
&(UsbIf->IfSetting->Endpoints[Index]->Desc), | |
sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) | |
); | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
} | |
/** | |
Retrieve the supported language ID table from the device. | |
@param This The USB IO instance. | |
@param LangIDTable The table to return the language IDs. | |
@param TableSize The size, in bytes, of the table LangIDTable. | |
@retval EFI_SUCCESS The language ID is return. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetSupportedLanguages ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
OUT UINT16 **LangIDTable, | |
OUT UINT16 *TableSize | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
EFI_TPL OldTpl; | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
*LangIDTable = Dev->LangId; | |
*TableSize = (UINT16) (Dev->TotalLangId * sizeof (UINT16)); | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
} | |
/** | |
Retrieve an indexed string in the language of LangID. | |
@param This The USB IO instance. | |
@param LangID The language ID of the string to retrieve. | |
@param StringIndex The index of the string. | |
@param String The variable to receive the string. | |
@retval EFI_SUCCESS The string is returned. | |
@retval EFI_NOT_FOUND No such string existed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoGetStringDescriptor ( | |
IN EFI_USB_IO_PROTOCOL *This, | |
IN UINT16 LangID, | |
IN UINT8 StringIndex, | |
OUT CHAR16 **String | |
) | |
{ | |
USB_DEVICE *Dev; | |
USB_INTERFACE *UsbIf; | |
EFI_USB_STRING_DESCRIPTOR *StrDesc; | |
EFI_TPL OldTpl; | |
UINT8 *Buf; | |
UINT8 Index; | |
EFI_STATUS Status; | |
if ((StringIndex == 0) || (LangID == 0)) { | |
return EFI_NOT_FOUND; | |
} | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
// | |
// Check whether language ID is supported | |
// | |
Status = EFI_NOT_FOUND; | |
for (Index = 0; Index < Dev->TotalLangId; Index++) { | |
ASSERT (Index < USB_MAX_LANG_ID); | |
if (Dev->LangId[Index] == LangID) { | |
break; | |
} | |
} | |
if (Index == Dev->TotalLangId) { | |
goto ON_EXIT; | |
} | |
// | |
// Retrieve the string descriptor then allocate a buffer | |
// to hold the string itself. | |
// | |
StrDesc = UsbGetOneString (Dev, StringIndex, LangID); | |
if (StrDesc == NULL) { | |
goto ON_EXIT; | |
} | |
if (StrDesc->Length <= 2) { | |
goto FREE_STR; | |
} | |
Buf = AllocateZeroPool (StrDesc->Length); | |
if (Buf == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto FREE_STR; | |
} | |
CopyMem (Buf, StrDesc->String, StrDesc->Length - 2); | |
*String = (CHAR16 *) Buf; | |
Status = EFI_SUCCESS; | |
FREE_STR: | |
gBS->FreePool (StrDesc); | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Reset the device, then if that succeeds, reconfigure the | |
device with its address and current active configuration. | |
@param This The USB IO instance. | |
@retval EFI_SUCCESS The device is reset and configured. | |
@retval Others Failed to reset the device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbIoPortReset ( | |
IN EFI_USB_IO_PROTOCOL *This | |
) | |
{ | |
USB_INTERFACE *UsbIf; | |
USB_INTERFACE *HubIf; | |
USB_DEVICE *Dev; | |
EFI_TPL OldTpl; | |
EFI_STATUS Status; | |
UINT8 DevAddress; | |
OldTpl = gBS->RaiseTPL (USB_BUS_TPL); | |
UsbIf = USB_INTERFACE_FROM_USBIO (This); | |
Dev = UsbIf->Device; | |
if (UsbIf->IsHub) { | |
Status = EFI_INVALID_PARAMETER; | |
goto ON_EXIT; | |
} | |
HubIf = Dev->ParentIf; | |
Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n", | |
Dev->ParentPort, Dev->ParentAddr, Status)); | |
goto ON_EXIT; | |
} | |
HubIf->HubApi->ClearPortChange (HubIf, Dev->ParentPort); | |
// | |
// Reset the device to its current address. The device now has an address | |
// of ZERO after port reset, so need to set Dev->Address to the device again for | |
// host to communicate with it. | |
// | |
DevAddress = Dev->Address; | |
Dev->Address = 0; | |
Status = UsbSetAddress (Dev, DevAddress); | |
Dev->Address = DevAddress; | |
gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL); | |
if (EFI_ERROR (Status)) { | |
// | |
// It may fail due to device disconnection or other reasons. | |
// | |
DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n", | |
Dev->Address, Status)); | |
goto ON_EXIT; | |
} | |
DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Dev->Address)); | |
// | |
// Reset the current active configure, after this device | |
// is in CONFIGURED state. | |
// | |
if (Dev->ActiveConfig != NULL) { | |
Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n", | |
Dev->Address, Status)); | |
} | |
} | |
ON_EXIT: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
/** | |
Install Usb Bus Protocol on host controller, and start the Usb bus. | |
@param This The USB bus driver binding instance. | |
@param Controller The controller to check. | |
@param RemainingDevicePath The remaining device patch. | |
@retval EFI_SUCCESS The controller is controlled by the usb bus. | |
@retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus. | |
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbBusBuildProtocol ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
USB_BUS *UsbBus; | |
USB_DEVICE *RootHub; | |
USB_INTERFACE *RootIf; | |
EFI_STATUS Status; | |
EFI_STATUS Status2; | |
UsbBus = AllocateZeroPool (sizeof (USB_BUS)); | |
if (UsbBus == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
UsbBus->Signature = USB_BUS_SIGNATURE; | |
UsbBus->HostHandle = Controller; | |
UsbBus->MaxDevices = USB_MAX_DEVICES; | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &UsbBus->DevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status)); | |
FreePool (UsbBus); | |
return Status; | |
} | |
// | |
// Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI). | |
// This is for backward compatibility with EFI 1.x. In UEFI | |
// 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2 | |
// and USB_HC because EHCI driver will install both protocols | |
// (for the same reason). If we don't consume both of them, | |
// the unconsumed one may be opened by others. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsb2HcProtocolGuid, | |
(VOID **) &(UsbBus->Usb2Hc), | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
Status2 = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsbHcProtocolGuid, | |
(VOID **) &(UsbBus->UsbHc), | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { | |
DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status)); | |
Status = EFI_DEVICE_ERROR; | |
goto CLOSE_HC; | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// The EFI_USB2_HC_PROTOCOL is produced for XHCI support. | |
// Then its max supported devices are 256. Otherwise it's 128. | |
// | |
ASSERT (UsbBus->Usb2Hc != NULL); | |
if (UsbBus->Usb2Hc->MajorRevision == 0x3) { | |
UsbBus->MaxDevices = 256; | |
} | |
} | |
UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL); | |
UsbHcSetState (UsbBus, EfiUsbHcStateOperational); | |
// | |
// Install an EFI_USB_BUS_PROTOCOL to host controller to identify it. | |
// | |
Status = gBS->InstallProtocolInterface ( | |
&Controller, | |
&gEfiCallerIdGuid, | |
EFI_NATIVE_INTERFACE, | |
&UsbBus->BusId | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status)); | |
goto CLOSE_HC; | |
} | |
// | |
// Initial the wanted child device path list, and add first RemainingDevicePath | |
// | |
InitializeListHead (&UsbBus->WantedUsbIoDPList); | |
Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath); | |
ASSERT (!EFI_ERROR (Status)); | |
// | |
// Create a fake usb device for root hub | |
// | |
RootHub = AllocateZeroPool (sizeof (USB_DEVICE)); | |
if (RootHub == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto UNINSTALL_USBBUS; | |
} | |
RootIf = AllocateZeroPool (sizeof (USB_INTERFACE)); | |
if (RootIf == NULL) { | |
FreePool (RootHub); | |
Status = EFI_OUT_OF_RESOURCES; | |
goto FREE_ROOTHUB; | |
} | |
RootHub->Bus = UsbBus; | |
RootHub->NumOfInterface = 1; | |
RootHub->Interfaces[0] = RootIf; | |
RootHub->Tier = 0; | |
RootIf->Signature = USB_INTERFACE_SIGNATURE; | |
RootIf->Device = RootHub; | |
RootIf->DevicePath = UsbBus->DevicePath; | |
// | |
// Report Status Code here since we will enumerate the USB devices | |
// | |
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
EFI_PROGRESS_CODE, | |
(EFI_IO_BUS_USB | EFI_IOB_PC_DETECT), | |
UsbBus->DevicePath | |
); | |
Status = mUsbRootHubApi.Init (RootIf); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status)); | |
goto FREE_ROOTHUB; | |
} | |
UsbBus->Devices[0] = RootHub; | |
DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf)); | |
return EFI_SUCCESS; | |
FREE_ROOTHUB: | |
if (RootIf != NULL) { | |
FreePool (RootIf); | |
} | |
if (RootHub != NULL) { | |
FreePool (RootHub); | |
} | |
UNINSTALL_USBBUS: | |
gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &UsbBus->BusId); | |
CLOSE_HC: | |
if (UsbBus->Usb2Hc != NULL) { | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsb2HcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} | |
if (UsbBus->UsbHc != NULL) { | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsbHcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
FreePool (UsbBus); | |
DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status)); | |
return Status; | |
} | |
/** | |
The USB bus driver entry pointer. | |
@param ImageHandle The driver image handle. | |
@param SystemTable The system table. | |
@return EFI_SUCCESS The component name protocol is installed. | |
@return Others Failed to init the usb driver. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbBusDriverEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
return EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&mUsbBusDriverBinding, | |
ImageHandle, | |
&mUsbBusComponentName, | |
&mUsbBusComponentName2 | |
); | |
} | |
/** | |
Check whether USB bus driver support this device. | |
@param This The USB bus driver binding protocol. | |
@param Controller The controller handle to check. | |
@param RemainingDevicePath The remaining device path. | |
@retval EFI_SUCCESS The bus supports this controller. | |
@retval EFI_UNSUPPORTED This device isn't supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbBusControllerDriverSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_DEV_PATH_PTR DevicePathNode; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
EFI_USB2_HC_PROTOCOL *Usb2Hc; | |
EFI_USB_HC_PROTOCOL *UsbHc; | |
EFI_STATUS Status; | |
// | |
// Check whether device path is valid | |
// | |
if (RemainingDevicePath != NULL) { | |
// | |
// Check if RemainingDevicePath is the End of Device Path Node, | |
// if yes, go on checking other conditions | |
// | |
if (!IsDevicePathEnd (RemainingDevicePath)) { | |
// | |
// If RemainingDevicePath isn't the End of Device Path Node, | |
// check its validation | |
// | |
DevicePathNode.DevPath = RemainingDevicePath; | |
if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) || | |
(DevicePathNode.DevPath->SubType != MSG_USB_DP && | |
DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP | |
&& DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP | |
)) { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
} | |
// | |
// Check whether USB_HC2 protocol is installed | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsb2HcProtocolGuid, | |
(VOID **) &Usb2Hc, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (Status == EFI_ALREADY_STARTED) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
// | |
// If failed to open USB_HC2, fall back to USB_HC | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiUsbHcProtocolGuid, | |
(VOID **) &UsbHc, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (Status == EFI_ALREADY_STARTED) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Close the USB_HC used to perform the supported test | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsbHcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} else { | |
// | |
// Close the USB_HC2 used to perform the supported test | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsb2HcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} | |
// | |
// Open the EFI Device Path protocol needed to perform the supported test | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &ParentDevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (Status == EFI_ALREADY_STARTED) { | |
return EFI_SUCCESS; | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// Close protocol, don't use device path protocol in the Support() function | |
// | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
return EFI_SUCCESS; | |
} | |
return Status; | |
} | |
/** | |
Start to process the controller. | |
@param This The USB bus driver binding instance. | |
@param Controller The controller to check. | |
@param RemainingDevicePath The remaining device patch. | |
@retval EFI_SUCCESS The controller is controlled by the usb bus. | |
@retval EFI_ALREADY_STARTED The controller is already controlled by the usb | |
bus. | |
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbBusControllerDriverStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_USB_BUS_PROTOCOL *UsbBusId; | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **) &ParentDevicePath, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Report Status Code here since we will initialize the host controller | |
// | |
REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
EFI_PROGRESS_CODE, | |
(EFI_IO_BUS_USB | EFI_IOB_PC_INIT), | |
ParentDevicePath | |
); | |
// | |
// Locate the USB bus protocol, if it is found, USB bus | |
// is already started on this controller. | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
(VOID **) &UsbBusId, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// If first start, build the bus execute environment and install bus protocol | |
// | |
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE)); | |
Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Try get the Usb Bus protocol interface again | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
(VOID **) &UsbBusId, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
ASSERT (!EFI_ERROR (Status)); | |
} else { | |
// | |
// USB Bus driver need to control the recursive connect policy of the bus, only those wanted | |
// usb child device will be recursively connected. | |
// The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time. | |
// All wanted usb child devices will be remembered by the usb bus driver itself. | |
// If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices. | |
// | |
// Save the passed in RemainingDevicePath this time | |
// | |
if (RemainingDevicePath != NULL) { | |
if (IsDevicePathEnd (RemainingDevicePath)) { | |
// | |
// If RemainingDevicePath is the End of Device Path Node, | |
// skip enumerate any device and return EFI_SUCESSS | |
// | |
return EFI_SUCCESS; | |
} | |
} | |
Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath); | |
ASSERT (!EFI_ERROR (Status)); | |
// | |
// Ensure all wanted child usb devices are fully recursively connected | |
// | |
Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId); | |
ASSERT (!EFI_ERROR (Status)); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Stop handle the controller by this USB bus driver. | |
@param This The USB bus driver binding protocol. | |
@param Controller The controller to release. | |
@param NumberOfChildren The child of USB bus that opened controller | |
BY_CHILD. | |
@param ChildHandleBuffer The array of child handle. | |
@retval EFI_SUCCESS The controller or children are stopped. | |
@retval EFI_DEVICE_ERROR Failed to stop the driver. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UsbBusControllerDriverStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
{ | |
USB_BUS *Bus; | |
USB_DEVICE *RootHub; | |
USB_DEVICE *UsbDev; | |
USB_INTERFACE *RootIf; | |
USB_INTERFACE *UsbIf; | |
EFI_USB_BUS_PROTOCOL *BusId; | |
EFI_USB_IO_PROTOCOL *UsbIo; | |
EFI_TPL OldTpl; | |
UINTN Index; | |
EFI_STATUS Status; | |
EFI_STATUS ReturnStatus; | |
Status = EFI_SUCCESS; | |
if (NumberOfChildren > 0) { | |
// | |
// BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict | |
// | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
ReturnStatus = EFI_SUCCESS; | |
for (Index = 0; Index < NumberOfChildren; Index++) { | |
Status = gBS->OpenProtocol ( | |
ChildHandleBuffer[Index], | |
&gEfiUsbIoProtocolGuid, | |
(VOID **) &UsbIo, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// It is possible that the child has already been released: | |
// 1. For combo device, free one device will release others. | |
// 2. If a hub is released, all devices on its down facing | |
// ports are released also. | |
// | |
continue; | |
} | |
UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo); | |
UsbDev = UsbIf->Device; | |
ReturnStatus = UsbRemoveDevice (UsbDev); | |
} | |
gBS->RestoreTPL (OldTpl); | |
return ReturnStatus; | |
} | |
DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller)); | |
// | |
// Locate USB_BUS for the current host controller | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiCallerIdGuid, | |
(VOID **) &BusId, | |
This->DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Bus = USB_BUS_FROM_THIS (BusId); | |
// | |
// Stop the root hub, then free all the devices | |
// | |
// BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict | |
// | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
RootHub = Bus->Devices[0]; | |
RootIf = RootHub->Interfaces[0]; | |
ASSERT (Bus->MaxDevices <= 256); | |
ReturnStatus = EFI_SUCCESS; | |
for (Index = 1; Index < Bus->MaxDevices; Index++) { | |
if (Bus->Devices[Index] != NULL) { | |
Status = UsbRemoveDevice (Bus->Devices[Index]); | |
if (EFI_ERROR (Status)) { | |
ReturnStatus = Status; | |
} | |
} | |
} | |
gBS->RestoreTPL (OldTpl); | |
if (!EFI_ERROR (ReturnStatus)) { | |
mUsbRootHubApi.Release (RootIf); | |
gBS->FreePool (RootIf); | |
gBS->FreePool (RootHub); | |
Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList); | |
ASSERT (!EFI_ERROR (Status)); | |
// | |
// Uninstall the bus identifier and close USB_HC/USB2_HC protocols | |
// | |
gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &Bus->BusId); | |
if (Bus->Usb2Hc != NULL) { | |
Status = gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsb2HcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} | |
if (Bus->UsbHc != NULL) { | |
Status = gBS->CloseProtocol ( | |
Controller, | |
&gEfiUsbHcProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
} | |
if (!EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
Controller, | |
&gEfiDevicePathProtocolGuid, | |
This->DriverBindingHandle, | |
Controller | |
); | |
gBS->FreePool (Bus); | |
} | |
} | |
return Status; | |
} |