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
[] = {
43 UINTN mUsbMscInfo
= DEBUG_INFO
;
44 UINTN mUsbMscError
= DEBUG_ERROR
;
48 Retrieve the media parameters such as disk gemotric for the
49 device's BLOCK IO protocol.
51 @param UsbMass The USB mass storage device
53 @retval EFI_SUCCESS The media parameters is updated successfully.
54 @retval Others Failed to get the media parameters.
59 IN USB_MASS_DEVICE
*UsbMass
62 EFI_BLOCK_IO_MEDIA
*Media
;
66 Media
= &UsbMass
->BlockIoMedia
;
69 // Initialize the MediaPrsent/ReadOnly and others to the default.
70 // We are not forced to get it right at this time, check UEFI2.0
71 // spec for more information:
73 // MediaPresent: This field shows the media present status as
74 // of the most recent ReadBlocks or WriteBlocks call.
76 // ReadOnly : This field shows the read-only status as of the
77 // recent WriteBlocks call.
79 // but remember to update MediaId/MediaPresent/ReadOnly status
80 // after ReadBlocks and WriteBlocks
82 Media
->MediaPresent
= FALSE
;
83 Media
->LogicalPartition
= FALSE
;
84 Media
->ReadOnly
= FALSE
;
85 Media
->WriteCaching
= FALSE
;
89 // Some device may spend several seconds before it is ready.
90 // Try several times before giving up. Wait 5s at most.
94 for (Index
= 0; Index
< USB_BOOT_INIT_MEDIA_RETRY
; Index
++) {
96 Status
= UsbBootGetParams (UsbMass
);
97 if ((Status
!= EFI_MEDIA_CHANGED
)
98 && (Status
!= EFI_NOT_READY
)
99 && (Status
!= EFI_TIMEOUT
)) {
103 Status
= UsbBootIsUnitReady (UsbMass
);
104 if (EFI_ERROR (Status
)) {
105 gBS
->Stall (USB_BOOT_RETRY_UNIT_READY_STALL
* (Index
+ 1));
115 Reset the block device. ExtendedVerification is ignored for this.
117 @param This The BLOCK IO protocol
118 @param ExtendedVerification Whether to execute extended verfication.
120 @retval EFI_SUCCESS The device is successfully resetted.
121 @retval Others Failed to reset the device.
126 IN EFI_BLOCK_IO_PROTOCOL
*This
,
127 IN BOOLEAN ExtendedVerification
130 USB_MASS_DEVICE
*UsbMass
;
134 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
136 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
137 Status
= UsbMass
->Transport
->Reset (UsbMass
->Context
, ExtendedVerification
);
139 gBS
->RestoreTPL (OldTpl
);
146 Read some blocks of data from the block device.
148 @param This The Block IO protocol
149 @param MediaId The media's ID of the device for current request
150 @param Lba The start block number
151 @param BufferSize The size of buffer to read data in
152 @param Buffer The buffer to read data to
154 @retval EFI_SUCCESS The data is successfully read
155 @retval EFI_NO_MEDIA Media isn't present
156 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
158 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
160 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
161 size, or overflow the last block number.
166 IN EFI_BLOCK_IO_PROTOCOL
*This
,
173 USB_MASS_DEVICE
*UsbMass
;
174 EFI_BLOCK_IO_MEDIA
*Media
;
179 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
180 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
181 Media
= &UsbMass
->BlockIoMedia
;
184 // First, validate the parameters
186 if ((Buffer
== NULL
) || (BufferSize
== 0)) {
187 Status
= EFI_INVALID_PARAMETER
;
192 // If it is a removable media, such as CD-Rom or Usb-Floppy,
193 // need to detect the media before each rw. While some of
194 // Usb-Flash is marked as removable media.
197 if (Media
->RemovableMedia
== TRUE
) {
198 Status
= UsbBootDetectMedia (UsbMass
);
199 if (EFI_ERROR (Status
)) {
200 DEBUG ((mUsbMscError
, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status
));
206 // Make sure BlockSize and LBA is consistent with BufferSize
208 if ((BufferSize
% Media
->BlockSize
) != 0) {
209 Status
= EFI_BAD_BUFFER_SIZE
;
213 TotalBlock
= BufferSize
/ Media
->BlockSize
;
215 if (Lba
+ TotalBlock
- 1 > Media
->LastBlock
) {
216 Status
= EFI_BAD_BUFFER_SIZE
;
220 Status
= UsbBootReadBlocks (UsbMass
, (UINT32
) Lba
, TotalBlock
, Buffer
);
221 if (EFI_ERROR (Status
)) {
222 DEBUG ((mUsbMscError
, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status
));
223 UsbMassReset (This
, TRUE
);
227 gBS
->RestoreTPL (OldTpl
);
233 Write some blocks of data to the block device.
235 @param This The Block IO protocol
236 @param MediaId The media's ID of the device for current request
237 @param Lba The start block number
238 @param BufferSize The size of buffer to write data to
239 @param Buffer The buffer to write data to
241 @retval EFI_SUCCESS The data is successfully written
242 @retval EFI_NO_MEDIA Media isn't present
243 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
245 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
247 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
253 IN EFI_BLOCK_IO_PROTOCOL
*This
,
260 USB_MASS_DEVICE
*UsbMass
;
261 EFI_BLOCK_IO_MEDIA
*Media
;
266 OldTpl
= gBS
->RaiseTPL (USB_MASS_TPL
);
267 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (This
);
268 Media
= &UsbMass
->BlockIoMedia
;
271 // First, validate the parameters
273 if ((Buffer
== NULL
) || (BufferSize
== 0)) {
274 Status
= EFI_INVALID_PARAMETER
;
279 // If it is a removable media, such as CD-Rom or Usb-Floppy,
280 // need to detect the media before each rw. While some of
281 // Usb-Flash is marked as removable media.
284 if (Media
->RemovableMedia
== TRUE
) {
285 Status
= UsbBootDetectMedia (UsbMass
);
286 if (EFI_ERROR (Status
)) {
287 DEBUG ((mUsbMscError
, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status
));
293 // Make sure BlockSize and LBA is consistent with BufferSize
295 if ((BufferSize
% Media
->BlockSize
) != 0) {
296 Status
= EFI_BAD_BUFFER_SIZE
;
300 TotalBlock
= BufferSize
/ Media
->BlockSize
;
302 if (Lba
+ TotalBlock
- 1 > Media
->LastBlock
) {
303 Status
= EFI_BAD_BUFFER_SIZE
;
308 // Try to write the data even the device is marked as ReadOnly,
309 // and clear the status should the write succeed.
311 Status
= UsbBootWriteBlocks (UsbMass
, (UINT32
) Lba
, TotalBlock
, Buffer
);
312 if (EFI_ERROR (Status
)) {
313 DEBUG ((mUsbMscError
, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status
));
314 UsbMassReset (This
, TRUE
);
318 gBS
->RestoreTPL (OldTpl
);
324 Flush the cached writes to disks. USB mass storage device doesn't
325 support write cache, so return EFI_SUCCESS directly.
327 @param This The BLOCK IO protocol
329 @retval EFI_SUCCESS Always returns success
334 IN EFI_BLOCK_IO_PROTOCOL
*This
342 Check whether the controller is a supported USB mass storage.
344 @param This The USB mass driver's driver binding.
345 @param Controller The device to test against.
346 @param RemainingDevicePath The remaining device path
348 @retval EFI_SUCCESS This device is a supported USB mass storage.
349 @retval EFI_UNSUPPORTED The device isn't supported
350 @retval Others Some error happened.
355 USBMassDriverBindingSupported (
356 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
357 IN EFI_HANDLE Controller
,
358 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
361 EFI_USB_IO_PROTOCOL
*UsbIo
;
362 EFI_USB_INTERFACE_DESCRIPTOR Interface
;
363 USB_MASS_TRANSPORT
*Transport
;
368 // Check whether the controlelr support USB_IO
370 Status
= gBS
->OpenProtocol (
372 &gEfiUsbIoProtocolGuid
,
374 This
->DriverBindingHandle
,
376 EFI_OPEN_PROTOCOL_BY_DRIVER
378 if (EFI_ERROR (Status
)) {
383 // Get the interface to check the USB class and find a transport
386 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &Interface
);
387 if (EFI_ERROR (Status
)) {
391 Status
= EFI_UNSUPPORTED
;
393 if (Interface
.InterfaceClass
!= USB_MASS_STORE_CLASS
) {
397 for (Index
= 0; mUsbMassTransport
[Index
] != NULL
; Index
++) {
398 Transport
= mUsbMassTransport
[Index
];
399 if (Interface
.InterfaceProtocol
== Transport
->Protocol
) {
400 Status
= Transport
->Init (UsbIo
, Controller
, NULL
);
405 DEBUG ((mUsbMscInfo
, "Found a USB mass store device %r\n", Status
));
410 &gEfiUsbIoProtocolGuid
,
411 This
->DriverBindingHandle
,
420 Start the USB mass storage device on the controller. It will
421 install a BLOCK_IO protocol on the device if everything is OK.
423 @param This The USB mass storage driver binding.
424 @param Controller The USB mass storage device to start on
425 @param RemainingDevicePath The remaining device path.
427 @retval EFI_SUCCESS The driver has started on the device.
428 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
429 @retval Others Failed to start the driver on the device.
434 USBMassDriverBindingStart (
435 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
436 IN EFI_HANDLE Controller
,
437 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
440 EFI_USB_IO_PROTOCOL
*UsbIo
;
441 EFI_USB_INTERFACE_DESCRIPTOR Interface
;
442 USB_MASS_DEVICE
*UsbMass
;
443 USB_MASS_TRANSPORT
*Transport
;
447 Status
= gBS
->OpenProtocol (
449 &gEfiUsbIoProtocolGuid
,
451 This
->DriverBindingHandle
,
453 EFI_OPEN_PROTOCOL_BY_DRIVER
456 if (EFI_ERROR (Status
)) {
460 UsbMass
= AllocateZeroPool (sizeof (USB_MASS_DEVICE
));
461 if (UsbMass
== NULL
) {
462 return EFI_OUT_OF_RESOURCES
;
466 // Initialize the transport protocols
468 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &Interface
);
469 if (EFI_ERROR (Status
)) {
470 DEBUG ((mUsbMscError
, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status
));
474 Status
= EFI_UNSUPPORTED
;
476 for (Index
= 0; mUsbMassTransport
[Index
] != NULL
; Index
++) {
477 Transport
= mUsbMassTransport
[Index
];
479 if (Interface
.InterfaceProtocol
== Transport
->Protocol
) {
480 UsbMass
->Transport
= Transport
;
481 Status
= Transport
->Init (UsbIo
, Controller
, &UsbMass
->Context
);
486 if (EFI_ERROR (Status
)) {
487 DEBUG ((mUsbMscError
, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status
));
491 UsbMass
->Signature
= USB_MASS_SIGNATURE
;
492 UsbMass
->Controller
= Controller
;
493 UsbMass
->UsbIo
= UsbIo
;
494 UsbMass
->BlockIo
.Media
= &UsbMass
->BlockIoMedia
;
495 UsbMass
->BlockIo
.Reset
= UsbMassReset
;
496 UsbMass
->BlockIo
.ReadBlocks
= UsbMassReadBlocks
;
497 UsbMass
->BlockIo
.WriteBlocks
= UsbMassWriteBlocks
;
498 UsbMass
->BlockIo
.FlushBlocks
= UsbMassFlushBlocks
;
499 UsbMass
->OpticalStorage
= FALSE
;
502 // Get the storage's parameters, such as last block number.
503 // then install the BLOCK_IO
505 Status
= UsbMassInitMedia (UsbMass
);
506 if (!EFI_ERROR (Status
)) {
507 if ((UsbMass
->Pdt
!= USB_PDT_DIRECT_ACCESS
) &&
508 (UsbMass
->Pdt
!= USB_PDT_CDROM
) &&
509 (UsbMass
->Pdt
!= USB_PDT_OPTICAL
) &&
510 (UsbMass
->Pdt
!= USB_PDT_SIMPLE_DIRECT
)) {
511 DEBUG ((mUsbMscError
, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass
->Pdt
));
514 } else if (Status
!= EFI_NO_MEDIA
){
515 DEBUG ((mUsbMscError
, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status
));
519 Status
= gBS
->InstallProtocolInterface (
521 &gEfiBlockIoProtocolGuid
,
522 EFI_NATIVE_INTERFACE
,
525 if (EFI_ERROR (Status
)) {
532 gBS
->FreePool (UsbMass
);
536 &gEfiUsbIoProtocolGuid
,
537 This
->DriverBindingHandle
,
546 Stop controlling the device.
548 @param This The USB mass storage driver binding
549 @param Controller The device controller controlled by the driver.
550 @param NumberOfChildren The number of children of this device
551 @param ChildHandleBuffer The buffer of children handle.
553 @retval EFI_SUCCESS The driver stopped from controlling the device.
554 @retval Others Failed to stop the driver
559 USBMassDriverBindingStop (
560 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
561 IN EFI_HANDLE Controller
,
562 IN UINTN NumberOfChildren
,
563 IN EFI_HANDLE
*ChildHandleBuffer
567 USB_MASS_DEVICE
*UsbMass
;
568 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
571 // First, get our context back from the BLOCK_IO
573 Status
= gBS
->OpenProtocol (
575 &gEfiBlockIoProtocolGuid
,
577 This
->DriverBindingHandle
,
579 EFI_OPEN_PROTOCOL_GET_PROTOCOL
582 if (EFI_ERROR (Status
)) {
586 UsbMass
= USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo
);
589 // Uninstall Block I/O protocol from the device handle,
590 // then call the transport protocol to stop itself.
592 Status
= gBS
->UninstallProtocolInterface (
594 &gEfiBlockIoProtocolGuid
,
597 if (EFI_ERROR (Status
)) {
603 &gEfiUsbIoProtocolGuid
,
604 This
->DriverBindingHandle
,
608 UsbMass
->Transport
->Fini (UsbMass
->Context
);
609 gBS
->FreePool (UsbMass
);
614 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding
= {
615 USBMassDriverBindingSupported
,
616 USBMassDriverBindingStart
,
617 USBMassDriverBindingStop
,
625 USBMassStorageEntryPoint (
626 IN EFI_HANDLE ImageHandle
,
627 IN EFI_SYSTEM_TABLE
*SystemTable
633 The entry point for the driver, which will install the driver binding and
634 component name protocol
638 ImageHandle - The image handle of this driver
639 SystemTable - The system table
643 EFI_SUCCESS - the protocols are installed OK
644 Others - Failed to install protocols.
651 // Install driver binding protocol
653 Status
= EfiLibInstallDriverBindingComponentName2 (
656 &gUSBMassDriverBinding
,
658 &gUsbMassStorageComponentName
,
659 &gUsbMassStorageComponentName2