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