isafloppyctrl.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,560 行 · 第 1/3 页
C
1,560 行
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
IsaFloppyCtrl.c
Abstract:
ISA Floppy Driver
1. Support two types diskette drive
1.44M drive and 2.88M drive (and now only support 1.44M)
2. Support two diskette drives
3. Use DMA channel 2 to transfer data
4. Do not use interrupt
5. Support diskette change line signal and write protect
The internal function for the floppy driver
Revision History:
--*/
#include "IsaFloppy.h"
EFI_STATUS
DiscoverFddDevice (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Detect the floppy drive is presented or not
Parameters:
FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS Drive is presented
EFI_NOT_FOUND Drive is not presented
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
EFI_STATUS Status;
FdcDev->BlkIo.Media = &FdcDev->BlkMedia;
//
// Call FddIndentify subroutine
//
Status = FddIdentify (FdcDev);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
FdcDev->BlkIo.Reset = FdcReset;
FdcDev->BlkIo.FlushBlocks = FddFlushBlocks;
FdcDev->BlkIo.ReadBlocks = FddReadBlocks;
FdcDev->BlkIo.WriteBlocks = FddWriteBlocks;
FdcDev->BlkMedia.LogicalPartition = FALSE;
FdcDev->BlkMedia.WriteCaching = FALSE;
return EFI_SUCCESS;
}
EFI_STATUS
FddIdentify (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Do recalibrate and see the drive is presented or not
Set the media parameters
Parameters:
FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS:
EFI_DEVICE_ERROR:
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
EFI_STATUS Status;
//
// Set Floppy Disk Controller's motor on
//
Status = MotorOn (FdcDev);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
Status = Recalibrate (FdcDev);
if (EFI_ERROR (Status)) {
MotorOff (FdcDev);
FdcDev->ControllerState->NeedRecalibrate = TRUE;
return EFI_DEVICE_ERROR;
}
//
// Set Media Parameter
//
FdcDev->BlkIo.Media->RemovableMedia = TRUE;
FdcDev->BlkIo.Media->MediaPresent = TRUE;
//
// investigate
//
FdcDev->BlkIo.Media->MediaId = 0;
//
// Check Media
//
Status = DisketChanged (FdcDev);
switch (Status) {
case EFI_NO_MEDIA:
FdcDev->BlkIo.Media->MediaPresent = FALSE;
break;
case EFI_MEDIA_CHANGED:
case EFI_SUCCESS:
break;
default:
MotorOff (FdcDev);
return Status;
}
//
// Check Disk Write Protected
//
Status = SenseDrvStatus (FdcDev, 0);
switch (Status) {
case EFI_WRITE_PROTECTED:
FdcDev->BlkIo.Media->ReadOnly = TRUE;
break;
case EFI_SUCCESS:
FdcDev->BlkIo.Media->ReadOnly = FALSE;
break;
default:
return EFI_DEVICE_ERROR;
break;
}
MotorOff (FdcDev);
//
// Set Media Default Type
//
FdcDev->BlkIo.Media->BlockSize = DISK_1440K_BYTEPERSECTOR;
FdcDev->BlkIo.Media->LastBlock = DISK_1440K_EOT * 2 * (DISK_1440K_MAXTRACKNUM + 1) - 1;
return EFI_SUCCESS;
}
EFI_STATUS
FddReset (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Reset the Floppy Logic Drive
Parameters:
FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS: The Floppy Logic Drive is reset
EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
can not be reset
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
UINT8 data;
UINT8 StatusRegister0;
UINT8 PresentCylinderNumber;
UINTN Index;
//
// Report reset progress code
//
ReportStatusCodeWithDevicePath (
EFI_PROGRESS_CODE,
EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET,
0,
&gEfiCallerIdGuid,
FdcDev->DevicePath
);
//
// Reset specified Floppy Logic Drive according to FdcDev -> Disk
// Set Digital Output Register(DOR) to do reset work
// bit0 & bit1 of DOR : Drive Select
// bit2 : Reset bit
// bit3 : DMA and Int bit
// Reset : a "0" written to bit2 resets the FDC, this reset will remain
// active until
// a "1" is written to this bit.
// Reset step 1:
// use bit0 & bit1 to select the logic drive
// write "0" to bit2
//
data = 0x0;
data |= (SELECT_DRV & FdcDev->Disk);
FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);
//
// wait some time,at least 120us
//
gBS->Stall (500);
//
// Reset step 2:
// write "1" to bit2
// write "1" to bit3 : enable DMA
//
data |= 0x0C;
FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);
//
// Experience value
//
gBS->Stall (2000);
//
// wait specified floppy logic drive is not busy
//
if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
return EFI_DEVICE_ERROR;
}
//
// Set the Transfer Data Rate
//
FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);
//
// Experience value
//
gBS->Stall (100);
//
// Issue Sense interrupt command for each drive (total 4 drives)
//
for (Index = 0; Index < 4; Index++) {
if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
return EFI_DEVICE_ERROR;
}
}
//
// issue Specify command
//
if (EFI_ERROR (Specify (FdcDev))) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
EFI_STATUS
MotorOn (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Turn the drive's motor on
The drive's motor must be on before any command can be executed
Parameters:
FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS: Turn the drive's motor on successfully
EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on
EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
EFI_STATUS Status;
UINT8 data;
//
// Control of the floppy drive motors is a big pain. If motor is off, you have
// to turn it on first. But you can not leave the motor on all the time, since
// that would wear out the disk. On the other hand, if you turn the motor off
// after each operation, the system performance will be awful. The compromise
// used in this driver is to leave the motor on for 2 seconds after
// each operation. If a new operation is started in that interval(2s),
// the motor need not be turned on again. If no new operation is started,
// a timer goes off and the motor is turned off
//
//
// Cancel the timer
//
Status = gBS->SetTimer (FdcDev->Event, TimerCancel, 0);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
//
// 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 EFI_SUCCESS;
}
//
// The drive's motor is off, so need turn it on
// first look at command and drive are busy or not
//
if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
return EFI_DEVICE_ERROR;
}
//
// for drive A: 1CH, drive B: 2DH
//
data = 0x0C;
data |= (SELECT_DRV & FdcDev->Disk);
if (FdcDev->Disk == FDC_DISK0) {
//
// drive A
//
data |= DRVA_MOTOR_ON;
} else {
//
// drive B
//
data |= DRVB_MOTOR_ON;
}
FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);
//
// Experience value
//
gBS->Stall (4000);
return EFI_SUCCESS;
}
EFI_STATUS
MotorOff (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Set a Timer and when Timer goes off, turn the motor off
Parameters:
FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS: Set the Timer successfully
EFI_INVALID_PARAMETER: Fail to Set the timer
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
//
// Set the timer : 2s
//
return gBS->SetTimer (FdcDev->Event, TimerRelative, 20000000);
}
EFI_STATUS
DisketChanged (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Detect the disk in the drive is changed or not
Parameters:
FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS: No disk media change
EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation
EFI_NO_MEDIA: No disk in the drive
EFI_MEDIA_CHANGED: There is a new disk in the drive
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
EFI_STATUS Status;
UINT8 data;
//
// Check change line
//
data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
//
// Io delay
//
gBS->Stall (50);
if ((data & DIR_DCL) == 0x80) {
//
// disk change line is active
//
if (FdcDev->PresentCylinderNumber != 0) {
Status = Recalibrate (FdcDev);
} else {
Status = Seek (FdcDev, 0x30);
}
if (EFI_ERROR (Status)) {
FdcDev->ControllerState->NeedRecalibrate = TRUE;
return EFI_DEVICE_ERROR;
//
// Fail to do the seek or recalibrate operation
//
}
data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
//
// Io delay
//
gBS->Stall (50);
if ((data & DIR_DCL) == 0x80) {
return EFI_NO_MEDIA;
}
return EFI_MEDIA_CHANGED;
}
return EFI_SUCCESS;
}
EFI_STATUS
Specify (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Do the Specify command, this command sets DMA operation
and the initial values for each of the three internal
times: HUT, SRT and HLT
Parameters:
None
Returns:
EFI_SUCCESS: Execute the Specify command successfully
EFI_DEVICE_ERROR: Fail to execute the command
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
FDD_SPECIFY_CMD Command;
UINTN Index;
UINT8 *CommandPointer;
EfiZeroMem (&Command, sizeof (FDD_SPECIFY_CMD));
Command.CommandCode = SPECIFY_CMD;
//
// set SRT, HUT
//
Command.SrtHut = 0xdf;
//
// 0xdf;
//
// set HLT and DMA
//
Command.HltNd = 0x02;
CommandPointer = (UINT8 *) (&Command);
for (Index = 0; Index < sizeof (FDD_SPECIFY_CMD); Index++) {
if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
return EFI_DEVICE_ERROR;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
Recalibrate (
IN FDC_BLK_IO_DEV *FdcDev
)
/*++
Routine Description: Set the head of floppy drive to track 0
Parameters:
FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
Returns:
EFI_SUCCESS: Execute the Recalibrate operation successfully
EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
--*/
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: FdcDev - add argument and description to function comment
{
FDD_COMMAND_PACKET2 Command;
UINTN Index;
UINT8 StatusRegister0;
UINT8 PresentCylinderNumber;
UINT8 *CommandPointer;
UINT8 Count;
Count = 2;
while (Count > 0) {
EfiZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));
Command.CommandCode = RECALIBRATE_CMD;
//
// drive select
//
if (FdcDev->Disk == FDC_DISK0) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?