]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
1. Added EFI_MEDIA_CHANGED and EFI_INVALID_PARAMETER returns in UsbMassReadBlocks().
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
1 /** @file
2
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
8
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.
11
12 Module Name:
13
14 UsbMassImpl.c
15
16 Abstract:
17
18 The implementation of USB mass storage class device driver.
19 The command set supported is "USB Mass Storage Specification
20 for Bootability".
21
22 Revision History
23
24
25 **/
26
27 #include "UsbMassImpl.h"
28
29 //
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.
34 //
35 STATIC
36 USB_MASS_TRANSPORT *mUsbMassTransport[] = {
37 &mUsbCbi0Transport,
38 &mUsbCbi1Transport,
39 &mUsbBotTransport,
40 NULL
41 };
42
43 /**
44 Retrieve the media parameters such as disk gemotric for the
45 device's BLOCK IO protocol.
46
47 @param UsbMass The USB mass storage device
48
49 @retval EFI_SUCCESS The media parameters is updated successfully.
50 @retval Others Failed to get the media parameters.
51
52 **/
53 EFI_STATUS
54 UsbMassInitMedia (
55 IN USB_MASS_DEVICE *UsbMass
56 )
57 {
58 EFI_BLOCK_IO_MEDIA *Media;
59 EFI_STATUS Status;
60 UINTN Index;
61
62 Media = &UsbMass->BlockIoMedia;
63
64 //
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:
68 //
69 // MediaPresent: This field shows the media present status as
70 // of the most recent ReadBlocks or WriteBlocks call.
71 //
72 // ReadOnly : This field shows the read-only status as of the
73 // recent WriteBlocks call.
74 //
75 // but remember to update MediaId/MediaPresent/ReadOnly status
76 // after ReadBlocks and WriteBlocks
77 //
78 Media->MediaPresent = FALSE;
79 Media->LogicalPartition = FALSE;
80 Media->ReadOnly = FALSE;
81 Media->WriteCaching = FALSE;
82 Media->IoAlign = 0;
83 Media->MediaId = 1;
84
85 //
86 // Some device may spend several seconds before it is ready.
87 // Try several times before giving up. Wait 5s at most.
88 //
89 Status = EFI_SUCCESS;
90
91 for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
92
93 Status = UsbBootGetParams (UsbMass);
94 if ((Status != EFI_MEDIA_CHANGED)
95 && (Status != EFI_NOT_READY)
96 && (Status != EFI_TIMEOUT)) {
97 break;
98 }
99
100 Status = UsbBootIsUnitReady (UsbMass);
101 if (EFI_ERROR (Status)) {
102 gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
103 }
104
105 }
106
107 return Status;
108 }
109
110
111 /**
112 Reset the block device. ExtendedVerification is ignored for this.
113
114 @param This The BLOCK IO protocol
115 @param ExtendedVerification Whether to execute extended verfication.
116
117 @retval EFI_SUCCESS The device is successfully resetted.
118 @retval Others Failed to reset the device.
119
120 **/
121 EFI_STATUS
122 EFIAPI
123 UsbMassReset (
124 IN EFI_BLOCK_IO_PROTOCOL *This,
125 IN BOOLEAN ExtendedVerification
126 )
127 {
128 USB_MASS_DEVICE *UsbMass;
129 EFI_TPL OldTpl;
130 EFI_STATUS Status;
131
132 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
133
134 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
135 Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
136
137 gBS->RestoreTPL (OldTpl);
138
139 return Status;
140 }
141
142
143 /**
144 Read some blocks of data from the block device.
145
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
151
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,
155 MediaId changed
156 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
157 NULL.
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.
160
161 **/
162 EFI_STATUS
163 EFIAPI
164 UsbMassReadBlocks (
165 IN EFI_BLOCK_IO_PROTOCOL *This,
166 IN UINT32 MediaId,
167 IN EFI_LBA Lba,
168 IN UINTN BufferSize,
169 OUT VOID *Buffer
170 )
171 {
172 USB_MASS_DEVICE *UsbMass;
173 EFI_BLOCK_IO_MEDIA *Media;
174 EFI_STATUS Status;
175 EFI_TPL OldTpl;
176 UINTN TotalBlock;
177
178 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
179 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
180 Media = &UsbMass->BlockIoMedia;
181
182 //
183 // First, validate the parameters
184 //
185 if ((Buffer == NULL) || (BufferSize == 0)) {
186 Status = EFI_INVALID_PARAMETER;
187 goto ON_EXIT;
188 }
189
190 //
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.
194 //
195 //
196 if (Media->RemovableMedia == TRUE) {
197 Status = UsbBootDetectMedia (UsbMass);
198 if (EFI_ERROR (Status)) {
199 DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
200 goto ON_EXIT;
201 }
202 }
203
204 //
205 // Make sure BlockSize and LBA is consistent with BufferSize
206 //
207 if ((BufferSize % Media->BlockSize) != 0) {
208 Status = EFI_BAD_BUFFER_SIZE;
209 goto ON_EXIT;
210 }
211
212 TotalBlock = BufferSize / Media->BlockSize;
213
214 if (Lba + TotalBlock - 1 > Media->LastBlock) {
215 Status = EFI_INVALID_PARAMETER;
216 goto ON_EXIT;
217 }
218
219 if (!(Media->MediaPresent)) {
220 Status = EFI_NO_MEDIA;
221 goto ON_EXIT;
222 }
223
224 if (MediaId != Media->MediaId) {
225 Status = EFI_MEDIA_CHANGED;
226 goto ON_EXIT;
227 }
228
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);
233 }
234
235 ON_EXIT:
236 gBS->RestoreTPL (OldTpl);
237 return Status;
238 }
239
240
241 /**
242 Write some blocks of data to the block device.
243
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
249
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,
253 MediaId changed
254 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
255 NULL.
256 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
257 size,
258
259 **/
260 EFI_STATUS
261 EFIAPI
262 UsbMassWriteBlocks (
263 IN EFI_BLOCK_IO_PROTOCOL *This,
264 IN UINT32 MediaId,
265 IN EFI_LBA Lba,
266 IN UINTN BufferSize,
267 IN VOID *Buffer
268 )
269 {
270 USB_MASS_DEVICE *UsbMass;
271 EFI_BLOCK_IO_MEDIA *Media;
272 EFI_STATUS Status;
273 EFI_TPL OldTpl;
274 UINTN TotalBlock;
275
276 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
277 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
278 Media = &UsbMass->BlockIoMedia;
279
280 //
281 // First, validate the parameters
282 //
283 if ((Buffer == NULL) || (BufferSize == 0)) {
284 Status = EFI_INVALID_PARAMETER;
285 goto ON_EXIT;
286 }
287
288 //
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.
292 //
293 //
294 if (Media->RemovableMedia == TRUE) {
295 Status = UsbBootDetectMedia (UsbMass);
296 if (EFI_ERROR (Status)) {
297 DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
298 goto ON_EXIT;
299 }
300 }
301
302 //
303 // Make sure BlockSize and LBA is consistent with BufferSize
304 //
305 if ((BufferSize % Media->BlockSize) != 0) {
306 Status = EFI_BAD_BUFFER_SIZE;
307 goto ON_EXIT;
308 }
309
310 TotalBlock = BufferSize / Media->BlockSize;
311
312 if (Lba + TotalBlock - 1 > Media->LastBlock) {
313 Status = EFI_INVALID_PARAMETER;
314 goto ON_EXIT;
315 }
316
317 if (!(Media->MediaPresent)) {
318 Status = EFI_NO_MEDIA;
319 goto ON_EXIT;
320 }
321
322 if (MediaId != Media->MediaId) {
323 Status = EFI_MEDIA_CHANGED;
324 goto ON_EXIT;
325 }
326
327 //
328 // Try to write the data even the device is marked as ReadOnly,
329 // and clear the status should the write succeed.
330 //
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);
335 }
336
337 ON_EXIT:
338 gBS->RestoreTPL (OldTpl);
339 return Status;
340 }
341
342
343 /**
344 Flush the cached writes to disks. USB mass storage device doesn't
345 support write cache, so return EFI_SUCCESS directly.
346
347 @param This The BLOCK IO protocol
348
349 @retval EFI_SUCCESS Always returns success
350
351 **/
352 EFI_STATUS
353 EFIAPI
354 UsbMassFlushBlocks (
355 IN EFI_BLOCK_IO_PROTOCOL *This
356 )
357 {
358 return EFI_SUCCESS;
359 }
360
361
362 /**
363 Check whether the controller is a supported USB mass storage.
364
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
368
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.
372
373 **/
374 EFI_STATUS
375 EFIAPI
376 USBMassDriverBindingSupported (
377 IN EFI_DRIVER_BINDING_PROTOCOL *This,
378 IN EFI_HANDLE Controller,
379 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
380 )
381 {
382 EFI_USB_IO_PROTOCOL *UsbIo;
383 EFI_USB_INTERFACE_DESCRIPTOR Interface;
384 USB_MASS_TRANSPORT *Transport;
385 EFI_STATUS Status;
386 INTN Index;
387
388 //
389 // Check whether the controlelr support USB_IO
390 //
391 Status = gBS->OpenProtocol (
392 Controller,
393 &gEfiUsbIoProtocolGuid,
394 (VOID **) &UsbIo,
395 This->DriverBindingHandle,
396 Controller,
397 EFI_OPEN_PROTOCOL_BY_DRIVER
398 );
399 if (EFI_ERROR (Status)) {
400 return Status;
401 }
402
403 //
404 // Get the interface to check the USB class and find a transport
405 // protocol handler.
406 //
407 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
408 if (EFI_ERROR (Status)) {
409 goto ON_EXIT;
410 }
411
412 Status = EFI_UNSUPPORTED;
413
414 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
415 goto ON_EXIT;
416 }
417
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);
422 break;
423 }
424 }
425
426 DEBUG ((EFI_D_INFO, "Found a USB mass store device %r\n", Status));
427
428 ON_EXIT:
429 gBS->CloseProtocol (
430 Controller,
431 &gEfiUsbIoProtocolGuid,
432 This->DriverBindingHandle,
433 Controller
434 );
435
436 return Status;
437 }
438
439
440 /**
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.
443
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.
447
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.
451
452 **/
453 EFI_STATUS
454 EFIAPI
455 USBMassDriverBindingStart (
456 IN EFI_DRIVER_BINDING_PROTOCOL *This,
457 IN EFI_HANDLE Controller,
458 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
459 )
460 {
461 EFI_USB_IO_PROTOCOL *UsbIo;
462 EFI_USB_INTERFACE_DESCRIPTOR Interface;
463 USB_MASS_DEVICE *UsbMass;
464 USB_MASS_TRANSPORT *Transport;
465 EFI_STATUS Status;
466 UINTN Index;
467
468 Status = gBS->OpenProtocol (
469 Controller,
470 &gEfiUsbIoProtocolGuid,
471 (VOID **) &UsbIo,
472 This->DriverBindingHandle,
473 Controller,
474 EFI_OPEN_PROTOCOL_BY_DRIVER
475 );
476
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480
481 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
482 if (UsbMass == NULL) {
483 return EFI_OUT_OF_RESOURCES;
484 }
485
486 //
487 // Initialize the transport protocols
488 //
489 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
490 if (EFI_ERROR (Status)) {
491 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
492 goto ON_ERROR;
493 }
494
495 Status = EFI_UNSUPPORTED;
496
497 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
498 Transport = mUsbMassTransport[Index];
499
500 if (Interface.InterfaceProtocol == Transport->Protocol) {
501 UsbMass->Transport = Transport;
502 Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);
503 break;
504 }
505 }
506
507 if (EFI_ERROR (Status)) {
508 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));
509 goto ON_ERROR;
510 }
511
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;
521
522 //
523 // Get the storage's parameters, such as last block number.
524 // then install the BLOCK_IO
525 //
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));
533 goto ON_ERROR;
534 }
535 } else if (Status != EFI_NO_MEDIA){
536 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));
537 goto ON_ERROR;
538 }
539
540 Status = gBS->InstallProtocolInterface (
541 &Controller,
542 &gEfiBlockIoProtocolGuid,
543 EFI_NATIVE_INTERFACE,
544 &UsbMass->BlockIo
545 );
546 if (EFI_ERROR (Status)) {
547 goto ON_ERROR;
548 }
549
550 return EFI_SUCCESS;
551
552 ON_ERROR:
553 gBS->FreePool (UsbMass);
554
555 gBS->CloseProtocol (
556 Controller,
557 &gEfiUsbIoProtocolGuid,
558 This->DriverBindingHandle,
559 Controller
560 );
561
562 return Status;
563 }
564
565
566 /**
567 Stop controlling the device.
568
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.
573
574 @retval EFI_SUCCESS The driver stopped from controlling the device.
575 @retval Others Failed to stop the driver
576
577 **/
578 EFI_STATUS
579 EFIAPI
580 USBMassDriverBindingStop (
581 IN EFI_DRIVER_BINDING_PROTOCOL *This,
582 IN EFI_HANDLE Controller,
583 IN UINTN NumberOfChildren,
584 IN EFI_HANDLE *ChildHandleBuffer
585 )
586 {
587 EFI_STATUS Status;
588 USB_MASS_DEVICE *UsbMass;
589 EFI_BLOCK_IO_PROTOCOL *BlockIo;
590
591 //
592 // First, get our context back from the BLOCK_IO
593 //
594 Status = gBS->OpenProtocol (
595 Controller,
596 &gEfiBlockIoProtocolGuid,
597 (VOID **) &BlockIo,
598 This->DriverBindingHandle,
599 Controller,
600 EFI_OPEN_PROTOCOL_GET_PROTOCOL
601 );
602
603 if (EFI_ERROR (Status)) {
604 return Status;
605 }
606
607 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
608
609 //
610 // Uninstall Block I/O protocol from the device handle,
611 // then call the transport protocol to stop itself.
612 //
613 Status = gBS->UninstallProtocolInterface (
614 Controller,
615 &gEfiBlockIoProtocolGuid,
616 &UsbMass->BlockIo
617 );
618 if (EFI_ERROR (Status)) {
619 return Status;
620 }
621
622 gBS->CloseProtocol (
623 Controller,
624 &gEfiUsbIoProtocolGuid,
625 This->DriverBindingHandle,
626 Controller
627 );
628
629 UsbMass->Transport->Fini (UsbMass->Context);
630 gBS->FreePool (UsbMass);
631
632 return EFI_SUCCESS;
633 }
634
635 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
636 USBMassDriverBindingSupported,
637 USBMassDriverBindingStart,
638 USBMassDriverBindingStop,
639 0x11,
640 NULL,
641 NULL
642 };
643
644 EFI_STATUS
645 EFIAPI
646 USBMassStorageEntryPoint (
647 IN EFI_HANDLE ImageHandle,
648 IN EFI_SYSTEM_TABLE *SystemTable
649 )
650 /*++
651
652 Routine Description:
653
654 The entry point for the driver, which will install the driver binding and
655 component name protocol
656
657 Arguments:
658
659 ImageHandle - The image handle of this driver
660 SystemTable - The system table
661
662 Returns:
663
664 EFI_SUCCESS - the protocols are installed OK
665 Others - Failed to install protocols.
666
667 --*/
668 {
669 EFI_STATUS Status;
670
671 //
672 // Install driver binding protocol
673 //
674 Status = EfiLibInstallDriverBindingComponentName2 (
675 ImageHandle,
676 SystemTable,
677 &gUSBMassDriverBinding,
678 ImageHandle,
679 &gUsbMassStorageComponentName,
680 &gUsbMassStorageComponentName2
681 );
682
683 return Status;
684 }