/************************************************************************************** Copyright (c) 2002 The UbixOS Project All rights reserved. Redistribution and use in source and binary forms, with or without modification, are prohibited. $Id$ **************************************************************************************/ #include <drivers/fdc.h> #include <drivers/8259.h> #include <drivers/video.h> #include <ubixos/gdt.h> #include <ubixos/idt.h> #include <ubixos/types.h> #include <ubixos/io.h> #include <ubixos/dma.h> static volatile bool done = FALSE; static drvGeom geometry = { dg144Heads,dg144Tracks,dg144Spt }; static bool diskChange = FALSE; static bool motor = FALSE; static int mTick = 0; static byte fdcTrack = 0xff; static byte sr0 = 0; static volatile int timeOut = 0; static byte statSize = 0; static byte status[7] = { 0 }; unsigned long tbaddr = 0x80000L; void initFloppy() { setVector(floppyIsr, mVec+6, (dInt+dPresent+dDpl1)); enableIrq(6); reset(); } asm( ".globl floppyIsr \n" "floppyIsr: \n" " pusha \n" " pushw %ds \n" " pushw %es \n" " pushw %ss \n" " pushw %ss \n" " popw %ds \n" " popw %es \n" " call floppyIsrhndlr \n" " popw %es \n" " popw %ds \n" " popa \n" " iret \n" ); void floppyIsrhndlr() { done = TRUE; outportByte(0x20,0x20); } void sendByte(int byte) { volatile int msr; int tmo; for (tmo=0;tmo<128;tmo++) { msr = inportByte(fdcMsr); if ((msr & 0xc0) == 0x80) { outportByte(fdcData,byte); return; } inportByte(0x80); } } int getByte() { volatile int msr; int tmo; for (tmo=0;tmo<128;tmo++) { msr = inportByte(fdcMsr); if ((msr & 0xd0) == 0xd0) { return inportByte(fdcData); } inportByte(0x80); } return(-1); } bool fdcRw(int block,byte *blockBuffer,bool read,unsigned long numSectors) { int head,track,sector,tries, copyCount = 0; unsigned char *p_tbaddr = (char *)0x80000; unsigned char *p_blockbuff = blockBuffer; block2Hts(block,&head,&track,§or); motorOn(); if (!read && blockBuffer) { /* copy data from data buffer into track buffer */ for (copyCount=0; copyCount<(numSectors*512); copyCount++) { *p_tbaddr = *p_blockbuff; p_blockbuff++; p_tbaddr++; } } for (tries = 0;tries < 3;tries++) { if (inportByte(fdcDir) & 0x80) { diskChange = TRUE; seek(1); /* clear "disk change" status */ recalibrate(); motorOff(); kprint("FDC: Disk change detected. Trying again.\n"); return fdcRw(block, blockBuffer, read, numSectors); } if (!seek(track)) { motorOff(); kprint("FDC: Error seeking to track\n"); return FALSE; } outportByte(fdcCcr,0); if (read) { dmaXfer(2,tbaddr,numSectors*512,FALSE); sendByte(cmdRead); } else { dmaXfer(2,tbaddr,numSectors*512,TRUE); sendByte(cmdWrite); } sendByte(head << 2); sendByte(track); sendByte(head); sendByte(sector); sendByte(2); /* 512 bytes/sector */ sendByte(geometry.spt); if (geometry.spt == dg144Spt) { sendByte(dg144Gap3rw); /* gap 3 size for 1.44M read/write */ } else { sendByte(dg168Gap3rw); /* gap 3 size for 1.68M read/write */ } sendByte(0xff); /* DTL = unused */ if (!waitFdc(TRUE)) { kprint("Timed out, trying operation again after reset()\n"); reset(); return fdcRw(block, blockBuffer, read, numSectors); } if ((status[0] & 0xc0) == 0) break; /* worked! outta here! */ recalibrate(); /* oops, try again... */ } motorOff(); if (read && blockBuffer) { p_blockbuff = blockBuffer; p_tbaddr = (char *) 0x80000; for (copyCount=0; copyCount<(numSectors*512); copyCount++) { *p_blockbuff = *p_tbaddr; p_blockbuff++; p_tbaddr++; } } return (tries != 3); } 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 motorOn(void) { if (!motor) { mTick = -1; /* stop motor kill countdown */ outportByte(fdcDor,0x1c); motor = TRUE; } } void motorOff(void) { if (motor) { mTick = 13500; } } bool seek(int track) { if (fdcTrack == track) { return(TRUE); } sendByte(cmdSeek); sendByte(0); sendByte(track); if (!waitFdc(TRUE)) { return(FALSE); } if ((sr0 != 0x20) || (fdcTrack != track)) { return(FALSE); } else { return(TRUE); } } bool readBlock(int block,byte *blockBuffer, unsigned long numSectors) { int track=0, sector=0, head=0, track2=0, result=0, loop=0; block2Hts(block, &head, &track, §or); block2Hts(block+numSectors, &head, &track2, §or); if (track!=track2) { for (loop=0; loop<numSectors; loop++) { result = fdcRw(block+loop, blockBuffer+(loop*512), TRUE, 1); } return result; } return fdcRw(block,blockBuffer,TRUE,numSectors); } bool writeBlock(int block,byte *blockBuffer, unsigned long numSectors) { return fdcRw(block,blockBuffer,FALSE, numSectors); } bool waitFdc(bool sensei) { timeOut = 50000; while (!done && timeOut); statSize = 0; while ((statSize < 7) && (inportByte(fdcMsr) & (1<<4))) { status[statSize++] = getByte(); } if (sensei) { sendByte(cmdSensei); sr0 = getByte(); fdcTrack = getByte(); } done = FALSE; if (!timeOut) { if (inportByte(fdcDir) & 0x80) { diskChange = TRUE; } return(FALSE); } else { return(TRUE); } } void recalibrate(void) { motorOn(); sendByte(cmdRecal); sendByte(0); waitFdc(TRUE); motorOff(); } void reset(void) { outportByte(fdcDor,0); mTick = 0; motor = FALSE; outportByte(fdcDrs,0); outportByte(fdcDor,0x0c); done = TRUE; waitFdc(TRUE); sendByte(cmdSpecify); sendByte(0xdf); sendByte(0x02); seek(1); recalibrate(); diskChange = FALSE; }