atapiextpassthru.c

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

C
2,448
字号
  UINT64  Delay;
  UINT8   AltStatusRegister;
  UINT8   ErrRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {

    AltStatusRegister = ReadPortB (
                          AtapiScsiPrivate->PciIo,
                          AtapiScsiPrivate->IoPort->Alt.AltStatus
                          );

    //
    // wait for BSY == 0 and DRQ == 0
    //
    if ((AltStatusRegister & (DRQ | BSY)) == 0) {
      break;
    }

    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

      ErrRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg1.Error
                      );
      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

        return EFI_ABORTED;
      }
    }
    //
    //  Stall for 30 us
    //
    gBS->Stall (30);

    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}

STATIC  
EFI_STATUS
StatusDRQReady (
  ATAPI_EXT_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
  UINT64                              TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   StatusRegister;
  UINT8   ErrRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {
    //
    //  read Status Register will clear interrupt
    //
    StatusRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg.Status
                      );

    //
    //  BSY==0,DRQ==1
    //
    if ((StatusRegister & (BSY | DRQ)) == DRQ) {
      break;
    }

    if ((StatusRegister & (BSY | ERR)) == ERR) {

      ErrRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg1.Error
                      );
      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
        return EFI_ABORTED;
      }
    }

    //
    // Stall for 30 us
    //
    gBS->Stall (30);

    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}

STATIC  
EFI_STATUS
AltStatusDRQReady (
  ATAPI_EXT_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
  UINT64                              TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether DRQ is ready in the Alternate Status Register. 
  (BSY must also be cleared)
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   AltStatusRegister;
  UINT8   ErrRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {
    //
    //  read Status Register will clear interrupt
    //
    AltStatusRegister = ReadPortB (
                          AtapiScsiPrivate->PciIo,
                          AtapiScsiPrivate->IoPort->Alt.AltStatus
                          );
    //
    //  BSY==0,DRQ==1
    //
    if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
      break;
    }

    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

      ErrRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg1.Error
                      );
      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
        return EFI_ABORTED;
      }
    }

    //
    // Stall for 30 us
    //
    gBS->Stall (30);

    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}

STATIC  
EFI_STATUS
StatusWaitForBSYClear (
  ATAPI_EXT_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
  UINT64                          TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether BSY is clear in the Status Register.
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   StatusRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {

    StatusRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg.Status
                      );
    if ((StatusRegister & BSY) == 0x00) {
      break;
    }

    //
    // Stall for 30 us
    //
    gBS->Stall (30);

    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}

STATIC  
EFI_STATUS
AltStatusWaitForBSYClear (
  ATAPI_EXT_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
  UINT64                          TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether BSY is clear in the Alternate Status Register.
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   AltStatusRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {

    AltStatusRegister = ReadPortB (
                          AtapiScsiPrivate->PciIo,
                          AtapiScsiPrivate->IoPort->Alt.AltStatus
                          );
    if ((AltStatusRegister & BSY) == 0x00) {
      break;
    }

    //
    // Stall for 30 us
    //
    gBS->Stall (30);
    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}

STATIC  
EFI_STATUS
StatusDRDYReady (
  ATAPI_EXT_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
  UINT64                           TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether DRDY is ready in the Status Register. 
  (BSY must also be cleared)
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   StatusRegister;
  UINT8   ErrRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {
    StatusRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg.Status
                      );
    //
    //  BSY == 0 , DRDY == 1
    //
    if ((StatusRegister & (DRDY | BSY)) == DRDY) {
      break;
    }

    if ((StatusRegister & (BSY | ERR)) == ERR) {

      ErrRegister = ReadPortB (
                      AtapiScsiPrivate->PciIo,
                      AtapiScsiPrivate->IoPort->Reg1.Error
                      );
      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
        return EFI_ABORTED;
      }
    }
    
    //
    // Stall for 30 us
    //
    gBS->Stall (30);
    //
    // Loop infinitely if not meeting expected condition
    //
    if (TimeoutInMicroSeconds == 0) {
      Delay = 2;
    }

    Delay--;
  } while (Delay);

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

  return EFI_SUCCESS;
}


STATIC  
EFI_STATUS
AltStatusDRDYReady (
  ATAPI_EXT_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
  UINT64                           TimeoutInMicroSeconds
  )
/*++

Routine Description:

  Check whether DRDY is ready in the Alternate Status Register. 
  (BSY must also be cleared)
  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 
  elapsed.

Arguments:

  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
  TimeoutInMicroSeconds       - The time to wait for
   
Returns:

  EFI_STATUS

--*/
{
  UINT64  Delay;
  UINT8   AltStatusRegister;
  UINT8   ErrRegister;
  UINTN   Remainder;

  if (TimeoutInMicroSeconds == 0) {
    Delay = 2;
  } else {
    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30, &Remainder) + 1;
  }

  do {
    AltStatusRegister = ReadPor

⌨️ 快捷键说明

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