Massive floppy work

svn path=/trunk/; revision=1757
This commit is contained in:
Phillip Susi 2001-03-31 15:53:56 +00:00
parent 6b46ea08e7
commit d8538e9795
5 changed files with 761 additions and 449 deletions

View file

@ -1,20 +1,28 @@
# $Id: Makefile,v 1.5 2000/12/08 00:43:45 ekohl Exp $
# $Id: Makefile,v 1.6 2001/03/31 15:53:56 phreak Exp $
#
#
PATH_TO_TOP = ../../..
TARGET=floppy
OBJECTS = $(TARGET).o $(TARGET).coff ../../../ntoskrnl/ntoskrnl.a
OBJECTS = floppy.o isr.o dpc.o $(TARGET).coff ../../../ntoskrnl/ntoskrnl.a
CFLAGS = -I.
all: $(TARGET).sys
floppy.o: floppy.h
isr.o: floppy.h
dpc.o: floppy.h
.phony: all
clean:
- $(RM) $(TARGET).o
- $(RM) floppy.o
- $(RM) isr.o
- $(RM) dpc.o
- $(RM) $(TARGET).coff
- $(RM) junk.tmp
- $(RM) base.tmp

View file

@ -0,0 +1,156 @@
/****************************************************************************
* Defered procedure calls for floppy disk driver, reactos project, created *
* by Phillip Susi on 2/25/2001. This software is published under the GNU *
* general public license, see the README file for more details *
***************************************************************************/
#include <ddk/ntddk.h>
#include <debug.h>
#include "floppy.h"
VOID FloppyDpc( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
CHECKPOINT1;
ControllerExtension->DpcState( Dpc,
DeviceObject,
Irp,
Context );
}
VOID FloppyDpcDetect( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
CHECKPOINT1;
KeSetEvent( &ControllerExtension->Event, 0, FALSE );
}
VOID FloppyDpcFailIrp( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context )
{
CHECKPOINT1;
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
IoCompleteRequest( Irp, 0 );
}
VOID FloppyMotorSpindownDpc( PKDPC Dpc,
PVOID Context,
PVOID Arg1,
PVOID Arg2 )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
PFLOPPY_DEVICE_EXTENSION DeviceExtension = (PFLOPPY_DEVICE_EXTENSION)ControllerExtension->Device->DeviceExtension;
CHECKPOINT1;
// queue call to turn off motor
IoAllocateController( Controller,
ControllerExtension->Device,
FloppyExecuteSpindown,
ControllerExtension );
}
VOID FloppyMotorSpinupDpc( PKDPC Dpc,
PVOID Context,
PVOID Arg1,
PVOID Arg2 )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
PFLOPPY_DEVICE_EXTENSION DeviceExtension = (PFLOPPY_DEVICE_EXTENSION)ControllerExtension->Device->DeviceExtension;
LARGE_INTEGER Timeout;
CHECKPOINT1;
Timeout.QuadPart = FLOPPY_MOTOR_SPINDOWN_TIME;
// Motor has had time to spin up, mark motor as spun up and restart IRP
// don't forget to set the spindown timer
KeSetTimer( &ControllerExtension->SpinupTimer,
Timeout,
&ControllerExtension->MotorSpindownDpc );
DPRINT( "Motor spun up, retrying operation\n" );
ControllerExtension->MotorOn = DeviceExtension->DriveSelect;
IoFreeController( Controller );
IoAllocateController( Controller,
ControllerExtension->Device,
FloppyExecuteReadWrite,
ControllerExtension->Irp );
}
VOID FloppyDpcReadWrite( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
DWORD SectorSize = 128 << ControllerExtension->SectorSizeCode;
CHECKPOINT1;
Irp = ControllerExtension->Irp;
// if the IO failed, fail the IRP
if( ControllerExtension->St0 & FLOPPY_ST0_GDMASK )
{
Irp->IoStatus.Status = STATUS_DISK_CORRUPT_ERROR;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, 0 );
CHECKPOINT1;
return;
}
ControllerExtension->CurrentOffset += SectorSize;
ControllerExtension->CurrentLength -= SectorSize;
(char *)ControllerExtension->CurrentVa += SectorSize;
// if there is more IO to be done, restart execute routine to issue next read
if( ControllerExtension->CurrentLength )
{
CHECKPOINT1;
if( FloppyExecuteReadWrite( DeviceObject,
Irp,
ControllerExtension->MapRegisterBase,
Irp ) == DeallocateObject )
IoFreeController( Controller );
}
else {
CHECKPOINT1;
// oetherwise, complete the Irp
IoCompleteRequest( Irp, 0 );
}
}
VOID FloppyDpcDetectMedia( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context )
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)Context;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
CHECKPOINT1;
// If the read ID failed, fail the irp
if( ControllerExtension->St1 != 0 )
{
DPRINT( "Read ID failed: ST1 = %2x\n", ControllerExtension->St1 );
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
IoCompleteRequest( Irp, 0 );
return;
}
// set media type, and restart the IRP from the beginning
((PFLOPPY_DEVICE_EXTENSION)ControllerExtension->Device->DeviceExtension)->MediaType = 0;
DPRINT( "Media detected, restarting IRP\n" );
// don't forget to free the controller so that the now queued routine may execute
IoFreeController( Controller );
IoAllocateController( Controller,
DeviceObject,
FloppyExecuteReadWrite,
Irp );
}

View file

