usbmassstoragehelper.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,603 行 · 第 1/3 页

C
1,603
字号
  IN  USB_FLOPPY_DEV  *UsbFloppyDevice,
  OUT UINTN           *SenseCounts
  )
/*++

  Routine Description:
    Retrieves Sense Data from device via 
    sending Request Sense Packet Command.
  
  Arguments:
    UsbFloppyDevice - The USB_FLOPPY_DEV instance.
    SenseCounts     - A pointer to the number of Sense Data returned.
      
  Returns:  
    EFI_DEVICE_ERROR - Hardware error
    EFI_SUCCESS      - Success
--*/         
{
  EFI_STATUS              Status;
  REQUEST_SENSE_DATA      *Sense;
  UINT8                   *Ptr;
  BOOLEAN                 SenseReq;
  ATAPI_PACKET_COMMAND    Packet;
  EFI_USB_ATAPI_PROTOCOL  *UsbAtapiInterface;

  UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;

  *SenseCounts      = 0;

  EfiZeroMem (
    UsbFloppyDevice->SenseData,
    sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber)
    );
  //
  // fill command packet for Request Sense Packet Command
  //
  EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
  Packet.RequestSense.opcode            = REQUEST_SENSE;
  Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA);
  
  //
  // initialize pointer
  //
  Ptr = (UINT8 *) (UsbFloppyDevice->SenseData);

  //
  //  request sense data from device continuously
  //  until no sense data exists in the device.
  //
  for (SenseReq = TRUE; SenseReq;) {

    Sense = (REQUEST_SENSE_DATA *) Ptr;

    //
    // send out Request Sense Packet Command and get one Sense
    // data from device.
    //
    Status = USBFloppyPacketCommand (
              UsbFloppyDevice,
              &Packet,
              sizeof (ATAPI_PACKET_COMMAND),
              (VOID *) Ptr,
              sizeof (REQUEST_SENSE_DATA),
              EfiUsbDataIn,
              USBFLPTIMEOUT
              );
    //
    // failed to get Sense data
    //
    if (EFI_ERROR (Status)) {
      //
      // Recovery the device back to normal state.
      //
      UsbFloppyDevice->AtapiProtocol->UsbAtapiReset (
                                        UsbFloppyDevice->AtapiProtocol,
                                        TRUE
                                        );

      if (*SenseCounts == 0) {
        //
        // never retrieved any sense data from device,
        // just return error.
        //
        return EFI_DEVICE_ERROR;
      } else {
        //
        // has retrieved some sense data from device,
        // so return success.
        //
        return EFI_SUCCESS;
      }
    }

    if (Sense->sense_key != SK_NO_SENSE) {
      //
      // Ptr is byte based pointer
      //
      Ptr += sizeof (REQUEST_SENSE_DATA);

      (*SenseCounts)++;

    } else {
      //
      // when no sense key, skip out the loop
      //
      SenseReq = FALSE;
    }
  
    //
    // If the sense key numbers exceed Sense Data Buffer size,
    // just skip the loop and do not fetch the sense key in this function.
    //
    if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) {
      SenseReq = FALSE;
    }
  }

  return EFI_SUCCESS;
}

EFI_STATUS
UsbFloppyTestUnitReady (
  IN  USB_FLOPPY_DEV    *UsbFloppyDevice
  )
/*++

  Routine Description:
    Sends Test Unit ReadyPacket Command to the device.
  
  Arguments:
    UsbFloppyDevice -  The USB_FLOPPY_DEV instance.
      
  Returns:  
    EFI_DEVICE_ERROR - Hardware error
    EFI_SUCCESS      - Success
--*/  
{ 
  ATAPI_PACKET_COMMAND      Packet; 
  EFI_STATUS                Status;
  EFI_USB_ATAPI_PROTOCOL    *UsbAtapiInterface;
  UINT32                    RetryIndex;
  UINT32                    MaximumRetryTimes;
  
  UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
  MaximumRetryTimes = 2;
  //
  // fill command packet  
  //
  EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
  Packet.TestUnitReady.opcode = TEST_UNIT_READY;

  //
  // send command packet
  //
  Status = EFI_DEVICE_ERROR;

  for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) {

    Status = USBFloppyPacketCommand (
              UsbFloppyDevice,
              &Packet,
              sizeof (ATAPI_PACKET_COMMAND),
              NULL,
              0,
              EfiUsbNoData,
              USBFLPTIMEOUT
              );

    if (EFI_ERROR (Status)) {
      gBS->Stall (100 * STALL_1_MILLI_SECOND);
    }
  }

  return Status;
}

EFI_STATUS
USBFloppyWrite10 (
  IN  USB_FLOPPY_DEV    *UsbFloppyDevice,
  IN  VOID              *Buffer,
  IN  EFI_LBA           Lba,
  IN  UINTN             NumberOfBlocks
  )
