]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
f440e9fd7c5f78820afbce67ed165630a94a26c3
[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. All rights reserved.<BR>
5 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 #define USB_MASS_TRANSPORT_COUNT 3
18 //
19 // Array of USB transport interfaces.
20 //
21 USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
22 &mUsbCbi0Transport,
23 &mUsbCbi1Transport,
24 &mUsbBotTransport,
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 parameter for USB_MASS_DEVICE.Context.
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; Index < USB_MASS_TRANSPORT_COUNT; 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 Initialize data for device that supports multiple LUNSs.
461
462 @param This The Driver Binding Protocol instance.
463 @param Controller The device to initialize.
464 @param Transport Pointer to USB_MASS_TRANSPORT.
465 @param Context Parameter for USB_MASS_DEVICE.Context.
466 @param DevicePath The remaining device path.
467 @param MaxLun The max LUN number.
468
469 @retval EFI_SUCCESS At least one LUN is initialized successfully.
470 @retval EFI_OUT_OF_RESOURCES Out of resource while creating device path node.
471 @retval Other Initialization fails.
472
473 **/
474 EFI_STATUS
475 UsbMassInitMultiLun (
476 IN EFI_DRIVER_BINDING_PROTOCOL *This,
477 IN EFI_HANDLE Controller,
478 IN USB_MASS_TRANSPORT *Transport,
479 IN VOID *Context,
480 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
481 IN UINT8 MaxLun
482 )
483 {
484 USB_MASS_DEVICE *UsbMass;
485 EFI_USB_IO_PROTOCOL *UsbIo;
486 DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
487 UINT8 Index;
488 EFI_STATUS Status;
489
490 ASSERT (MaxLun > 0);
491
492 for (Index = 0; Index <= MaxLun; Index++) {
493
494 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
495
496 UsbIo = NULL;
497 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
498 ASSERT (UsbMass != NULL);
499
500 UsbMass->Signature = USB_MASS_SIGNATURE;
501 UsbMass->UsbIo = UsbIo;
502 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
503 UsbMass->BlockIo.Reset = UsbMassReset;
504 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
505 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
506 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
507 UsbMass->OpticalStorage = FALSE;
508 UsbMass->Transport = Transport;
509 UsbMass->Context = Context;
510 UsbMass->Lun = Index;
511
512 //
513 // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
514 //
515 Status = UsbMassInitMedia (UsbMass);
516 if (!EFI_ERROR (Status)) {
517 //
518 // According to USB Mass Storage Specification for Bootability, only following
519 // 4 Peripheral Device Types are in spec.
520 //
521 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
522 (UsbMass->Pdt != USB_PDT_CDROM) &&
523 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
524 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
525 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
526 goto ON_ERROR;
527 }
528 } else if (Status != EFI_NO_MEDIA){
529 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
530 goto ON_ERROR;
531 }
532
533 //
534 // Create a device path node for device logic unit, and append it.
535 //
536 LunNode.Header.Type = MESSAGING_DEVICE_PATH;
537 LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
538 LunNode.Lun = UsbMass->Lun;
539
540 SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
541
542 UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
543
544 if (UsbMass->DevicePath == NULL) {
545 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
546
547 Status = EFI_OUT_OF_RESOURCES;
548 goto ON_ERROR;
549 }
550
551 //
552 // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
553 //
554 Status = gBS->InstallMultipleProtocolInterfaces (
555 &UsbMass->Controller,
556 &gEfiDevicePathProtocolGuid,
557 UsbMass->DevicePath,
558 &gEfiBlockIoProtocolGuid,
559 &UsbMass->BlockIo,
560 NULL
561 );
562
563 if (EFI_ERROR (Status)) {
564 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
565 goto ON_ERROR;
566 }
567
568 //
569 // Open USB I/O Protocol by child to setup a parent-child relationship.
570 //
571 Status = gBS->OpenProtocol (
572 Controller,
573 &gEfiUsbIoProtocolGuid,
574 (VOID **) &UsbIo,
575 This->DriverBindingHandle,
576 UsbMass->Controller,
577 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
578 );
579
580 if (EFI_ERROR (Status)) {
581 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
582 gBS->UninstallMultipleProtocolInterfaces (
583 &UsbMass->Controller,
584 &gEfiDevicePathProtocolGuid,
585 UsbMass->DevicePath,
586 &gEfiBlockIoProtocolGuid,
587 &UsbMass->BlockIo,
588 NULL
589 );
590 goto ON_ERROR;
591 }
592
593 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
594 }
595
596 return EFI_SUCCESS;
597
598 ON_ERROR:
599 if (UsbMass != NULL) {
600 if (UsbMass->DevicePath != NULL) {
601 FreePool (UsbMass->DevicePath);
602 }
603 FreePool (UsbMass);
604 }
605 if (UsbIo != NULL) {
606 gBS->CloseProtocol (
607 Controller,
608 &gEfiUsbIoProtocolGuid,
609 This->DriverBindingHandle,
610 UsbMass->Controller
611 );
612 }
613
614 //
615 // Return EFI_SUCCESS if at least one LUN is initialized successfully.
616 //
617 if (Index > 0) {
618 return EFI_SUCCESS;
619 } else {
620 return Status;
621 }
622 }
623
624 /**
625 Initialize data for device that does not support multiple LUNSs.
626
627 @param This The Driver Binding Protocol instance.
628 @param Controller The device to initialize.
629 @param Transport Pointer to USB_MASS_TRANSPORT.
630 @param Context Parameter for USB_MASS_DEVICE.Context.
631
632 @retval EFI_SUCCESS Initialization succeeds.
633 @retval Other Initialization fails.
634
635 **/
636 EFI_STATUS
637 UsbMassInitNonLun (
638 IN EFI_DRIVER_BINDING_PROTOCOL *This,
639 IN EFI_HANDLE Controller,
640 IN USB_MASS_TRANSPORT *Transport,
641 IN VOID *Context
642 )
643 {
644 USB_MASS_DEVICE *UsbMass;
645 EFI_USB_IO_PROTOCOL *UsbIo;
646 EFI_STATUS Status;
647
648 UsbIo = NULL;
649 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
650 ASSERT (UsbMass != NULL);
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 // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
680 //
681 Status = UsbMassInitMedia (UsbMass);
682 if (!EFI_ERROR (Status)) {
683 //
684 // According to USB Mass Storage Specification for Bootability, only following
685 // 4 Peripheral Device Types are in spec.
686 //
687 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
688 (UsbMass->Pdt != USB_PDT_CDROM) &&
689 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
690 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
691 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
692 goto ON_ERROR;
693 }
694 } else if (Status != EFI_NO_MEDIA){
695 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
696 goto ON_ERROR;
697 }
698
699 Status = gBS->InstallProtocolInterface (
700 &Controller,
701 &gEfiBlockIoProtocolGuid,
702 EFI_NATIVE_INTERFACE,
703 &UsbMass->BlockIo
704 );
705 if (EFI_ERROR (Status)) {
706 goto ON_ERROR;
707 }
708
709 return EFI_SUCCESS;
710
711 ON_ERROR:
712 if (UsbMass != NULL) {
713 FreePool (UsbMass);
714 }
715 if (UsbIo != NULL) {
716 gBS->CloseProtocol (
717 Controller,
718 &gEfiUsbIoProtocolGuid,
719 This->DriverBindingHandle,
720 Controller
721 );
722 }
723 return Status;
724 }
725
726
727 /**
728 Check whether the controller is a supported USB mass storage.
729
730 @param This The USB mass storage driver binding protocol.
731 @param Controller The controller handle to check.
732 @param RemainingDevicePath The remaining device path.
733
734 @retval EFI_SUCCESS The driver supports this controller.
735 @retval other This device isn't supported.
736
737 **/
738 EFI_STATUS
739 EFIAPI
740 USBMassDriverBindingSupported (
741 IN EFI_DRIVER_BINDING_PROTOCOL *This,
742 IN EFI_HANDLE Controller,
743 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
744 )
745 {
746 EFI_USB_IO_PROTOCOL *UsbIo;
747 EFI_USB_INTERFACE_DESCRIPTOR Interface;
748 USB_MASS_TRANSPORT *Transport;
749 EFI_STATUS Status;
750 UINTN Index;
751
752 Status = gBS->OpenProtocol (
753 Controller,
754 &gEfiUsbIoProtocolGuid,
755 (VOID **) &UsbIo,
756 This->DriverBindingHandle,
757 Controller,
758 EFI_OPEN_PROTOCOL_BY_DRIVER
759 );
760 if (EFI_ERROR (Status)) {
761 return Status;
762 }
763
764 //
765 // Get the interface descriptor to check the USB class and find a transport
766 // protocol handler.
767 //
768 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
769 if (EFI_ERROR (Status)) {
770 goto ON_EXIT;
771 }
772
773 Status = EFI_UNSUPPORTED;
774
775 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
776 goto ON_EXIT;
777 }
778
779 //
780 // Traverse the USB_MASS_TRANSPORT arrary and try to find the
781 // matching transport method.
782 // If not found, return EFI_UNSUPPORTED.
783 // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
784 //
785 for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
786 Transport = mUsbMassTransport[Index];
787 if (Interface.InterfaceProtocol == Transport->Protocol) {
788 Status = Transport->Init (UsbIo, NULL);
789 break;
790 }
791 }
792
793 ON_EXIT:
794 gBS->CloseProtocol (
795 Controller,
796 &gEfiUsbIoProtocolGuid,
797 This->DriverBindingHandle,
798 Controller
799 );
800
801 return Status;
802 }
803
804 /**
805 Starts the USB mass storage device with this driver.
806
807 This function consumes USB I/O Portocol, intializes USB mass storage device,
808 installs Block I/O Protocol, and submits Asynchronous Interrupt
809 Transfer to manage the USB mass storage device.
810
811 @param This The USB mass storage driver binding protocol.
812 @param Controller The USB mass storage device to start on
813 @param RemainingDevicePath The remaining device path.
814
815 @retval EFI_SUCCESS This driver supports this device.
816 @retval EFI_UNSUPPORTED This driver does not support this device.
817 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
818 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
819 @retval EFI_ALREADY_STARTED This driver has been started.
820
821 **/
822 EFI_STATUS
823 EFIAPI
824 USBMassDriverBindingStart (
825 IN EFI_DRIVER_BINDING_PROTOCOL *This,
826 IN EFI_HANDLE Controller,
827 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
828 )
829 {
830 USB_MASS_TRANSPORT *Transport;
831 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
832 VOID *Context;
833 UINT8 MaxLun;
834 EFI_STATUS Status;
835 EFI_USB_IO_PROTOCOL *UsbIo;
836 EFI_TPL OldTpl;
837
838 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
839
840 Transport = NULL;
841 Context = NULL;
842 MaxLun = 0;
843
844 Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
845
846 if (EFI_ERROR (Status)) {
847 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
848 goto Exit;
849 }
850 if (MaxLun == 0) {
851 //
852 // Initialize data for device that does not support multiple LUNSs.
853 //
854 Status = UsbMassInitNonLun (This, Controller, Transport, Context);
855 if (EFI_ERROR (Status)) {
856 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
857 }
858 } else {
859 //
860 // Open device path to prepare for appending Device Logic Unit node.
861 //
862 Status = gBS->OpenProtocol (
863 Controller,
864 &gEfiDevicePathProtocolGuid,
865 (VOID **) &DevicePath,
866 This->DriverBindingHandle,
867 Controller,
868 EFI_OPEN_PROTOCOL_BY_DRIVER
869 );
870
871 if (EFI_ERROR (Status)) {
872 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
873 goto Exit;
874 }
875
876 Status = gBS->OpenProtocol (
877 Controller,
878 &gEfiUsbIoProtocolGuid,
879 (VOID **) &UsbIo,
880 This->DriverBindingHandle,
881 Controller,
882 EFI_OPEN_PROTOCOL_BY_DRIVER
883 );
884
885 if (EFI_ERROR (Status)) {
886 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
887 gBS->CloseProtocol (
888 Controller,
889 &gEfiDevicePathProtocolGuid,
890 This->DriverBindingHandle,
891 Controller
892 );
893 goto Exit;
894 }
895
896 //
897 // Initialize data for device that supports multiple LUNSs.
898 // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
899 //
900 Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
901 if (EFI_ERROR (Status)) {
902 gBS->CloseProtocol (
903 Controller,
904 &gEfiDevicePathProtocolGuid,
905 This->DriverBindingHandle,
906 Controller
907 );
908 gBS->CloseProtocol (
909 Controller,
910 &gEfiUsbIoProtocolGuid,
911 This->DriverBindingHandle,
912 Controller
913 );
914 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
915 }
916 }
917 Exit:
918 gBS->RestoreTPL (OldTpl);
919 return Status;
920 }
921
922
923 /**
924 Stop controlling the device.
925
926 @param This The USB mass storage driver binding
927 @param Controller The device controller controlled by the driver.
928 @param NumberOfChildren The number of children of this device
929 @param ChildHandleBuffer The buffer of children handle.
930
931 @retval EFI_SUCCESS The driver stopped from controlling the device.
932 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
933 @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
934 @retval Others Failed to stop the driver
935
936 **/
937 EFI_STATUS
938 EFIAPI
939 USBMassDriverBindingStop (
940 IN EFI_DRIVER_BINDING_PROTOCOL *This,
941 IN EFI_HANDLE Controller,
942 IN UINTN NumberOfChildren,
943 IN EFI_HANDLE *ChildHandleBuffer
944 )
945 {
946 EFI_STATUS Status;
947 USB_MASS_DEVICE *UsbMass;
948 EFI_USB_IO_PROTOCOL *UsbIo;
949 EFI_BLOCK_IO_PROTOCOL *BlockIo;
950 UINTN Index;
951 BOOLEAN AllChildrenStopped;
952
953 //
954 // This is a bus driver stop function since multi-lun is supported.
955 // There are three kinds of device handles that might be passed:
956 // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
957 // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
958 // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
959 //
960 if (NumberOfChildren == 0) {
961 //
962 // A handle without any children, might be 1st and 2nd type.
963 //
964 Status = gBS->OpenProtocol (
965 Controller,
966 &gEfiBlockIoProtocolGuid,
967 (VOID **) &BlockIo,
968 This->DriverBindingHandle,
969 Controller,
970 EFI_OPEN_PROTOCOL_GET_PROTOCOL
971 );
972
973 if (EFI_ERROR(Status)) {
974 //
975 // This is a 2nd type handle(multi-lun root), it needs to close devicepath
976 // and usbio protocol.
977 //
978 gBS->CloseProtocol (
979 Controller,
980 &gEfiDevicePathProtocolGuid,
981 This->DriverBindingHandle,
982 Controller
983 );
984 gBS->CloseProtocol (
985 Controller,
986 &gEfiUsbIoProtocolGuid,
987 This->DriverBindingHandle,
988 Controller
989 );
990 DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
991 return EFI_SUCCESS;
992 }
993
994 //
995 // This is a 1st type handle(non-multi-lun), which only needs to uninstall
996 // Block I/O Protocol, close USB I/O Protocol and free mass device.
997 //
998 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
999
1000 //
1001 // Uninstall Block I/O protocol from the device handle,
1002 // then call the transport protocol to stop itself.
1003 //
1004 Status = gBS->UninstallProtocolInterface (
1005 Controller,
1006 &gEfiBlockIoProtocolGuid,
1007 &UsbMass->BlockIo
1008 );
1009 if (EFI_ERROR (Status)) {
1010 return Status;
1011 }
1012
1013 gBS->CloseProtocol (
1014 Controller,
1015 &gEfiUsbIoProtocolGuid,
1016 This->DriverBindingHandle,
1017 Controller
1018 );
1019
1020 UsbMass->Transport->CleanUp (UsbMass->Context);
1021 FreePool (UsbMass);
1022
1023 DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
1024 return EFI_SUCCESS;
1025 }
1026
1027 //
1028 // This is a 3rd type handle(multi-lun), which needs uninstall
1029 // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
1030 // free mass device for all children.
1031 //
1032 AllChildrenStopped = TRUE;
1033
1034 for (Index = 0; Index < NumberOfChildren; Index++) {
1035
1036 Status = gBS->OpenProtocol (
1037 ChildHandleBuffer[Index],
1038 &gEfiBlockIoProtocolGuid,
1039 (VOID **) &BlockIo,
1040 This->DriverBindingHandle,
1041 Controller,
1042 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1043 );
1044 if (EFI_ERROR (Status)) {
1045 AllChildrenStopped = FALSE;
1046 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
1047 continue;
1048 }
1049
1050 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
1051
1052 gBS->CloseProtocol (
1053 Controller,
1054 &gEfiUsbIoProtocolGuid,
1055 This->DriverBindingHandle,
1056 ChildHandleBuffer[Index]
1057 );
1058
1059 Status = gBS->UninstallMultipleProtocolInterfaces (
1060 ChildHandleBuffer[Index],
1061 &gEfiDevicePathProtocolGuid,
1062 UsbMass->DevicePath,
1063 &gEfiBlockIoProtocolGuid,
1064 &UsbMass->BlockIo,
1065 NULL
1066 );
1067
1068 if (EFI_ERROR (Status)) {
1069 //
1070 // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
1071 //
1072 AllChildrenStopped = FALSE;
1073 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
1074
1075 gBS->OpenProtocol (
1076 Controller,
1077 &gEfiUsbIoProtocolGuid,
1078 (VOID **) &UsbIo,
1079 This->DriverBindingHandle,
1080 ChildHandleBuffer[Index],
1081 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1082 );
1083 } else {
1084 //
1085 // Succeed to stop this multi-lun handle, so go on with next child.
1086 //
1087 if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
1088 UsbMass->Transport->CleanUp (UsbMass->Context);
1089 }
1090 FreePool (UsbMass);
1091 }
1092 }
1093
1094 if (!AllChildrenStopped) {
1095 return EFI_DEVICE_ERROR;
1096 }
1097
1098 DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
1099 return EFI_SUCCESS;
1100 }
1101
1102 /**
1103 Entrypoint of USB Mass Storage Driver.
1104
1105 This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
1106 Protocol together with Component Name Protocols.
1107
1108 @param ImageHandle The firmware allocated handle for the EFI image.
1109 @param SystemTable A pointer to the EFI System Table.
1110
1111 @retval EFI_SUCCESS The entry point is executed successfully.
1112
1113 **/
1114 EFI_STATUS
1115 EFIAPI
1116 USBMassStorageEntryPoint (
1117 IN EFI_HANDLE ImageHandle,
1118 IN EFI_SYSTEM_TABLE *SystemTable
1119 )
1120 {
1121 EFI_STATUS Status;
1122
1123 //
1124 // Install driver binding protocol
1125 //
1126 Status = EfiLibInstallDriverBindingComponentName2 (
1127 ImageHandle,
1128 SystemTable,
1129 &gUSBMassDriverBinding,
1130 ImageHandle,
1131 &gUsbMassStorageComponentName,
1132 &gUsbMassStorageComponentName2
1133 );
1134 ASSERT_EFI_ERROR (Status);
1135
1136 return EFI_SUCCESS;
1137 }