| /** @file | |
| Manage Usb Descriptor List | |
| Copyright (c) 2007 - 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" | |
| /** | |
| 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; | |
| } | |
| // | |
| // 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; | |
| if (Len <= Offset) { | |
| DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor, Beyond boundary!\n")); | |
| return NULL; | |
| } | |
| Head = (USB_DESC_HEAD*)(DescBuf + Offset); | |
| if (Head->Len == 0) { | |
| DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n")); | |
| return NULL; | |
| } | |
| } | |
| 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 ((UINTN) CtrlLen); | |
| if (Desc == NULL) { | |
| return NULL; | |
| } | |
| CopyMem (Desc, Head, (UINTN) DescLen); | |
| *Consumed = Offset + Head->Len; | |
| 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 (( 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, | |
| 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); | |
| 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)) { | |
| 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)); | |
| 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; | |
| } |