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