/*++

  Routine Description:
    Sends Write10 Packet Command to device to perform data transfer
    from host to device.
  
  Arguments:
    UsbFloppyDevice -   The USB_FLOPPY_DEV instance.
    Buffer          -   A pointer to the source buffer for the data. 
                        The caller is responsible for either having implicit
                        or explicit ownership of the buffer.
    Lba             -   The starting logical block address to written to 
                        the device.
    NumberOfBlocks  -   Indicates the number of blocks that the write 
                        operation requests.
      
  Returns:  
    EFI_DEVICE_ERROR - Hardware error
    EFI_SUCCESS      - Success
--*/      
{
  ATAPI_PACKET_COMMAND    Packet;
  READ10_CMD              *Write10Packet;
  UINT16                  MaxBlock;
  UINT16                  BlocksRemaining;
  UINT16                  SectorCount;
  UINT32                  Lba32;
  UINT32                  BlockSize;
  UINT32                  ByteCount;
  VOID                    *ptrBuffer;
  EFI_STATUS              Status;
  UINT16                  TimeOut;
  EFI_USB_ATAPI_PROTOCOL  *UsbAtapiInterface;
  UINT8                   Index;
 
  UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;

  //
  // prepare command packet for the Write10 Packet Command.
  //
  EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
  Write10Packet   = &Packet.Read10;
  Lba32           = (UINT32) Lba;
  ptrBuffer       = Buffer;
  BlockSize       = UsbFloppyDevice->BlkIo.Media->BlockSize;

  MaxBlock        = (UINT16) (65536 / BlockSize);
  BlocksRemaining = (UINT16) NumberOfBlocks;

  Status          = EFI_SUCCESS;
  while (BlocksRemaining > 0) {

    if (BlocksRemaining <= MaxBlock) {
      SectorCount = BlocksRemaining;
    } else {
      SectorCount = MaxBlock;
    }

    for (Index = 0; Index < 3; Index ++) {
      //
      // fill the Packet data structure
      //
      Write10Packet->opcode = WRITE_10;
      
      //
      // Lba0 ~ Lba3 specify the start logical block address
      // of the data transfer.
      // Lba0 is MSB, Lba3 is LSB
      //
      Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
      Write10Packet->Lba2 = (UINT8) (Lba32 >> 8);
      Write10Packet->Lba1 = (UINT8) (Lba32 >> 16);
      Write10Packet->Lba0 = (UINT8) (Lba32 >> 24);
      
      //
      // TranLen0 ~ TranLen1 specify the transfer length in block unit.
      // TranLen0 is MSB, TranLen is LSB
      //
      Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
      Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
      
      ByteCount               = SectorCount * BlockSize;
      
      TimeOut                 = (UINT16) (SectorCount * USBFLPTIMEOUT);
      
      Status = USBFloppyPacketCommand (
                 UsbFloppyDevice,
                 &Packet,
                 sizeof (ATAPI_PACKET_COMMAND),
                 (VOID *) ptrBuffer,
                 ByteCount,
                 EfiUsbDataOut,
                 TimeOut
                 );
      if (!EFI_ERROR (Status)) {
         break;
      }
    }
   
    if (Index == 3) {
      return EFI_DEVICE_ERROR;
    }

    Lba32 += SectorCount;
    ptrBuffer       = (UINT8 *) ptrBuffer + SectorCount * BlockSize;
    BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
  }

  return Status;
}

EFI_STATUS
UsbFloppyDetectMedia (
  IN  USB_FLOPPY_DEV  *UsbFloppyDevice,
  OUT BOOLEAN         *MediaChange
  )
