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