]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
1 /** @file
2
3 The implementation of USB mass storage class device driver.
4 The command set supported is "USB Mass Storage Specification
5 for Bootability".
6
7 Copyright (c) 2007 - 2008, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "UsbMassImpl.h"
19
20 USB_MASS_TRANSPORT *mUsbMassTransport[] = {
21 &mUsbCbi0Transport,
22 &mUsbCbi1Transport,
23 &mUsbBotTransport,
24 NULL
25 };
26
27 /**
28 Reset the block device. ExtendedVerification is ignored for this.
29
30 @param This The BLOCK IO protocol
31 @param ExtendedVerification Whether to execute extended verfication.
32
33 @retval EFI_SUCCESS The device is successfully resetted.
34 @retval Others Failed to reset the device.
35
36 **/
37 EFI_STATUS
38 EFIAPI
39 UsbMassReset (
40 IN EFI_BLOCK_IO_PROTOCOL *This,
41 IN BOOLEAN ExtendedVerification
42 )
43 {
44 USB_MASS_DEVICE *UsbMass;
45 EFI_TPL OldTpl;
46 EFI_STATUS Status;
47
48 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
49
50 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
51 Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
52
53 gBS->RestoreTPL (OldTpl);
54
55 return Status;
56 }
57
58 /**
59 Read some blocks of data from the block device.
60
61 @param This The Block IO protocol
62 @param MediaId The media's ID of the device for current request
63 @param Lba The start block number
64 @param BufferSize The size of buffer to read data in
65 @param Buffer The buffer to read data to
66
67 @retval EFI_SUCCESS The data is successfully read
68 @retval EFI_NO_MEDIA Media isn't present
69 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
70 MediaId changed
71 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
72 NULL.
73 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
74 size, or overflow the last block number.
75
76 **/
77 EFI_STATUS
78 EFIAPI
79 UsbMassReadBlocks (
80 IN EFI_BLOCK_IO_PROTOCOL *This,
81 IN UINT32 MediaId,
82 IN EFI_LBA Lba,
83 IN UINTN BufferSize,
84 OUT VOID *Buffer
85 )
86 {
87 USB_MASS_DEVICE *UsbMass;
88 EFI_BLOCK_IO_MEDIA *Media;
89 EFI_STATUS Status;
90 EFI_TPL OldTpl;
91 UINTN TotalBlock;
92
93 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
94 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
95 Media = &UsbMass->BlockIoMedia;
96
97 //
98 // First, validate the parameters
99 //
100 if ((Buffer == NULL) || (BufferSize == 0)) {
101 Status = EFI_INVALID_PARAMETER;
102 goto ON_EXIT;
103 }
104
105 //
106 // If it is a removable media, such as CD-Rom or Usb-Floppy,
107 // need to detect the media before each rw. While some of
108 // Usb-Flash is marked as removable media.
109 //
110 //
111 if (Media->RemovableMedia == TRUE) {
112 Status = UsbBootDetectMedia (UsbMass);
113 if (EFI_ERROR (Status)) {
114 DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
115 goto ON_EXIT;
116 }
117 }
118
119 //
120 // Make sure BlockSize and LBA is consistent with BufferSize
121 //
122 if ((BufferSize % Media->BlockSize) != 0) {
123 Status = EFI_BAD_BUFFER_SIZE;
124 goto ON_EXIT;
125 }
126
127 TotalBlock = BufferSize / Media->BlockSize;
128
129 if (Lba + TotalBlock - 1 > Media->LastBlock) {
130 Status = EFI_INVALID_PARAMETER;
131 goto ON_EXIT;
132 }
133
134 if (!(Media->MediaPresent)) {
135 Status = EFI_NO_MEDIA;
136 goto ON_EXIT;
137 }
138
139 if (MediaId != Media->MediaId) {
140 Status = EFI_MEDIA_CHANGED;
141 goto ON_EXIT;
142 }
143
144 Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
145 if (EFI_ERROR (Status)) {
146 DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
147 UsbMassReset (This, TRUE);
148 }
149
150 ON_EXIT:
151 gBS->RestoreTPL (OldTpl);
152 return Status;
153 }
154
155
156 /**
157 Write some blocks of data to the block device.
158
159 @param This The Block IO protocol
160 @param MediaId The media's ID of the device for current request
161 @param Lba The start block number
162 @param BufferSize The size of buffer to write data to
163 @param Buffer The buffer to write data to
164
165 @retval EFI_SUCCESS The data is successfully written
166 @retval EFI_NO_MEDIA Media isn't present
167 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
168 MediaId changed
169 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
170 NULL.
171 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
172 size,
173
174 **/
175 EFI_STATUS
176 EFIAPI
177 UsbMassWriteBlocks (
178 IN EFI_BLOCK_IO_PROTOCOL *This,
179 IN UINT32 MediaId,
180 IN EFI_LBA Lba,
181 IN UINTN BufferSize,
182 IN VOID *Buffer
183 )
184 {
185 USB_MASS_DEVICE *UsbMass;
186 EFI_BLOCK_IO_MEDIA *Media;
187 EFI_STATUS Status;
188 EFI_TPL OldTpl;
189 UINTN TotalBlock;
190
191 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
192 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
193 Media = &UsbMass->BlockIoMedia;
194
195 //
196 // First, validate the parameters
197 //
198 if ((Buffer == NULL) || (BufferSize == 0)) {
199 Status = EFI_INVALID_PARAMETER;
200 goto ON_EXIT;
201 }
202
203 //
204 // If it is a removable media, such as CD-Rom or Usb-Floppy,
205 // need to detect the media before each rw. While some of
206 // Usb-Flash is marked as removable media.
207 //
208 //
209 if (Media->RemovableMedia == TRUE) {
210 Status = UsbBootDetectMedia (UsbMass);
211 if (EFI_ERROR (Status)) {
212 DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
213 goto ON_EXIT;
214 }
215 }
216
217 //
218 // Make sure BlockSize and LBA is consistent with BufferSize
219 //
220 if ((BufferSize % Media->BlockSize) != 0) {
221 Status = EFI_BAD_BUFFER_SIZE;
222 goto ON_EXIT;
223 }
224
225 TotalBlock = BufferSize / Media->BlockSize;
226
227 if (Lba + TotalBlock - 1 > Media->LastBlock) {
228 Status = EFI_INVALID_PARAMETER;
229 goto ON_EXIT;
230 }
231
232 if (!(Media->MediaPresent)) {
233 Status = EFI_NO_MEDIA;
234 goto ON_EXIT;
235 }
236
237 if (MediaId != Media->MediaId) {
238 Status = EFI_MEDIA_CHANGED;
239 goto ON_EXIT;
240 }
241
242 //
243 // Try to write the data even the device is marked as ReadOnly,
244 // and clear the status should the write succeed.
245 //
246 Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
247 if (EFI_ERROR (Status)) {
248 DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
249 UsbMassReset (This, TRUE);
250 }
251
252 ON_EXIT:
253 gBS->RestoreTPL (OldTpl);
254 return Status;
255 }
256
257 /**
258 Flush the cached writes to disks. USB mass storage device doesn't
259 support write cache, so return EFI_SUCCESS directly.
260
261 @param This The BLOCK IO protocol
262
263 @retval EFI_SUCCESS Always returns success
264
265 **/
266 EFI_STATUS
267 EFIAPI
268 UsbMassFlushBlocks (
269 IN EFI_BLOCK_IO_PROTOCOL *This
270 )
271 {
272 return EFI_SUCCESS;
273 }
274
275 /**
276 Retrieve the media parameters such as disk gemotric for the
277 device's BLOCK IO protocol.
278
279 @param UsbMass The USB mass storage device
280
281 @retval EFI_SUCCESS The media parameters is updated successfully.
282 @retval Others Failed to get the media parameters.
283
284 **/
285 EFI_STATUS
286 UsbMassInitMedia (
287 IN USB_MASS_DEVICE *UsbMass
288 )
289 {
290 EFI_BLOCK_IO_MEDIA *Media;
291 EFI_STATUS Status;
292 UINTN Index;
293
294 Media = &UsbMass->BlockIoMedia;
295
296 //
297 // Initialize the MediaPrsent/ReadOnly and others to the default.
298 // We are not forced to get it right at this time, check UEFI2.0
299 // spec for more information:
300 //
301 // MediaPresent: This field shows the media present status as
302 // of the most recent ReadBlocks or WriteBlocks call.
303 //
304 // ReadOnly : This field shows the read-only status as of the
305 // recent WriteBlocks call.
306 //
307 // but remember to update MediaId/MediaPresent/ReadOnly status
308 // after ReadBlocks and WriteBlocks
309 //
310 Media->MediaPresent = FALSE;
311 Media->LogicalPartition = FALSE;
312 Media->ReadOnly = FALSE;
313 Media->WriteCaching = FALSE;
314 Media->IoAlign = 0;
315 Media->MediaId = 1;
316
317 //
318 // Some device may spend several seconds before it is ready.
319 // Try several times before giving up. Wait 5s at most.
320 //
321 Status = EFI_SUCCESS;
322
323 for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
324
325 Status = UsbBootGetParams (UsbMass);
326 if ((Status != EFI_MEDIA_CHANGED)
327 && (Status != EFI_NOT_READY)
328 && (Status != EFI_TIMEOUT)) {
329 break;
330 }
331
332 Status = UsbBootIsUnitReady (UsbMass);
333 if (EFI_ERROR (Status)) {
334 gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
335 }
336
337 }
338
339 return Status;
340 }
341
342 /**
343 Initilize the transport.
344
345 @param This The USB mass driver's driver binding.
346 @param Controller The device to test.
347 @param Transport The pointer to pointer to USB_MASS_TRANSPORT.
348 @param Context The passing parameter.
349 @param MaxLun Get the MaxLun if is BOT dev.
350
351 @retval EFI_SUCCESS The initilization is successful.
352 @retval Others Failed to initilize dev.
353
354 **/
355 EFI_STATUS
356 UsbMassInitTransport (
357 IN EFI_DRIVER_BINDING_PROTOCOL *This,
358 IN EFI_HANDLE Controller,
359 OUT USB_MASS_TRANSPORT **Transport,
360 OUT VOID **Context,
361 OUT UINT8 *MaxLun
362 )
363 {
364 EFI_USB_IO_PROTOCOL *UsbIo;
365 EFI_USB_INTERFACE_DESCRIPTOR Interface;
366 UINT8 Index;
367 EFI_STATUS Status;
368
369 Status = gBS->OpenProtocol (
370 Controller,
371 &gEfiUsbIoProtocolGuid,
372 (VOID **) &UsbIo,
373 This->DriverBindingHandle,
374 Controller,
375 EFI_OPEN_PROTOCOL_BY_DRIVER
376 );
377
378 if (EFI_ERROR (Status)) {
379 DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: OpenUsbIoProtocol By Driver (%r)\n", Status));
380 return Status;
381 }
382
383 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
384 if (EFI_ERROR (Status)) {
385 DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
386 goto ON_EXIT;
387 }
388
389 Status = EFI_UNSUPPORTED;
390
391 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
392 *Transport = mUsbMassTransport[Index];
393
394 if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
395 Status = (*Transport)->Init (UsbIo, Context);
396 break;
397 }
398 }
399
400 if (EFI_ERROR (Status)) {
401 DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: Transport->Init (%r)\n", Status));
402 goto ON_EXIT;
403 }
404
405 //
406 // For bot device, try to get max lun.
407 // If maxlun=0, then non-lun device, else multi-lun device.
408 //
409 if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
410 (*Transport)->GetMaxLun (*Context, MaxLun);
411 DEBUG ((EFI_D_INFO, "UsbMassInitTransport: GetMaxLun = %d\n", *MaxLun));
412 }
413
414 ON_EXIT:
415 gBS->CloseProtocol (
416 Controller,
417 &gEfiUsbIoProtocolGuid,
418 This->DriverBindingHandle,
419 Controller
420 );
421 return Status;
422 }
423
424 /**
425 Usb mass storage driver initializes multi lun.
426
427 @param This The USB mass driver's driver binding.
428 @param Controller The device to test.
429 @param Transport The pointer to USB_MASS_TRANSPORT.
430 @param Context The passing parameter.
431 @param DevicePath The remaining device path
432 @param MaxLun The MaxLun number passed.
433
434 @retval EFI_SUCCESS Initialization is success.
435 @retval Other Initialization fails.
436
437 **/
438 EFI_STATUS
439 UsbMassInitMultiLun (
440 IN EFI_DRIVER_BINDING_PROTOCOL *This,
441 IN EFI_HANDLE Controller,
442 IN USB_MASS_TRANSPORT *Transport,
443 IN VOID *Context,
444 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
445 IN UINT8 MaxLun
446 )
447 {
448 USB_MASS_DEVICE *UsbMass;
449 EFI_USB_IO_PROTOCOL *UsbIo;
450 DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
451 UINT8 Index;
452 EFI_STATUS Status;
453
454 ASSERT (MaxLun > 0);
455
456 for (Index = 0; Index <= MaxLun; Index++) {
457
458 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
459
460 UsbIo = NULL;
461 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
462 if (UsbMass == NULL) {
463 Status = EFI_OUT_OF_RESOURCES;
464 goto ON_ERROR;
465 }
466
467 UsbMass->Signature = USB_MASS_SIGNATURE;
468 UsbMass->UsbIo = UsbIo;
469 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
470 UsbMass->BlockIo.Reset = UsbMassReset;
471 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
472 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
473 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
474 UsbMass->OpticalStorage = FALSE;
475 UsbMass->Transport = Transport;
476 UsbMass->Context = Context;
477 UsbMass->Lun = Index;
478
479 //
480 // Get the storage's parameters, such as last block number.
481 // then install the BLOCK_IO
482 //
483 Status = UsbMassInitMedia (UsbMass);
484 if (!EFI_ERROR (Status)) {
485 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
486 (UsbMass->Pdt != USB_PDT_CDROM) &&
487 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
488 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
489 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
490 goto ON_ERROR;
491 }
492 } else if (Status != EFI_NO_MEDIA){
493 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
494 goto ON_ERROR;
495 }
496
497 //
498 // Create a device path node of device logic unit, and append it
499 //
500 LunNode.Header.Type = MESSAGING_DEVICE_PATH;
501 LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
502 LunNode.Lun = UsbMass->Lun;
503
504 SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
505
506 UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
507
508 if (UsbMass->DevicePath == NULL) {
509 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
510
511 Status = EFI_OUT_OF_RESOURCES;
512 goto ON_ERROR;
513 }
514
515 //
516 // Create a UsbMass handle for each lun, and install blockio and devicepath protocols.
517 //
518 Status = gBS->InstallMultipleProtocolInterfaces (
519 &UsbMass->Controller,
520 &gEfiDevicePathProtocolGuid,
521 UsbMass->DevicePath,
522 &gEfiBlockIoProtocolGuid,
523 &UsbMass->BlockIo,
524 NULL
525 );
526
527 if (EFI_ERROR (Status)) {
528 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
529 goto ON_ERROR;
530 }
531
532 //
533 // Open UsbIo protocol by child to setup a parent-child relationship.
534 //
535 Status = gBS->OpenProtocol (
536 Controller,
537 &gEfiUsbIoProtocolGuid,
538 (VOID **) &UsbIo,
539 This->DriverBindingHandle,
540 UsbMass->Controller,
541 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
542 );
543
544 if (EFI_ERROR (Status)) {
545 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
546 gBS->UninstallMultipleProtocolInterfaces (
547 &UsbMass->Controller,
548 &gEfiDevicePathProtocolGuid,
549 UsbMass->DevicePath,
550 &gEfiBlockIoProtocolGuid,
551 &UsbMass->BlockIo,
552 NULL
553 );
554 goto ON_ERROR;
555 }
556
557 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
558 }
559
560 return EFI_SUCCESS;
561
562 ON_ERROR:
563 if (UsbMass->DevicePath != NULL) {
564 gBS->FreePool (UsbMass->DevicePath);
565 }
566 if (UsbMass != NULL) {
567 gBS->FreePool (UsbMass);
568 }
569 if (UsbIo != NULL) {
570 gBS->CloseProtocol (
571 Controller,
572 &gEfiUsbIoProtocolGuid,
573 This->DriverBindingHandle,
574 UsbMass->Controller
575 );
576 }
577
578 //
579 // If only success to initialize one lun, return success, or else return error
580 //
581 if (Index > 0) {
582 return EFI_SUCCESS;
583 } else {
584 return Status;
585 }
586 }
587
588 /**
589 Initialize No/Unsupported LUN device.
590
591 @param This The USB mass driver's driver binding.
592 @param Controller The device to test.
593 @param Transport The pointer to USB_MASS_TRANSPORT.
594 @param Context The passing parameter.
595
596 @retval EFI_SUCCESS Initialization is success.
597 @retval Other Initialization fails.
598
599 **/
600 EFI_STATUS
601 UsbMassInitNonLun (
602 IN EFI_DRIVER_BINDING_PROTOCOL *This,
603 IN EFI_HANDLE Controller,
604 IN USB_MASS_TRANSPORT *Transport,
605 IN VOID *Context
606 )
607 {
608 USB_MASS_DEVICE *UsbMass;
609 EFI_USB_IO_PROTOCOL *UsbIo;
610 EFI_STATUS Status;
611
612 UsbIo = NULL;
613 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
614 if (UsbMass == NULL) {
615 return EFI_OUT_OF_RESOURCES;
616 }
617 Status = gBS->OpenProtocol (
618 Controller,
619 &gEfiUsbIoProtocolGuid,
620 (VOID **) &UsbIo,
621 This->DriverBindingHandle,
622 Controller,
623 EFI_OPEN_PROTOCOL_BY_DRIVER
624 );
625
626 if (EFI_ERROR (Status)) {
627 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
628 goto ON_ERROR;
629 }
630
631 UsbMass->Signature = USB_MASS_SIGNATURE;
632 UsbMass->Controller = Controller;
633 UsbMass->UsbIo = UsbIo;
634 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
635 UsbMass->BlockIo.Reset = UsbMassReset;
636 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
637 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
638 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
639 UsbMass->OpticalStorage = FALSE;
640 UsbMass->Transport = Transport;
641 UsbMass->Context = Context;
642
643 //
644 // Get the storage's parameters, such as last block number.
645 // then install the BLOCK_IO
646 //
647 Status = UsbMassInitMedia (UsbMass);
648 if (!EFI_ERROR (Status)) {
649 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
650 (UsbMass->Pdt != USB_PDT_CDROM) &&
651 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
652 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
653 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
654 goto ON_ERROR;
655 }
656 } else if (Status != EFI_NO_MEDIA){
657 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
658 goto ON_ERROR;
659 }
660
661 Status = gBS->InstallProtocolInterface (
662 &Controller,
663 &gEfiBlockIoProtocolGuid,
664 EFI_NATIVE_INTERFACE,
665 &UsbMass->BlockIo
666 );
667 if (EFI_ERROR (Status)) {
668 goto ON_ERROR;
669 }
670
671 return EFI_SUCCESS;
672
673 ON_ERROR:
674 if (UsbMass != NULL) {
675 gBS->FreePool (UsbMass);
676 }
677 gBS->CloseProtocol (
678 Controller,
679 &gEfiUsbIoProtocolGuid,
680 This->DriverBindingHandle,
681 Controller
682 );
683 return Status;
684 }
685
686
687 /**
688 Check whether the controller is a supported USB mass storage.
689
690 @param This The USB mass driver's driver binding.
691 @param Controller The device to test against.
692 @param RemainingDevicePath The remaining device path
693
694 @retval EFI_SUCCESS This device is a supported USB mass storage.
695 @retval EFI_UNSUPPORTED The device isn't supported
696 @retval Others Some error happened.
697
698 **/
699 EFI_STATUS
700 EFIAPI
701 USBMassDriverBindingSupported (
702 IN EFI_DRIVER_BINDING_PROTOCOL *This,
703 IN EFI_HANDLE Controller,
704 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
705 )
706 {
707 EFI_USB_IO_PROTOCOL *UsbIo;
708 EFI_USB_INTERFACE_DESCRIPTOR Interface;
709 USB_MASS_TRANSPORT *Transport;
710 EFI_STATUS Status;
711 INTN Index;
712
713 //
714 // Check whether the controlelr support USB_IO
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 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 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
744 Transport = mUsbMassTransport[Index];
745 if (Interface.InterfaceProtocol == Transport->Protocol) {
746 Status = Transport->Init (UsbIo, NULL);
747 break;
748 }
749 }
750
751 DEBUG ((EFI_D_INFO, "Found a USB mass store device %r\n", Status));
752
753 ON_EXIT:
754 gBS->CloseProtocol (
755 Controller,
756 &gEfiUsbIoProtocolGuid,
757 This->DriverBindingHandle,
758 Controller
759 );
760
761 return Status;
762 }
763
764
765 /**
766 Start the USB mass storage device on the controller. It will
767 install a BLOCK_IO protocol on the device if everything is OK.
768
769 @param This The USB mass storage driver binding.
770 @param Controller The USB mass storage device to start on
771 @param RemainingDevicePath The remaining device path.
772
773 @retval EFI_SUCCESS The driver has started on the device.
774 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
775 @retval Others Failed to start the driver on the device.
776
777 **/
778 EFI_STATUS
779 EFIAPI
780 USBMassDriverBindingStart (
781 IN EFI_DRIVER_BINDING_PROTOCOL *This,
782 IN EFI_HANDLE Controller,
783 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
784 )
785 {
786 USB_MASS_TRANSPORT *Transport;
787 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
788 VOID *Context;
789 UINT8 MaxLun;
790 EFI_STATUS Status;
791
792 Transport = NULL;
793 Context = NULL;
794 MaxLun = 0;
795
796 //
797 // Get interface and protocols, initialize transport
798 //
799 Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
800
801 if (EFI_ERROR (Status)) {
802 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
803 return Status;
804 }
805 if (MaxLun == 0) {
806 //
807 // Initialize No/Unsupported LUN device
808 //
809 Status = UsbMassInitNonLun(This, Controller, Transport, Context);
810 if (EFI_ERROR (Status)) {
811 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
812 }
813 } else {
814 //
815 // Open device path to perpare append Device Logic Unit node.
816 //
817 Status = gBS->OpenProtocol (
818 Controller,
819 &gEfiDevicePathProtocolGuid,
820 (VOID **) &DevicePath,
821 This->DriverBindingHandle,
822 Controller,
823 EFI_OPEN_PROTOCOL_BY_DRIVER
824 );
825
826 if (EFI_ERROR (Status)) {
827 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
828 return Status;
829 }
830
831 //
832 // Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized.
833 //
834 Status = UsbMassInitMultiLun(This, Controller, Transport, Context, DevicePath, MaxLun);
835 if (EFI_ERROR (Status)) {
836 gBS->CloseProtocol (
837 Controller,
838 &gEfiDevicePathProtocolGuid,
839 This->DriverBindingHandle,
840 Controller
841 );
842 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
843 }
844 }
845 return Status;
846 }
847
848
849 /**
850 Stop controlling the device.
851
852 @param This The USB mass storage driver binding
853 @param Controller The device controller controlled by the driver.
854 @param NumberOfChildren The number of children of this device
855 @param ChildHandleBuffer The buffer of children handle.
856
857 @retval EFI_SUCCESS The driver stopped from controlling the device.
858 @retval Others Failed to stop the driver
859
860 **/
861 EFI_STATUS
862 EFIAPI
863 USBMassDriverBindingStop (
864 IN EFI_DRIVER_BINDING_PROTOCOL *This,
865 IN EFI_HANDLE Controller,
866 IN UINTN NumberOfChildren,
867 IN EFI_HANDLE *ChildHandleBuffer
868 )
869 {
870 EFI_STATUS Status;
871 USB_MASS_DEVICE *UsbMass;
872 EFI_USB_IO_PROTOCOL *UsbIo;
873 EFI_BLOCK_IO_PROTOCOL *BlockIo;
874 UINTN Index;
875 BOOLEAN AllChildrenStopped;
876
877 //
878 // This a bus driver stop function since multi-lun supported. There are three
879 // kinds of device handle might be passed, 1st is a handle with devicepath/
880 // usbio/blockio installed(non-multi-lun), 2nd is a handle with devicepath/
881 // usbio installed(multi-lun root), 3rd is a handle with devicepath/blockio
882 // installed(multi-lun).
883 //
884 if (NumberOfChildren == 0) {
885 //
886 // A handle without any children, might be 1st and 2nd type.
887 //
888 Status = gBS->OpenProtocol (
889 Controller,
890 &gEfiBlockIoProtocolGuid,
891 (VOID **) &BlockIo,
892 This->DriverBindingHandle,
893 Controller,
894 EFI_OPEN_PROTOCOL_GET_PROTOCOL
895 );
896
897 if (EFI_ERROR(Status)) {
898 //
899 // This is a 2nd type handle(multi-lun root), which only needs close
900 // devicepath protocol.
901 //
902 gBS->CloseProtocol (
903 Controller,
904 &gEfiDevicePathProtocolGuid,
905 This->DriverBindingHandle,
906 Controller
907 );
908 DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
909 return EFI_SUCCESS;
910 }
911
912 //
913 // This is a 1st type handle(non-multi-lun), which only needs uninstall
914 // blockio protocol, close usbio protocol and free mass device.
915 //
916 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
917
918 //
919 // Uninstall Block I/O protocol from the device handle,
920 // then call the transport protocol to stop itself.
921 //
922 Status = gBS->UninstallProtocolInterface (
923 Controller,
924 &gEfiBlockIoProtocolGuid,
925 &UsbMass->BlockIo
926 );
927 if (EFI_ERROR (Status)) {
928 return Status;
929 }
930
931 gBS->CloseProtocol (
932 Controller,
933 &gEfiUsbIoProtocolGuid,
934 This->DriverBindingHandle,
935 Controller
936 );
937
938 UsbMass->Transport->Fini (UsbMass->Context);
939 gBS->FreePool (UsbMass);
940
941 DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
942 return EFI_SUCCESS;
943 }
944
945 //
946 // This is a 3rd type handle(multi-lun), which needs uninstall
947 // blockio and devicepath protocol, close usbio protocol and
948 // free mass device.
949 //
950 AllChildrenStopped = TRUE;
951
952 for (Index = 0; Index < NumberOfChildren; Index++) {
953
954 Status = gBS->OpenProtocol (
955 ChildHandleBuffer[Index],
956 &gEfiBlockIoProtocolGuid,
957 (VOID **) &BlockIo,
958 This->DriverBindingHandle,
959 Controller,
960 EFI_OPEN_PROTOCOL_GET_PROTOCOL
961 );
962 if (EFI_ERROR (Status)) {
963 AllChildrenStopped = FALSE;
964 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", Index));
965 continue;
966 }
967
968 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
969
970 gBS->CloseProtocol (
971 Controller,
972 &gEfiUsbIoProtocolGuid,
973 This->DriverBindingHandle,
974 ChildHandleBuffer[Index]
975 );
976
977 Status = gBS->UninstallMultipleProtocolInterfaces (
978 ChildHandleBuffer[Index],
979 &gEfiDevicePathProtocolGuid,
980 UsbMass->DevicePath,
981 &gEfiBlockIoProtocolGuid,
982 &UsbMass->BlockIo,
983 NULL
984 );
985
986 if (EFI_ERROR (Status)) {
987 //
988 // Fail to uninstall blockio and devicepath protocol, so re-open usbio by child.
989 //
990 AllChildrenStopped = FALSE;
991 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", Index));
992
993 gBS->OpenProtocol (
994 Controller,
995 &gEfiUsbIoProtocolGuid,
996 (VOID **) &UsbIo,
997 This->DriverBindingHandle,
998 ChildHandleBuffer[Index],
999 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1000 );
1001 } else {
1002 //
1003 // Success to stop this multi-lun handle, so go on next child.
1004 //
1005 if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
1006 UsbMass->Transport->Fini (UsbMass->Context);
1007 }
1008 gBS->FreePool (UsbMass);
1009 }
1010 }
1011
1012 if (!AllChildrenStopped) {
1013 return EFI_DEVICE_ERROR;
1014 }
1015
1016 DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", NumberOfChildren));
1017 return EFI_SUCCESS;
1018 }
1019
1020 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
1021 USBMassDriverBindingSupported,
1022 USBMassDriverBindingStart,
1023 USBMassDriverBindingStop,
1024 0x11,
1025 NULL,
1026 NULL
1027 };
1028
1029 /**
1030 The entry point for the driver, which will install the driver binding and
1031 component name protocol.
1032
1033 @param ImageHandle The image handle of this driver.
1034 @param SystemTable The system table.
1035
1036 @retval EFI_SUCCESS The protocols are installed OK.
1037 @retval Others Failed to install protocols.
1038
1039 **/
1040 EFI_STATUS
1041 EFIAPI
1042 USBMassStorageEntryPoint (
1043 IN EFI_HANDLE ImageHandle,
1044 IN EFI_SYSTEM_TABLE *SystemTable
1045 )
1046 {
1047 EFI_STATUS Status;
1048
1049 //
1050 // Install driver binding protocol
1051 //
1052 Status = EfiLibInstallDriverBindingComponentName2 (
1053 ImageHandle,
1054 SystemTable,
1055 &gUSBMassDriverBinding,
1056 ImageHandle,
1057 &gUsbMassStorageComponentName,
1058 &gUsbMassStorageComponentName2
1059 );
1060
1061 return Status;
1062 }