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