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