| /** @file | |
| Copyright (c) 2007, Intel Corporation | |
| All rights reserved. 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. | |
| Module Name: | |
| UsbDesc.c | |
| Abstract: | |
| Manage Usb Descriptor List | |
| Revision History | |
| **/ | |
| #include "UsbBus.h" | |
| /** | |
| Free the interface setting descriptor | |
| @param Setting The descriptor to free | |
| @return None | |
| **/ | |
| STATIC | |
| 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) { | |
| gBS->FreePool (Ep); | |
| } | |
| } | |
| gBS->FreePool (Setting->Endpoints); | |
| } | |
| gBS->FreePool (Setting); | |
| } | |
| /** | |
| Free a configuration descriptor with its interface | |
| descriptors. It may be initialized partially | |
| @param Config The configuration descriptor to free | |
| @return None | |
| **/ | |
| STATIC | |
| 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]); | |
| } | |
| } | |
| gBS->FreePool (Interface); | |
| } | |
| gBS->FreePool (Config->Interfaces); | |
| } | |
| gBS->FreePool (Config); | |
| } | |
| /** | |
| Free a device descriptor with its configurations | |
| @param DevDesc The device descriptor | |
| @return None | |
| **/ | |
| 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]); | |
| } | |
| } | |
| gBS->FreePool (DevDesc->Configs); | |
| } | |
| gBS->FreePool (DevDesc); | |
| } | |
| /** | |
| Create a descriptor | |
| @param DescBuf The buffer of raw descriptor | |
| @param Len The lenght of the raw descriptor buffer | |
| @param Type The type of descriptor to create | |
| @param Consumed Number of bytes consumed | |
| @return Created descriptor or NULL | |
| **/ | |
| STATIC | |
| VOID * | |
| UsbCreateDesc ( | |
| IN UINT8 *DescBuf, | |
| IN INTN Len, | |
| IN UINT8 Type, | |
| OUT INTN *Consumed | |
| ) | |
| { | |
| USB_DESC_HEAD *Head; | |
| INTN DescLen; | |
| INTN CtrlLen; | |
| INTN 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; | |
| } | |
| // | |
| // 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) && (Head->Type != Type)) { | |
| Offset += Head->Len; | |
| Head = (USB_DESC_HEAD*)(DescBuf + Offset); | |
| } | |
| if ((Len <= Offset) || (Len < Offset + DescLen) || | |
| (Head->Type != Type) || (Head->Len != DescLen)) { | |
| DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor\n")); | |
| return NULL; | |
| } | |
| Desc = AllocateZeroPool (CtrlLen); | |
| if (Desc == NULL) { | |
| return NULL; | |
| } | |
| CopyMem (Desc, Head, DescLen); | |
| *Consumed = Offset + Head->Len; | |
| return Desc; | |
| } | |
| /** | |
| Parse an interface desciptor and its endpoints | |
| @param DescBuf The buffer of raw descriptor | |
| @param Len The lenght of the raw descriptor buffer | |
| @param Consumed The number of raw descriptor consumed | |
| @return The create interface setting or NULL if failed | |
| **/ | |
| STATIC | |
| USB_INTERFACE_SETTING * | |
| UsbParseInterfaceDesc ( | |
| IN UINT8 *DescBuf, | |
| IN INTN Len, | |
| OUT INTN *Consumed | |
| ) | |
| { | |
| USB_INTERFACE_SETTING *Setting; | |
| USB_ENDPOINT_DESC *Ep; | |
| UINTN Index; | |
| UINTN NumEp; | |
| INTN Used; | |
| INTN 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 arry 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, 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; 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", 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 lenght of the raw descriptor buffer | |
| @return The created configuration descriptor | |
| **/ | |
| STATIC | |
| USB_CONFIG_DESC * | |
| UsbParseConfigDesc ( | |
| IN UINT8 *DescBuf, | |
| IN INTN Len | |
| ) | |
| { | |
| USB_CONFIG_DESC *Config; | |
| USB_INTERFACE_SETTING *Setting; | |
| USB_INTERFACE_DESC *Interface; | |
| UINTN Index; | |
| UINTN NumIf; | |
| INTN 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, 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; | |
| while (Len > 0) { | |
| Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed); | |
| if ((Setting == NULL)) { | |
| DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: failed to parse interface setting\n")); | |
| goto ON_ERROR; | |
| } else if (Setting->Desc.InterfaceNumber >= NumIf) { | |
| DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: mal-formated 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, | |
| 50 * USB_STALL_1_MS, | |
| &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 | |
| **/ | |
| STATIC | |
| 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. | |
| // | |
| UsbDev->MaxPacket0 = 8; | |
| for (Index = 0; Index < 3; Index++) { | |
| Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8); | |
| if (!EFI_ERROR (Status)) { | |
| UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0; | |
| return EFI_SUCCESS; | |
| } | |
| gBS->Stall (100 * USB_STALL_1_MS); | |
| } | |
| 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 | |
| **/ | |
| STATIC | |
| 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); | |
| if (EFI_ERROR (Status)) { | |
| 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)) { | |
| gBS->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 | |
| **/ | |
| STATIC | |
| 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 = (Max < USB_MAX_LANG_ID ? 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 togetther 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 | |
| **/ | |
| STATIC | |
| 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", | |
| Status, Desc.TotalLength)); | |
| return NULL; | |
| } | |
| DEBUG (( EFI_D_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength)); | |
| 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)); | |
| gBS->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; | |
| 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); | |
| gBS->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_ERROR, "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, | |
| 10 * USB_STALL_1_MS, | |
| NULL, | |
| 0, | |
| &UsbResult | |
| ); | |
| return Status; | |
| } |