Re: Help with floppy driver
Posted: Sat Mar 26, 2005 12:00 am
by prajwal
Is there a way to send a text file in reply as attachment?
Any ways..... Here there is some C code which might be usefull with the intel 82077AA PDF...
#define READ 0
#define WRITE 1
#define DMA_READ 0x44
#define DMA_WRITE 0x48
#define NO_TRACK 255
#define FD_STATUS 0x3f4
#define FD_DATA 0x3f5
#define FD_DOR 0x3f2 // Digital Output Register
#define FD_DIR 0x3f7 // Digital Input Register (read)
#define FD_DCR 0x3f7 // Diskette Control Register (write)
#define STATUS_BUSYMASK 0x0F // drive busy mask
#define STATUS_BUSY 0x10 // FDC busy
#define STATUS_DMA 0x20 // 0- DMA mode
#define STATUS_DIR 0x40 // 0- cpu->fdc
#define STATUS_READY 0x80 // Data reg ready
#define FD_RECALIBRATE 0x07 // move to track 0
#define FD_SEEK 0x0F // seek track
#define FD_READ 0xE6 // read with MT, MFM, SKip deleted
#define FD_WRITE 0xC5 // write with MT, MFM
#define FD_SENSEI 0x08 // Sense Interrupt Status
#define FD_SPECIFY 0x03 // specify HUT etc
/* FDC DOR register bits */
#define FD_MOTOR0 0x10
#define FD_MOTOR1 0x20
#define FD_INTS 0x08
#define FD_RESET 0x04
#define FD_DRV1SEL 0x01
#define FD_MOTMASK 0xf0 /* mask to see motor bits */
static long PhysicalDMABuffer;
static int BufferDrive;
static int BufferTrack;
// #define TRACELINE kprintf ("[%4d]", __LINE__);
#define TRACELINE
extern void * GetLowMemoryPage (int MustBeAboveKernel);
typedef struct FloppyInfo
{
ushort size, sect, head, track, stretch;
byte gap,rate,spec1;
} FloppyInfo;
static FloppyInfo FloppyTypes [] =
{
{ 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
{ 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
{ 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
{ 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
{ 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
{ 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
{ 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
{ 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
};
#define MAX_REPLIES 7
static unsigned char reply_buffer[MAX_REPLIES];
#define ST0 (reply_buffer[0])
#define ST1 (reply_buffer[1])
#define ST2 (reply_buffer[2])
#define ST3 (reply_buffer[3])
static WaitQ *FloppyCompleted = 0;
static FloppyInfo *CurrentFloppy;
static byte CurrentFloppyNr;
static char *CurrentBuffer;
static byte Writing;
static ulong FloppyLastUsed;
static byte CurrentDOR;
static byte NeedAReset;
static byte NeedArecalibrate;
static byte CurrentTrack;
static byte sector;
static byte head;
static byte track;
static byte seek_track;
static void FloppyInterrupt (IntRegs *regs, long NotUsed)
{
regs = regs;
NotUsed = NotUsed;
WakeUp (&FloppyCompleted);
}
static void SendCmd(char Cmd)
{
int counter;
byte status;
if (NeedAReset)
return;
for(counter = 0 ; counter < 10000 ; counter++)
{
status = inportb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
if (status == STATUS_READY)
{
outportb_p(FD_DATA, Cmd);
return;
}
}
CurrentTrack = NO_TRACK;
NeedAReset = 1;
kprintf("Unable to send byte to FDC\n");
}
static int FloppyResult(void)
{
int i = 0, counter, status;
if (NeedAReset)
return -1;
for (counter = 0 ; counter < 10000 ; counter++)
{
status = inportb_p(FD_STATUS) & (STATUS_DIR|STATUS_READY|STATUS_BUSY);
if (status == STATUS_READY)
return i;
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))
{
if (i >= MAX_REPLIES)
{
kprintf("floppy_stat reply overrun\n");
break;
}
reply_buffer[i++] = inportb_p(FD_DATA);
}
}
NeedAReset = 1;
CurrentTrack = NO_TRACK;
kprintf("Getstatus times out\n");
return -1;
}
static void SelectFloppy (void)
{
int SendTheCommand = 0;
int DelayAfterCommand = 0;
FloppyLastUsed = GetTickCount();
if (CurrentFloppyNr == 0)
{
if (CurrentDOR & 0x01)
{
SendTheCommand = 1;
CurrentDOR &= 0xFE;
}
if (!(CurrentDOR & FD_MOTOR0))
{
SendTheCommand = 1;
DelayAfterCommand = 1;
CurrentDOR |= FD_MOTOR0;
}
}
else if (CurrentFloppyNr == 1)
{
if (!(CurrentDOR & 0x01))
{
SendTheCommand = 1;
CurrentDOR |= 0x01;
}
if (!(CurrentDOR & FD_MOTOR1))
{
SendTheCommand = 1;
DelayAfterCommand = 1;
CurrentDOR |= FD_MOTOR1;
}
}
else
{
kprintf ("wrong floppy drive %d selected!\n", CurrentFloppyNr);
return;
}
if (SendTheCommand)
{
outportb_p (FD_DOR, CurrentDOR);
SleepOn (&FloppyCompleted);
if (DelayAfterCommand)
Sleep(330);
SendCmd (FD_SPECIFY);
SendCmd (CurrentFloppy->spec1);
SendCmd (6);
// set data rate
outportb_p (FD_DCR, CurrentFloppy -> rate);
}
}
static void DoFloppyReset (void)
{
long flags;
int i;
NeedAReset = 0;
CurrentTrack = NO_TRACK;
NeedArecalibrate = 1;
save_flags (flags);
cli();
outportb_p(FD_DOR, 0x08);
// TODO: delay 1 ms
for (i = 0 ; i < 10000 ; i++)
__asm__("nop");
outportb_p(FD_DOR, 0x0c);
CurrentDOR = 0x0c;
restore_flags(flags);
SleepOn (&FloppyCompleted);
SendCmd(FD_SENSEI);
FloppyResult();
SendCmd(FD_SPECIFY);
SendCmd(0xAf);
SendCmd(6);
FloppyResult();
}
static int DoCalibrate (void)
{
SendCmd (7);
SendCmd (0);
SleepOn (&FloppyCompleted);
SendCmd (8);
if (FloppyResult() >= 0)
{
if (reply_buffer[0] & 0x20)
{
if (reply_buffer[1])
return (0);
NeedArecalibrate = 0;
CurrentTrack = -1;
return(1);
}
}
return (0);
}
static int DoSeek (void)
{
if (NeedArecalibrate)
{
if (! DoCalibrate ())
DoCalibrate ();
if (seek_track == CurrentTrack)
Sleep (1);
}
if (seek_track == CurrentTrack)
return (1);
SendCmd (FD_SEEK);
SendCmd ((head << 2) | CurrentFloppyNr);
SendCmd (seek_track);
SleepOn (&FloppyCompleted);
SendCmd (8);
if (FloppyResult() >= 0)
{
if (! (reply_buffer[0] & 0x20))
{
kprintf ("R");
NeedArecalibrate = 1;
return (0);
}
CurrentTrack = seek_track;
Sleep (1);
return (1);
}
return (0);
}
static void SetupDMA (void)
{
unsigned long flags;
unsigned long count = (Writing) ? 512 : CurrentFloppy -> sect * 2 /*CurrentFloppy -> head*/ * 512;
save_flags(flags);
cli ();
disable_dma(2);
clear_dma_ff(2);
set_dma_mode(2, (Writing)? DMA_WRITE : DMA_READ);
set_dma_addr(2, PhysicalDMABuffer);
set_dma_count(2, count);
enable_dma(2);
restore_flags(flags);
}
static int DoReadWrite (void)
{
int retrys;
int error;
if ((! Writing) && (BufferTrack == seek_track) && (BufferDrive == CurrentFloppyNr))
{
long buffer_area = PhysicalDMABuffer + ((sector-1 + head*CurrentFloppy->sect)<<9);
CopyMem(SEL_DLINEAR, buffer_area, GetDS(), (long) CurrentBuffer, 512);
return (0);
}
if (Writing)
{
CopyMem(GetDS(), (long) CurrentBuffer, SEL_DLINEAR, PhysicalDMABuffer, 512);
}
SetupDMA ();
for (retrys = 0; retrys < 3; retrys++)
{
error = 0;
if (DoSeek() < 0)
{
error = 1;
continue;
}
SendCmd ((Writing) ? FD_WRITE : FD_READ);
SendCmd ((Writing) ? ((head <<2) & 4) | CurrentFloppyNr : CurrentFloppyNr);
SendCmd (track);
SendCmd ((Writing) ? head : 0);
SendCmd ((Writing) ? sector : 1);
SendCmd (2);
SendCmd (CurrentFloppy -> sect);
SendCmd (CurrentFloppy -> gap);
SendCmd (0xFF);
SleepOn (&FloppyCompleted);
if (FloppyResult() >= 0)
{
if (! Writing)
{
long buffer_area = PhysicalDMABuffer + ((sector-1 + head*CurrentFloppy->sect)<<9);
BufferTrack = seek_track;
BufferDrive = CurrentFloppyNr;
CopyMem(SEL_DLINEAR, buffer_area, GetDS(), (long) CurrentBuffer, 512);
}
break;
}
else
error = 1;
}
return ((error) ? -1 : 0);
}
static int DoFloppyRequest (int Cmd, int Nr, char *Buffer)
{
Writing = (Cmd == WRITE) ? 1 : 0;
CurrentBuffer = Buffer;
if (Writing)
BufferDrive = -1;
CurrentFloppyNr = 0;
CurrentFloppy = FloppyTypes + 6; //TODO: hardcoded 1.44MB
if (Nr + 2 > CurrentFloppy->size)
return (-1);
sector = (Nr % CurrentFloppy->sect);
Nr /= CurrentFloppy->sect;
head = Nr % CurrentFloppy->head;
track = Nr / CurrentFloppy->head;
seek_track = track << CurrentFloppy->stretch;
sector ++; // sector starts at 1!
// select floppy and switch motor on
SelectFloppy ();
// discard any waiting results
FloppyResult();
return (DoReadWrite());
}
/////////////////////////////////////////////////////////////////////////
// public functions
void InitFloppy (void)
{
// Set Interrupt procedure
RequestIRQ (6, FloppyInterrupt, 0);
RequestDMA (2, "floppy");
outportb (FD_DOR, 0);
// TODO: this needs to be contignous memory
// PhysicalDMABuffer = (long) GetLowMemoryPage (0);
// kprintf ("Floppy DMA is at %08X:%08X:%08X:%08X:%08X (physical)\n", PhysicalDMABuffer,
// GetLowMemoryPage (0), GetLowMemoryPage (0), GetLowMemoryPage (0), GetLowMemoryPage (0));
BufferDrive = -1;
BufferTrack = -1;
Writing = 0;
CurrentDOR = 0x0C;
// DoFloppyReset ();
NeedArecalibrate = 1;
// kprintf ("Floppy initialized\n");
}
int FloppyDiskReadBlock (int Nr, char *Buffer)
{
return (DoFloppyRequest (READ, Nr, Buffer));
}
int FloppyDiskWriteBlock (int Nr, char *Buffer)
{
return (DoFloppyRequest (WRITE, Nr, Buffer));
}
V#include <string.h>
#include <kernel/kernel.h>
#include <kernel/irq.h>
#include <kernel/kprint.h>
#include <kernel/schedule.h>
#include <kernel/waitq.h>
#include <kernel/timer.h>
#include <kernel/selector.h>
#include <kernel/console.h>
#include <kernel/dma.h>
#define READ 0
#define WRITE 1
#define DMA_READ 0x44
#define DMA_WRITE 0x48
#define NO_TRACK 255
#define FD_STATUS 0x3f4
#define FD_DATA 0x3f5
#define FD_DOR 0x3f2 // Digital Output Register
#define FD_DIR 0x3f7 // Digital Input Register (read)
#define FD_DCR 0x3f7 // Diskette Control Register (write)
#define STATUS_BUSYMASK 0x0F // drive busy mask
#define STATUS_BUSY 0x10 // FDC busy
#define STATUS_DMA 0x20 // 0- DMA mode
#define STATUS_DIR 0x40 // 0- cpu->fdc
#define STATUS_READY 0x80 // Data reg ready
#define FD_RECALIBRATE 0x07 // move to track 0
#define FD_SEEK 0x0F // seek track
#define FD_READ 0xE6 // read with MT, MFM, SKip deleted
#define FD_WRITE 0xC5 // write with MT, MFM
#define FD_SENSEI 0x08 // Sense Interrupt Status
#define FD_SPECIFY 0x03 // specify HUT etc
/* FDC DOR register bits */
#define FD_MOTOR0 0x10
#define FD_MOTOR1 0x20
#define FD_INTS 0x08
#define FD_RESET 0x04
#define FD_DRV1SEL 0x01
#define FD_MOTMASK 0xf0 /* mask to see motor bits */
static long PhysicalDMABuffer;
static int BufferDrive;
static int BufferTrack;
// #define TRACELINE kprintf ("[%4d]", __LINE__);
#define TRACELINE
extern void * GetLowMemoryPage (int MustBeAboveKernel);
typedef struct FloppyInfo
{
ushort size, sect, head, track, stretch;
byte gap,rate,spec1;
} FloppyInfo;
static FloppyInfo FloppyTypes [] =
{
{ 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
{ 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
{ 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
{ 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
{ 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
{ 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
{ 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
{ 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
};
#define MAX_REPLIES 7
static unsigned char reply_buffer[MAX_REPLIES];
#define ST0 (reply_buffer[0])
#define ST1 (reply_buffer[1])
#define ST2 (reply_buffer[2])
#define ST3 (reply_buffer[3])
static WaitQ *FloppyCompleted = 0;
static FloppyInfo *CurrentFloppy;
static byte CurrentFloppyNr;
static char *CurrentBuffer;
static byte Writing;
static ulong FloppyLastUsed;
static byte CurrentDOR;
static byte NeedAReset;
static byte NeedArecalibrate;
static byte CurrentTrack;
static byte sector;
static byte head;
static byte track;
static byte seek_track;
static void FloppyInterrupt (IntRegs *regs, long NotUsed)
{
regs = regs;
NotUsed = NotUsed;
WakeUp (&FloppyCompleted);
}
static void SendCmd(char Cmd)
{
int counter;
byte status;
if (NeedAReset)
return;
for(counter = 0 ; counter < 10000 ; counter++)
{
status = inportb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
if (status == STATUS_READY)
{
outportb_p(FD_DATA, Cmd);
return;
}
}
CurrentTrack = NO_TRACK;
NeedAReset = 1;
kprintf("Unable to send byte to FDC\n");
}
static int FloppyResult(void)
{
int i = 0, counter, status;
if (NeedAReset)
return -1;
for (counter = 0 ; counter < 10000 ; counter++)
{
status = inportb_p(FD_STATUS) & (STATUS_DIR|STATUS_READY|STATUS_BUSY);
if (status == STATUS_READY)
return i;
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))
{
if (i >= MAX_REPLIES)
{
kprintf("floppy_stat reply overrun\n");
break;
}
reply_buffer[i++] = inportb_p(FD_DATA);
}
}
NeedAReset = 1;
CurrentTrack = NO_TRACK;
kprintf("Getstatus times out\n");
return -1;
}
static void SelectFloppy (void)
{
int SendTheCommand = 0;
int DelayAfterCommand = 0;
FloppyLastUsed = GetTickCount();
if (CurrentFloppyNr == 0)
{
if (CurrentDOR & 0x01)
{
SendTheCommand = 1;
CurrentDOR &= 0xFE;
}
if (!(CurrentDOR & FD_MOTOR0))
{
SendTheCommand = 1;
DelayAfterCommand = 1;
CurrentDOR |= FD_MOTOR0;
}
}
else if (CurrentFloppyNr == 1)
{
if (!(CurrentDOR & 0x01))
{
SendTheCommand = 1;
CurrentDOR |= 0x01;
}
if (!(CurrentDOR & FD_MOTOR1))
{
SendTheCommand = 1;
DelayAfterCommand = 1;
CurrentDOR |= FD_MOTOR1;
}
}
else
{
kprintf ("wrong floppy drive %d selected!\n", CurrentFloppyNr);
return;
}
if (SendTheCommand)
{
outportb_p (FD_DOR, CurrentDOR);
SleepOn (&FloppyCompleted);
if (DelayAfterCommand)
Sleep(330);
SendCmd (FD_SPECIFY);
SendCmd (CurrentFloppy->spec1);
SendCmd (6);
// set data rate
outportb_p (FD_DCR, CurrentFloppy -> rate);
}
}
static void DoFloppyReset (void)
{
long flags;
int i;
NeedAReset = 0;
CurrentTrack = NO_TRACK;
NeedArecalibrate = 1;
save_flags (flags);
cli();
outportb_p(FD_DOR, 0x08);
// TODO: delay 1 ms
for (i = 0 ; i < 10000 ; i++)
__asm__("nop");
outportb_p(FD_DOR, 0x0c);
CurrentDOR = 0x0c;
restore_flags(flags);
SleepOn (&FloppyCompleted);
SendCmd(FD_SENSEI);
FloppyResult();
SendCmd(FD_SPECIFY);
SendCmd(0xAf);
SendCmd(6);
FloppyResult();
}
static int DoCalibrate (void)
{
SendCmd (7);
SendCmd (0);
SleepOn (&FloppyCompleted);
SendCmd (8);
if (FloppyResult() >= 0)
{
if (reply_buffer[0] & 0x20)
{
if (reply_buffer[1])
return (0);
NeedArecalibrate = 0;
CurrentTrack = -1;
return(1);
}
}
return (0);
}
static int DoSeek (void)
{
if (NeedArecalibrate)
{
if (! DoCalibrate ())
DoCalibrate ();
if (seek_track == CurrentTrack)
Sleep (1);
}
if (seek_track == CurrentTrack)
return (1);
SendCmd (FD_SEEK);
SendCmd ((head << 2) | CurrentFloppyNr);
SendCmd (seek_track);
SleepOn (&FloppyCompleted);
SendCmd (8);
if (FloppyResult() >= 0)
{
if (! (reply_buffer[0] & 0x20))
{
kprintf ("R");
NeedArecalibrate = 1;
return (0);
}
CurrentTrack = seek_track;
Sleep (1);
return (1);
}
return (0);
}
static void SetupDMA (void)
{
unsigned long flags;
unsigned long count = (Writing) ? 512 : CurrentFloppy -> sect * 2 /*CurrentFloppy -> head*/ * 512;
save_flags(flags);
cli ();
disable_dma(2);
clear_dma_ff(2);
set_dma_mode(2, (Writing)? DMA_WRITE : DMA_READ);
set_dma_addr(2, PhysicalDMABuffer);
set_dma_count(2, count);
enable_dma(2);
restore_flags(flags);
}
static int DoReadWrite (void)
{
int retrys;
int error;
if ((! Writing) && (BufferTrack == seek_track) && (BufferDrive == CurrentFloppyNr))
{
long buffer_area = PhysicalDMABuffer + ((sector-1 + head*CurrentFloppy->sect)<<9);
CopyMem(SEL_DLINEAR, buffer_area, GetDS(), (long) CurrentBuffer, 512);
return (0);
}
if (Writing)
{
CopyMem(GetDS(), (long) CurrentBuffer, SEL_DLINEAR, PhysicalDMABuffer, 512);
}
SetupDMA ();
for (retrys = 0; retrys < 3; retrys++)
{
error = 0;
if (DoSeek() < 0)
{
error = 1;
continue;
}
SendCmd ((Writing) ? FD_WRITE : FD_READ);
SendCmd ((Writing) ? ((head <<2) & 4) | CurrentFloppyNr : CurrentFloppyNr);
SendCmd (track);
SendCmd ((Writing) ? head : 0);
SendCmd ((Writing) ? sector : 1);
SendCmd (2);
SendCmd (CurrentFloppy -> sect);
SendCmd (CurrentFloppy -> gap);
SendCmd (0xFF);
SleepOn (&FloppyCompleted);
if (FloppyResult() >= 0)
{
if (! Writing)
{
long buffer_area = PhysicalDMABuffer + ((sector-1 + head*CurrentFloppy->sect)<<9);
BufferTrack = seek_track;
BufferDrive = CurrentFloppyNr;
CopyMem(SEL_DLINEAR, buffer_area, GetDS(), (long) CurrentBuffer, 512);
}
break;
}
else
error = 1;
}
return ((error) ? -1 : 0);
}
static int DoFloppyRequest (int Cmd, int Nr, char *Buffer)
{
Writing = (Cmd == WRITE) ? 1 : 0;
CurrentBuffer = Buffer;
if (Writing)
BufferDrive = -1;
CurrentFloppyNr = 0;
CurrentFloppy = FloppyTypes + 6; //TODO: hardcoded 1.44MB
if (Nr + 2 > CurrentFloppy->size)
return (-1);
sector = (Nr % CurrentFloppy->sect);
Nr /= CurrentFloppy->sect;
head = Nr % CurrentFloppy->head;
track = Nr / CurrentFloppy->head;
seek_track = track << CurrentFloppy->stretch;
sector ++; // sector starts at 1!
// select floppy and switch motor on
SelectFloppy ();
// discard any waiting results
FloppyResult();
return (DoReadWrite());
}
/////////////////////////////////////////////////////////////////////////
// public functions
void InitFloppy (void)
{
// Set Interrupt procedure
RequestIRQ (6, FloppyInterrupt, 0);
RequestDMA (2, "floppy");
outportb (FD_DOR, 0);
// TODO: this needs to be contignous memory
// PhysicalDMABuffer = (long) GetLowMemoryPage (0);
// kprintf ("Floppy DMA is at %08X:%08X:%08X:%08X:%08X (physical)\n", PhysicalDMABuffer,
// GetLowMemoryPage (0), GetLowMemoryPage (0), GetLowMemoryPage (0), GetLowMemoryPage (0));
BufferDrive = -1;
BufferTrack = -1;
Writing = 0;
CurrentDOR = 0x0C;
// DoFloppyReset ();
NeedArecalibrate = 1;
// kprintf ("Floppy initialized\n");
}
int FloppyDiskReadBlock (int Nr, char *Buffer)
{
return (DoFloppyRequest (READ, Nr, Buffer));
}
int FloppyDiskWriteBlock (int Nr, char *Buffer)
{
return (DoFloppyRequest (WRITE, Nr, Buffer));
}
[/img]