/*++ Copyright (c) 2006 - 2007, 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); if (Status == EFI_NO_MEDIA) { FdcDev->BlkIo.Media->MediaPresent = FALSE; } else if (Status != EFI_MEDIA_CHANGED) { MotorOff (FdcDev); return Status; } // // Check Disk Write Protected // Status = SenseDrvStatus (FdcDev, 0); if (Status == EFI_WRITE_PROTECTED) { FdcDev->BlkIo.Media->ReadOnly = TRUE; } else if (Status == EFI_SUCCESS) { FdcDev->BlkIo.Media->ReadOnly = FALSE; } else { return EFI_DEVICE_ERROR; } 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 // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET, 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 = (UINT8) (data | (SELECT_DRV & FdcDev->Disk)); FdcWritePort (FdcDev, FDC_REGISTER_DOR, data); // // wait some time,at least 120us // MicroSecondDelay (500); // // Reset step 2: // write "1" to bit2 // write "1" to bit3 : enable DMA // data |= 0x0C; FdcWritePort (FdcDev, FDC_REGISTER_DOR, data); // // Experience value // MicroSecondDelay (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 // MicroSecondDelay (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 = (UINT8) (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 // MicroSecondDelay (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 // MicroSecondDelay (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 // MicroSecondDelay (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; ZeroMem (&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) { ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2)); Command.CommandCode = RECALIBRATE_CMD; // // drive select // if (FdcDev->Disk == FDC_DISK0) { Command.DiskHeadSel = 0; // // 0 // } else { Command.DiskHeadSel = 1; // // 1 // } CommandPointer = (UINT8 *) (&Command); for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) { if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) { return EFI_DEVICE_ERROR; } } // // Experience value // MicroSecondDelay (250000); // // need modify according to 1.44M or 2.88M // if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) { return EFI_DEVICE_ERROR; } if ((StatusRegister0 & 0xf0) == 0x20 && PresentCylinderNumber == 0) { FdcDev->PresentCylinderNumber = 0; FdcDev->ControllerState->NeedRecalibrate = FALSE; return EFI_SUCCESS; } else { Count--; if (Count == 0) { return EFI_DEVICE_ERROR; } } } // // end while // return EFI_SUCCESS; } EFI_STATUS Seek ( IN FDC_BLK_IO_DEV *FdcDev, IN EFI_LBA Lba ) /*++ Routine Description: Set the head of floppy drive to the new cylinder Parameters: FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV Lba EFI_LBA : The logic block address want to seek Returns: EFI_SUCCESS: Execute the Seek operation successfully EFI_DEVICE_ERROR: Fail to execute the Seek operation --*/ // 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 { FDD_SEEK_CMD Command; UINT8 EndOfTrack; UINT8 Head; UINT8 Cylinder; UINT8 StatusRegister0; UINT8 *CommandPointer; UINT8 PresentCylinderNumber; UINTN Index; UINT8 DelayTime; if (FdcDev->ControllerState->NeedRecalibrate) { if (EFI_ERROR (Recalibrate (FdcDev))) { FdcDev->ControllerState->NeedRecalibrate = TRUE; return EFI_DEVICE_ERROR; } } EndOfTrack = DISK_1440K_EOT; // // Calculate cylinder based on Lba and EOT // Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2); // // if the destination cylinder is the present cylinder, unnecessary to do the // seek operation // if (FdcDev->PresentCylinderNumber == Cylinder) { return EFI_SUCCESS; } // // Calculate the head : 0 or 1 // Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2); ZeroMem (&Command, sizeof (FDD_SEEK_CMD)); Command.CommandCode = SEEK_CMD; if (FdcDev->Disk == FDC_DISK0) { Command.DiskHeadSel = 0; // // 0 // } else { Command.DiskHeadSel = 1; // // 1 // } Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2)); Command.NewCylinder = Cylinder; CommandPointer = (UINT8 *) (&Command); for (Index = 0; Index < sizeof (FDD_SEEK_CMD); Index++) { if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) { return EFI_DEVICE_ERROR; } } // // Io delay // MicroSecondDelay (100); // // Calculate waiting time // if (FdcDev->PresentCylinderNumber > Cylinder) { DelayTime = (UINT8) (FdcDev->PresentCylinderNumber - Cylinder); } else { DelayTime = (UINT8) (Cylinder - FdcDev->PresentCylinderNumber); } MicroSecondDelay ((DelayTime + 1) * 4000); if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) { return EFI_DEVICE_ERROR; } if ((StatusRegister0 & 0xf0) == 0x20) { FdcDev->PresentCylinderNumber = Command.NewCylinder; return EFI_SUCCESS; } else { FdcDev->ControllerState->NeedRecalibrate = TRUE; return EFI_DEVICE_ERROR; } } EFI_STATUS SenseIntStatus ( IN FDC_BLK_IO_DEV *FdcDev, IN OUT UINT8 *StatusRegister0, IN OUT UINT8 *PresentCylinderNumber ) /*++ Routine Description: Do the Sense Interrupt Status command, this command resets the interrupt signal Parameters: StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC PresentCylinderNumber UINT8 *: Be used to save present cylinder number read from FDC Returns: EFI_SUCCESS: Execute the Sense Interrupt Status 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 // GC_TODO: StatusRegister0 - add argument and description to function comment // GC_TODO: PresentCylinderNumber - add argument and description to function comment { UINT8 command; command = SENSE_INT_STATUS_CMD; if (EFI_ERROR (DataOutByte (FdcDev, &command))) { return EFI_DEVICE_ERROR; } if (EFI_ERROR (DataInByte (FdcDev, StatusRegister0))) { return EFI_DEVICE_ERROR; } if (EFI_ERROR (DataInByte (FdcDev, PresentCylinderNumber))) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } EFI_STATUS SenseDrvStatus ( IN FDC_BLK_IO_DEV *FdcDev, IN EFI_LBA Lba ) /*++ Routine Description: Do the Sense Drive Status command Parameters: FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV Lba EFI_LBA : Logic block address Returns: EFI_SUCCESS: Execute the Sense Drive Status command successfully EFI_DEVICE_ERROR: Fail to execute the command EFI_WRITE_PROTECTED:The disk is write protected --*/ // 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 { FDD_COMMAND_PACKET2 Command; UINT8 Head; UINT8 EndOfTrack; UINTN Index; UINT8 StatusRegister3; UINT8 *CommandPointer; // // Sense Drive Status command obtains drive status information, // it has not execution phase and goes directly to the result phase from the // command phase, Status Register 3 contains the drive status information // ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2)); Command.CommandCode = SENSE_DRV_STATUS_CMD; if (FdcDev->Disk == FDC_DISK0) { Command.DiskHeadSel = 0; } else { Command.DiskHeadSel = 1; } EndOfTrack = DISK_1440K_EOT; Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2); Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2)); CommandPointer = (UINT8 *) (&Command); for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) { if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) { return EFI_DEVICE_ERROR; } } if (EFI_ERROR (DataInByte (FdcDev, &StatusRegister3))) { return EFI_DEVICE_ERROR; } // // Io delay // MicroSecondDelay (50); // // Check Status Register 3 to get drive status information // return CheckStatus3 (StatusRegister3); } EFI_STATUS DetectMedia ( IN FDC_BLK_IO_DEV *FdcDev ) /*++ Routine Description: Update the disk media properties and if necessary reinstall Block I/O interface Parameters: FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV Returns: EFI_SUCCESS: Do the operation successfully EFI_DEVICE_ERROR: Fail to the operation --*/ // GC_TODO: function comment is missing 'Arguments:' // GC_TODO: FdcDev - add argument and description to function comment { EFI_STATUS Status; BOOLEAN bReset; BOOLEAN bReadOnlyLastTime; BOOLEAN bMediaPresentLastTime; bReset = FALSE; bReadOnlyLastTime = FdcDev->BlkIo.Media->ReadOnly; bMediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent; // // Check disk change // Status = DisketChanged (FdcDev); if (Status == EFI_MEDIA_CHANGED) { FdcDev->BlkIo.Media->MediaId++; FdcDev->BlkIo.Media->MediaPresent = TRUE; bReset = TRUE; } else if (Status == EFI_NO_MEDIA) { FdcDev->BlkIo.Media->MediaPresent = FALSE; } else if (Status != EFI_SUCCESS) { MotorOff (FdcDev); return Status; // // EFI_DEVICE_ERROR // } if (FdcDev->BlkIo.Media->MediaPresent) { // // Check disk write protected // Status = SenseDrvStatus (FdcDev, 0); if (Status == EFI_WRITE_PROTECTED) { FdcDev->BlkIo.Media->ReadOnly = TRUE; } else { FdcDev->BlkIo.Media->ReadOnly = FALSE; } } if (FdcDev->BlkIo.Media->MediaPresent && (bReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) { bReset = TRUE; } if (bMediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) { bReset = TRUE; } if (bReset) { Status = gBS->ReinstallProtocolInterface ( FdcDev->Handle, &gEfiBlockIoProtocolGuid, &FdcDev->BlkIo, &FdcDev->BlkIo ); if (EFI_ERROR (Status)) { return Status; } } return EFI_SUCCESS; } EFI_STATUS Setup ( IN FDC_BLK_IO_DEV *FdcDev ) /*++ Routine Description: Set the data rate and so on Parameters: None Returns: EFI_SUCCESS: --*/ // GC_TODO: function comment is missing 'Arguments:' // GC_TODO: FdcDev - add argument and description to function comment // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment { EFI_STATUS Status; // // Set data rate 500kbs // FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0); // // Io delay // MicroSecondDelay (50); Status = Specify (FdcDev); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } EFI_STATUS ReadWriteDataSector ( IN FDC_BLK_IO_DEV *FdcDev, IN VOID *HostAddress, IN EFI_LBA Lba, IN UINTN NumberOfBlocks, IN BOOLEAN Read ) /*++ Routine Description: Read or Write a number of blocks in the same cylinder Parameters: FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV Buffer VOID *: Lba EFI_LBA: NumberOfBlocks UINTN: Read BOOLEAN: Returns: EFI_SUCCESS: --*/ // GC_TODO: function comment is missing 'Arguments:' // GC_TODO: FdcDev - add argument and description to function comment // GC_TODO: HostAddress - 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 // GC_TODO: Read - add argument and description to function comment // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment // GC_TODO: EFI_TIMEOUT - add return value to function comment // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment { EFI_STATUS Status; FDD_COMMAND_PACKET1 Command; FDD_RESULT_PACKET Result; UINTN Index; UINTN Times; UINT8 *CommandPointer; EFI_PHYSICAL_ADDRESS DeviceAddress; EFI_ISA_IO_PROTOCOL *IsaIo; UINTN NumberofBytes; VOID *Mapping; EFI_ISA_IO_PROTOCOL_OPERATION Operation; EFI_STATUS Status1; UINT8 Channel; EFI_ISA_ACPI_RESOURCE *ResourceItem; UINT32 Attribute; Status = Seek (FdcDev, Lba); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } // // Map Dma // IsaIo = FdcDev->IsaIo; NumberofBytes = NumberOfBlocks * 512; if (Read == READ) { Operation = EfiIsaIoOperationSlaveWrite; } else { Operation = EfiIsaIoOperationSlaveRead; } ResourceItem = IsaIo->ResourceList->ResourceItem; Index = 0; while (ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList) { if (ResourceItem[Index].Type == EfiIsaAcpiResourceDma) { break; } Index++; } if (ResourceItem[Index].Type == EfiIsaAcpiResourceEndOfList) { return EFI_DEVICE_ERROR; } Channel = (UINT8) IsaIo->ResourceList->ResourceItem[Index].StartRange; Attribute = IsaIo->ResourceList->ResourceItem[Index].Attribute; Status1 = IsaIo->Map ( IsaIo, Operation, Channel, Attribute, HostAddress, &NumberofBytes, &DeviceAddress, &Mapping ); if (EFI_ERROR (Status1)) { return Status1; } // // Allocate Read or Write command packet // ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET1)); if (Read == READ) { Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK; } else { Command.CommandCode = WRITE_DATA_CMD | CMD_MT | CMD_MFM; } FillPara (FdcDev, Lba, &Command); // // Write command bytes to FDC // CommandPointer = (UINT8 *) (&Command); for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET1); Index++) { if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) { return EFI_DEVICE_ERROR; } } // // wait for some time // Times = (STALL_1_SECOND / 50) + 1; do { if ((FdcReadPort (FdcDev, FDC_REGISTER_MSR) & 0xc0) == 0xc0) { break; } MicroSecondDelay (50); Times = Times - 1; } while (Times); 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 = (UINT8) (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 // MicroSecondDelay (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 // MicroSecondDelay (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 // } MicroSecondDelay (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 // } MicroSecondDelay (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 = (UINT8) (data | (SELECT_DRV & FdcDev->Disk)); FdcWritePort (FdcDev, FDC_REGISTER_DOR, data); MicroSecondDelay (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; // // Call IsaIo // 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 { // // Call IsaIo // FdcDev->IsaIo->Io.Write ( FdcDev->IsaIo, EfiIsaIoWidthUint8, FdcDev->BaseAddress + Offset, 1, &Data ); }