3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 The implementation of USB mass storage class device driver.
19 The command set supported is "USB Mass Storage Specification
27 #include "UsbMassImpl.h"
30 // The underlying transport protocol. CBI support isn't included
31 // in the current build. It is being obseleted by the standard
32 // body. If you want to enable it, remove the if directive here,
33 // then add the UsbMassCbi.c/.h to the driver's inf file.
36 USB_MASS_TRANSPORT
*mUsbMassTransport
[] = {
44 Retrieve the media parameters such as disk gemotric for the
45 device's BLOCK IO protocol.
47 @param UsbMass The USB mass storage device
49 @retval EFI_SUCCESS The media parameters is updated successfully.
50 @retval Others Failed to get the media parameters.
55 IN USB_MASS_DEVICE
*UsbMass
58 EFI_BLOCK_IO_MEDIA
*Media
;
62 Media
= &UsbMass
->BlockIoMedia
;
65 // Initialize the MediaPrsent/ReadOnly and others to the default.
66 // We are not forced to get it right at this time, check UEFI2.0
67 // spec for more information:
69 // MediaPresent: This field shows the media present status as
70 // of the most recent ReadBlocks or WriteBlocks call.
72 // ReadOnly : This field shows the read-only status as of the
73 // recent WriteBlocks call.
75 // but remember to update MediaId/MediaPresent/ReadOnly status
76 // after ReadBlocks and WriteBlocks
78 Media
->MediaPresent
= FALSE
;
79 Media
->LogicalPartition
= FALSE
;
80 Media
->ReadOnly
= FALSE
;
81 Media
->WriteCaching
= FALSE
;
86 // Some device may spend several seconds before it is ready.
87 // Try several times before giving up. Wait 5s at most.
91 for (Index
= 0; Index
< USB_BOOT_INIT_MEDIA_RETRY
; Index
++) {
93 Status
= UsbBootGetParams (UsbMass
);
94 if ((Status
!= EFI_MEDIA_CHANGED
)
95 && (Status
!= EFI_NOT_READY
)
96 && (Status
!= EFI_TIMEOUT
)) {
100 Status
= UsbBootIsUnitReady (UsbMass
);
101 if (EFI_ERROR (Status
)) {
102 gBS
->Stall (USB_BOOT_RETRY_UNIT_READY_STALL
* (Index
+ 1));
112 Reset the block device. ExtendedVerification is ignored for this.
114 @param This The BLOCK IO protocol
115 @param ExtendedVerification Whether to execute extended verfication.
117 @retval EFI_SUCCESS The device is successfully resetted.
118 @retval Others Failed to reset the device.
124 IN EFI_BLOCK_IO_PROTOCOL
*This
,
125 IN BOOLEAN ExtendedVerification
128 USB_MASS_DEVICE
*UsbMass
;
132 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
134 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
135 Status
= UsbMass
->Transport
->Reset (UsbMass
->Context
, ExtendedVerification
);
137 gBS
->RestoreTPL (OldTpl
);
144 Read some blocks of data from the block device.
146 @param This The Block IO protocol
147 @param MediaId The media's ID of the device for current request
148 @param Lba The start block number
149 @param BufferSize The size of buffer to read data in
150 @param Buffer The buffer to read data to
152 @retval EFI_SUCCESS The data is successfully read
153 @retval EFI_NO_MEDIA Media isn't present
154 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
156 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
158 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
159 size, or overflow the last block number.
165 IN EFI_BLOCK_IO_PROTOCOL
*This
,
172 USB_MASS_DEVICE
*UsbMass
;
173 EFI_BLOCK_IO_MEDIA
*Media
;
178 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
179 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
180 Media
= &UsbMass
->BlockIoMedia
;
183 // First, validate the parameters
185 if ((Buffer
== NULL
) || (BufferSize
== 0)) {
186 Status
= EFI_INVALID_PARAMETER
;
191 // If it is a removable media, such as CD-Rom or Usb-Floppy,
192 // need to detect the media before each rw. While some of
193 // Usb-Flash is marked as removable media.
196 if (Media
->RemovableMedia
== TRUE
) {
197 Status
= UsbBootDetectMedia (UsbMass
);
198 if (EFI_ERROR (Status
)) {
199 DEBUG ((EFI_D_ERROR
, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status
));
205 // Make sure BlockSize and LBA is consistent with BufferSize
207 if ((BufferSize
% Media
->BlockSize
) != 0) {
208 Status
= EFI_BAD_BUFFER_SIZE
;
212 TotalBlock
= BufferSize
/ Media
->BlockSize
;
214 if (Lba
+ TotalBlock
- 1 > Media
->LastBlock
) {
215 Status
= EFI_INVALID_PARAMETER
;
219 if (!(Media
->MediaPresent
)) {
220 Status
= EFI_NO_MEDIA
;
224 if (MediaId
!= Media
->MediaId
) {
225 Status
= EFI_MEDIA_CHANGED
;
229 Status
= UsbBootReadBlocks (UsbMass
, (UINT32
) Lba
, TotalBlock
, Buffer
);
230 if (EFI_ERROR (Status
)) {
231 DEBUG ((EFI_D_ERROR
, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status
));
232 UsbMassReset (This
, TRUE
);
236 gBS
->RestoreTPL (OldTpl
);
242 Write some blocks of data to the block device.
244 @param This The Block IO protocol
245 @param MediaId The media's ID of the device for current request
246 @param Lba The start block number
247 @param BufferSize The size of buffer to write data to
248 @param Buffer The buffer to write data to
250 @retval EFI_SUCCESS The data is successfully written
251 @retval EFI_NO_MEDIA Media isn't present
252 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
254 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
256 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
263 IN EFI_BLOCK_IO_PROTOCOL
*This
,
270 USB_MASS_DEVICE
*UsbMass
;
271 EFI_BLOCK_IO_MEDIA
*Media
;
276 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
277 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
278 Media
= &UsbMass
->BlockIoMedia
;
281 // First, validate the parameters
283 if ((Buffer
== NULL
) || (BufferSize
== 0)) {
284 Status
= EFI_INVALID_PARAMETER
;
289 // If it is a removable media, such as CD-Rom or Usb-Floppy,
290 // need to detect the media before each rw. While some of
291 // Usb-Flash is marked as removable media.
294 if (Media
->RemovableMedia
== TRUE
) {
295 Status
= UsbBootDetectMedia (UsbMass
);
296 if (EFI_ERROR (Status
)) {
297 DEBUG ((EFI_D_ERROR
, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status
));
303 // Make sure BlockSize and LBA is consistent with BufferSize
305 if ((BufferSize
% Media
->BlockSize
) != 0) {
306 Status
= EFI_BAD_BUFFER_SIZE
;
310 TotalBlock
= BufferSize
/ Media
->BlockSize
;
312 if (Lba
+ TotalBlock
- 1 > Media
->LastBlock
) {
313 Status
= EFI_INVALID_PARAMETER
;
317 if (!(Media
->MediaPresent
)) {
318 Status
= EFI_NO_MEDIA
;
322 if (MediaId
!= Media
->MediaId
) {
323 Status
= EFI_MEDIA_CHANGED
;
328 // Try to write the data even the device is marked as ReadOnly,
329 // and clear the status should the write succeed.
331 Status
= UsbBootWriteBlocks (UsbMass
, (UINT32
) Lba
, TotalBlock
, Buffer
);
332 if (EFI_ERROR (Status
)) {
333 DEBUG ((EFI_D_ERROR
, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status
));
334 UsbMassReset (This
, TRUE
);
338 gBS
->RestoreTPL (OldTpl
);
344 Flush the cached writes to disks. USB mass storage device doesn't
345 support write cache, so return EFI_SUCCESS directly.
347 @param This The BLOCK IO protocol
349 @retval EFI_SUCCESS Always returns success
355 IN EFI_BLOCK_IO_PROTOCOL
*This
363 Check whether the controller is a supported USB mass storage.
365 @param This The USB mass driver's driver binding.
366 @param Controller The device to test against.
367 @param RemainingDevicePath The remaining device path
369 @retval EFI_SUCCESS This device is a supported USB mass storage.
370 @retval EFI_UNSUPPORTED The device isn't supported
371 @retval Others Some error happened.
376 USBMassDriverBindingSupported (
377 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
378 IN EFI_HANDLE Controller
,
379 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
382 EFI_USB_IO_PROTOCOL
*UsbIo
;
383 EFI_USB_INTERFACE_DESCRIPTOR Interface
;
384 USB_MASS_TRANSPORT
*Transport
;
389 // Check whether the controlelr support USB_IO
391 Status
= gBS
->OpenProtocol (
393 &gEfiUsbIoProtocolGuid
,
395 This
->DriverBindingHandle
,
397 EFI_OPEN_PROTOCOL_BY_DRIVER
399 if (EFI_ERROR (Status
)) {
404 // Get the interface to check the USB class and find a transport
407 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &Interface
);
408 if (EFI_ERROR (Status
)) {
412 Status
= EFI_UNSUPPORTED
;
414 if (Interface
.InterfaceClass
!= USB_MASS_STORE_CLASS
) {
418 for (Index
= 0; mUsbMassTransport
[Index
] != NULL
; Index
++) {
419 Transport
= mUsbMassTransport
[Index
];
420 if (Interface
.InterfaceProtocol
== Transport
->Protocol
) {
421 Status
= Transport
->Init (UsbIo
, Controller
, NULL
);
426 DEBUG ((EFI_D_INFO
, "Found a USB mass store device %r\n", Status
));
431 &gEfiUsbIoProtocolGuid
,
432 This
->DriverBindingHandle
,
441 Start the USB mass storage device on the controller. It will
442 install a BLOCK_IO protocol on the device if everything is OK.
444 @param This The USB mass storage driver binding.
445 @param Controller The USB mass storage device to start on
446 @param RemainingDevicePath The remaining device path.
448 @retval EFI_SUCCESS The driver has started on the device.
449 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
450 @retval Others Failed to start the driver on the device.
455 USBMassDriverBindingStart (
456 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
457 IN EFI_HANDLE Controller
,
458 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
461 EFI_USB_IO_PROTOCOL
*UsbIo
;
462 EFI_USB_INTERFACE_DESCRIPTOR Interface
;
463 USB_MASS_DEVICE
*UsbMass
;
464 USB_MASS_TRANSPORT
*Transport
;
468 Status
= gBS
->OpenProtocol (
470 &gEfiUsbIoProtocolGuid
,
472 This
->DriverBindingHandle
,
474 EFI_OPEN_PROTOCOL_BY_DRIVER
477 if (EFI_ERROR (Status
)) {
481 UsbMass
= AllocateZeroPool (sizeof (USB_MASS_DEVICE
));
482 if (UsbMass
== NULL
) {
483 return EFI_OUT_OF_RESOURCES
;
487 // Initialize the transport protocols
489 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &Interface
);
490 if (EFI_ERROR (Status
)) {
491 DEBUG ((EFI_D_ERROR
, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status
));
495 Status
= EFI_UNSUPPORTED
;
497 for (Index
= 0; mUsbMassTransport
[Index
] != NULL
; Index
++) {
498 Transport
= mUsbMassTransport
[Index
];
500 if (Interface
.InterfaceProtocol
== Transport
->Protocol
) {
501 UsbMass
->Transport
= Transport
;
502 Status
= Transport
->Init (UsbIo
, Controller
, &UsbMass
->Context
);
507 if (EFI_ERROR (Status
)) {
508 DEBUG ((EFI_D_ERROR
, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status
));
512 UsbMass
->Signature
= USB_MASS_SIGNATURE
;
513 UsbMass
->Controller
= Controller
;
514 UsbMass
->UsbIo
= UsbIo
;
515 UsbMass
->BlockIo
.Media
= &UsbMass
->BlockIoMedia
;
516 UsbMass
->BlockIo
.Reset
= UsbMassReset
;
517 UsbMass
->BlockIo
.ReadBlocks
= UsbMassReadBlocks
;
518 UsbMass
->BlockIo
.WriteBlocks
= UsbMassWriteBlocks
;
519 UsbMass
->BlockIo
.FlushBlocks
= UsbMassFlushBlocks
;
520 UsbMass
->OpticalStorage
= FALSE
;
523 // Get the storage's parameters, such as last block number.
524 // then install the BLOCK_IO
526 Status
= UsbMassInitMedia (UsbMass
);
527 if (!EFI_ERROR (Status
)) {
528 if ((UsbMass
->Pdt
!= USB_PDT_DIRECT_ACCESS
) &&
529 (UsbMass
->Pdt
!= USB_PDT_CDROM
) &&
530 (UsbMass
->Pdt
!= USB_PDT_OPTICAL
) &&
531 (UsbMass
->Pdt
!= USB_PDT_SIMPLE_DIRECT
)) {
532 DEBUG ((EFI_D_ERROR
, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass
->Pdt
));
535 } else if (Status
!= EFI_NO_MEDIA
){
536 DEBUG ((EFI_D_ERROR
, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status
));
540 Status
= gBS
->InstallProtocolInterface (
542 &gEfiBlockIoProtocolGuid
,
543 EFI_NATIVE_INTERFACE
,
546 if (EFI_ERROR (Status
)) {
553 gBS
->FreePool (UsbMass
);
557 &gEfiUsbIoProtocolGuid
,
558 This
->DriverBindingHandle
,
567 Stop controlling the device.
569 @param This The USB mass storage driver binding
570 @param Controller The device controller controlled by the driver.
571 @param NumberOfChildren The number of children of this device
572 @param ChildHandleBuffer The buffer of children handle.
574 @retval EFI_SUCCESS The driver stopped from controlling the device.
575 @retval Others Failed to stop the driver
580 USBMassDriverBindingStop (
581 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
582 IN EFI_HANDLE Controller
,
583 IN UINTN NumberOfChildren
,
584 IN EFI_HANDLE
*ChildHandleBuffer
588 USB_MASS_DEVICE
*UsbMass
;
589 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
592 // First, get our context back from the BLOCK_IO
594 Status
= gBS
->OpenProtocol (
596 &gEfiBlockIoProtocolGuid
,
598 This
->DriverBindingHandle
,
600 EFI_OPEN_PROTOCOL_GET_PROTOCOL
603 if (EFI_ERROR (Status
)) {
607 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo
);
610 // Uninstall Block I/O protocol from the device handle,
611 // then call the transport protocol to stop itself.
613 Status
= gBS
->UninstallProtocolInterface (
615 &gEfiBlockIoProtocolGuid
,
618 if (EFI_ERROR (Status
)) {
624 &gEfiUsbIoProtocolGuid
,
625 This
->DriverBindingHandle
,
629 UsbMass
->Transport
->Fini (UsbMass
->Context
);
630 gBS
->FreePool (UsbMass
);
635 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding
= {
636 USBMassDriverBindingSupported
,
637 USBMassDriverBindingStart
,
638 USBMassDriverBindingStop
,
646 USBMassStorageEntryPoint (
647 IN EFI_HANDLE ImageHandle
,
648 IN EFI_SYSTEM_TABLE
*SystemTable
654 The entry point for the driver, which will install the driver binding and
655 component name protocol
659 ImageHandle - The image handle of this driver
660 SystemTable - The system table
664 EFI_SUCCESS - the protocols are installed OK
665 Others - Failed to install protocols.
672 // Install driver binding protocol
674 Status
= EfiLibInstallDriverBindingComponentName2 (
677 &gUSBMassDriverBinding
,
679 &gUsbMassStorageComponentName
,
680 &gUsbMassStorageComponentName2