git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9119 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1133 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1133 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
 | |
| 
 | |
| Copyright (c) 2007 - 2008, 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "UsbMassImpl.h"
 | |
| 
 | |
| #define USB_MASS_TRANSPORT_COUNT    3
 | |
| //
 | |
| // Array of USB transport interfaces. 
 | |
| //
 | |
| USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
 | |
|   &mUsbCbi0Transport,
 | |
|   &mUsbCbi1Transport,
 | |
|   &mUsbBotTransport,
 | |
| };
 | |
| 
 | |
| EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
 | |
|   USBMassDriverBindingSupported,
 | |
|   USBMassDriverBindingStart,
 | |
|   USBMassDriverBindingStop,
 | |
|   0x11,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Reset the block device.
 | |
| 
 | |
|   This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). 
 | |
|   It resets the block device hardware.
 | |
|   ExtendedVerification is ignored in this implementation.
 | |
| 
 | |
|   @param  This                   Indicates a pointer to the calling context.
 | |
|   @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive
 | |
|                                  verification operation of the device during reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The block device was reset.
 | |
|   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and could not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UsbMassReset (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL    *This,
 | |
|   IN BOOLEAN                  ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   USB_MASS_DEVICE *UsbMass;
 | |
|   EFI_TPL         OldTpl;
 | |
|   EFI_STATUS      Status;
 | |
| 
 | |
|   //
 | |
|   // Raise TPL to TPL_NOTIFY to serialize all its operations
 | |
|   // to protect shared data structures.
 | |
|   //
 | |
|   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
 | |
|   Status  = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads the requested number of blocks from the device.
 | |
| 
 | |
|   This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). 
 | |
|   It reads the requested number of blocks from the device.
 | |
|   All the blocks are read, or an error is returned.
 | |
| 
 | |
|   @param  This                   Indicates a pointer to the calling context.
 | |
|   @param  MediaId                The media ID that the read request is for.
 | |
|   @param  Lba                    The starting logical block address to read from on the device.
 | |
|   @param  BufferSize             The size of the Buffer in bytes.
 | |
|                                  This must be a multiple of the intrinsic block size of the device.
 | |
|   @param  Buffer                 A pointer to the destination buffer for the data. The caller is
 | |
|                                  responsible for either having implicit or explicit ownership of the buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The data was read correctly from the device.
 | |
|   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the read operation.
 | |
|   @retval EFI_NO_MEDIA           There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
 | |
|   @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
 | |
|                                  or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UsbMassReadBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL    *This,
 | |
|   IN UINT32                   MediaId,
 | |
|   IN EFI_LBA                  Lba,
 | |
|   IN UINTN                    BufferSize,
 | |
|   OUT VOID                    *Buffer
 | |
|   )
 | |
