isafloppyctrl.c

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

C
1,560
字号

  if (Times == 0) {
    return EFI_TIMEOUT;
  }
  //
  // Read result bytes from FDC
  //
  CommandPointer = (UINT8 *) (&Result);
  for (Index = 0; Index < sizeof (FDD_RESULT_PACKET); Index++) {
    if (EFI_ERROR (DataInByte (FdcDev, CommandPointer++))) {
      return EFI_DEVICE_ERROR;
    }
  }
  //
  // Flush before Unmap
  //
  if (Read == READ) {
    Status1 = IsaIo->Flush (IsaIo);
    if (EFI_ERROR (Status1)) {
      return Status1;
    }
  }
  //
  // Unmap Dma
  //
  Status1 = IsaIo->Unmap (IsaIo, Mapping);
  if (EFI_ERROR (Status1)) {
    return Status1;
  }

  return CheckResult (Result, FdcDev);
}

VOID
FillPara (
  IN  FDC_BLK_IO_DEV       *FdcDev,
  IN  EFI_LBA              Lba,
  IN  FDD_COMMAND_PACKET1  *Command
  )
/*++

  Routine Description: Fill in Parameter
  Parameters:
  Returns:
    
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Lba - add argument and description to function comment
// GC_TODO:    Command - add argument and description to function comment
{
  UINT8 EndOfTrack;

  //
  // Get EndOfTrack from the Para table
  //
  EndOfTrack = DISK_1440K_EOT;

  //
  // Fill the command parameter
  //
  if (FdcDev->Disk == FDC_DISK0) {
    Command->DiskHeadSel = 0;
  } else {
    Command->DiskHeadSel = 1;
  }

  Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
  Command->Head     = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
  Command->Sector   = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);
  Command->DiskHeadSel |= Command->Head << 2;
  Command->Number     = DISK_1440K_NUMBER;
  Command->EndOfTrack = DISK_1440K_EOT;
  Command->GapLength  = DISK_1440K_GPL;
  Command->DataLength = DISK_1440K_DTL;
}

EFI_STATUS
DataInByte (
  IN     FDC_BLK_IO_DEV  *FdcDev,
  IN OUT UINT8           *Pointer
  )
/*++

  Routine Description:  Read result byte from Data Register of FDC
  Parameters:
    Pointer UINT8 *: Be used to save result byte read from FDC   
  Returns:
    EFI_SUCCESS:    Read result byte from FDC successfully
    EFI_DEVICE_ERROR: The FDC is not ready to be read

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Pointer - add argument and description to function comment
{
  UINT8 data;

  //
  // wait for 1ms and detect the FDC is ready to be read
  //
  if (EFI_ERROR (FddDRQReady (FdcDev, DATA_IN, 1))) {
    return EFI_DEVICE_ERROR;
    //
    // is not ready
    //
  }

  data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);

  //
  // Io delay
  //
  gBS->Stall (50);

  *Pointer = data;
  return EFI_SUCCESS;
}

EFI_STATUS
DataOutByte (
  IN FDC_BLK_IO_DEV  *FdcDev,
  IN UINT8           *Pointer
  )
/*++

  Routine Description:  Write command byte to Data Register of FDC
  Parameters:
    Pointer UINT8 *: Be used to save command byte written to FDC   
  Returns:
    EFI_SUCCESS:    Write command byte to FDC successfully
    EFI_DEVICE_ERROR: The FDC is not ready to be written

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Pointer - add argument and description to function comment
{
  UINT8 data;

  //
  // wait for 1ms and detect the FDC is ready to be written
  //
  if (EFI_ERROR (FddDRQReady (FdcDev, DATA_OUT, 1))) {
    return EFI_DEVICE_ERROR;
    //
    // is not ready
    //
  }

  data = *Pointer;

  FdcWritePort (FdcDev, FDC_REGISTER_DTR, data);

  //
  // Io delay
  //
  gBS->Stall (50);

  return EFI_SUCCESS;
}

EFI_STATUS
FddWaitForBSYClear (
  IN FDC_BLK_IO_DEV  *FdcDev,
  IN UINTN           TimeoutInSeconds
  )
/*++

  Routine Description:  Detect the specified floppy logic drive is busy or 
                        not within a period of time
  Parameters:
    Disk EFI_FDC_DISK:    Indicate it is drive A or drive B
    TimeoutInSeconds UINTN: the time period for waiting   
  Returns:
    EFI_SUCCESS:  The drive and command are not busy
    EFI_TIMEOUT:  The drive or command is still busy after a period time that 
                  set by TimeoutInSeconds

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    TimeoutInSeconds - add argument and description to function comment
{
  UINTN Delay;
  UINT8 StatusRegister;
  UINT8 Mask;

  //
  // How to determine drive and command are busy or not: by the bits of
  // Main Status Register
  // bit0: Drive 0 busy (drive A)
  // bit1: Drive 1 busy (drive B)
  // bit4: Command busy
  //
  //
  // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
  //
  Mask  = (UINT8) ((FdcDev->Disk == FDC_DISK0 ? MSR_DAB : MSR_DBB) | MSR_CB);

  Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;
  do {
    StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
    if ((StatusRegister & Mask) == 0x00) {
      break;
      //
      // not busy
      //
    }

    gBS->Stall (50);
    Delay = Delay - 1;
  } while (Delay);

  if (Delay == 0) {
    return EFI_TIMEOUT;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
FddDRQReady (
  IN FDC_BLK_IO_DEV  *FdcDev,
  IN BOOLEAN         Dio,
  IN  UINTN          TimeoutInSeconds
  )
/*++

  Routine Description:  Determine whether FDC is ready to write or read
  Parameters:
    Dio BOOLEAN:      Indicate the FDC is waiting to write or read
    TimeoutInSeconds UINTN: The time period for waiting   
  Returns:
    EFI_SUCCESS:  FDC is ready to write or read
    EFI_NOT_READY:  FDC is not ready within the specified time period

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Dio - add argument and description to function comment
// GC_TODO:    TimeoutInSeconds - add argument and description to function comment
{
  UINTN Delay;
  UINT8 StatusRegister;
  UINT8 DataInOut;

  //
  // Before writing to FDC or reading from FDC, the Host must examine
  // the bit7(RQM) and bit6(DIO) of the Main Status Register.
  // That is to say:
  //  command bytes can not be written to Data Register
  //  unless RQM is 1 and DIO is 0
  //  result bytes can not be read from Data Register
  //  unless RQM is 1 and DIO is 1
  //
  DataInOut = (UINT8) (Dio << 6);
  //
  // in order to compare bit6
  //
  Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;
  do {
    StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
    if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {
      break;
      //
      // FDC is ready
      //
    }

    gBS->Stall (50);
    //
    // Stall for 50 us
    //
    Delay = Delay - 1;
  } while (Delay);

  if (Delay == 0) {
    return EFI_NOT_READY;
    //
    // FDC is not ready within the specified time period
    //
  }

  return EFI_SUCCESS;
}

EFI_STATUS
CheckResult (
  IN     FDD_RESULT_PACKET  Result,
  IN OUT FDC_BLK_IO_DEV     *FdcDev
  )
/*++

Routine Description:

  GC_TODO: Add function description

Arguments:

  Result  - GC_TODO: add argument description
  FdcDev  - GC_TODO: add argument description

Returns:

  EFI_DEVICE_ERROR - GC_TODO: Add description for return value
  EFI_DEVICE_ERROR - GC_TODO: Add description for return value
  EFI_DEVICE_ERROR - GC_TODO: Add description for return value
  EFI_SUCCESS - GC_TODO: Add description for return value

--*/
{
  //
  // Check Status Register0
  //
  if ((Result.Status0 & STS0_IC) != IC_NT) {
    if ((Result.Status0 & STS0_SE) == 0x20) {
      //
      // seek error
      //
      FdcDev->ControllerState->NeedRecalibrate = TRUE;
    }

    FdcDev->ControllerState->NeedRecalibrate = TRUE;
    return EFI_DEVICE_ERROR;
  }
  //
  // Check Status Register1
  //
  if (Result.Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) {
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
    return EFI_DEVICE_ERROR;
  }
  //
  // Check Status Register2
  //
  if (Result.Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) {
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
CheckStatus3 (
  IN UINT8 StatusRegister3
  )
/*++

  Routine Description:  Check the drive status information
  Parameters:
    StatusRegister3 UINT8: the value of Status Register 3    
  Returns:
    EFI_SUCCESS:     
    EFI_WRITE_PROTECTED:  The disk is write protected

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    StatusRegister3 - add argument and description to function comment
{
  if (StatusRegister3 & STS3_WP) {
    return EFI_WRITE_PROTECTED;
  }

  return EFI_SUCCESS;
}

UINTN
GetTransferBlockCount (
  IN  FDC_BLK_IO_DEV  *FdcDev,
  IN  EFI_LBA         LBA,
  IN  UINTN           NumberOfBlocks
  )
/*++

  Routine Description:  Calculate the number of block in the same cylinder 
                        according to LBA
  Parameters:
    FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
    LBA EFI_LBA:      The starting logic block address            
    NumberOfBlocks UINTN: The number of blocks
  Returns:
    UINTN : The number of blocks in the same cylinder which the starting 
        logic block address is LBA

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    LBA - add argument and description to function comment
// GC_TODO:    NumberOfBlocks - add argument and description to function comment
{
  UINT8 EndOfTrack;
  UINT8 Head;
  UINT8 SectorsInTrack;

  //
  // Calculate the number of block in the same cylinder
  //
  EndOfTrack      = DISK_1440K_EOT;
  Head            = (UINT8) ((UINTN) LBA / EndOfTrack % 2);

  SectorsInTrack  = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));
  if (SectorsInTrack < NumberOfBlocks) {
    return SectorsInTrack;
  } else {
    return NumberOfBlocks;
  }
}

VOID
EFIAPI
FddTimerProc (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
/*++

  Routine Description:  When the Timer(2s) off, turn the drive's motor off
  Parameters:
    Event EFI_EVENT: Event(the timer) whose notification function is being 
                     invoked
    Context VOID *:  Pointer to the notification function's context 
  Returns:
    VOID

--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    Event - add argument and description to function comment
// GC_TODO:    Context - add argument and description to function comment
{
  FDC_BLK_IO_DEV  *FdcDev;
  UINT8           data;

  FdcDev = (FDC_BLK_IO_DEV *) Context;

  //
  // Get the motor status
  //
  data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);

  if (((FdcDev->Disk == FDC_DISK0) && ((data & 0x10) != 0x10)) ||
      ((FdcDev->Disk == FDC_DISK1) && ((data & 0x21) != 0x21))
      ) {
    return ;
  }
  //
  // the motor is on, so need motor off
  //
  data = 0x0C;
  data |= (SELECT_DRV & FdcDev->Disk);
  FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);
  gBS->Stall (500);
}

UINT8
FdcReadPort (
  IN FDC_BLK_IO_DEV  *FdcDev,
  IN UINT32          Offset
  )
/*++

  Routine Description: Read I/O port for FDC  
  Parameters:
  Returns:
    
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Offset - add argument and description to function comment
{
  UINT8       Data;
  EFI_STATUS  Status;

  //
  // Call IsaIo
  //
  Status = FdcDev->IsaIo->Io.Read (
                              FdcDev->IsaIo,
                              EfiIsaIoWidthUint8,
                              FdcDev->BaseAddress + Offset,
                              1,
                              &Data
                              );

  return Data;
}

VOID
FdcWritePort (
  IN FDC_BLK_IO_DEV  *FdcDev,
  IN UINT32          Offset,
  IN UINT8           Data
  )
/*++

  Routine Description: Write I/O port for FDC  
  Parameters:
  Returns:
    
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO:    FdcDev - add argument and description to function comment
// GC_TODO:    Offset - add argument and description to function comment
// GC_TODO:    Data - add argument and description to function comment
{
  EFI_STATUS  Status;

  //
  // Call IsaIo
  //
  Status = FdcDev->IsaIo->Io.Write (
                              FdcDev->IsaIo,
                              EfiIsaIoWidthUint8,
                              FdcDev->BaseAddress + Offset,
                              1,
                              &Data
                              );
}

⌨️ 快捷键说明

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