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