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