mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 06:52:16 +00:00 
			
		
		
		
	Fix various typos in comments and documentation. Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Acked-by: Liming Gao <liming.gao@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-20-philmd@redhat.com>
		
			
				
	
	
		
			999 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			999 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implementation of the command set of USB Mass Storage Specification
 | 
						|
  for Bootability, Revision 1.0.
 | 
						|
 | 
						|
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "UsbMass.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Execute REQUEST SENSE Command to retrieve sense data from device.
 | 
						|
 | 
						|
  @param  UsbMass                The device whose sense data is requested.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The command is executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR       Failed to request sense.
 | 
						|
  @retval EFI_NO_RESPONSE        The device media doesn't response this request.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The command has some invalid parameters.
 | 
						|
  @retval EFI_WRITE_PROTECTED    The device is write protected.
 | 
						|
  @retval EFI_MEDIA_CHANGED      The device media has been changed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootRequestSense (
 | 
						|
  IN USB_MASS_DEVICE          *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BOOT_REQUEST_SENSE_CMD  SenseCmd;
 | 
						|
  USB_BOOT_REQUEST_SENSE_DATA SenseData;
 | 
						|
  EFI_BLOCK_IO_MEDIA          *Media;
 | 
						|
  USB_MASS_TRANSPORT          *Transport;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UINT32                      CmdResult;
 | 
						|
 | 
						|
  Transport = UsbMass->Transport;
 | 
						|
 | 
						|
  //
 | 
						|
  // Request the sense data from the device
 | 
						|
  //
 | 
						|
  ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
 | 
						|
  ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
 | 
						|
 | 
						|
  SenseCmd.OpCode   = USB_BOOT_REQUEST_SENSE_OPCODE;
 | 
						|
  SenseCmd.Lun      = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
 | 
						|
  SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA);
 | 
						|
 | 
						|
  Status = Transport->ExecCommand (
 | 
						|
                        UsbMass->Context,
 | 
						|
                        &SenseCmd,
 | 
						|
                        sizeof (USB_BOOT_REQUEST_SENSE_CMD),
 | 
						|
                        EfiUsbDataIn,
 | 
						|
                        &SenseData,
 | 
						|
                        sizeof (USB_BOOT_REQUEST_SENSE_DATA),
 | 
						|
                        UsbMass->Lun,
 | 
						|
                        USB_BOOT_GENERAL_CMD_TIMEOUT,
 | 
						|
                        &CmdResult
 | 
						|
                        );
 | 
						|
  if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If sense data is retrieved successfully, interpret the sense data
 | 
						|
  // and update the media status if necessary.
 | 
						|
  //
 | 
						|
  Media = &UsbMass->BlockIoMedia;
 | 
						|
 | 
						|
  switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_NO_SENSE:
 | 
						|
    if (SenseData.Asc == USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION) {
 | 
						|
      //
 | 
						|
      // It is not an error if a device does not have additional sense information
 | 
						|
      //
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      Status = EFI_NO_RESPONSE;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_RECOVERED:
 | 
						|
    //
 | 
						|
    // Suppose hardware can handle this case, and recover later by itself
 | 
						|
    //
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
    break;
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_NOT_READY:
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
 | 
						|
      Media->MediaPresent = FALSE;
 | 
						|
      Status = EFI_NO_MEDIA;
 | 
						|
    } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
 | 
						|
      Status = EFI_NOT_READY;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_ILLEGAL_REQUEST:
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    break;
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_UNIT_ATTENTION:
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) {
 | 
						|
      //
 | 
						|
      // If MediaChange, reset ReadOnly and new MediaId
 | 
						|
      //
 | 
						|
      Status = EFI_MEDIA_CHANGED;
 | 
						|
      Media->ReadOnly = FALSE;
 | 
						|
      Media->MediaId++;
 | 
						|
    } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
 | 
						|
      Status = EFI_NOT_READY;
 | 
						|
    } else if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
 | 
						|
      Status = EFI_NOT_READY;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case USB_BOOT_SENSE_DATA_PROTECT:
 | 
						|
    Status = EFI_WRITE_PROTECTED;
 | 
						|
    Media->ReadOnly = TRUE;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with error code (%x) sense key %x/%x/%x\n",
 | 
						|
          Status,
 | 
						|
          SenseData.ErrorCode,
 | 
						|
          USB_BOOT_SENSE_KEY (SenseData.SenseKey),
 | 
						|
          SenseData.Asc,
 | 
						|
          SenseData.Ascq
 | 
						|
          ));
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute the USB mass storage bootability commands.
 | 
						|
 | 
						|
  This function executes the USB mass storage bootability commands.
 | 
						|
  If execution failed, retrieve the error by REQUEST_SENSE, then
 | 
						|
  update the device's status, such as ReadyOnly.
 | 
						|
 | 
						|
  @param  UsbMass                The device to issue commands to
 | 
						|
  @param  Cmd                    The command to execute
 | 
						|
  @param  CmdLen                 The length of the command
 | 
						|
  @param  DataDir                The direction of data transfer
 | 
						|
  @param  Data                   The buffer to hold the data
 | 
						|
  @param  DataLen                The length of expected data
 | 
						|
  @param  Timeout                The timeout used to transfer
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Command is executed successfully
 | 
						|
  @retval Others                 Command execution failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootExecCmd (
 | 
						|
  IN USB_MASS_DEVICE            *UsbMass,
 | 
						|
  IN VOID                       *Cmd,
 | 
						|
  IN UINT8                      CmdLen,
 | 
						|
  IN EFI_USB_DATA_DIRECTION     DataDir,
 | 
						|
  IN VOID                       *Data,
 | 
						|
  IN UINT32                     DataLen,
 | 
						|
  IN UINT32                     Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_MASS_TRANSPORT          *Transport;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UINT32                      CmdResult;
 | 
						|
 | 
						|
  Transport = UsbMass->Transport;
 | 
						|
  Status    = Transport->ExecCommand (
 | 
						|
                           UsbMass->Context,
 | 
						|
                           Cmd,
 | 
						|
                           CmdLen,
 | 
						|
                           DataDir,
 | 
						|
                           Data,
 | 
						|
                           DataLen,
 | 
						|
                           UsbMass->Lun,
 | 
						|
                           Timeout,
 | 
						|
                           &CmdResult
 | 
						|
                           );
 | 
						|
 | 
						|
  if (Status == EFI_TIMEOUT) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd\n", Status, *(UINT8 *)Cmd));
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If ExecCommand() returns no error and CmdResult is success,
 | 
						|
  // then the command transfer is successful.
 | 
						|
  //
 | 
						|
  if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If command execution failed, then retrieve error info via sense request.
 | 
						|
  //
 | 
						|
  DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd (Result = %x)\n", Status, *(UINT8 *)Cmd, CmdResult));
 | 
						|
  return UsbBootRequestSense (UsbMass);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute the USB mass storage bootability commands with retrial.
 | 
						|
 | 
						|
  This function executes USB mass storage bootability commands.
 | 
						|
  If the device isn't ready, wait for it. If the device is ready
 | 
						|
  and error occurs, retry the command again until it exceeds the
 | 
						|
  limit of retrial times.
 | 
						|
 | 
						|
  @param  UsbMass                The device to issue commands to
 | 
						|
  @param  Cmd                    The command to execute
 | 
						|
  @param  CmdLen                 The length of the command
 | 
						|
  @param  DataDir                The direction of data transfer
 | 
						|
  @param  Data                   The buffer to hold the data
 | 
						|
  @param  DataLen                The length of expected data
 | 
						|
  @param  Timeout                The timeout used to transfer
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The command is executed successfully.
 | 
						|
  @retval EFI_NO_MEDIA           The device media is removed.
 | 
						|
  @retval Others                 Command execution failed after retrial.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootExecCmdWithRetry (
 | 
						|
  IN USB_MASS_DEVICE          *UsbMass,
 | 
						|
  IN VOID                     *Cmd,
 | 
						|
  IN UINT8                    CmdLen,
 | 
						|
  IN EFI_USB_DATA_DIRECTION   DataDir,
 | 
						|
  IN VOID                     *Data,
 | 
						|
  IN UINT32                   DataLen,
 | 
						|
  IN UINT32                   Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UINTN                       Retry;
 | 
						|
  EFI_EVENT                   TimeoutEvt;
 | 
						|
 | 
						|
  Retry  = 0;
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_TIMER,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  NULL,
 | 
						|
                  NULL,
 | 
						|
                  &TimeoutEvt
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60));
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Execute the cmd and retry if it fails.
 | 
						|
  //
 | 
						|
  while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
 | 
						|
    Status = UsbBootExecCmd (
 | 
						|
               UsbMass,
 | 
						|
               Cmd,
 | 
						|
               CmdLen,
 | 
						|
               DataDir,
 | 
						|
               Data,
 | 
						|
               DataLen,
 | 
						|
               Timeout
 | 
						|
               );
 | 
						|
    if (Status == EFI_SUCCESS || Status == EFI_NO_MEDIA) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // If the sense data shows the drive is not ready, we need execute the cmd again.
 | 
						|
    // We limit the upper boundary to 60 seconds.
 | 
						|
    //
 | 
						|
    if (Status == EFI_NOT_READY) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // If the status is other error, then just retry 5 times.
 | 
						|
    //
 | 
						|
    if (Retry++ >= USB_BOOT_COMMAND_RETRY) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
