#include "dma.h"
#include "fdc.h"
#include "video.h"
#include "delay.h"
#include "gdt.h"
#include "idt.h"
#include "8259.h"
#include "io.h"
static volatile BOOL done = FALSE;
static BOOL dchange = FALSE;
static BOOL motor = FALSE;
static int mtick = 0;
static volatile int tmout = 0;
static BYTE status[7] = { 0 };
static BYTE statsz = 0;
static BYTE sr0 = 0;
static BYTE fdc_track = 0xff;
static DrvGeom geometry = { DG144_HEADS,DG144_TRACKS,DG144_SPT };
unsigned long tbaddr = 0x80000L;
extern void floppy_ISR();
extern void _int1c();
void sendbyte(int byte);
int getbyte();
void irq6(void);
void int1c(void);
BOOL waitfdc(BOOL sensei);
BOOL fdc_rw(int block,BYTE *blockbuff,BOOL read,unsigned long nosectors);
void init_floppy(void)
{
int i;
set_vector(floppy_ISR, M_VEC+6, (D_INT+D_PRESENT+D_DPL1));
enable_irq(6);
set_vector(_int1c, 0x1c, (D_INT+D_PRESENT+D_DPL1));
reset();
sendbyte(CMD_VERSION);
i = getbyte();
kprint("Initialising Floppy driver... ");
if (i == 0x80)
kprint("NEC765 controller found\n");
else
kprint("Enhanced controller found\n");
}
void sendbyte(int byte)
{
volatile int msr;
int tmo;
for (tmo = 0;tmo < 128;tmo++) {
msr = inportb(FDC_MSR);
if ((msr & 0xc0) == 0x80) {
outportb(FDC_DATA,byte);
return;
}
inportb(0x80);
}
}
int getbyte()
{
volatile int msr;
int tmo;
for (tmo = 0;tmo < 128;tmo++) {
msr = inportb(FDC_MSR);
if ((msr & 0xd0) == 0xd0) {
return inportb(FDC_DATA);
}
inportb(0x80);
}
return -1;
}
BOOL waitfdc(BOOL sensei)
{
tmout = 50000;
while (!done && tmout)
;
statsz = 0;
while ((statsz < 7) && (inportb(FDC_MSR) & (1<<4))) {
status[statsz++] = getbyte();
}
if (sensei) {
sendbyte(CMD_SENSEI);
sr0 = getbyte();
fdc_track = getbyte();
}
done = FALSE;
if (!tmout) {
if (inportb(FDC_DIR) & 0x80)
dchange = TRUE;
return FALSE;
} else
return TRUE;
}
void irq6(void)
{
done = TRUE;
outportb(0x20,0x20);
}
void int1c(void)
{
if (tmout) --tmout;
if (mtick > 0)
--mtick;
else if (!mtick && motor) {
outportb(FDC_DOR,0x0c);
motor = FALSE;
}
}
void block2hts(int block,int *head,int *track,int *sector)
{
*head = (block % (geometry.spt * geometry.heads)) / (geometry.spt);
*track = block / (geometry.spt * geometry.heads);
*sector = block % geometry.spt + 1;
}
void reset(void)
{
outportb(FDC_DOR,0);
mtick = 0;
motor = FALSE;
outportb(FDC_DRS,0);
outportb(FDC_DOR,0x0c);
done = TRUE;
waitfdc(TRUE);
sendbyte(CMD_SPECIFY);
sendbyte(0xdf);
sendbyte(0x02);
seek(1);
recalibrate();
dchange = FALSE;
}
BOOL diskchange(void)
{
return dchange;
}
void motoron(void)
{
if (!motor) {
mtick = -1;
outportb(FDC_DOR,0x1c);
delay(500);
motor = TRUE;
}
}
void motoroff(void)
{
if (motor) {
mtick = 13500;
}
}
void recalibrate(void)
{
motoron();
sendbyte(CMD_RECAL);
sendbyte(0);
waitfdc(TRUE);
motoroff();
}
BOOL seek(int track)
{
if (fdc_track == track)
return TRUE;
sendbyte(CMD_SEEK);
sendbyte(0);
sendbyte(track);
if (!waitfdc(TRUE))
return FALSE;
delay(15);
if ((sr0 != 0x20) || (fdc_track != track))
return FALSE;
else
return TRUE;
}
BOOL log_disk(DrvGeom *g)
{
reset();
geometry.heads = DG168_HEADS;
geometry.tracks = DG168_TRACKS;
geometry.spt = DG168_SPT;
if (read_block(20,NULL,1)) {
if (g) {
g->heads = geometry.heads;
g->tracks = geometry.tracks;
g->spt = geometry.spt;
}
return TRUE;
}
geometry.heads = DG144_HEADS;
geometry.tracks = DG144_TRACKS;
geometry.spt = DG144_SPT;
if (read_block(17,NULL,1)) {
if (g) {
g->heads = geometry.heads;
g->tracks = geometry.tracks;
g->spt = geometry.spt;
}
return TRUE;
}
return FALSE;
}
BOOL read_block(int block,BYTE *blockbuff, unsigned long nosectors)
{
int track=0, sector=0, head=0, track2=0, result=0, loop=0;
block2hts(block, &head, &track, §or);
block2hts(block+nosectors, &head, &track2, §or);
if(track!=track2)
{
for(loop=0; loop<nosectors; loop++)
result = fdc_rw(block+loop, blockbuff+(loop*512), TRUE, 1);
return result;
}
return fdc_rw(block,blockbuff,TRUE,nosectors);
}
BOOL write_block(int block,BYTE *blockbuff, unsigned long nosectors)
{
return fdc_rw(block,blockbuff,FALSE, nosectors);
}
BOOL fdc_rw(int block,BYTE *blockbuff,BOOL read,unsigned long nosectors)
{
int head,track,sector,tries, copycount = 0;
unsigned char *p_tbaddr = (char *)0x80000;
unsigned char *p_blockbuff = blockbuff;
block2hts(block,&head,&track,§or);
motoron();
if (!read && blockbuff) {
for(copycount=0; copycount<(nosectors*512); copycount++) {
*p_tbaddr = *p_blockbuff;
p_blockbuff++;
p_tbaddr++;
}
}
for (tries = 0;tries < 3;tries++) {
if (inportb(FDC_DIR) & 0x80) {
dchange = TRUE;
seek(1);
recalibrate();
motoroff();
kprint("FDC: Disk change detected. Trying again.\n");
return fdc_rw(block, blockbuff, read, nosectors);
}
if (!seek(track)) {
motoroff();
kprint("FDC: Error seeking to track\n");
return FALSE;
}
outportb(FDC_CCR,0);
if (read) {
dma_xfer(2,tbaddr,nosectors*512,FALSE);
sendbyte(CMD_READ);
} else {
dma_xfer(2,tbaddr,nosectors*512,TRUE);
sendbyte(CMD_WRITE);
}
sendbyte(head << 2);
sendbyte(track);
sendbyte(head);
sendbyte(sector);
sendbyte(2);
sendbyte(geometry.spt);
if (geometry.spt == DG144_SPT)
sendbyte(DG144_GAP3RW);
else
sendbyte(DG168_GAP3RW);
sendbyte(0xff);
if (!waitfdc(TRUE)) {
kprint("Timed out, trying operation again after reset()\n");
reset();
return fdc_rw(block, blockbuff, read, nosectors);
}
if ((status[0] & 0xc0) == 0) break;
recalibrate();
}
motoroff();
if (read && blockbuff) {
p_blockbuff = blockbuff;
p_tbaddr = (char *) 0x80000;
for(copycount=0; copycount<(nosectors*512); copycount++) {
*p_blockbuff = *p_tbaddr;
p_blockbuff++;
p_tbaddr++;
}
}
return (tries != 3);
}
BOOL format_track(BYTE track,DrvGeom *g)
{
int i,h,r,r_id,split;
BYTE tmpbuff[256];
unsigned char *p_tbaddr = (char *)0x8000;
unsigned int copycount = 0;
if (g->spt != DG144_SPT && g->spt != DG168_SPT)
return FALSE;
motoron();
outportb(FDC_CCR,0);
seek(track);
split = g->spt / 2;
if (g->spt & 1) split++;
for (h = 0;h < g->heads;h++) {
if (inportb(FDC_DIR) & 0x80) {
dchange = TRUE;
seek(1);
recalibrate();
motoroff();
return FALSE;
}
i = 0;
for (r = 0;r < g->spt;r++) {
r_id = r / 2 + 1;
if (r & 1) r_id += split;
if (h & 1) {
r_id -= 2;
if (r_id < 1) r_id += g->spt;
}
if (track & 1) {
r_id -= g->spt / 2;
if (r_id < 1) r_id += g->spt;
}
tmpbuff[i++] = track;
tmpbuff[i++] = h;
tmpbuff[i++] = r_id;
tmpbuff[i++] = 2;
}
for(copycount = 0; copycount<i; copycount++) {
*p_tbaddr = tmpbuff[copycount];
p_tbaddr++;
}
dma_xfer(2,tbaddr,i,TRUE);
sendbyte(CMD_FORMAT);
sendbyte(h << 2);
sendbyte(2);
sendbyte(g->spt);
if (g->spt == DG144_SPT)
sendbyte(DG144_GAP3FMT);
else
sendbyte(DG168_GAP3FMT);
sendbyte(0);
if (!waitfdc(FALSE))
return FALSE;
if (status[0] & 0xc0) {
motoroff();
return FALSE;
}
}
motoroff();
return TRUE;
}
asm (
".globl _int1c \n"
"_int1c: \n"
" pusha \n"
" pushw %ds \n"
" pushw %es \n"
" pushw %ss \n"
" pushw %ss \n"
" popw %ds \n"
" popw %es \n"
" \n"
" call int1c \n"
" \n"
" popw %es \n"
" popw %ds \n"
" popa \n"
" iret \n"
);
asm (
".globl floppy_ISR \n"
"floppy_ISR: \n"
" pusha \n"
" pushw %ds \n"
" pushw %es \n"
" pushw %ss \n"
" pushw %ss \n"
" popw %ds \n"
" popw %es \n"
" \n"
" call irq6 \n"
" \n"
" popw %es \n"
" popw %ds \n"
" popa \n"
" iret \n"
);