Fork me on GitHub

root/drivers/block/floppy.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fdc_in
  2. fdc_out
  3. fdc_get_results
  4. fdc_motor_on
  5. do_motor_off
  6. fdc_motor_off
  7. fdc_reset
  8. fdc_recalibrate
  9. fdc_seek
  10. fdc_get_chip
  11. fdc_block2chs
  12. set_current_fdd_type
  13. irq_floppy
  14. fdc_timer
  15. fdc_open
  16. fdc_close
  17. fdc_read
  18. fdc_write
  19. fdc_ioctl
  20. fdc_lseek
  21. floppy_init

   1 /*
   2  * fiwix/drivers/block/floppy.c
   3  *
   4  * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/floppy.h>
  10 #include <fiwix/ioctl.h>
  11 #include <fiwix/devices.h>
  12 #include <fiwix/part.h>
  13 #include <fiwix/fs.h>
  14 #include <fiwix/buffer.h>
  15 #include <fiwix/sleep.h>
  16 #include <fiwix/timer.h>
  17 #include <fiwix/sched.h>
  18 #include <fiwix/errno.h>
  19 #include <fiwix/pic.h>
  20 #include <fiwix/cmos.h>
  21 #include <fiwix/dma.h>
  22 #include <fiwix/stdio.h>
  23 #include <fiwix/string.h>
  24 
  25 #define WAIT_MOTOR_OFF  (3 * HZ)        /* time waiting to turn the motor off */
  26 #define WAIT_FDC        WAIT_MOTOR_OFF
  27 
  28 #define INVALID_TRACK   -1
  29 
  30 #define DEV_TYPE_SHIFT  2               /* right shift to match with the floppy
  31                                            type when minor > 3 */
  32 
  33 static int need_reset = 0;
  34 static int fdc_wait_interrupt = 0;
  35 static int fdc_timeout = 0;
  36 static unsigned char fdc_results[MAX_FDC_RESULTS];
  37 static struct resource floppy_resource = { NULL, NULL };
  38 
  39 static struct fddt fdd_type[] = {
  40 /*
  41  * R (data rate): 0 = 500Kb/s, 2 = 250Kb/s, 3 = 1Mb/s
  42  * SPEC(IFY) 0xAF: SRT = 6ms, HUT = 240ms (500Kb/s)
  43  * SPEC(IFY) 0xD7: SRT = 6ms, HUT = 240ms (250Kb/s)
  44  * SPEC(IFY) 0xDF: SRT = 3ms, HUT = 240ms (500Kb/s)
  45  * Head Load Time 0x02: HLT = 4ms (500Kb/s), Non-DMA = 0 (DMA enabled)
  46  *
  47  *        SIZE    KB   T   S  H  G_RW  G_FM  R  SPEC  HLT   NAME
  48  *        ---------------------------------------------------------------- */
  49         {    0,    0,  0,  0, 0, 0x00, 0x00, 0, 0x00, 0x00, NULL           },
  50         {  720,  360, 40,  9, 2, 0x2A, 0x50, 2, 0xD7, 0x02, "360KB 5.25\"" },
  51         { 2400, 1200, 80, 15, 2, 0x2A, 0x50, 0, 0xAF, 0x02, "1.2MB 5.25\"" },
  52         { 1440,  720, 80,  9, 2, 0x1B, 0x54, 2, 0xD7, 0x02, "720KB 3.5\""  },
  53         { 2880, 1440, 80, 18, 2, 0x1B, 0x54, 0, 0xAF, 0x02, "1.44MB 3.5\"" },
  54 /*      { 5760, 2880, 80, 36, 2, 0x38, 0x53, 3, 0xDF, 0x02, "2.88MB 3.5\"" },*/
  55 };
  56 
  57 /* buffer area used for I/O operations (1KB) */
  58 char fdc_transfer_area[BPS * 2];
  59 
  60 struct fdd_status {
  61         char type;              /* floppy disk drive type */
  62         char motor;
  63         char recalibrated;
  64         char current_track;
  65 };
  66 
  67 static struct fdd_status fdd_status[] = {
  68         { 0, 0, 0, INVALID_TRACK },
  69         { 0, 0, 0, INVALID_TRACK },
  70 };
  71 
  72 static unsigned char current_fdd = 0;
  73 static struct fddt *current_fdd_type;
  74 static unsigned int fdd_sizes[256];
  75 
  76 static struct fs_operations fdc_driver_fsop = {
  77         0,
  78         0,
  79 
  80         fdc_open,
  81         fdc_close,
  82         NULL,                   /* read */
  83         NULL,                   /* write */
  84         fdc_ioctl,
  85         fdc_lseek,
  86         NULL,                   /* readdir */
  87         NULL,                   /* mmap */
  88         NULL,                   /* select */
  89 
  90         NULL,                   /* readlink */
  91         NULL,                   /* followlink */
  92         NULL,                   /* bmap */
  93         NULL,                   /* lockup */
  94         NULL,                   /* rmdir */
  95         NULL,                   /* link */
  96         NULL,                   /* unlink */
  97         NULL,                   /* symlink */
  98         NULL,                   /* mkdir */
  99         NULL,                   /* mknod */
 100         NULL,                   /* truncate */
 101         NULL,                   /* create */
 102         NULL,                   /* rename */
 103 
 104         fdc_read,
 105         fdc_write,
 106 
 107         NULL,                   /* read_inode */
 108         NULL,                   /* write_inode */
 109         NULL,                   /* ialloc */
 110         NULL,                   /* ifree */
 111         NULL,                   /* statfs */
 112         NULL,                   /* read_superblock */
 113         NULL,                   /* remount_fs */
 114         NULL,                   /* write_superblock */
 115         NULL                    /* release_superblock */
 116 };
 117 
 118 static struct device floppy_device = {
 119         "floppy",
 120         FDC_MAJOR,
 121         { 0, 0, 0, 0, 0, 0, 0, 0 },
 122         BLKSIZE_1K,
 123         &fdd_sizes,
 124         &fdc_driver_fsop,
 125         NULL
 126 };
 127 
 128 static struct interrupt irq_config_floppy = { 0, "floppy", &irq_floppy, NULL };
 129 
 130 static int fdc_in(void)
 131 {
 132         int n;
 133         unsigned char status;
 134 
 135         if(need_reset) {
 136                 return -1;
 137         }
 138 
 139         for(n = 0; n < 10000; n++) {
 140                 status = inport_b(FDC_MSR) & (FDC_RQM | FDC_DIO);
 141                 if(status == FDC_RQM) {
 142                         return 0;
 143                 }
 144                 if(status == (FDC_RQM | FDC_DIO)) {
 145                         return inport_b(FDC_DATA);
 146                 }
 147         }
 148         need_reset = 1;
 149         printk("WARNING: %s(): fd%d: timeout on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 150         return -1;
 151 }
 152 
 153 static void fdc_out(unsigned char value)
 154 {
 155         int n;
 156         unsigned char status;
 157 
 158         if(need_reset) {
 159                 return;
 160         }
 161 
 162         for(n = 0; n < 10000; n++) {
 163                 status = inport_b(FDC_MSR) & (FDC_RQM | FDC_DIO);
 164                 if(status == FDC_RQM) {
 165                         outport_b(FDC_DATA, value);
 166                         return;
 167                 }
 168         }
 169 
 170         need_reset = 1;
 171         printk("WARNING: %s(): fd%d: unable to send byte 0x%x on %s.\n", __FUNCTION__, current_fdd, value, floppy_device.name);
 172 }
 173 
 174 static void fdc_get_results(void)
 175 {
 176         int n;
 177 
 178         memset_b(fdc_results, 0, sizeof(fdc_results));
 179         for(n = 0; n < MAX_FDC_RESULTS; n++) {
 180                 fdc_results[n] = fdc_in();
 181         }
 182         return;
 183 }
 184 
 185 static int fdc_motor_on(void)
 186 {
 187         struct callout_req creq;
 188         int errno;
 189 
 190         if(fdd_status[current_fdd].motor) {
 191                 return 0;
 192         }
 193 
 194         /* select floppy disk drive and turn on its motor */
 195         outport_b(FDC_DOR, (FDC_DRIVE0 << current_fdd) | FDC_DMA_ENABLE | FDC_ENABLE | current_fdd);
 196         fdd_status[current_fdd].motor = 1;
 197         fdd_status[!current_fdd].motor = 0;
 198 
 199         /* fixed spin-up time of 500ms for 3.5" and 5.25" */
 200         creq.fn = fdc_timer;
 201         creq.arg = FDC_TR_MOTOR;
 202         add_callout(&creq, HZ / 2);
 203         sleep(&fdc_motor_on, PROC_UNINTERRUPTIBLE);
 204 
 205         errno = 0;
 206 
 207         /* check for a disk change */
 208         if(inport_b(FDC_DIR) & 0x80) {
 209                 errno = 1;
 210         }
 211 
 212         return errno;
 213 }
 214 
 215 static void do_motor_off(unsigned int fdd)
 216 {
 217         outport_b(FDC_DOR, FDC_DMA_ENABLE | FDC_ENABLE | fdd);
 218         fdd_status[fdd].motor = 0;
 219         fdd_status[0].motor = fdd_status[1].motor = 0;
 220 }
 221 
 222 static void fdc_motor_off(void)
 223 {
 224         struct callout_req creq;
 225 
 226         creq.fn = do_motor_off;
 227         creq.arg = current_fdd;
 228         add_callout(&creq, WAIT_FDC);
 229 }
 230 
 231 static void fdc_reset(void)
 232 {
 233         int n;
 234         struct callout_req creq;
 235 
 236         need_reset = 0;
 237 
 238         fdc_wait_interrupt = FDC_RESET;
 239         outport_b(FDC_DOR, 0);                  /* enter in reset mode */
 240 /*      outport_b(FDC_DOR, FDC_DMA_ENABLE); */
 241         for(n = 0; n < 1000; n++) {             /* recovery time */
 242                 NOP();
 243         }
 244         outport_b(FDC_DOR, FDC_DMA_ENABLE | FDC_ENABLE);
 245 
 246         creq.fn = fdc_timer;
 247         creq.arg = FDC_TR_DEFAULT;
 248         add_callout(&creq, WAIT_FDC);
 249         /* avoid sleep if interrupt already happened */
 250         if(fdc_wait_interrupt) {
 251                 sleep(&irq_floppy, PROC_UNINTERRUPTIBLE);
 252         }
 253         if(fdc_timeout) {
 254                 need_reset = 1;
 255                 printk("WARNING: %s(): fd%d: timeout on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 256         }
 257         del_callout(&creq);
 258 
 259         fdd_status[0].motor = fdd_status[1].motor = 0;
 260         fdd_status[current_fdd].recalibrated = 0;
 261 
 262         /* assumes drive polling mode is ON (by default) */
 263         for(n = 0; n < 4; n++) {
 264                 fdc_out(FDC_SENSEI);
 265                 fdc_get_results();
 266         }
 267 
 268         /* keeps controller informed on the drive about to use */
 269         fdc_out(FDC_SPECIFY);
 270         fdc_out(current_fdd_type->spec);
 271         fdc_out(current_fdd_type->hlt);
 272 
 273         /* set data rate */
 274         outport_b(FDC_CCR, current_fdd_type->rate);
 275 }
 276 
 277 static int fdc_recalibrate(void)
 278 {
 279         struct callout_req creq;
 280 
 281         if(need_reset) {
 282                 return 1;
 283         }
 284 
 285         fdc_wait_interrupt = FDC_RECALIBRATE;
 286         fdc_motor_on();
 287         fdc_out(FDC_RECALIBRATE);
 288         fdc_out(current_fdd);
 289 
 290         if(need_reset) {
 291                 return 1;
 292         }
 293 
 294         creq.fn = fdc_timer;
 295         creq.arg = FDC_TR_DEFAULT;
 296         add_callout(&creq, WAIT_FDC);
 297         /* avoid sleep if interrupt already happened */
 298         if(fdc_wait_interrupt) {
 299                 sleep(&irq_floppy, PROC_UNINTERRUPTIBLE);
 300         }
 301         if(fdc_timeout) {
 302                 need_reset = 1;
 303                 printk("WARNING: %s(): fd%d: timeout on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 304                 return 1;
 305         }
 306 
 307         del_callout(&creq);
 308         fdc_out(FDC_SENSEI);
 309         fdc_get_results();
 310 
 311         /* PCN must be 0 indicating a successful position to track 0 */
 312         if((fdc_results[ST0] & (ST0_IC | ST0_SE | ST0_UC | ST0_NR)) != ST0_RECALIBRATE || fdc_results[ST_PCN]) {
 313                 need_reset = 1;
 314                 printk("WARNING: %s(): fd%d: unable to recalibrate on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 315                 return 1;
 316         }
 317 
 318         fdd_status[current_fdd].current_track = INVALID_TRACK;
 319         fdd_status[current_fdd].recalibrated = 1;
 320         fdc_motor_off();
 321         return 0;
 322 }
 323 
 324 static int fdc_seek(int track, int head)
 325 {
 326         struct callout_req creq;
 327 
 328         if(need_reset) {
 329                 return 1;
 330         }
 331 
 332         if(!fdd_status[current_fdd].recalibrated) {
 333                 if(fdc_recalibrate()) {
 334                         return 1;
 335                 }
 336         }
 337 
 338         if(fdd_status[current_fdd].current_track == track) {
 339                 return 0;
 340         }
 341 
 342         fdc_wait_interrupt = FDC_SEEK;
 343         fdc_motor_on();
 344         fdc_out(FDC_SEEK);
 345         fdc_out((head << 2) | current_fdd);
 346         fdc_out(track);
 347 
 348         if(need_reset) {
 349                 return 1;
 350         }
 351 
 352         creq.fn = fdc_timer;
 353         creq.arg = FDC_TR_DEFAULT;
 354         add_callout(&creq, WAIT_FDC);
 355         /* avoid sleep if interrupt already happened */
 356         if(fdc_wait_interrupt) {
 357                 sleep(&irq_floppy, PROC_UNINTERRUPTIBLE);
 358         }
 359         if(fdc_timeout) {
 360                 need_reset = 1;
 361                 printk("WARNING: %s(): fd%d: timeout on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 362                 return 1;
 363         }
 364 
 365         del_callout(&creq);
 366         fdc_out(FDC_SENSEI);
 367         fdc_get_results();
 368 
 369         if((fdc_results[ST0] & (ST0_IC | ST0_SE | ST0_UC | ST0_NR)) != ST0_SEEK || fdc_results[ST_PCN] != track) {
 370                 need_reset = 1;
 371                 printk("WARNING: %s(): fd%d: unable to seek on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 372                 return 1;
 373         }
 374 
 375         fdc_motor_off();
 376         fdd_status[current_fdd].current_track = track;
 377         return 0;
 378 }
 379 
 380 static int fdc_get_chip(void)
 381 {
 382         unsigned char version, fifo, id;
 383 
 384         fdc_out(FDC_VERSION);
 385         version = fdc_in();
 386         fdc_out(FDC_LOCK);
 387         fifo = fdc_in();
 388         fdc_out(FDC_PARTID);
 389         id = fdc_in();
 390 
 391         if(version == 0x80) {
 392                 if(fifo == 0x80) {
 393                         printk("(NEC D765/Intel 8272A/compatible)\n");
 394                         return 0;
 395                 }
 396                 if(fifo == 0) {
 397                         printk("(Intel 82072)\n");
 398                         return 0;
 399                 }
 400         }
 401 
 402         if(version == 0x81) {
 403                 printk("(Very Early Intel 82077/compatible)\n");
 404                 return 0;
 405         }
 406 
 407         if(version == 0x90) {
 408                 if(fifo == 0x80) {
 409                         printk("(Old Intel 82077, no FIFO)\n");
 410                         return 0;
 411                 }
 412                 if(fifo == 0) {
 413                         if(id == 0x80) {
 414                                 printk("(New Intel 82077)\n");
 415                                 return 0;
 416                         }
 417                         if(id == 0x41) {
 418                                 printk("(Intel 82078)\n");
 419                                 return 0;
 420                         }
 421                         if(id == 0x73) {
 422                                 printk("(National Semiconductor PC87306)\n");
 423                                 return 0;
 424                         }
 425                         printk("(Intel 82078 compatible)\n");
 426                         return 0;
 427                 }
 428                 printk("(NEC 72065B)\n");
 429                 return 0;
 430         }
 431 
 432         if(version == 0xA0) {
 433                 printk("(SMC FDC37c65C+)\n");
 434                 return 0;
 435         }
 436         printk("(unknown controller chip)\n");
 437         return 1;
 438 }
 439 
 440 static int fdc_block2chs(__blk_t block, int blksize, int *cyl, int *head, int *sector)
 441 {
 442         int spb = blksize / FDC_SECTSIZE;
 443 
 444         *cyl = (block * spb) / (current_fdd_type->spt * current_fdd_type->heads);
 445         *head = ((block * spb) % (current_fdd_type->spt * current_fdd_type->heads)) / current_fdd_type->spt;
 446         *sector = (((block * spb) % (current_fdd_type->spt * current_fdd_type->heads)) % current_fdd_type->spt) + 1;
 447 
 448         if(*cyl >= current_fdd_type->tracks || *head >= current_fdd_type->heads || *sector > current_fdd_type->spt) {
 449                 return 1;
 450         }
 451 
 452         return 0;
 453 }
 454 
 455 static void set_current_fdd_type(int minor)
 456 {
 457         current_fdd = minor & 1;
 458 
 459         /* minors 0 and 1 are directly assigned */
 460         if(minor < 2) {
 461                 current_fdd_type = &fdd_type[(int)fdd_status[current_fdd].type];
 462         } else {
 463                 current_fdd_type = &fdd_type[minor >> DEV_TYPE_SHIFT];
 464         }
 465 }
 466 
 467 void irq_floppy(int num, struct sigcontext *sc)
 468 {
 469         if(!fdc_wait_interrupt) {
 470                 printk("WARNING: %s(): fd%d: unexpected interrupt on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 471                 need_reset = 1;
 472         } else {
 473                 fdc_timeout = fdc_wait_interrupt = 0;
 474                 wakeup(&irq_floppy);
 475         }
 476 }
 477 
 478 void fdc_timer(unsigned int reason)
 479 {
 480         switch(reason) {
 481                 case FDC_TR_DEFAULT:
 482                         fdc_timeout = 1;
 483                         fdc_wait_interrupt = 0;
 484                         wakeup(&irq_floppy);
 485                         break;
 486                 case FDC_TR_MOTOR:
 487                         wakeup(&fdc_motor_on);
 488                         break;
 489         }
 490 }
 491 
 492 int fdc_open(struct inode *i, struct fd *fd_table)
 493 {
 494         unsigned char minor;
 495 
 496         minor = MINOR(i->rdev);
 497         if(!TEST_MINOR(floppy_device.minors, minor)) {
 498                 return -ENXIO;
 499         }
 500 
 501         lock_resource(&floppy_resource);
 502         set_current_fdd_type(minor);
 503         unlock_resource(&floppy_resource);
 504 
 505         return 0;
 506 }
 507 
 508 int fdc_close(struct inode *i, struct fd *fd_table)
 509 {
 510         unsigned char minor;
 511 
 512         minor = MINOR(i->rdev);
 513         if(!TEST_MINOR(floppy_device.minors, minor)) {
 514                 return -ENXIO;
 515         }
 516 
 517         lock_resource(&floppy_resource);
 518         set_current_fdd_type(minor);
 519         unlock_resource(&floppy_resource);
 520 
 521         return 0;
 522 }
 523 
 524 int fdc_read(__dev_t dev, __blk_t block, char *buffer, int blksize)
 525 {
 526         unsigned char minor;
 527         unsigned int sectors_read;
 528         int cyl, head, sector;
 529         int retries;
 530         struct callout_req creq;
 531         struct device *d;
 532 
 533         minor = MINOR(dev);
 534         if(!TEST_MINOR(floppy_device.minors, minor)) {
 535                 return -ENXIO;
 536         }
 537 
 538         if(!blksize) {
 539                 if(!(d = get_device(BLK_DEV, dev))) {
 540                         return -EINVAL;
 541                 }
 542                 blksize = d->blksize;
 543         }
 544         blksize = blksize ? blksize : BLKSIZE_1K;
 545 
 546         lock_resource(&floppy_resource);
 547         set_current_fdd_type(minor);
 548 
 549         if(fdc_block2chs(block, blksize, &cyl, &head, &sector)) {
 550                 printk("WARNING: %s(): fd%d: invalid block number %d on %s device %d,%d.\n", __FUNCTION__, current_fdd, block, floppy_device.name, MAJOR(dev), MINOR(dev));
 551                 unlock_resource(&floppy_resource);
 552                 return -EINVAL;
 553         }
 554 
 555         for(retries = 0; retries < MAX_FDC_ERR; retries++) {
 556                 if(need_reset) {
 557                         fdc_reset();
 558                 }
 559                 if(fdc_motor_on()) {
 560                         printk("%s(): %s disk was changed in device %d,%d!\n", __FUNCTION__, floppy_device.name, MAJOR(dev), MINOR(dev));
 561                         invalidate_buffers(dev);
 562                         fdd_status[current_fdd].recalibrated = 0;
 563                 }
 564 
 565                 if(fdc_seek(cyl, head)) {
 566                         printk("WARNING: %s(): fd%d: seek error on %s device %d,%d during read operation.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 567                         continue;
 568                 }
 569 
 570                 start_dma(FLOPPY_DMA, fdc_transfer_area, blksize, DMA_MODE_WRITE | DMA_MODE_SINGLE);
 571 
 572                 /* send READ command */
 573                 fdc_wait_interrupt = FDC_READ;
 574                 fdc_out(FDC_READ);
 575                 fdc_out((head << 2) | current_fdd);
 576                 fdc_out(cyl);
 577                 fdc_out(head);
 578                 fdc_out(sector);
 579                 fdc_out(2);     /* sector size is 512 bytes */
 580                 fdc_out(current_fdd_type->spt);
 581                 fdc_out(current_fdd_type->gpl1);
 582                 fdc_out(0xFF);  /* sector size is 512 bytes */
 583 
 584                 if(need_reset) {
 585                         printk("WARNING: %s(): fd%d: needs reset on %s device %d,%d during read operation.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 586                         continue;
 587                 }
 588                 creq.fn = fdc_timer;
 589                 creq.arg = FDC_TR_DEFAULT;
 590                 add_callout(&creq, WAIT_FDC);
 591                 /* avoid sleep if interrupt already happened */
 592                 if(fdc_wait_interrupt) {
 593                         sleep(&irq_floppy, PROC_UNINTERRUPTIBLE);
 594                 }
 595                 if(fdc_timeout) {
 596                         need_reset = 1;
 597                         printk("WARNING: %s(): fd%d: timeout on %s device %d,%d.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 598                         continue;
 599                 }
 600                 del_callout(&creq);
 601                 fdc_get_results();
 602                 if(fdc_results[ST0] & (ST0_IC | ST0_UC | ST0_NR)) {
 603                         need_reset = 1;
 604                         continue;
 605                 }
 606                 break;
 607         }
 608 
 609         if(retries >= MAX_FDC_ERR) {
 610                 printk("WARNING: %s(): fd%d: error on %s device %d,%d during read operation,\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 611                 printk("\tblock=%d, sector=%d, cylinder/head=%d/%d\n", block, sector, cyl, head);
 612                 unlock_resource(&floppy_resource);
 613                 fdc_motor_off();
 614                 return -EIO;
 615         }
 616 
 617         fdc_motor_off();
 618         sectors_read = (fdc_results[ST_CYL] - cyl) * (current_fdd_type->heads * current_fdd_type->spt);
 619         sectors_read += (fdc_results[ST_HEAD] - head) * current_fdd_type->spt;
 620         sectors_read += fdc_results[ST_SECTOR] - sector;
 621         if(sectors_read * BPS != blksize) {
 622                 printk("WARNING: %s(): fd%d: read error on %s device %d,%d (%d sectors read).\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev), sectors_read);
 623                 printk("\tblock=%d, sector=%d, cylinder/head=%d/%d\n", block, sector, cyl, head);
 624                 unlock_resource(&floppy_resource);
 625                 fdc_motor_off();
 626                 return -EIO;
 627         }
 628 
 629         memcpy_b(buffer, (void *)fdc_transfer_area, blksize);
 630 
 631         unlock_resource(&floppy_resource);
 632         return sectors_read * BPS;
 633 }
 634 
 635 int fdc_write(__dev_t dev, __blk_t block, char *buffer, int blksize)
 636 {
 637         unsigned char minor;
 638         unsigned int sectors_written;
 639         int cyl, head, sector;
 640         int retries;
 641         struct callout_req creq;
 642         struct device *d;
 643 
 644         minor = MINOR(dev);
 645         if(!TEST_MINOR(floppy_device.minors, minor)) {
 646                 return -ENXIO;
 647         }
 648 
 649         if(!blksize) {
 650                 if(!(d = get_device(BLK_DEV, dev))) {
 651                         return -EINVAL;
 652                 }
 653                 blksize = d->blksize;
 654         }
 655         blksize = blksize ? blksize : BLKSIZE_1K;
 656 
 657         lock_resource(&floppy_resource);
 658         set_current_fdd_type(minor);
 659 
 660         if(fdc_block2chs(block, blksize, &cyl, &head, &sector)) {
 661                 printk("WARNING: %s(): fd%d: invalid block number %d on %s device %d,%d.\n", __FUNCTION__, current_fdd, block, floppy_device.name, MAJOR(dev), MINOR(dev));
 662                 unlock_resource(&floppy_resource);
 663                 return -EINVAL;
 664         }
 665 
 666         for(retries = 0; retries < MAX_FDC_ERR; retries++) {
 667                 if(need_reset) {
 668                         fdc_reset();
 669                 }
 670                 if(fdc_motor_on()) {
 671                         printk("%s(): %s disk was changed in device %d,%d!\n", __FUNCTION__, floppy_device.name, MAJOR(dev), MINOR(dev));
 672                         invalidate_buffers(dev);
 673                         fdd_status[current_fdd].recalibrated = 0;
 674                 }
 675 
 676                 if(fdc_seek(cyl, head)) {
 677                         printk("WARNING: %s(): fd%d: seek error on %s device %d,%d during write operation.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 678                         continue;
 679                 }
 680 
 681                 start_dma(FLOPPY_DMA, fdc_transfer_area, blksize, DMA_MODE_READ | DMA_MODE_SINGLE);
 682                 memcpy_b((void *)fdc_transfer_area, buffer, blksize);
 683 
 684                 /* send WRITE command */
 685                 fdc_wait_interrupt = FDC_WRITE;
 686                 fdc_out(FDC_WRITE);
 687                 fdc_out((head << 2) | current_fdd);
 688                 fdc_out(cyl);
 689                 fdc_out(head);
 690                 fdc_out(sector);
 691                 fdc_out(2);     /* sector size is 512 bytes */
 692                 fdc_out(current_fdd_type->spt);
 693                 fdc_out(current_fdd_type->gpl1);
 694                 fdc_out(0xFF);  /* sector size is 512 bytes */
 695 
 696                 if(need_reset) {
 697                         printk("WARNING: %s(): fd%d: needs reset on %s device %d,%d during write operation.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 698                         continue;
 699                 }
 700                 creq.fn = fdc_timer;
 701                 creq.arg = FDC_TR_DEFAULT;
 702                 add_callout(&creq, WAIT_FDC);
 703                 /* avoid sleep if interrupt already happened */
 704                 if(fdc_wait_interrupt) {
 705                         sleep(&irq_floppy, PROC_UNINTERRUPTIBLE);
 706                 }
 707                 if(fdc_timeout) {
 708                         need_reset = 1;
 709                         printk("WARNING: %s(): fd%d: timeout on %s device %d,%d.\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 710                         continue;
 711                 }
 712                 del_callout(&creq);
 713                 fdc_get_results();
 714                 if(fdc_results[ST1] & ST1_NW) {
 715                         unlock_resource(&floppy_resource);
 716                         fdc_motor_off();
 717                         return -EROFS;
 718                 }
 719                 if(fdc_results[ST0] & (ST0_IC | ST0_UC | ST0_NR)) {
 720                         need_reset = 1;
 721                         continue;
 722                 }
 723                 break;
 724         }
 725 
 726         if(retries >= MAX_FDC_ERR) {
 727                 printk("WARNING: %s(): fd%d: error on %s device %d,%d during write operation,\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));
 728                 printk("\tblock=%d, sector=%d, cylinder/head=%d/%d\n", block, sector, cyl, head);
 729                 unlock_resource(&floppy_resource);
 730                 fdc_motor_off();
 731                 return -EIO;
 732         }
 733 
 734         fdc_motor_off();
 735         sectors_written = (fdc_results[ST_CYL] - cyl) * (current_fdd_type->heads * current_fdd_type->spt);
 736         sectors_written += (fdc_results[ST_HEAD] - head) * current_fdd_type->spt;
 737         sectors_written += fdc_results[ST_SECTOR] - sector;
 738         if(sectors_written * BPS != blksize) {
 739                 printk("WARNING: %s(): fd%d: write error on %s device %d,%d (%d sectors written).\n", __FUNCTION__, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev), sectors_written);
 740                 printk("\tblock=%d, sector=%d, cylinder/head=%d/%d\n", block, sector, cyl, head);
 741                 unlock_resource(&floppy_resource);
 742                 fdc_motor_off();
 743                 return -EIO;
 744         }
 745 
 746         unlock_resource(&floppy_resource);
 747         return sectors_written * BPS;
 748 }
 749 
 750 int fdc_ioctl(struct inode *i, int cmd, unsigned long int arg)
 751 {
 752         unsigned char minor;
 753         struct hd_geometry *geom;
 754         int errno;
 755 
 756         minor = MINOR(i->rdev);
 757         if(!TEST_MINOR(floppy_device.minors, minor)) {
 758                 return -ENXIO;
 759         }
 760 
 761         lock_resource(&floppy_resource);
 762         set_current_fdd_type(minor);
 763         unlock_resource(&floppy_resource);
 764 
 765         switch(cmd) {
 766                 case HDIO_GETGEO:
 767                         if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct hd_geometry)))) {
 768                                 return errno;
 769                         }
 770                         geom = (struct hd_geometry *)arg;
 771                         geom->heads = current_fdd_type->heads;
 772                         geom->sectors = current_fdd_type->spt;
 773                         geom->cylinders = current_fdd_type->tracks;
 774                         geom->start = 0;
 775                         break;
 776                 case BLKRRPART:
 777                         break;
 778                 case BLKGETSIZE:
 779                         if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {
 780                                 return errno;
 781                         }
 782                         *(int *)arg = fdd_sizes[MINOR(i->rdev)] * 2;
 783                         break;
 784                 default:
 785                         return -EINVAL;
 786         }
 787         return 0;
 788 }
 789 
 790 int fdc_lseek(struct inode *i, __off_t offset)
 791 {
 792         unsigned char minor;
 793 
 794         minor = MINOR(i->rdev);
 795         if(!TEST_MINOR(floppy_device.minors, minor)) {
 796                 return -ENXIO;
 797         }
 798 
 799         lock_resource(&floppy_resource);
 800         set_current_fdd_type(minor);
 801         unlock_resource(&floppy_resource);
 802 
 803         return offset;
 804 }
 805 
 806 void floppy_init(void)
 807 {
 808         short int cmosval, master, slave;
 809 
 810         cmosval = cmos_read(CMOS_FDDTYPE);
 811         set_current_fdd_type(0);        /* sets /dev/fd0 by default */
 812 
 813         /* the high nibble describes the 'master' floppy drive */
 814         master = cmosval >> 4;
 815 
 816         /* 
 817          * Some BIOS may return the value 0x05 (for 2.88MB floppy type) which is
 818          * not supported by Fiwix. This prevents from using an unexistent type
 819          * in the fdd_type structure if this happens.
 820          */
 821         if(master > 4) {
 822                 master = 4;
 823         }
 824 
 825         if(master) {
 826                 if(!register_irq(FLOPPY_IRQ, &irq_config_floppy)) {
 827                         enable_irq(FLOPPY_IRQ);
 828                 }
 829                 printk("fd0       0x%04X-0x%04X   %2d    ", FDC_SRA, FDC_CCR, FLOPPY_IRQ);
 830                 printk("%s ", fdd_type[master].name);
 831                 fdd_status[0].type = fdd_status[1].type = master;
 832                 SET_MINOR(floppy_device.minors, 0);
 833                 SET_MINOR(floppy_device.minors, 4);
 834                 SET_MINOR(floppy_device.minors, 8);
 835                 SET_MINOR(floppy_device.minors, 12);
 836                 SET_MINOR(floppy_device.minors, 16);
 837                 fdd_sizes[0] = fdd_type[master].sizekb;
 838                 fdd_sizes[4] = fdd_type[1].sizekb;
 839                 fdd_sizes[8] = fdd_type[2].sizekb;
 840                 fdd_sizes[12] = fdd_type[3].sizekb;
 841                 fdd_sizes[16] = fdd_type[4].sizekb;
 842                 fdc_reset();
 843                 fdc_get_chip();
 844         }
 845 
 846         /* the low nibble is for the 'slave' floppy drive */
 847         slave = cmosval & 0x0F;
 848         if(slave) {
 849                 if(!master) {
 850                         if(!register_irq(FLOPPY_IRQ, &irq_config_floppy)) {
 851                                 enable_irq(FLOPPY_IRQ);
 852                         }
 853                 }
 854                 printk("fd1       0x%04X-0x%04X   %2d    ", FDC_SRA, FDC_CCR, FLOPPY_IRQ);
 855                 printk("%s  ", fdd_type[slave].name);
 856                 fdd_status[1].type = slave;
 857                 SET_MINOR(floppy_device.minors, 1);
 858                 SET_MINOR(floppy_device.minors, 5);
 859                 SET_MINOR(floppy_device.minors, 9);
 860                 SET_MINOR(floppy_device.minors, 13);
 861                 SET_MINOR(floppy_device.minors, 17);
 862                 fdd_sizes[1] = fdd_type[slave].sizekb;
 863                 fdd_sizes[5] = fdd_type[1].sizekb;
 864                 fdd_sizes[9] = fdd_type[2].sizekb;
 865                 fdd_sizes[13] = fdd_type[3].sizekb;
 866                 fdd_sizes[17] = fdd_type[4].sizekb;
 867                 if(!master) {
 868                         fdc_get_chip();
 869                 } else {
 870                         printk("\n");
 871                 }
 872         }
 873 
 874         if(master || slave) {
 875                 need_reset = 1;
 876                 dma_init();
 877                 if(dma_register(FLOPPY_DMA, floppy_device.name)) {
 878                         printk("WARNING: %s(): fd%d: unable to register DMA channel on %s.\n", __FUNCTION__, current_fdd, floppy_device.name);
 879                 } else  {
 880                         if(!register_device(BLK_DEV, &floppy_device)) {
 881                                 do_motor_off(current_fdd);
 882                         }
 883                 }
 884         }
 885 }

/* [previous][next][first][last][top][bottom][index][help] */