/** 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)); if (!UsbDev || !(UsbDev->Bus)) { return EFI_DEVICE_ERROR; } 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; }
/** 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; }