Continuing work in progress

svn path=/trunk/; revision=102
This commit is contained in:
Rex Jolliff 1998-11-29 19:25:39 +00:00
parent e96765787f
commit fd5a21279e
2 changed files with 438 additions and 129 deletions

View file

@ -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 <ddk/ntddk.h>
#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;
}

View file

@ -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;