00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <isa/fdc.h>
00031 #include <isa/8259.h>
00032 #include <sys/video.h>
00033 #include <sys/gdt.h>
00034 #include <sys/idt.h>
00035 #include <ubixos/types.h>
00036 #include <ubixos/spinlock.h>
00037 #include <sys/io.h>
00038 #include <sys/dma.h>
00039 #include <sys/device.h>
00040 #include <lib/kprintf.h>
00041 #include <lib/kmalloc.h>
00042 #include <devfs/devfs.h>
00043
00044 static spinLock_t fdcSpinLock = SPIN_LOCK_INITIALIZER;
00045
00046 static volatile bool done = FALSE;
00047 static drvGeom geometry = { dg144Heads,dg144Tracks,dg144Spt };
00048 static bool diskChange = FALSE;
00049 static bool motor = FALSE;
00050 static volatile Int8 fdcTrack = 0xff;
00051 static Int8 sr0 = 0;
00052 static volatile int timeOut = 0;
00053 static Int8 statSize = 0;
00054 static Int8 status[7] = { 0 };
00055
00056 unsigned long tbaddr = 0x80000L;
00057
00058 int fdcInit2(struct device_node *dev) {
00059 dev->devInfo->size = (1024 * 1450);
00060 return(0x0);
00061 }
00062
00063 int fdc_init() {
00064 struct device_interface *devInfo = (struct device_interface *)kmalloc(sizeof(struct device_interface));
00065 setVector(floppyIsr, mVec+6, (dInt+dPresent));
00066 irqEnable(6);
00067 reset();
00068 devInfo->major = 0x0;
00069 devInfo->init = (void *)&fdcInit2;
00070 devInfo->read = fdcRead;
00071 devInfo->write = fdcWrite;
00072 devInfo->reset = (void *)reset;
00073
00074 device_add(0,'c',devInfo);
00075 devfs_makeNode("fd0",'b',0x0,0x0);
00076 return(0x0);
00077 }
00078
00079 asm(
00080 ".globl floppyIsr \n"
00081 "floppyIsr: \n"
00082 " pusha \n"
00083 " push %ss \n"
00084 " push %ds \n"
00085 " push %es \n"
00086 " push %fs \n"
00087 " push %gs \n"
00088 " call floppyIsrhndlr \n"
00089 " pop %gs \n"
00090 " pop %fs \n"
00091 " pop %es \n"
00092 " pop %ds \n"
00093 " pop %ss \n"
00094 " popa \n"
00095 " iret \n"
00096 );
00097
00098 void floppyIsrhndlr() {
00099 done = TRUE;
00100 outportByte(0x20,0x20);
00101 }
00102
00103 void sendByte(int Int8) {
00104 volatile int msr;
00105 int tmo;
00106 for (tmo=0;tmo<128;tmo++) {
00107 msr = inportByte(fdcMsr);
00108 if ((msr & 0xc0) == 0x80) {
00109 outportByte(fdcData,Int8);
00110 return;
00111 }
00112 inportByte(0x80);
00113 }
00114 }
00115
00116 int getByte() {
00117 volatile int msr;
00118 int tmo;
00119 for (tmo=0;tmo<128;tmo++) {
00120 msr = inportByte(fdcMsr);
00121 if ((msr & 0xd0) == 0xd0) {
00122 return inportByte(fdcData);
00123 }
00124 inportByte(0x80);
00125 }
00126 return(-1);
00127 }
00128
00129 bool fdcRw(int block,Int8 *blockBuffer,bool read,unsigned long numSectors) {
00130 int head = 0x0,track = 0x0,sector = 0x0,tries= 0x0, copyCount = 0x0;
00131 unsigned char *p_tbaddr = (char *)0x80000;
00132 unsigned char *p_blockbuff = blockBuffer;
00133
00134 block2Hts(block,&head,&track,§or);
00135 motorOn();
00136 if (!read && blockBuffer) {
00137
00138 for (copyCount=0; copyCount<(numSectors*512); copyCount++) {
00139 *p_tbaddr = *p_blockbuff;
00140 p_blockbuff++;
00141 p_tbaddr++;
00142 }
00143 }
00144 for (tries = 0;tries < 3;tries++) {
00145 if (inportByte(fdcDir) & 0x80) {
00146 diskChange = TRUE;
00147 seek(1);
00148 recalibrate();
00149 motorOff();
00150 kprint("FDC: Disk change detected. Trying again.\n");
00151 return fdcRw(block, blockBuffer, read, numSectors);
00152 }
00153 if (!seek(track)) {
00154 motorOff();
00155 kprintf("FDC: Error seeking to track [%i]\n",block);
00156 return FALSE;
00157 }
00158 outportByte(fdcCcr,0);
00159 if (read) {
00160 dmaXfer(2,tbaddr,numSectors*512,FALSE);
00161 sendByte(cmdRead);
00162 }
00163 else {
00164 dmaXfer(2,tbaddr,numSectors*512,TRUE);
00165 sendByte(cmdWrite);
00166 }
00167 sendByte(head << 2);
00168 sendByte(track);
00169 sendByte(head);
00170 sendByte(sector);
00171 sendByte(2);
00172 sendByte(geometry.spt);
00173 if (geometry.spt == dg144Spt) {
00174 sendByte(dg144Gap3rw);
00175 }
00176 else {
00177 sendByte(dg168Gap3rw);
00178 }
00179 sendByte(0xff);
00180 if (!waitFdc(TRUE)) {
00181 kprint("Timed out, trying operation again after reset()\n");
00182 reset();
00183 return fdcRw(block, blockBuffer, read, numSectors);
00184 }
00185 if ((status[0] & 0xc0) == 0) break;
00186 recalibrate();
00187 }
00188 motorOff();
00189 if (read && blockBuffer) {
00190 p_blockbuff = blockBuffer;
00191 p_tbaddr = (char *) 0x80000;
00192 for (copyCount=0x0; copyCount<(numSectors*512); copyCount++) {
00193 *p_blockbuff = *p_tbaddr;
00194 p_blockbuff++;
00195 p_tbaddr++;
00196 }
00197 }
00198 return (tries != 3);
00199 }
00200
00201 void block2Hts(int block,int *head,int *track,int *sector) {
00202 *head = (block % (geometry.spt * geometry.heads)) / (geometry.spt);
00203 *track = block / (geometry.spt * geometry.heads);
00204 *sector = block % geometry.spt + 1;
00205 }
00206
00207 void motorOn(void) {
00208 if (motor == FALSE) {
00209 outportByte(fdcDor,0x1c);
00210 motor = TRUE;
00211 }
00212 }
00213
00214 void motorOff(void) {
00215 if (motor == TRUE) {
00216
00217
00218 motor = FALSE;
00219 }
00220 }
00221
00222 bool seek(int track) {
00223 if (fdcTrack == track) {
00224 return(TRUE);
00225 }
00226 sendByte(cmdSeek);
00227 sendByte(0);
00228 sendByte(track);
00229 if (!waitFdc(TRUE)) {
00230 kprintf("wait fdc failed\n");
00231 return(FALSE);
00232 }
00233 if ((sr0 != 0x20) || (fdcTrack != track)) {
00234 return(FALSE);
00235 }
00236 else {
00237 return(TRUE);
00238 }
00239 }
00240
00241 bool readBlock(int block,Int8 *blockBuffer, unsigned long numSectors) {
00242 int result = 0x0,loop = 0x0;
00243 if (numSectors > 1) {
00244 for (loop=0; loop<numSectors; loop++) {
00245 result = fdcRw(block+loop, blockBuffer+(loop*512), TRUE, 1);
00246 }
00247 return result;
00248 }
00249 return fdcRw(block,blockBuffer,TRUE,numSectors);
00250 }
00251
00252 bool writeBlock(int block,Int8 *blockBuffer, unsigned long numSectors) {
00253 return fdcRw(block,blockBuffer,FALSE, numSectors);
00254 }
00255
00256 bool waitFdc(bool sensei) {
00257 timeOut = 50000;
00258 while (!done && timeOut);
00259 statSize = 0;
00260 while ((statSize < 7) && (inportByte(fdcMsr) & (1<<4))) {
00261 status[(int)statSize++] = getByte();
00262 }
00263 if (sensei) {
00264 sendByte(cmdSensei);
00265 sr0 = getByte();
00266 fdcTrack = getByte();
00267 }
00268 done = FALSE;
00269 if (!timeOut) {
00270 if (inportByte(fdcDir) & 0x80) {
00271 diskChange = TRUE;
00272 }
00273 return(FALSE);
00274 }
00275 else {
00276 return(TRUE);
00277 }
00278 }
00279
00280 void recalibrate(void) {
00281 motorOn();
00282 sendByte(cmdRecal);
00283 sendByte(0);
00284 waitFdc(TRUE);
00285 motorOff();
00286 }
00287
00288 void reset(void) {
00289 outportByte(fdcDor,0);
00290 motor = FALSE;
00291 outportByte(fdcDor,0x0c);
00292 done = TRUE;
00293 waitFdc(TRUE);
00294 sendByte(cmdSpecify);
00295 sendByte(0xdf);
00296 sendByte(0x02);
00297 seek(1);
00298 recalibrate();
00299 diskChange = FALSE;
00300 return;
00301 }
00302
00303 void fdcRead(void *info,void *baseAddr,uInt32 startSector,uInt32 sectorCount) {
00304 spinLock(&fdcSpinLock);
00305 readBlock(startSector,baseAddr,sectorCount);
00306 spinUnlock(&fdcSpinLock);
00307 return;
00308 }
00309 void fdcWrite(void *info,void *baseAddr,uInt32 startSector,uInt32 sectorCount){
00310 writeBlock(startSector,baseAddr,sectorCount);
00311 return;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414