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