]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
modify coding style to pass ecc tool
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBoot.c
1 /** @file
2
3 This file implement the command set of "USB Mass Storage Specification
4 for Bootability".
5
6 Copyright (c) 2007 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "UsbMassImpl.h"
18
19
20 /**
21 Return the current TPL.
22
23 @return Current TPL.
24
25 **/
26 EFI_TPL
27 UsbGetCurrentTpl (
28 VOID
29 )
30 {
31 EFI_TPL Tpl;
32
33 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
34 gBS->RestoreTPL (Tpl);
35
36 return Tpl;
37 }
38
39 /**
40 Read an UINT32 from the buffer to avoid byte alignment problems, then
41 convert that to the little endia. The USB mass storage bootability spec
42 use big endia.
43
44 @param Buf The buffer contains the first byte of the UINT32
45 in big endia.
46
47 @return The UINT32 value read from the buffer in little endia.
48
49 **/
50 UINT32
51 UsbBootGetUint32 (
52 IN UINT8 *Buf
53 )
54 {
55 UINT32 Value;
56
57 CopyMem (&Value, Buf, sizeof (UINT32));
58 return USB_BOOT_SWAP32 (Value);
59 }
60
61
62 /**
63 Put an UINT32 in little endia to the buffer. The data is converted to
64 big endia before writing.
65
66 @param Buf The buffer to write data to.
67 @param Data32 The data to write.
68
69 @return None.
70
71 **/
72 VOID
73 UsbBootPutUint32 (
74 IN UINT8 *Buf,
75 IN UINT32 Data32
76 )
77 {
78 Data32 = USB_BOOT_SWAP32 (Data32);
79 CopyMem (Buf, &Data32, sizeof (UINT32));
80 }
81
82 /**
83 Put an UINT16 in little endia to the buffer. The data is converted to
84 big endia before writing.
85
86 @param Buf The buffer to write data to.
87 @param Data16 The data to write.
88
89 @return None.
90
91 **/
92 VOID
93 UsbBootPutUint16 (
94 IN UINT8 *Buf,
95 IN UINT16 Data16
96 )
97 {
98 Data16 = (UINT16) (USB_BOOT_SWAP16 (Data16));
99 CopyMem (Buf, &Data16, sizeof (UINT16));
100 }
101
102 /**
103 Request sense information via sending Request Sense
104 Packet Command.
105
106 @param UsbMass The device to be requested sense data.
107
108 @retval EFI_SUCCESS The command is excuted OK.
109 @retval EFI_DEVICE_ERROR Failed to request sense.
110 @retval EFI_NO_RESPONSE The device media doesn't response this request.
111 @retval EFI_INVALID_PARAMETER The command has some invalid parameters.
112 @retval EFI_WRITE_PROTECTED The device is write protected.
113 @retval EFI_MEDIA_CHANGED The device media has been changed.
114
115 **/
116 EFI_STATUS
117 UsbBootRequestSense (
118 IN USB_MASS_DEVICE *UsbMass
119 )
120 {
121 USB_BOOT_REQUEST_SENSE_CMD SenseCmd;
122 USB_BOOT_REQUEST_SENSE_DATA SenseData;
123 EFI_BLOCK_IO_MEDIA *Media;
124 USB_MASS_TRANSPORT *Transport;
125 EFI_STATUS Status;
126 UINT32 CmdResult;
127
128 Transport = UsbMass->Transport;
129
130 //
131 // Request the sense data from the device if command failed
132 //
133 ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
134 ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
135
136 SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;
137 SenseCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
138 SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA);
139
140 Status = Transport->ExecCommand (
141 UsbMass->Context,
142 &SenseCmd,
143 sizeof (USB_BOOT_REQUEST_SENSE_CMD),
144 EfiUsbDataIn,
145 &SenseData,
146 sizeof (USB_BOOT_REQUEST_SENSE_DATA),
147 UsbMass->Lun,
148 USB_BOOT_GENERAL_CMD_TIMEOUT,
149 &CmdResult
150 );
151 if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
152 DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
153 return Status;
154 }
155
156 //
157 // Interpret the sense data and update the media status if necessary.
158 //
159 Media = &UsbMass->BlockIoMedia;
160
161 switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
162
163 case USB_BOOT_SENSE_NO_SENSE:
164 Status = EFI_NO_RESPONSE;
165 break;
166
167 case USB_BOOT_SENSE_RECOVERED:
168 //
169 // Suppose hardware can handle this case, and recover later by itself
170 //
171 Status = EFI_NOT_READY;
172 break;
173
174 case USB_BOOT_SENSE_NOT_READY:
175 Status = EFI_DEVICE_ERROR;
176 if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) {
177 Media->MediaPresent = FALSE;
178 Status = EFI_NO_MEDIA;
179 } else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) {
180 Status = EFI_NOT_READY;
181 }
182 break;
183
184 case USB_BOOT_SENSE_ILLEGAL_REQUEST:
185 Status = EFI_INVALID_PARAMETER;
186 break;
187
188 case USB_BOOT_SENSE_UNIT_ATTENTION:
189 Status = EFI_DEVICE_ERROR;
190 if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {
191 //
192 // If MediaChange, reset ReadOnly and new MediId
193 //
194 Status = EFI_MEDIA_CHANGED;
195 Media->ReadOnly = FALSE;
196 Media->MediaId++;
197 }
198 break;
199
200 case USB_BOOT_SNESE_DATA_PROTECT:
201 Status = EFI_WRITE_PROTECTED;
202 Media->ReadOnly = TRUE;
203 break;
204
205 default:
206 Status = EFI_DEVICE_ERROR;
207 break;
208 }
209
210 DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
211 Status,
212 USB_BOOT_SENSE_KEY (SenseData.SenseKey),
213 SenseData.ASC,
214 SenseData.ASCQ
215 ));
216
217 return Status;
218 }
219
220
221 /**
222 Execute the USB mass storage bootability commands. If execution
223 failed, retrieve the error by REQUEST_SENSE then update the device's
224 status, such as ReadyOnly.
225
226 @param UsbMass The device to issue commands to
227 @param Cmd The command to execute
228 @param CmdLen The length of the command
229 @param DataDir The direction of data transfer
230 @param Data The buffer to hold the data
231 @param DataLen The length of expected data
232 @param Timeout The timeout used to transfer
233
234 @retval EFI_SUCCESS The command is excuted OK
235 @retval EFI_DEVICE_ERROR Failed to request sense
236 @retval EFI_INVALID_PARAMETER The command has some invalid parameters
237 @retval EFI_WRITE_PROTECTED The device is write protected
238 @retval EFI_MEDIA_CHANGED The device media has been changed
239
240 **/
241 EFI_STATUS
242 UsbBootExecCmd (
243 IN USB_MASS_DEVICE *UsbMass,
244 IN VOID *Cmd,
245 IN UINT8 CmdLen,
246 IN EFI_USB_DATA_DIRECTION DataDir,
247 IN VOID *Data,
248 IN UINT32 DataLen,
249 IN UINT32 Timeout
250 )
251 {
252 USB_MASS_TRANSPORT *Transport;
253 EFI_STATUS Status;
254 UINT32 CmdResult;
255
256 Transport = UsbMass->Transport;
257 Status = Transport->ExecCommand (
258 UsbMass->Context,
259 Cmd,
260 CmdLen,
261 DataDir,
262 Data,
263 DataLen,
264 UsbMass->Lun,
265 Timeout,
266 &CmdResult
267 );
268 //
269 // ExecCommand return success and get the right CmdResult means
270 // the commnad transfer is OK.
271 //
272 if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) {
273 return EFI_SUCCESS;
274 }
275
276 DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",
277 *(UINT8 *)Cmd ,Status));
278
279 return UsbBootRequestSense (UsbMass);
280 }
281
282
283 /**
284 Execute the USB mass storage bootability commands. If execution
285 failed, retrieve the error by REQUEST_SENSE then update the device's
286 status, such as ReadyOnly.
287
288 @param UsbMass The device to issue commands to
289 @param Cmd The command to execute
290 @param CmdLen The length of the command
291 @param DataDir The direction of data transfer
292 @param Data The buffer to hold the data
293 @param DataLen The length of expected data
294 @param Timeout The timeout used to transfer
295
296 @retval EFI_SUCCESS The command is excuted OK
297 @retval EFI_DEVICE_ERROR Failed to request sense
298 @retval EFI_INVALID_PARAMETER The command has some invalid parameters
299 @retval EFI_WRITE_PROTECTED The device is write protected
300 @retval EFI_MEDIA_CHANGED The device media has been changed
301
302 **/
303 EFI_STATUS
304 UsbBootExecCmdWithRetry (
305 IN USB_MASS_DEVICE *UsbMass,
306 IN VOID *Cmd,
307 IN UINT8 CmdLen,
308 IN EFI_USB_DATA_DIRECTION DataDir,
309 IN VOID *Data,
310 IN UINT32 DataLen,
311 IN UINT32 Timeout
312 )
313 {
314 EFI_STATUS Status;
315 INT16 Index;
316
317 //
318 // If the device isn't ready, wait some time. If the device is ready,
319 // retry the command again.
320 //
321 Status = EFI_SUCCESS;
322
323 for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) {
324 //
325 // Execute the command with an increasingly larger timeout value.
326 //
327 Status = UsbBootExecCmd (
328 UsbMass,
329 Cmd,
330 CmdLen,
331 DataDir,
332 Data,
333 DataLen,
334 Timeout
335 );
336 if (Status == EFI_SUCCESS ||
337 Status == EFI_MEDIA_CHANGED) {
338 break;
339 }
340 //
341 // Need retry once more, so reset index
342 //
343 if (Status == EFI_NOT_READY) {
344 Index = 0;
345 }
346 }
347
348 return Status;
349 }
350
351
352 /**
353 Use the TEST UNIT READY command to check whether it is ready.
354 If it is ready, update the parameters.
355
356 @param UsbMass The device to test
357
358 @retval EFI_SUCCESS The device is ready and parameters are updated.
359 @retval Others Device not ready.
360
361 **/
362 EFI_STATUS
363 UsbBootIsUnitReady (
364 IN USB_MASS_DEVICE *UsbMass
365 )
366 {
367 USB_BOOT_TEST_UNIT_READY_CMD TestCmd;
368
369 ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
370
371 TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;
372 TestCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
373
374 return UsbBootExecCmdWithRetry (
375 UsbMass,
376 &TestCmd,
377 sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
378 EfiUsbNoData,
379 NULL,
380 0,
381 USB_BOOT_GENERAL_CMD_TIMEOUT
382 );
383 }
384
385
386 /**
387 Inquiry Command requests that information regrarding parameters of
388 the Device be sent to the Host.
389
390 @param UsbMass The device to inquiry.
391
392 @retval EFI_SUCCESS The device is ready and parameters are updated.
393 @retval Others Device not ready.
394
395 **/
396 EFI_STATUS
397 UsbBootInquiry (
398 IN USB_MASS_DEVICE *UsbMass
399 )
400 {
401 USB_BOOT_INQUIRY_CMD InquiryCmd;
402 USB_BOOT_INQUIRY_DATA InquiryData;
403 EFI_BLOCK_IO_MEDIA *Media;
404 EFI_STATUS Status;
405
406 Media = &(UsbMass->BlockIoMedia);
407
408 //
409 // Use the Inquiry command to get the RemovableMedia setting.
410 //
411 ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
412 ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
413
414 InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
415 InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
416 InquiryCmd.AllocLen = sizeof (InquiryData);
417
418 Status = UsbBootExecCmdWithRetry (
419 UsbMass,
420 &InquiryCmd,
421 sizeof (USB_BOOT_INQUIRY_CMD),
422 EfiUsbDataIn,
423 &InquiryData,
424 sizeof (USB_BOOT_INQUIRY_DATA),
425 USB_BOOT_GENERAL_CMD_TIMEOUT
426 );
427 if (EFI_ERROR (Status)) {
428 return Status;
429 }
430
431 UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt));
432 Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable));
433 //
434 // Default value 512 Bytes, in case no media present at first time
435 //
436 Media->BlockSize = 0x0200;
437
438 return Status;
439 }
440
441
442 /**
443 Get the capacity of the USB mass storage media, including
444 the presentation, block size, and last block number. This
445 function is used to get the disk parameters at the start if
446 it is a non-removable media or to detect the media if it is
447 removable.
448
449 @param UsbMass The device to retireve disk gemotric.
450
451 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
452 @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
453 @retval Other Read capacity request fails.
454
455 **/
456 EFI_STATUS
457 UsbBootReadCapacity (
458 IN USB_MASS_DEVICE *UsbMass
459 )
460 {
461 USB_BOOT_READ_CAPACITY_CMD CapacityCmd;
462 USB_BOOT_READ_CAPACITY_DATA CapacityData;
463 EFI_BLOCK_IO_MEDIA *Media;
464 EFI_STATUS Status;
465
466 Media = &UsbMass->BlockIoMedia;
467
468 //
469 // Use the READ CAPACITY command to get the block length and last blockno
470 //
471 ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
472 ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
473
474 CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
475 CapacityCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
476
477 Status = UsbBootExecCmdWithRetry (
478 UsbMass,
479 &CapacityCmd,
480 sizeof (USB_BOOT_READ_CAPACITY_CMD),
481 EfiUsbDataIn,
482 &CapacityData,
483 sizeof (USB_BOOT_READ_CAPACITY_DATA),
484 USB_BOOT_GENERAL_CMD_TIMEOUT
485 );
486 if (EFI_ERROR (Status)) {
487 return Status;
488 }
489
490 Media->MediaPresent = TRUE;
491 Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba);
492 Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen);
493
494 if (Media->BlockSize == 0) {
495 return EFI_NOT_READY;
496 }
497
498 DEBUG ((EFI_D_INFO, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n",
499 Media->LastBlock, Media->BlockSize));
500
501 return EFI_SUCCESS;
502 }
503
504 /**
505 Retrieves mode sense information via sending Mode Sense
506 Packet Command.
507
508 @param UsbMass The USB_FLOPPY_DEV instance.
509
510 @retval EFI_SUCCESS Success
511 @retval Other Execute Request command fails.
512
513 **/
514 EFI_STATUS
515 UsbScsiModeSense (
516 IN USB_MASS_DEVICE *UsbMass
517 )
518 {
519 EFI_STATUS Status;
520 USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;
521 USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
522 EFI_BLOCK_IO_MEDIA *Media;
523
524 Media = &UsbMass->BlockIoMedia;
525
526 ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
527 ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
528
529 //
530 // ModeSense6 command is defined in [SCSI2Spec-Page151]
531 //
532 ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;
533 ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
534 ModeSenseCmd.PageCode = 0x3F;
535 ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
536
537 Status = UsbBootExecCmdWithRetry (
538 UsbMass,
539 &ModeSenseCmd,
540 sizeof (USB_SCSI_MODE_SENSE6_CMD),
541 EfiUsbDataIn,
542 &ModeParaHeader,
543 sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
544 USB_BOOT_GENERAL_CMD_TIMEOUT
545 );
546
547 //
548 // ModeSense(6) is used to get the information of WriteProtected. While only some of
549 // devices support this command, so have a try here.
550 //
551 if (!EFI_ERROR (Status)) {
552 Media->ReadOnly = (BOOLEAN) (((ModeParaHeader.DevicePara & 0x80) != 0) ? TRUE : FALSE);
553 }
554
555 return Status;
556 }
557
558
559 /**
560 Get the parameters for the USB mass storage media, including
561 the RemovableMedia, block size, and last block number. This
562 function is used both to initialize the media during the
563 DriverBindingStart and to re-initialize it when the media is
564 changed. Althought the RemoveableMedia is unlikely to change,
565 I include it here.
566
567 @param UsbMass The device to retireve disk gemotric.
568
569 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
570 @retval Other Get the parameters failed.
571
572 **/
573 EFI_STATUS
574 UsbBootGetParams (
575 IN USB_MASS_DEVICE *UsbMass
576 )
577 {
578 EFI_BLOCK_IO_MEDIA *Media;
579 EFI_STATUS Status;
580 UINT8 CmdSet;
581
582 Media = &(UsbMass->BlockIoMedia);
583 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
584
585 Status = UsbBootInquiry (UsbMass);
586 if (EFI_ERROR (Status)) {
587 DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
588 return Status;
589 }
590
591 //
592 // Don't use the Removable bit in inquirydata to test whether the media
593 // is removable because many flash disks wrongly set this bit.
594 //
595 if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
596 //
597 // CD-Rom device and Non-CD optical device
598 //
599 UsbMass->OpticalStorage = TRUE;
600 //
601 // Default value 2048 Bytes, in case no media present at first time
602 //
603 Media->BlockSize = 0x0800;
604 }
605
606 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
607 //
608 // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,
609 // which is from [MassStorageBootabilitySpec-Page7].
610 // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI
611 // could get the information of WriteProtected.
612 // Since not all device support this command, so skip if fail.
613 //
614 UsbScsiModeSense (UsbMass);
615 }
616
617 return UsbBootReadCapacity (UsbMass);
618 }
619
620
621 /**
622 Detect whether the removable media is present and whether it has changed.
623 The Non-removable media doesn't need it.
624
625 @param UsbMass The device to retireve disk gemotric.
626
627 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
628 @retval Other Decect media fails.
629
630 **/
631 EFI_STATUS
632 UsbBootDetectMedia (
633 IN USB_MASS_DEVICE *UsbMass
634 )
635 {
636 EFI_BLOCK_IO_MEDIA OldMedia;
637 EFI_BLOCK_IO_MEDIA *Media;
638 UINT8 CmdSet;
639 EFI_TPL OldTpl;
640 EFI_STATUS Status;
641
642 Media = &UsbMass->BlockIoMedia;
643
644 CopyMem (
645 &OldMedia,
646 &(UsbMass->BlockIoMedia),
647 sizeof (EFI_BLOCK_IO_MEDIA)
648 );
649
650 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
651
652 Status = UsbBootIsUnitReady (UsbMass);
653 if (EFI_ERROR (Status)) {
654 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));
655 goto ON_ERROR;
656 }
657
658 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
659 //
660 // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,
661 // which is from [MassStorageBootabilitySpec-Page7].
662 // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI
663 // could get the information of WriteProtected.
664 // Since not all device support this command, so skip if fail.
665 //
666 UsbScsiModeSense (UsbMass);
667 }
668
669 Status = UsbBootReadCapacity (UsbMass);
670 if (EFI_ERROR (Status)) {
671 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
672 goto ON_ERROR;
673 }
674
675 return EFI_SUCCESS;
676
677 ON_ERROR:
678 //
679 // Detect whether it is necessary to reinstall the BlockIO
680 //
681 // MediaId may change in RequestSense for MediaChanged
682 // MediaPresent may change in RequestSense for NoMedia
683 // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
684 // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
685 //
686 if ((Media->MediaId != OldMedia.MediaId) ||
687 (Media->MediaPresent != OldMedia.MediaPresent) ||
688 (Media->ReadOnly != OldMedia.ReadOnly) ||
689 (Media->BlockSize != OldMedia.BlockSize) ||
690 (Media->LastBlock != OldMedia.LastBlock)) {
691
692 OldTpl = UsbGetCurrentTpl ();
693 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL before reinstall BlockIoProtocol is %d\n", OldTpl));
694
695 gBS->RestoreTPL (TPL_CALLBACK);
696
697 gBS->ReinstallProtocolInterface (
698 UsbMass->Controller,
699 &gEfiBlockIoProtocolGuid,
700 &UsbMass->BlockIo,
701 &UsbMass->BlockIo
702 );
703
704 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL after reinstall is %d\n", UsbGetCurrentTpl()));
705 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
706
707 gBS->RaiseTPL (OldTpl);
708
709 //
710 // Update MediaId after reinstall BLOCK_IO_PROTOCOL
711 //
712 if (Media->MediaPresent != OldMedia.MediaPresent) {
713 if (Media->MediaPresent == TRUE) {
714 Media->MediaId = 1;
715 } else {
716 Media->MediaId = 0;
717 }
718 }
719
720 if ((Media->ReadOnly != OldMedia.ReadOnly) ||
721 (Media->BlockSize != OldMedia.BlockSize) ||
722 (Media->LastBlock != OldMedia.LastBlock)) {
723 Media->MediaId++;
724 }
725 }
726
727 return Status;
728 }
729
730
731 /**
732 Read some blocks from the device.
733
734 @param UsbMass The USB mass storage device to read from
735 @param Lba The start block number
736 @param TotalBlock Total block number to read
737 @param Buffer The buffer to read to
738
739 @retval EFI_SUCCESS Data are read into the buffer
740 @retval Others Failed to read all the data
741
742 **/
743 EFI_STATUS
744 UsbBootReadBlocks (
745 IN USB_MASS_DEVICE *UsbMass,
746 IN UINT32 Lba,
747 IN UINTN TotalBlock,
748 OUT UINT8 *Buffer
749 )
750 {
751 USB_BOOT_READ10_CMD ReadCmd;
752 EFI_STATUS Status;
753 UINT16 Count;
754 UINT32 BlockSize;
755 UINT32 ByteSize;
756 UINT32 Timeout;
757
758 BlockSize = UsbMass->BlockIoMedia.BlockSize;
759 Status = EFI_SUCCESS;
760
761 while (TotalBlock > 0) {
762 //
763 // Split the total blocks into smaller pieces to ease the pressure
764 // on the device. We must split the total block because the READ10
765 // command only has 16 bit transfer length (in the unit of block).
766 //
767 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
768 ByteSize = (UINT32)Count * BlockSize;
769
770 //
771 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
772 //
773 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
774
775 //
776 // Fill in the command then execute
777 //
778 ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));
779
780 ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;
781 ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
782 UsbBootPutUint32 (ReadCmd.Lba, Lba);
783 UsbBootPutUint16 (ReadCmd.TransferLen, Count);
784
785 Status = UsbBootExecCmdWithRetry (
786 UsbMass,
787 &ReadCmd,
788 sizeof (USB_BOOT_READ10_CMD),
789 EfiUsbDataIn,
790 Buffer,
791 ByteSize,
792 Timeout
793 );
794 if (EFI_ERROR (Status)) {
795 return Status;
796 }
797
798 Lba += Count;
799 Buffer += Count * BlockSize;
800 TotalBlock -= Count;
801 }
802
803 return Status;
804 }
805
806
807 /**
808 Write some blocks to the device.
809
810 @param UsbMass The USB mass storage device to write to
811 @param Lba The start block number
812 @param TotalBlock Total block number to write
813 @param Buffer The buffer to write to
814
815 @retval EFI_SUCCESS Data are written into the buffer
816 @retval Others Failed to write all the data
817
818 **/
819 EFI_STATUS
820 UsbBootWriteBlocks (
821 IN USB_MASS_DEVICE *UsbMass,
822 IN UINT32 Lba,
823 IN UINTN TotalBlock,
824 OUT UINT8 *Buffer
825 )
826 {
827 USB_BOOT_WRITE10_CMD WriteCmd;
828 EFI_STATUS Status;
829 UINT16 Count;
830 UINT32 BlockSize;
831 UINT32 ByteSize;
832 UINT32 Timeout;
833
834 BlockSize = UsbMass->BlockIoMedia.BlockSize;
835 Status = EFI_SUCCESS;
836
837 while (TotalBlock > 0) {
838 //
839 // Split the total blocks into smaller pieces to ease the pressure
840 // on the device. We must split the total block because the WRITE10
841 // command only has 16 bit transfer length (in the unit of block).
842 //
843 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
844 ByteSize = (UINT32)Count * BlockSize;
845
846 //
847 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
848 //
849 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
850
851 //
852 // Fill in the write10 command block
853 //
854 ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));
855
856 WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
857 WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
858 UsbBootPutUint32 (WriteCmd.Lba, Lba);
859 UsbBootPutUint16 (WriteCmd.TransferLen, Count);
860
861 Status = UsbBootExecCmdWithRetry (
862 UsbMass,
863 &WriteCmd,
864 sizeof (USB_BOOT_WRITE10_CMD),
865 EfiUsbDataOut,
866 Buffer,
867 ByteSize,
868 Timeout
869 );
870 if (EFI_ERROR (Status)) {
871 return Status;
872 }
873
874 Lba += Count;
875 Buffer += Count * BlockSize;
876 TotalBlock -= Count;
877 }
878
879 return Status;
880 }
881
882
883 /**
884 Use the USB clear feature control transfer to clear the endpoint
885 stall condition.
886
887 @param UsbIo The USB IO protocol to use
888 @param EndpointAddr The endpoint to clear stall for
889
890 @retval EFI_SUCCESS The endpoint stall condtion is clear
891 @retval Others Failed to clear the endpoint stall condtion
892
893 **/
894 EFI_STATUS
895 UsbClearEndpointStall (
896 IN EFI_USB_IO_PROTOCOL *UsbIo,
897 IN UINT8 EndpointAddr
898 )
899 {
900 EFI_USB_DEVICE_REQUEST Request;
901 EFI_STATUS Status;
902 UINT32 CmdResult;
903 UINT32 Timeout;
904
905 Request.RequestType = 0x02;
906 Request.Request = USB_REQ_CLEAR_FEATURE;
907 Request.Value = USB_FEATURE_ENDPOINT_HALT;
908 Request.Index = EndpointAddr;
909 Request.Length = 0;
910 Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;
911
912 Status = UsbIo->UsbControlTransfer (
913 UsbIo,
914 &Request,
915 EfiUsbNoData,
916 Timeout,
917 NULL,
918 0,
919 &CmdResult
920 );
921
922 return Status;
923 }