git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3896 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1527 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1527 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**@file
 | |
|   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
 | |
|   
 | |
| Copyright (c) 2006 - 2007, Intel Corporation.<BR>
 | |
| 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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) &&
 | |
|              (Status != EFI_SUCCESS)) {
 | |
|     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
 | |
|                       );
 | |
| }
 |