]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
fixed memcpy link issue.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
CommitLineData
e237e7ae 1/** @file\r
2\r
3Copyright (c) 2007, Intel Corporation\r
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
43UINTN mUsbMscInfo = DEBUG_INFO;\r
44UINTN mUsbMscError = DEBUG_ERROR;\r
45\r
46\r
47/**\r
48 Retrieve the media parameters such as disk gemotric for the\r
49 device's BLOCK IO protocol.\r
50\r
51 @param UsbMass The USB mass storage device\r
52\r
53 @retval EFI_SUCCESS The media parameters is updated successfully.\r
54 @retval Others Failed to get the media parameters.\r
55\r
56**/\r
57EFI_STATUS\r
58UsbMassInitMedia (\r
59 IN USB_MASS_DEVICE *UsbMass\r
60 )\r
61{\r
62 EFI_BLOCK_IO_MEDIA *Media;\r
63 EFI_STATUS Status;\r
64 UINTN Index;\r
65\r
66 Media = &UsbMass->BlockIoMedia;\r
67\r
68 //\r
69 // Initialize the MediaPrsent/ReadOnly and others to the default.\r
70 // We are not forced to get it right at this time, check UEFI2.0\r
71 // spec for more information:\r
72 //\r
73 // MediaPresent: This field shows the media present status as\r
74 // of the most recent ReadBlocks or WriteBlocks call.\r
75 //\r
76 // ReadOnly : This field shows the read-only status as of the\r
77 // recent WriteBlocks call.\r
78 //\r
79 // but remember to update MediaId/MediaPresent/ReadOnly status\r
80 // after ReadBlocks and WriteBlocks\r
81 //\r
82 Media->MediaPresent = FALSE;\r
83 Media->LogicalPartition = FALSE;\r
84 Media->ReadOnly = FALSE;\r
85 Media->WriteCaching = FALSE;\r
86 Media->IoAlign = 0;\r
87\r
88 //\r
89 // Some device may spend several seconds before it is ready.\r
90 // Try several times before giving up. Wait 5s at most.\r
91 //\r
92 Status = EFI_SUCCESS;\r
93\r
94 for (Index = 0; Index < USB_BOOT_WAIT_RETRY; Index++) {\r
95\r
96 Status = UsbBootGetParams (UsbMass);\r
97 if ((Status != EFI_MEDIA_CHANGED)\r
98 && (Status != EFI_NOT_READY)\r
99 && (Status != EFI_TIMEOUT)) {\r
100 break;\r
101 }\r
102\r
103 Status = UsbBootIsUnitReady (UsbMass);\r
104 if (EFI_ERROR (Status)) {\r
105 gBS->Stall (USB_BOOT_UNIT_READY_STALL * (Index + 1));\r
106 }\r
107\r
108 }\r
109\r
110 return Status;\r
111}\r
112\r
113\r
114/**\r
115 Reset the block device. ExtendedVerification is ignored for this.\r
116\r
117 @param This The BLOCK IO protocol\r
118 @param ExtendedVerification Whether to execute extended verfication.\r
119\r
120 @retval EFI_SUCCESS The device is successfully resetted.\r
121 @retval Others Failed to reset the device.\r
122\r
123**/\r
124EFI_STATUS\r
125UsbMassReset (\r
126 IN EFI_BLOCK_IO_PROTOCOL *This,\r
127 IN BOOLEAN ExtendedVerification\r
128 )\r
129{\r
130 USB_MASS_DEVICE *UsbMass;\r
131\r
132 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
133 return UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);\r
134}\r
135\r
136\r
137/**\r
138 Read some blocks of data from the block device.\r
139\r
140 @param This The Block IO protocol\r
141 @param MediaId The media's ID of the device for current request\r
142 @param Lba The start block number\r
143 @param BufferSize The size of buffer to read data in\r
144 @param Buffer The buffer to read data to\r
145\r
146 @retval EFI_SUCCESS The data is successfully read\r
147 @retval EFI_NO_MEDIA Media isn't present\r
148 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,\r
149 MediaId changed\r
150 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is\r
151 NULL.\r
152 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block\r
153 size, or overflow the last block number.\r
154\r
155**/\r
156EFI_STATUS\r
157UsbMassReadBlocks (\r
158 IN EFI_BLOCK_IO_PROTOCOL *This,\r
159 IN UINT32 MediaId,\r
160 IN EFI_LBA Lba,\r
161 IN UINTN BufferSize,\r
162 OUT VOID *Buffer\r
163 )\r
164{\r
165 USB_MASS_DEVICE *UsbMass;\r
166 EFI_BLOCK_IO_MEDIA *Media;\r
167 EFI_STATUS Status;\r
168 UINTN TotalBlock;\r
169\r
170 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
171 Media = &UsbMass->BlockIoMedia;\r
172\r
173 //\r
174 // First, validate the parameters\r
175 //\r
176 if ((Buffer == NULL) || (BufferSize == 0)) {\r
177 return EFI_INVALID_PARAMETER;\r
178 }\r
179\r
180 //\r
181 // If it is a remoable media, such as CD-Rom or Usb-Floppy,\r
182 // if, need to detect the media before each rw, while Usb-Flash\r
183 // needn't. However, it's hard to identify Usb-Floppy between\r
184 // Usb-Flash by now, so detect media every time.\r
185 //\r
186 Status = UsbBootDetectMedia (UsbMass);\r
187 if (EFI_ERROR (Status)) {\r
188 DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));\r
189 return Status;\r
190 }\r
191\r
192 //\r
193 // Make sure BlockSize and LBA is consistent with BufferSize\r
194 //\r
195 if ((BufferSize % Media->BlockSize) != 0) {\r
196 return EFI_BAD_BUFFER_SIZE;\r
197 }\r
198\r
199 TotalBlock = BufferSize / Media->BlockSize;\r
200\r
201 if (Lba + TotalBlock - 1 > Media->LastBlock) {\r
202 return EFI_BAD_BUFFER_SIZE;\r
203 }\r
204\r
205 Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);\r
206 if (EFI_ERROR (Status)) {\r
207 DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));\r
208 UsbMassReset (This, TRUE);\r
209 }\r
210\r
211 return Status;\r
212}\r
213\r
214\r
215/**\r
216 Write some blocks of data to the block device.\r
217\r
218 @param This The Block IO protocol\r
219 @param MediaId The media's ID of the device for current request\r
220 @param Lba The start block number\r
221 @param BufferSize The size of buffer to write data to\r
222 @param Buffer The buffer to write data to\r
223\r
224 @retval EFI_SUCCESS The data is successfully written\r
225 @retval EFI_NO_MEDIA Media isn't present\r
226 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,\r
227 MediaId changed\r
228 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is\r
229 NULL.\r
230 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block\r
231 size,\r
232\r
233**/\r
234EFI_STATUS\r
235UsbMassWriteBlocks (\r
236 IN EFI_BLOCK_IO_PROTOCOL *This,\r
237 IN UINT32 MediaId,\r
238 IN EFI_LBA Lba,\r
239 IN UINTN BufferSize,\r
240 IN VOID *Buffer\r
241 )\r
242{\r
243 USB_MASS_DEVICE *UsbMass;\r
244 EFI_BLOCK_IO_MEDIA *Media;\r
245 EFI_STATUS Status;\r
246 UINTN TotalBlock;\r
247\r
248 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);\r
249 Media = &UsbMass->BlockIoMedia;\r
250\r
251 //\r
252 // First, validate the parameters\r
253 //\r
254 if ((Buffer == NULL) || (BufferSize == 0)) {\r
255 return EFI_INVALID_PARAMETER;\r
256 }\r
257\r
258 //\r
259 // If it is a remoable media, such as CD-Rom or Usb-Floppy,\r
260 // if, need to detect the media before each rw, while Usb-Flash\r
261 // needn't. However, it's hard to identify Usb-Floppy between\r
262 // Usb-Flash by now, so detect media every time.\r
263 //\r
264 Status = UsbBootDetectMedia (UsbMass);\r
265 if (EFI_ERROR (Status)) {\r
266 DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));\r
267 return Status;\r
268 }\r
269\r
270 //\r
271 // Make sure BlockSize and LBA is consistent with BufferSize\r
272 //\r
273 if ((BufferSize % Media->BlockSize) != 0) {\r
274 return EFI_BAD_BUFFER_SIZE;\r
275 }\r
276\r
277 TotalBlock = BufferSize / Media->BlockSize;\r
278\r
279 if (Lba + TotalBlock - 1 > Media->LastBlock) {\r
280 return EFI_BAD_BUFFER_SIZE;\r
281 }\r
282\r
283 //\r
284 // Try to write the data even the device is marked as ReadOnly,\r
285 // and clear the status should the write succeed.\r
286 //\r
287 Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);\r
288 if (EFI_ERROR (Status)) {\r
289 DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));\r
290 UsbMassReset (This, TRUE);\r
291 }\r
292\r
293 return Status;\r
294}\r
295\r
296\r
297/**\r
298 Flush the cached writes to disks. USB mass storage device doesn't\r
299 support write cache, so return EFI_SUCCESS directly.\r
300\r
301 @param This The BLOCK IO protocol\r
302\r
303 @retval EFI_SUCCESS Always returns success\r
304\r
305**/\r
306EFI_STATUS\r
307UsbMassFlushBlocks (\r
308 IN EFI_BLOCK_IO_PROTOCOL *This\r
309 )\r
310{\r
311 return EFI_SUCCESS;\r
312}\r
313\r
314\r
315/**\r
316 Check whether the controller is a supported USB mass storage.\r
317\r
318 @param This The USB mass driver's driver binding.\r
319 @param Controller The device to test against.\r
320 @param RemainingDevicePath The remaining device path\r
321\r
322 @retval EFI_SUCCESS This device is a supported USB mass storage.\r
323 @retval EFI_UNSUPPORTED The device isn't supported\r
324 @retval Others Some error happened.\r
325\r
326**/\r
327EFI_STATUS\r
328EFIAPI\r
329USBMassDriverBindingSupported (\r
330 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
331 IN EFI_HANDLE Controller,\r
332 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
333 )\r
334{\r
335 EFI_USB_IO_PROTOCOL *UsbIo;\r
336 EFI_USB_INTERFACE_DESCRIPTOR Interface;\r
337 USB_MASS_TRANSPORT *Transport;\r
338 EFI_STATUS Status;\r
339 INTN Index;\r
340\r
341 //\r
342 // Check whether the controlelr support USB_IO\r
343 //\r
344 Status = gBS->OpenProtocol (\r
345 Controller,\r
346 &gEfiUsbIoProtocolGuid,\r
347 &UsbIo,\r
348 This->DriverBindingHandle,\r
349 Controller,\r
350 EFI_OPEN_PROTOCOL_BY_DRIVER\r
351 );\r
352 if (EFI_ERROR (Status)) {\r
353 return Status;\r
354 }\r
355\r
356 //\r
357 // Get the interface to check the USB class and find a transport\r
358 // protocol handler.\r
359 //\r
360 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);\r
361 if (EFI_ERROR (Status)) {\r
362 goto ON_EXIT;\r
363 }\r
364\r
365 Status = EFI_UNSUPPORTED;\r
366\r
367 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {\r
368 goto ON_EXIT;\r
369 }\r
370\r
371 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {\r
372 Transport = mUsbMassTransport[Index];\r
373 if (Interface.InterfaceProtocol == Transport->Protocol) {\r
374 Status = Transport->Init (UsbIo, Controller, NULL);\r
375 break;\r
376 }\r
377 }\r
378\r
379 DEBUG ((mUsbMscInfo, "Found a USB mass store device %r\n", Status));\r
380\r
381ON_EXIT:\r
382 gBS->CloseProtocol (\r
383 Controller,\r
384 &gEfiUsbIoProtocolGuid,\r
385 This->DriverBindingHandle,\r
386 Controller\r
387 );\r
388\r
389 return Status;\r
390}\r
391\r
392\r
393/**\r
394 Start the USB mass storage device on the controller. It will\r
395 install a BLOCK_IO protocol on the device if everything is OK.\r
396\r
397 @param This The USB mass storage driver binding.\r
398 @param Controller The USB mass storage device to start on\r
399 @param RemainingDevicePath The remaining device path.\r
400\r
401 @retval EFI_SUCCESS The driver has started on the device.\r
402 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory\r
403 @retval Others Failed to start the driver on the device.\r
404\r
405**/\r
406EFI_STATUS\r
407EFIAPI\r
408USBMassDriverBindingStart (\r
409 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
410 IN EFI_HANDLE Controller,\r
411 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
412 )\r
413{\r
414 EFI_USB_IO_PROTOCOL *UsbIo;\r
415 EFI_USB_INTERFACE_DESCRIPTOR Interface;\r
416 USB_MASS_DEVICE *UsbMass;\r
417 USB_MASS_TRANSPORT *Transport;\r
418 EFI_STATUS Status;\r
419 UINTN Index;\r
420\r
421 Status = gBS->OpenProtocol (\r
422 Controller,\r
423 &gEfiUsbIoProtocolGuid,\r
424 &UsbIo,\r
425 This->DriverBindingHandle,\r
426 Controller,\r
427 EFI_OPEN_PROTOCOL_BY_DRIVER\r
428 );\r
429\r
430 if (EFI_ERROR (Status)) {\r
431 return Status;\r
432 }\r
433\r
434 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));\r
435 if (UsbMass == NULL) {\r
436 return EFI_OUT_OF_RESOURCES;\r
437 }\r
438\r
439 //\r
440 // Initialize the transport protocols\r
441 //\r
442 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);\r
443 if (EFI_ERROR (Status)) {\r
444 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));\r
445 goto ON_ERROR;\r
446 }\r
447\r
448 Status = EFI_UNSUPPORTED;\r
449\r
450 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {\r
451 Transport = mUsbMassTransport[Index];\r
452\r
453 if (Interface.InterfaceProtocol == Transport->Protocol) {\r
454 UsbMass->Transport = Transport;\r
455 Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);\r
456 break;\r
457 }\r
458 }\r
459\r
460 if (EFI_ERROR (Status)) {\r
461 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));\r
462 goto ON_ERROR;\r
463 }\r
464\r
465 UsbMass->Signature = USB_MASS_SIGNATURE;\r
466 UsbMass->Controller = Controller;\r
467 UsbMass->UsbIo = UsbIo;\r
468 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;\r
469 UsbMass->BlockIo.Reset = UsbMassReset;\r
470 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;\r
471 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;\r
472 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;\r
473 UsbMass->OpticalStorage = FALSE;\r
474\r
475 //\r
476 // Get the storage's parameters, such as last block number.\r
477 // then install the BLOCK_IO\r
478 //\r
479 Status = UsbMassInitMedia (UsbMass);\r
480 if (!EFI_ERROR (Status)) {\r
481 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&\r
482 (UsbMass->Pdt != USB_PDT_CDROM) &&\r
483 (UsbMass->Pdt != USB_PDT_OPTICAL) &&\r
484 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {\r
485 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));\r
486 goto ON_ERROR;\r
487 }\r
488 } else if (Status != EFI_NO_MEDIA){\r
489 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));\r
490 goto ON_ERROR;\r
491 }\r
492\r
493 Status = gBS->InstallProtocolInterface (\r
494 &Controller,\r
495 &gEfiBlockIoProtocolGuid,\r
496 EFI_NATIVE_INTERFACE,\r
497 &UsbMass->BlockIo\r
498 );\r
499 if (EFI_ERROR (Status)) {\r
500 goto ON_ERROR;\r
501 }\r
502\r
503 return EFI_SUCCESS;\r
504\r
505ON_ERROR:\r
506 gBS->FreePool (UsbMass);\r
507\r
508 gBS->CloseProtocol (\r
509 Controller,\r
510 &gEfiUsbIoProtocolGuid,\r
511 This->DriverBindingHandle,\r
512 Controller\r
513 );\r
514\r
515 return Status;\r
516}\r
517\r
518\r
519/**\r
520 Stop controlling the device.\r
521\r
522 @param This The USB mass storage driver binding\r
523 @param Controller The device controller controlled by the driver.\r
524 @param NumberOfChildren The number of children of this device\r
525 @param ChildHandleBuffer The buffer of children handle.\r
526\r
527 @retval EFI_SUCCESS The driver stopped from controlling the device.\r
528 @retval Others Failed to stop the driver\r
529\r
530**/\r
531EFI_STATUS\r
532EFIAPI\r
533USBMassDriverBindingStop (\r
534 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
535 IN EFI_HANDLE Controller,\r
536 IN UINTN NumberOfChildren,\r
537 IN EFI_HANDLE *ChildHandleBuffer\r
538 )\r
539{\r
540 EFI_STATUS Status;\r
541 USB_MASS_DEVICE *UsbMass;\r
542 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
543\r
544 //\r
545 // First, get our context back from the BLOCK_IO\r
546 //\r
547 Status = gBS->OpenProtocol (\r
548 Controller,\r
549 &gEfiBlockIoProtocolGuid,\r
550 &BlockIo,\r
551 This->DriverBindingHandle,\r
552 Controller,\r
553 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
554 );\r
555\r
556 if (EFI_ERROR (Status)) {\r
557 return Status;\r
558 }\r
559\r
560 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);\r
561\r
562 //\r
563 // Uninstall Block I/O protocol from the device handle,\r
564 // then call the transport protocol to stop itself.\r
565 //\r
566 Status = gBS->UninstallProtocolInterface (\r
567 Controller,\r
568 &gEfiBlockIoProtocolGuid,\r
569 &UsbMass->BlockIo\r
570 );\r
571 if (EFI_ERROR (Status)) {\r
572 return Status;\r
573 }\r
574\r
575 gBS->CloseProtocol (\r
576 Controller,\r
577 &gEfiUsbIoProtocolGuid,\r
578 This->DriverBindingHandle,\r
579 Controller\r
580 );\r
581\r
582 UsbMass->Transport->Fini (UsbMass->Context);\r
583 gBS->FreePool (UsbMass);\r
584\r
585 return EFI_SUCCESS;\r
586}\r
587\r
588EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {\r
589 USBMassDriverBindingSupported,\r
590 USBMassDriverBindingStart,\r
591 USBMassDriverBindingStop,\r
592 0x11,\r
593 NULL,\r
594 NULL\r
595};\r
596\r
597//@MT: EFI_DRIVER_ENTRY_POINT (USBMassStorageEntryPoint)\r
598\r
599EFI_STATUS\r
600EFIAPI\r
601USBMassStorageEntryPoint (\r
602 IN EFI_HANDLE ImageHandle,\r
603 IN EFI_SYSTEM_TABLE *SystemTable\r
604 )\r
605/*++\r
606\r
607Routine Description:\r
608\r
609 The entry point for the driver, which will install the driver binding and\r
610 component name protocol\r
611\r
612Arguments:\r
613\r
614 ImageHandle - The image handle of this driver\r
615 SystemTable - The system table\r
616\r
617Returns:\r
618\r
619 EFI_SUCCESS - the protocols are installed OK\r
620 Others - Failed to install protocols.\r
621\r
622--*/\r
623{\r
624 EFI_STATUS Status;\r
625\r
626 //\r
627 // Install driver binding protocol\r
628 //\r
629 Status = EfiLibInstallAllDriverProtocols (\r
630 ImageHandle,\r
631 SystemTable,\r
632 &gUSBMassDriverBinding,\r
633 ImageHandle,\r
634 &gUsbMassStorageComponentName,\r
635 NULL,\r
636 NULL\r
637 );\r
638\r
639 return Status;\r
640}\r