| {
 | |
|   USB_MASS_DEVICE     *UsbMass;
 | |
|   EFI_BLOCK_IO_MEDIA  *Media;
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_TPL             OldTpl;
 | |
|   UINTN               TotalBlock;
 | |
| 
 | |
|   //
 | |
|   // First, validate the parameters
 | |
|   //
 | |
|   if ((Buffer == NULL) || (BufferSize == 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Raise TPL to TPL_NOTIFY to serialize all its operations
 | |
|   // to protect shared data structures.
 | |
|   //
 | |
|   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
 | |
|   Media   = &UsbMass->BlockIoMedia;
 | |
| 
 | |
|   //
 | |
|   // If it is a removable media, such as CD-Rom or Usb-Floppy,
 | |
|   // need to detect the media before each read/write. While some of
 | |
|   // Usb-Flash is marked as removable media.
 | |
|   //
 | |
|   if (Media->RemovableMedia) {
 | |
|     Status = UsbBootDetectMedia (UsbMass);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // BufferSize must be a multiple of the intrinsic block size of the device.
 | |
|   //
 | |
|   if ((BufferSize % Media->BlockSize) != 0) {
 | |
|     Status = EFI_BAD_BUFFER_SIZE;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   TotalBlock = BufferSize / Media->BlockSize;
 | |
| 
 | |
|   //
 | |
|   // Make sure the range to read is valid.
 | |
|   //
 | |
|   if (Lba + TotalBlock - 1 > Media->LastBlock) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (!(Media->MediaPresent)) {
 | |
|     Status = EFI_NO_MEDIA;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     Status = EFI_MEDIA_CHANGED;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
 | |
|     UsbMassReset (This, TRUE);
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Writes a specified number of blocks to the device.
 | |
| 
 | |
|   This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). 
 | |
|   It writes a specified number of blocks to the device.
 | |
|   All blocks are written, or an error is returned.
 | |
| 
 | |
|   @param  This                   Indicates a pointer to the calling context.
 | |
|   @param  MediaId                The media ID that the write request is for.
 | |
|   @param  Lba                    The starting logical block address to be written.
 | |
|   @param  BufferSize             The size of the Buffer in bytes.
 | |
|                                  This must be a multiple of the intrinsic block size of the device.
 | |
|   @param  Buffer                 Pointer to the source buffer for the data.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The data were written correctly to the device.
 | |
|   @retval EFI_WRITE_PROTECTED    The device cannot be written to.
 | |
|   @retval EFI_NO_MEDIA           There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
 | |
|   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the write operation.
 | |
|   @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic
 | |
|                                  block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid,
 | |
|                                  or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UsbMassWriteBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL    *This,
 | |
|   IN UINT32                   MediaId,
 | |
|   IN EFI_LBA                  Lba,
 | |
|   IN UINTN                    BufferSize,
 | |
|   IN VOID                     *Buffer
 | |
|   )
 | |
| {
 | |
|   USB_MASS_DEVICE     *UsbMass;
 | |
|   EFI_BLOCK_IO_MEDIA  *Media;
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_TPL             OldTpl;
 | |
|   UINTN               TotalBlock;
 | |
| 
 | |
|   //
 | |
|   // First, validate the parameters
 | |
|   //
 | |
|   if ((Buffer == NULL) || (BufferSize == 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Raise TPL to TPL_NOTIFY to serialize all its operations
 | |
|   // to protect shared data structures.
 | |
|   //
 | |
|   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
 | |
|   Media   = &UsbMass->BlockIoMedia;
 | |
| 
 | |
|   //
 | |
|   // If it is a removable media, such as CD-Rom or Usb-Floppy,
 | |
|   // need to detect the media before each read/write. Some of
 | |
|   // USB Flash is marked as removable media.
 | |
|   //
 | |
|   if (Media->RemovableMedia) {
 | |
|     Status = UsbBootDetectMedia (UsbMass);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // BufferSize must be a multiple of the intrinsic block size of the device.
 | |
|   //
 | |
|   if ((BufferSize % Media->BlockSize) != 0) {
 | |
|     Status = EFI_BAD_BUFFER_SIZE;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   TotalBlock = BufferSize / Media->BlockSize;
 | |
| 
 | |
|   //
 | |
|   // Make sure the range to write is valid.
 | |
|   //
 | |
|   if (Lba + TotalBlock - 1 > Media->LastBlock) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (!(Media->MediaPresent)) {
 | |
|     Status = EFI_NO_MEDIA;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     Status = EFI_MEDIA_CHANGED;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try to write the data even the device is marked as ReadOnly,
 | |
|   // and clear the status should the write succeed.
 | |
|   //
 | |
|   Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
 | |
|     UsbMassReset (This, TRUE);
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flushes all modified data to a physical block device.
 | |
| 
 | |
|   This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
 | |
|   USB mass storage device doesn't support write cache,
 | |
|   so return EFI_SUCCESS directly.
 | |
| 
 | |
|   @param  This                   Indicates a pointer to the calling context.
 | |
| 
 | |
|   @retval EFI_SUCCESS            All outstanding data were written correctly to the device.
 | |
|   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to write data.
 | |
|   @retval EFI_NO_MEDIA           There is no media in the device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UsbMassFlushBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
 | |
| 
 | |
|   @param  UsbMass                The USB mass storage device
 | |
| 
 | |
|   @retval EFI_SUCCESS            The media parameters are updated successfully.
 | |
|   @retval Others                 Failed to get the media parameters.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbMassInitMedia (
 | |
|   IN USB_MASS_DEVICE          *UsbMass
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA          *Media;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINTN                       Index;
 | |
| 
 | |
|   Media = &UsbMass->BlockIoMedia;
 | |
| 
 | |
|   //
 | |
|   // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
 | |
|   // section for Block I/O Protocol.
 | |
|   //
 | |
|   Media->MediaPresent     = FALSE;
 | |
|   Media->LogicalPartition = FALSE;
 | |
|   Media->ReadOnly         = FALSE;
 | |
|   Media->WriteCaching     = FALSE;
 | |
|   Media->IoAlign          = 0;
 | |
|   Media->MediaId          = 1;
 | |
| 
 | |
|   //
 | |
|   // Some device may spend several seconds before it is ready.
 | |
|   // Try several times before giving up. Wait 5s at most.
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
 | |
| 
 | |
|     Status = UsbBootGetParams (UsbMass);
 | |
|     if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_NOT_READY) && (Status != EFI_TIMEOUT)) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Status = UsbBootIsUnitReady (UsbMass);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initilize the USB Mass Storage transport.
 | |
| 
 | |
|   This function tries to find the matching USB Mass Storage transport
 | |
|   protocol for USB device. If found, initializes the matching transport.
 | |
| 
 | |
|   @param  This            The USB mass driver's driver binding.
 | |
|   @param  Controller      The device to test.
 | |
|   @param  Transport       The pointer to pointer to USB_MASS_TRANSPORT.
 | |
|   @param  Context         The parameter for USB_MASS_DEVICE.Context.
 | |
|   @param  MaxLun          Get the MaxLun if is BOT dev.
 | |
| 
 | |
|   @retval EFI_SUCCESS     The initialization is successful.
 | |
|   @retval EFI_UNSUPPORTED No matching transport protocol is found.
 | |
|   @retval Others          Failed to initialize dev.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbMassInitTransport (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN  EFI_HANDLE                   Controller,
 | |
|   OUT USB_MASS_TRANSPORT           **Transport,
 | |
|   OUT VOID                         **Context,
 | |
|   OUT UINT8                        *MaxLun
 | |
|   )
 | |
| {
 | |
|   EFI_USB_IO_PROTOCOL           *UsbIo;
 | |
|   EFI_USB_INTERFACE_DESCRIPTOR  Interface;
 | |
|   UINT8                         Index;
 | |
|   EFI_STATUS                    Status;
 | |
|  
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiUsbIoProtocolGuid,
 | |
|                   (VOID **) &UsbIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   
 | |
|   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
|   
 | |
|   Status = EFI_UNSUPPORTED;
 | |
| 
 | |
|   //
 | |
|   // Traverse the USB_MASS_TRANSPORT arrary and try to find the
 | |
|   // matching transport protocol.
 | |
|   // If not found, return EFI_UNSUPPORTED.
 | |
|   // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
 | |
|   //
 | |
|   for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
 | |
|     *Transport = mUsbMassTransport[Index];
 | |
| 
 | |
|     if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
 | |
|       Status  = (*Transport)->Init (UsbIo, Context);
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // For BOT device, try to get its max LUN. 
 | |
|   // If max LUN is 0, then it is a non-lun device.
 | |
|   // Otherwise, it is a multi-lun device.
 | |
|   //
 | |
|   if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
 | |
|     (*Transport)->GetMaxLun (*Context, MaxLun);
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiUsbIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
|   return Status;  
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize data for device that supports multiple LUNSs.
 | |
| 
 | |
|   @param  This                 The Driver Binding Protocol instance.
 | |
|   @param  Controller           The device to initialize.
 | |
|   @param  Transport            Pointer to USB_MASS_TRANSPORT.
 | |
|   @param  Context              Parameter for USB_MASS_DEVICE.Context.
 | |
|   @param  DevicePath           The remaining device path.
 | |
|   @param  MaxLun               The max LUN number.
 | |
| 
 | |
|   @retval EFI_SUCCESS          At least one LUN is initialized successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES Out of resource while creating device path node.
 | |
|   @retval Other                Initialization fails.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbMassInitMultiLun (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN EFI_HANDLE                    Controller,
 | |
|   IN USB_MASS_TRANSPORT            *Transport,
 | |
|   IN VOID                          *Context,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
 | |
|   IN UINT8                         MaxLun
 | |
|   )
 | |
| {
 | |
|   USB_MASS_DEVICE                  *UsbMass;
 | |
|   EFI_USB_IO_PROTOCOL              *UsbIo;
 | |
|   DEVICE_LOGICAL_UNIT_DEVICE_PATH  LunNode;
 | |
|   UINT8                            Index;
 | |
|   EFI_STATUS                       Status;
 | |
| 
 | |
|   ASSERT (MaxLun > 0);
 | |
| 
 | |
|   for (Index = 0; Index <= MaxLun; Index++) { 
 | |
| 
 | |
|     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
 | |
|     
 | |
|     UsbIo   = NULL;
 | |
|     UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
 | |
|     ASSERT (UsbMass != NULL);
 | |
|       
 | |
|     UsbMass->Signature            = USB_MASS_SIGNATURE;
 | |
|     UsbMass->UsbIo                = UsbIo;
 | |
|     UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
 | |
|     UsbMass->BlockIo.Reset        = UsbMassReset;
 | |
|     UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
 | |
|     UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
 | |
|     UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
 | |
|     UsbMass->OpticalStorage       = FALSE;
 | |
|     UsbMass->Transport            = Transport;
 | |
|     UsbMass->Context              = Context;
 | |
|     UsbMass->Lun                  = Index;
 | |
|     
 | |
|     //
 | |
|     // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
 | |
|     //
 | |
|     Status = UsbMassInitMedia (UsbMass);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // According to USB Mass Storage Specification for Bootability, only following
 | |
|       // 4 Peripheral Device Types are in spec.
 | |
|       //
 | |
|       if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) && 
 | |
|            (UsbMass->Pdt != USB_PDT_CDROM) &&
 | |
|            (UsbMass->Pdt != USB_PDT_OPTICAL) && 
 | |
|            (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
 | |
|         DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
 | |
|         goto ON_ERROR;
 | |
|       }
 | |
|     } else if (Status != EFI_NO_MEDIA){
 | |
|       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Create a device path node for device logic unit, and append it.
 | |
|     //
 | |
|     LunNode.Header.Type    = MESSAGING_DEVICE_PATH;
 | |
|     LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
 | |
|     LunNode.Lun            = UsbMass->Lun;
 | |
|   
 | |
|     SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
 | |
|   
 | |
|     UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
 | |
|   
 | |
|     if (UsbMass->DevicePath == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
 | |
|   
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
 | |
|     //
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &UsbMass->Controller,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     UsbMass->DevicePath,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     &UsbMass->BlockIo,
 | |
|                     NULL
 | |
|                     );
 | |
|     
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Open USB I/O Protocol by child to setup a parent-child relationship.
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiUsbIoProtocolGuid,
 | |
|                     (VOID **) &UsbIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     UsbMass->Controller,
 | |
|                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                     );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
 | |
|       gBS->UninstallMultipleProtocolInterfaces (
 | |
|              &UsbMass->Controller,
 | |
|              &gEfiDevicePathProtocolGuid,
 | |
|              UsbMass->DevicePath,
 | |
|              &gEfiBlockIoProtocolGuid,
 | |
|              &UsbMass->BlockIo,
 | |
|              NULL
 | |
|              );
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
|     
 | |
|     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ON_ERROR:
 | |
|   if (UsbMass != NULL) {
 | |
|     if (UsbMass->DevicePath != NULL) {
 | |
|       FreePool (UsbMass->DevicePath);
 | |
|     }
 | |
|     FreePool (UsbMass);
 | |
|   }
 | |
|   if (UsbIo != NULL) {
 | |
|     gBS->CloseProtocol (
 | |
|            Controller,
 | |
|            &gEfiUsbIoProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            UsbMass->Controller
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Return EFI_SUCCESS if at least one LUN is initialized successfully.
 | |
|   //
 | |
|   if (Index > 0) {
 | |
|     return EFI_SUCCESS; 
 | |
|   } else {
 | |
|     return Status;
 | |
|   } 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize data for device that does not support multiple LUNSs.
 | |
| 
 | |
|   @param  This            The Driver Binding Protocol instance.
 | |
|   @param  Controller      The device to initialize.
 | |
|   @param  Transport       Pointer to USB_MASS_TRANSPORT.
 | |
|   @param  Context         Parameter for USB_MASS_DEVICE.Context.
 | |
| 
 | |
|   @retval EFI_SUCCESS     Initialization succeeds.
 | |
|   @retval Other           Initialization fails.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbMassInitNonLun (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN EFI_HANDLE                    Controller,
 | |
|   IN USB_MASS_TRANSPORT            *Transport,
 | |
|   IN VOID                          *Context
 | |
|   )
 | |
| {
 | |
|   USB_MASS_DEVICE             *UsbMass;
 | |
|   EFI_USB_IO_PROTOCOL         *UsbIo;
 | |
|   EFI_STATUS                  Status;
 | |
| 
 | |
|   UsbIo   = NULL;
 | |
|   UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
 | |
|   ASSERT (UsbMass != NULL);
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiUsbIoProtocolGuid,
 | |
|                   (VOID **) &UsbIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
|   
 | |
|   UsbMass->Signature            = USB_MASS_SIGNATURE;
 | |
|   UsbMass->Controller           = Controller;
 | |
|   UsbMass->UsbIo                = UsbIo;
 | |
|   UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
 | |
|   UsbMass->BlockIo.Reset        = UsbMassReset;
 | |
|   UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
 | |
|   UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
 | |
|   UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
 | |
|   UsbMass->OpticalStorage       = FALSE;
 | |
|   UsbMass->Transport            = Transport;
 | |
|   UsbMass->Context              = Context;
 | |
|   
 | |
|   //
 | |
|   // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
 | |
|   //
 | |
|   Status = UsbMassInitMedia (UsbMass);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // According to USB Mass Storage Specification for Bootability, only following
 | |
|     // 4 Peripheral Device Types are in spec.
 | |
|     //
 | |
|     if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) && 
 | |
|          (UsbMass->Pdt != USB_PDT_CDROM) &&
 | |
|          (UsbMass->Pdt != USB_PDT_OPTICAL) && 
 | |
|          (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
 | |
|       DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
|   } else if (Status != EFI_NO_MEDIA){
 | |
|     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
|     
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &Controller,
 | |
|                   &gEfiBlockIoProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &UsbMass->BlockIo
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ON_ERROR:
 | |
|   if (UsbMass != NULL) {
 | |
|     FreePool (UsbMass);
 | |
|   }
 | |
|   if (UsbIo != NULL) {
 | |
|     gBS->CloseProtocol (
 | |
|            Controller,
 | |
|            &gEfiUsbIoProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            Controller
 | |
|            );
 | |
|   }
 | |
|   return Status;  
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check whether the controller is a supported USB mass storage.
 | |
| 
 | |
|   @param  This                   The USB mass storage driver binding protocol.
 | |
|   @param  Controller             The controller handle to check.
 | |
|   @param  RemainingDevicePath    The remaining device path.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The driver supports this controller.
 | |
|   @retval other                  This device isn't supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| USBMassDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_USB_IO_PROTOCOL           *UsbIo;
 | |
|   EFI_USB_INTERFACE_DESCRIPTOR  Interface;
 | |
|   USB_MASS_TRANSPORT            *Transport;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         Index;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiUsbIoProtocolGuid,
 | |
|                   (VOID **) &UsbIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the interface descriptor to check the USB class and find a transport
 | |
|   // protocol handler.
 | |
|   //
 | |
|   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_UNSUPPORTED;
 | |
| 
 | |
|   if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Traverse the USB_MASS_TRANSPORT arrary and try to find the
 | |
|   // matching transport method.
 | |
|   // If not found, return EFI_UNSUPPORTED.
 | |
|   // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
 | |
|   //
 | |
|   for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
 | |
|     Transport = mUsbMassTransport[Index];
 | |
|     if (Interface.InterfaceProtocol == Transport->Protocol) {
 | |
|       Status = Transport->Init (UsbIo, NULL);
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiUsbIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Starts the USB mass storage device with this driver.
 | |
| 
 | |
|   This function consumes USB I/O Portocol, intializes USB mass storage device,
 | |
|   installs Block I/O Protocol, and submits Asynchronous Interrupt
 | |
|   Transfer to manage the USB mass storage device.
 | |
| 
 | |
|   @param  This                  The USB mass storage driver binding protocol.
 | |
|   @param  Controller            The USB mass storage device to start on
 | |
|   @param  RemainingDevicePath   The remaining device path.
 | |
| 
 | |
|   @retval EFI_SUCCESS           This driver supports this device.
 | |
|   @retval EFI_UNSUPPORTED       This driver does not support this device.
 | |
|   @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
 | |
|   @retval EFI_ALREADY_STARTED   This driver has been started.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| USBMassDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   USB_MASS_TRANSPORT            *Transport;
 | |
|   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
 | |
|   VOID                          *Context;
 | |
|   UINT8                         MaxLun;
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_USB_IO_PROTOCOL           *UsbIo; 
 | |
|   
 | |
|   Transport = NULL;
 | |
|   Context   = NULL;
 | |
|   MaxLun    = 0;
 | |
| 
 | |
|   Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
|   if (MaxLun == 0) {
 | |
|     //
 | |
|     // Initialize data for device that does not support multiple LUNSs.
 | |
|     //
 | |
|     Status = UsbMassInitNonLun (This, Controller, Transport, Context);
 | |
|     if (EFI_ERROR (Status)) { 
 | |
|       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Open device path to prepare for appending Device Logic Unit node.
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     (VOID **) &DevicePath,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Controller,
 | |
|                     EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                     );
 | |
|   
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiUsbIoProtocolGuid,
 | |
|                     (VOID **) &UsbIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Controller,
 | |
|                     EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                     );
 | |
|   
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
 | |
|       gBS->CloseProtocol (
 | |
|              Controller,
 | |
|              &gEfiDevicePathProtocolGuid,
 | |
|              This->DriverBindingHandle,
 | |
|              Controller
 | |
|              );
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Initialize data for device that supports multiple LUNSs.
 | |
|     // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
 | |
|     //
 | |
|     Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->CloseProtocol (
 | |
|               Controller,
 | |
|               &gEfiDevicePathProtocolGuid,
 | |
|               This->DriverBindingHandle,
 | |
|               Controller
 | |
|               );
 | |
|       gBS->CloseProtocol (
 | |
|               Controller,
 | |
|               &gEfiUsbIoProtocolGuid,
 | |
|               This->DriverBindingHandle,
 | |
|               Controller
 | |
|               );
 | |
|       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
 | |
|     }
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop controlling the device.
 | |
| 
 | |
|   @param  This                   The USB mass storage driver binding
 | |
|   @param  Controller             The device controller controlled by the driver.
 | |
|   @param  NumberOfChildren       The number of children of this device
 | |
|   @param  ChildHandleBuffer      The buffer of children handle.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The driver stopped from controlling the device.
 | |
|   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
 | |
|   @retval EFI_UNSUPPORTED        Block I/O Protocol is not installed on Controller.
 | |
|   @retval Others                 Failed to stop the driver
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| USBMassDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL *This,
 | |
|   IN  EFI_HANDLE                  Controller,
 | |
|   IN  UINTN                       NumberOfChildren,
 | |
|   IN  EFI_HANDLE                  *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   USB_MASS_DEVICE       *UsbMass;
 | |
|   EFI_USB_IO_PROTOCOL   *UsbIo;
 | |
|   EFI_BLOCK_IO_PROTOCOL *BlockIo;
 | |
|   UINTN                 Index;
 | |
|   BOOLEAN               AllChildrenStopped;
 | |
| 
 | |
|   //
 | |
|   // This is a bus driver stop function since multi-lun is supported.
 | |
|   // There are three kinds of device handles that might be passed:
 | |
|   // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
 | |
|   // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
 | |
|   // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
 | |
|   //
 | |
|   if (NumberOfChildren == 0) {
 | |
|     //
 | |
|     // A handle without any children, might be 1st and 2nd type.
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     (VOID **) &BlockIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Controller,
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|   
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       //
 | |
|       // This is a 2nd type handle(multi-lun root), it needs to close devicepath
 | |
|       // and usbio protocol.
 | |
|       //
 | |
|       gBS->CloseProtocol (
 | |
|             Controller,
 | |
|             &gEfiDevicePathProtocolGuid,
 | |
|             This->DriverBindingHandle,
 | |
|             Controller
 | |
|             );
 | |
|       gBS->CloseProtocol (
 | |
|             Controller,
 | |
|             &gEfiUsbIoProtocolGuid,
 | |
|             This->DriverBindingHandle,
 | |
|             Controller
 | |
|             );
 | |
|       DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // This is a 1st type handle(non-multi-lun), which only needs to uninstall
 | |
|     // Block I/O Protocol, close USB I/O Protocol and free mass device.
 | |
|     //
 | |
|     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
 | |
|   
 | |
|     //
 | |
|     // Uninstall Block I/O protocol from the device handle,
 | |
|     // then call the transport protocol to stop itself.
 | |
|     //
 | |
|     Status = gBS->UninstallProtocolInterface (
 | |
|                     Controller,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     &UsbMass->BlockIo
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   
 | |
|     gBS->CloseProtocol (
 | |
|           Controller,
 | |
|           &gEfiUsbIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           Controller
 | |
|           );
 | |
|   
 | |
|     UsbMass->Transport->CleanUp (UsbMass->Context);
 | |
|     FreePool (UsbMass);
 | |
|     
 | |
|     DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
 | |
|     return EFI_SUCCESS;
 | |
|   } 
 | |
| 
 | |
|   //
 | |
|   // This is a 3rd type handle(multi-lun), which needs uninstall
 | |
|   // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and 
 | |
|   // free mass device for all children.
 | |
|   //
 | |
|   AllChildrenStopped = TRUE;
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfChildren; Index++) {
 | |
| 
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     (VOID **) &BlockIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Controller,
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       AllChildrenStopped = FALSE;
 | |
|       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|            Controller,
 | |
|            &gEfiUsbIoProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            ChildHandleBuffer[Index]
 | |
|            );
 | |
|   
 | |
|     Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     UsbMass->DevicePath,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     &UsbMass->BlockIo,
 | |
|                     NULL
 | |
|                     );
 | |
|     
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
 | |
|       //
 | |
|       AllChildrenStopped = FALSE;
 | |
|       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
 | |
|       
 | |
|       gBS->OpenProtocol (
 | |
|              Controller,
 | |
|              &gEfiUsbIoProtocolGuid,
 | |
|              (VOID **) &UsbIo,
 | |
|              This->DriverBindingHandle,
 | |
|              ChildHandleBuffer[Index],
 | |
|              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|              );
 | |
|     } else {
 | |
|       //
 | |
|       // Succeed to stop this multi-lun handle, so go on with next child.
 | |
|       //
 | |
|       if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
 | |
|         UsbMass->Transport->CleanUp (UsbMass->Context);
 | |
|       }
 | |
|       FreePool (UsbMass);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!AllChildrenStopped) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
|   
 | |
|   DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Entrypoint of USB Mass Storage Driver.
 | |
| 
 | |
|   This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
 | |
|   Protocol together with Component Name Protocols.
 | |
| 
 | |
|   @param  ImageHandle       The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable       A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The entry point is executed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| USBMassStorageEntryPoint (
 | |
|   IN EFI_HANDLE               ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE         *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Install driver binding protocol
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gUSBMassDriverBinding,
 | |
|              ImageHandle,
 | |
|              &gUsbMassStorageComponentName,
 | |
|              &gUsbMassStorageComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |