diff --git a/reactos/drivers/dd/floppy/floppy.c b/reactos/drivers/dd/floppy/floppy.c index c625d1d316c..ce6016bdabe 100644 --- a/reactos/drivers/dd/floppy/floppy.c +++ b/reactos/drivers/dd/floppy/floppy.c @@ -7,15 +7,56 @@ // Modification History: // 08/19/98 RJJ Created. // - +// To do: +// FIXME: get it working +// FIXME: add support for DMA hardware +// FIXME: should add support for floppy tape/zip devices #include + #include "floppy.h" #define VERSION "V0.0.1" // --------------------------------------------------- File Statics +typedef struct _FLOPPY_CONTROLLER_PARAMETERS +{ + int PortBase; + int Vector; + int IrqL; + int 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}, +}; + +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"} +}; + +static BOOLEAN FloppyInitialized = FALSE; + // ------------------------------------------------------ Functions // ModuleEntry @@ -37,14 +78,14 @@ // RETURNS: // NTSTATUS -NTSTATUS ModuleEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) { +NTSTATUS +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ NTSTATUS RC; PFLOPPY_DEVICE_EXTENSION DeviceExtension; - // Export other driver entry points... + // Export other driver entry points... DriverObject->DriverStartIo = FloppyStartIo; DriverObject->MajorFunction[IRP_MJ_CREATE] = FloppyDispatchOpenClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = FloppyDispatchOpenClose; @@ -52,43 +93,82 @@ NTSTATUS ModuleEntry( DriverObject->MajorFunction[IRP_MJ_WRITE] = FloppyDispatchReadWrite; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FloppyDispatchDeviceControl; - // FIXME: Try to detect floppy and abort if it fails + // Try to detect controller and abort if it fails + if (!FloppyCreateController(DriverObject, + &ControllerParameters[0], + 0)) + { + DPRINT("Could not find floppy controller"); + return STATUS_NO_SUCH_DEVICE; + } - // Create a device object for the floppy - RC = IoCreateDevice(DriverObject, - sizeof(FLOPPY_DEVICE_EXTENSION), - DeviceName, - FILE_DEVICE_DISK, - 0, - TRUE, - &DeviceObject); - if (!NT_SUCCESS(RC)) { - DPRINT("Could not create device for floppy"); - return STATUS_NO_SUCH_DEVICE; - } + return STATUS_SUCCESS; +} - // Fill out Device Extension - DeviceExtension = (PFLOPPY_DEVICE_EXTENSION) - DeviceObject->DeviceExtension; - DeviceExtension->Number = 0; - DeviceExtension->PortBase = FLOPPY_PORT_BASE; - DeviceExtension->Vector = FLOPPY_IRQ_VECTOR; - DeviceExtension->IrqL = FLOPPY_DIRQL; - DeviceExtension->DMASupported = FALSE; - DeviceExtension->FloppyState = FloppyStateIdle; +static BOOLEAN +FloppyCreateController(PDRIVER_OBJECT DriverObject, + PFLOPPY_CONTROLLER_PARAMETERS ControllerParameters, + int Index) +{ + PFLOPPY_CONTROLLER_TYPE ControllerType; + PCONTROLLER_OBJECT ControllerObject; + PFLOPPY_CONTROLLER_EXTENSION ControllerExtension; - // Register an interrupt handler for this device - RC = IoConnectInterrupt(&DeviceExtension->Interrupt, - FloppyIsr, DeviceExtension, NULL, - DeviceExtension->Vector, DeviceExtension->IrqL, - DeviceExtension->IrqL, FLOPPY_IRQ_MODE, - FALSE, FLOPPY_AFFINITY, FALSE); - if (!NT_SUCCESS(RC)) { - DPRINT("Could not Connect Interrupt %d\n", DeviceExtension->Vector); - return STATUS_NO_SUCH_DEVICE; - } + /* Detect controller and determine type */ + if (!FloppyGetControllerVersion(ControllerParameters, &ControllerType)) + { + return FALSE; + } - // FIXME: register a DMA handler if needed for this controller + // FIXME: Register port ranges and interrupts with HAL + + /* Create controller object for FDC */ + ControllerObject = IoCreateController(sizeof(FLOPPY_CONTROLLER_EXTENSION)); + if (ControllerObject == NULL) + { + DPRINT("Could not create controller object for controller %d\n", + Index); + return FALSE; + } + + // FIXME: fill out controller data + ControllerExtension = (PFLOPPY_CONTROLLER_EXTENSION) + ControllerObject->ControllerExtension; + ControllerExtension->Number = Index; + ControllerExtension->PortBase = ControllerParameters->PortBase; + ControllerExtension->Vector = ControllerParameters->Vector; + ControllerExtension->FDCType = ControllerType; + + /* Initialize the spin lock in the controller extension */ + KeInitializeSpinLock(&ControllerExtension->SpinLock); + + /* Register an interrupt handler for this controller */ + RC = IoConnectInterrupt(&ControllerExtension->Interrupt, + FloppyIsr, + ControllerExtension, + &ControllerExtension->SpinLock, + ControllerExtension->Vector, + ControllerParameters->IrqL, + ControllerParameters->SynchronizeIrqL, + ControllerParameters->InterruptMode, + FALSE, + ControllerParameters->Affinity, + FALSE); + if (!NT_SUCCESS(RC)) + { + DPRINT("Could not Connect Interrupt %d\n", ControllerExtension->Vector); + IoDeleteController(ControllerObject); + return FALSE; + } + + // FIXME: setup DMA stuff for controller + + // Check for each possible drive and create devices for them + for (DriveIdx = 0; DriveIdx < FLOPPY_MAX_DRIVES; DriveIdx++) + { + // FIXME: try to identify the drive + // FIXME: create a device if it's there + } return STATUS_SUCCESS; } @@ -110,109 +190,255 @@ NTSTATUS ModuleEntry( // COMMENTS: // This routine (get_fdc_version) was originally written by David C. Niemi // -static BOOLEAN FloppyGetControllerVersion( - IN OUT PFLOPPY_DEVICE_EXTENSION DeviceExtension - ) { - int Result; - FLOPPY_CMD CommandToSend; - FLOPPY_RESULT ResultReturned +static BOOLEAN +FloppyGetControllerVersion(IN PFLOPPY_CONTROLLER_PARAMETERS ControllerParameters, + OUT PFLOPPY_CONTROLLER_TYPE ControllerType) +{ + BYTE ResultReturned + BYTE Result[FLOPPY_MAX_REPLIES]; + int ResultLength; - CommandToSend.CMd[0] = FLOPPY_CMD_FD_DUMPREGS; - FloppyWriteCommand(DeviceExtension->PortBase, &CommandToSend, &ResultReturned); + /* 82072 and better know DUMPREGS */ + if (!FloppyWriteCommandByte(ControllerParameters->PortBase, + FLOPPY_CMD_DUMP_FDC)) + { + return FALSE; + } + ResultLength = FloppyReadResultCode(PortBase, &Result)); + if (ResultLength < 0) + { + return FALSE; + } - /* 82072 and better know DUMPREGS */ - if (FDCS->reset) - return FDC_NONE; - if ((r = result()) <= 0x00) - return FDC_NONE; /* No FDC present ??? */ - if ((r==1) && (reply_buffer[0] == 0x80)){ - printk(KERN_INFO "FDC %d is an 8272A\n",fdc); - return FDC_8272A; /* 8272a/765 don't know DUMPREGS */ - } - if (r != 10) { - printk("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } + /* 8272a/765 don't know DUMPREGS */ + if ((ResultLength == 1) && (Result[0] == 0x80)) + { + DPRINT("FDC %d is an 8272A\n", PortBase); + *ControllerType = FDC_8272A; + return TRUE; + } + if (r != 10) + { + DPRINT("FDC %d init: DUMP_FDC: unexpected return of %d bytes.\n", + PortBase, + ResultLength); + return FALSE; + } - if(!fdc_configure()) { - printk(KERN_INFO "FDC %d is an 82072\n",fdc); - return FDC_82072; /* 82072 doesn't know CONFIGURE */ - } + if (!FloppyConfigure(PortBase, FALSE, 0x0a)) + { + DPRINT("FDC %d is an 82072\n", PortBase); + *ControllerType = FDC_82072; + return TRUE; + } + FloppyWriteCommandByte(PortBase, FLOPPY_CMD_PPND_RW); + if (FloppyNeedsMoreOutput(PortBase, Result) == FLOPPY_NEEDS_OUTPUT) + { + FloppyWriteCommandByte(PortBase, 0); + } + else + { + DPRINT("FDC %d is an 82072A\n", PortBase); + *ControllerType = FDC_82072A; + return TRUE; + } - output_byte(FD_PERPENDICULAR); - if(need_more_output() == MORE_OUTPUT) { - output_byte(0); - } else { - printk(KERN_INFO "FDC %d is an 82072A\n", fdc); - return FDC_82072A; /* 82072A as found on Sparcs. */ - } + /* Pre-1991 82077, doesn't know LOCK/UNLOCK */ + FloppyWriteCommandByte(PortBase, FLOPPY_CMD_UNLK_FIFO); + ResultLength = FloppyReadResultCode(PortBase, &Result)); + if ((ResultLength == 1) && (Result[0] == 0x80)) + { + DPRINT("FDC %d is a pre-1991 82077\n", PortBase); + *ControllerType = FDC_82077_ORIG; + return TRUE; + } + if ((ResultLength != 1) || (Result[0] != 0x00)) + { + DPRINT("FDC %d init: UNLOCK: unexpected return of %d bytes.\n", + PortBase, + ResultLength); + return FALSE; + } - output_byte(FD_UNLOCK); - r = result(); - if ((r == 1) && (reply_buffer[0] == 0x80)){ - printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc); - return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know - * LOCK/UNLOCK */ - } - if ((r != 1) || (reply_buffer[0] != 0x00)) { - printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - output_byte(FD_PARTID); - r = result(); - if (r != 1) { - printk("FDC %d init: PARTID: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - if (reply_buffer[0] == 0x80) { - printk(KERN_INFO "FDC %d is a post-1991 82077\n",fdc); - return FDC_82077; /* Revised 82077AA passes all the tests */ - } - switch (reply_buffer[0] >> 5) { - case 0x0: - /* Either a 82078-1 or a 82078SL running at 5Volt */ - printk(KERN_INFO "FDC %d is an 82078.\n",fdc); - return FDC_82078; - case 0x1: - printk(KERN_INFO "FDC %d is a 44pin 82078\n",fdc); - return FDC_82078; - case 0x2: - printk(KERN_INFO "FDC %d is a S82078B\n", fdc); - return FDC_S82078B; - case 0x3: - printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n", fdc); - return FDC_87306; - default: - printk(KERN_INFO "FDC %d init: 82078 variant with unknown PARTID=%d.\n", - fdc, reply_buffer[0] >> 5); - return FDC_82078_UNKN; - } -} /* get_fdc_version */ + /* Revised 82077AA passes all the tests */ + FloppyWriteCommandByte(PortBase, FLOPPY_CMD_PARTID); + ResultLength = FloppyReadResultCode(PortBase, &Result)); + if (ResultLength != 1) + { + DPRINT("FDC %d init: PARTID: unexpected return of %d bytes.\n", + PortBase, + ResultLength); + return FALSE; + } + if (Result[0] == 0x80) + { + DPRINT("FDC %d is a post-1991 82077\n", 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", PortBase); + *ControllerType = FDC_82078; + return TRUE; + case 0x1: + DPRINT("FDC %d is a 44pin 82078\n", PortBase); + *ControllerType = FDC_82078; + return TRUE; -static NTSTATUS FloppyStartIo( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) { - PIO_STACK_LOCATION IrpStack; - PFLOPPY_DEVICE_EXTENSION DeviceExtension; - - IrpStack = IoGetCurrentIrpStackLocation(Irp); - DeviceExtension = (PFLOPPY_DEVICE_EXTENSION) DeviceObject->DeviceExtension; + case 0x2: + DPRINT("FDC %d is a S82078B\n", PortBase); + *ControllerType = FDC_S82078B; + return TRUE; - + case 0x3: + DPRINT("FDC %d is a National Semiconductor PC87306\n", PortBase); + *ControllerType = FDC_87306; + return TRUE; + default: + DPRINT("FDC %d init: 82078 variant with unknown PARTID=%d.\n", + PortBase, + Result[0] >> 5); + *ControllerType = FDC_82078_UNKN; + return TRUE; + } } -FloppyDispatchOpenClose +/* sends a command byte to the fdc */ +static BOOLEAN +FloppyWriteCommandByte(WORD PortBase, BYTE Byte) +{ + int Status; -FloppyDispatchReadWrite + if ((Status = FloppyWaitUntilReady()) < 0) + { + return FALSE; + } -FloppyDispatchDeviceControl + if ((Status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY) + { + FloppyWriteData(PortBase, Byte); + return 0; + } -FloppyIsr + 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(WORD PortBase, PBYTE 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] = fd_inb(FD_DATA); + } + else + { + break; + } + } + + if (FloppyInitialized) + { + DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n", + PortBase, + Status, + Replies); + } + + return -1; +} + +/* waits until the fdc becomes ready */ +static int +FloppyWaitUntilReady(WORD 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; +} + + +#define MORE_OUTPUT -2 +/* does the fdc need more output? */ +static int +FloppyNeedsMoreOutput(WORD PortBase, PBYTE 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(WORD PortBase, BOOLEAN DisableFIFO, BYTE FIFODepth) +{ + BYTE Result[FLOPPY_MAX_REPLIES]; + + /* Turn on FIFO */ + FloppyWriteCommandByte(FLOPPY_CMD_CFG_FIFO); + if (FloppyNeedsOutput(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; +} diff --git a/reactos/drivers/dd/floppy/floppy.h b/reactos/drivers/dd/floppy/floppy.h index 7021aa39aac..2dea2c85088 100644 --- a/reactos/drivers/dd/floppy/floppy.h +++ b/reactos/drivers/dd/floppy/floppy.h @@ -1,4 +1,10 @@ +#define FLOPPY_MAX_STAT_RETRIES 10000 + +#define FLOPPY_NEEDS_OUTPUT -2 +// +// Floppy register definitions +// #define FLOPPY_REG_DOR 0x0002 #define FLOPPY_REG_MSTAT 0x0004 @@ -71,5 +77,82 @@ #define FLOPPY_CMD_WRITE (FLOPPY_CMD_WRT_DATA | FLOPPY_C0M_MFM | FLOPPY_C0M_MT) #define FLOPPY_CMD_FORMAT (FLOPPY_CMD_FMT_TRK | FLOPPY_C0M_MFM) +// +// 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; + +typedef struct _FLOPPY_ERROR_THRESHOLDS +{ + /* number of errors to be reached before aborting */ + unsigned int Abort; + /* maximal number of errors permitted to read an entire track at once */ + unsigned int ReadTrack; + /* maximal number of errors before a reset is tried */ + unsigned int Reset; + /* maximal number of errors before a recalibrate is tried */ + unsigned int Recal; + /* + * Threshold for reporting FDC errors to the console. + * Setting this to zero may flood your screen when using + * ultra cheap floppies ;-) + */ + unsigned int Reporting; +} FLOPPY_ERROR_THRESHOLDS; + +#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 +{ + 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;