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