]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
Code scrub for USB Mass Storage Driver.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
1 /** @file
2 USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
3
4 Copyright (c) 2007 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "UsbMassImpl.h"
16
17 //
18 // Array of USB transport interfaces.
19 //
20 USB_MASS_TRANSPORT *mUsbMassTransport[] = {
21 &mUsbCbi0Transport,
22 &mUsbCbi1Transport,
23 &mUsbBotTransport,
24 NULL
25 };
26
27 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
28 USBMassDriverBindingSupported,
29 USBMassDriverBindingStart,
30 USBMassDriverBindingStop,
31 0x11,
32 NULL,
33 NULL
34 };
35
36 /**
37 Reset the block device.
38
39 This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
40 It resets the block device hardware.
41 ExtendedVerification is ignored in this implementation.
42
43 @param This Indicates a pointer to the calling context.
44 @param ExtendedVerification Indicates that the driver may perform a more exhaustive
45 verification operation of the device during reset.
46
47 @retval EFI_SUCCESS The block device was reset.
48 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
49
50 **/
51 EFI_STATUS
52 EFIAPI
53 UsbMassReset (
54 IN EFI_BLOCK_IO_PROTOCOL *This,
55 IN BOOLEAN ExtendedVerification
56 )
57 {
58 USB_MASS_DEVICE *UsbMass;
59 EFI_TPL OldTpl;
60 EFI_STATUS Status;
61
62 //
63 // Raise TPL to TPL_NOTIFY to serialize all its operations
64 // to protect shared data structures.
65 //
66 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
67
68 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
69 Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
70
71 gBS->RestoreTPL (OldTpl);
72
73 return Status;
74 }
75
76 /**
77 Reads the requested number of blocks from the device.
78
79 This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
80 It reads the requested number of blocks from the device.
81 All the blocks are read, or an error is returned.
82
83 @param This Indicates a pointer to the calling context.
84 @param MediaId The media ID that the read request is for.
85 @param Lba The starting logical block address to read from on the device.
86 @param BufferSize The size of the Buffer in bytes.
87 This must be a multiple of the intrinsic block size of the device.
88 @param Buffer A pointer to the destination buffer for the data. The caller is
89 responsible for either having implicit or explicit ownership of the buffer.
90
91 @retval EFI_SUCCESS The data was read correctly from the device.
92 @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
93 @retval EFI_NO_MEDIA There is no media in the device.
94 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
95 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
96 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
97 or the buffer is not on proper alignment.
98
99 **/
100 EFI_STATUS
101 EFIAPI
102 UsbMassReadBlocks (
103 IN EFI_BLOCK_IO_PROTOCOL *This,
104 IN UINT32 MediaId,
105 IN EFI_LBA Lba,
106 IN UINTN BufferSize,
107 OUT VOID *Buffer
108 )
109 {
110 USB_MASS_DEVICE *UsbMass;
111 EFI_BLOCK_IO_MEDIA *Media;
112 EFI_STATUS Status;
113 EFI_TPL OldTpl;
114 UINTN TotalBlock;
115
116 //
117 // First, validate the parameters
118 //
119 if ((Buffer == NULL) || (BufferSize == 0)) {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 //
124 // Raise TPL to TPL_NOTIFY to serialize all its operations
125 // to protect shared data structures.
126 //
127 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
128 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
129 Media = &UsbMass->BlockIoMedia;
130
131 //
132 // If it is a removable media, such as CD-Rom or Usb-Floppy,
133 // need to detect the media before each read/write. While some of
134 // Usb-Flash is marked as removable media.
135 //
136 if (Media->RemovableMedia) {
137 Status = UsbBootDetectMedia (UsbMass);
138 if (EFI_ERROR (Status)) {
139 goto ON_EXIT;
140 }
141 }
142
143 //
144 // BufferSize must be a multiple of the intrinsic block size of the device.
145 //
146 if ((BufferSize % Media->BlockSize) != 0) {
147 Status = EFI_BAD_BUFFER_SIZE;
148 goto ON_EXIT;
149 }
150
151 TotalBlock = BufferSize / Media->BlockSize;
152
153 //
154 // Make sure the range to read is valid.
155 //
156 if (Lba + TotalBlock - 1 > Media->LastBlock) {
157 Status = EFI_INVALID_PARAMETER;
158 goto ON_EXIT;
159 }
160
161 if (!(Media->MediaPresent)) {
162 Status = EFI_NO_MEDIA;
163 goto ON_EXIT;
164 }
165
166 if (MediaId != Media->MediaId) {
167 Status = EFI_MEDIA_CHANGED;
168 goto ON_EXIT;
169 }
170
171 Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
172 if (EFI_ERROR (Status)) {
173 DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
174 UsbMassReset (This, TRUE);
175 }
176
177 ON_EXIT:
178 gBS->RestoreTPL (OldTpl);
179 return Status;
180 }
181
182
183 /**
184 Writes a specified number of blocks to the device.
185
186 This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
187 It writes a specified number of blocks to the device.
188 All blocks are written, or an error is returned.
189
190 @param This Indicates a pointer to the calling context.
191 @param MediaId The media ID that the write request is for.
192 @param Lba The starting logical block address to be written.
193 @param BufferSize The size of the Buffer in bytes.
194 This must be a multiple of the intrinsic block size of the device.
195 @param Buffer Pointer to the source buffer for the data.
196
197 @retval EFI_SUCCESS The data were written correctly to the device.
198 @retval EFI_WRITE_PROTECTED The device cannot be written to.
199 @retval EFI_NO_MEDIA There is no media in the device.
200 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
201 @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
202 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
203 block size of the device.
204 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
205 or the buffer is not on proper alignment.
206
207 **/
208 EFI_STATUS
209 EFIAPI
210 UsbMassWriteBlocks (
211 IN EFI_BLOCK_IO_PROTOCOL *This,
212 IN UINT32 MediaId,
213 IN EFI_LBA Lba,
214 IN UINTN BufferSize,
215 IN VOID *Buffer
216 )
217 {
218 USB_MASS_DEVICE *UsbMass;
219 EFI_BLOCK_IO_MEDIA *Media;
220 EFI_STATUS Status;
221 EFI_TPL OldTpl;
222 UINTN TotalBlock;
223
224 //
225 // First, validate the parameters
226 //
227 if ((Buffer == NULL) || (BufferSize == 0)) {
228 return EFI_INVALID_PARAMETER;
229 }
230
231 //
232 // Raise TPL to TPL_NOTIFY to serialize all its operations
233 // to protect shared data structures.
234 //
235 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
236 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
237 Media = &UsbMass->BlockIoMedia;
238
239 //
240 // If it is a removable media, such as CD-Rom or Usb-Floppy,
241 // need to detect the media before each read/write. Some of
242 // USB Flash is marked as removable media.
243 //
244 if (Media->RemovableMedia) {
245 Status = UsbBootDetectMedia (UsbMass);
246 if (EFI_ERROR (Status)) {
247 goto ON_EXIT;
248 }
249 }
250
251 //
252 // BufferSize must be a multiple of the intrinsic block size of the device.
253 //
254 if ((BufferSize % Media->BlockSize) != 0) {
255 Status = EFI_BAD_BUFFER_SIZE;
256 goto ON_EXIT;
257 }
258
259 TotalBlock = BufferSize / Media->BlockSize;
260
261 //
262 // Make sure the range to write is valid.
263 //
264 if (Lba + TotalBlock - 1 > Media->LastBlock) {
265 Status = EFI_INVALID_PARAMETER;
266 goto ON_EXIT;
267 }
268
269 if (!(Media->MediaPresent)) {
270 Status = EFI_NO_MEDIA;
271 goto ON_EXIT;
272 }
273
274 if (MediaId != Media->MediaId) {
275 Status = EFI_MEDIA_CHANGED;
276 goto ON_EXIT;
277 }
278
279 //
280 // Try to write the data even the device is marked as ReadOnly,
281 // and clear the status should the write succeed.
282 //
283 Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
284 if (EFI_ERROR (Status)) {
285 DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
286 UsbMassReset (This, TRUE);
287 }
288
289 ON_EXIT:
290 gBS->RestoreTPL (OldTpl);
291 return Status;
292 }
293
294 /**
295 Flushes all modified data to a physical block device.
296
297 This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
298 USB mass storage device doesn't support write cache,
299 so return EFI_SUCCESS directly.
300
301 @param This Indicates a pointer to the calling context.
302
303 @retval EFI_SUCCESS All outstanding data were written correctly to the device.
304 @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
305 @retval EFI_NO_MEDIA There is no media in the device.
306
307 **/
308 EFI_STATUS
309 EFIAPI
310 UsbMassFlushBlocks (
311 IN EFI_BLOCK_IO_PROTOCOL *This
312 )
313 {
314 return EFI_SUCCESS;
315 }
316
317 /**
318 Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
319
320 @param UsbMass The USB mass storage device
321
322 @retval EFI_SUCCESS The media parameters are updated successfully.
323 @retval Others Failed to get the media parameters.
324
325 **/
326 EFI_STATUS
327 UsbMassInitMedia (
328 IN USB_MASS_DEVICE *UsbMass
329 )
330 {
331 EFI_BLOCK_IO_MEDIA *Media;
332 EFI_STATUS Status;
333 UINTN Index;
334
335 Media = &UsbMass->BlockIoMedia;
336
337 //
338 // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
339 // section for Block I/O Protocol.
340 //
341 Media->MediaPresent = FALSE;
342 Media->LogicalPartition = FALSE;
343 Media->ReadOnly = FALSE;
344 Media->WriteCaching = FALSE;
345 Media->IoAlign = 0;
346 Media->MediaId = 1;
347
348 //
349 // Some device may spend several seconds before it is ready.
350 // Try several times before giving up. Wait 5s at most.
351 //
352 Status = EFI_SUCCESS;
353
354 for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
355
356 Status = UsbBootGetParams (UsbMass);
357 if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_NOT_READY) && (Status != EFI_TIMEOUT)) {
358 break;
359 }
360
361 Status = UsbBootIsUnitReady (UsbMass);
362 if (EFI_ERROR (Status)) {
363 gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
364 }
365 }
366
367 return Status;
368 }
369
370 /**
371 Initilize the USB Mass Storage transport.
372
373 This function tries to find the matching USB Mass Storage transport
374 protocol for USB device. If found, initializes the matching transport.
375
376 @param This The USB mass driver's driver binding.
377 @param Controller The device to test.
378 @param Transport The pointer to pointer to USB_MASS_TRANSPORT.
379 @param Context The passing parameter.
380 @param MaxLun Get the MaxLun if is BOT dev.
381
382 @retval EFI_SUCCESS The initialization is successful.
383 @retval EFI_UNSUPPORTED No matching transport protocol is found.
384 @retval Others Failed to initialize dev.
385
386 **/
387 EFI_STATUS
388 UsbMassInitTransport (
389 IN EFI_DRIVER_BINDING_PROTOCOL *This,
390 IN EFI_HANDLE Controller,
391 OUT USB_MASS_TRANSPORT **Transport,
392 OUT VOID **Context,
393 OUT UINT8 *MaxLun
394 )
395 {
396 EFI_USB_IO_PROTOCOL *UsbIo;
397 EFI_USB_INTERFACE_DESCRIPTOR Interface;
398 UINT8 Index;
399 EFI_STATUS Status;
400
401 Status = gBS->OpenProtocol (
402 Controller,
403 &gEfiUsbIoProtocolGuid,
404 (VOID **) &UsbIo,
405 This->DriverBindingHandle,
406 Controller,
407 EFI_OPEN_PROTOCOL_BY_DRIVER
408 );
409
410 if (EFI_ERROR (Status)) {
411 return Status;
412 }
413
414 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
415 if (EFI_ERROR (Status)) {
416 goto ON_EXIT;
417 }
418
419 Status = EFI_UNSUPPORTED;
420
421 //
422 // Traverse the USB_MASS_TRANSPORT arrary and try to find the
423 // matching transport protocol.
424 // If not found, return EFI_UNSUPPORTED.
425 // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
426 //
427 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
428 *Transport = mUsbMassTransport[Index];
429
430 if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
431 Status = (*Transport)->Init (UsbIo, Context);
432 break;
433 }
434 }
435
436 if (EFI_ERROR (Status)) {
437 goto ON_EXIT;
438 }
439
440 //
441 // For BOT device, try to get its max LUN.
442 // If max LUN is 0, then it is a non-lun device.
443 // Otherwise, it is a multi-lun device.
444 //
445 if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
446 (*Transport)->GetMaxLun (*Context, MaxLun);
447 }
448
449 ON_EXIT:
450 gBS->CloseProtocol (
451 Controller,
452 &gEfiUsbIoProtocolGuid,
453 This->DriverBindingHandle,
454 Controller
455 );
456 return Status;
457 }
458
459 /**
460 Usb mass storage driver initializes multi lun.
461
462 @param This The USB mass driver's driver binding.
463 @param Controller The device to test.
464 @param Transport The pointer to USB_MASS_TRANSPORT.
465 @param Context The passing parameter.
466 @param DevicePath The remaining device path
467 @param MaxLun The MaxLun number passed.
468
469 @retval EFI_SUCCESS Initialization is success.
470 @retval Other Initialization fails.
471
472 **/
473 EFI_STATUS
474 UsbMassInitMultiLun (
475 IN EFI_DRIVER_BINDING_PROTOCOL *This,
476 IN EFI_HANDLE Controller,
477 IN USB_MASS_TRANSPORT *Transport,
478 IN VOID *Context,
479 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
480 IN UINT8 MaxLun
481 )
482 {
483 USB_MASS_DEVICE *UsbMass;
484 EFI_USB_IO_PROTOCOL *UsbIo;
485 DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
486 UINT8 Index;
487 EFI_STATUS Status;
488
489 ASSERT (MaxLun > 0);
490
491 for (Index = 0; Index <= MaxLun; Index++) {
492
493 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
494
495 UsbIo = NULL;
496 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
497 if (UsbMass == NULL) {
498 Status = EFI_OUT_OF_RESOURCES;
499 goto ON_ERROR;
500 }
501
502 UsbMass->Signature = USB_MASS_SIGNATURE;
503 UsbMass->UsbIo = UsbIo;
504 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
505 UsbMass->BlockIo.Reset = UsbMassReset;
506 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
507 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
508 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
509 UsbMass->OpticalStorage = FALSE;
510 UsbMass->Transport = Transport;
511 UsbMass->Context = Context;
512 UsbMass->Lun = Index;
513
514 //
515 // Get the storage's parameters, such as last block number.
516 // then install the BLOCK_IO
517 //
518 Status = UsbMassInitMedia (UsbMass);
519 if (!EFI_ERROR (Status)) {
520 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
521 (UsbMass->Pdt != USB_PDT_CDROM) &&
522 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
523 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
524 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
525 goto ON_ERROR;
526 }
527 } else if (Status != EFI_NO_MEDIA){
528 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
529 goto ON_ERROR;
530 }
531
532 //
533 // Create a device path node of device logic unit, and append it
534 //
535 LunNode.Header.Type = MESSAGING_DEVICE_PATH;
536 LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
537 LunNode.Lun = UsbMass->Lun;
538
539 SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
540
541 UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
542
543 if (UsbMass->DevicePath == NULL) {
544 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
545
546 Status = EFI_OUT_OF_RESOURCES;
547 goto ON_ERROR;
548 }
549
550 //
551 // Create a UsbMass handle for each lun, and install blockio and devicepath protocols.
552 //
553 Status = gBS->InstallMultipleProtocolInterfaces (
554 &UsbMass->Controller,
555 &gEfiDevicePathProtocolGuid,
556 UsbMass->DevicePath,
557 &gEfiBlockIoProtocolGuid,
558 &UsbMass->BlockIo,
559 NULL
560 );
561
562 if (EFI_ERROR (Status)) {
563 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
564 goto ON_ERROR;
565 }
566
567 //
568 // Open UsbIo protocol by child to setup a parent-child relationship.
569 //
570 Status = gBS->OpenProtocol (
571 Controller,
572 &gEfiUsbIoProtocolGuid,
573 (VOID **) &UsbIo,
574 This->DriverBindingHandle,
575 UsbMass->Controller,
576 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
577 );
578
579 if (EFI_ERROR (Status)) {
580 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
581 gBS->UninstallMultipleProtocolInterfaces (
582 &UsbMass->Controller,
583 &gEfiDevicePathProtocolGuid,
584 UsbMass->DevicePath,
585 &gEfiBlockIoProtocolGuid,
586 &UsbMass->BlockIo,
587 NULL
588 );
589 goto ON_ERROR;
590 }
591
592 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
593 }
594
595 return EFI_SUCCESS;
596
597 ON_ERROR:
598 if (UsbMass->DevicePath != NULL) {
599 gBS->FreePool (UsbMass->DevicePath);
600 }
601 if (UsbMass != NULL) {
602 gBS->FreePool (UsbMass);
603 }
604 if (UsbIo != NULL) {
605 gBS->CloseProtocol (
606 Controller,
607 &gEfiUsbIoProtocolGuid,
608 This->DriverBindingHandle,
609 UsbMass->Controller
610 );
611 }
612
613 //
614 // If only success to initialize one lun, return success, or else return error
615 //
616 if (Index > 0) {
617 return EFI_SUCCESS;
618 } else {
619 return Status;
620 }
621 }
622
623 /**
624 Initialize No/Unsupported LUN device.
625
626 @param This The USB mass driver's driver binding.
627 @param Controller The device to test.
628 @param Transport The pointer to USB_MASS_TRANSPORT.
629 @param Context The passing parameter.
630
631 @retval EFI_SUCCESS Initialization is success.
632 @retval Other Initialization fails.
633
634 **/
635 EFI_STATUS
636 UsbMassInitNonLun (
637 IN EFI_DRIVER_BINDING_PROTOCOL *This,
638 IN EFI_HANDLE Controller,
639 IN USB_MASS_TRANSPORT *Transport,
640 IN VOID *Context
641 )
642 {
643 USB_MASS_DEVICE *UsbMass;
644 EFI_USB_IO_PROTOCOL *UsbIo;
645 EFI_STATUS Status;
646
647 UsbIo = NULL;
648 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
649 if (UsbMass == NULL) {
650 return EFI_OUT_OF_RESOURCES;
651 }
652 Status = gBS->OpenProtocol (
653 Controller,
654 &gEfiUsbIoProtocolGuid,
655 (VOID **) &UsbIo,
656 This->DriverBindingHandle,
657 Controller,
658 EFI_OPEN_PROTOCOL_BY_DRIVER
659 );
660
661 if (EFI_ERROR (Status)) {
662 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
663 goto ON_ERROR;
664 }
665
666 UsbMass->Signature = USB_MASS_SIGNATURE;
667 UsbMass->Controller = Controller;
668 UsbMass->UsbIo = UsbIo;
669 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
670 UsbMass->BlockIo.Reset = UsbMassReset;
671 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
672 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
673 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
674 UsbMass->OpticalStorage = FALSE;
675 UsbMass->Transport = Transport;
676 UsbMass->Context = Context;
677
678 //
679 // Get the storage's parameters, such as last block number.
680 // then install the BLOCK_IO
681 //
682 Status = UsbMassInitMedia (UsbMass);
683 if (!EFI_ERROR (Status)) {
684 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
685 (UsbMass->Pdt != USB_PDT_CDROM) &&
686 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
687 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
688 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
689 goto ON_ERROR;
690 }
691 } else if (Status != EFI_NO_MEDIA){
692 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
693 goto ON_ERROR;
694 }
695
696 Status = gBS->InstallProtocolInterface (
697 &Controller,
698 &gEfiBlockIoProtocolGuid,
699 EFI_NATIVE_INTERFACE,
700 &UsbMass->BlockIo
701 );
702 if (EFI_ERROR (Status)) {
703 goto ON_ERROR;
704 }
705
706 return EFI_SUCCESS;
707
708 ON_ERROR:
709 if (UsbMass != NULL) {
710 gBS->FreePool (UsbMass);
711 }
712 gBS->CloseProtocol (
713 Controller,
714 &gEfiUsbIoProtocolGuid,
715 This->DriverBindingHandle,
716 Controller
717 );
718 return Status;
719 }
720
721
722 /**
723 Check whether the controller is a supported USB mass storage.
724
725 @param This The USB mass storage driver binding protocol.
726 @param Controller The controller handle to check.
727 @param RemainingDevicePath The remaining device path.
728
729 @retval EFI_SUCCESS The driver supports this controller.
730 @retval other This device isn't supported.
731
732 **/
733 EFI_STATUS
734 EFIAPI
735 USBMassDriverBindingSupported (
736 IN EFI_DRIVER_BINDING_PROTOCOL *This,
737 IN EFI_HANDLE Controller,
738 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
739 )
740 {
741 EFI_USB_IO_PROTOCOL *UsbIo;
742 EFI_USB_INTERFACE_DESCRIPTOR Interface;
743 USB_MASS_TRANSPORT *Transport;
744 EFI_STATUS Status;
745 UINTN Index;
746
747 Status = gBS->OpenProtocol (
748 Controller,
749 &gEfiUsbIoProtocolGuid,
750 (VOID **) &UsbIo,
751 This->DriverBindingHandle,
752 Controller,
753 EFI_OPEN_PROTOCOL_BY_DRIVER
754 );
755 if (EFI_ERROR (Status)) {
756 return Status;
757 }
758
759 //
760 // Get the interface descriptor to check the USB class and find a transport
761 // protocol handler.
762 //
763 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
764 if (EFI_ERROR (Status)) {
765 goto ON_EXIT;
766 }
767
768 Status = EFI_UNSUPPORTED;
769
770 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
771 goto ON_EXIT;
772 }
773
774 //
775 // Traverse the USB_MASS_TRANSPORT arrary and try to find the
776 // matching transport method.
777 // If not found, return EFI_UNSUPPORTED.
778 // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
779 //
780 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
781 Transport = mUsbMassTransport[Index];
782 if (Interface.InterfaceProtocol == Transport->Protocol) {
783 Status = Transport->Init (UsbIo, NULL);
784 break;
785 }
786 }
787
788 ON_EXIT:
789 gBS->CloseProtocol (
790 Controller,
791 &gEfiUsbIoProtocolGuid,
792 This->DriverBindingHandle,
793 Controller
794 );
795
796 return Status;
797 }
798
799
800 /**
801 Starts the USB mass storage device with this driver.
802
803 This function consumes USB I/O Portocol, intializes USB mass storage device,
804 installs Block I/O Protocol, and submits Asynchronous Interrupt
805 Transfer to manage the USB mass storage device.
806
807 @param This The USB mass storage driver binding protocol.
808 @param Controller The USB mass storage device to start on
809 @param RemainingDevicePath The remaining device path.
810
811 @retval EFI_SUCCESS This driver supports this device.
812 @retval EFI_UNSUPPORTED This driver does not support this device.
813 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
814 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
815 @retval EFI_ALREADY_STARTED This driver has been started.
816
817 **/
818 EFI_STATUS
819 EFIAPI
820 USBMassDriverBindingStart (
821 IN EFI_DRIVER_BINDING_PROTOCOL *This,
822 IN EFI_HANDLE Controller,
823 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
824 )
825 {
826 USB_MASS_TRANSPORT *Transport;
827 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
828 VOID *Context;
829 UINT8 MaxLun;
830 EFI_STATUS Status;
831
832 Transport = NULL;
833 Context = NULL;
834 MaxLun = 0;
835
836 //
837 // Get interface and protocols, initialize transport
838 //
839 Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
840
841 if (EFI_ERROR (Status)) {
842 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
843 return Status;
844 }
845 if (MaxLun == 0) {
846 //
847 // Initialize No/Unsupported LUN device
848 //
849 Status = UsbMassInitNonLun(This, Controller, Transport, Context);
850 if (EFI_ERROR (Status)) {
851 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
852 }
853 } else {
854 //
855 // Open device path to prepare append Device Logic Unit node.
856 //
857 Status = gBS->OpenProtocol (
858 Controller,
859 &gEfiDevicePathProtocolGuid,
860 (VOID **) &DevicePath,
861 This->DriverBindingHandle,
862 Controller,
863 EFI_OPEN_PROTOCOL_BY_DRIVER
864 );
865
866 if (EFI_ERROR (Status)) {
867 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
868 return Status;
869 }
870
871 //
872 // Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized.
873 //
874 Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
875 if (EFI_ERROR (Status)) {
876 gBS->CloseProtocol (
877 Controller,
878 &gEfiDevicePathProtocolGuid,
879 This->DriverBindingHandle,
880 Controller
881 );
882 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
883 }
884 }
885 return Status;
886 }
887
888
889 /**
890 Stop controlling the device.
891
892 @param This The USB mass storage driver binding
893 @param Controller The device controller controlled by the driver.
894 @param NumberOfChildren The number of children of this device
895 @param ChildHandleBuffer The buffer of children handle.
896
897 @retval EFI_SUCCESS The driver stopped from controlling the device.
898 @retval Others Failed to stop the driver
899
900 **/
901 EFI_STATUS
902 EFIAPI
903 USBMassDriverBindingStop (
904 IN EFI_DRIVER_BINDING_PROTOCOL *This,
905 IN EFI_HANDLE Controller,
906 IN UINTN NumberOfChildren,
907 IN EFI_HANDLE *ChildHandleBuffer
908 )
909 {
910 EFI_STATUS Status;
911 USB_MASS_DEVICE *UsbMass;
912 EFI_USB_IO_PROTOCOL *UsbIo;
913 EFI_BLOCK_IO_PROTOCOL *BlockIo;
914 UINTN Index;
915 BOOLEAN AllChildrenStopped;
916
917 //
918 // This a bus driver stop function since multi-lun supported. There are three
919 // kinds of device handle might be passed, 1st is a handle with devicepath/
920 // usbio/blockio installed(non-multi-lun), 2nd is a handle with devicepath/
921 // usbio installed(multi-lun root), 3rd is a handle with devicepath/blockio
922 // installed(multi-lun).
923 //
924 if (NumberOfChildren == 0) {
925 //
926 // A handle without any children, might be 1st and 2nd type.
927 //
928 Status = gBS->OpenProtocol (
929 Controller,
930 &gEfiBlockIoProtocolGuid,
931 (VOID **) &BlockIo,
932 This->DriverBindingHandle,
933 Controller,
934 EFI_OPEN_PROTOCOL_GET_PROTOCOL
935 );
936
937 if (EFI_ERROR(Status)) {
938 //
939 // This is a 2nd type handle(multi-lun root), which only needs close
940 // devicepath protocol.
941 //
942 gBS->CloseProtocol (
943 Controller,
944 &gEfiDevicePathProtocolGuid,
945 This->DriverBindingHandle,
946 Controller
947 );
948 DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
949 return EFI_SUCCESS;
950 }
951
952 //
953 // This is a 1st type handle(non-multi-lun), which only needs uninstall
954 // blockio protocol, close usbio protocol and free mass device.
955 //
956 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
957
958 //
959 // Uninstall Block I/O protocol from the device handle,
960 // then call the transport protocol to stop itself.
961 //
962 Status = gBS->UninstallProtocolInterface (
963 Controller,
964 &gEfiBlockIoProtocolGuid,
965 &UsbMass->BlockIo
966 );
967 if (EFI_ERROR (Status)) {
968 return Status;
969 }
970
971 gBS->CloseProtocol (
972 Controller,
973 &gEfiUsbIoProtocolGuid,
974 This->DriverBindingHandle,
975 Controller
976 );
977
978 UsbMass->Transport->CleanUp (UsbMass->Context);
979 gBS->FreePool (UsbMass);
980
981 DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
982 return EFI_SUCCESS;
983 }
984
985 //
986 // This is a 3rd type handle(multi-lun), which needs uninstall
987 // blockio and devicepath protocol, close usbio protocol and
988 // free mass device.
989 //
990 AllChildrenStopped = TRUE;
991
992 for (Index = 0; Index < NumberOfChildren; Index++) {
993
994 Status = gBS->OpenProtocol (
995 ChildHandleBuffer[Index],
996 &gEfiBlockIoProtocolGuid,
997 (VOID **) &BlockIo,
998 This->DriverBindingHandle,
999 Controller,
1000 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1001 );
1002 if (EFI_ERROR (Status)) {
1003 AllChildrenStopped = FALSE;
1004 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
1005 continue;
1006 }
1007
1008 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
1009
1010 gBS->CloseProtocol (
1011 Controller,
1012 &gEfiUsbIoProtocolGuid,
1013 This->DriverBindingHandle,
1014 ChildHandleBuffer[Index]
1015 );
1016
1017 Status = gBS->UninstallMultipleProtocolInterfaces (
1018 ChildHandleBuffer[Index],
1019 &gEfiDevicePathProtocolGuid,
1020 UsbMass->DevicePath,
1021 &gEfiBlockIoProtocolGuid,
1022 &UsbMass->BlockIo,
1023 NULL
1024 );
1025
1026 if (EFI_ERROR (Status)) {
1027 //
1028 // Fail to uninstall blockio and devicepath protocol, so re-open usbio by child.
1029 //
1030 AllChildrenStopped = FALSE;
1031 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
1032
1033 gBS->OpenProtocol (
1034 Controller,
1035 &gEfiUsbIoProtocolGuid,
1036 (VOID **) &UsbIo,
1037 This->DriverBindingHandle,
1038 ChildHandleBuffer[Index],
1039 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1040 );
1041 } else {
1042 //
1043 // Success to stop this multi-lun handle, so go on next child.
1044 //
1045 if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
1046 UsbMass->Transport->CleanUp (UsbMass->Context);
1047 }
1048 gBS->FreePool (UsbMass);
1049 }
1050 }
1051
1052 if (!AllChildrenStopped) {
1053 return EFI_DEVICE_ERROR;
1054 }
1055
1056 DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32)NumberOfChildren));
1057 return EFI_SUCCESS;
1058 }
1059
1060 /**
1061 The entry point for the driver, which will install the driver binding and
1062 component name protocol.
1063
1064 @param ImageHandle The image handle of this driver.
1065 @param SystemTable The system table.
1066
1067 @retval EFI_SUCCESS The protocols are installed OK.
1068 @retval Others Failed to install protocols.
1069
1070 **/
1071 EFI_STATUS
1072 EFIAPI
1073 USBMassStorageEntryPoint (
1074 IN EFI_HANDLE ImageHandle,
1075 IN EFI_SYSTEM_TABLE *SystemTable
1076 )
1077 {
1078 EFI_STATUS Status;
1079
1080 //
1081 // Install driver binding protocol
1082 //
1083 Status = EfiLibInstallDriverBindingComponentName2 (
1084 ImageHandle,
1085 SystemTable,
1086 &gUSBMassDriverBinding,
1087 ImageHandle,
1088 &gUsbMassStorageComponentName,
1089 &gUsbMassStorageComponentName2
1090 );
1091 ASSERT_EFI_ERROR (Status);
1092
1093 return EFI_SUCCESS;
1094 }