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