/** @file\r
+ Implementation of the USB mass storage Control/Bulk/Interrupt transport,\r
+ according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.\r
+ Notice: it is being obsoleted by the standard body in favor of the BOT\r
+ (Bulk-Only Transport).\r
\r
-Copyright (c) 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
-Module Name:\r
-\r
- UsbMassCbi.c\r
-\r
-Abstract:\r
-\r
- Implementation of the USB mass storage Control/Bulk/Interrupt transpor.\r
- Notice: it is being obseleted by the standard body in favor of the BOT\r
- (Bulk-Only Transport).\r
-\r
-Revision History\r
-\r
-\r
**/\r
\r
-#include "UsbMass.h"\r
+#include "UsbMassBoot.h"\r
#include "UsbMassCbi.h"\r
\r
-STATIC\r
-EFI_STATUS\r
-UsbCbiResetDevice (\r
- IN VOID *Context,\r
- IN BOOLEAN ExtendedVerification\r
- );\r
+//\r
+// Definition of USB CBI0 Transport Protocol\r
+//\r
+USB_MASS_TRANSPORT mUsbCbi0Transport = {\r
+ USB_MASS_STORE_CBI0,\r
+ UsbCbiInit,\r
+ UsbCbiExecCommand,\r
+ UsbCbiResetDevice,\r
+ NULL,\r
+ UsbCbiCleanUp\r
+};\r
\r
+//\r
+// Definition of USB CBI1 Transport Protocol\r
+//\r
+USB_MASS_TRANSPORT mUsbCbi1Transport = {\r
+ USB_MASS_STORE_CBI1,\r
+ UsbCbiInit,\r
+ UsbCbiExecCommand,\r
+ UsbCbiResetDevice,\r
+ NULL,\r
+ UsbCbiCleanUp\r
+};\r
\r
/**\r
- Initialize the USB mass storage class CBI transport protocol.\r
- If Context isn't NULL, it will save its context in it.\r
+ Initializes USB CBI protocol.\r
+\r
+ This function initializes the USB mass storage class CBI protocol.\r
+ It will save its context which is a USB_CBI_PROTOCOL structure\r
+ in the Context if Context isn't NULL.\r
\r
- @param UsbIo The USB IO to use\r
- @param Controller The device controller\r
- @param Context The variable to save context in\r
+ @param UsbIo The USB I/O Protocol instance\r
+ @param Context The buffer to save the context to\r
\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory\r
- @retval EFI_UNSUPPORTED The device isn't supported\r
- @retval EFI_SUCCESS The CBI protocol is initialized.\r
+ @retval EFI_SUCCESS The device is successfully initialized.\r
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.\r
+ @retval Other The USB CBI initialization fails.\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiInit (\r
IN EFI_USB_IO_PROTOCOL *UsbIo,\r
- IN EFI_HANDLE Controller,\r
OUT VOID **Context OPTIONAL\r
)\r
{\r
UINT8 Index;\r
\r
//\r
- // Allocate the CBI context\r
+ // Allocate the CBI context for USB_CBI_PROTOCOL and 3 endpoint descriptors.\r
//\r
UsbCbi = AllocateZeroPool (\r
sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
);\r
-\r
- if (UsbCbi == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ ASSERT (UsbCbi != NULL);\r
\r
UsbCbi->UsbIo = UsbIo;\r
\r
//\r
- // Get the interface descriptor and validate that it is a USB mass\r
- // storage class CBI interface.\r
+ // Get the interface descriptor and validate that it\r
+ // is a USB Mass Storage CBI interface.\r
//\r
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);\r
if (EFI_ERROR (Status)) {\r
UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;\r
CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint));\r
}\r
-\r
} else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {\r
//\r
// Use the first interrupt endpoint if it is CBI0\r
}\r
}\r
\r
- if ((UsbCbi->BulkInEndpoint == NULL)\r
- || (UsbCbi->BulkOutEndpoint == NULL)\r
- || ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0)\r
- && (UsbCbi->InterruptEndpoint == NULL))) {\r
+ if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_ERROR;\r
+ }\r
+ if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) {\r
Status = EFI_UNSUPPORTED;\r
goto ON_ERROR;\r
}\r
if (Context != NULL) {\r
*Context = UsbCbi;\r
} else {\r
- gBS->FreePool (UsbCbi);\r
+ FreePool (UsbCbi);\r
}\r
+ \r
return EFI_SUCCESS;\r
\r
ON_ERROR:\r
- gBS->FreePool (UsbCbi);\r
+ FreePool (UsbCbi);\r
return Status;\r
}\r
\r
-\r
-\r
/**\r
Send the command to the device using class specific control transfer.\r
\r
+ This function sends command to the device using class specific control transfer.\r
+ The CBI contains three phases: Command, Data, and Status. This is Command phase.\r
+\r
@param UsbCbi The USB CBI protocol\r
@param Cmd The high level command to transfer to device\r
@param CmdLen The length of the command\r
@param Timeout The time to wait the command to finish\r
\r
- @retval EFI_SUCCESS The command is transferred to device\r
+ @retval EFI_SUCCESS The command is sent to the device.\r
@retval Others The command failed to transfer to device\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiSendCommand (\r
IN USB_CBI_PROTOCOL *UsbCbi,\r
\r
//\r
// Fill in the device request, CBI use the "Accept Device-Specific\r
- // Cmd" (ADSC) class specific request to send commands\r
+ // Cmd" (ADSC) class specific request to send commands.\r
//\r
Request.RequestType = 0x21;\r
Request.Request = 0;\r
\r
for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {\r
//\r
- // Use the UsbIo to send the command to the device\r
+ // Use USB I/O Protocol to send the command to the device\r
//\r
TransStatus = 0;\r
DataLen = CmdLen;\r
\r
\r
/**\r
- Transfer data between the device and host. The CBI contains three phase,\r
- command, data, and status. This is data phase.\r
+ Transfer data between the device and host.\r
+\r
+ This function transfers data between the device and host.\r
+ The CBI contains three phases: Command, Data, and Status. This is Data phase.\r
\r
@param UsbCbi The USB CBI device\r
@param DataDir The direction of the data transfer\r
- @param Data The buffer to hold the data\r
- @param TransLen The expected transfer length\r
- @param Timeout The time to wait the command to execute\r
+ @param Data The buffer to hold the data for input or output.\r
+ @param TransLen On input, the expected transfer length.\r
+ On output, the length of data actually transferred.\r
+ @param Timeout The time to wait for the command to execute\r
\r
- @retval EFI_SUCCESS The data transfer succeeded\r
+ @retval EFI_SUCCESS The data transferred successfully.\r
+ @retval EFI_SUCCESS No data to transfer\r
@retval Others Failed to transfer all the data\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiDataTransfer (\r
IN USB_CBI_PROTOCOL *UsbCbi,\r
UINTN Retry;\r
\r
//\r
- // It's OK if no data to transfer\r
+ // If no data to transfer, just return EFI_SUCCESS.\r
//\r
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {\r
return EFI_SUCCESS;\r
Timeout = Timeout / USB_MASS_1_MILLISECOND;\r
\r
//\r
- // Transfer the data, if the device returns NAK, retry it.\r
+ // Transfer the data with a loop. The length of data transferred once is restricted.\r
//\r
while (Remain > 0) {\r
TransStatus = 0;\r
if (TransStatus == EFI_USB_ERR_NAK) {\r
//\r
// The device can NAK the host if either the data/buffer isn't\r
- // aviable or the command is in-progress. The data can be partly\r
- // transferred. The transfer is aborted if several succssive data\r
- // transfer commands are NAKed.\r
+ // aviable or the command is in-progress.\r
+ // If data are partially transferred, we just ignore NAK and continue.\r
+ // If all data have been transferred and status is NAK, then we retry for several times.\r
+ // If retry exceeds the USB_CBI_MAX_RETRY, then return error status.\r
//\r
if (Increment == 0) {\r
if (++Retry > USB_CBI_MAX_RETRY) {\r
goto ON_EXIT;\r
}\r
-\r
} else {\r
Next += Increment;\r
Remain -= Increment;\r
\r
\r
/**\r
- Get the result of high level command execution from interrupt\r
- endpoint. This function returns the USB transfer status, and\r
- put the high level command execution result in Result.\r
+ Gets the result of high level command execution from interrupt endpoint.\r
+\r
+ This function returns the USB transfer status, and put the high level\r
+ command execution result in Result.\r
+ The CBI contains three phases: Command, Data, and Status. This is Status phase.\r
\r
@param UsbCbi The USB CBI protocol\r
- @param Timeout The time to wait the command to execute\r
- @param Result GC_TODO: add argument description\r
+ @param Timeout The time to wait for the command to execute\r
+ @param Result The result of the command execution.\r
\r
@retval EFI_SUCCESS The high level command execution result is\r
retrieved in Result.\r
@retval Others Failed to retrieve the result.\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiGetStatus (\r
IN USB_CBI_PROTOCOL *UsbCbi,\r
\r
\r
/**\r
- Execute USB mass storage command through the CBI0/CBI1 transport protocol\r
+ Execute USB mass storage command through the CBI0/CBI1 transport protocol.\r
\r
- @param Context The USB CBI device\r
+ @param Context The USB CBI Protocol.\r
@param Cmd The command to transfer to device\r
@param CmdLen The length of the command\r
@param DataDir The direction of data transfer\r
@param Data The buffer to hold the data\r
@param DataLen The length of the buffer\r
+ @param Lun Should be 0, this field for bot only\r
@param Timeout The time to wait\r
@param CmdStatus The result of the command execution\r
\r
- @retval EFI_SUCCESS The command is executed OK and result in CmdStatus.\r
- @retval EFI_DEVICE_ERROR Failed to execute the command\r
+ @retval EFI_SUCCESS The command is executed successfully.\r
+ @retval Other Failed to execute the command\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiExecCommand (\r
IN VOID *Context,\r
IN EFI_USB_DATA_DIRECTION DataDir,\r
IN VOID *Data,\r
IN UINT32 DataLen,\r
+ IN UINT8 Lun,\r
IN UINT32 Timeout,\r
OUT UINT32 *CmdStatus\r
)\r
//\r
Status = UsbCbiSendCommand (UsbCbi, Cmd, CmdLen, Timeout);\r
if (EFI_ERROR (Status)) {\r
+ gBS->Stall(10 * USB_MASS_1_MILLISECOND);\r
DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status));\r
return Status;\r
}\r
\r
//\r
- // Transfer the data, return this status if no interrupt endpoint\r
+ // Transfer the data. Return this status if no interrupt endpoint\r
// is used to report the transfer status.\r
//\r
TransLen = (UINTN) DataLen;\r
}\r
\r
//\r
- // Get the status, if that succeeds, interpret the result\r
+ // Get the status. If it succeeds, interpret the result.\r
//\r
Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));\r
- return EFI_DEVICE_ERROR;\r
+ return Status;\r
}\r
\r
if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {\r
//\r
// For UFI device, ASC and ASCQ are returned.\r
//\r
- if (Result.Type != 0) {\r
+ // Do not set the USB_MASS_CMD_FAIL for a request sense command\r
+ // as a bad result type doesn't mean a cmd failure\r
+ //\r
+ if (Result.Type != 0 && *(UINT8*)Cmd != 0x03) {\r
*CmdStatus = USB_MASS_CMD_FAIL;\r
}\r
-\r
} else {\r
//\r
// Check page 27, CBI spec 1.1 for vaious reture status.\r
\r
case 0x02:\r
//\r
- // Phase Error, response with reset. Fall through to Fail.\r
+ // Phase Error, response with reset.\r
+ // No break here to fall through to "Fail".\r
//\r
UsbCbiResetDevice (UsbCbi, FALSE);\r
\r
\r
case 0x03:\r
//\r
- // Persistent Fail, need to send REQUEST SENSE.\r
+ // Persistent Fail. Need to send REQUEST SENSE.\r
//\r
*CmdStatus = USB_MASS_CMD_PERSISTENT;\r
break;\r
\r
\r
/**\r
- Call the Usb mass storage class transport protocol to\r
- reset the device. The reset is defined as a Non-Data\r
- command. Don't use UsbCbiExecCommand to send the command\r
- to device because that may introduce recursive loop.\r
+ Reset the USB mass storage device by CBI protocol.\r
+\r
+ This function resets the USB mass storage device by CBI protocol.\r
+ The reset is defined as a non-data command. Don't use UsbCbiExecCommand\r
+ to send the command to device because that may introduce recursive loop.\r
\r
- @param Context The USB CBI device protocol\r
+ @param Context The USB CBI protocol\r
+ @param ExtendedVerification The flag controlling the rule of reset.\r
+ Not used here.\r
\r
- @retval EFI_SUCCESS the device is reset\r
- @retval Others Failed to reset the device\r
+ @retval EFI_SUCCESS The device is reset.\r
+ @retval Others Failed to reset the device.\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
UsbCbiResetDevice (\r
IN VOID *Context,\r
\r
//\r
// Just retrieve the status and ignore that. Then stall\r
- // 50ms to wait it complete\r
+ // 50ms to wait for it to complete.\r
//\r
UsbCbiGetStatus (UsbCbi, Timeout, &Result);\r
gBS->Stall (USB_CBI_RESET_DEVICE_STALL);\r
\r
//\r
- // Clear the Bulk-In and Bulk-Out stall condition and\r
- // init data toggle.\r
+ // Clear the Bulk-In and Bulk-Out stall condition and init data toggle.\r
//\r
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);\r
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);\r
+\r
return Status;\r
}\r
\r
\r
/**\r
- Clean up the CBI protocol's resource\r
+ Clean up the CBI protocol's resource.\r
\r
- @param Context The CBI protocol\r
+ @param Context The instance of CBI protocol.\r
\r
@retval EFI_SUCCESS The resource is cleaned up.\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
-UsbCbiFini (\r
+UsbCbiCleanUp (\r
IN VOID *Context\r
)\r
{\r
- gBS->FreePool (Context);\r
+ FreePool (Context);\r
return EFI_SUCCESS;\r
}\r
-\r
-USB_MASS_TRANSPORT\r
-mUsbCbi0Transport = {\r
- USB_MASS_STORE_CBI0,\r
- UsbCbiInit,\r
- UsbCbiExecCommand,\r
- UsbCbiResetDevice,\r
- UsbCbiFini\r
-};\r
-\r
-USB_MASS_TRANSPORT\r
-mUsbCbi1Transport = {\r
- USB_MASS_STORE_CBI1,\r
- UsbCbiInit,\r
- UsbCbiExecCommand,\r
- UsbCbiResetDevice,\r
- UsbCbiFini\r
-};\r