| /*++ | |
| Copyright (c) 2006, 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: | |
| BOT.c | |
| Abstract: | |
| --*/ | |
| #include "bot.h" | |
| GLOBAL_REMOVE_IF_UNREFERENCED UINT32 gBOTDebugLevel = EFI_D_INFO; | |
| GLOBAL_REMOVE_IF_UNREFERENCED UINT32 gBOTErrorLevel = EFI_D_INFO; | |
| EFI_DRIVER_BINDING_PROTOCOL gUsbBotDriverBinding = { | |
| BotDriverBindingSupported, | |
| BotDriverBindingStart, | |
| BotDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Bot Protocol | |
| // | |
| STATIC | |
| EFI_STATUS | |
| BotCommandPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| IN VOID *Command, | |
| IN UINT8 CommandSize, | |
| IN UINT32 DataTransferLength, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 Timeout | |
| ); | |
| STATIC | |
| EFI_STATUS | |
| BotDataPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| IN UINTN *DataSize, | |
| IN OUT VOID *DataBuffer, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 Timeout | |
| ); | |
| STATIC | |
| EFI_STATUS | |
| BotStatusPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| OUT UINT32 *DataResidue, | |
| IN UINT16 Timeout | |
| ); | |
| // | |
| // USB Atapi protocol prototype | |
| // | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| BotAtapiCommand ( | |
| IN EFI_USB_ATAPI_PROTOCOL *This, | |
| IN VOID *Command, | |
| IN UINT8 CommandSize, | |
| IN VOID *DataBuffer, | |
| IN UINT32 BufferLength, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 TimeOutInMilliSeconds | |
| ); | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| BotMassStorageReset ( | |
| IN EFI_USB_ATAPI_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ); | |
| STATIC | |
| VOID | |
| BotReportStatusCode ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN EFI_STATUS_CODE_TYPE CodeType, | |
| IN EFI_STATUS_CODE_VALUE Value | |
| ); | |
| STATIC EFI_USB_ATAPI_PROTOCOL BotAtapiProtocol = { | |
| BotAtapiCommand, | |
| BotMassStorageReset, | |
| 0 | |
| }; | |
| EFI_STATUS | |
| EFIAPI | |
| BotDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| /*++ | |
| Routine Description: | |
| Test to see if this driver supports ControllerHandle. Any ControllerHandle | |
| than contains a BlockIo and DiskIo protocol can be supported. | |
| Arguments: | |
| This - Protocol instance pointer. | |
| ControllerHandle - Handle of device to test | |
| RemainingDevicePath - Not used | |
| Returns: | |
| EFI_SUCCESS - This driver supports this device | |
| EFI_ALREADY_STARTED - This driver is already running on this device | |
| other - This driver does not support this device | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; | |
| // | |
| // Check if the Controller supports USB IO protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| (VOID **) &UsbIo, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Get the Default interface descriptor, now we only | |
| // suppose interface 1 | |
| // | |
| Status = UsbIo->UsbGetInterfaceDescriptor ( | |
| UsbIo, | |
| &InterfaceDescriptor | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| // | |
| // Check if it is a BOT type Mass Storage Device | |
| // | |
| if ((InterfaceDescriptor.InterfaceClass != MASS_STORAGE_CLASS) || | |
| (InterfaceDescriptor.InterfaceProtocol != BOT)) { | |
| Status = EFI_UNSUPPORTED; | |
| goto Exit; | |
| } | |
| Exit: | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| BotDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| /*++ | |
| Routine Description: | |
| Start this driver on ControllerHandle by opening a Block IO and Disk IO | |
| protocol, reading Device Path, and creating a child handle with a | |
| Disk IO and device path protocol. | |
| Arguments: | |
| This - Protocol instance pointer. | |
| ControllerHandle - Handle of device to bind driver to | |
| RemainingDevicePath - Not used | |
| Returns: | |
| EFI_SUCCESS - This driver is added to DeviceHandle | |
| EFI_ALREADY_STARTED - This driver is already running on DeviceHandle | |
| EFI_OUT_OF_RESOURCES- Can't allocate the memory resource | |
| other - This driver does not support this device | |
| --*/ | |
| { | |
| USB_BOT_DEVICE *UsbBotDev; | |
| UINT8 Index; | |
| EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; | |
| EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; | |
| EFI_STATUS Status; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| // | |
| // Check if the Controller supports USB IO protocol | |
| // | |
| UsbBotDev = NULL; | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| (VOID **) &UsbIo, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| InterfaceDescriptor = AllocateZeroPool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); | |
| if (InterfaceDescriptor == NULL) { | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Get the controller interface descriptor, | |
| // | |
| Status = UsbIo->UsbGetInterfaceDescriptor ( | |
| UsbIo, | |
| InterfaceDescriptor | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->FreePool (InterfaceDescriptor); | |
| goto ErrorExit; | |
| } | |
| BotAtapiProtocol.CommandProtocol = InterfaceDescriptor->InterfaceSubClass; | |
| UsbBotDev = AllocateZeroPool (sizeof (USB_BOT_DEVICE)); | |
| if (UsbBotDev == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| gBS->FreePool (InterfaceDescriptor); | |
| goto ErrorExit; | |
| } | |
| UsbBotDev->Signature = USB_BOT_DEVICE_SIGNATURE; | |
| UsbBotDev->UsbIo = UsbIo; | |
| UsbBotDev->InterfaceDescriptor = InterfaceDescriptor; | |
| CopyMem (&UsbBotDev->UsbAtapiProtocol, &BotAtapiProtocol, sizeof (BotAtapiProtocol)); | |
| // | |
| // Get the Device Path Protocol on Controller's handle | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &UsbBotDev->DevicePath, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ErrorExit; | |
| } | |
| for (Index = 0; Index < InterfaceDescriptor->NumEndpoints; Index++) { | |
| EndpointDescriptor = AllocatePool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); | |
| if (EndpointDescriptor == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto ErrorExit; | |
| } | |
| UsbIo->UsbGetEndpointDescriptor ( | |
| UsbIo, | |
| Index, | |
| EndpointDescriptor | |
| ); | |
| // | |
| // We parse bulk endpoint | |
| // | |
| if ((EndpointDescriptor->Attributes & 0x03) == 0x02) { | |
| if ((EndpointDescriptor->EndpointAddress & 0x80) != 0) { | |
| UsbBotDev->BulkInEndpointDescriptor = EndpointDescriptor; | |
| } else { | |
| UsbBotDev->BulkOutEndpointDescriptor = EndpointDescriptor; | |
| } | |
| continue; | |
| } | |
| gBS->FreePool (EndpointDescriptor); | |
| } | |
| // | |
| // Double check we have these endpoint descriptors | |
| // | |
| if (!(UsbBotDev->BulkInEndpointDescriptor && | |
| UsbBotDev->BulkOutEndpointDescriptor)) { | |
| Status = EFI_DEVICE_ERROR; | |
| goto ErrorExit; | |
| } | |
| // | |
| // After installing Usb-Atapi protocol onto this handle | |
| // it will be called by upper layer drivers such as Fat | |
| // | |
| BotReportStatusCode ( | |
| UsbBotDev->DevicePath, | |
| EFI_PROGRESS_CODE, | |
| (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) | |
| ); | |
| // | |
| // Install Usb-Atapi Protocol onto the handle | |
| // | |
| Status = gBS->InstallProtocolInterface ( | |
| &ControllerHandle, | |
| &gEfiUsbAtapiProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &UsbBotDev->UsbAtapiProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ErrorExit; | |
| } | |
| UsbBotDev->ControllerNameTable = NULL; | |
| AddUnicodeString ( | |
| "eng", | |
| gUsbBotComponentName.SupportedLanguages, | |
| &UsbBotDev->ControllerNameTable, | |
| (CHAR16 *) L"Usb Bot Mass Storage" | |
| ); | |
| return EFI_SUCCESS; | |
| ErrorExit: | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| if (UsbBotDev != NULL) { | |
| if (UsbBotDev->InterfaceDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->InterfaceDescriptor); | |
| } | |
| if (UsbBotDev->BulkInEndpointDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); | |
| } | |
| if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); | |
| } | |
| gBS->FreePool (UsbBotDev); | |
| } | |
| return Status; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| BotDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Stop this driver on ControllerHandle. Support stoping any child handles | |
| created by this driver. | |
| Arguments: | |
| This - Protocol instance pointer. | |
| ControllerHandle - Handle of device to stop driver on | |
| NumberOfChildren - Number of Children in the ChildHandleBuffer | |
| ChildHandleBuffer - List of handles for the children we need to stop. | |
| Returns: | |
| EFI_SUCCESS - This driver is removed DeviceHandle | |
| EFI_UNSUPPORTED - Can't open the gEfiUsbAtapiProtocolGuid protocl | |
| other - This driver was not removed from this device | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_USB_ATAPI_PROTOCOL *BotAtapiProtocol; | |
| USB_BOT_DEVICE *UsbBotDev; | |
| // | |
| // Get our context back. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbAtapiProtocolGuid, | |
| (VOID **) &BotAtapiProtocol, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| UsbBotDev = USB_BOT_DEVICE_FROM_THIS (BotAtapiProtocol); | |
| // | |
| // After installing Usb-Atapi protocol onto this handle | |
| // it will be called by upper layer drivers such as Fat | |
| // | |
| BotReportStatusCode ( | |
| UsbBotDev->DevicePath, | |
| EFI_PROGRESS_CODE, | |
| (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) | |
| ); | |
| // | |
| // Uninstall protocol | |
| // | |
| Status = gBS->UninstallProtocolInterface ( | |
| ControllerHandle, | |
| &gEfiUsbAtapiProtocolGuid, | |
| &UsbBotDev->UsbAtapiProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->CloseProtocol ( | |
| ControllerHandle, | |
| &gEfiUsbIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| // | |
| // Free all allocated resources | |
| // | |
| if (UsbBotDev->InterfaceDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->InterfaceDescriptor); | |
| } | |
| if (UsbBotDev->BulkInEndpointDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); | |
| } | |
| if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { | |
| gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); | |
| } | |
| if (UsbBotDev->ControllerNameTable) { | |
| FreeUnicodeStringTable (UsbBotDev->ControllerNameTable); | |
| } | |
| gBS->FreePool (UsbBotDev); | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| ClearBulkInPipe ( | |
| IN USB_BOT_DEVICE *UsbBotDev | |
| ) | |
| { | |
| UINT32 Result; | |
| return UsbClearEndpointHalt ( | |
| UsbBotDev->UsbIo, | |
| UsbBotDev->BulkInEndpointDescriptor->EndpointAddress, | |
| &Result | |
| ); | |
| } | |
| STATIC | |
| EFI_STATUS | |
| ClearBulkOutPipe ( | |
| IN USB_BOT_DEVICE *UsbBotDev | |
| ) | |
| { | |
| UINT32 Result; | |
| return UsbClearEndpointHalt ( | |
| UsbBotDev->UsbIo, | |
| UsbBotDev->BulkOutEndpointDescriptor->EndpointAddress, | |
| &Result | |
| ); | |
| } | |
| STATIC | |
| EFI_STATUS | |
| BotRecoveryReset ( | |
| IN USB_BOT_DEVICE *UsbBotDev | |
| ) | |
| /*++ | |
| Routine Description: | |
| Bot reset routine | |
| Arguments: | |
| UsbBotDev - USB_BOT_DEVICE pointer | |
| Returns: | |
| EFI_SUCCESS - Success the operation | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_USB_DEVICE_REQUEST Request; | |
| UINT32 Result; | |
| BotReportStatusCode ( | |
| UsbBotDev->DevicePath, | |
| EFI_PROGRESS_CODE, | |
| (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) | |
| ); | |
| ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); | |
| // | |
| // See BOT specification | |
| // | |
| Request.RequestType = 0x21; | |
| Request.Request = 0xFF; | |
| Status = UsbBotDev->UsbIo->UsbControlTransfer ( | |
| UsbBotDev->UsbIo, | |
| &Request, | |
| EfiUsbNoData, | |
| TIMEOUT_VALUE, | |
| NULL, | |
| 0, | |
| &Result | |
| ); | |
| gBS->Stall (100 * 1000); | |
| ClearBulkInPipe (UsbBotDev); | |
| ClearBulkOutPipe (UsbBotDev); | |
| return Status; | |
| } | |
| // | |
| // Bot Protocol Implementation | |
| // | |
| STATIC | |
| EFI_STATUS | |
| BotCommandPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| IN VOID *Command, | |
| IN UINT8 CommandSize, | |
| IN UINT32 DataTransferLength, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 Timeout | |
| ) | |
| /*++ | |
| Routine Description: | |
| Send ATAPI command through BOT interface. | |
| Parameters: | |
| UsbBotDev - USB_BOT_DEVICE | |
| Command - command packet | |
| CommandSize - Command size | |
| DataTransferLength - Data Transfer Length | |
| Direction - Data IN/OUT/NODATA | |
| Timeout - Time out value in milliseconds | |
| Return Values: | |
| EFI_SUCCESS | |
| Others | |
| --*/ | |
| { | |
| CBW cbw; | |
| EFI_STATUS Status; | |
| UINT32 Result; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| UINTN DataSize; | |
| UsbIo = UsbBotDev->UsbIo; | |
| ZeroMem (&cbw, sizeof (CBW)); | |
| // | |
| // Fill the command block, detailed see BOT spec | |
| // | |
| cbw.dCBWSignature = CBWSIG; | |
| cbw.dCBWTag = 0x01; | |
| cbw.dCBWDataTransferLength = DataTransferLength; | |
| cbw.bmCBWFlags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0); | |
| cbw.bCBWCBLength = CommandSize; | |
| CopyMem (cbw.CBWCB, Command, CommandSize); | |
| DataSize = sizeof (CBW); | |
| Status = UsbIo->UsbBulkTransfer ( | |
| UsbIo, | |
| UsbBotDev->BulkOutEndpointDescriptor->EndpointAddress, | |
| &cbw, | |
| &DataSize, | |
| Timeout, | |
| &Result | |
| ); | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| BotDataPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| IN UINTN *DataSize, | |
| IN OUT VOID *DataBuffer, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 Timeout | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get/Send Data through BOT interface | |
| Parameters: | |
| UsbBotDev - USB_BOT_DEVICE pointer | |
| DataSize - Data size | |
| DataBuffer - Data buffer pointer | |
| Direction - IN/OUT/NODATA | |
| Timeout - Time out value in milliseconds | |
| Return Value: | |
| EFI_SUCCESS | |
| Others | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT32 Result; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| UINT8 EndpointAddr; | |
| UINT8 *BufferPtr; | |
| UsbIo = UsbBotDev->UsbIo; | |
| BufferPtr = (UINT8 *) DataBuffer; | |
| // | |
| // retrieve the the max packet length of the given endpoint | |
| // | |
| if (Direction == EfiUsbDataIn) { | |
| EndpointAddr = UsbBotDev->BulkInEndpointDescriptor->EndpointAddress; | |
| } else { | |
| EndpointAddr = UsbBotDev->BulkOutEndpointDescriptor->EndpointAddress; | |
| } | |
| Status = UsbIo->UsbBulkTransfer ( | |
| UsbIo, | |
| EndpointAddr, | |
| BufferPtr, | |
| DataSize, | |
| (UINT16)(Timeout), | |
| &Result | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { | |
| if (Direction == EfiUsbDataIn) { | |
| DEBUG((gBOTErrorLevel, "BOT: Data IN Stall, ClearBulkInPipe\n")); | |
| ClearBulkInPipe (UsbBotDev); | |
| } else { | |
| DEBUG((gBOTErrorLevel, "BOT: Data OUT Stall, ClearBulkInPipe\n")); | |
| ClearBulkOutPipe (UsbBotDev); | |
| } | |
| } | |
| // BotRecoveryReset (UsbBotDev); | |
| } | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| BotStatusPhase ( | |
| IN USB_BOT_DEVICE *UsbBotDev, | |
| OUT UINT32 *DataResidue, | |
| IN UINT16 Timeout | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get transfer status through BOT interface | |
| Parameters: | |
| UsbBotDev - USB_BOT_DEVICE pointer | |
| Timeout - Time out value in milliseconds | |
| Return Value: | |
| EFI_SUCCESS | |
| Others | |
| --*/ | |
| { | |
| CSW csw; | |
| EFI_STATUS Status; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| UINT8 EndpointAddr; | |
| UINTN DataSize; | |
| UINT32 Result; | |
| UINT8 Index; | |
| UsbIo = UsbBotDev->UsbIo; | |
| EndpointAddr = UsbBotDev->BulkInEndpointDescriptor->EndpointAddress; | |
| for (Index = 0; Index < 3; Index ++) { | |
| ZeroMem (&csw, sizeof (CSW)); | |
| DataSize = sizeof (CSW); | |
| Result = 0; | |
| Status = UsbIo->UsbBulkTransfer ( | |
| UsbIo, | |
| EndpointAddr, | |
| &csw, | |
| &DataSize, | |
| Timeout, | |
| &Result | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { | |
| DEBUG((gBOTDebugLevel, "BOT: CSW Stall, ClearBulkInPipe\n")); | |
| ClearBulkInPipe (UsbBotDev); | |
| continue; | |
| } | |
| } | |
| if (csw.dCSWSignature == CSWSIG) { | |
| if (csw.bCSWStatus == 0 || csw.bCSWStatus == 0x01) { | |
| if (DataResidue != NULL) { | |
| *DataResidue = csw.dCSWDataResidue; | |
| } | |
| if (csw.bCSWStatus == 0x01) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| break; | |
| } else if (csw.bCSWStatus == 0x02) { | |
| DEBUG((gBOTErrorLevel, "BOT: Bot Phase error\n")); | |
| BotRecoveryReset (UsbBotDev); | |
| } | |
| } | |
| } | |
| if (Index == 3) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Usb Atapi Protocol implementation | |
| // | |
| EFI_STATUS | |
| EFIAPI | |
| BotAtapiCommand ( | |
| IN EFI_USB_ATAPI_PROTOCOL *This, | |
| IN VOID *Command, | |
| IN UINT8 CommandSize, | |
| IN VOID *DataBuffer, | |
| IN UINT32 BufferLength, | |
| IN EFI_USB_DATA_DIRECTION Direction, | |
| IN UINT16 TimeOutInMilliSeconds | |
| ) | |
| /*++ | |
| Routine Description: | |
| Send ATAPI command using BOT protocol. | |
| Arguments: | |
| This - Protocol instance pointer. | |
| Command - Command buffer | |
| CommandSize - Size of Command Buffer | |
| DataBuffer - Data buffer | |
| BufferLength - Length of Data buffer | |
| Direction - Data direction of this command | |
| TimeoutInMilliSeconds - Timeout value in ms | |
| Returns: | |
| EFI_SUCCESS - Command succeeded. | |
| EFI_DEVICE_ERROR - Command failed. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS BotDataStatus; | |
| USB_BOT_DEVICE *UsbBotDev; | |
| UINTN BufferSize; | |
| UINT8 Index; | |
| UINT32 DataResidue; | |
| // | |
| // Get the context | |
| // | |
| UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); | |
| BotDataStatus = EFI_SUCCESS; | |
| BufferSize = 0; | |
| for (Index = 0; Index < 3; Index ++) { | |
| // | |
| // First send ATAPI command through Bot | |
| // | |
| Status = BotCommandPhase ( | |
| UsbBotDev, | |
| Command, | |
| CommandSize, | |
| BufferLength, | |
| Direction, | |
| 10 * 1000 | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG((gBOTErrorLevel, "BotCommandPhase Fail\n")); | |
| return Status; | |
| } | |
| // | |
| // Send/Get Data if there is a Data Stage | |
| // | |
| switch (Direction) { | |
| case EfiUsbDataIn: | |
| case EfiUsbDataOut: | |
| BufferSize = BufferLength; | |
| BotDataStatus = BotDataPhase ( | |
| UsbBotDev, | |
| &BufferSize, | |
| DataBuffer, | |
| Direction, | |
| (UINT16) (TimeOutInMilliSeconds) | |
| ); | |
| if (EFI_ERROR (BotDataStatus)) { | |
| DEBUG((gBOTErrorLevel, "BotDataPhase Fail\n")); | |
| } | |
| break; | |
| case EfiUsbNoData: | |
| break; | |
| } | |
| DataResidue = 0; | |
| // | |
| // Status Phase | |
| // | |
| Status = BotStatusPhase ( | |
| UsbBotDev, | |
| &DataResidue, | |
| 10 * 1000 | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG((gBOTErrorLevel, "BotStatusPhase Fail\n")); | |
| return Status; | |
| } | |
| if (!EFI_ERROR (BotDataStatus)) { | |
| break; | |
| } | |
| } | |
| return BotDataStatus; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| BotMassStorageReset ( | |
| IN EFI_USB_ATAPI_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| /*++ | |
| Routine Description: | |
| Reset Bot Devices | |
| Arguments: | |
| This - Protocol instance pointer. | |
| ExtendedVerification - TRUE if we need to do strictly reset. | |
| Returns: | |
| EFI_SUCCESS - Command succeeded. | |
| EFI_DEVICE_ERROR - Command failed. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| USB_BOT_DEVICE *UsbBotDev; | |
| EFI_USB_IO_PROTOCOL *UsbIo; | |
| UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); | |
| UsbIo = UsbBotDev->UsbIo; | |
| if (ExtendedVerification) { | |
| // | |
| // If we need to do strictly reset, reset its parent hub port | |
| // | |
| Status = UsbIo->UsbPortReset (UsbIo); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| Status = BotRecoveryReset (UsbBotDev); | |
| return Status; | |
| } | |
| STATIC | |
| VOID | |
| BotReportStatusCode ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN EFI_STATUS_CODE_TYPE CodeType, | |
| IN EFI_STATUS_CODE_VALUE Value | |
| ) | |
| /*++ | |
| Routine Description: | |
| Report Status Code in Usb Bot Driver | |
| Arguments: | |
| DevicePath - Use this to get Device Path | |
| CodeType - Status Code Type | |
| CodeValue - Status Code Value | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| REPORT_STATUS_CODE_WITH_DEVICE_PATH ( | |
| CodeType, | |
| Value, | |
| DevicePath | |
| ); | |
| } |