/** Select a new configuration for the device. Each device may support several configurations. @param Device The device to select configuration. @param ConfigValue The index of the configuration ( != 0). @retval EFI_NOT_FOUND There is no configuration with the index. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. @retval EFI_SUCCESS The configuration is selected. **/ EFI_STATUS UsbSelectConfig ( IN USB_DEVICE *Device, IN UINT8 ConfigValue ) { USB_DEVICE_DESC *DevDesc; USB_CONFIG_DESC *ConfigDesc; USB_INTERFACE_DESC *IfDesc; USB_INTERFACE *UsbIf; EFI_STATUS Status; UINT8 Index; // // Locate the active config, then set the device's pointer // DevDesc = Device->DevDesc; ConfigDesc = NULL; for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) { ConfigDesc = DevDesc->Configs[Index]; if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) { break; } } if (Index == DevDesc->Desc.NumConfigurations) { return EFI_NOT_FOUND; } Device->ActiveConfig = ConfigDesc; // DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n", // ConfigValue, Device->Address)); DBG("UsbSelectConfig: config %d selected for device %d\n", ConfigValue, Device->Address); // // Create interfaces for each USB interface descriptor. // for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) { // // First select the default interface setting, and reset // the endpoint toggles to zero for its endpoints. // IfDesc = ConfigDesc->Interfaces[Index]; UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting); // // Create a USB_INTERFACE and install USB_IO and other protocols // UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]); if (UsbIf == NULL) { Device->NumOfInterface = Index; return EFI_OUT_OF_RESOURCES; } // ASSERT (Index < USB_MAX_INTERFACE); Device->Interfaces[Index] = UsbIf; // // Connect the device to drivers, if it failed, ignore // the error. Don't let the unsupported interfaces to block // the supported interfaces. // Status = UsbConnectDriver (UsbIf); DBG("UsbSelect[%d]:%r\n", Index, Status); if (EFI_ERROR (Status)) { // DEBUG ((EFI_D_ERROR, "UsbSelectConfig: failed to connect driver %r, ignored\n", Status)); } } Device->NumOfInterface = Index; return EFI_SUCCESS; }
/** 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; }
EFI_STATUS UsbSelectConfig ( IN USB_DEVICE *Device, IN UINT8 ConfigValue ) /*++ Routine Description: Select a new configuration for the device. Each device may support several configurations. Arguments: Device - The device to select configuration ConfigValue - The index of the configuration ( != 0) Returns: EFI_NOT_FOUND - There is no configuration with the index EFI_OUT_OF_RESOURCES - Failed to allocate resource EFI_SUCCESS - The configuration is selected. --*/ { USB_DEVICE_DESC *DevDesc; USB_CONFIG_DESC *ConfigDesc; USB_INTERFACE_DESC *IfDesc; USB_INTERFACE *UsbIf; EFI_STATUS Status; UINT8 Index; // // Locate the active config, then set the device's pointer // DevDesc = Device->DevDesc; ConfigDesc = NULL; for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) { ConfigDesc = DevDesc->Configs[Index]; if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) { break; } } if (Index == DevDesc->Desc.NumConfigurations) { return EFI_NOT_FOUND; } Device->ActiveConfig = ConfigDesc; USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n", ConfigValue, Device->Address)); // // Create interfaces for each USB interface descriptor. // for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) { // // First select the default interface setting, and reset // the endpoint toggles to zero for its endpoints. // IfDesc = ConfigDesc->Interfaces[Index]; UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting); // // Create a USB_INTERFACE and install USB_IO and other protocols // UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]); if (UsbIf == NULL) { return EFI_OUT_OF_RESOURCES; } Device->Interfaces[Index] = UsbIf; // // Connect the device to drivers, if it failed, ignore // the error. Don't let the unsupported interfaces to block // the supported interfaces. // Status = UsbConnectDriver (UsbIf); if (EFI_ERROR (Status)) { USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status)); } } Device->NumOfInterface = Index; return EFI_SUCCESS; }