diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c new file mode 100644 index 00000000..c33b17f1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c @@ -0,0 +1,1017 @@ +/** @file + + Manage Usb Descriptor List + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbBus.h" + + +/** + Free the interface setting descriptor. + + @param Setting The descriptor to free. + +**/ +VOID +UsbFreeInterfaceDesc ( + IN USB_INTERFACE_SETTING *Setting + ) +{ + USB_ENDPOINT_DESC *Ep; + UINTN Index; + + if (Setting->Endpoints != NULL) { + // + // Each interface setting may have several endpoints, free them first. + // + for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) { + Ep = Setting->Endpoints[Index]; + + if (Ep != NULL) { + FreePool (Ep); + } + } + + // + // Only call FreePool() if NumEndpoints > 0. + // + if (Setting->Desc.NumEndpoints > 0) { + FreePool (Setting->Endpoints); + } + } + + FreePool (Setting); +} + + +/** + Free a configuration descriptor with its interface + descriptors. It may be initialized partially. + + @param Config The configuration descriptor to free. + +**/ +VOID +UsbFreeConfigDesc ( + IN USB_CONFIG_DESC *Config + ) +{ + USB_INTERFACE_DESC *Interface; + UINTN Index; + UINTN SetIndex; + + if (Config->Interfaces != NULL) { + // + // A configuration may have several interfaces, free the interface + // + for (Index = 0; Index < Config->Desc.NumInterfaces; Index++) { + Interface = Config->Interfaces[Index]; + + if (Interface == NULL) { + continue; + } + + // + // Each interface may have several settings, free the settings + // + for (SetIndex = 0; SetIndex < Interface->NumOfSetting; SetIndex++) { + if (Interface->Settings[SetIndex] != NULL) { + UsbFreeInterfaceDesc (Interface->Settings[SetIndex]); + } + } + + FreePool (Interface); + } + + FreePool (Config->Interfaces); + } + + FreePool (Config); + +} + + +/** + Free a device descriptor with its configurations. + + @param DevDesc The device descriptor. + +**/ +VOID +UsbFreeDevDesc ( + IN USB_DEVICE_DESC *DevDesc + ) +{ + UINTN Index; + + if (DevDesc->Configs != NULL) { + for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) { + if (DevDesc->Configs[Index] != NULL) { + UsbFreeConfigDesc (DevDesc->Configs[Index]); + } + } + + FreePool (DevDesc->Configs); + } + + FreePool (DevDesc); +} + + +/** + Create a descriptor. + + @param DescBuf The buffer of raw descriptor. + @param Len The length of the raw descriptor buffer. + @param Type The type of descriptor to create. + @param Consumed Number of bytes consumed. + + @return Created descriptor or NULL. + +**/ +VOID * +UsbCreateDesc ( + IN UINT8 *DescBuf, + IN UINTN Len, + IN UINT8 Type, + OUT UINTN *Consumed + ) +{ + USB_DESC_HEAD *Head; + UINTN DescLen; + UINTN CtrlLen; + UINTN Offset; + VOID *Desc; + + DescLen = 0; + CtrlLen = 0; + *Consumed = 0; + + switch (Type) { + case USB_DESC_TYPE_DEVICE: + DescLen = sizeof (EFI_USB_DEVICE_DESCRIPTOR); + CtrlLen = sizeof (USB_DEVICE_DESC); + break; + + case USB_DESC_TYPE_CONFIG: + DescLen = sizeof (EFI_USB_CONFIG_DESCRIPTOR); + CtrlLen = sizeof (USB_CONFIG_DESC); + break; + + case USB_DESC_TYPE_INTERFACE: + DescLen = sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + CtrlLen = sizeof (USB_INTERFACE_SETTING); + break; + + case USB_DESC_TYPE_ENDPOINT: + DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + CtrlLen = sizeof (USB_ENDPOINT_DESC); + break; + + default: + ASSERT (FALSE); + return NULL; + } + + // + // Total length is too small that cannot hold the single descriptor header plus data. + // + if (Len <= sizeof (USB_DESC_HEAD)) { + DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, total length = %d!\n", Len)); + return NULL; + } + + // + // All the descriptor has a common LTV (Length, Type, Value) + // format. Skip the descriptor that isn't of this Type + // + Offset = 0; + Head = (USB_DESC_HEAD *)DescBuf; + while (Offset < Len - sizeof (USB_DESC_HEAD)) { + // + // Above condition make sure Head->Len and Head->Type are safe to access + // + Head = (USB_DESC_HEAD *)&DescBuf[Offset]; + + if (Head->Len == 0) { + DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n")); + return NULL; + } + + // + // Make sure no overflow when adding Head->Len to Offset. + // + if (Head->Len > MAX_UINTN - Offset) { + DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = %d!\n", Head->Len)); + return NULL; + } + + Offset += Head->Len; + + if (Head->Type == Type) { + break; + } + } + + // + // Head->Len is invalid resulting data beyond boundary, or + // Descriptor cannot be found: No such type. + // + if (Len < Offset) { + DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Len)); + return NULL; + } + + if ((Head->Type != Type) || (Head->Len < DescLen)) { + DEBUG ((DEBUG_ERROR, "UsbCreateDesc: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len)); + return NULL; + } + + Desc = AllocateZeroPool ((UINTN) CtrlLen); + if (Desc == NULL) { + return NULL; + } + + CopyMem (Desc, Head, (UINTN) DescLen); + + *Consumed = Offset; + + return Desc; +} + + +/** + Parse an interface descriptor and its endpoints. + + @param DescBuf The buffer of raw descriptor. + @param Len The length of the raw descriptor buffer. + @param Consumed The number of raw descriptor consumed. + + @return The create interface setting or NULL if failed. + +**/ +USB_INTERFACE_SETTING * +UsbParseInterfaceDesc ( + IN UINT8 *DescBuf, + IN UINTN Len, + OUT UINTN *Consumed + ) +{ + USB_INTERFACE_SETTING *Setting; + USB_ENDPOINT_DESC *Ep; + UINTN Index; + UINTN NumEp; + UINTN Used; + UINTN Offset; + + *Consumed = 0; + Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used); + + if (Setting == NULL) { + DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create interface descriptor\n")); + return NULL; + } + + Offset = Used; + + // + // Create an array to hold the interface's endpoints + // + NumEp = Setting->Desc.NumEndpoints; + + DEBUG (( EFI_D_INFO, "UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n", + Setting->Desc.InterfaceNumber, Setting->Desc.AlternateSetting, (UINT32)NumEp)); + + if (NumEp == 0) { + goto ON_EXIT; + } + + Setting->Endpoints = AllocateZeroPool (sizeof (USB_ENDPOINT_DESC *) * NumEp); + + if (Setting->Endpoints == NULL) { + goto ON_ERROR; + } + + // + // Create the endpoints for this interface + // + for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) { + Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used); + + if (Ep == NULL) { + DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", (UINT32)Index)); + goto ON_ERROR; + } + + Setting->Endpoints[Index] = Ep; + Offset += Used; + } + + +ON_EXIT: + *Consumed = Offset; + return Setting; + +ON_ERROR: + UsbFreeInterfaceDesc (Setting); + return NULL; +} + + +/** + Parse the configuration descriptor and its interfaces. + + @param DescBuf The buffer of raw descriptor. + @param Len The length of the raw descriptor buffer. + + @return The created configuration descriptor. + +**/ +USB_CONFIG_DESC * +UsbParseConfigDesc ( + IN UINT8 *DescBuf, + IN UINTN Len + ) +{ + USB_CONFIG_DESC *Config; + USB_INTERFACE_SETTING *Setting; + USB_INTERFACE_DESC *Interface; + UINTN Index; + UINTN NumIf; + UINTN Consumed; + + ASSERT (DescBuf != NULL); + + Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed); + + if (Config == NULL) { + return NULL; + } + + // + // Initialize an array of setting for the configuration's interfaces. + // + NumIf = Config->Desc.NumInterfaces; + Config->Interfaces = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf); + + if (Config->Interfaces == NULL) { + goto ON_ERROR; + } + + DEBUG (( EFI_D_INFO, "UsbParseConfigDesc: config %d has %d interfaces\n", + Config->Desc.ConfigurationValue, (UINT32)NumIf)); + + for (Index = 0; Index < NumIf; Index++) { + Interface = AllocateZeroPool (sizeof (USB_INTERFACE_DESC)); + + if (Interface == NULL) { + goto ON_ERROR; + } + + Config->Interfaces[Index] = Interface; + } + + // + // If a configuration has several interfaces, these interfaces are + // numbered from zero to n. If a interface has several settings, + // these settings are also number from zero to m. The interface + // setting must be organized as |interface 0, setting 0|interface 0 + // setting 1|interface 1, setting 0|interface 2, setting 0|. Check + // USB2.0 spec, page 267. + // + DescBuf += Consumed; + Len -= Consumed; + + // + // Make allowances for devices that return extra data at the + // end of their config descriptors + // + while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) { + Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed); + + if (Setting == NULL) { + DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n")); + break; + + } else if (Setting->Desc.InterfaceNumber >= NumIf) { + DEBUG (( DEBUG_ERROR, "UsbParseConfigDesc: malformatted interface descriptor\n")); + + UsbFreeInterfaceDesc (Setting); + goto ON_ERROR; + } + + // + // Insert the descriptor to the corresponding set. + // + Interface = Config->Interfaces[Setting->Desc.InterfaceNumber]; + + if (Interface->NumOfSetting >= USB_MAX_INTERFACE_SETTING) { + goto ON_ERROR; + } + + Interface->Settings[Interface->NumOfSetting] = Setting; + Interface->NumOfSetting++; + + DescBuf += Consumed; + Len -= Consumed; + } + + return Config; + +ON_ERROR: + UsbFreeConfigDesc (Config); + return NULL; +} + + +/** + USB standard control transfer support routine. This + function is used by USB device. It is possible that + the device's interfaces are still waiting to be + enumerated. + + @param UsbDev The usb device. + @param Direction The direction of data transfer. + @param Type Standard / class specific / vendor specific. + @param Target The receiving target. + @param Request Which request. + @param Value The wValue parameter of the request. + @param Index The wIndex parameter of the request. + @param Buf The buffer to receive data into / transmit from. + @param Length The length of the buffer. + + @retval EFI_SUCCESS The control request is executed. + @retval EFI_DEVICE_ERROR Failed to execute the control transfer. + +**/ +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 + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS Status; + UINT32 Result; + UINTN Len; + + ASSERT ((UsbDev != NULL) && (UsbDev->Bus != NULL)); + + DevReq.RequestType = USB_REQUEST_TYPE (Direction, Type, Target); + DevReq.Request = (UINT8) Request; + DevReq.Value = Value; + DevReq.Index = Index; + DevReq.Length = (UINT16) Length; + + Len = Length; + Status = UsbHcControlTransfer ( + UsbDev->Bus, + UsbDev->Address, + UsbDev->Speed, + UsbDev->MaxPacket0, + &DevReq, + Direction, + Buf, + &Len, + USB_GENERAL_DEVICE_REQUEST_TIMEOUT, + &UsbDev->Translator, + &Result + ); + + return Status; +} + + +/** + Get the standard descriptors. + + @param UsbDev The USB device to read descriptor from. + @param DescType The type of descriptor to read. + @param DescIndex The index of descriptor to read. + @param LangId Language ID, only used to get string, otherwise set + it to 0. + @param Buf The buffer to hold the descriptor read. + @param Length The length of the buffer. + + @retval EFI_SUCCESS The descriptor is read OK. + @retval Others Failed to retrieve the descriptor. + +**/ +EFI_STATUS +UsbCtrlGetDesc ( + IN USB_DEVICE *UsbDev, + IN UINTN DescType, + IN UINTN DescIndex, + IN UINT16 LangId, + OUT VOID *Buf, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + Status = UsbCtrlRequest ( + UsbDev, + EfiUsbDataIn, + USB_REQ_TYPE_STANDARD, + USB_TARGET_DEVICE, + USB_REQ_GET_DESCRIPTOR, + (UINT16) ((DescType << 8) | DescIndex), + LangId, + Buf, + Length + ); + + return Status; +} + + +/** + Return the max packet size for endpoint zero. This function + is the first function called to get descriptors during bus + enumeration. + + @param UsbDev The usb device. + + @retval EFI_SUCCESS The max packet size of endpoint zero is retrieved. + @retval EFI_DEVICE_ERROR Failed to retrieve it. + +**/ +EFI_STATUS +UsbGetMaxPacketSize0 ( + IN USB_DEVICE *UsbDev + ) +{ + EFI_USB_DEVICE_DESCRIPTOR DevDesc; + EFI_STATUS Status; + UINTN Index; + + + // + // Get the first 8 bytes of the device descriptor which contains + // max packet size for endpoint 0, which is at least 8. + // + for (Index = 0; Index < 3; Index++) { + Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8); + + if (!EFI_ERROR (Status)) { + if ((DevDesc.BcdUSB >= 0x0300) && (DevDesc.MaxPacketSize0 == 9)) { + UsbDev->MaxPacket0 = 1 << 9; + return EFI_SUCCESS; + } + UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0; + return EFI_SUCCESS; + } + + gBS->Stall (USB_RETRY_MAX_PACK_SIZE_STALL); + } + + return EFI_DEVICE_ERROR; +} + + +/** + Get the device descriptor for the device. + + @param UsbDev The Usb device to retrieve descriptor from. + + @retval EFI_SUCCESS The device descriptor is returned. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + +**/ +EFI_STATUS +UsbGetDevDesc ( + IN USB_DEVICE *UsbDev + ) +{ + USB_DEVICE_DESC *DevDesc; + EFI_STATUS Status; + + DevDesc = AllocateZeroPool (sizeof (USB_DEVICE_DESC)); + + if (DevDesc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = UsbCtrlGetDesc ( + UsbDev, + USB_DESC_TYPE_DEVICE, + 0, + 0, + DevDesc, + sizeof (EFI_USB_DEVICE_DESCRIPTOR) + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (DevDesc); + } else { + UsbDev->DevDesc = DevDesc; + } + + return Status; +} + + +/** + Retrieve the indexed string for the language. It requires two + steps to get a string, first to get the string's length. Then + the string itself. + + @param UsbDev The usb device. + @param Index The index the string to retrieve. + @param LangId Language ID. + + @return The created string descriptor or NULL. + +**/ +EFI_USB_STRING_DESCRIPTOR * +UsbGetOneString ( + IN USB_DEVICE *UsbDev, + IN UINT8 Index, + IN UINT16 LangId + ) +{ + EFI_USB_STRING_DESCRIPTOR Desc; + EFI_STATUS Status; + UINT8 *Buf; + + // + // First get two bytes which contains the string length. + // + Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2); + + // + // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even. + // + if (EFI_ERROR (Status) || + (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) || + (Desc.Length % 2 != 0) + ) { + return NULL; + } + + Buf = AllocateZeroPool (Desc.Length); + + if (Buf == NULL) { + return NULL; + } + + Status = UsbCtrlGetDesc ( + UsbDev, + USB_DESC_TYPE_STRING, + Index, + LangId, + Buf, + Desc.Length + ); + + if (EFI_ERROR (Status)) { + FreePool (Buf); + return NULL; + } + + return (EFI_USB_STRING_DESCRIPTOR *) Buf; +} + + +/** + Build the language ID table for string descriptors. + + @param UsbDev The Usb device. + + @retval EFI_UNSUPPORTED This device doesn't support string table. + +**/ +EFI_STATUS +UsbBuildLangTable ( + IN USB_DEVICE *UsbDev + ) +{ + EFI_USB_STRING_DESCRIPTOR *Desc; + EFI_STATUS Status; + UINTN Index; + UINTN Max; + UINT16 *Point; + + // + // The string of language ID zero returns the supported languages + // + Desc = UsbGetOneString (UsbDev, 0, 0); + + if (Desc == NULL) { + return EFI_UNSUPPORTED; + } + + if (Desc->Length < 4) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + Status = EFI_SUCCESS; + + Max = (Desc->Length - 2) / 2; + Max = MIN(Max, USB_MAX_LANG_ID); + + Point = Desc->String; + for (Index = 0; Index < Max; Index++) { + UsbDev->LangId[Index] = *Point; + Point++; + } + + UsbDev->TotalLangId = (UINT16)Max; + +ON_EXIT: + gBS->FreePool (Desc); + return Status; +} + + +/** + Retrieve the indexed configure for the device. USB device + returns the configuration together with the interfaces for + this configuration. Configuration descriptor is also of + variable length. + + @param UsbDev The Usb interface. + @param Index The index of the configuration. + + @return The created configuration descriptor. + +**/ +EFI_USB_CONFIG_DESCRIPTOR * +UsbGetOneConfig ( + IN USB_DEVICE *UsbDev, + IN UINT8 Index + ) +{ + EFI_USB_CONFIG_DESCRIPTOR Desc; + EFI_STATUS Status; + VOID *Buf; + + // + // First get four bytes which contains the total length + // for this configuration. + // + Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, &Desc, 8); + + if (EFI_ERROR (Status)) { + DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get descript length(%d) %r\n", + Desc.TotalLength, Status)); + + return NULL; + } + + DEBUG (( EFI_D_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength)); + + // + // Reject if TotalLength even cannot cover itself. + // + if (Desc.TotalLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (Desc.TotalLength)) { + return NULL; + } + + Buf = AllocateZeroPool (Desc.TotalLength); + + if (Buf == NULL) { + return NULL; + } + + Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, Buf, Desc.TotalLength); + + if (EFI_ERROR (Status)) { + DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get full descript %r\n", Status)); + + FreePool (Buf); + return NULL; + } + + return Buf; +} + + +/** + Build the whole array of descriptors. This function must + be called after UsbGetMaxPacketSize0 returns the max packet + size correctly for endpoint 0. + + @param UsbDev The Usb device. + + @retval EFI_SUCCESS The descriptor table is build. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor. + +**/ +EFI_STATUS +UsbBuildDescTable ( + IN USB_DEVICE *UsbDev + ) +{ + EFI_USB_CONFIG_DESCRIPTOR *Config; + USB_DEVICE_DESC *DevDesc; + USB_CONFIG_DESC *ConfigDesc; + UINT8 NumConfig; + EFI_STATUS Status; + UINT8 Index; + + // + // Get the device descriptor, then allocate the configure + // descriptor pointer array to hold configurations. + // + Status = UsbGetDevDesc (UsbDev); + + if (EFI_ERROR (Status)) { + DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get device descriptor - %r\n", Status)); + return Status; + } + + DevDesc = UsbDev->DevDesc; + NumConfig = DevDesc->Desc.NumConfigurations; + if (NumConfig == 0) { + return EFI_DEVICE_ERROR; + } + + DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *)); + if (DevDesc->Configs == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DEBUG (( EFI_D_INFO, "UsbBuildDescTable: device has %d configures\n", NumConfig)); + + // + // Read each configurations, then parse them + // + for (Index = 0; Index < NumConfig; Index++) { + Config = UsbGetOneConfig (UsbDev, Index); + + if (Config == NULL) { + DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get configure (index %d)\n", Index)); + + // + // If we can get the default descriptor, it is likely that the + // device is still operational. + // + if (Index == 0) { + return EFI_DEVICE_ERROR; + } + + break; + } + + ConfigDesc = UsbParseConfigDesc ((UINT8 *) Config, Config->TotalLength); + + FreePool (Config); + + if (ConfigDesc == NULL) { + DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to parse configure (index %d)\n", Index)); + + // + // If we can get the default descriptor, it is likely that the + // device is still operational. + // + if (Index == 0) { + return EFI_DEVICE_ERROR; + } + + break; + } + + DevDesc->Configs[Index] = ConfigDesc; + } + + // + // Don't return error even this function failed because + // it is possible for the device to not support strings. + // + Status = UsbBuildLangTable (UsbDev); + + if (EFI_ERROR (Status)) { + DEBUG (( EFI_D_INFO, "UsbBuildDescTable: get language ID table %r\n", Status)); + } + + return EFI_SUCCESS; +} + + +/** + Set the device's address. + + @param UsbDev The device to set address to. + @param Address The address to set. + + @retval EFI_SUCCESS The device is set to the address. + @retval Others Failed to set the device address. + +**/ +EFI_STATUS +UsbSetAddress ( + IN USB_DEVICE *UsbDev, + IN UINT8 Address + ) +{ + EFI_STATUS Status; + + Status = UsbCtrlRequest ( + UsbDev, + EfiUsbNoData, + USB_REQ_TYPE_STANDARD, + USB_TARGET_DEVICE, + USB_REQ_SET_ADDRESS, + Address, + 0, + NULL, + 0 + ); + + return Status; +} + + +/** + Set the device's configuration. This function changes + the device's internal state. UsbSelectConfig changes + the Usb bus's internal state. + + @param UsbDev The USB device to set configure to. + @param ConfigIndex The configure index to set. + + @retval EFI_SUCCESS The device is configured now. + @retval Others Failed to set the device configure. + +**/ +EFI_STATUS +UsbSetConfig ( + IN USB_DEVICE *UsbDev, + IN UINT8 ConfigIndex + ) +{ + EFI_STATUS Status; + + Status = UsbCtrlRequest ( + UsbDev, + EfiUsbNoData, + USB_REQ_TYPE_STANDARD, + USB_TARGET_DEVICE, + USB_REQ_SET_CONFIG, + ConfigIndex, + 0, + NULL, + 0 + ); + + return Status; +} + + +/** + Usb UsbIo interface to clear the feature. This is should + only be used by HUB which is considered a device driver + on top of the UsbIo interface. + + @param UsbIo The UsbIo interface. + @param Target The target of the transfer: endpoint/device. + @param Feature The feature to clear. + @param Index The wIndex parameter. + + @retval EFI_SUCCESS The device feature is cleared. + @retval Others Failed to clear the feature. + +**/ +EFI_STATUS +UsbIoClearFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINTN Target, + IN UINT16 Feature, + IN UINT16 Index + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + UINT32 UsbResult; + EFI_STATUS Status; + + DevReq.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, Target); + DevReq.Request = USB_REQ_CLEAR_FEATURE; + DevReq.Value = Feature; + DevReq.Index = Index; + DevReq.Length = 0; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + USB_CLEAR_FEATURE_REQUEST_TIMEOUT, + NULL, + 0, + &UsbResult + ); + + return Status; +} |