]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBot.c
index 6c92da9c717d54fda7f4f2362f608c42cffc234b..98d2ba99688b5c4a610b1db5237ef56b73987245 100644 (file)
@@ -1,60 +1,44 @@
 /** @file\r
+  Implementation of the USB mass storage Bulk-Only Transport protocol,\r
+  according to USB Mass Storage Class Bulk-Only Transport, Revision 1.0.\r
 \r
-Copyright (c) 2007, Intel Corporation\r
-All rights reserved. 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
-\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
-  UsbMassBot.c\r
-\r
-Abstract:\r
-\r
-  Implementation of the USB mass storage Bulk-Only Transport protocol.\r
-\r
-Revision History\r
-\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "UsbMass.h"\r
-#include "UsbMassBot.h"\r
-\r
-UINTN mUsbBotInfo  = DEBUG_INFO;\r
-UINTN mUsbBotError = DEBUG_ERROR;\r
-\r
-STATIC\r
-EFI_STATUS\r
-UsbBotResetDevice (\r
-  IN  VOID                    *Context,\r
-  IN  BOOLEAN                  ExtendedVerification\r
-  );\r
 \r
+//\r
+// Definition of USB BOT Transport Protocol\r
+//\r
+USB_MASS_TRANSPORT mUsbBotTransport = {\r
+  USB_MASS_STORE_BOT,\r
+  UsbBotInit,\r
+  UsbBotExecCommand,\r
+  UsbBotResetDevice,\r
+  UsbBotGetMaxLun,\r
+  UsbBotCleanUp\r
+};\r
 \r
 /**\r
-  Initialize the USB mass storage class BOT transport protocol.\r
+  Initializes USB BOT protocol.\r
+\r
+  This function initializes the USB mass storage class BOT protocol.\r
   It will save its context which is a USB_BOT_PROTOCOL structure\r
   in the Context if Context isn't NULL.\r
 \r
-  @param  UsbIo                 The USB IO protocol to use\r
-  @param  Controller            The controller to init\r
-  @param  Context               The variable to save the context to\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_SUCCESS           The device is successfully initialized.\r
   @retval EFI_UNSUPPORTED       The transport protocol doesn't support the device.\r
-  @retval EFI_SUCCESS           The device is supported and protocol initialized.\r
+  @retval Other                 The USB BOT initialization fails.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbBotInit (\r
-  IN  EFI_USB_IO_PROTOCOL       * UsbIo,\r
-  IN  EFI_HANDLE                Controller,\r
+  IN  EFI_USB_IO_PROTOCOL       *UsbIo,\r
   OUT VOID                      **Context OPTIONAL\r
   )\r
 {\r
@@ -65,25 +49,20 @@ UsbBotInit (
   UINT8                         Index;\r
 \r
   //\r
-  // Allocate the BOT context, append two endpoint descriptors to it\r
+  // Allocate the BOT context for USB_BOT_PROTOCOL and two endpoint descriptors.\r
   //\r
-  UsbBot = AllocateZeroPool (\r
-             sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
-             );\r
-  if (UsbBot == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  UsbBot = AllocateZeroPool (sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));\r
+  ASSERT (UsbBot != NULL);\r
 \r
   UsbBot->UsbIo = UsbIo;\r
 \r
   //\r
   // Get the interface descriptor and validate that it\r
-  // is a USB MSC BOT interface.\r
+  // is a USB Mass Storage BOT interface.\r
   //\r
   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((mUsbBotError, "UsbBotInit: Get invalid BOT interface (%r)\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
@@ -115,57 +94,63 @@ UsbBotInit (
        (UsbBot->BulkOutEndpoint == NULL)) {\r
 \r
       UsbBot->BulkOutEndpoint   = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;\r
-      CopyMem(UsbBot->BulkOutEndpoint, &EndPoint, sizeof(EndPoint));\r
+      CopyMem (UsbBot->BulkOutEndpoint, &EndPoint, sizeof(EndPoint));\r
     }\r
   }\r
 \r
+  //\r
+  // If bulk-in or bulk-out endpoint is not found, report error.\r
+  //\r
   if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {\r
-    DEBUG ((mUsbBotError, "UsbBotInit: In/Out Endpoint invalid\n"));\r
     Status = EFI_UNSUPPORTED;\r
     goto ON_ERROR;\r
   }\r
 \r
   //\r
-  // The USB BOT protocol uses dCBWTag to match the CBW and CSW.\r
+  // The USB BOT protocol uses CBWTag to match the CBW and CSW.\r
   //\r
   UsbBot->CbwTag = 0x01;\r
 \r
   if (Context != NULL) {\r
     *Context = UsbBot;\r
   } else {\r
-    gBS->FreePool (UsbBot);\r
+    FreePool (UsbBot);\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  gBS->FreePool (UsbBot);\r
+  FreePool (UsbBot);\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Send the command to the device using Bulk-Out endpoint\r
+  Send the command to the device using Bulk-Out endpoint.\r
+\r
+  This function sends the command to the device using Bulk-Out endpoint.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Command phase.\r
 \r
   @param  UsbBot                The USB BOT device\r
   @param  Cmd                   The command to transfer to device\r
-  @param  CmdLen                the length of the command\r
+  @param  CmdLen                The length of the command\r
   @param  DataDir               The direction of the data\r
   @param  TransLen              The expected length of the data\r
+  @param  Lun                   The number of logic unit\r
 \r
-  @retval EFI_NOT_READY         The device return NAK to the transfer\r
   @retval EFI_SUCCESS           The command is sent to the device.\r
+  @retval EFI_NOT_READY         The device return NAK to the transfer\r
   @retval Others                Failed to send the command to device\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbBotSendCommand (\r
   IN USB_BOT_PROTOCOL         *UsbBot,\r
   IN UINT8                    *Cmd,\r
   IN UINT8                    CmdLen,\r
   IN EFI_USB_DATA_DIRECTION   DataDir,\r
-  IN UINT32                   TransLen\r
+  IN UINT32                   TransLen,\r
+  IN UINT8                    Lun\r
   )\r
 {\r
   USB_BOT_CBW               Cbw;\r
@@ -177,25 +162,24 @@ UsbBotSendCommand (
   ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));\r
 \r
   //\r
-  // Fill in the CSW. Only the first LUN is supported now.\r
+  // Fill in the Command Block Wrapper.\r
   //\r
   Cbw.Signature = USB_BOT_CBW_SIGNATURE;\r
   Cbw.Tag       = UsbBot->CbwTag;\r
   Cbw.DataLen   = TransLen;\r
-  Cbw.Flag      = (UINT8) ((DataDir == EfiUsbDataIn) ? 0x80 : 0);\r
-  Cbw.Lun       = 0;\r
+  Cbw.Flag      = (UINT8) ((DataDir == EfiUsbDataIn) ? BIT7 : 0);\r
+  Cbw.Lun       = Lun;\r
   Cbw.CmdLen    = CmdLen;\r
 \r
   ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);\r
   CopyMem (Cbw.CmdBlock, Cmd, CmdLen);\r
 \r
-  Result        = 0;\r
-  DataLen       = sizeof (USB_BOT_CBW);\r
-  Timeout       = USB_BOT_CBW_TIMEOUT / USB_MASS_STALL_1_MS;\r
+  Result  = 0;\r
+  DataLen = sizeof (USB_BOT_CBW);\r
+  Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND;\r
 \r
   //\r
-  // Use the UsbIo to send the command to the device. The default\r
-  // time out is enough.\r
+  // Use USB I/O Protocol to send the Command Block Wrapper to the device.\r
   //\r
   Status = UsbBot->UsbIo->UsbBulkTransfer (\r
                             UsbBot->UsbIo,\r
@@ -205,12 +189,12 @@ UsbBotSendCommand (
                             Timeout,\r
                             &Result\r
                             );\r
-  //\r
-  // Respond to Bulk-Out endpoint stall with a Reset Recovery,\r
-  // see the spec section 5.3.1\r
-  //\r
   if (EFI_ERROR (Status)) {\r
     if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {\r
+      //\r
+      // Respond to Bulk-Out endpoint stall with a Reset Recovery,\r
+      // according to section 5.3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.\r
+      //\r
       UsbBotResetDevice (UsbBot, FALSE);\r
     } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {\r
       Status = EFI_NOT_READY;\r
@@ -222,8 +206,11 @@ UsbBotSendCommand (
 \r
 \r
 /**\r
-  Transfer the data between the device and host. BOT transfer\r
-  is composed of three phase, command, data, and status.\r
+  Transfer the data between the device and host.\r
+\r
+  This function transfers the data between the device and host.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Data phase.\r
 \r
   @param  UsbBot                The USB BOT device\r
   @param  DataDir               The direction of the data\r
@@ -232,10 +219,11 @@ UsbBotSendCommand (
   @param  Timeout               The time to wait the command to complete\r
 \r
   @retval EFI_SUCCESS           The data is transferred\r
+  @retval EFI_SUCCESS           No data to transfer\r
+  @retval EFI_NOT_READY         The device return NAK to the transfer\r
   @retval Others                Failed to transfer data\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbBotDataTransfer (\r
   IN USB_BOT_PROTOCOL         *UsbBot,\r
@@ -250,7 +238,7 @@ UsbBotDataTransfer (
   UINT32                      Result;\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
@@ -266,7 +254,7 @@ UsbBotDataTransfer (
   }\r
 \r
   Result  = 0;\r
-  Timeout = Timeout / USB_MASS_STALL_1_MS;\r
+  Timeout = Timeout / USB_MASS_1_MILLISECOND;\r
 \r
   Status = UsbBot->UsbIo->UsbBulkTransfer (\r
                             UsbBot->UsbIo,\r
@@ -277,12 +265,17 @@ UsbBotDataTransfer (
                             &Result\r
                             );\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((mUsbBotError, "UsbBotDataTransfer: (%r)\n", Status));\r
     if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {\r
-      DEBUG ((mUsbBotError, "UsbBotDataTransfer: DataIn Stall\n"));\r
+      DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: (%r)\n", Status));\r
+      DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: DataIn Stall\n"));\r
       UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);\r
     } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {\r
       Status = EFI_NOT_READY;\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status));\r
+    }\r
+    if(Status == EFI_TIMEOUT){\r
+      UsbBotResetDevice(UsbBot, FALSE);\r
     }\r
   }\r
 \r
@@ -291,23 +284,24 @@ UsbBotDataTransfer (
 \r
 \r
 /**\r
-  Get the command execution status from device. BOT transfer is\r
-  composed of three phase, command, data, and status.\r
-  This function return the transfer status of the BOT's CSW status,\r
-  and return the high level command execution result in Result. So\r
-  even it returns EFI_SUCCESS, the command may still have failed.\r
+  Get the command execution status from device.\r
 \r
-  @param  UsbBot                The USB BOT device\r
-  @param  TransLen              The expected length of the data\r
-  @param  Timeout               The time to wait the command to complete\r
-  @param  CmdStatus             The result of the command execution.\r
+  This function gets the command execution status from device.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Status phase.\r
+\r
+  This function returns the transfer status of the BOT's CSW status,\r
+  and returns the high level command execution result in Result. So\r
+  even if EFI_SUCCESS is returned, the command may still have failed.\r
+\r
+  @param  UsbBot         The USB BOT device.\r
+  @param  TransLen       The expected length of the data.\r
+  @param  CmdStatus      The result of the command execution.\r
 \r
-  @retval EFI_DEVICE_ERROR      Failed to retrieve the command execute result\r
-  @retval EFI_SUCCESS           Command execute result is retrieved and in the\r
-                                Result.\r
+  @retval EFI_SUCCESS    Command execute result is retrieved and in the Result.\r
+  @retval Other          Error occurred when trying to get status.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbBotGetStatus (\r
   IN  USB_BOT_PROTOCOL      *UsbBot,\r
@@ -328,11 +322,11 @@ UsbBotGetStatus (
   Status     = EFI_DEVICE_ERROR;\r
   Endpoint   = UsbBot->BulkInEndpoint->EndpointAddress;\r
   UsbIo      = UsbBot->UsbIo;\r
-  Timeout    = USB_BOT_CSW_TIMEOUT / USB_MASS_STALL_1_MS;\r
+  Timeout    = USB_BOT_RECV_CSW_TIMEOUT / USB_MASS_1_MILLISECOND;\r
 \r
-  for (Index = 0; Index < USB_BOT_GET_STATUS_RETRY; Index++) {\r
+  for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) {\r
     //\r
-    // Attemp to the read CSW from bulk in endpoint\r
+    // Attemp to the read Command Status Wrapper from bulk in endpoint\r
     //\r
     ZeroMem (&Csw, sizeof (USB_BOT_CSW));\r
     Result = 0;\r
@@ -346,9 +340,7 @@ UsbBotGetStatus (
                       &Result\r
                       );\r
     if (EFI_ERROR(Status)) {\r
-      DEBUG ((mUsbBotError, "UsbBotGetStatus (%r)\n", Status));\r
       if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {\r
-        DEBUG ((mUsbBotError, "UsbBotGetStatus: DataIn Stall\n"));\r
         UsbClearEndpointStall (UsbIo, Endpoint);\r
       }\r
       continue;\r
@@ -356,24 +348,21 @@ UsbBotGetStatus (
 \r
     if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {\r
       //\r
-      // Invalid Csw need perform reset recovery\r
+      // CSW is invalid, so perform reset recovery\r
       //\r
-      DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a invalid signature\n"));\r
       Status = UsbBotResetDevice (UsbBot, FALSE);\r
     } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {\r
       //\r
-      // Respond phase error need perform reset recovery\r
+      // Respond phase error also needs reset recovery\r
       //\r
-      DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a phase error\n"));\r
       Status = UsbBotResetDevice (UsbBot, FALSE);\r
     } else {\r
-\r
       *CmdStatus = Csw.CmdStatus;\r
       break;\r
     }\r
   }\r
   //\r
-  //The tag is increased even there is an error.\r
+  //The tag is increased even if there is an error.\r
   //\r
   UsbBot->CbwTag++;\r
 \r
@@ -382,8 +371,8 @@ UsbBotGetStatus (
 \r
 \r
 /**\r
-  Call the Usb mass storage class transport protocol to issue\r
-  the command/data/status circle to execute the commands\r
+  Call the USB Mass Storage Class BOT protocol to issue\r
+  the command/data/status circle to execute the commands.\r
 \r
   @param  Context               The context of the BOT protocol, that is,\r
                                 USB_BOT_PROTOCOL\r
@@ -392,14 +381,14 @@ UsbBotGetStatus (
   @param  DataDir               The direction of the data transfer\r
   @param  Data                  The buffer to hold data\r
   @param  DataLen               The length of the data\r
+  @param  Lun                   The number of logic unit\r
   @param  Timeout               The time to wait command\r
   @param  CmdStatus             The result of high level command execution\r
 \r
-  @retval EFI_DEVICE_ERROR      Failed to excute command\r
-  @retval EFI_SUCCESS           The command is executed OK, and result in CmdStatus\r
+  @retval EFI_SUCCESS           The command is executed successfully.\r
+  @retval Other                 Failed to execute command\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbBotExecCommand (\r
   IN  VOID                    *Context,\r
@@ -408,6 +397,7 @@ UsbBotExecCommand (
   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
@@ -424,16 +414,16 @@ UsbBotExecCommand (
   // Send the command to the device. Return immediately if device\r
   // rejects the command.\r
   //\r
-  Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen);\r
+  Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen, Lun);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));\r
     return Status;\r
   }\r
 \r
   //\r
   // Transfer the data. Don't return immediately even data transfer\r
   // failed. The host should attempt to receive the CSW no matter\r
-  // whether it succeeds or failed.\r
+  // whether it succeeds or fails.\r
   //\r
   TransLen = (UINTN) DataLen;\r
   UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);\r
@@ -443,7 +433,7 @@ UsbBotExecCommand (
   //\r
   Status = UsbBotGetStatus (UsbBot, DataLen, &Result);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));\r
     return Status;\r
   }\r
 \r
@@ -456,20 +446,21 @@ UsbBotExecCommand (
 \r
 \r
 /**\r
-  Reset the mass storage device by BOT protocol\r
+  Reset the USB mass storage device by BOT protocol.\r
 \r
   @param  Context               The context of the BOT protocol, that is,\r
-                                USB_BOT_PROTOCOL\r
+                                USB_BOT_PROTOCOL.\r
+  @param  ExtendedVerification  If FALSE, just issue Bulk-Only Mass Storage Reset request.\r
+                                If TRUE, additionally reset parent hub port.\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
 UsbBotResetDevice (\r
   IN  VOID                    *Context,\r
-  IN  BOOLEAN                  ExtendedVerification\r
+  IN  BOOLEAN                 ExtendedVerification\r
   )\r
 {\r
   USB_BOT_PROTOCOL        *UsbBot;\r
@@ -486,20 +477,20 @@ UsbBotResetDevice (
     //\r
     Status = UsbBot->UsbIo->UsbPortReset (UsbBot->UsbIo);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      return EFI_DEVICE_ERROR;\r
     }\r
   }\r
 \r
   //\r
-  // Issue a class specific "Bulk-Only Mass Storage Reset reqest.\r
-  // See the spec section 3.1\r
+  // Issue a class specific Bulk-Only Mass Storage Reset request,\r
+  // according to section 3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.\r
   //\r
   Request.RequestType = 0x21;\r
   Request.Request     = USB_BOT_RESET_REQUEST;\r
   Request.Value       = 0;\r
   Request.Index       = UsbBot->Interface.InterfaceNumber;\r
   Request.Length      = 0;\r
-  Timeout             = USB_BOT_RESET_TIMEOUT / USB_MASS_STALL_1_MS;\r
+  Timeout             = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;\r
 \r
   Status = UsbBot->UsbIo->UsbControlTransfer (\r
                             UsbBot->UsbIo,\r
@@ -512,50 +503,105 @@ UsbBotResetDevice (
                             );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((mUsbBotError, "UsbBotResetDevice: (%r)\n", Status));\r
-    return Status;\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   //\r
   // The device shall NAK the host's request until the reset is\r
   // complete. We can use this to sync the device and host. For\r
-  // now just stall 100ms to wait the device.\r
+  // now just stall 100ms to wait for the device.\r
   //\r
-  gBS->Stall (USB_BOT_RESET_STALL);\r
+  gBS->Stall (USB_BOT_RESET_DEVICE_STALL);\r
 \r
   //\r
   // Clear the Bulk-In and Bulk-Out stall condition.\r
   //\r
   UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);\r
   UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);\r
+\r
   return Status;\r
 }\r
 \r
 \r
 /**\r
-  Clean up the resource used by this BOT protocol\r
+  Get the max LUN (Logical Unit Number) of USB mass storage device.\r
 \r
-  @param  Context               The context of the BOT protocol, that is,\r
-                                USB_BOT_PROTOCOL\r
+  @param  Context          The context of the BOT protocol, that is, USB_BOT_PROTOCOL\r
+  @param  MaxLun           Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and\r
+                           LUN1 in all.)\r
+\r
+  @retval EFI_SUCCESS      Max LUN is got successfully.\r
+  @retval Others           Fail to execute this request.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBotGetMaxLun (\r
+  IN  VOID                    *Context,\r
+  OUT UINT8                   *MaxLun\r
+  )\r
+{\r
+  USB_BOT_PROTOCOL        *UsbBot;\r
+  EFI_USB_DEVICE_REQUEST  Request;\r
+  EFI_STATUS              Status;\r
+  UINT32                  Result;\r
+  UINT32                  Timeout;\r
+\r
+  if (Context == NULL || MaxLun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UsbBot = (USB_BOT_PROTOCOL *) Context;\r
+\r
+  //\r
+  // Issue a class specific Bulk-Only Mass Storage get max lun reqest.\r
+  // according to section 3.2 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.\r
+  //\r
+  Request.RequestType = 0xA1;\r
+  Request.Request     = USB_BOT_GETLUN_REQUEST;\r
+  Request.Value       = 0;\r
+  Request.Index       = UsbBot->Interface.InterfaceNumber;\r
+  Request.Length      = 1;\r
+  Timeout             = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;\r
 \r
-  @retval EFI_SUCCESS           The resource is cleaned up.\r
+  Status = UsbBot->UsbIo->UsbControlTransfer (\r
+                            UsbBot->UsbIo,\r
+                            &Request,\r
+                            EfiUsbDataIn,\r
+                            Timeout,\r
+                            (VOID *) MaxLun,\r
+                            1,\r
+                            &Result\r
+                            );\r
+  if (EFI_ERROR (Status) || *MaxLun > USB_BOT_MAX_LUN) {\r
+    //\r
+    // If the Get LUN request returns an error or the MaxLun is larger than\r
+    // the maximum LUN value (0x0f) supported by the USB Mass Storage Class\r
+    // Bulk-Only Transport Spec, then set MaxLun to 0.\r
+    //\r
+    // This improves compatibility with USB FLASH drives that have a single LUN\r
+    // and either do not return a max LUN value or return an invalid maximum LUN\r
+    // value.\r
+    //\r
+    *MaxLun = 0;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Clean up the resource used by this BOT protocol.\r
+\r
+  @param  Context         The context of the BOT protocol, that is, USB_BOT_PROTOCOL.\r
+\r
+  @retval EFI_SUCCESS     The resource is cleaned up.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
-UsbBotFini (\r
+UsbBotCleanUp (\r
   IN  VOID                    *Context\r
   )\r
 {\r
-  gBS->FreePool (Context);\r
+  FreePool (Context);\r
   return EFI_SUCCESS;\r
 }\r
 \r
-USB_MASS_TRANSPORT\r
-mUsbBotTransport = {\r
-  USB_MASS_STORE_BOT,\r
-  UsbBotInit,\r
-  UsbBotExecCommand,\r
-  UsbBotResetDevice,\r
-  UsbBotFini\r
-};\r