/*++

  Routine Description:
    Retrieves media information.
  
  Arguments:
    UsbFloppyDevice  -  The USB_FLOPPY_DEV instance.
    MediaChange      -  Indicates whether media was changed.
      
  Returns:  
    EFI_DEVICE_ERROR - Hardware error
    EFI_SUCCESS      - Success
    EFI_INVALID_PARAMETER - Parameter is error
--*/        
{
  EFI_STATUS          Status;
  EFI_STATUS          FloppyStatus;
  //
  // the following variables are used to record previous media information
  //
  EFI_BLOCK_IO_MEDIA  OldMediaInfo;
  UINTN               SenseCounts;
  UINTN               RetryIndex;
  UINTN               RetryTimes;
  UINTN               MaximumRetryTimes;
  BOOLEAN             NeedRetry;

  //
  // a flag used to determine whether need to perform Read Capacity command.
  //

  REQUEST_SENSE_DATA  *SensePtr;

  //
  // init
  //
  Status            = EFI_SUCCESS;
  FloppyStatus      = EFI_SUCCESS;
  OldMediaInfo      = *UsbFloppyDevice->BlkIo.Media;
  *MediaChange      = FALSE;

  //
  // if there is no media present,or media not changed,
  // the request sense command will detect faster than read capacity command.
  // read capacity command can be bypassed, thus improve performance.
  //
  SenseCounts = 0;
  Status      = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);

  if (!EFI_ERROR (Status)) {

    SensePtr = UsbFloppyDevice->SenseData;

    //
    // No Media
    //
    if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {

      UsbFloppyDevice->NeedReadCapacity = FALSE;
      UsbFloppyDevice->BlkIo.Media->MediaId = 0;
      UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
      UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
    } else {
      //
      // Media Changed
      //
      if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) {
        UsbFloppyDevice->BlkIo.Media->MediaId++;
      }
        
      //
      // Media Write-protected
      //
      if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
        UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
      }
        
      //
      // Media Error
      //
      if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
        //
        // if media error encountered, make it look like no media present.
        //
        UsbFloppyDevice->BlkIo.Media->MediaId       = 0;
        UsbFloppyDevice->BlkIo.Media->MediaPresent  = FALSE;
        UsbFloppyDevice->BlkIo.Media->LastBlock     = 0;
      }

    }

  }

  if (UsbFloppyDevice->NeedReadCapacity) {
    //
    // at most retry 5 times
    //
    MaximumRetryTimes = 5;
    //
    // initial retry twice
    //
    RetryTimes        = 2;

    for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) {
      //
      // Using different command to retrieve media capacity.
      //
      switch (UsbFloppyDevice->DeviceType) {

      case USBCDROM:
        Status = USBFloppyReadCapacity (UsbFloppyDevice);
        break;

      case USBFLOPPY2:
        UsbMassStorageModeSense (UsbFloppyDevice);
        Status = USBFloppyReadFormatCapacity (UsbFloppyDevice);
        if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) {
          //
          // retry the ReadCapacity command
          //
          UsbFloppyDevice->DeviceType = USBFLOPPY;
          Status                      = EFI_DEVICE_ERROR;
        } else {
          UsbFloppyDevice->NeedReadCapacity = FALSE;
        }
        break;

      case USBFLOPPY:
        UsbMassStorageModeSense (UsbFloppyDevice);
        Status = USBFloppyReadCapacity (UsbFloppyDevice);
        if (EFI_ERROR (Status)) {
          //
          // retry the ReadFormatCapacity command
          //
          UsbFloppyDevice->DeviceType = USBFLOPPY2;
        } else {
          UsbFloppyDevice->NeedReadCapacity = FALSE;
        }
        //
        // force the BlockSize to be 0x200.
        //
        UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200;
        break;

      default:
        return EFI_INVALID_PARAMETER;
      }

      if (!EFI_ERROR (Status)) {
        //
        // skip the loop when read capacity succeeds.
        //
        break;
      }

      SenseCounts   = 0;

      FloppyStatus  = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);

      //
      // If Request Sense data failed,retry.
      //
      if (EFI_ERROR (FloppyStatus)) {
        //
        // retry once more
        //
        RetryTimes++;
        continue;
      }
      //
      // No Media
      //
      if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {

        UsbFloppyDevice->BlkIo.Media->MediaId       = 0;
        UsbFloppyDevice->BlkIo.Media->MediaPresent  = FALSE;
        UsbFloppyDevice->BlkIo.Media->LastBlock     = 0;
        break;
      }

      if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
        //
        // if media error encountered, make it look like no media present.
        //
        UsbFloppyDevice->BlkIo.Media->MediaId       = 0;
        UsbFloppyDevice->BlkIo.Media->MediaPresent  = FALSE;
        UsbFloppyDevice->BlkIo.Media->LastBlock     = 0;
        break;
      }

      if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
        UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
        continue;
      }

      if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) {
          
        //
        // Drive not ready: if NeedRetry, then retry once more;
        // else return error
        //
        if (NeedRetry) {
          //
          // Stall 0.1 second to wait for drive becoming ready
          //
          gBS->Stall (100 * STALL_1_MILLI_SECOND);
          //
          // reset retry variable to zero,
          // to make it retry for "drive in progress of becoming ready".
          //
          RetryIndex = 0;
          continue;
        } else {
          return EFI_DEVICE_ERROR;
        }
      }
      //
      // if read capacity fail not for above reasons, retry once more
      //
      RetryTimes++;

    }
    //
    // ENDFOR
    //

    //
    // tell whether the readcapacity process is successful or not
    // ("Status" variable record the latest status returned
    // by ReadCapacity AND "FloppyStatus" record the latest status
    // returned by RequestSense)
    //
    if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) {
      return EFI_DEVICE_ERROR;
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?