root/kernel/blk_drv/floppy.c

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

DEFINITIONS

This source file includes following definitions.
  1. floppy_deselect
  2. request_done
  3. floppy_change
  4. setup_DMA
  5. output_byte
  6. result
  7. bad_flp_intr
  8. rw_interrupt
  9. setup_rw_floppy
  10. seek_interrupt
  11. transfer
  12. recal_interrupt
  13. unexpected_floppy_interrupt
  14. recalibrate_floppy
  15. reset_interrupt
  16. reset_floppy
  17. floppy_shutdown
  18. shake_done
  19. retry_recal
  20. shake_zero
  21. shake_one
  22. floppy_on_interrupt
  23. setup_format_params
  24. redo_fd_request
  25. do_fd_request
  26. fd_ioctl
  27. find_base
  28. config_types
  29. floppy_open
  30. floppy_release
  31. floppy_init

   1 /*
   2  *  linux/kernel/floppy.c
   3  *
   4  *  (C) 1991  Linus Torvalds
   5  */
   6 
   7 /*
   8  * 02.12.91 - Changed to static variables to indicate need for reset
   9  * and recalibrate. This makes some things easier (output_byte reset
  10  * checking etc), and means less interrupt jumping in case of errors,
  11  * so the code is hopefully easier to understand.
  12  */
  13 
  14 /*
  15  * This file is certainly a mess. I've tried my best to get it working,
  16  * but I don't like programming floppies, and I have only one anyway.
  17  * Urgel. I should check for more errors, and do more graceful error
  18  * recovery. Seems there are problems with several drives. I've tried to
  19  * correct them. No promises. 
  20  */
  21 
  22 /*
  23  * As with hd.c, all routines within this file can (and will) be called
  24  * by interrupts, so extreme caution is needed. A hardware interrupt
  25  * handler may not sleep, or a kernel panic will happen. Thus I cannot
  26  * call "floppy-on" directly, but have to set a special timer interrupt
  27  * etc.
  28  */
  29 
  30 /*
  31  * 28.02.92 - made track-buffering routines, based on the routines written
  32  * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
  33  */
  34 
  35 /*
  36  * Automatic floppy-detection and formatting written by Werner Almesberger
  37  * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
  38  * the floppy-change signa| detection.
  39  */
  40 
  41 #include <linux/sched.h>
  42 #include <linux/fs.h>
  43 #include <linux/kernel.h>
  44 #include <linux/timer.h>
  45 #include <linux/fdreg.h>
  46 #include <linux/fd.h>
  47 #include <asm/system.h>
  48 #include <asm/io.h>
  49 #include <asm/segment.h>
  50 #include <errno.h>
  51 
  52 #define MAJOR_NR 2
  53 #include "blk.h"
  54 
  55 static unsigned int changed_floppies = 0, fake_change = 0;
  56 
  57 static int recalibrate = 0;
  58 static int reset = 0;
  59 static int recover = 0; /* recalibrate immediately after resetting */
  60 static int seek = 0;
  61 
  62 extern unsigned char current_DOR;
  63 
  64 #define immoutb_p(val,port) \
  65 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
  66 
  67 #define TYPE(x) ((x)>>2)
  68 #define DRIVE(x) ((x)&0x03)
  69 /*
  70  * Note that MAX_ERRORS=X doesn't imply that we retry every bad read
  71  * max X times - some types of errors increase the errorcount by 2 or
  72  * even 3, so we might actually retry only X/2 times before giving up.
  73  */
  74 #define MAX_ERRORS 12
  75 
  76 /*
  77  * Maximum disk size (in kilobytes). This default is used whenever the
  78  * current disk size is unknown.
  79  */
  80 
  81 #define MAX_DISK_SIZE 1440
  82 
  83 /*
  84  * Maximum number of sectors in a track buffer. Track buffering is disabled
  85  * if tracks are bigger.
  86  */
  87 
  88 #define MAX_BUFFER_SECTORS 18
  89 
  90 /*
  91  * globals used by 'result()'
  92  */
  93 #define MAX_REPLIES 7
  94 static unsigned char reply_buffer[MAX_REPLIES];
  95 #define ST0 (reply_buffer[0])
  96 #define ST1 (reply_buffer[1])
  97 #define ST2 (reply_buffer[2])
  98 #define ST3 (reply_buffer[3])
  99 
 100 /*
 101  * This struct defines the different floppy types. Unlike minix
 102  * linux doesn't have a "search for right type"-type, as the code
 103  * for that is convoluted and weird. I've got enough problems with
 104  * this driver as it is.
 105  *
 106  * The 'stretch' tells if the tracks need to be boubled for some
 107  * types (ie 360kB diskette in 1.2MB drive etc). Others should
 108  * be self-explanatory.
 109  */
 110 
 111 static struct floppy_struct floppy_type[] = {
 112         {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },    /* no testing */
 113         {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL },    /* 360kB PC diskettes */
 114         { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL },    /* 1.2 MB AT-diskettes */
 115         {  720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL },    /* 360kB in 720kB drive */
 116         { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL },    /* 3.5" 720kB diskette */
 117         {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL },    /* 360kB in 1.2MB drive */
 118         { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL },    /* 720kB in 1.2MB drive */
 119         { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL },    /* 1.44MB diskette */
 120 };
 121 
 122 /* For auto-detection. Each drive type has a pair of formats to try. */
 123 
 124 static struct floppy_struct floppy_types[] = {
 125         {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
 126         {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
 127         { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" },    /* 1.2 MB AT-diskettes */
 128         {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */
 129         { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },    /* 3.5" 720kB diskette */
 130         { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },    /* 3.5" 720kB diskette */
 131         { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" },   /* 1.44MB diskette */
 132         { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
 133 };
 134 
 135 /* Auto-detection: Disk type used until the next media change occurs. */
 136 
 137 struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
 138 
 139 /* This type is tried first. */
 140 
 141 struct floppy_struct *base_type[4];
 142 
 143 /* User-provided type information. current_type points to the respective entry
 144    of this array. */
 145 
 146 struct floppy_struct user_params[4];
 147 
 148 static int floppy_sizes[] ={
 149         MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
 150          360, 360 ,360, 360,
 151         1200,1200,1200,1200,
 152          360, 360, 360, 360,
 153          720, 720, 720, 720,
 154          360, 360, 360, 360,
 155          720, 720, 720, 720,
 156         1440,1440,1440,1440
 157 };
 158 
 159 /* The driver is trying to determine the correct media format while probing
 160    is set. rw_interrupts clears it after a successful access. */
 161 
 162 static int probing = 0;
 163 
 164 /* (User-provided) media information is _not_ discarded after a media change
 165    if the corresponding keep_data flag is non-zero. Positive values are
 166    decremented after each probe. */
 167 
 168 static int keep_data[4] = { 0,0,0,0 };
 169 
 170 /* Announce successful media type detection and media information loss after
 171    disk changes. */
 172 
 173 static ftd_msg[4] = { 1,1,1,1 };
 174 
 175 /* Synchronization of FDC access. */
 176 
 177 static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
 178 static struct task_struct *fdc_wait = NULL, *format_done = NULL;
 179 
 180 /* Errors during formatting are counted here. */
 181 
 182 static int format_errors;
 183 
 184 /* Format request descriptor. */
 185 
 186 static struct format_descr format_req;
 187 
 188 /* Current device number. Taken either from the block header or from the
 189    format request descriptor. */
 190 
 191 #define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \
 192    (CURRENT->dev))
 193 
 194 /* Current error count. */
 195 
 196 #define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \
 197     (CURRENT->errors))
 198 
 199 /*
 200  * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
 201  * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
 202  * H is head unload time (1=16ms, 2=32ms, etc)
 203  *
 204  * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
 205  * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
 206  */
 207 
 208 extern void floppy_interrupt(void);
 209 extern char tmp_floppy_area[1024];
 210 extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
 211 
 212 static void redo_fd_request(void);
 213 
 214 /*
 215  * These are global variables, as that's the easiest way to give
 216  * information to interrupts. They are the data used for the current
 217  * request.
 218  */
 219 #define NO_TRACK 255
 220 
 221 static int read_track = 0;      /* flag to indicate if we want to read all track */
 222 static int buffer_track = -1;
 223 static int buffer_drive = -1;
 224 static int cur_spec1 = -1;
 225 static int cur_rate = -1;
 226 static struct floppy_struct * floppy = floppy_type;
 227 static unsigned char current_drive = 255;
 228 static unsigned char sector = 0;
 229 static unsigned char head = 0;
 230 static unsigned char track = 0;
 231 static unsigned char seek_track = 0;
 232 static unsigned char current_track = NO_TRACK;
 233 static unsigned char command = 0;
 234 unsigned char selected = 0;
 235 struct task_struct * wait_on_floppy_select = NULL;
 236 
 237 void floppy_deselect(unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239         if (nr != (current_DOR & 3))
 240                 printk("floppy_deselect: drive not selected\n\r");
 241         selected = 0;
 242         wake_up(&wait_on_floppy_select);
 243 }
 244 
 245 void request_done(int uptodate)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         timer_active &= ~(1 << FLOPPY_TIMER);
 248         if (format_status != FORMAT_BUSY) end_request(uptodate);
 249         else {
 250                 format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
 251                 wake_up(&format_done);
 252         }
 253 }
 254 
 255 /*
 256  * floppy-change is never called from an interrupt, so we can relax a bit
 257  * here, sleep etc. Note that floppy-on tries to set current_DOR to point
 258  * to the desired drive, but it will probably not survive the sleep if
 259  * several floppies are used at the same time: thus the loop.
 260  */
 261 int floppy_change(struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         unsigned int mask = 1 << (bh->b_dev & 0x03);
 264 
 265         if (MAJOR(bh->b_dev) != 2) {
 266                 printk("floppy_changed: not a floppy\r\n");
 267                 return 0;
 268         }
 269         if (fake_change & mask) {
 270                 fake_change &= ~mask;
 271 /* omitting the next line breaks formatting in a horrible way ... */
 272                 changed_floppies &= ~mask;
 273                 return 1;
 274         }
 275         if (changed_floppies & mask) {
 276                 changed_floppies &= ~mask;
 277                 recalibrate = 1;
 278                 return 1;
 279         }
 280         if (!bh)
 281                 return 0;
 282         if (bh->b_dirt)
 283                 ll_rw_block(WRITE,bh);
 284         else {
 285                 buffer_track = -1;
 286                 bh->b_uptodate = 0;
 287                 ll_rw_block(READ,bh);
 288         }
 289         cli();
 290         while (bh->b_lock)
 291                 sleep_on(&bh->b_wait);
 292         sti();
 293         if (changed_floppies & mask) {
 294                 changed_floppies &= ~mask;
 295                 recalibrate = 1;
 296                 return 1;
 297         }
 298         return 0;
 299 }
 300 
 301 #define copy_buffer(from,to) \
 302 __asm__("cld ; rep ; movsl" \
 303         ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
 304         :"cx","di","si")
 305 
 306 static void setup_DMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308         unsigned long addr,count;
 309 
 310         if (command == FD_FORMAT) {
 311                 addr = (long) tmp_floppy_area;
 312                 count = floppy->sect*4;
 313         }
 314         else {
 315                 addr = (long) CURRENT->buffer;
 316                 count = 1024;
 317         }
 318         if (read_track) {
 319 /* mark buffer-track bad, in case all this fails.. */
 320                 buffer_drive = buffer_track = -1;
 321                 count = floppy->sect*2*512;
 322                 addr = (long) floppy_track_buffer;
 323         } else if (addr >= 0x100000) {
 324                 addr = (long) tmp_floppy_area;
 325                 if (command == FD_WRITE)
 326                         copy_buffer(CURRENT->buffer,tmp_floppy_area);
 327         }
 328 /* mask DMA 2 */
 329         cli();
 330         immoutb_p(4|2,10);
 331 /* output command byte. I don't know why, but everyone (minix, */
 332 /* sanches & canton) output this twice, first to 12 then to 11 */
 333         __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
 334         "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
 335         "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
 336 /* 8 low bits of addr */
 337         immoutb_p(addr,4);
 338         addr >>= 8;
 339 /* bits 8-15 of addr */
 340         immoutb_p(addr,4);
 341         addr >>= 8;
 342 /* bits 16-19 of addr */
 343         immoutb_p(addr,0x81);
 344 /* low 8 bits of count-1 */
 345         count--;
 346         immoutb_p(count,5);
 347         count >>= 8;
 348 /* high 8 bits of count-1 */
 349         immoutb_p(count,5);
 350 /* activate DMA 2 */
 351         immoutb_p(0|2,10);
 352         sti();
 353 }
 354 
 355 static void output_byte(char byte)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357         int counter;
 358         unsigned char status;
 359 
 360         if (reset)
 361                 return;
 362         for(counter = 0 ; counter < 10000 ; counter++) {
 363                 status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
 364                 if (status == STATUS_READY) {
 365                         outb(byte,FD_DATA);
 366                         return;
 367                 }
 368         }
 369         current_track = NO_TRACK;
 370         reset = 1;
 371         printk("Unable to send byte to FDC\n\r");
 372 }
 373 
 374 static int result(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 375 {
 376         int i = 0, counter, status;
 377 
 378         if (reset)
 379                 return -1;
 380         for (counter = 0 ; counter < 10000 ; counter++) {
 381                 status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
 382                 if (status == STATUS_READY)
 383                         return i;
 384                 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
 385                         if (i >= MAX_REPLIES)
 386                                 break;
 387                         reply_buffer[i++] = inb_p(FD_DATA);
 388                 }
 389         }
 390         reset = 1;
 391         current_track = NO_TRACK;
 392         printk("Getstatus times out\n\r");
 393         return -1;
 394 }
 395 
 396 static void bad_flp_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398         current_track = NO_TRACK;
 399         CURRENT_ERRORS++;
 400         if (CURRENT_ERRORS > MAX_ERRORS) {
 401                 floppy_deselect(current_drive);
 402                 request_done(0);
 403         }
 404         if (CURRENT_ERRORS > MAX_ERRORS/2)
 405                 reset = 1;
 406         else
 407                 recalibrate = 1;
 408 }       
 409 
 410 /*
 411  * Ok, this interrupt is called after a DMA read/write has succeeded,
 412  * so we check the results, and copy any buffers.
 413  */
 414 static void rw_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416         char * buffer_area;
 417 
 418         if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
 419                 if (ST1 & 0x02) {
 420                         printk("Drive %d is write protected\n\r",current_drive);
 421                         floppy_deselect(current_drive);
 422                         request_done(0);
 423                 } else
 424                         bad_flp_intr();
 425                 redo_fd_request();
 426                 return;
 427         }
 428         if (probing) {
 429                 int drive = MINOR(CURRENT->dev);
 430 
 431                 if (ftd_msg[drive])
 432                         printk("Auto-detected floppy type %s in fd%d\r\n",
 433                             floppy->name,drive);
 434                 current_type[drive] = floppy;
 435                 floppy_sizes[drive] = floppy->size >> 1;
 436                 probing = 0;
 437         }
 438         if (read_track) {
 439                 buffer_track = seek_track;
 440                 buffer_drive = current_drive;
 441                 buffer_area = floppy_track_buffer +
 442                         ((sector-1 + head*floppy->sect)<<9);
 443                 copy_buffer(buffer_area,CURRENT->buffer);
 444         } else if (command == FD_READ &&
 445                 (unsigned long)(CURRENT->buffer) >= 0x100000)
 446                 copy_buffer(tmp_floppy_area,CURRENT->buffer);
 447         floppy_deselect(current_drive);
 448         request_done(1);
 449         redo_fd_request();
 450 }
 451 
 452 /*
 453  * We try to read tracks, but if we get too many errors, we
 454  * go back to reading just one sector at a time.
 455  *
 456  * This means we should be able to read a sector even if there
 457  * are other bad sectors on this track.
 458  */
 459 inline void setup_rw_floppy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461         setup_DMA();
 462         do_floppy = rw_interrupt;
 463         output_byte(command);
 464         if (command != FD_FORMAT) {
 465                 if (read_track) {
 466                         output_byte(current_drive);
 467                         output_byte(track);
 468                         output_byte(0);
 469                         output_byte(1);
 470                 } else {
 471                         output_byte(head<<2 | current_drive);
 472                         output_byte(track);
 473                         output_byte(head);
 474                         output_byte(sector);
 475                 }
 476                 output_byte(2);         /* sector size = 512 */
 477                 output_byte(floppy->sect);
 478                 output_byte(floppy->gap);
 479                 output_byte(0xFF);      /* sector size (0xff when n!=0 ?) */
 480         } else {
 481                 output_byte(head<<2 | current_drive);
 482                 output_byte(2);
 483                 output_byte(floppy->sect);
 484                 output_byte(floppy->fmt_gap);
 485                 output_byte(FD_FILL_BYTE);
 486         }
 487         if (reset)
 488                 redo_fd_request();
 489 }
 490 
 491 /*
 492  * This is the routine called after every seek (or recalibrate) interrupt
 493  * from the floppy controller. Note that the "unexpected interrupt" routine
 494  * also does a recalibrate, but doesn't come here.
 495  */
 496 static void seek_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498 /* sense drive status */
 499         output_byte(FD_SENSEI);
 500         if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
 501                 recalibrate = 1;
 502                 bad_flp_intr();
 503                 redo_fd_request();
 504                 return;
 505         }
 506         current_track = ST1;
 507         setup_rw_floppy();
 508 }
 509 
 510 /*
 511  * This routine is called when everything should be correctly set up
 512  * for the transfer (ie floppy motor is on and the correct floppy is
 513  * selected).
 514  */
 515 static void transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517         read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
 518             (floppy->sect <= MAX_BUFFER_SECTORS);
 519         if (cur_spec1 != floppy->spec1) {
 520                 cur_spec1 = floppy->spec1;
 521                 output_byte(FD_SPECIFY);
 522                 output_byte(cur_spec1);         /* hut etc */
 523                 output_byte(6);                 /* Head load time =6ms, DMA */
 524         }
 525         if (cur_rate != floppy->rate)
 526                 outb_p(cur_rate = floppy->rate,FD_DCR);
 527         if (reset) {
 528                 redo_fd_request();
 529                 return;
 530         }
 531         if (!seek) {
 532                 setup_rw_floppy();
 533                 return;
 534         }
 535         do_floppy = seek_interrupt;
 536         output_byte(FD_SEEK);
 537         if (read_track)
 538                 output_byte(current_drive);
 539         else
 540                 output_byte((head<<2) | current_drive);
 541         output_byte(seek_track);
 542         if (reset)
 543                 redo_fd_request();
 544 }
 545 
 546 /*
 547  * Special case - used after a unexpected interrupt (or reset)
 548  */
 549 
 550 static void recalibrate_floppy();
 551 
 552 static void recal_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 553 {
 554         output_byte(FD_SENSEI);
 555         current_track = NO_TRACK;
 556         if (result()!=2 || (ST0 & 0xE0) == 0x60)
 557                 reset = 1;
 558 /* Recalibrate until track 0 is reached. Might help on some errors. */
 559         if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
 560         else redo_fd_request();
 561 }
 562 
 563 void unexpected_floppy_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         current_track = NO_TRACK;
 566         output_byte(FD_SENSEI);
 567         if (result()!=2 || (ST0 & 0xE0) == 0x60)
 568                 reset = 1;
 569         else
 570                 recalibrate = 1;
 571 }
 572 
 573 static void recalibrate_floppy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575         recalibrate = 0;
 576         current_track = 0;
 577         do_floppy = recal_interrupt;
 578         output_byte(FD_RECALIBRATE);
 579         output_byte(head<<2 | current_drive);
 580         if (reset)
 581                 redo_fd_request();
 582 }
 583 
 584 static void reset_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 585 {
 586         output_byte(FD_SENSEI);
 587         (void) result();
 588         output_byte(FD_SPECIFY);
 589         output_byte(cur_spec1);         /* hut etc */
 590         output_byte(6);                 /* Head load time =6ms, DMA */
 591         if (!recover) redo_fd_request();
 592         else {
 593                 recalibrate_floppy();
 594                 recover = 0;
 595         }
 596 }
 597 
 598 /*
 599  * reset is done by pulling bit 2 of DOR low for a while.
 600  */
 601 static void reset_floppy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603         int i;
 604 
 605         do_floppy = reset_interrupt;
 606         reset = 0;
 607         current_track = NO_TRACK;
 608         cur_spec1 = -1;
 609         cur_rate = -1;
 610         recalibrate = 1;
 611         printk("Reset-floppy called\n\r");
 612         cli();
 613         outb_p(current_DOR & ~0x04,FD_DOR);
 614         for (i=0 ; i<1000 ; i++)
 615                 __asm__("nop");
 616         outb(current_DOR,FD_DOR);
 617         sti();
 618 }
 619 
 620 static void floppy_shutdown(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 621 {
 622         cli();
 623         request_done(0);
 624         recover = 1;
 625         reset_floppy();
 626         sti();
 627 }
 628 
 629 static void shake_done(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 630 {
 631         current_track = NO_TRACK;
 632         if (inb(FD_DIR) & 0x80) request_done(0);
 633         redo_fd_request();
 634 }
 635 
 636 static int retry_recal(void (*proc)(void))
     /* [previous][next][first][last][top][bottom][index][help] */
 637 {
 638         output_byte(FD_SENSEI);
 639         if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;
 640         do_floppy = proc;
 641         output_byte(FD_RECALIBRATE);
 642         output_byte(head<<2 | current_drive);
 643         return 1;
 644 }
 645 
 646 static void shake_zero(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 647 {
 648         if (!retry_recal(shake_zero)) shake_done();
 649 }
 650 
 651 static void shake_one(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 652 {
 653         if (retry_recal(shake_one)) return;
 654         do_floppy = shake_done;
 655         output_byte(FD_SEEK);
 656         output_byte(head << 2 | current_drive);
 657         output_byte(1);
 658 }
 659 
 660 static void floppy_on_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 661 {
 662         if (inb(FD_DIR) & 0x80) {
 663                 changed_floppies |= 1<<current_drive;
 664                 buffer_track = -1;
 665                 if (keep_data[current_drive]) {
 666                         if (keep_data[current_drive] > 0)
 667                                 keep_data[current_drive]--;
 668                 }
 669                 else {
 670                         if (ftd_msg[current_drive] && current_type[
 671                             current_drive] != NULL)
 672                                 printk("Disk type is undefined after disk "
 673                                     "change in fd%d\r\n",current_drive);
 674                         current_type[current_drive] = NULL;
 675                         floppy_sizes[current_drive] = MAX_DISK_SIZE;
 676                 }
 677 /* Forcing the drive to seek makes the "media changed" condition go away.
 678    There should be a cleaner solution for that ... */
 679                 if (!reset && !recalibrate) {
 680                         do_floppy = (current_track && current_track != NO_TRACK)
 681                             ?  shake_zero : shake_one;
 682                         output_byte(FD_RECALIBRATE);
 683                         output_byte(head<<2 | current_drive);
 684                         return;
 685                 }
 686         }
 687         if (reset) {
 688                 reset_floppy();
 689                 return;
 690         }
 691         if (recalibrate) {
 692                 recalibrate_floppy();
 693                 return;
 694         }
 695 /* We cannot do a floppy-select, as that might sleep. We just force it */
 696         selected = 1;
 697         if (current_drive != (current_DOR & 3)) {
 698                 seek = 1;
 699                 current_track = NO_TRACK;
 700                 current_DOR &= 0xFC;
 701                 current_DOR |= current_drive;
 702                 outb(current_DOR,FD_DOR);
 703                 add_timer(2,&transfer);
 704         } else
 705                 transfer();
 706 }
 707 
 708 static void setup_format_params(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 709 {
 710     unsigned char *here = (unsigned char *) tmp_floppy_area;
 711     int count;
 712 
 713     for (count = 1; count <= floppy->sect; count++) {
 714         *here++ = track;
 715         *here++ = head;
 716         *here++ = count;
 717         *here++ = 2; /* 512 bytes */
 718     }
 719 }
 720 
 721 static void redo_fd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 722 {
 723         unsigned int block;
 724         char * buffer_area;
 725         int device;
 726 
 727 repeat:
 728         if (format_status == FORMAT_WAIT) format_status = FORMAT_BUSY;
 729         if (format_status != FORMAT_BUSY) {
 730                 if (!CURRENT) {
 731                         if (!fdc_busy) panic("FDC access conflict");
 732                         fdc_busy = 0;
 733                         wake_up(&fdc_wait);
 734                         CLEAR_INTR;
 735                         return;
 736                 }
 737                 if (MAJOR(CURRENT->dev) != MAJOR_NR)
 738                         panic(DEVICE_NAME ": request list destroyed"); \
 739                 if (CURRENT->bh) {
 740                         if (!CURRENT->bh->b_lock)
 741                                 panic(DEVICE_NAME ": block not locked");
 742                 }
 743         }
 744         seek = 0;
 745         probing = 0;
 746         device = MINOR(CURRENT_DEVICE);
 747         if (device > 3)
 748                 floppy = (device >> 2) + floppy_type;
 749         else { /* Auto-detection */
 750                 if ((floppy = current_type[device & 3]) == NULL) {
 751                         probing = 1;
 752                         if ((floppy = base_type[device & 3]) ==
 753                             NULL) {
 754                                 request_done(0);
 755                                 goto repeat;
 756                         }
 757                         floppy += CURRENT_ERRORS & 1;
 758                 }
 759         }
 760         if (format_status != FORMAT_BUSY) {
 761                 if (current_drive != CURRENT_DEV)
 762                         current_track = NO_TRACK;
 763                 current_drive = CURRENT_DEV;
 764                 block = CURRENT->sector;
 765                 if (block+2 > floppy->size) {
 766                         request_done(0);
 767                         goto repeat;
 768                 }
 769                 sector = block % floppy->sect;
 770                 block /= floppy->sect;
 771                 head = block % floppy->head;
 772                 track = block / floppy->head;
 773                 seek_track = track << floppy->stretch;
 774                 if (CURRENT->cmd == READ)
 775                         command = FD_READ;
 776                 else if (CURRENT->cmd == WRITE)
 777                         command = FD_WRITE;
 778                 else {
 779                         printk("do_fd_request: unknown command\n");
 780                         request_done(0);
 781                         goto repeat;
 782                 }
 783         }
 784         else {
 785                 if (current_drive != (format_req.device & 3))
 786                         current_track = NO_TRACK;
 787                 current_drive = format_req.device & 3;
 788                 if (format_req.track < 0 || format_req.track >= floppy->track ||
 789                     (format_req.head & 0xfffe) || probing) {
 790                         request_done(0);
 791                         goto repeat;
 792                 }
 793                 head = format_req.head;
 794                 track = format_req.track;
 795                 seek_track = track << floppy->stretch;
 796                 if (seek_track == buffer_track) buffer_track = -1;
 797                 command = FD_FORMAT;
 798                 setup_format_params();
 799         }
 800         timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
 801         timer_active |= 1 << FLOPPY_TIMER;
 802         if ((seek_track == buffer_track) &&
 803          (current_drive == buffer_drive)) {
 804                 buffer_area = floppy_track_buffer +
 805                         ((sector + head*floppy->sect)<<9);
 806                 if (command == FD_READ) {
 807                         copy_buffer(buffer_area,CURRENT->buffer);
 808                         request_done(1);
 809                         goto repeat;
 810                 } else if (command == FD_WRITE)
 811                         copy_buffer(CURRENT->buffer,buffer_area);
 812         }
 813         if (seek_track != current_track)
 814                 seek = 1;
 815         sector++;
 816         add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
 817 }
 818 
 819 void do_fd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 820 {
 821         cli();
 822         while (fdc_busy) sleep_on(&fdc_wait);
 823         fdc_busy = 1;
 824         sti();
 825         redo_fd_request();
 826 }
 827 
 828 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 829     unsigned int param)
 830 {
 831         int drive,cnt,okay;
 832         struct floppy_struct *this;
 833 
 834         if (!suser()) return -EPERM;
 835         drive = MINOR(inode->i_rdev);
 836         switch (cmd) {
 837                 case FDFMTBEG:
 838                         return 0;
 839                 case FDFMTEND:
 840                         cli();
 841                         fake_change |= 1 << (drive & 3);
 842                         sti();
 843                         drive &= 3;
 844                         cmd = FDCLRPRM;
 845                         break;
 846                 case FDGETPRM:
 847                         if (drive > 3) this = &floppy_type[drive >> 2];
 848                         else if ((this = current_type[drive & 3]) == NULL)
 849                                     return -ENODEV;
 850                         verify_area((void *) param,sizeof(struct floppy_struct));
 851                         for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
 852                                 put_fs_byte(((char *) this)[cnt],
 853                                     (char *) param+cnt);
 854                         return 0;
 855                 case FDFMTTRK:
 856                         cli();
 857                         while (format_status != FORMAT_NONE)
 858                                 sleep_on(&format_done);
 859                         for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
 860                                 ((char *) &format_req)[cnt] = get_fs_byte(
 861                                     (char *) param+cnt);
 862                         format_req.device = drive;
 863                         format_status = FORMAT_WAIT;
 864                         format_errors = 0;
 865                         while (format_status != FORMAT_OKAY && format_status !=
 866                             FORMAT_ERROR) {
 867                                 if (fdc_busy) sleep_on(&fdc_wait);
 868                                 else {
 869                                         fdc_busy = 1;
 870                                         redo_fd_request();
 871                                 }
 872                         }
 873                         while (format_status != FORMAT_OKAY && format_status !=
 874                             FORMAT_ERROR)
 875                                 sleep_on(&format_done);
 876                         sti();
 877                         okay = format_status == FORMAT_OKAY;
 878                         format_status = FORMAT_NONE;
 879                         wake_up(&format_done);
 880                         return okay ? 0 : -EIO;
 881         }
 882         if (drive < 0 || drive > 3) return -EINVAL;
 883         switch (cmd) {
 884                 case FDCLRPRM:
 885                         current_type[drive] = NULL;
 886                         floppy_sizes[drive] = MAX_DISK_SIZE;
 887                         keep_data[drive] = 0;
 888                         break;
 889                 case FDSETPRM:
 890                 case FDDEFPRM:
 891                         for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
 892                                 ((char *) &user_params[drive])[cnt] =
 893                                     get_fs_byte((char *) param+cnt);
 894                         current_type[drive] = &user_params[drive];
 895                         floppy_sizes[drive] = user_params[drive].size >> 1;
 896                         if (cmd == FDDEFPRM) keep_data[drive] = -1;
 897                         else {
 898                                 cli();
 899                                 while (fdc_busy) sleep_on(&fdc_wait);
 900                                 fdc_busy = 1;
 901                                 sti();
 902                                 outb_p((current_DOR & 0xfc) | drive |
 903                                     (0x10 << drive),FD_DOR);
 904                                 for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
 905                                 keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
 906                                 outb_p(current_DOR,FD_DOR);
 907                                 fdc_busy = 0;
 908                                 wake_up(&fdc_wait);
 909                         }
 910                         break;
 911                 case FDMSGON:
 912                         ftd_msg[drive] = 1;
 913                         break;
 914                 case FDMSGOFF:
 915                         ftd_msg[drive] = 0;
 916                         break;
 917                 default:
 918                         return -EINVAL;
 919         }
 920         return 0;
 921 }
 922 
 923 #define CMOS_READ(addr) ({ \
 924 outb_p(0x80|addr,0x70); \
 925 inb_p(0x71); \
 926 })
 927 
 928 static struct floppy_struct *find_base(int drive,int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 929 {
 930         struct floppy_struct *base;
 931 
 932         if (code > 0 && code < 5) {
 933                 base = &floppy_types[(code-1)*2];
 934                 printk("fd%d is %s",drive,base->name);
 935                 return base;
 936         }
 937         printk("fd%d is unknown type %d",drive,code);
 938         return NULL;
 939 }
 940 
 941 static void config_types(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 942 {
 943         printk("Floppy drive(s): ");
 944         base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
 945         if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[0] = NULL;
 946         else {
 947                 printk(", ");
 948                 base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
 949         }
 950         base_type[2] = base_type[3] = NULL;
 951         printk("\r\n");
 952 }
 953 
 954 static int floppy_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 955 {
 956         if (filp->f_mode)
 957                 check_disk_change(inode->i_rdev);
 958         return 0;
 959 }
 960 
 961 static void floppy_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 962 {
 963         sync_dev(inode->i_rdev);
 964 }
 965 
 966 static struct file_operations floppy_fops = {
 967         NULL,                   /* lseek - default */
 968         block_read,             /* read - general block-dev read */
 969         block_write,            /* write - general block-dev write */
 970         NULL,                   /* readdir - bad */
 971         NULL,                   /* select */
 972         fd_ioctl,               /* ioctl */
 973         floppy_open,            /* open */
 974         floppy_release          /* release */
 975 };
 976 
 977 void floppy_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 978 {
 979         outb(current_DOR,FD_DOR);
 980         blk_size[MAJOR_NR] = floppy_sizes;
 981         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 982         blkdev_fops[MAJOR_NR] = &floppy_fops;
 983         timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
 984         timer_active &= ~(1 << FLOPPY_TIMER);
 985         config_types();
 986         set_intr_gate(0x26,&floppy_interrupt);
 987         outb(inb_p(0x21)&~0x40,0x21);
 988 }

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