/** @file\r
+ USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.\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
- UsbMassImpl.c\r
-\r
-Abstract:\r
-\r
- The implementation of USB mass storage class device driver.\r
- The command set supported is "USB Mass Storage Specification\r
- for Bootability".\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 "UsbMassImpl.h"\r
+#include "UsbMass.h"\r
\r
+#define USB_MASS_TRANSPORT_COUNT 3\r
//\r
-// The underlying transport protocol. CBI support isn't included\r
-// in the current build. It is being obseleted by the standard\r
-// body. If you want to enable it, remove the if directive here,\r
-// then add the UsbMassCbi.c/.h to the driver's inf file.\r
+// Array of USB transport interfaces.\r
//\r
-STATIC\r
-USB_MASS_TRANSPORT *mUsbMassTransport[] = {\r
+USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {\r
&mUsbCbi0Transport,\r
&mUsbCbi1Transport,\r
&mUsbBotTransport,\r
- NULL\r
};\r
\r
-UINTN mUsbMscInfo = DEBUG_INFO;\r
-UINTN mUsbMscError = DEBUG_ERROR;\r
-\r
+EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {\r
+ USBMassDriverBindingSupported,\r
+ USBMassDriverBindingStart,\r
+ USBMassDriverBindingStop,\r
+ 0x11,\r
+ NULL,\r
+ NULL\r
+};\r
\r
/**\r
- Retrieve the media parameters such as disk gemotric for the\r
- device's BLOCK IO protocol.\r
+ Reset the block device.\r
\r
- @param UsbMass The USB mass storage device\r
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().\r
+ It resets the block device hardware.\r
+ ExtendedVerification is ignored in this implementation.\r
\r
- @retval EFI_SUCCESS The media parameters is updated successfully.\r
- @retval Others Failed to get the media parameters.\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive\r
+ verification operation of the device during reset.\r
+\r
+ @retval EFI_SUCCESS The block device was reset.\r
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.\r
\r
**/\r
EFI_STATUS\r
-UsbMassInitMedia (\r
- IN USB_MASS_DEVICE *UsbMass\r
+EFIAPI\r
+UsbMassReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
)\r
{\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- EFI_STATUS Status;\r
- UINTN Index;\r
-\r
- Media = &UsbMass->BlockIoMedia;\r
-\r
- //\r
- // Initialize the MediaPrsent/ReadOnly and others to the default.\r
- // We are not forced to get it right at this time, check UEFI2.0\r
- // spec for more information:\r
- //\r
- // MediaPresent: This field shows the media present status as\r
- // of the most recent ReadBlocks or WriteBlocks call.\r
- //\r
- // ReadOnly : This field shows the read-only status as of the\r
- // recent WriteBlocks call.\r
- //\r
- // but remember to update MediaId/MediaPresent/ReadOnly status\r
- // after ReadBlocks and WriteBlocks\r
- //\r
- Media->MediaPresent = FALSE;\r
- Media->LogicalPartition = FALSE;\r
- Media->ReadOnly = FALSE;\r
- Media->WriteCaching = FALSE;\r
- Media->IoAlign = 0;\r
+ USB_MASS_DEVICE *UsbMass;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
\r
//\r
- // Some device may spend several seconds before it is ready.\r
- // Try several times before giving up. Wait 5s at most.\r
+ // Raise TPL to TPL_CALLBACK to serialize all its operations\r
+ // to protect shared data structures.\r
//\r
- Status = EFI_SUCCESS;\r
-\r
- for (Index = 0; Index < USB_BOOT_WAIT_RETRY; Index++) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
\r
- Status = UsbBootGetParams (UsbMass);\r
- if ((Status != EFI_MEDIA_CHANGED)\r
- && (Status != EFI_NOT_READY)\r
- && (Status != EFI_TIMEOUT)) {\r
- break;\r
- }\r
-\r
- Status = UsbBootIsUnitReady (UsbMass);\r
- if (EFI_ERROR (Status)) {\r
- gBS->Stall (USB_BOOT_UNIT_READY_STALL * (Index + 1));\r
- }\r
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);\r
+ Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);\r
\r
- }\r
+ gBS->RestoreTPL (OldTpl);\r
\r
return Status;\r
}\r
\r
-\r
-/**\r
- Reset the block device. ExtendedVerification is ignored for this.\r
-\r
- @param This The BLOCK IO protocol\r
- @param ExtendedVerification Whether to execute extended verfication.\r
-\r
- @retval EFI_SUCCESS The device is successfully resetted.\r
- @retval Others Failed to reset the device.\r
-\r
-**/\r
-EFI_STATUS\r
-UsbMassReset (\r
- IN EFI_BLOCK_IO_PROTOCOL *This,\r
- IN BOOLEAN ExtendedVerification\r
- )\r
-{\r
- USB_MASS_DEVICE *UsbMass;\r
-\r
- UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
- return UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);\r
-}\r
-\r
-\r
/**\r
- Read some blocks of data from the block device.\r
-\r
- @param This The Block IO protocol\r
- @param MediaId The media's ID of the device for current request\r
- @param Lba The start block number\r
- @param BufferSize The size of buffer to read data in\r
- @param Buffer The buffer to read data to\r
-\r
- @retval EFI_SUCCESS The data is successfully read\r
- @retval EFI_NO_MEDIA Media isn't present\r
- @retval EFI_MEDIA_CHANGED The device media has been changed, that is,\r
- MediaId changed\r
- @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is\r
- NULL.\r
- @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block\r
- size, or overflow the last block number.\r
+ Reads the requested number of blocks from the device.\r
+\r
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().\r
+ It reads the requested number of blocks from the device.\r
+ All the blocks are read, or an error is returned.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the read request is for.\r
+ @param Lba The starting logical block address to read from on the device.\r
+ @param BufferSize The size of the Buffer in bytes.\r
+ This must be a multiple of the intrinsic block size of the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
\r
**/\r
EFI_STATUS\r
+EFIAPI\r
UsbMassReadBlocks (\r
IN EFI_BLOCK_IO_PROTOCOL *This,\r
IN UINT32 MediaId,\r
USB_MASS_DEVICE *UsbMass;\r
EFI_BLOCK_IO_MEDIA *Media;\r
EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
UINTN TotalBlock;\r
\r
- UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
+ //\r
+ // Raise TPL to TPL_CALLBACK to serialize all its operations\r
+ // to protect shared data structures.\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);\r
Media = &UsbMass->BlockIoMedia;\r
\r
//\r
- // First, validate the parameters\r
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,\r
+ // need to detect the media before each read/write. While some of\r
+ // Usb-Flash is marked as removable media.\r
//\r
- if ((Buffer == NULL) || (BufferSize == 0)) {\r
- return EFI_INVALID_PARAMETER;\r
+ if (Media->RemovableMedia) {\r
+ Status = UsbBootDetectMedia (UsbMass);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
}\r
\r
- //\r
- // If it is a remoable media, such as CD-Rom or Usb-Floppy,\r
- // if, need to detect the media before each rw, while Usb-Flash\r
- // needn't. However, it's hard to identify Usb-Floppy between\r
- // Usb-Flash by now, so detect media every time.\r
- //\r
- Status = UsbBootDetectMedia (UsbMass);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));\r
- return Status;\r
+ if (!(Media->MediaPresent)) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
}\r
\r
//\r
- // Make sure BlockSize and LBA is consistent with BufferSize\r
+ // BufferSize must be a multiple of the intrinsic block size of the device.\r
//\r
if ((BufferSize % Media->BlockSize) != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto ON_EXIT;\r
}\r
\r
TotalBlock = BufferSize / Media->BlockSize;\r
\r
+ //\r
+ // Make sure the range to read is valid.\r
+ //\r
if (Lba + TotalBlock - 1 > Media->LastBlock) {\r
- return EFI_BAD_BUFFER_SIZE;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (UsbMass->Cdb16Byte) {\r
+ Status = UsbBootReadWriteBlocks16 (UsbMass, FALSE, Lba, TotalBlock, Buffer);\r
+ } else {\r
+ Status = UsbBootReadWriteBlocks (UsbMass, FALSE, (UINT32) Lba, TotalBlock, Buffer);\r
}\r
\r
- Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));\r
+ DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));\r
UsbMassReset (This, TRUE);\r
}\r
\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
return Status;\r
}\r
\r
\r
/**\r
- Write some blocks of data to the block device.\r
-\r
- @param This The Block IO protocol\r
- @param MediaId The media's ID of the device for current request\r
- @param Lba The start block number\r
- @param BufferSize The size of buffer to write data to\r
- @param Buffer The buffer to write data to\r
-\r
- @retval EFI_SUCCESS The data is successfully written\r
- @retval EFI_NO_MEDIA Media isn't present\r
- @retval EFI_MEDIA_CHANGED The device media has been changed, that is,\r
- MediaId changed\r
- @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is\r
- NULL.\r
- @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block\r
- size,\r
+ Writes a specified number of blocks to the device.\r
+\r
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().\r
+ It writes a specified number of blocks to the device.\r
+ All blocks are written, or an error is returned.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written.\r
+ @param BufferSize The size of the Buffer in bytes.\r
+ This must be a multiple of the intrinsic block size of the device.\r
+ @param Buffer Pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data were written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic\r
+ block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
\r
**/\r
EFI_STATUS\r
+EFIAPI\r
UsbMassWriteBlocks (\r
IN EFI_BLOCK_IO_PROTOCOL *This,\r
IN UINT32 MediaId,\r
USB_MASS_DEVICE *UsbMass;\r
EFI_BLOCK_IO_MEDIA *Media;\r
EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
UINTN TotalBlock;\r
\r
- UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
+ //\r
+ // Raise TPL to TPL_CALLBACK to serialize all its operations\r
+ // to protect shared data structures.\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);\r
Media = &UsbMass->BlockIoMedia;\r
\r
//\r
- // First, validate the parameters\r
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,\r
+ // need to detect the media before each read/write. Some of\r
+ // USB Flash is marked as removable media.\r
//\r
- if ((Buffer == NULL) || (BufferSize == 0)) {\r
- return EFI_INVALID_PARAMETER;\r
+ if (Media->RemovableMedia) {\r
+ Status = UsbBootDetectMedia (UsbMass);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
}\r
\r
- //\r
- // If it is a remoable media, such as CD-Rom or Usb-Floppy,\r
- // if, need to detect the media before each rw, while Usb-Flash\r
- // needn't. However, it's hard to identify Usb-Floppy between\r
- // Usb-Flash by now, so detect media every time.\r
- //\r
- Status = UsbBootDetectMedia (UsbMass);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));\r
- return Status;\r
+ if (!(Media->MediaPresent)) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
}\r
\r
//\r
- // Make sure BlockSize and LBA is consistent with BufferSize\r
+ // BufferSize must be a multiple of the intrinsic block size of the device.\r
//\r
if ((BufferSize % Media->BlockSize) != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto ON_EXIT;\r
}\r
\r
TotalBlock = BufferSize / Media->BlockSize;\r
\r
+ //\r
+ // Make sure the range to write is valid.\r
+ //\r
if (Lba + TotalBlock - 1 > Media->LastBlock) {\r
- return EFI_BAD_BUFFER_SIZE;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
}\r
\r
//\r
// Try to write the data even the device is marked as ReadOnly,\r
// and clear the status should the write succeed.\r
//\r
- Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);\r
+ if (UsbMass->Cdb16Byte) {\r
+ Status = UsbBootReadWriteBlocks16 (UsbMass, TRUE, Lba, TotalBlock, Buffer);\r
+ } else {\r
+ Status = UsbBootReadWriteBlocks (UsbMass, TRUE, (UINT32) Lba, TotalBlock, Buffer);\r
+ }\r
+\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));\r
+ DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));\r
UsbMassReset (This, TRUE);\r
}\r
\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
return Status;\r
}\r
\r
-\r
/**\r
- Flush the cached writes to disks. USB mass storage device doesn't\r
- support write cache, so return EFI_SUCCESS directly.\r
+ Flushes all modified data to a physical block device.\r
\r
- @param This The BLOCK IO protocol\r
+ This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().\r
+ USB mass storage device doesn't support write cache,\r
+ so return EFI_SUCCESS directly.\r
\r
- @retval EFI_SUCCESS Always returns success\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
\r
**/\r
EFI_STATUS\r
+EFIAPI\r
UsbMassFlushBlocks (\r
IN EFI_BLOCK_IO_PROTOCOL *This\r
)\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.\r
+\r
+ @param UsbMass The USB mass storage device\r
+\r
+ @retval EFI_SUCCESS The media parameters are updated successfully.\r
+ @retval Others Failed to get the media parameters.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbMassInitMedia (\r
+ IN USB_MASS_DEVICE *UsbMass\r
+ )\r
+{\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ EFI_STATUS Status;\r
+\r
+ Media = &UsbMass->BlockIoMedia;\r
+\r
+ //\r
+ // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,\r
+ // section for Block I/O Protocol.\r
+ //\r
+ Media->MediaPresent = FALSE;\r
+ Media->LogicalPartition = FALSE;\r
+ Media->ReadOnly = FALSE;\r
+ Media->WriteCaching = FALSE;\r
+ Media->IoAlign = 0;\r
+ Media->MediaId = 1;\r
+\r
+ Status = UsbBootGetParams (UsbMass);\r
+ DEBUG ((DEBUG_INFO, "UsbMassInitMedia: UsbBootGetParams (%r)\n", Status));\r
+ if (Status == EFI_MEDIA_CHANGED) {\r
+ //\r
+ // Some USB storage devices may report MEDIA_CHANGED sense key when hot-plugged.\r
+ // Treat it as SUCCESS\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
\r
/**\r
- Check whether the controller is a supported USB mass storage.\r
+ Initilize the USB Mass Storage transport.\r
\r
- @param This The USB mass driver's driver binding.\r
- @param Controller The device to test against.\r
- @param RemainingDevicePath The remaining device path\r
+ This function tries to find the matching USB Mass Storage transport\r
+ protocol for USB device. If found, initializes the matching transport.\r
\r
- @retval EFI_SUCCESS This device is a supported USB mass storage.\r
- @retval EFI_UNSUPPORTED The device isn't supported\r
- @retval Others Some error happened.\r
+ @param This The USB mass driver's driver binding.\r
+ @param Controller The device to test.\r
+ @param Transport The pointer to pointer to USB_MASS_TRANSPORT.\r
+ @param Context The parameter for USB_MASS_DEVICE.Context.\r
+ @param MaxLun Get the MaxLun if is BOT dev.\r
+\r
+ @retval EFI_SUCCESS The initialization is successful.\r
+ @retval EFI_UNSUPPORTED No matching transport protocol is found.\r
+ @retval Others Failed to initialize dev.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-USBMassDriverBindingSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+UsbMassInitTransport (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ OUT USB_MASS_TRANSPORT **Transport,\r
+ OUT VOID **Context,\r
+ OUT UINT8 *MaxLun\r
)\r
{\r
EFI_USB_IO_PROTOCOL *UsbIo;\r
EFI_USB_INTERFACE_DESCRIPTOR Interface;\r
- USB_MASS_TRANSPORT *Transport;\r
+ UINT8 Index;\r
EFI_STATUS Status;\r
- INTN Index;\r
\r
- //\r
- // Check whether the controlelr support USB_IO\r
- //\r
Status = gBS->OpenProtocol (\r
Controller,\r
&gEfiUsbIoProtocolGuid,\r
Controller,\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
);\r
+\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- //\r
- // Get the interface to check the USB class and find a transport\r
- // protocol handler.\r
- //\r
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);\r
if (EFI_ERROR (Status)) {\r
goto ON_EXIT;\r
\r
Status = EFI_UNSUPPORTED;\r
\r
- if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {\r
- goto ON_EXIT;\r
- }\r
+ //\r
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the\r
+ // matching transport protocol.\r
+ // If not found, return EFI_UNSUPPORTED.\r
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.\r
+ //\r
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {\r
+ *Transport = mUsbMassTransport[Index];\r
\r
- for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {\r
- Transport = mUsbMassTransport[Index];\r
- if (Interface.InterfaceProtocol == Transport->Protocol) {\r
- Status = Transport->Init (UsbIo, Controller, NULL);\r
+ if (Interface.InterfaceProtocol == (*Transport)->Protocol) {\r
+ Status = (*Transport)->Init (UsbIo, Context);\r
break;\r
}\r
}\r
\r
- DEBUG ((mUsbMscInfo, "Found a USB mass store device %r\n", Status));\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // For BOT device, try to get its max LUN.\r
+ // If max LUN is 0, then it is a non-lun device.\r
+ // Otherwise, it is a multi-lun device.\r
+ //\r
+ if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {\r
+ (*Transport)->GetMaxLun (*Context, MaxLun);\r
+ }\r
\r
ON_EXIT:\r
gBS->CloseProtocol (\r
- Controller,\r
- &gEfiUsbIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize data for device that supports multiple LUNSs.\r
+\r
+ @param This The Driver Binding Protocol instance.\r
+ @param Controller The device to initialize.\r
+ @param Transport Pointer to USB_MASS_TRANSPORT.\r
+ @param Context Parameter for USB_MASS_DEVICE.Context.\r
+ @param DevicePath The remaining device path.\r
+ @param MaxLun The max LUN number.\r
+\r
+ @retval EFI_SUCCESS At least one LUN is initialized successfully.\r
+ @retval EFI_NOT_FOUND Fail to initialize any of multiple LUNs.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbMassInitMultiLun (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN USB_MASS_TRANSPORT *Transport,\r
+ IN VOID *Context,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN UINT8 MaxLun\r
+ )\r
+{\r
+ USB_MASS_DEVICE *UsbMass;\r
+ EFI_USB_IO_PROTOCOL *UsbIo;\r
+ DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;\r
+ UINT8 Index;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS ReturnStatus;\r
+\r
+ ASSERT (MaxLun > 0);\r
+ ReturnStatus = EFI_NOT_FOUND;\r
+\r
+ for (Index = 0; Index <= MaxLun; Index++) {\r
+\r
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));\r
+\r
+ UsbIo = NULL;\r
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));\r
+ ASSERT (UsbMass != NULL);\r
+\r
+ UsbMass->Signature = USB_MASS_SIGNATURE;\r
+ UsbMass->UsbIo = UsbIo;\r
+ UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;\r
+ UsbMass->BlockIo.Reset = UsbMassReset;\r
+ UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;\r
+ UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;\r
+ UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;\r
+ UsbMass->OpticalStorage = FALSE;\r
+ UsbMass->Transport = Transport;\r
+ UsbMass->Context = Context;\r
+ UsbMass->Lun = Index;\r
+\r
+ //\r
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.\r
+ //\r
+ Status = UsbMassInitMedia (UsbMass);\r
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));\r
+ FreePool (UsbMass);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Create a device path node for device logic unit, and append it.\r
+ //\r
+ LunNode.Header.Type = MESSAGING_DEVICE_PATH;\r
+ LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;\r
+ LunNode.Lun = UsbMass->Lun;\r
+\r
+ SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));\r
+\r
+ UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);\r
+\r
+ if (UsbMass->DevicePath == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ FreePool (UsbMass);\r
+ continue;\r
+ }\r
+\r
+ InitializeDiskInfo (UsbMass);\r
+\r
+ //\r
+ // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &UsbMass->Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ UsbMass->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &UsbMass->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &UsbMass->DiskInfo,\r
+ NULL\r
+ );\r
\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));\r
+ FreePool (UsbMass->DevicePath);\r
+ FreePool (UsbMass);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Open USB I/O Protocol by child to setup a parent-child relationship.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ (VOID **) &UsbIo,\r
+ This->DriverBindingHandle,\r
+ UsbMass->Controller,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &UsbMass->Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ UsbMass->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &UsbMass->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &UsbMass->DiskInfo,\r
+ NULL\r
+ );\r
+ FreePool (UsbMass->DevicePath);\r
+ FreePool (UsbMass);\r
+ continue;\r
+ }\r
+ ReturnStatus = EFI_SUCCESS;\r
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));\r
+ }\r
+\r
+ return ReturnStatus;\r
+}\r
+\r
+/**\r
+ Initialize data for device that does not support multiple LUNSs.\r
+\r
+ @param This The Driver Binding Protocol instance.\r
+ @param Controller The device to initialize.\r
+ @param Transport Pointer to USB_MASS_TRANSPORT.\r
+ @param Context Parameter for USB_MASS_DEVICE.Context.\r
+\r
+ @retval EFI_SUCCESS Initialization succeeds.\r
+ @retval Other Initialization fails.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbMassInitNonLun (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN USB_MASS_TRANSPORT *Transport,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ USB_MASS_DEVICE *UsbMass;\r
+ EFI_USB_IO_PROTOCOL *UsbIo;\r
+ EFI_STATUS Status;\r
+\r
+ UsbIo = NULL;\r
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));\r
+ ASSERT (UsbMass != NULL);\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ (VOID **) &UsbIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ UsbMass->Signature = USB_MASS_SIGNATURE;\r
+ UsbMass->Controller = Controller;\r
+ UsbMass->UsbIo = UsbIo;\r
+ UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;\r
+ UsbMass->BlockIo.Reset = UsbMassReset;\r
+ UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;\r
+ UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;\r
+ UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;\r
+ UsbMass->OpticalStorage = FALSE;\r
+ UsbMass->Transport = Transport;\r
+ UsbMass->Context = Context;\r
+\r
+ //\r
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.\r
+ //\r
+ Status = UsbMassInitMedia (UsbMass);\r
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {\r
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ InitializeDiskInfo (UsbMass);\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &UsbMass->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &UsbMass->DiskInfo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ if (UsbMass != NULL) {\r
+ FreePool (UsbMass);\r
+ }\r
+ if (UsbIo != NULL) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
return Status;\r
}\r
\r
\r
/**\r
- Start the USB mass storage device on the controller. It will\r
- install a BLOCK_IO protocol on the device if everything is OK.\r
+ Check whether the controller is a supported USB mass storage.\r
\r
- @param This The USB mass storage driver binding.\r
- @param Controller The USB mass storage device to start on\r
+ @param This The USB mass storage driver binding protocol.\r
+ @param Controller The controller handle to check.\r
@param RemainingDevicePath The remaining device path.\r
\r
- @retval EFI_SUCCESS The driver has started on the device.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory\r
- @retval Others Failed to start the driver on the device.\r
+ @retval EFI_SUCCESS The driver supports this controller.\r
+ @retval other This device isn't supported.\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-USBMassDriverBindingStart (\r
+USBMassDriverBindingSupported (\r
IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
IN EFI_HANDLE Controller,\r
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
{\r
EFI_USB_IO_PROTOCOL *UsbIo;\r
EFI_USB_INTERFACE_DESCRIPTOR Interface;\r
- USB_MASS_DEVICE *UsbMass;\r
USB_MASS_TRANSPORT *Transport;\r
EFI_STATUS Status;\r
UINTN Index;\r
Controller,\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
);\r
-\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));\r
- if (UsbMass == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
//\r
- // Initialize the transport protocols\r
+ // Get the interface descriptor to check the USB class and find a transport\r
+ // protocol handler.\r
//\r
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));\r
- goto ON_ERROR;\r
+ goto ON_EXIT;\r
}\r
\r
Status = EFI_UNSUPPORTED;\r
\r
- for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {\r
- Transport = mUsbMassTransport[Index];\r
+ if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {\r
+ goto ON_EXIT;\r
+ }\r
\r
+ //\r
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the\r
+ // matching transport method.\r
+ // If not found, return EFI_UNSUPPORTED.\r
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.\r
+ //\r
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {\r
+ Transport = mUsbMassTransport[Index];\r
if (Interface.InterfaceProtocol == Transport->Protocol) {\r
- UsbMass->Transport = Transport;\r
- Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);\r
+ Status = Transport->Init (UsbIo, NULL);\r
break;\r
}\r
}\r
\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));\r
- goto ON_ERROR;\r
- }\r
+ON_EXIT:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
\r
- UsbMass->Signature = USB_MASS_SIGNATURE;\r
- UsbMass->Controller = Controller;\r
- UsbMass->UsbIo = UsbIo;\r
- UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;\r
- UsbMass->BlockIo.Reset = UsbMassReset;\r
- UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;\r
- UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;\r
- UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;\r
- UsbMass->OpticalStorage = FALSE;\r
+ return Status;\r
+}\r
\r
- //\r
- // Get the storage's parameters, such as last block number.\r
- // then install the BLOCK_IO\r
- //\r
- Status = UsbMassInitMedia (UsbMass);\r
- if (!EFI_ERROR (Status)) {\r
- if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&\r
- (UsbMass->Pdt != USB_PDT_CDROM) &&\r
- (UsbMass->Pdt != USB_PDT_OPTICAL) &&\r
- (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {\r
- DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));\r
- goto ON_ERROR;\r
- }\r
- } else if (Status != EFI_NO_MEDIA){\r
- DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));\r
- goto ON_ERROR;\r
- }\r
+/**\r
+ Starts the USB mass storage device with this driver.\r
+\r
+ This function consumes USB I/O Portocol, intializes USB mass storage device,\r
+ installs Block I/O Protocol, and submits Asynchronous Interrupt\r
+ Transfer to manage the USB mass storage device.\r
+\r
+ @param This The USB mass storage driver binding protocol.\r
+ @param Controller The USB mass storage device to start on\r
+ @param RemainingDevicePath The remaining device path.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_ALREADY_STARTED This driver has been started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+USBMassDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ USB_MASS_TRANSPORT *Transport;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ VOID *Context;\r
+ UINT8 MaxLun;\r
+ EFI_STATUS Status;\r
+ EFI_USB_IO_PROTOCOL *UsbIo;\r
+ EFI_TPL OldTpl;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Transport = NULL;\r
+ Context = NULL;\r
+ MaxLun = 0;\r
+\r
+ Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);\r
\r
- Status = gBS->InstallProtocolInterface (\r
- &Controller,\r
- &gEfiBlockIoProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &UsbMass->BlockIo\r
- );\r
if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));\r
+ goto Exit;\r
}\r
+ if (MaxLun == 0) {\r
+ //\r
+ // Initialize data for device that does not support multiple LUNSs.\r
+ //\r
+ Status = UsbMassInitNonLun (This, Controller, Transport, Context);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));\r
+ }\r
+ } else {\r
+ //\r
+ // Open device path to prepare for appending Device Logic Unit node.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
\r
- return EFI_SUCCESS;\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));\r
+ goto Exit;\r
+ }\r
\r
-ON_ERROR:\r
- gBS->FreePool (UsbMass);\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ (VOID **) &UsbIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiUsbIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ goto Exit;\r
+ }\r
\r
+ //\r
+ // Initialize data for device that supports multiple LUNs.\r
+ // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.\r
+ //\r
+ Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));\r
+ }\r
+ }\r
+Exit:\r
+ gBS->RestoreTPL (OldTpl);\r
return Status;\r
}\r
\r
@param ChildHandleBuffer The buffer of children handle.\r
\r
@retval EFI_SUCCESS The driver stopped from controlling the device.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+ @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.\r
@retval Others Failed to stop the driver\r
\r
**/\r
{\r
EFI_STATUS Status;\r
USB_MASS_DEVICE *UsbMass;\r
+ EFI_USB_IO_PROTOCOL *UsbIo;\r
EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ UINTN Index;\r
+ BOOLEAN AllChildrenStopped;\r
\r
//\r
- // First, get our context back from the BLOCK_IO\r
+ // This is a bus driver stop function since multi-lun is supported.\r
+ // There are three kinds of device handles that might be passed:\r
+ // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)\r
+ // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)\r
+ // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).\r
//\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlockIo,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // A handle without any children, might be 1st and 2nd type.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // This is a 2nd type handle(multi-lun root), it needs to close devicepath\r
+ // and usbio protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ //\r
+ // This is a 1st type handle(non-multi-lun), which only needs to uninstall\r
+ // Block I/O Protocol, close USB I/O Protocol and free mass device.\r
+ //\r
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);\r
+\r
+ //\r
+ // Uninstall Block I/O protocol from the device handle,\r
+ // then call the transport protocol to stop itself.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &UsbMass->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &UsbMass->DiskInfo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
\r
- UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);\r
+ UsbMass->Transport->CleanUp (UsbMass->Context);\r
+ FreePool (UsbMass);\r
+\r
+ DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
\r
//\r
- // Uninstall Block I/O protocol from the device handle,\r
- // then call the transport protocol to stop itself.\r
+ // This is a 3rd type handle(multi-lun), which needs uninstall\r
+ // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and\r
+ // free mass device for all children.\r
//\r
- Status = gBS->UninstallProtocolInterface (\r
- Controller,\r
- &gEfiBlockIoProtocolGuid,\r
- &UsbMass->BlockIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));\r
+ continue;\r
+ }\r
\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiUsbIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ UsbMass->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &UsbMass->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &UsbMass->DiskInfo,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.\r
+ //\r
+ AllChildrenStopped = FALSE;\r
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));\r
+\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbIoProtocolGuid,\r
+ (VOID **) &UsbIo,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ //\r
+ // Succeed to stop this multi-lun handle, so go on with next child.\r
+ //\r
+ if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {\r
+ UsbMass->Transport->CleanUp (UsbMass->Context);\r
+ }\r
+ FreePool (UsbMass);\r
+ }\r
+ }\r
\r
- UsbMass->Transport->Fini (UsbMass->Context);\r
- gBS->FreePool (UsbMass);\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
+ DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));\r
return EFI_SUCCESS;\r
}\r
\r
-EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {\r
- USBMassDriverBindingSupported,\r
- USBMassDriverBindingStart,\r
- USBMassDriverBindingStop,\r
- 0x11,\r
- NULL,\r
- NULL\r
-};\r
+/**\r
+ Entrypoint of USB Mass Storage Driver.\r
+\r
+ This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding\r
+ Protocol together with Component Name Protocols.\r
\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
USBMassStorageEntryPoint (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
-/*++\r
-\r
-Routine Description:\r
-\r
- The entry point for the driver, which will install the driver binding and\r
- component name protocol\r
-\r
-Arguments:\r
-\r
- ImageHandle - The image handle of this driver\r
- SystemTable - The system table\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - the protocols are installed OK\r
- Others - Failed to install protocols.\r
-\r
---*/\r
{\r
EFI_STATUS Status;\r
\r
&gUsbMassStorageComponentName,\r
&gUsbMassStorageComponentName2\r
);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r