EXIT:
 | 
						|
  if (TimeoutEvt != NULL) {
 | 
						|
    gBS->CloseEvent (TimeoutEvt);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute TEST UNIT READY command to check if the device is ready.
 | 
						|
 | 
						|
  @param  UsbMass                The device to test
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The device is ready.
 | 
						|
  @retval Others                 Device not ready.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootIsUnitReady (
 | 
						|
  IN USB_MASS_DEVICE            *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BOOT_TEST_UNIT_READY_CMD  TestCmd;
 | 
						|
 | 
						|
  ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
 | 
						|
 | 
						|
  TestCmd.OpCode  = USB_BOOT_TEST_UNIT_READY_OPCODE;
 | 
						|
  TestCmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
 | 
						|
 | 
						|
  return UsbBootExecCmdWithRetry (
 | 
						|
           UsbMass,
 | 
						|
           &TestCmd,
 | 
						|
           (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
 | 
						|
           EfiUsbNoData,
 | 
						|
           NULL,
 | 
						|
           0,
 | 
						|
           USB_BOOT_GENERAL_CMD_TIMEOUT
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute INQUIRY Command to request information regarding parameters of
 | 
						|
  the device be sent to the host computer.
 | 
						|
 | 
						|
  @param  UsbMass                The device to inquire.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            INQUIRY Command is executed successfully.
 | 
						|
  @retval Others                 INQUIRY Command is not executed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootInquiry (
 | 
						|
  IN USB_MASS_DEVICE            *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BOOT_INQUIRY_CMD        InquiryCmd;
 | 
						|
  EFI_BLOCK_IO_MEDIA          *Media;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
 | 
						|
  Media = &(UsbMass->BlockIoMedia);
 | 
						|
 | 
						|
  ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
 | 
						|
  ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
 | 
						|
 | 
						|
  InquiryCmd.OpCode   = USB_BOOT_INQUIRY_OPCODE;
 | 
						|
  InquiryCmd.Lun      = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
 | 
						|
  InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);
 | 
						|
 | 
						|
  Status = UsbBootExecCmdWithRetry (
 | 
						|
             UsbMass,
 | 
						|
             &InquiryCmd,
 | 
						|
             (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),
 | 
						|
             EfiUsbDataIn,
 | 
						|
             &UsbMass->InquiryData,
 | 
						|
             sizeof (USB_BOOT_INQUIRY_DATA),
 | 
						|
             USB_BOOT_GENERAL_CMD_TIMEOUT
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
 | 
						|
  // from the inquiry data.
 | 
						|
  //
 | 
						|
  UsbMass->Pdt          = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));
 | 
						|
  Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));
 | 
						|
  //
 | 
						|
  // Set block size to the default value of 512 Bytes, in case no media is present at first time.
 | 
						|
  //
 | 
						|
  Media->BlockSize      = 0x0200;
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ CAPACITY 16 bytes command to request information regarding
 | 
						|
  the capacity of the installed medium of the device.
 | 
						|
 | 
						|
  This function executes READ CAPACITY 16 bytes command to get the capacity
 | 
						|
  of the USB mass storage media, including the presence, block size,
 | 
						|
  and last block number.
 | 
						|
 | 
						|
  @param  UsbMass                The device to retireve disk gemotric.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The disk geometry is successfully retrieved.
 | 
						|
  @retval EFI_NOT_READY          The returned block size is zero.
 | 
						|
  @retval Other                  READ CAPACITY 16 bytes command execution failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootReadCapacity16 (
 | 
						|
  IN USB_MASS_DEVICE            *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                         CapacityCmd[16];
 | 
						|
  EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData;
 | 
						|
  EFI_BLOCK_IO_MEDIA            *Media;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINT32                        BlockSize;
 | 
						|
 | 
						|
  Media   = &UsbMass->BlockIoMedia;
 | 
						|
 | 
						|
  Media->MediaPresent = FALSE;
 | 
						|
  Media->LastBlock    = 0;
 | 
						|
  Media->BlockSize    = 0;
 | 
						|
 | 
						|
  ZeroMem (CapacityCmd, sizeof (CapacityCmd));
 | 
						|
  ZeroMem (&CapacityData, sizeof (CapacityData));
 | 
						|
 | 
						|
  CapacityCmd[0]  = EFI_SCSI_OP_READ_CAPACITY16;
 | 
						|
  CapacityCmd[1]  = 0x10;
 | 
						|
  //
 | 
						|
  // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO.
 | 
						|
  //
 | 
						|
  ZeroMem ((CapacityCmd + 2), 8);
 | 
						|
 | 
						|
  CapacityCmd[13] = sizeof (CapacityData);
 | 
						|
 | 
						|
  Status = UsbBootExecCmdWithRetry (
 | 
						|
             UsbMass,
 | 
						|
             CapacityCmd,
 | 
						|
             (UINT8) sizeof (CapacityCmd),
 | 
						|
             EfiUsbDataIn,
 | 
						|
             &CapacityData,
 | 
						|
             sizeof (CapacityData),
 | 
						|
             USB_BOOT_GENERAL_CMD_TIMEOUT
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the information on media presence, block size, and last block number
 | 
						|
  // from READ CAPACITY data.
 | 
						|
  //
 | 
						|
  Media->MediaPresent = TRUE;
 | 
						|
  Media->LastBlock    = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));
 | 
						|
 | 
						|
  BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));
 | 
						|
 | 
						|
  Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |
 | 
						|
                             CapacityData.LowestAlignLogic1;
 | 
						|
  Media->LogicalBlocksPerPhysicalBlock  = (1 << CapacityData.LogicPerPhysical);
 | 
						|
  if (BlockSize == 0) {
 | 
						|
    //
 | 
						|
    //  Get sense data
 | 
						|
    //
 | 
						|
    return UsbBootRequestSense (UsbMass);
 | 
						|
  } else {
 | 
						|
    Media->BlockSize = BlockSize;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ CAPACITY command to request information regarding
 | 
						|
  the capacity of the installed medium of the device.
 | 
						|
 | 
						|
  This function executes READ CAPACITY command to get the capacity
 | 
						|
  of the USB mass storage media, including the presence, block size,
 | 
						|
  and last block number.
 | 
						|
 | 
						|
  @param  UsbMass                The device to retireve disk gemotric.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The disk geometry is successfully retrieved.
 | 
						|
  @retval EFI_NOT_READY          The returned block size is zero.
 | 
						|
  @retval Other                  READ CAPACITY command execution failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootReadCapacity (
 | 
						|
  IN USB_MASS_DEVICE          *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BOOT_READ_CAPACITY_CMD  CapacityCmd;
 | 
						|
  USB_BOOT_READ_CAPACITY_DATA CapacityData;
 | 
						|
  EFI_BLOCK_IO_MEDIA          *Media;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UINT32                      BlockSize;
 | 
						|
 | 
						|
  Media   = &UsbMass->BlockIoMedia;
 | 
						|
 | 
						|
  ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
 | 
						|
  ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
 | 
						|
 | 
						|
  CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
 | 
						|
  CapacityCmd.Lun    = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
 | 
						|
 | 
						|
  Status = UsbBootExecCmdWithRetry (
 | 
						|
             UsbMass,
 | 
						|
             &CapacityCmd,
 | 
						|
             (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD),
 | 
						|
             EfiUsbDataIn,
 | 
						|
             &CapacityData,
 | 
						|
             sizeof (USB_BOOT_READ_CAPACITY_DATA),
 | 
						|
             USB_BOOT_GENERAL_CMD_TIMEOUT
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the information on media presence, block size, and last block number
 | 
						|
  // from READ CAPACITY data.
 | 
						|
  //
 | 
						|
  Media->MediaPresent = TRUE;
 | 
						|
  Media->LastBlock    = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
 | 
						|
 | 
						|
  BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
 | 
						|
  if (BlockSize == 0) {
 | 
						|
    //
 | 
						|
    //  Get sense data
 | 
						|
    //
 | 
						|
    return UsbBootRequestSense (UsbMass);
 | 
						|
  } else {
 | 
						|
    Media->BlockSize = BlockSize;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Media->LastBlock == 0xFFFFFFFF) {
 | 
						|
    Status = UsbBootReadCapacity16 (UsbMass);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      UsbMass->Cdb16Byte = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieves SCSI mode sense information via MODE SENSE(6) command.
 | 
						|
 | 
						|
  @param  UsbMass                The device whose sense data is requested.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            SCSI mode sense information retrieved successfully.
 | 
						|
  @retval Other                  Command execution failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbScsiModeSense (
 | 
						|
  IN USB_MASS_DEVICE          *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  USB_SCSI_MODE_SENSE6_CMD         ModeSenseCmd;
 | 
						|
  USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
 | 
						|
  EFI_BLOCK_IO_MEDIA               *Media;
 | 
						|
 | 
						|
  Media   = &UsbMass->BlockIoMedia;
 | 
						|
 | 
						|
  ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
 | 
						|
  ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
 | 
						|
 | 
						|
  //
 | 
						|
  // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
 | 
						|
  //
 | 
						|
  ModeSenseCmd.OpCode         = USB_SCSI_MODE_SENSE6_OPCODE;
 | 
						|
  ModeSenseCmd.Lun            = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
 | 
						|
  ModeSenseCmd.PageCode       = 0x3F;
 | 
						|
  ModeSenseCmd.AllocateLen    = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
 | 
						|
 | 
						|
  Status = UsbBootExecCmdWithRetry (
 | 
						|
             UsbMass,
 | 
						|
             &ModeSenseCmd,
 | 
						|
             (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),
 | 
						|
             EfiUsbDataIn,
 | 
						|
             &ModeParaHeader,
 | 
						|
             sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
 | 
						|
             USB_BOOT_GENERAL_CMD_TIMEOUT
 | 
						|
             );
 | 
						|
 | 
						|
  //
 | 
						|
  // Format of device-specific parameter byte of the mode parameter header is defined in
 | 
						|
  // Section 8.2.10 of SCSI-2 Spec.
 | 
						|
  // BIT7 of this byte is indicates whether the medium is write protected.
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the parameters for the USB mass storage media.
 | 
						|
 | 
						|
  This function get the parameters for the USB mass storage media,
 | 
						|
  It is used both to initialize the media during the Start() phase
 | 
						|
  of Driver Binding Protocol and to re-initialize it when the media is
 | 
						|
  changed. Although the RemoveableMedia is unlikely to change,
 | 
						|
  it is also included here.
 | 
						|
 | 
						|
  @param  UsbMass                The device to retrieve disk gemotric.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The disk gemotric is successfully retrieved.
 | 
						|
  @retval Other                  Failed to get the parameters.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootGetParams (
 | 
						|
  IN USB_MASS_DEVICE          *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_BLOCK_IO_MEDIA          *Media;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
 | 
						|
  Media  = &(UsbMass->BlockIoMedia);
 | 
						|
 | 
						|
  Status = UsbBootInquiry (UsbMass);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // According to USB Mass Storage Specification for Bootability, only following
 | 
						|
  // 4 Peripheral Device Types are in spec.
 | 
						|
  //
 | 
						|
  if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
 | 
						|
       (UsbMass->Pdt != USB_PDT_CDROM) &&
 | 
						|
       (UsbMass->Pdt != USB_PDT_OPTICAL) &&
 | 
						|
       (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Don't use the Removable bit in inquiry data to test whether the media
 | 
						|
  // is removable because many flash disks wrongly set this bit.
 | 
						|
  //
 | 
						|
  if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
 | 
						|
    //
 | 
						|
    // CD-Rom device and Non-CD optical device
 | 
						|
    //
 | 
						|
    UsbMass->OpticalStorage = TRUE;
 | 
						|
    //
 | 
						|
    // Default value 2048 Bytes, in case no media present at first time
 | 
						|
    //
 | 
						|
    Media->BlockSize        = 0x0800;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UsbBootDetectMedia (UsbMass);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Detect whether the removable media is present and whether it has changed.
 | 
						|
 | 
						|
  @param  UsbMass                The device to check.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The media status is successfully checked.
 | 
						|
  @retval Other                  Failed to detect media.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootDetectMedia (
 | 
						|
  IN  USB_MASS_DEVICE       *UsbMass
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_BLOCK_IO_MEDIA        OldMedia;
 | 
						|
  EFI_BLOCK_IO_MEDIA        *Media;
 | 
						|
  UINT8                     CmdSet;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  Media    = &UsbMass->BlockIoMedia;
 | 
						|
 | 
						|
  CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
 | 
						|
 | 
						|
  CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
 | 
						|
 | 
						|
  Status = UsbBootIsUnitReady (UsbMass);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Status could be:
 | 
						|
  //   EFI_SUCCESS: all good.
 | 
						|
  //   EFI_NO_MEDIA: media is not present.
 | 
						|
  //   others: HW error.
 | 
						|
  // For either EFI_NO_MEDIA, or HW error, skip to get WriteProtected and capacity information.
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
 | 
						|
      //
 | 
						|
      // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
 | 
						|
      // according to Section 4 of USB Mass Storage Specification for Bootability.
 | 
						|
      // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
 | 
						|
      // could get the information of Write Protected.
 | 
						|
      // Since not all device support this command, skip if fail.
 | 
						|
      //
 | 
						|
      UsbScsiModeSense (UsbMass);
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UsbBootReadCapacity (UsbMass);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) && Status != EFI_NO_MEDIA) {
 | 
						|
    //
 | 
						|
    // For NoMedia, BlockIo is still needed.
 | 
						|
    //
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Simply reject device whose block size is unacceptable small (==0) or large (>64K).
 | 
						|
  //
 | 
						|
  if ((Media->BlockSize == 0) || (Media->BlockSize > USB_BOOT_MAX_CARRY_SIZE)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Detect whether it is necessary to reinstall the Block I/O Protocol.
 | 
						|
  //
 | 
						|
  // MediaId may change in RequestSense for MediaChanged
 | 
						|
  // MediaPresent may change in RequestSense for NoMedia
 | 
						|
  // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
 | 
						|
  // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
 | 
						|
  //
 | 
						|
  if ((Media->MediaId != OldMedia.MediaId) ||
 | 
						|
      (Media->MediaPresent != OldMedia.MediaPresent) ||
 | 
						|
      (Media->ReadOnly != OldMedia.ReadOnly) ||
 | 
						|
      (Media->BlockSize != OldMedia.BlockSize) ||
 | 
						|
      (Media->LastBlock != OldMedia.LastBlock)) {
 | 
						|
 | 
						|
    //
 | 
						|
    // This function is called from:
 | 
						|
    //   Block I/O Protocol APIs, which run at TPL_CALLBACK.
 | 
						|
    //   DriverBindingStart(), which raises to TPL_CALLBACK.
 | 
						|
    ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
 | 
						|
 | 
						|
    //
 | 
						|
    // When it is called from DriverBindingStart(), below reinstall fails.
 | 
						|
    // So ignore the return status check.
 | 
						|
    //
 | 
						|
    gBS->ReinstallProtocolInterface (
 | 
						|
           UsbMass->Controller,
 | 
						|
           &gEfiBlockIoProtocolGuid,
 | 
						|
           &UsbMass->BlockIo,
 | 
						|
           &UsbMass->BlockIo
 | 
						|
           );
 | 
						|
 | 
						|
    //
 | 
						|
    // Reset MediaId after reinstalling Block I/O Protocol.
 | 
						|
    //
 | 
						|
    if (Media->MediaPresent != OldMedia.MediaPresent) {
 | 
						|
      if (Media->MediaPresent) {
 | 
						|
        Media->MediaId = 1;
 | 
						|
      } else {
 | 
						|
        Media->MediaId = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if ((Media->ReadOnly != OldMedia.ReadOnly) ||
 | 
						|
        (Media->BlockSize != OldMedia.BlockSize) ||
 | 
						|
        (Media->LastBlock != OldMedia.LastBlock)) {
 | 
						|
      Media->MediaId++;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read or write some blocks from the device.
 | 
						|
 | 
						|
  @param  UsbMass                The USB mass storage device to access
 | 
						|
  @param  Write                  TRUE for write operation.
 | 
						|
  @param  Lba                    The start block number
 | 
						|
  @param  TotalBlock             Total block number to read or write
 | 
						|
  @param  Buffer                 The buffer to read to or write from
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Data are read into the buffer or writen into the device.
 | 
						|
  @retval Others                 Failed to read or write all the data
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootReadWriteBlocks (
 | 
						|
  IN  USB_MASS_DEVICE       *UsbMass,
 | 
						|
  IN  BOOLEAN               Write,
 | 
						|
  IN  UINT32                Lba,
 | 
						|
  IN  UINTN                 TotalBlock,
 | 
						|
  IN OUT UINT8              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BOOT_READ_WRITE_10_CMD Cmd;
 | 
						|
  EFI_STATUS                 Status;
 | 
						|
  UINT32                     Count;
 | 
						|
  UINT32                     CountMax;
 | 
						|
  UINT32                     BlockSize;
 | 
						|
  UINT32                     ByteSize;
 | 
						|
  UINT32                     Timeout;
 | 
						|
 | 
						|
  BlockSize = UsbMass->BlockIoMedia.BlockSize;
 | 
						|
  CountMax  = USB_BOOT_MAX_CARRY_SIZE / BlockSize;
 | 
						|
  Status    = EFI_SUCCESS;
 | 
						|
 | 
						|
  while (TotalBlock > 0) {
 | 
						|
    //
 | 
						|
    // Split the total blocks into smaller pieces to ease the pressure
 | 
						|
    // on the device. We must split the total block because the READ10
 | 
						|
    // command only has 16 bit transfer length (in the unit of block).
 | 
						|
    //
 | 
						|
    Count    = (UINT32)MIN (TotalBlock, CountMax);
 | 
						|
    Count    = MIN (MAX_UINT16, Count);
 | 
						|
    ByteSize = Count * BlockSize;
 | 
						|
 | 
						|
    //
 | 
						|
    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
 | 
						|
    //
 | 
						|
    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
 | 
						|
 | 
						|
    //
 | 
						|
    // Fill in the command then execute
 | 
						|
    //
 | 
						|
    ZeroMem (&Cmd, sizeof (USB_BOOT_READ_WRITE_10_CMD));
 | 
						|
 | 
						|
    Cmd.OpCode  = Write ? USB_BOOT_WRITE10_OPCODE : USB_BOOT_READ10_OPCODE;
 | 
						|
    Cmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
 | 
						|
    WriteUnaligned32 ((UINT32 *) Cmd.Lba, SwapBytes32 (Lba));
 | 
						|
    WriteUnaligned16 ((UINT16 *) Cmd.TransferLen, SwapBytes16 ((UINT16)Count));
 | 
						|
 | 
						|
    Status = UsbBootExecCmdWithRetry (
 | 
						|
               UsbMass,
 | 
						|
               &Cmd,
 | 
						|
               (UINT8) sizeof (USB_BOOT_READ_WRITE_10_CMD),
 | 
						|
               Write ? EfiUsbDataOut : EfiUsbDataIn,
 | 
						|
               Buffer,
 | 
						|
               ByteSize,
 | 
						|
               Timeout
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_BLKIO, "UsbBoot%sBlocks: LBA (0x%lx), Blk (0x%x)\n",
 | 
						|
      Write ? L"Write" : L"Read",
 | 
						|
      Lba, Count
 | 
						|
      ));
 | 
						|
    Lba        += Count;
 | 
						|
    Buffer     += ByteSize;
 | 
						|
    TotalBlock -= Count;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read or write some blocks from the device by SCSI 16 byte cmd.
 | 
						|
 | 
						|
  @param  UsbMass                The USB mass storage device to access
 | 
						|
  @param  Write                  TRUE for write operation.
 | 
						|
  @param  Lba                    The start block number
 | 
						|
  @param  TotalBlock             Total block number to read or write
 | 
						|
  @param  Buffer                 The buffer to read to or write from
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Data are read into the buffer or writen into the device.
 | 
						|
  @retval Others                 Failed to read or write all the data
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbBootReadWriteBlocks16 (
 | 
						|
  IN  USB_MASS_DEVICE       *UsbMass,
 | 
						|
  IN  BOOLEAN               Write,
 | 
						|
  IN  UINT64                Lba,
 | 
						|
  IN  UINTN                 TotalBlock,
 | 
						|
  IN OUT UINT8              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                     Cmd[16];
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINT32                    Count;
 | 
						|
  UINT32                    CountMax;
 | 
						|
  UINT32                    BlockSize;
 | 
						|
  UINT32                    ByteSize;
 | 
						|
  UINT32                    Timeout;
 | 
						|
 | 
						|
  BlockSize = UsbMass->BlockIoMedia.BlockSize;
 | 
						|
  CountMax  = USB_BOOT_MAX_CARRY_SIZE / BlockSize;
 | 
						|
  Status    = EFI_SUCCESS;
 | 
						|
 | 
						|
  while (TotalBlock > 0) {
 | 
						|
    //
 | 
						|
    // Split the total blocks into smaller pieces.
 | 
						|
    //
 | 
						|
    Count    = (UINT32)MIN (TotalBlock, CountMax);
 | 
						|
    ByteSize = Count * BlockSize;
 | 
						|
 | 
						|
    //
 | 
						|
    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
 | 
						|
    //
 | 
						|
    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
 | 
						|
 | 
						|
    //
 | 
						|
    // Fill in the command then execute
 | 
						|
    //
 | 
						|
    ZeroMem (Cmd, sizeof (Cmd));
 | 
						|
 | 
						|
    Cmd[0]  = Write ? EFI_SCSI_OP_WRITE16 : EFI_SCSI_OP_READ16;
 | 
						|
    Cmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));
 | 
						|
    WriteUnaligned64 ((UINT64 *) &Cmd[2], SwapBytes64 (Lba));
 | 
						|
    WriteUnaligned32 ((UINT32 *) &Cmd[10], SwapBytes32 (Count));
 | 
						|
 | 
						|
    Status = UsbBootExecCmdWithRetry (
 | 
						|
               UsbMass,
 | 
						|
               Cmd,
 | 
						|
               (UINT8) sizeof (Cmd),
 | 
						|
               Write ? EfiUsbDataOut : EfiUsbDataIn,
 | 
						|
               Buffer,
 | 
						|
               ByteSize,
 | 
						|
               Timeout
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_BLKIO, "UsbBoot%sBlocks16: LBA (0x%lx), Blk (0x%x)\n",
 | 
						|
      Write ? L"Write" : L"Read",
 | 
						|
      Lba, Count
 | 
						|
      ));
 | 
						|
    Lba        += Count;
 | 
						|
    Buffer     += ByteSize;
 | 
						|
    TotalBlock -= Count;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Use the USB clear feature control transfer to clear the endpoint stall condition.
 | 
						|
 | 
						|
  @param  UsbIo                  The USB I/O Protocol instance
 | 
						|
  @param  EndpointAddr           The endpoint to clear stall for
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The endpoint stall condition is cleared.
 | 
						|
  @retval Others                 Failed to clear the endpoint stall condition.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UsbClearEndpointStall (
 | 
						|
  IN EFI_USB_IO_PROTOCOL    *UsbIo,
 | 
						|
  IN UINT8                  EndpointAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_USB_DEVICE_REQUEST    Request;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINT32                    CmdResult;
 | 
						|
  UINT32                    Timeout;
 | 
						|
 | 
						|
  Request.RequestType = 0x02;
 | 
						|
  Request.Request     = USB_REQ_CLEAR_FEATURE;
 | 
						|
  Request.Value       = USB_FEATURE_ENDPOINT_HALT;
 | 
						|
  Request.Index       = EndpointAddr;
 | 
						|
  Request.Length      = 0;
 | 
						|
  Timeout             = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;
 | 
						|
 | 
						|
  Status = UsbIo->UsbControlTransfer (
 | 
						|
                    UsbIo,
 | 
						|
                    &Request,
 | 
						|
                    EfiUsbNoData,
 | 
						|
                    Timeout,
 | 
						|
                    NULL,
 | 
						|
                    0,
 | 
						|
                    &CmdResult
 | 
						|
                    );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |