+/** @file\r
+ The driver wrappers BlockMmio protocol instances to produce\r
+ Block I/O Protocol instances.\r
+\r
+ Copyright (c) 2007 - 2010, 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
+**/\r
+\r
+#include "BlockIo.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gBlockIoDriverBinding = {\r
+ BlockIoDriverBindingSupported,\r
+ BlockIoDriverBindingStart,\r
+ BlockIoDriverBindingStop,\r
+ 0x11,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+/**\r
+ Reset the block device.\r
+\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
+ @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
+EFIAPI\r
+BlockIoReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\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 ReadData If TRUE then read data. If FALSE then write data.\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
+ReadOrWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ReadData,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BLOCK_MMIO_TO_BLOCK_IO_DEVICE *Private;\r
+ UINTN TotalBlock;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINT64 Address;\r
+ UINTN Count;\r
+ EFI_CPU_IO_PROTOCOL_IO_MEM CpuAccessFunction;\r
+\r
+ //\r
+ // First, validate the parameters\r
+ //\r
+ if ((Buffer == NULL) || (BufferSize == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Get private data structure\r
+ //\r
+ Private = PRIVATE_FROM_BLOCK_IO (This);\r
+ Media = Private->BlockMmio->Media;\r
+\r
+ //\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
+ }\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_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!(Media->MediaPresent)) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ Address = Private->BlockMmio->BaseAddress;\r
+ Address += Media->BlockSize * Lba;\r
+\r
+ Count = BufferSize / 8;\r
+\r
+ if (ReadData) {\r
+ CpuAccessFunction = Private->CpuIo->Mem.Read;\r
+ } else {\r
+ CpuAccessFunction = Private->CpuIo->Mem.Write;\r
+ }\r
+\r
+ Status = (CpuAccessFunction) (\r
+ Private->CpuIo,\r
+ EfiCpuIoWidthUint64,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\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
+BlockIoReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ DEBUG ((EFI_D_INFO, "BlockIo (MMIO) ReadBlocks: lba=0x%lx, size=0x%x\n", Lba, BufferSize));\r
+ return ReadOrWriteBlocks (\r
+ This,\r
+ TRUE,\r
+ MediaId,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+}\r
+\r
+\r
+/**\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
+BlockIoWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ DEBUG ((EFI_D_INFO, "BlockIo (MMIO) WriteBlocks: lba=0x%lx, size=0x%x\n", Lba, BufferSize));\r
+ return ReadOrWriteBlocks (\r
+ This,\r
+ FALSE,\r
+ MediaId,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+}\r
+\r
+/**\r
+ Flushes all modified data to a physical block device.\r
+\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
+BlockIoFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\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 BlockMmio 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
+BlockIoInit (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BLOCK_MMIO_TO_BLOCK_IO_DEVICE *Private;\r
+ BLOCK_MMIO_PROTOCOL *BlockMmio;\r
+\r
+ Private = (BLOCK_MMIO_TO_BLOCK_IO_DEVICE*) AllocateZeroPool (sizeof (Private));\r
+ ASSERT (Private != NULL);\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiCpuIo2ProtocolGuid,\r
+ NULL,\r
+ (VOID **) &(Private->CpuIo)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gBlockMmioProtocolGuid,\r
+ (VOID **) &BlockMmio,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "BlockIoInit: OpenBlockMmioProtocol By Driver (%r)\n", Status));\r
+ goto ON_ERROR;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "BlockMmio: 0x%x\n", BlockMmio));\r
+ DEBUG ((EFI_D_INFO, "BlockMmio->Media->LastBlock: 0x%lx\n", BlockMmio->Media->LastBlock));\r
+ \r
+ Private->Signature = BLOCK_MMIO_TO_BLOCK_IO_SIGNATURE;\r
+ Private->Controller = Controller;\r
+ Private->BlockMmio = BlockMmio;\r
+ Private->BlockIo.Media = BlockMmio->Media;\r
+ Private->BlockIo.Reset = BlockIoReset;\r
+ Private->BlockIo.ReadBlocks = BlockIoReadBlocks;\r
+ Private->BlockIo.WriteBlocks = BlockIoWriteBlocks;\r
+ Private->BlockIo.FlushBlocks = BlockIoFlushBlocks;\r
+\r
+ DEBUG ((EFI_D_INFO, "Private->BlockIo.Media->LastBlock: 0x%lx\n", Private->BlockIo.Media->LastBlock));\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Private->BlockIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ if (Private != NULL) {\r
+ FreePool (Private);\r
+ }\r
+ if (BlockMmio != NULL) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gBlockMmioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ return Status; \r
+}\r
+\r
+\r
+/**\r
+ Check whether the controller is a supported USB mass storage.\r
+\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 supports this controller.\r
+ @retval other This device isn't supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BLOCK_MMIO_PROTOCOL *BlockMmio;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gBlockMmioProtocolGuid,\r
+ (VOID **) &BlockMmio,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gBlockMmioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\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
+BlockIoDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ \r
+ Status = BlockIoInit (This, Controller);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "BlockIoDriverBindingStart: BlockIoInit (%r)\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INIT, "BlockIoDriverBindingStart: Successfully started\n"));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop controlling the device.\r
+\r
+ @param This The USB mass storage driver binding\r
+ @param Controller The device controller controlled by the driver.\r
+ @param NumberOfChildren The number of children of this device\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
+EFI_STATUS\r
+EFIAPI\r
+BlockIoDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BLOCK_MMIO_TO_BLOCK_IO_DEVICE *Private;\r
+\r
+ Private = PRIVATE_FROM_BLOCK_IO (This);\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->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Private->BlockIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gBlockMmioProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ FreePool (Private);\r
+ \r
+ DEBUG ((EFI_D_INFO, "Successfully stopped BlockIo on BlockMmio\n"));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Entrypoint of Block MMIO to Block IO 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
+BlockMmioToBlockIoEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install driver binding protocol\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gBlockIoDriverBinding,\r
+ ImageHandle,\r
+ &gBlockMmioToBlockIoComponentName,\r
+ &gBlockMmioToBlockIoComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r