diff --git a/reactos/drivers/dd/floppy/Makefile b/reactos/drivers/dd/floppy/Makefile index ce3b50f86a0..77e78804b85 100644 --- a/reactos/drivers/dd/floppy/Makefile +++ b/reactos/drivers/dd/floppy/Makefile @@ -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 diff --git a/reactos/drivers/dd/floppy/dpc.c b/reactos/drivers/dd/floppy/dpc.c new file mode 100644 index 00000000000..7c4eabfc0c9 --- /dev/null +++ b/reactos/drivers/dd/floppy/dpc.c @@ -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 +#include +#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 ); +} diff --git a/reactos/drivers/dd/floppy/floppy.c b/reactos/drivers/dd/floppy/floppy.c index 6a58d5bfda4..c3d98ac454e 100644 --- a/reactos/drivers/dd/floppy/floppy.c +++ b/reactos/drivers/dd/floppy/floppy.c @@ -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 -#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; diff --git a/reactos/drivers/dd/floppy/floppy.h b/reactos/drivers/dd/floppy/floppy.h index 2dea2c85088..2f1fada6ac1 100644 --- a/reactos/drivers/dd/floppy/floppy.h +++ b/reactos/drivers/dd/floppy/floppy.h @@ -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 ); diff --git a/reactos/drivers/dd/floppy/isr.c b/reactos/drivers/dd/floppy/isr.c new file mode 100644 index 00000000000..0842c6e1036 --- /dev/null +++ b/reactos/drivers/dd/floppy/isr.c @@ -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 +#include +#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 ); +} + +