2 Implementation of the command set of USB Mass Storage Specification
3 for Bootability, Revision 1.0.
5 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UsbMassImpl.h"
19 Execute REQUEST SENSE Command to retrieve sense data from device.
21 @param UsbMass The device whose sense data is requested.
23 @retval EFI_SUCCESS The command is excuted successfully.
24 @retval EFI_DEVICE_ERROR Failed to request sense.
25 @retval EFI_NO_RESPONSE The device media doesn't response this request.
26 @retval EFI_INVALID_PARAMETER The command has some invalid parameters.
27 @retval EFI_WRITE_PROTECTED The device is write protected.
28 @retval EFI_MEDIA_CHANGED The device media has been changed.
33 IN USB_MASS_DEVICE
*UsbMass
36 USB_BOOT_REQUEST_SENSE_CMD SenseCmd
;
37 USB_BOOT_REQUEST_SENSE_DATA SenseData
;
38 EFI_BLOCK_IO_MEDIA
*Media
;
39 USB_MASS_TRANSPORT
*Transport
;
43 Transport
= UsbMass
->Transport
;
46 // Request the sense data from the device
48 ZeroMem (&SenseCmd
, sizeof (USB_BOOT_REQUEST_SENSE_CMD
));
49 ZeroMem (&SenseData
, sizeof (USB_BOOT_REQUEST_SENSE_DATA
));
51 SenseCmd
.OpCode
= USB_BOOT_REQUEST_SENSE_OPCODE
;
52 SenseCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
53 SenseCmd
.AllocLen
= (UINT8
) sizeof (USB_BOOT_REQUEST_SENSE_DATA
);
55 Status
= Transport
->ExecCommand (
58 sizeof (USB_BOOT_REQUEST_SENSE_CMD
),
61 sizeof (USB_BOOT_REQUEST_SENSE_DATA
),
63 USB_BOOT_GENERAL_CMD_TIMEOUT
,
66 if (EFI_ERROR (Status
) || CmdResult
!= USB_MASS_CMD_SUCCESS
) {
67 DEBUG ((EFI_D_ERROR
, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status
, CmdResult
));
68 if (!EFI_ERROR (Status
)) {
69 Status
= EFI_DEVICE_ERROR
;
75 // If sense data is retrieved successfully, interpret the sense data
76 // and update the media status if necessary.
78 Media
= &UsbMass
->BlockIoMedia
;
80 switch (USB_BOOT_SENSE_KEY (SenseData
.SenseKey
)) {
82 case USB_BOOT_SENSE_NO_SENSE
:
83 Status
= EFI_NO_RESPONSE
;
86 case USB_BOOT_SENSE_RECOVERED
:
88 // Suppose hardware can handle this case, and recover later by itself
90 Status
= EFI_NOT_READY
;
93 case USB_BOOT_SENSE_NOT_READY
:
94 Status
= EFI_DEVICE_ERROR
;
95 if (SenseData
.Asc
== USB_BOOT_ASC_NO_MEDIA
) {
96 Media
->MediaPresent
= FALSE
;
97 Status
= EFI_NO_MEDIA
;
98 } else if (SenseData
.Asc
== USB_BOOT_ASC_NOT_READY
) {
99 Status
= EFI_NOT_READY
;
103 case USB_BOOT_SENSE_ILLEGAL_REQUEST
:
104 Status
= EFI_INVALID_PARAMETER
;
107 case USB_BOOT_SENSE_UNIT_ATTENTION
:
108 Status
= EFI_DEVICE_ERROR
;
109 if (SenseData
.Asc
== USB_BOOT_ASC_MEDIA_CHANGE
) {
111 // If MediaChange, reset ReadOnly and new MediaId
113 Status
= EFI_MEDIA_CHANGED
;
114 Media
->ReadOnly
= FALSE
;
119 case USB_BOOT_SENSE_DATA_PROTECT
:
120 Status
= EFI_WRITE_PROTECTED
;
121 Media
->ReadOnly
= TRUE
;
125 Status
= EFI_DEVICE_ERROR
;
129 DEBUG ((EFI_D_INFO
, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
131 USB_BOOT_SENSE_KEY (SenseData
.SenseKey
),
141 Execute the USB mass storage bootability commands.
143 This function executes the USB mass storage bootability commands.
144 If execution failed, retrieve the error by REQUEST_SENSE, then
145 update the device's status, such as ReadyOnly.
147 @param UsbMass The device to issue commands to
148 @param Cmd The command to execute
149 @param CmdLen The length of the command
150 @param DataDir The direction of data transfer
151 @param Data The buffer to hold the data
152 @param DataLen The length of expected data
153 @param Timeout The timeout used to transfer
155 @retval EFI_SUCCESS Command is excuted successfully
156 @retval Others Command execution failed.
161 IN USB_MASS_DEVICE
*UsbMass
,
164 IN EFI_USB_DATA_DIRECTION DataDir
,
170 USB_MASS_TRANSPORT
*Transport
;
174 Transport
= UsbMass
->Transport
;
175 Status
= Transport
->ExecCommand (
187 // If ExecCommand() returns no error and CmdResult is success,
188 // then the commnad transfer is successful.
190 if ((CmdResult
== USB_MASS_CMD_SUCCESS
) && !EFI_ERROR (Status
)) {
194 DEBUG ((EFI_D_INFO
, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",
195 *(UINT8
*)Cmd
,Status
));
198 // If command execution failed, then retrieve error info via sense request.
200 return UsbBootRequestSense (UsbMass
);
205 Execute the USB mass storage bootability commands with retrial.
207 This function executes USB mass storage bootability commands.
208 If the device isn't ready, wait for it. If the device is ready
209 and error occurs, retry the command again until it exceeds the
210 limit of retrial times.
212 @param UsbMass The device to issue commands to
213 @param Cmd The command to execute
214 @param CmdLen The length of the command
215 @param DataDir The direction of data transfer
216 @param Data The buffer to hold the data
217 @param DataLen The length of expected data
218 @param Timeout The timeout used to transfer
220 @retval EFI_SUCCESS The command is executed successfully.
221 @retval EFI_MEDIA_CHANGED The device media has been changed.
222 @retval Others Command execution failed after retrial.
226 UsbBootExecCmdWithRetry (
227 IN USB_MASS_DEVICE
*UsbMass
,
230 IN EFI_USB_DATA_DIRECTION DataDir
,
240 Status
= EFI_SUCCESS
;
242 for (Retry
= 0, Terminate
= 0; Retry
< USB_BOOT_COMMAND_RETRY
; Retry
++) {
243 Status
= UsbBootExecCmd (
252 if (Status
== EFI_SUCCESS
|| Status
== EFI_MEDIA_CHANGED
) {
256 // If the device isn't ready, just wait for it without limit on retrial times.
258 if (Status
== EFI_NOT_READY
&& Terminate
< 3) {
269 Execute TEST UNIT READY command to check if the device is ready.
271 @param UsbMass The device to test
273 @retval EFI_SUCCESS The device is ready.
274 @retval Others Device not ready.
279 IN USB_MASS_DEVICE
*UsbMass
282 USB_BOOT_TEST_UNIT_READY_CMD TestCmd
;
284 ZeroMem (&TestCmd
, sizeof (USB_BOOT_TEST_UNIT_READY_CMD
));
286 TestCmd
.OpCode
= USB_BOOT_TEST_UNIT_READY_OPCODE
;
287 TestCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
289 return UsbBootExecCmdWithRetry (
292 (UINT8
) sizeof (USB_BOOT_TEST_UNIT_READY_CMD
),
296 USB_BOOT_GENERAL_CMD_TIMEOUT
302 Execute INQUIRY Command to request information regarding parameters of
303 the device be sent to the host computer.
305 @param UsbMass The device to inquire.
307 @retval EFI_SUCCESS INQUIRY Command is executed successfully.
308 @retval Others INQUIRY Command is not executed successfully.
313 IN USB_MASS_DEVICE
*UsbMass
316 USB_BOOT_INQUIRY_CMD InquiryCmd
;
317 USB_BOOT_INQUIRY_DATA InquiryData
;
318 EFI_BLOCK_IO_MEDIA
*Media
;
321 Media
= &(UsbMass
->BlockIoMedia
);
323 ZeroMem (&InquiryCmd
, sizeof (USB_BOOT_INQUIRY_CMD
));
324 ZeroMem (&InquiryData
, sizeof (USB_BOOT_INQUIRY_DATA
));
326 InquiryCmd
.OpCode
= USB_BOOT_INQUIRY_OPCODE
;
327 InquiryCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
328 InquiryCmd
.AllocLen
= (UINT8
) sizeof (InquiryData
);
330 Status
= UsbBootExecCmdWithRetry (
333 (UINT8
) sizeof (USB_BOOT_INQUIRY_CMD
),
336 sizeof (USB_BOOT_INQUIRY_DATA
),
337 USB_BOOT_GENERAL_CMD_TIMEOUT
339 if (EFI_ERROR (Status
)) {
344 // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
345 // from the inquiry data.
347 UsbMass
->Pdt
= (UINT8
) (USB_BOOT_PDT (InquiryData
.Pdt
));
348 Media
->RemovableMedia
= (BOOLEAN
) (USB_BOOT_REMOVABLE (InquiryData
.Removable
));
350 // Set block size to the default value of 512 Bytes, in case no media is present at first time.
352 Media
->BlockSize
= 0x0200;
359 Execute READ CAPACITY command to request information regarding
360 the capacity of the installed medium of the device.
362 This function executes READ CAPACITY command to get the capacity
363 of the USB mass storage media, including the presence, block size,
364 and last block number.
366 @param UsbMass The device to retireve disk gemotric.
368 @retval EFI_SUCCESS The disk geometry is successfully retrieved.
369 @retval EFI_NOT_READY The returned block size is zero.
370 @retval Other READ CAPACITY command execution failed.
374 UsbBootReadCapacity (
375 IN USB_MASS_DEVICE
*UsbMass
378 USB_BOOT_READ_CAPACITY_CMD CapacityCmd
;
379 USB_BOOT_READ_CAPACITY_DATA CapacityData
;
380 EFI_BLOCK_IO_MEDIA
*Media
;
384 Media
= &UsbMass
->BlockIoMedia
;
386 ZeroMem (&CapacityCmd
, sizeof (USB_BOOT_READ_CAPACITY_CMD
));
387 ZeroMem (&CapacityData
, sizeof (USB_BOOT_READ_CAPACITY_DATA
));
389 CapacityCmd
.OpCode
= USB_BOOT_READ_CAPACITY_OPCODE
;
390 CapacityCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
392 Status
= UsbBootExecCmdWithRetry (
395 (UINT8
) sizeof (USB_BOOT_READ_CAPACITY_CMD
),
398 sizeof (USB_BOOT_READ_CAPACITY_DATA
),
399 USB_BOOT_GENERAL_CMD_TIMEOUT
401 if (EFI_ERROR (Status
)) {
406 // Get the information on media presence, block size, and last block number
407 // from READ CAPACITY data.
409 Media
->MediaPresent
= TRUE
;
410 Media
->LastBlock
= SwapBytes32 (ReadUnaligned32 ((CONST UINT32
*) CapacityData
.LastLba
));
412 BlockSize
= SwapBytes32 (ReadUnaligned32 ((CONST UINT32
*) CapacityData
.BlockLen
));
413 if (BlockSize
== 0) {
417 return UsbBootRequestSense (UsbMass
);
419 Media
->BlockSize
= BlockSize
;
422 DEBUG ((EFI_D_INFO
, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n",
423 Media
->LastBlock
, Media
->BlockSize
));
429 Retrieves SCSI mode sense information via MODE SENSE(6) command.
431 @param UsbMass The device whose sense data is requested.
433 @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.
434 @retval Other Command execution failed.
439 IN USB_MASS_DEVICE
*UsbMass
443 USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd
;
444 USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader
;
445 EFI_BLOCK_IO_MEDIA
*Media
;
447 Media
= &UsbMass
->BlockIoMedia
;
449 ZeroMem (&ModeSenseCmd
, sizeof (USB_SCSI_MODE_SENSE6_CMD
));
450 ZeroMem (&ModeParaHeader
, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER
));
453 // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
455 ModeSenseCmd
.OpCode
= USB_SCSI_MODE_SENSE6_OPCODE
;
456 ModeSenseCmd
.Lun
= (UINT8
) USB_BOOT_LUN (UsbMass
->Lun
);
457 ModeSenseCmd
.PageCode
= 0x3F;
458 ModeSenseCmd
.AllocateLen
= (UINT8
) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER
);
460 Status
= UsbBootExecCmdWithRetry (
463 (UINT8
) sizeof (USB_SCSI_MODE_SENSE6_CMD
),
466 sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER
),
467 USB_BOOT_GENERAL_CMD_TIMEOUT
471 // Format of device-specific parameter byte of the mode parameter header is defined in
472 // Section 8.2.10 of SCSI-2 Spec.
473 // BIT7 of this byte is indicates whether the medium is write protected.
475 if (!EFI_ERROR (Status
)) {
476 Media
->ReadOnly
= (BOOLEAN
) ((ModeParaHeader
.DevicePara
& BIT7
) != 0);
484 Get the parameters for the USB mass storage media.
486 This function get the parameters for the USB mass storage media,
487 It is used both to initialize the media during the Start() phase
488 of Driver Binding Protocol and to re-initialize it when the media is
489 changed. Althought the RemoveableMedia is unlikely to change,
490 it is also included here.
492 @param UsbMass The device to retrieve disk gemotric.
494 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
495 @retval Other Failed to get the parameters.
500 IN USB_MASS_DEVICE
*UsbMass
503 EFI_BLOCK_IO_MEDIA
*Media
;
507 Media
= &(UsbMass
->BlockIoMedia
);
508 CmdSet
= ((EFI_USB_INTERFACE_DESCRIPTOR
*) (UsbMass
->Context
))->InterfaceSubClass
;
510 Status
= UsbBootInquiry (UsbMass
);
511 if (EFI_ERROR (Status
)) {
512 DEBUG ((EFI_D_ERROR
, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status
));
517 // Don't use the Removable bit in inquiry data to test whether the media
518 // is removable because many flash disks wrongly set this bit.
520 if ((UsbMass
->Pdt
== USB_PDT_CDROM
) || (UsbMass
->Pdt
== USB_PDT_OPTICAL
)) {
522 // CD-Rom device and Non-CD optical device
524 UsbMass
->OpticalStorage
= TRUE
;
526 // Default value 2048 Bytes, in case no media present at first time
528 Media
->BlockSize
= 0x0800;
531 if ((UsbMass
->Pdt
!= USB_PDT_CDROM
) && (CmdSet
== USB_MASS_STORE_SCSI
)) {
533 // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,
534 // which is from [MassStorageBootabilitySpec-Page7].
535 // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI
536 // could get the information of WriteProtected.
537 // Since not all device support this command, so skip if fail.
539 UsbScsiModeSense (UsbMass
);
542 return UsbBootReadCapacity (UsbMass
);
547 Detect whether the removable media is present and whether it has changed.
549 @param UsbMass The device to check.
551 @retval EFI_SUCCESS The media status is successfully checked.
552 @retval Other Failed to detect media.
557 IN USB_MASS_DEVICE
*UsbMass
560 EFI_BLOCK_IO_MEDIA OldMedia
;
561 EFI_BLOCK_IO_MEDIA
*Media
;
566 Media
= &UsbMass
->BlockIoMedia
;
568 CopyMem (&OldMedia
, &(UsbMass
->BlockIoMedia
), sizeof (EFI_BLOCK_IO_MEDIA
));
570 CmdSet
= ((EFI_USB_INTERFACE_DESCRIPTOR
*) (UsbMass
->Context
))->InterfaceSubClass
;
572 Status
= UsbBootIsUnitReady (UsbMass
);
573 if (EFI_ERROR (Status
)) {
577 if ((UsbMass
->Pdt
!= USB_PDT_CDROM
) && (CmdSet
== USB_MASS_STORE_SCSI
)) {
579 // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
580 // according to Section 4 of USB Mass Storage Specification for Bootability.
581 // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
582 // could get the information of Write Protected.
583 // Since not all device support this command, skip if fail.
585 UsbScsiModeSense (UsbMass
);
588 Status
= UsbBootReadCapacity (UsbMass
);
589 if (EFI_ERROR (Status
)) {
590 DEBUG ((EFI_D_ERROR
, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status
));
598 // Detect whether it is necessary to reinstall the Block I/O Protocol.
600 // MediaId may change in RequestSense for MediaChanged
601 // MediaPresent may change in RequestSense for NoMedia
602 // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
603 // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
605 if ((Media
->MediaId
!= OldMedia
.MediaId
) ||
606 (Media
->MediaPresent
!= OldMedia
.MediaPresent
) ||
607 (Media
->ReadOnly
!= OldMedia
.ReadOnly
) ||
608 (Media
->BlockSize
!= OldMedia
.BlockSize
) ||
609 (Media
->LastBlock
!= OldMedia
.LastBlock
)) {
612 // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.
613 // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().
615 OldTpl
= EfiGetCurrentTpl ();
616 gBS
->RestoreTPL (TPL_CALLBACK
);
618 gBS
->ReinstallProtocolInterface (
620 &gEfiBlockIoProtocolGuid
,
625 ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK
);
626 gBS
->RaiseTPL (OldTpl
);
629 // Update MediaId after reinstalling Block I/O Protocol.
631 if (Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
632 if (Media
->MediaPresent
) {
639 if ((Media
->ReadOnly
!= OldMedia
.ReadOnly
) ||
640 (Media
->BlockSize
!= OldMedia
.BlockSize
) ||
641 (Media
->LastBlock
!= OldMedia
.LastBlock
)) {
651 Read some blocks from the device.
653 @param UsbMass The USB mass storage device to read from
654 @param Lba The start block number
655 @param TotalBlock Total block number to read
656 @param Buffer The buffer to read to
658 @retval EFI_SUCCESS Data are read into the buffer
659 @retval Others Failed to read all the data
664 IN USB_MASS_DEVICE
*UsbMass
,
670 USB_BOOT_READ10_CMD ReadCmd
;
677 BlockSize
= UsbMass
->BlockIoMedia
.BlockSize
;
678 Status
= EFI_SUCCESS
;
680 while (TotalBlock
> 0) {
682 // Split the total blocks into smaller pieces to ease the pressure
683 // on the device. We must split the total block because the READ10
684 // command only has 16 bit transfer length (in the unit of block).
686 Count
= (UINT16
)((TotalBlock
< USB_BOOT_IO_BLOCKS
) ? TotalBlock
: USB_BOOT_IO_BLOCKS
);
687 ByteSize
= (UINT32
)Count
* BlockSize
;
690 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
692 Timeout
= (UINT32
) USB_BOOT_GENERAL_CMD_TIMEOUT
;
695 // Fill in the command then execute
697 ZeroMem (&ReadCmd
, sizeof (USB_BOOT_READ10_CMD
));
699 ReadCmd
.OpCode
= USB_BOOT_READ10_OPCODE
;
700 ReadCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
701 WriteUnaligned32 ((UINT32
*) ReadCmd
.Lba
, SwapBytes32 (Lba
));
702 WriteUnaligned16 ((UINT16
*) ReadCmd
.TransferLen
, SwapBytes16 (Count
));
704 Status
= UsbBootExecCmdWithRetry (
707 (UINT8
) sizeof (USB_BOOT_READ10_CMD
),
713 if (EFI_ERROR (Status
)) {
718 Buffer
+= Count
* BlockSize
;
727 Write some blocks to the device.
729 @param UsbMass The USB mass storage device to write to
730 @param Lba The start block number
731 @param TotalBlock Total block number to write
732 @param Buffer Pointer to the source buffer for the data.
734 @retval EFI_SUCCESS Data are written into the buffer
735 @retval Others Failed to write all the data
740 IN USB_MASS_DEVICE
*UsbMass
,
746 USB_BOOT_WRITE10_CMD WriteCmd
;
753 BlockSize
= UsbMass
->BlockIoMedia
.BlockSize
;
754 Status
= EFI_SUCCESS
;
756 while (TotalBlock
> 0) {
758 // Split the total blocks into smaller pieces to ease the pressure
759 // on the device. We must split the total block because the WRITE10
760 // command only has 16 bit transfer length (in the unit of block).
762 Count
= (UINT16
)((TotalBlock
< USB_BOOT_IO_BLOCKS
) ? TotalBlock
: USB_BOOT_IO_BLOCKS
);
763 ByteSize
= (UINT32
)Count
* BlockSize
;
766 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
768 Timeout
= (UINT32
) USB_BOOT_GENERAL_CMD_TIMEOUT
;
771 // Fill in the write10 command block
773 ZeroMem (&WriteCmd
, sizeof (USB_BOOT_WRITE10_CMD
));
775 WriteCmd
.OpCode
= USB_BOOT_WRITE10_OPCODE
;
776 WriteCmd
.Lun
= (UINT8
) (USB_BOOT_LUN (UsbMass
->Lun
));
777 WriteUnaligned32 ((UINT32
*) WriteCmd
.Lba
, SwapBytes32 (Lba
));
778 WriteUnaligned16 ((UINT16
*) WriteCmd
.TransferLen
, SwapBytes16 (Count
));
780 Status
= UsbBootExecCmdWithRetry (
783 (UINT8
) sizeof (USB_BOOT_WRITE10_CMD
),
789 if (EFI_ERROR (Status
)) {
794 Buffer
+= Count
* BlockSize
;
802 Use the USB clear feature control transfer to clear the endpoint stall condition.
804 @param UsbIo The USB I/O Protocol instance
805 @param EndpointAddr The endpoint to clear stall for
807 @retval EFI_SUCCESS The endpoint stall condition is cleared.
808 @retval Others Failed to clear the endpoint stall condition.
812 UsbClearEndpointStall (
813 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
814 IN UINT8 EndpointAddr
817 EFI_USB_DEVICE_REQUEST Request
;
822 Request
.RequestType
= 0x02;
823 Request
.Request
= USB_REQ_CLEAR_FEATURE
;
824 Request
.Value
= USB_FEATURE_ENDPOINT_HALT
;
825 Request
.Index
= EndpointAddr
;
827 Timeout
= USB_BOOT_GENERAL_CMD_TIMEOUT
/ USB_MASS_1_MILLISECOND
;
829 Status
= UsbIo
->UsbControlTransfer (