00001
00002
00003
00004
00005
00006
00007
00008 #include <const.h>
00009
00010 #include <arch/i386.h>
00011 #include <arch/interrupt.h>
00012 #include <arch/mem.h>
00013 #include <arch/paging.h>
00014
00015 #include <kernel/clock.h>
00016 #include <kernel/console.h>
00017 #include <kernel/dma.h>
00018 #include <kernel/task.h>
00019
00020 #include <kernel/floppy.h>
00021
00022
00023
00024
00025
00026
00027
00028
00029 volatile bool fdc_motor = FALSE;
00030
00031
00032 volatile int fdc_timeout = 0;
00033
00034
00035 volatile int fdc_motor_countdown=0;
00036
00037
00038 volatile bool fdc_done = FALSE;
00039
00040
00041 volatile bool fdc_change = FALSE;
00042
00043
00044 volatile byte fdc_status[7] = { 0 };
00045
00046
00047 volatile byte fdc_track = 0xFF;
00048
00049
00050 volatile byte ST0 = 0;
00051
00052
00053 static floppy_struct floppy_type[] = {
00054 { 2880, 18, 2, 80, 0x54, 0x1B, 0x00, "H1440" },
00055 { 3360, 21, 2, 80, 0x0C, 0x1C, 0x00, "H1680" }
00056 };
00057
00058
00059 byte fdc_geometry = 0;
00060
00061
00062 byte *fdc_buffer;
00063
00064
00065
00066
00067
00068 void fdc_sendbyte(byte b)
00069 {
00070 int msr;
00071 int tmo;
00072
00073 for (tmo=0; tmo<128; tmo++)
00074 {
00075 msr = inportb(FDC_MSR);
00076 if ((msr & 0xC0) == 0x80)
00077 {
00078 outportb(FDC_DATA, b);
00079 return;
00080 }
00081 inportb(0x80);
00082 }
00083 }
00084
00085
00086
00087
00088 int fdc_getbyte()
00089 {
00090 int msr;
00091 int tmo;
00092
00093 for (tmo=0; tmo<128; tmo++)
00094 {
00095 msr = inportb(FDC_MSR);
00096 if ((msr & 0xD0) == 0xD0)
00097 return(inportb(FDC_DATA));
00098 inportb(0x80);
00099 }
00100 return(-1);
00101 }
00102
00103
00104 void fdc_motor_on()
00105 {
00106 if (!fdc_motor)
00107 {
00108 outportb(FDC_DOR, 0x1C);
00109 delay(FDC_TIME_MOTOR_SPINUP);
00110 fdc_motor = TRUE;
00111 }
00112 fdc_motor_countdown = -1;
00113 }
00114
00115
00116 void fdc_motor_off()
00117 {
00118 if (fdc_motor && (fdc_motor_countdown==-1))
00119 fdc_motor_countdown = FDC_TIME_MOTOR_OFF/1000*HZ;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 bool fdc_wait(bool sensei)
00137 {
00138 byte i;
00139
00140 fdc_timeout = HZ;
00141
00142
00143 while((!fdc_done) && (fdc_timeout))
00144 {
00145 enable();
00146 idle();
00147 }
00148
00149
00150 i = 0;
00151 while ((i < 7) && (inportb(FDC_MSR) & MSR_BUSY))
00152 fdc_status[i++] = fdc_getbyte();
00153
00154
00155 if (sensei)
00156 {
00157 fdc_sendbyte(CMD_SENSEI);
00158 ST0 = fdc_getbyte();
00159 fdc_track = fdc_getbyte();
00160 }
00161
00162
00163 if (!fdc_done)
00164 {
00165
00166 if (inportb(FDC_DIR) & 0x80)
00167 fdc_change = TRUE;
00168 return(FALSE);
00169 }
00170 else
00171 {
00172 fdc_done = FALSE;
00173 return(TRUE);
00174 }
00175 }
00176
00177
00178 void fdc_recalibrate()
00179 {
00180
00181 fdc_motor_on();
00182
00183
00184 fdc_sendbyte(CMD_RECAL);
00185 fdc_sendbyte(0);
00186
00187
00188 fdc_wait(TRUE);
00189
00190
00191 fdc_motor_off();
00192 }
00193
00194
00195
00196
00197
00198
00199 bool fdc_seek(int track)
00200 {
00201
00202 if (fdc_track == track)
00203 return(TRUE);
00204
00205
00206 fdc_motor_on();
00207
00208
00209 fdc_sendbyte(CMD_SEEK);
00210 fdc_sendbyte(0);
00211 fdc_sendbyte(track);
00212
00213
00214 if (!fdc_wait(TRUE))
00215 {
00216
00217 fdc_motor_off();
00218 return(FALSE);
00219 }
00220
00221
00222 delay(15);
00223
00224
00225 fdc_motor_off();
00226
00227
00228 if ((ST0 != 0x20) || (fdc_track != track))
00229 return(FALSE);
00230 else
00231 return(TRUE);
00232 }
00233
00234
00235 void fdc_reset()
00236 {
00237
00238 outportb(FDC_DOR, 0x00);
00239
00240
00241 outportb(FDC_DSR, 0x00);
00242
00243
00244 outportb(FDC_DOR, 0x0C);
00245
00246
00247 fdc_done = TRUE;
00248 fdc_wait(TRUE);
00249
00250
00251 fdc_sendbyte(CMD_SPECIFY);
00252 fdc_sendbyte(0xDF);
00253 fdc_sendbyte(0x02);
00254
00255
00256 fdc_seek(1);
00257 fdc_recalibrate();
00258 fdc_change = FALSE;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268 void lba2chs(int lba, int *track, int *head, int *sector)
00269 {
00270 *track = lba / (floppy_type[fdc_geometry].spt * floppy_type[fdc_geometry].heads);
00271 *head = (lba / floppy_type[fdc_geometry].spt) % floppy_type[fdc_geometry].heads;
00272 *sector = (lba % floppy_type[fdc_geometry].spt) + 1;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 bool fdc_rw(int block, byte *buffer, bool do_read)
00290 {
00291 int track, head, sector, tries;
00292
00293
00294 lba2chs(block, &track, &head, §or);
00295
00296
00297 fdc_motor_on();
00298
00299 if (!do_read)
00300
00301 memcpy(fdc_buffer, buffer, FDC_SECTOR_SIZE);
00302
00303 for(tries=0; tries<3; tries++)
00304 {
00305
00306 if (inportb(FDC_DIR) & 0x80)
00307 {
00308 fdc_change = TRUE;
00309 fdc_seek(1);
00310 fdc_recalibrate();
00311 fdc_motor_off();
00312 return(FALSE);
00313 }
00314
00315 if (!fdc_seek(track))
00316 {
00317 fdc_motor_off();
00318 return(FALSE);
00319 }
00320
00321 outportb(FDC_CCR, floppy_type[fdc_geometry].rate);
00322
00323
00324 if (do_read)
00325 {
00326
00327 dma_xfer(2, (dword)fdc_buffer, FDC_SECTOR_SIZE, FALSE);
00328 fdc_sendbyte(CMD_READ);
00329 }
00330 else
00331 {
00332
00333 dma_xfer(2, (dword)fdc_buffer, FDC_SECTOR_SIZE, TRUE);
00334 fdc_sendbyte(CMD_WRITE);
00335 }
00336 fdc_sendbyte(head << 2);
00337 fdc_sendbyte(track);
00338 fdc_sendbyte(head);
00339 fdc_sendbyte(sector);
00340 fdc_sendbyte(2);
00341 fdc_sendbyte(floppy_type[fdc_geometry].spt);
00342 fdc_sendbyte(floppy_type[fdc_geometry].rwgap);
00343 fdc_sendbyte(0xFF);
00344
00345
00346 if (!fdc_wait(FALSE))
00347 return(FALSE);
00348
00349 if ((fdc_status[0] & 0xC0) == 0) break;
00350
00351
00352 fdc_recalibrate();
00353 }
00354
00355
00356 fdc_motor_off();
00357
00358 if (do_read)
00359
00360 memcpy(buffer, fdc_buffer, FDC_SECTOR_SIZE);
00361
00362
00363 return(tries != 3);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 bool fdc_read(int block, byte *buffer, uint32_t count)
00377 {
00378 register int i;
00379
00380 for(i=0; i<count; i++)
00381 if (!(fdc_rw(block+i, buffer+(FDC_SECTOR_SIZE*i), TRUE)))
00382 return(FALSE);
00383
00384 return(TRUE);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 bool fdc_write(int block, byte *buffer, uint32_t count)
00397 {
00398 register int i;
00399
00400 for(i=0; i<count; i++)
00401 if (!(fdc_rw(block+i, buffer+(FDC_SECTOR_SIZE*i), FALSE)))
00402 return(FALSE);
00403
00404 return(TRUE);
00405 }
00406
00407
00408
00409
00410
00411 bool fdc_is_changed()
00412 {
00413 return(fdc_change);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 void floppy_thread()
00423 {
00424 if (fdc_timeout > 0)
00425 fdc_timeout--;
00426
00427 if (fdc_motor_countdown > 0)
00428 fdc_motor_countdown--;
00429 else if (fdc_motor && !fdc_motor_countdown)
00430 {
00431 outportb(FDC_DOR, 0x0C);
00432 fdc_motor = FALSE;
00433 }
00434 }
00435
00436
00437
00438
00439
00440 void floppy_handler()
00441 {
00442 fdc_done = TRUE;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 bool init_floppy()
00452 {
00453 int v;
00454
00455
00456 install_irq_handler( FLOPPY_IRQ, (void *)floppy_handler );
00457
00458
00459 fdc_buffer = PHYSICAL( dma_phys_alloc(PAGE_SIZE) );
00460
00461
00462 fdc_reset();
00463
00464
00465 fdc_sendbyte(CMD_VERSION);
00466 v = fdc_getbyte();
00467
00468 switch ( v )
00469 {
00470 case 0xFF:
00471 return( FALSE );
00472 break;
00473
00474 case 0x90:
00475 kprintf("\n\rEnhanced controller found!");
00476 return( TRUE );
00477 break;
00478
00479 default:
00480 kprintf("\n\r8272A/765A controller found! (cmd_version=%02X)", v);
00481 return( TRUE );
00482 break;
00483 }
00484 }
00485
00486