@ -6,6 +6,7 @@
*
* Modification History:
* 08/19/98 RJJ Created.
* 01/31/01 PJS Heavy rewrite, most of code thrown out
*
* To do:
* FIXME: get it working
@ -19,390 +20,37 @@
#include <debug.h>
#define VERSION "V0.0.1"
/* --------------------------------------------------- File Statics */
/* from linux drivers/block/floppy.c */
#define FLOPPY_MAX_REPLIES (16)
typedef struct _FLOPPY_DEVICE_EXTENSION
{
} FLOPPY_DEVICE_EXTENSION, *PFLOPPY_DEVICE_EXTENSION;
typedef struct _FLOPPY_CONTROLLER_EXTENSION
{
PKINTERRUPT Interrupt;
KSPIN_LOCK SpinLock;
FLOPPY_CONTROLLER_TYPE FDCType;
ULONG Number;
ULONG PortBase;
ULONG Vector;
} FLOPPY_CONTROLLER_EXTENSION, *PFLOPPY_CONTROLLER_EXTENSION;
typedef struct _FLOPPY_CONTROLLER_PARAMETERS
{
ULONG PortBase;
ULONG Vector;
ULONG IrqL;
ULONG SynchronizeIrqL;
KINTERRUPT_MODE InterruptMode;
KAFFINITY Affinity;
} FLOPPY_CONTROLLER_PARAMETERS, *PFLOPPY_CONTROLLER_PARAMETERS;
#define FLOPPY_MAX_CONTROLLERS 2
FLOPPY_CONTROLLER_PARAMETERS ControllerParameters[FLOPPY_MAX_CONTROLLERS] =
{
{0x03f0, 6, 6, 6, LevelSensitive, 0xffff},
{0x0370, 6, 6, 6, LevelSensitive, 0xffff},
{0x03f0, 6, 6, 2, 6, LevelSensitive, 0xffff}
// {0x0370, 6, 6, 6, LevelSensitive, 0xffff},
};
FLOPPY_DEVICE_PARAMETERS DeviceTypes[] =
{
/* Unknown */
{0, 500, 16, 16, 8000, 1000, 3000, 0, 20, 5, 80, 3000, 20, {3,1,2,0,2}, 0, 0, { 7, 4, 8, 2, 1, 5, 3,10}, 1500, 0, "unknown"},
/* 5 1/4 360 KB PC*/
{1, 300, 16, 16, 8000, 1000, 3000, 0, 20, 5, 40, 3000, 17, {3,1,2,0,2}, 0, 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 1500, 1, "360K PC"},
/* 5 1/4 HD AT*/
{2, 500, 16, 16, 6000, 400, 3000, 14, 20, 6, 83, 3000, 17, {3,1,2,0,2}, 0, 0, { 2, 5, 6,23,10,20,11, 0}, 1500, 2, "1.2M"},
/* 3 1/2 DD*/
{3, 250, 16, 16, 3000, 1000, 3000, 0, 20, 5, 83, 3000, 20, {3,1,2,0,2}, 0, 0, { 4,22,21,30, 3, 0, 0, 0}, 1500, 4, "720k"},
/* 3 1/2 HD*/
{4, 500, 16, 16, 4000, 400, 3000, 10, 20, 5, 83, 3000, 20, {3,1,2,0,2}, 0, 0, { 7, 4,25,22,31,21,29,11}, 1500, 7, "1.44M"},
/* 3 1/2 ED*/
{5, 1000, 15, 8, 3000, 400, 3000, 10, 20, 5, 83, 3000, 40, {3,1,2,0,2}, 0, 0, { 7, 8, 4,25,28,22,31,21}, 1500, 8, "2.88M AMI BIOS"},
/* 3 1/2 ED*/
{6, 1000, 15, 8, 3000, 400, 3000, 10, 20, 5, 83, 3000, 40, {3,1,2,0,2}, 0, 0, { 7, 8, 4,25,28,22,31,21}, 1500, 8, "2.88M"}
};
const FLOPPY_MEDIA_TYPE MediaTypes[] = {
{ 0x02, 9, 80, 18, 512 },
{ 0, 0, 0, 0, 0 } };
static BOOLEAN FloppyInitialized = FALSE;
/* Bits of main status register */
#define STATUS_BUSYMASK (0x0f)
#define STATUS_BUSY (0x10)
#define STATUS_DMA (0x20)
#define STATUS_DIR (0x40)
#define STATUS_READY (0x80)
#define FLOPPY_STATUS (4)
#define FLOPPY_DATA (5)
#define FLOPPY_CMD_UNLK_FIFO 0x14
#define FLOPPY_CMD_LOCK_FIFO 0x94
/* ------------------------------------------------------ Functions */
static int
FloppyReadSTAT(ULONG PortBase)
{
return(READ_PORT_UCHAR((PUCHAR)(PortBase + FLOPPY_STATUS)));
}
/* waits until the fdc becomes ready */
static int
FloppyWaitUntilReady(ULONG PortBase)
{
int Retries;
int Status;
for (Retries = 0; Retries < FLOPPY_MAX_STAT_RETRIES; Retries++)
{
Status = FloppyReadSTAT(PortBase);
if (Status & STATUS_READY)
{
return Status;
}
}
if (FloppyInitialized)
{
DPRINT("Getstatus times out (%x) on fdc %d\n",
Status,
PortBase);
}
return -1;
}
static VOID
FloppyWriteData(ULONG PortBase, BYTE Byte)
{
WRITE_PORT_UCHAR((PUCHAR)(PortBase + FLOPPY_DATA), Byte);
}
/* sends a command byte to the fdc */
static BOOLEAN
FloppyWriteCommandByte(ULONG PortBase, BYTE Byte)
{
int Status;
if ((Status = FloppyWaitUntilReady(PortBase)) < 0)
{
return FALSE;
}
if ((Status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY)
{
FloppyWriteData(PortBase, Byte);
return TRUE;
}
if (FloppyInitialized)
{
DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
Byte,
PortBase,
Status);
}
return FALSE;
}
/* gets the response from the fdc */
static int
FloppyReadResultCode(ULONG PortBase, PUCHAR Result)
{
int Replies;
int Status;
for (Replies = 0; Replies < FLOPPY_MAX_REPLIES; Replies++)
{
if ((Status = FloppyWaitUntilReady(PortBase)) < 0)
{
break;
}
Status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
if ((Status & ~STATUS_BUSY) == STATUS_READY)
{
return Replies;
}
if (Status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
{
Result[Replies] = READ_PORT_UCHAR((PUCHAR)(PortBase + FLOPPY_DATA));
}
else
{
DPRINT("FloppyReadResultCode: break\n");
break;
}
}
if (FloppyInitialized)
{
DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
PortBase,
Status,
Replies);
}
return -1;
}
#define MORE_OUTPUT -2
/* does the fdc need more output? */
static int
FloppyNeedsMoreOutput(ULONG PortBase, PUCHAR Result)
{
int Status;
if ((Status = FloppyWaitUntilReady(PortBase)) < 0)
return -1;
if ((Status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
{
return FLOPPY_NEEDS_OUTPUT;
}
return FloppyReadResultCode(PortBase, Result);
}
static BOOLEAN
FloppyConfigure(ULONG PortBase, BOOLEAN DisableFIFO, BYTE FIFODepth)
{
BYTE Result[FLOPPY_MAX_REPLIES];
/* Turn on FIFO */
FloppyWriteCommandByte(PortBase, FLOPPY_CMD_CFG_FIFO);
if (FloppyNeedsMoreOutput(PortBase, Result) != FLOPPY_NEEDS_OUTPUT)
{
return FALSE;
}
FloppyWriteCommandByte(PortBase, 0);
FloppyWriteCommandByte(PortBase,
0x10 |
(DisableFIFO ? 0x20 : 0x00) |
(FIFODepth & 0x0f));
/* pre-compensation from track 0 upwards */
FloppyWriteCommandByte(PortBase, 0);
return TRUE;
}
/* FloppyGetControllerVersion
*
* DESCRIPTION
* Get the type/version of the floppy controller
*
* RUN LEVEL:
* PASSIVE_LEVEL
*
* ARGUMENTS:
* IN OUT PFLOPPY_DEVICE_EXTENSION DeviceExtension
*
* RETURNS:
* BOOL success or failure
*
* COMMENTS:
* This routine (get_fdc_version) was originally written by David C. Niemi
*/
static BOOLEAN
FloppyGetControllerVersion(IN PFLOPPY_CONTROLLER_PARAMETERS ControllerParameters,
OUT PFLOPPY_CONTROLLER_TYPE ControllerType)
{
UCHAR Result[FLOPPY_MAX_REPLIES];
int ResultLength;
/* 82072 and better know DUMPREGS */
if (!FloppyWriteCommandByte(ControllerParameters->PortBase,
FLOPPY_CMD_DUMP_FDC))
{
DPRINT("Failed to write command byte\n");
return FALSE;
}
ResultLength = FloppyReadResultCode(ControllerParameters->PortBase,
Result);
if (ResultLength < 0)
{
return FALSE;
}
/* 8272a/765 don't know DUMPREGS */
if ((ResultLength == 1) && (Result[0] == 0x80))
{
DPRINT("FDC %d is an 8272A\n", ControllerParameters->PortBase);
*ControllerType = FDC_8272A;
return TRUE;
}
if (ResultLength != 10)
{
DPRINT("FDC %d init: DUMP_FDC: unexpected return of %d bytes.\n",
ControllerParameters->PortBase,
ResultLength);
return FALSE;
}
if (!FloppyConfigure(ControllerParameters->PortBase, FALSE, 0x0a))
{
DPRINT("FDC %d is an 82072\n", ControllerParameters->PortBase);
*ControllerType = FDC_82072;
return TRUE;
}
FloppyWriteCommandByte(ControllerParameters->PortBase, FLOPPY_CMD_PPND_RW);
if (FloppyNeedsMoreOutput(ControllerParameters->PortBase, Result) ==
FLOPPY_NEEDS_OUTPUT)
{
FloppyWriteCommandByte(ControllerParameters->PortBase, 0);
}
else
{
DPRINT("FDC %d is an 82072A\n", ControllerParameters->PortBase);
*ControllerType = FDC_82072A;
return TRUE;
}
/* Pre-1991 82077, doesn't know LOCK/UNLOCK */
FloppyWriteCommandByte(ControllerParameters->PortBase, FLOPPY_CMD_UNLK_FIFO);
ResultLength = FloppyReadResultCode(ControllerParameters->PortBase,
Result);
if ((ResultLength == 1) && (Result[0] == 0x80))
{
DPRINT("FDC %d is a pre-1991 82077\n", ControllerParameters->PortBase);
*ControllerType = FDC_82077_ORIG;
return TRUE;
}
if ((ResultLength != 1) || (Result[0] != 0x00))
{
DPRINT("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
ControllerParameters->PortBase,
ResultLength);
return FALSE;
}
/* Revised 82077AA passes all the tests */
FloppyWriteCommandByte(ControllerParameters->PortBase, FLOPPY_CMD_PARTID);
ResultLength = FloppyReadResultCode(ControllerParameters->PortBase,
Result);
if (ResultLength != 1)
{
DPRINT("FDC %d init: PARTID: unexpected return of %d bytes.\n",
ControllerParameters->PortBase,
ResultLength);
return FALSE;
}
if (Result[0] == 0x80)
{
DPRINT("FDC %d is a post-1991 82077\n", ControllerParameters->PortBase);
*ControllerType = FDC_82077;
return TRUE;
}
switch (Result[0] >> 5)
{
case 0x0:
/* Either a 82078-1 or a 82078SL running at 5Volt */
DPRINT("FDC %d is an 82078.\n", ControllerParameters->PortBase);
*ControllerType = FDC_82078;
return TRUE;
case 0x1:
DPRINT("FDC %d is a 44pin 82078\n", ControllerParameters->PortBase);
*ControllerType = FDC_82078;
return TRUE;
case 0x2:
DPRINT("FDC %d is a S82078B\n", ControllerParameters->PortBase);
*ControllerType = FDC_S82078B;
return TRUE;
case 0x3:
DPRINT("FDC %d is a National Semiconductor PC87306\n",
ControllerParameters->PortBase);
*ControllerType = FDC_87306;
return TRUE;
default:
DPRINT("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
ControllerParameters->PortBase,
Result[0] >> 5);
*ControllerType = FDC_82078_UNKN;
return TRUE;
}
}
static BOOLEAN
FloppyIsr(PKINTERRUPT Interrupt, PVOID ServiceContext)
{
return(TRUE);
}
static BOOLEAN
FloppyCreateController(PDRIVER_OBJECT DriverObject,
PFLOPPY_CONTROLLER_PARAMETERS ControllerParameters,
int Index)
{
FLOPPY_CONTROLLER_TYPE ControllerType;
PCONTROLLER_OBJECT ControllerObject;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension;
PFLOPPY_DEVICE_EXTENSION DeviceExtension;
UNICODE_STRING DeviceName;
UNICODE_STRING SymlinkName;
NTSTATUS Status;
PDEVICE_OBJECT DeviceObject;
PCONFIGURATION_INFORMATION ConfigInfo;
/* Detect controller and determine type */
if (!FloppyGetControllerVersion(ControllerParameters, &ControllerType))
{
DPRINT("Failed to get controller version\n");
return FALSE;
}
LARGE_INTEGER Timeout;
BYTE Byte;
int c;
PCONFIGURATION_INFORMATION Config;
DEVICE_DESCRIPTION DeviceDescription;
ULONG MaxMapRegs;
/* FIXME: Register port ranges and interrupts with HAL */
@ -421,15 +69,18 @@ FloppyCreateController(PDRIVER_OBJECT DriverObject,
ControllerExtension->Number = Index;
ControllerExtension->PortBase = ControllerParameters->PortBase;
ControllerExtension->Vector = ControllerParameters->Vector;
ControllerExtension->FDCType = ControllerType;
KeInitializeEvent( &ControllerExtension->Event, SynchronizationEvent, FALSE );
ControllerExtension->Device = 0; // no active device
ControllerExtension->Irp = 0; // no active IRP
/* Initialize the spin lock in the controller extension */
KeInitializeSpinLock(&ControllerExtension->SpinLock);
ControllerExtension->IsrState = FloppyIsrDetect;
ControllerExtension->DpcState = FloppyDpcDetect;
/* Register an interrupt handler for this controller */
Status = IoConnectInterrupt(&ControllerExtension->Interrupt,
FloppyIsr,
ControllerExtension,
ControllerObject,
&ControllerExtension->SpinLock,
ControllerExtension->Vector,
ControllerParameters->IrqL,
@ -442,12 +93,26 @@ FloppyCreateController(PDRIVER_OBJECT DriverObject,
{
DPRINT("Could not Connect Interrupt %d\n",
ControllerExtension->Vector);
IoDeleteController(ControllerObject);
return FALSE;
goto controllercleanup;
}
/* FIXME: setup DMA stuff for controller */
/* setup DMA stuff for controller */
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = FALSE;
DeviceDescription.ScatterGather = FALSE;
DeviceDescription.AutoInitialize = FALSE;
DeviceDescription.Dma32BitAddress = FALSE;
DeviceDescription.DmaChannel = ControllerParameters->DmaChannel;
DeviceDescription.InterfaceType = Isa;
// DeviceDescription.DmaWidth = Width8Bits;
ControllerExtension->AdapterObject = HalGetAdapter( &DeviceDescription, &MaxMapRegs );
if( ControllerExtension->AdapterObject == NULL )
{
DPRINT1( "Could not get adapter object\n" );
goto interruptcleanup;
}
#if 0
/* Check for each possible drive and create devices for them */
for (DriveIdx = 0; DriveIdx < FLOPPY_MAX_DRIVES; DriveIdx++)
@ -468,40 +133,292 @@ FloppyCreateController(PDRIVER_OBJECT DriverObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
IoDisconnectInterrupt(ControllerExtension->Interrupt);
IoDeleteController(ControllerObject);
goto interruptcleanup;
}
DeviceExtension = (PFLOPPY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceExtension->DriveSelect = 0;
DeviceExtension->Controller = ControllerObject;
DeviceExtension->MediaType = ~0;
ControllerExtension->MotorOn = ~0;
// set up DPC
ControllerExtension->Device = DeviceObject;
KeInitializeDpc( &ControllerExtension->MotorSpinupDpc,
FloppyMotorSpinupDpc,
ControllerObject );
KeInitializeDpc( &ControllerExtension->MotorSpindownDpc,
FloppyMotorSpindownDpc,
ControllerObject );
KeInitializeTimer( &ControllerExtension->SpinupTimer );
IoInitializeDpcRequest( DeviceObject, FloppyDpc );
// reset controller and wait for interrupt
DPRINT( "Controller Off\n" );
FloppyWriteDOR( ControllerExtension->PortBase, 0 );
// let controller reset for at least FLOPPY_RESET_TIME
KeStallExecutionProcessor( FLOPPY_RESET_TIME );
DPRINT( "Controller On\n" );
FloppyWriteDOR( ControllerExtension->PortBase, FLOPPY_DOR_ENABLE | FLOPPY_DOR_DMA );
// wait for interrupt now
Timeout.QuadPart = -10000000;
Status = KeWaitForSingleObject( &ControllerExtension->Event,
Executive,
KernelMode,
FALSE,
&Timeout );
if( Status != STATUS_WAIT_0 )
{
DPRINT1( "Error: KeWaitForSingleObject returned: %x\n", Status );
goto devicecleanup;
}
// ok, so we have an FDC, now check for drives
// aparently the sense drive status command does not work on any FDC I can find
// so instead we will just have to assume a 1.44 meg 3.5 inch floppy. At some
// point we should get the bios disk parameters passed in to the kernel at boot
// and stored in the HARDWARE registry key for us to pick up here.
// turn on motor, wait for spinup time, and recalibrate the drive
FloppyWriteDOR( ControllerExtension->PortBase, FLOPPY_DRIVE0_ON );
Timeout.QuadPart = FLOPPY_MOTOR_SPINUP_TIME;
KeDelayExecutionThread( KernelMode, FALSE, &Timeout );
DPRINT( "MSTAT: %2x\n", FloppyReadMSTAT( ControllerExtension->PortBase ) );
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_RECAL );
DPRINT( "MSTAT: %2x\n", FloppyReadMSTAT( ControllerExtension->PortBase ) );
FloppyWriteDATA( ControllerExtension->PortBase, 0 ); // drive select
Timeout.QuadPart = FLOPPY_RECAL_TIMEOUT;
Status = KeWaitForSingleObject( &ControllerExtension->Event,
Executive,
KernelMode,
FALSE,
&Timeout );
if( Status != STATUS_WAIT_0 )
{
DPRINT1( "Error: KeWaitForSingleObject returned: %x\n", Status );
goto devicecleanup;
}
if( ControllerExtension->St0 != FLOPPY_ST0_SEEKGD )
{
DbgPrint( "Floppy: error recalibrating drive, ST0: %2x\n", (DWORD)ControllerExtension->St0 );
goto interruptcleanup;
}
// drive is good, and it is now on track 0, turn off the motor
FloppyWriteDOR( ControllerExtension->PortBase, FLOPPY_DOR_ENABLE | FLOPPY_DOR_DMA );
/* Initialize the device */
DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
/* count new floppy drive */
/* NOTE: HalIoAssignDriveLetters assigns the drive letters! */
ConfigInfo = IoGetConfigurationInformation ();
ConfigInfo->FloppyCount++;
DeviceObject->AlignmentRequirement = FILE_512_BYTE_ALIGNMENT;
// change state machine, no interrupt expected
ControllerExtension->IsrState = FloppyIsrUnexpected;
Config = IoGetConfigurationInformation();
Config->FloppyCount++;
// call IoAllocateAdapterChannel, and wait for execution routine to be given the channel
CHECKPOINT;
Status = IoAllocateAdapterChannel( ControllerExtension->AdapterObject,
DeviceObject,
0x3000/PAGESIZE, // max track size is 12k
FloppyAdapterControl,
ControllerExtension );
if( !NT_SUCCESS( Status ) )
{
DPRINT1( "Error: IoAllocateAdapterChannel returned %x\n", Status );
goto interruptcleanup;
}
CHECKPOINT;
Status = KeWaitForSingleObject( &ControllerExtension->Event,
Executive,
KernelMode,
FALSE,
&Timeout );
CHECKPOINT;
if( Status != STATUS_WAIT_0 )
{
DPRINT1( "Error: KeWaitForSingleObject returned: %x\n", Status );
goto interruptcleanup;
}
// Ok, we own the adapter object, from now on we can just IoMapTransfer, and not
// bother releasing the adapter ever.
DbgPrint( "Floppy drive initialized\n" );
return TRUE;
devicecleanup:
IoDeleteDevice( DeviceObject );
interruptcleanup:
IoDisconnectInterrupt(ControllerExtension->Interrupt);
controllercleanup:
// turn off controller
FloppyWriteDOR( ControllerExtension->PortBase, 0 );
IoDeleteController(ControllerObject);
for(;;);
return FALSE;
}
VOID STDCALL FloppyStartIo(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
IO_ALLOCATION_ACTION FloppyExecuteSpindown( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterbase,
PVOID Context )
{
DPRINT("FloppyStartIo\n");
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension= (PFLOPPY_CONTROLLER_EXTENSION)Context;
// turn off motor, and return
DPRINT( "Spinning down motor\n" );
ControllerExtension->MotorOn = ~0;
FloppyWriteDOR( ControllerExtension->PortBase,
FLOPPY_DOR_ENABLE | FLOPPY_DOR_DMA );
return DeallocateObject;
}
IO_ALLOCATION_ACTION FloppyExecuteReadWrite( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterbase,
PVOID Context )
{
PFLOPPY_DEVICE_EXTENSION DeviceExtension = (PFLOPPY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)DeviceExtension->Controller->ControllerExtension;
LARGE_INTEGER Timeout;
BOOLEAN WriteToDevice;
UCHAR Cyl, Sector, Head;
ControllerExtension->Irp = Irp = (PIRP)Context;
ControllerExtension->Device = DeviceObject;
Timeout.QuadPart = FLOPPY_MOTOR_SPINUP_TIME;
CHECKPOINT;
WriteToDevice = IoGetCurrentIrpStackLocation( Irp )->MajorFunction == IRP_MJ_WRITE ? TRUE : FALSE;
// verify drive is spun up and selected
if( ControllerExtension->MotorOn != DeviceExtension->DriveSelect )
{
// turn on and select drive, and allow it to spin up
// FloppyMotorSpinupDpc will restart this operation once motor is spun up
DPRINT( "Motor not on, turning it on now\n" );
FloppyWriteDOR( ControllerExtension->PortBase,
DeviceExtension->DriveSelect ? FLOPPY_DRIVE1_ON : FLOPPY_DRIVE0_ON );
// cancel possible spindown timer first
KeCancelTimer( &ControllerExtension->SpinupTimer );
KeSetTimerEx( &ControllerExtension->SpinupTimer,
Timeout,
0,
&ControllerExtension->MotorSpinupDpc );
return KeepObject;
}
// verify media content
if( FloppyReadDIR( ControllerExtension->PortBase ) & FLOPPY_DI_DSKCHNG )
{
// No disk is in the drive
DPRINT( "No disk is in the drive\n" );
Irp->IoStatus.Status = STATUS_NO_MEDIA;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, 0 );
return DeallocateObject;
}
if( DeviceExtension->MediaType == ~0 )
{
// media is in disk, but we have not yet detected what kind it is,
// so detect it now
// First, we need to recalibrate the drive though
ControllerExtension->IsrState = FloppyIsrRecal;
DPRINT( "Recalibrating drive\n" );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_RECAL );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, DeviceExtension->DriveSelect );
return KeepObject;
}
// looks like we have media in the drive.... do the read
// first, calculate geometry for read
Sector = ControllerExtension->CurrentOffset / MediaTypes[DeviceExtension->MediaType].BytesPerSector;
// absolute sector right now
Cyl = Sector / MediaTypes[DeviceExtension->MediaType].SectorsPerTrack;
Head = Cyl % MediaTypes[DeviceExtension->MediaType].Heads;
// convert absolute cyl to relative
Cyl /= MediaTypes[DeviceExtension->MediaType].Heads;
// convert absolute sector to relative
Sector %= MediaTypes[DeviceExtension->MediaType].SectorsPerTrack;
Sector++; // track relative sector numbers are 1 based, not 0 based
DPRINT( "Cyl = %2x, Head = %2x, Sector = %2x\n", Cyl, Head, Sector );
//set up DMA and issue read command
IoMapTransfer( ControllerExtension->AdapterObject,
Irp->MdlAddress,
ControllerExtension->MapRegisterBase,
ControllerExtension->CurrentVa,
&MediaTypes[DeviceExtension->MediaType].BytesPerSector,
WriteToDevice );
ControllerExtension->IsrState = FloppyIsrReadWrite;
ControllerExtension->DpcState = FloppyDpcReadWrite;
CHECKPOINT;
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_READ );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, ( Head << 2 ) | DeviceExtension->DriveSelect );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, Cyl );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, Head );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, Sector );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, MediaTypes[DeviceExtension->MediaType].SectorSizeCode );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, MediaTypes[DeviceExtension->MediaType].SectorsPerTrack );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, 0 );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, 0xFF );
CHECKPOINT;
// eventually, the FDC will interrupt and we will read results then
return KeepObject;
}
NTSTATUS STDCALL FloppyDispatchOpenClose(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
DPRINT("FloppyDispatchOpenClose\n");
return(STATUS_UNSUCCESSFUL);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL FloppyDispatchReadWrite(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
DPRINT("FloppyDispatchReadWrite\n");
return(STATUS_UNSUCCESSFUL);
PFLOPPY_DEVICE_EXTENSION DeviceExtension = (PFLOPPY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)DeviceExtension->Controller->ControllerExtension;
PIO_STACK_LOCATION Stk = IoGetCurrentIrpStackLocation( Irp );
KIRQL oldlvl;
if( Stk->Parameters.Read.ByteOffset.u.HighPart )
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, 1 );
return STATUS_INVALID_PARAMETER;
}
ControllerExtension->CurrentOffset = Stk->Parameters.Read.ByteOffset.u.LowPart;
ControllerExtension->CurrentLength = Stk->Parameters.Read.Length;
ControllerExtension->CurrentVa = MmGetMdlVirtualAddress( Irp->MdlAddress );
DPRINT( "FloppyDispatchReadWrite: offset = %x, length = %x, va = %x\n",
ControllerExtension->CurrentOffset,
ControllerExtension->CurrentLength,
ControllerExtension->CurrentVa );
// Queue IRP
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = ControllerExtension->CurrentLength;
IoMarkIrpPending( Irp );
KeRaiseIrql( DISPATCH_LEVEL, &oldlvl );
IoAllocateController( ((PFLOPPY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Controller,
DeviceObject,
FloppyExecuteReadWrite,
Irp );
KeLowerIrql( oldlvl );
return STATUS_PENDING;
}
IO_ALLOCATION_ACTION FloppyAdapterControl( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterBase,
PVOID Context )
{
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Context;
// just set the event, and return KeepObject
CHECKPOINT;
ControllerExtension->MapRegisterBase = MapRegisterBase;
KeSetEvent( &ControllerExtension->Event, 0, FALSE );
return KeepObject;
}
NTSTATUS STDCALL FloppyDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
@ -536,7 +453,6 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject,
DbgPrint("Floppy driver\n");
/* Export other driver entry points... */
DriverObject->DriverStartIo = FloppyStartIo;
DriverObject->MajorFunction[IRP_MJ_CREATE] = FloppyDispatchOpenClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FloppyDispatchOpenClose;
DriverObject->MajorFunction[IRP_MJ_READ] = FloppyDispatchReadWrite;

View file

@ -1,12 +1,14 @@
#define FLOPPY_MAX_STAT_RETRIES 10000
#define FLOPPY_NEEDS_OUTPUT -2
//
// Floppy register definitions
//
#define FLOPPY_REG_DOR 0x0002
#define FLOPPY_DOR_ENABLE 0x04
#define FLOPPY_DOR_DMA 0x08
#define FLOPPY_DOR_MOTOR0 0x10
#define FLOPPY_DOR_MOTOR1 0x20
#define FLOPPY_DRIVE0_ON ( FLOPPY_DOR_ENABLE | FLOPPY_DOR_DMA | FLOPPY_DOR_MOTOR0 )
#define FLOPPY_DRIVE1_ON ( FLOPPY_DOR_ENABLE | FLOPPY_DOR_DMA | FLOPPY_DOR_MOTOR1 | 1 )
#define FLOPPY_REG_MSTAT 0x0004
#define FLOPPY_MS_DRV0BUSY 0x01
#define FLOPPY_MS_DRV1BUSY 0x02
@ -15,7 +17,9 @@
#define FLOPPY_MS_FDCBUSY 0x10
#define FLOPPY_MS_DMAMODE 0x20
#define FLOPPY_MS_DATADIR 0x40
#define FLOPPY_MS_DATARDY 0x80
#define FLOPPY_MS_RDYMASK 0xF0
#define FLOPPY_MS_DATARDYW 0x80
#define FLOPPY_MS_DATARDYR 0xC0
#define FLOPPY_REG_DATA 0x0005
#define FLOPPY_REG_DIR 0x0007 /* READ ONLY */
#define FLOPPY_DI_DSKCHNG 0x80
@ -32,10 +36,8 @@
#define FLOPPY_CMD_RD_DATA 0x06
#define FLOPPY_CMD_RECAL 0x07
#define FLOPPY_CMD_SNS_INTR 0x08
#define FLOPPY_CSI_IC_MASK 0xe0
#define FLOPPY_CSI_IC_RDYCH 0x60
#define FLOPPY_CSI_IC_SEEKGD 0x80
#define FLOPPY_CSI_IC_SEEKBD 0xc0
#define FLOPPY_ST0_SEEKGD 0x20
#define FLOPPY_ST0_GDMASK 0xd8
#define FLOPPY_CMD_WRT_DEL 0x09
#define FLOPPY_CMD_RD_ID 0x0a
#define FLOPPY_CMD_RD_DEL 0x0c
@ -80,32 +82,12 @@
//
// HAL floppy register access commands
//
#define FloppyWriteDOR(A, V) (WRITE_BYTE((A) + FLOPPY_REG_DOR, (V)))
#define FloppyReadMSTAT(A) (READ_BYTE((A) + FLOPPY_REG_MSTAT))
#define FloppyReadDATA(A) (READ_BYTE((A) + FLOPPY_REG_DATA))
#define FloppyWriteDATA(A, V) (WRITE_BYTE((A) + FLOPPY_REG_DATA, (V)))
#define FloppyReadDIR(A) (READ_BYTE((A) + FLOPPY_REG_DIR))
#define FloppyWriteCCNTL(A, V) (WRITE_BYTE((A) + FLOPPY_REG_CCNTL, (V)))
//
// Known Floppy controller types
//
typedef enum _FLOPPY_CONTROLLER_TYPE
{
FDC_NONE,
FDC_UNKNOWN,
FDC_8272A, /* Intel 8272a, NEC 765 */
FDC_765ED, /* Non-Intel 1MB-compatible FDC, can't detect */
FDC_82072, /* Intel 82072; 8272a + FIFO + DUMPREGS */
FDC_82072A, /* 82072A (on Sparcs) */
FDC_82077_ORIG, /* Original version of 82077AA, sans LOCK */
FDC_82077, /* 82077AA-1 */
FDC_82078_UNKN, /* Unknown 82078 variant */
FDC_82078, /* 44pin 82078 or 64pin 82078SL */
FDC_82078_1, /* 82078-1 (2Mbps fdc) */
FDC_S82078B, /* S82078B (first seen on Adaptec AVA-2825 VLB SCSI/EIDE/Floppy controller) */
FDC_87306 /* National Semiconductor PC 87306 */
} FLOPPY_CONTROLLER_TYPE, *PFLOPPY_CONTROLLER_TYPE;
#define FloppyWriteDOR(A, V) (WRITE_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_DOR, (V)))
#define FloppyReadMSTAT(A) (READ_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_MSTAT))
#define FloppyReadDATA(A) (READ_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_DATA))
#define FloppyWriteDATA(A, V) (WRITE_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_DATA, (V)))
#define FloppyReadDIR(A) (READ_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_DIR))
#define FloppyWriteCCNTL(A, V) (WRITE_PORT_UCHAR((PVOID)(A) + FLOPPY_REG_CCNTL, (V)))
typedef struct _FLOPPY_ERROR_THRESHOLDS
{
@ -125,34 +107,134 @@ typedef struct _FLOPPY_ERROR_THRESHOLDS
unsigned int Reporting;
} FLOPPY_ERROR_THRESHOLDS;
typedef struct _FLOPPY_MEDIA_TYPE
{
BYTE SectorSizeCode;
BYTE MaximumTrack;
BYTE Heads;
DWORD SectorsPerTrack;
ULONG BytesPerSector;
} FLOPPY_MEDIA_TYPE;
#define FDP_DEBUG 0x02
#define FDP_SILENT_DCL_CLEAR 0x04
#define FDP_MSG 0x10
#define FDP_BROKEN_DCL 0x20
#define FDP_INVERTED_DCL 0x80
typedef struct _FLOPPY_DEVICE_PARAMETERS
// time to hold reset line low
#define FLOPPY_RESET_TIME 1000
#define FLOPPY_MOTOR_SPINUP_TIME -10000000
#define FLOPPY_MOTOR_SPINDOWN_TIME -30000000
#define FLOPPY_RECAL_TIMEOUT -5000000
typedef BOOLEAN (*FloppyIsrStateRoutine)( PCONTROLLER_OBJECT Controller );
typedef PIO_DPC_ROUTINE FloppyDpcStateRoutine;
typedef struct _FLOPPY_DEVICE_EXTENSION
{
char CMOSType;
unsigned long MaxDTR; /* Step rate, usec */
unsigned long HLT; /* Head load/settle time, msec */
unsigned long HUT; /* Head unload time (remnant of 8" drives) */
unsigned long SRT; /* Step rate, usec */
unsigned long Spinup; /* time needed for spinup */
unsigned long Spindown; /* timeout needed for spindown */
unsigned char SpindownOffset; /* decides in which position the disk will stop */
unsigned char SelectDelay; /* delay to wait after select */
unsigned char RPS; /* rotations per second */
unsigned char Tracks; /* maximum number of tracks */
unsigned long Timeout; /* timeout for interrupt requests */
unsigned char InterleaveSect; /* if there are more sectors, use interleave */
FLOPPY_ERROR_THRESHOLDS MaxErrors;
char Flags; /* various flags, including ftd_msg */
BOOLEAN ReadTrack; /* use readtrack during probing? */
short Autodetect[8]; /* autodetected formats */
int CheckFreq; /* how often should the drive be checked for disk changes */
int NativeFormat; /* native format of this drive */
char *DriveName; /* name of the drive for reporting */
} FLOPPY_DEVICE_PARAMETERS, *PFLOPPY_DEVICE_PARAMETERS;
PCONTROLLER_OBJECT Controller;
CHAR DriveSelect;
ULONG MediaType; // Media type index
} FLOPPY_DEVICE_EXTENSION, *PFLOPPY_DEVICE_EXTENSION;
typedef struct _FLOPPY_CONTROLLER_EXTENSION
{
PKINTERRUPT Interrupt;
KSPIN_LOCK SpinLock;
ULONG Number;
ULONG PortBase;
ULONG Vector;
KEVENT Event; // Event set by ISR/DPC to wake DeviceEntry
PDEVICE_OBJECT Device; // Pointer to the primary device on this controller
PIRP Irp; // Current IRP
CHAR St0; // Status registers
CHAR St1;
CHAR St2;
CHAR SectorSizeCode;
FloppyIsrStateRoutine IsrState; // pointer to state routine handler for ISR
FloppyDpcStateRoutine DpcState; // pointer to state routine handler for DPC
CHAR MotorOn; // drive select for drive with motor on
KDPC MotorSpinupDpc; // DPC for motor spin up time
KTIMER SpinupTimer; // Timer for motor spin up time
KDPC MotorSpindownDpc; // DPC for motor spin down
PADAPTER_OBJECT AdapterObject; // Adapter object for dma
PVOID MapRegisterBase;
DWORD CurrentOffset;
DWORD CurrentLength; // offset and length of next operation
PVOID CurrentVa; // current VA offset for IoMapTransfer
} FLOPPY_CONTROLLER_EXTENSION, *PFLOPPY_CONTROLLER_EXTENSION;
typedef struct _FLOPPY_CONTROLLER_PARAMETERS
{
ULONG PortBase;
ULONG Vector;
ULONG IrqL;
ULONG DmaChannel;
ULONG SynchronizeIrqL;
KINTERRUPT_MODE InterruptMode;
KAFFINITY Affinity;
} FLOPPY_CONTROLLER_PARAMETERS, *PFLOPPY_CONTROLLER_PARAMETERS;
#define FLOPPY_MAX_CONTROLLERS 1
VOID FloppyDpcDetectMedia( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
VOID FloppyDpcFailIrp( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
IO_ALLOCATION_ACTION FloppyExecuteReadWrite( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterbase,
PVOID Context );
IO_ALLOCATION_ACTION FloppyExecuteSpindown( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterbase,
PVOID Context );
VOID FloppyMotorSpinupDpc( PKDPC Dpc,
PVOID Context,
PVOID Arg1,
PVOID Arg2 );
VOID FloppyMotorSpindownDpc( PKDPC Dpc,
PVOID Context,
PVOID Arg1,
PVOID Arg2 );
VOID FloppyDpcDetect( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
VOID FloppyDpcReadWrite( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
VOID FloppyDpc( PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
BOOLEAN FloppyIsrDetect( PCONTROLLER_OBJECT Controller );
BOOLEAN FloppyIsrReadWrite( PCONTROLLER_OBJECT Controller );
BOOLEAN FloppyIsrUnexpected( PCONTROLLER_OBJECT Controller );
BOOLEAN FloppyIsrDetectMedia( PCONTROLLER_OBJECT Controller );
BOOLEAN FloppyIsrRecal( PCONTROLLER_OBJECT Controller );
BOOLEAN FloppyIsr(PKINTERRUPT Interrupt, PVOID ServiceContext);
IO_ALLOCATION_ACTION FloppyAdapterControl( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID MapRegisterBase,
PVOID Context );

View file

@ -0,0 +1,150 @@
/************************************************************************
* Interrupt handlers for floppy disk driver, reactos project, created *
* by Phillip Susi on 2/25/2001. This software is publised under the *
* GNU General public license. See the README file for more details *
***********************************************************************/
#include <ddk/ntddk.h>
#include <debug.h>
#include "floppy.h"
// ISR state machine function called when expecting an interrupt due to reset
// During reset, there is nothing ready to read, just issue sense interrupt status
BOOLEAN FloppyIsrDetect( PCONTROLLER_OBJECT Controller )
{
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
// Issue read interrupt status, and store the results
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_SNS_INTR );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St0 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // ignore cyl
// now queue DPC to set the event
IoRequestDpc( ControllerExtension->Device,
0,
Controller );
return TRUE;
}
// ISR state machine handler for unexpected interrupt
BOOLEAN FloppyIsrUnexpected( PCONTROLLER_OBJECT Controller )
{
DPRINT( "Unexpected interrupt!\n" );
return FALSE;
}
BOOLEAN FloppyIsrDetectMedia( PCONTROLLER_OBJECT Controller )
{
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
BYTE SectorSize;
// media detect in progress, read ID command already issued
// first, read result registers
KeStallExecutionProcessor( 1000 );
ControllerExtension->St0 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St1 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St2 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // ignore cyl
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // ignore head
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // ignore sector
KeStallExecutionProcessor( 1000 );
SectorSize = FloppyReadDATA( ControllerExtension->PortBase );
DPRINT( "Sector Size Code: %2x\n", SectorSize );
DPRINT( "St0 = %2x, St1 = %2x, St2 = %2x\n", ControllerExtension->St0, ControllerExtension->St1, ControllerExtension->St2 );
DPRINT( "ControllerExtension->Device = %x, ControllerExtension->Irp = %x\n", ControllerExtension->Device, ControllerExtension->Irp );
// queue DPC
ControllerExtension->DpcState = FloppyDpcDetectMedia;
IoRequestDpc( ControllerExtension->Device,
ControllerExtension->Irp,
Controller );
return TRUE;
}
BOOLEAN FloppyIsrRecal( PCONTROLLER_OBJECT Controller )
{
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
// issue sense interrupt status, and read St0 and cyl
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_SNS_INTR );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St0 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // ignore cyl number
DPRINT( "Recal St0: %2x\n", ControllerExtension->St0 );
// If recalibrate worked, issue read ID for each media type untill one works
if( ControllerExtension->St0 != FLOPPY_ST0_SEEKGD )
{
DPRINT( "Recalibrate failed, ST0 = %2x\n", ControllerExtension->St0 );
// queue DPC to fail IRP
ControllerExtension->DpcState = FloppyDpcFailIrp;
IoRequestDpc( ControllerExtension->Device,
ControllerExtension->Irp,
Controller );
}
else {
// issue first read id, FloppyIsrDetectMedia will handle
DPRINT( "Recalibrate worked, issuing read ID mark command\n" );
ControllerExtension->IsrState = FloppyIsrDetectMedia;
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, FLOPPY_CMD_RD_ID | FLOPPY_C0M_MFM );
KeStallExecutionProcessor( 1000 );
FloppyWriteDATA( ControllerExtension->PortBase, ((PFLOPPY_DEVICE_EXTENSION)ControllerExtension->Device->DeviceExtension)->DriveSelect );
}
return TRUE;
}
BOOLEAN FloppyIsrReadWrite( PCONTROLLER_OBJECT Controller )
{
// read result registers from read or write command, and queue dpc to start next operation
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
CHECKPOINT1;
ControllerExtension->St0 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St1 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
ControllerExtension->St2 = FloppyReadDATA( ControllerExtension->PortBase );
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // cyl
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // head
KeStallExecutionProcessor( 1000 );
FloppyReadDATA( ControllerExtension->PortBase ); // sector
KeStallExecutionProcessor( 1000 );
ControllerExtension->SectorSizeCode = FloppyReadDATA( ControllerExtension->PortBase );
CHECKPOINT1;
IoRequestDpc( ControllerExtension->Device,
ControllerExtension->Irp,
Controller );
return TRUE;
}
// actual ISR, passes controll to handler for current state in state machine
BOOLEAN FloppyIsr(PKINTERRUPT Interrupt, PVOID ServiceContext)
{
PCONTROLLER_OBJECT Controller = (PCONTROLLER_OBJECT)ServiceContext;
PFLOPPY_CONTROLLER_EXTENSION ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION)Controller->ControllerExtension;
BYTE Byte;
// need to make sure interrupt is for us, and add some delay for the damn FDC
// without the delay, even though the thing has interrupted, it's still not ready
// for us to read the data register.
Byte = FloppyReadMSTAT( ControllerExtension->PortBase );
if( Byte == 0 )
{
DPRINT( "Ignoring interrupt, MSTAT = 0\n" );
return TRUE;
}
return ControllerExtension->IsrState( Controller );
}