|
|
1.1 root 1: /*
2: * linux/kernel/floppy.c
3: *
1.1.1.10! root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1 root 5: */
6:
7: /*
1.1.1.2 root 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: /*
1.1 root 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.
1.1.1.4 root 28: */
29:
30: /*
31: * 28.02.92 - made track-buffering routines, based on the routines written
32: * by [email protected] (Lawrence Foard). Linus.
1.1 root 33: */
34:
1.1.1.7 root 35: /*
36: * Automatic floppy-detection and formatting written by Werner Almesberger
37: * ([email protected]), who also corrected some problems with
1.1.1.8 root 38: * the floppy-change signal detection.
1.1.1.7 root 39: */
40:
1.1.1.10! root 41: /*
! 42: * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
! 43: * FDC data overrun bug, added some preliminary stuff for vertical
! 44: * recording support.
! 45: * TODO: Errors are still not counted properly.
! 46: */
! 47:
! 48: #define REALLY_SLOW_IO
! 49: #define FLOPPY_IRQ 6
! 50:
1.1 root 51: #include <linux/sched.h>
52: #include <linux/fs.h>
53: #include <linux/kernel.h>
1.1.1.7 root 54: #include <linux/timer.h>
1.1 root 55: #include <linux/fdreg.h>
1.1.1.7 root 56: #include <linux/fd.h>
1.1.1.10! root 57: #include <linux/errno.h>
! 58: #ifdef HHB_SYSMACROS
! 59: #include <linux/system.h>
! 60: #endif
! 61:
1.1 root 62: #include <asm/system.h>
63: #include <asm/io.h>
64: #include <asm/segment.h>
65:
66: #define MAJOR_NR 2
67: #include "blk.h"
68:
1.1.1.7 root 69: static unsigned int changed_floppies = 0, fake_change = 0;
1.1.1.5 root 70:
1.1.1.2 root 71: static int recalibrate = 0;
72: static int reset = 0;
1.1.1.7 root 73: static int recover = 0; /* recalibrate immediately after resetting */
1.1.1.2 root 74: static int seek = 0;
1.1 root 75:
76: extern unsigned char current_DOR;
77:
78: #define immoutb_p(val,port) \
79: __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
80:
81: #define TYPE(x) ((x)>>2)
82: #define DRIVE(x) ((x)&0x03)
1.1.1.10! root 83:
1.1 root 84: /*
1.1.1.4 root 85: * Note that MAX_ERRORS=X doesn't imply that we retry every bad read
1.1.1.5 root 86: * max X times - some types of errors increase the errorcount by 2 or
87: * even 3, so we might actually retry only X/2 times before giving up.
1.1 root 88: */
1.1.1.4 root 89: #define MAX_ERRORS 12
1.1 root 90:
91: /*
1.1.1.7 root 92: * Maximum disk size (in kilobytes). This default is used whenever the
93: * current disk size is unknown.
94: */
95: #define MAX_DISK_SIZE 1440
96:
97: /*
98: * Maximum number of sectors in a track buffer. Track buffering is disabled
99: * if tracks are bigger.
100: */
101: #define MAX_BUFFER_SECTORS 18
102:
103: /*
1.1.1.10! root 104: * The DMA channel used by the floppy controller cannot access data at
! 105: * addresses >= 1MB
! 106: */
! 107: #define LAST_DMA_ADDR (0x100000 - BLOCK_SIZE)
! 108:
! 109: /*
1.1 root 110: * globals used by 'result()'
111: */
112: #define MAX_REPLIES 7
113: static unsigned char reply_buffer[MAX_REPLIES];
114: #define ST0 (reply_buffer[0])
115: #define ST1 (reply_buffer[1])
116: #define ST2 (reply_buffer[2])
117: #define ST3 (reply_buffer[3])
118:
119: /*
1.1.1.10! root 120: * This struct defines the different floppy types.
1.1 root 121: *
1.1.1.10! root 122: * The 'stretch' tells if the tracks need to be doubled for some
1.1 root 123: * types (ie 360kB diskette in 1.2MB drive etc). Others should
124: * be self-explanatory.
125: */
1.1.1.4 root 126: static struct floppy_struct floppy_type[] = {
1.1.1.7 root 127: { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* no testing */
128: { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB PC diskettes */
129: { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL }, /* 1.2 MB AT-diskettes */
130: { 720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB in 720kB drive */
131: { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL }, /* 3.5" 720kB diskette */
132: { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL }, /* 360kB in 1.2MB drive */
133: { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL }, /* 720kB in 1.2MB drive */
134: { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }, /* 1.44MB diskette */
135: };
136:
1.1.1.10! root 137: /*
! 138: * Auto-detection. Each drive type has a pair of formats which are
! 139: * used in succession to try to read the disk. If the FDC cannot lock onto
! 140: * the disk, the next format is tried. This uses the variable 'probing'.
! 141: */
1.1.1.7 root 142: static struct floppy_struct floppy_types[] = {
143: { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
144: { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
145: { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" }, /* 1.2 MB AT-diskettes */
146: { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */
147: { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */
148: { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */
149: { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" }, /* 1.44MB diskette */
150: { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
151: };
152:
153: /* Auto-detection: Disk type used until the next media change occurs. */
154: struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
155:
156: /* This type is tried first. */
157: struct floppy_struct *base_type[4];
158:
1.1.1.10! root 159: /*
! 160: * User-provided type information. current_type points to
! 161: * the respective entry of this array.
! 162: */
1.1.1.7 root 163: struct floppy_struct user_params[4];
164:
165: static int floppy_sizes[] ={
166: MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
167: 360, 360 ,360, 360,
168: 1200,1200,1200,1200,
169: 360, 360, 360, 360,
170: 720, 720, 720, 720,
171: 360, 360, 360, 360,
172: 720, 720, 720, 720,
173: 1440,1440,1440,1440
1.1 root 174: };
1.1.1.3 root 175:
1.1.1.10! root 176: /*
! 177: * The driver is trying to determine the correct media format
! 178: * while probing is set. rw_interrupt() clears it after a
! 179: * successful access.
! 180: */
1.1.1.7 root 181: static int probing = 0;
182:
1.1.1.10! root 183: /*
! 184: * (User-provided) media information is _not_ discarded after a media change
! 185: * if the corresponding keep_data flag is non-zero. Positive values are
! 186: * decremented after each probe.
! 187: */
1.1.1.7 root 188: static int keep_data[4] = { 0,0,0,0 };
189:
1.1.1.10! root 190: /*
! 191: * Announce successful media type detection and media information loss after
! 192: * disk changes.
! 193: */
1.1.1.7 root 194: static ftd_msg[4] = { 1,1,1,1 };
195:
1.1.1.10! root 196: /* Prevent "aliased" accesses. */
! 197:
! 198: static fd_ref[4] = { 0,0,0,0 };
! 199: static fd_device[4] = { 0,0,0,0 };
1.1.1.7 root 200:
1.1.1.10! root 201: /* Synchronization of FDC access. */
1.1.1.7 root 202: static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
1.1.1.10! root 203: static struct wait_queue *fdc_wait = NULL, *format_done = NULL;
1.1.1.7 root 204:
205: /* Errors during formatting are counted here. */
206: static int format_errors;
207:
208: /* Format request descriptor. */
209: static struct format_descr format_req;
210:
1.1.1.10! root 211: /*
! 212: * Current device number. Taken either from the block header or from the
! 213: * format request descriptor.
! 214: */
1.1.1.7 root 215: #define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \
216: (CURRENT->dev))
217:
218: /* Current error count. */
219: #define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \
220: (CURRENT->errors))
221:
1.1 root 222: /*
1.1.1.10! root 223: * Treshold for reporting FDC errors to the console.
! 224: * Setting this to zero may flood your screen when using
! 225: * ultra cheap floppies ;-)
! 226: */
! 227: static unsigned short min_report_error_cnt[4] = {2, 2, 2, 2};
! 228:
! 229: /*
! 230: * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
1.1 root 231: * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
232: * H is head unload time (1=16ms, 2=32ms, etc)
233: *
234: * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
235: * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
236: */
237:
1.1.1.10! root 238: /*
! 239: * Track buffer and block buffer (in case track buffering doesn't work).
! 240: * Because these are written to by the DMA controller, they must
! 241: * not contain a 64k byte boundary crossing, or data will be
! 242: * corrupted/lost. Alignment of these is enforced in boot/head.s.
! 243: * Note that you must not change the sizes below without updating head.s.
! 244: */
! 245: extern char tmp_floppy_area[BLOCK_SIZE];
1.1.1.7 root 246: extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
247:
248: static void redo_fd_request(void);
1.1 root 249:
250: /*
251: * These are global variables, as that's the easiest way to give
252: * information to interrupts. They are the data used for the current
253: * request.
254: */
1.1.1.5 root 255: #define NO_TRACK 255
256:
1.1.1.10! root 257: static int read_track = 0; /* flag to indicate if we want to read entire track */
1.1.1.4 root 258: static int buffer_track = -1;
259: static int buffer_drive = -1;
1.1 root 260: static int cur_spec1 = -1;
261: static int cur_rate = -1;
262: static struct floppy_struct * floppy = floppy_type;
1.1.1.5 root 263: static unsigned char current_drive = 255;
1.1 root 264: static unsigned char sector = 0;
265: static unsigned char head = 0;
266: static unsigned char track = 0;
267: static unsigned char seek_track = 0;
1.1.1.5 root 268: static unsigned char current_track = NO_TRACK;
1.1 root 269: static unsigned char command = 0;
1.1.1.10! root 270: static unsigned char fdc_version = FDC_TYPE_STD; /* FDC version code */
1.1.1.2 root 271: unsigned char selected = 0;
1.1.1.10! root 272: struct wait_queue * wait_on_floppy_select = NULL;
1.1.1.2 root 273:
274: void floppy_deselect(unsigned int nr)
275: {
276: if (nr != (current_DOR & 3))
277: printk("floppy_deselect: drive not selected\n\r");
278: selected = 0;
279: wake_up(&wait_on_floppy_select);
280: }
1.1 root 281:
1.1.1.7 root 282: void request_done(int uptodate)
283: {
284: timer_active &= ~(1 << FLOPPY_TIMER);
285: if (format_status != FORMAT_BUSY) end_request(uptodate);
286: else {
287: format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
288: wake_up(&format_done);
289: }
290: }
291:
1.1 root 292: /*
293: * floppy-change is never called from an interrupt, so we can relax a bit
1.1.1.2 root 294: * here, sleep etc. Note that floppy-on tries to set current_DOR to point
295: * to the desired drive, but it will probably not survive the sleep if
296: * several floppies are used at the same time: thus the loop.
1.1 root 297: */
1.1.1.5 root 298: int floppy_change(struct buffer_head * bh)
1.1 root 299: {
1.1.1.5 root 300: unsigned int mask = 1 << (bh->b_dev & 0x03);
301:
302: if (MAJOR(bh->b_dev) != 2) {
1.1.1.7 root 303: printk("floppy_changed: not a floppy\r\n");
1.1.1.5 root 304: return 0;
305: }
1.1.1.7 root 306: if (fake_change & mask) {
307: fake_change &= ~mask;
308: /* omitting the next line breaks formatting in a horrible way ... */
309: changed_floppies &= ~mask;
310: return 1;
311: }
1.1.1.5 root 312: if (changed_floppies & mask) {
313: changed_floppies &= ~mask;
314: recalibrate = 1;
1.1 root 315: return 1;
316: }
1.1.1.5 root 317: if (!bh)
318: return 0;
319: if (bh->b_dirt)
320: ll_rw_block(WRITE,bh);
321: else {
322: buffer_track = -1;
323: bh->b_uptodate = 0;
324: ll_rw_block(READ,bh);
325: }
326: cli();
327: while (bh->b_lock)
328: sleep_on(&bh->b_wait);
329: sti();
330: if (changed_floppies & mask) {
331: changed_floppies &= ~mask;
332: recalibrate = 1;
333: return 1;
1.1.1.7 root 334: }
1.1 root 335: return 0;
336: }
337:
338: #define copy_buffer(from,to) \
339: __asm__("cld ; rep ; movsl" \
340: ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
341: :"cx","di","si")
342:
343: static void setup_DMA(void)
344: {
1.1.1.7 root 345: unsigned long addr,count;
1.1 root 346:
1.1.1.7 root 347: if (command == FD_FORMAT) {
348: addr = (long) tmp_floppy_area;
349: count = floppy->sect*4;
350: }
351: else {
352: addr = (long) CURRENT->buffer;
353: count = 1024;
354: }
1.1.1.4 root 355: if (read_track) {
356: /* mark buffer-track bad, in case all this fails.. */
357: buffer_drive = buffer_track = -1;
358: count = floppy->sect*2*512;
359: addr = (long) floppy_track_buffer;
1.1.1.10! root 360: } else if (addr >= LAST_DMA_ADDR) {
1.1 root 361: addr = (long) tmp_floppy_area;
362: if (command == FD_WRITE)
363: copy_buffer(CURRENT->buffer,tmp_floppy_area);
364: }
365: /* mask DMA 2 */
1.1.1.7 root 366: cli();
1.1.1.10! root 367: #ifndef HHB_SYSMACROS
1.1 root 368: immoutb_p(4|2,10);
369: /* output command byte. I don't know why, but everyone (minix, */
370: /* sanches & canton) output this twice, first to 12 then to 11 */
371: __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
372: "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
373: "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
374: /* 8 low bits of addr */
375: immoutb_p(addr,4);
376: addr >>= 8;
377: /* bits 8-15 of addr */
378: immoutb_p(addr,4);
379: addr >>= 8;
380: /* bits 16-19 of addr */
381: immoutb_p(addr,0x81);
1.1.1.4 root 382: /* low 8 bits of count-1 */
383: count--;
384: immoutb_p(count,5);
385: count >>= 8;
1.1 root 386: /* high 8 bits of count-1 */
1.1.1.4 root 387: immoutb_p(count,5);
1.1 root 388: /* activate DMA 2 */
389: immoutb_p(0|2,10);
1.1.1.10! root 390: #else /* just to show off my macros -- hhb */
! 391: DISABLE_DMA(DMA2);
! 392: CLEAR_DMA_FF(DMA2);
! 393: SET_DMA_MODE(DMA2, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
! 394: SET_DMA_ADDR(DMA2, addr);
! 395: SET_DMA_COUNT(DMA2, count);
! 396: ENABLE_DMA(DMA2);
! 397: #endif
1.1.1.2 root 398: sti();
1.1 root 399: }
400:
401: static void output_byte(char byte)
402: {
403: int counter;
404: unsigned char status;
405:
1.1.1.2 root 406: if (reset)
407: return;
1.1 root 408: for(counter = 0 ; counter < 10000 ; counter++) {
1.1.1.2 root 409: status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
1.1 root 410: if (status == STATUS_READY) {
411: outb(byte,FD_DATA);
412: return;
413: }
414: }
1.1.1.5 root 415: current_track = NO_TRACK;
1.1.1.2 root 416: reset = 1;
1.1 root 417: printk("Unable to send byte to FDC\n\r");
418: }
419:
420: static int result(void)
421: {
422: int i = 0, counter, status;
423:
1.1.1.2 root 424: if (reset)
425: return -1;
1.1 root 426: for (counter = 0 ; counter < 10000 ; counter++) {
1.1.1.2 root 427: status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
1.1.1.10! root 428: if (status == STATUS_READY) {
1.1 root 429: return i;
1.1.1.10! root 430: }
1.1 root 431: if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
1.1.1.10! root 432: if (i >= MAX_REPLIES) {
! 433: printk("floppy_stat reply overrun\n");
1.1 root 434: break;
1.1.1.10! root 435: }
1.1.1.2 root 436: reply_buffer[i++] = inb_p(FD_DATA);
1.1 root 437: }
438: }
1.1.1.2 root 439: reset = 1;
1.1.1.5 root 440: current_track = NO_TRACK;
1.1 root 441: printk("Getstatus times out\n\r");
442: return -1;
443: }
444:
1.1.1.2 root 445: static void bad_flp_intr(void)
446: {
1.1.1.5 root 447: current_track = NO_TRACK;
1.1.1.7 root 448: CURRENT_ERRORS++;
449: if (CURRENT_ERRORS > MAX_ERRORS) {
1.1.1.2 root 450: floppy_deselect(current_drive);
1.1.1.7 root 451: request_done(0);
1.1.1.2 root 452: }
1.1.1.7 root 453: if (CURRENT_ERRORS > MAX_ERRORS/2)
1.1.1.2 root 454: reset = 1;
1.1.1.5 root 455: else
456: recalibrate = 1;
1.1.1.2 root 457: }
458:
1.1 root 459: /*
1.1.1.10! root 460: * This has only been tested for the case fdc_version == FDC_TYPE_STD.
! 461: * In case you have a 82077 and want to test it, you'll have to compile
! 462: * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for
! 463: * recognizing drives with vertical recording support.
! 464: */
! 465: static void configure_fdc_mode(void)
! 466: {
! 467: if (fdc_version == FDC_TYPE_82077) {
! 468: /* Enhanced version with FIFO & vertical recording. */
! 469: output_byte(FD_CONFIGURE);
! 470: output_byte(0);
! 471: output_byte(0x1A); /* FIFO on, polling off, 10 byte treshold */
! 472: output_byte(0); /* precompensation from track 0 upwards */
! 473: printk(DEVICE_NAME ": FIFO enabled\n");
! 474: }
! 475: } /* configure_fdc_mode */
! 476:
! 477:
! 478: static void tell_sector(int nr)
! 479: {
! 480: if (nr!=7) {
! 481: printk(" -- FDC reply errror");
! 482: reset = 1;
! 483: } else
! 484: printk(": track %d, head %d, sector %d", reply_buffer[3],
! 485: reply_buffer[4], reply_buffer[5]);
! 486: } /* tell_sector */
! 487:
! 488:
! 489: /*
! 490: * Ok, this interrupt is called after a DMA read/write has succeeded
! 491: * or failed, so we check the results, and copy any buffers.
! 492: * hhb: Added better error reporting.
1.1 root 493: */
1.1.1.2 root 494: static void rw_interrupt(void)
1.1 root 495: {
1.1.1.4 root 496: char * buffer_area;
1.1.1.10! root 497: int nr;
! 498: char bad;
1.1.1.4 root 499:
1.1.1.10! root 500: nr = result();
! 501: /* check IC to find cause of interrupt */
! 502: switch ((ST0 & ST0_INTR)>>6) {
! 503: case 1: /* error occured during command execution */
! 504: bad = 1;
! 505: if (ST1 & ST1_WP) {
! 506: printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive);
! 507: floppy_deselect(current_drive);
! 508: request_done(0);
! 509: bad = 0;
! 510: } else if (ST1 & ST1_OR) {
! 511: printk(DEVICE_NAME ": Over/Underrun - retrying\n");
! 512: /* could continue from where we stopped, but ... */
! 513: bad = 0;
! 514: } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {
! 515: printk(DEVICE_NAME " %d: ", ST0 & ST0_DS);
! 516: if (ST0 & ST0_ECE) {
! 517: printk("Recalibrate failed!");
! 518: } else if (ST2 & ST2_CRC) {
! 519: printk("data CRC error");
! 520: tell_sector(nr);
! 521: } else if (ST1 & ST1_CRC) {
! 522: printk("CRC error");
! 523: tell_sector(nr);
! 524: } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
! 525: if (!probing) {
! 526: printk("sector not found");
! 527: tell_sector(nr);
! 528: } else
! 529: printk("probe failed...");
! 530: } else if (ST2 & ST2_WC) { /* seek error */
! 531: printk("wrong cylinder");
! 532: } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
! 533: printk("bad cylinder");
! 534: } else {
! 535: printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3);
! 536: }
! 537: printk("\n");
! 538:
! 539: }
! 540: if (bad)
! 541: bad_flp_intr();
! 542: redo_fd_request();
! 543: return;
! 544: case 2: /* invalid command given */
! 545: printk(DEVICE_NAME ": Invalid FDC command given!\n");
1.1.1.7 root 546: request_done(0);
1.1.1.10! root 547: return;
! 548: case 3:
! 549: printk(DEVICE_NAME ": Abnormal termination caused by polling\n");
1.1.1.2 root 550: bad_flp_intr();
1.1.1.10! root 551: redo_fd_request();
! 552: return;
! 553: default: /* (0) Normal command termination */
! 554: break;
1.1 root 555: }
1.1.1.10! root 556:
1.1.1.7 root 557: if (probing) {
558: int drive = MINOR(CURRENT->dev);
559:
560: if (ftd_msg[drive])
561: printk("Auto-detected floppy type %s in fd%d\r\n",
562: floppy->name,drive);
563: current_type[drive] = floppy;
564: floppy_sizes[drive] = floppy->size >> 1;
565: probing = 0;
566: }
1.1.1.4 root 567: if (read_track) {
568: buffer_track = seek_track;
569: buffer_drive = current_drive;
570: buffer_area = floppy_track_buffer +
571: ((sector-1 + head*floppy->sect)<<9);
572: copy_buffer(buffer_area,CURRENT->buffer);
573: } else if (command == FD_READ &&
1.1.1.10! root 574: (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR)
1.1.1.2 root 575: copy_buffer(tmp_floppy_area,CURRENT->buffer);
576: floppy_deselect(current_drive);
1.1.1.7 root 577: request_done(1);
578: redo_fd_request();
1.1.1.2 root 579: }
580:
1.1.1.4 root 581: /*
582: * We try to read tracks, but if we get too many errors, we
583: * go back to reading just one sector at a time.
584: *
585: * This means we should be able to read a sector even if there
586: * are other bad sectors on this track.
587: */
1.1.1.2 root 588: inline void setup_rw_floppy(void)
589: {
1.1 root 590: setup_DMA();
591: do_floppy = rw_interrupt;
592: output_byte(command);
1.1.1.7 root 593: if (command != FD_FORMAT) {
594: if (read_track) {
595: output_byte(current_drive);
596: output_byte(track);
597: output_byte(0);
598: output_byte(1);
599: } else {
600: output_byte(head<<2 | current_drive);
601: output_byte(track);
602: output_byte(head);
603: output_byte(sector);
604: }
605: output_byte(2); /* sector size = 512 */
606: output_byte(floppy->sect);
607: output_byte(floppy->gap);
608: output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
1.1.1.4 root 609: } else {
610: output_byte(head<<2 | current_drive);
1.1.1.7 root 611: output_byte(2);
612: output_byte(floppy->sect);
613: output_byte(floppy->fmt_gap);
614: output_byte(FD_FILL_BYTE);
615: }
1.1.1.2 root 616: if (reset)
1.1.1.7 root 617: redo_fd_request();
1.1 root 618: }
619:
620: /*
1.1.1.2 root 621: * This is the routine called after every seek (or recalibrate) interrupt
622: * from the floppy controller. Note that the "unexpected interrupt" routine
623: * also does a recalibrate, but doesn't come here.
1.1 root 624: */
1.1.1.2 root 625: static void seek_interrupt(void)
1.1 root 626: {
1.1.1.2 root 627: /* sense drive status */
628: output_byte(FD_SENSEI);
629: if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
1.1.1.10! root 630: printk(DEVICE_NAME ": seek failed\n");
1.1.1.4 root 631: recalibrate = 1;
1.1.1.2 root 632: bad_flp_intr();
1.1.1.7 root 633: redo_fd_request();
1.1 root 634: return;
635: }
1.1.1.2 root 636: current_track = ST1;
637: setup_rw_floppy();
1.1 root 638: }
639:
1.1.1.10! root 640: /* Set perpendicular mode as required, based on data rate, if supported.
! 641: * 80277: 1Mbps data rate only possible with 82077-1.
! 642: * Untested!! TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
! 643: */
! 644: static void inline perpendicular_mode(unsigned char rate)
! 645: {
! 646: if (fdc_version == FDC_TYPE_82077) {
! 647: output_byte(FD_PERPENDICULAR);
! 648: if (rate & 0x40) {
! 649: unsigned char r = rate & 0x03;
! 650: if (r == 0)
! 651: output_byte(2); /* perpendicular, 500 kbps */
! 652: else if (r == 3)
! 653: output_byte(3); /* perpendicular, 1Mbps */
! 654: else {
! 655: printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
! 656: reset = 1;
! 657: }
! 658: } else
! 659: output_byte(0); /* conventional mode */
! 660: } else {
! 661: if (rate & 0x40) {
! 662: printk(DEVICE_NAME ": perpendicular mode not supported by FDC.\n");
! 663: reset = 1;
! 664: }
! 665: }
! 666: } /* perpendicular_mode */
! 667:
1.1 root 668: /*
669: * This routine is called when everything should be correctly set up
670: * for the transfer (ie floppy motor is on and the correct floppy is
671: * selected).
672: */
673: static void transfer(void)
674: {
1.1.1.7 root 675: read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
676: (floppy->sect <= MAX_BUFFER_SECTORS);
1.1 root 677: if (cur_spec1 != floppy->spec1) {
678: cur_spec1 = floppy->spec1;
679: output_byte(FD_SPECIFY);
680: output_byte(cur_spec1); /* hut etc */
681: output_byte(6); /* Head load time =6ms, DMA */
682: }
1.1.1.10! root 683: if (cur_rate != floppy->rate) {
! 684: /* use bit 6 of floppy->rate to indicate perpendicular mode */
! 685: perpendicular_mode(floppy->rate);
! 686: outb_p(cur_rate = ((floppy->rate)) & ~0x40, FD_DCR);
! 687: }
1.1.1.2 root 688: if (reset) {
1.1.1.7 root 689: redo_fd_request();
1.1.1.2 root 690: return;
691: }
692: if (!seek) {
693: setup_rw_floppy();
694: return;
695: }
1.1 root 696: do_floppy = seek_interrupt;
1.1.1.4 root 697: output_byte(FD_SEEK);
698: if (read_track)
699: output_byte(current_drive);
700: else
701: output_byte((head<<2) | current_drive);
702: output_byte(seek_track);
1.1.1.2 root 703: if (reset)
1.1.1.7 root 704: redo_fd_request();
1.1 root 705: }
706:
707: /*
708: * Special case - used after a unexpected interrupt (or reset)
709: */
1.1.1.7 root 710:
1.1.1.10! root 711: static void recalibrate_floppy(void);
1.1.1.7 root 712:
1.1 root 713: static void recal_interrupt(void)
714: {
715: output_byte(FD_SENSEI);
1.1.1.5 root 716: current_track = NO_TRACK;
1.1.1.2 root 717: if (result()!=2 || (ST0 & 0xE0) == 0x60)
718: reset = 1;
1.1.1.7 root 719: /* Recalibrate until track 0 is reached. Might help on some errors. */
720: if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
721: else redo_fd_request();
1.1 root 722: }
723:
1.1.1.10! root 724: static void unexpected_floppy_interrupt(void)
1.1 root 725: {
1.1.1.5 root 726: current_track = NO_TRACK;
1.1 root 727: output_byte(FD_SENSEI);
1.1.1.10! root 728: printk(DEVICE_NAME ": unexpected interrupt\n");
1.1.1.2 root 729: if (result()!=2 || (ST0 & 0xE0) == 0x60)
730: reset = 1;
731: else
732: recalibrate = 1;
733: }
734:
735: static void recalibrate_floppy(void)
736: {
737: recalibrate = 0;
738: current_track = 0;
1.1 root 739: do_floppy = recal_interrupt;
740: output_byte(FD_RECALIBRATE);
741: output_byte(head<<2 | current_drive);
1.1.1.2 root 742: if (reset)
1.1.1.7 root 743: redo_fd_request();
1.1 root 744: }
745:
1.1.1.10! root 746: /*
! 747: * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
! 748: */
1.1 root 749: static void reset_interrupt(void)
750: {
1.1.1.10! root 751: short i;
! 752:
! 753: for (i=0; i<4; i++) {
! 754: output_byte(FD_SENSEI);
! 755: (void) result();
! 756: }
1.1.1.2 root 757: output_byte(FD_SPECIFY);
758: output_byte(cur_spec1); /* hut etc */
759: output_byte(6); /* Head load time =6ms, DMA */
1.1.1.10! root 760: configure_fdc_mode(); /* reprogram if smart fdc */
1.1.1.7 root 761: if (!recover) redo_fd_request();
762: else {
763: recalibrate_floppy();
764: recover = 0;
765: }
1.1 root 766: }
767:
1.1.1.2 root 768: /*
769: * reset is done by pulling bit 2 of DOR low for a while.
770: */
1.1 root 771: static void reset_floppy(void)
772: {
1.1.1.2 root 773: int i;
774:
1.1.1.5 root 775: do_floppy = reset_interrupt;
1.1.1.2 root 776: reset = 0;
1.1.1.5 root 777: current_track = NO_TRACK;
1.1.1.2 root 778: cur_spec1 = -1;
779: cur_rate = -1;
780: recalibrate = 1;
1.1 root 781: printk("Reset-floppy called\n\r");
1.1.1.2 root 782: cli();
783: outb_p(current_DOR & ~0x04,FD_DOR);
1.1.1.5 root 784: for (i=0 ; i<1000 ; i++)
1.1.1.2 root 785: __asm__("nop");
1.1 root 786: outb(current_DOR,FD_DOR);
1.1.1.2 root 787: sti();
1.1 root 788: }
789:
1.1.1.7 root 790: static void floppy_shutdown(void)
791: {
792: cli();
793: request_done(0);
794: recover = 1;
795: reset_floppy();
796: sti();
797: }
798:
799: static void shake_done(void)
800: {
801: current_track = NO_TRACK;
802: if (inb(FD_DIR) & 0x80) request_done(0);
803: redo_fd_request();
804: }
805:
806: static int retry_recal(void (*proc)(void))
807: {
808: output_byte(FD_SENSEI);
809: if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;
810: do_floppy = proc;
811: output_byte(FD_RECALIBRATE);
812: output_byte(head<<2 | current_drive);
813: return 1;
814: }
815:
816: static void shake_zero(void)
817: {
818: if (!retry_recal(shake_zero)) shake_done();
819: }
820:
821: static void shake_one(void)
822: {
823: if (retry_recal(shake_one)) return;
824: do_floppy = shake_done;
825: output_byte(FD_SEEK);
826: output_byte(head << 2 | current_drive);
827: output_byte(1);
828: }
829:
1.1 root 830: static void floppy_on_interrupt(void)
831: {
1.1.1.5 root 832: if (inb(FD_DIR) & 0x80) {
833: changed_floppies |= 1<<current_drive;
834: buffer_track = -1;
1.1.1.7 root 835: if (keep_data[current_drive]) {
836: if (keep_data[current_drive] > 0)
837: keep_data[current_drive]--;
838: }
839: else {
840: if (ftd_msg[current_drive] && current_type[
841: current_drive] != NULL)
842: printk("Disk type is undefined after disk "
843: "change in fd%d\r\n",current_drive);
844: current_type[current_drive] = NULL;
845: floppy_sizes[current_drive] = MAX_DISK_SIZE;
846: }
847: /* Forcing the drive to seek makes the "media changed" condition go away.
1.1.1.10! root 848: * There should be a cleaner solution for that ...
! 849: */
1.1.1.7 root 850: if (!reset && !recalibrate) {
851: do_floppy = (current_track && current_track != NO_TRACK)
852: ? shake_zero : shake_one;
853: output_byte(FD_RECALIBRATE);
854: output_byte(head<<2 | current_drive);
855: return;
856: }
1.1.1.5 root 857: }
858: if (reset) {
859: reset_floppy();
860: return;
861: }
862: if (recalibrate) {
863: recalibrate_floppy();
864: return;
865: }
1.1 root 866: /* We cannot do a floppy-select, as that might sleep. We just force it */
867: selected = 1;
1.1.1.2 root 868: if (current_drive != (current_DOR & 3)) {
1.1.1.6 root 869: seek = 1;
870: current_track = NO_TRACK;
1.1.1.2 root 871: current_DOR &= 0xFC;
872: current_DOR |= current_drive;
873: outb(current_DOR,FD_DOR);
874: add_timer(2,&transfer);
875: } else
876: transfer();
1.1 root 877: }
878:
1.1.1.7 root 879: static void setup_format_params(void)
880: {
881: unsigned char *here = (unsigned char *) tmp_floppy_area;
882: int count;
883:
1.1.1.10! root 884: /* XXX: should do a check to see this fits in tmp_floppy_area!! */
1.1.1.7 root 885: for (count = 1; count <= floppy->sect; count++) {
886: *here++ = track;
887: *here++ = head;
888: *here++ = count;
889: *here++ = 2; /* 512 bytes */
890: }
891: }
892:
893: static void redo_fd_request(void)
1.1 root 894: {
895: unsigned int block;
1.1.1.4 root 896: char * buffer_area;
1.1.1.7 root 897: int device;
1.1 root 898:
1.1.1.7 root 899: repeat:
1.1.1.10! root 900: if (format_status == FORMAT_WAIT)
! 901: format_status = FORMAT_BUSY;
1.1.1.7 root 902: if (format_status != FORMAT_BUSY) {
903: if (!CURRENT) {
1.1.1.10! root 904: if (!fdc_busy)
! 905: printk("FDC access conflict");
1.1.1.7 root 906: fdc_busy = 0;
907: wake_up(&fdc_wait);
908: CLEAR_INTR;
909: return;
910: }
911: if (MAJOR(CURRENT->dev) != MAJOR_NR)
912: panic(DEVICE_NAME ": request list destroyed"); \
913: if (CURRENT->bh) {
914: if (!CURRENT->bh->b_lock)
915: panic(DEVICE_NAME ": block not locked");
916: }
917: }
1.1.1.5 root 918: seek = 0;
1.1.1.7 root 919: probing = 0;
920: device = MINOR(CURRENT_DEVICE);
921: if (device > 3)
922: floppy = (device >> 2) + floppy_type;
923: else { /* Auto-detection */
924: if ((floppy = current_type[device & 3]) == NULL) {
925: probing = 1;
926: if ((floppy = base_type[device & 3]) ==
927: NULL) {
928: request_done(0);
929: goto repeat;
930: }
931: floppy += CURRENT_ERRORS & 1;
932: }
933: }
934: if (format_status != FORMAT_BUSY) {
1.1.1.10! root 935: if (current_drive != CURRENT_DEV) {
1.1.1.7 root 936: current_track = NO_TRACK;
1.1.1.10! root 937: current_drive = CURRENT_DEV;
! 938: }
1.1.1.7 root 939: block = CURRENT->sector;
940: if (block+2 > floppy->size) {
941: request_done(0);
942: goto repeat;
943: }
944: sector = block % floppy->sect;
945: block /= floppy->sect;
946: head = block % floppy->head;
947: track = block / floppy->head;
948: seek_track = track << floppy->stretch;
949: if (CURRENT->cmd == READ)
950: command = FD_READ;
951: else if (CURRENT->cmd == WRITE)
952: command = FD_WRITE;
953: else {
954: printk("do_fd_request: unknown command\n");
955: request_done(0);
956: goto repeat;
957: }
1.1.1.10! root 958: } else {
1.1.1.7 root 959: if (current_drive != (format_req.device & 3))
960: current_track = NO_TRACK;
961: current_drive = format_req.device & 3;
1.1.1.9 root 962: if (((unsigned) format_req.track) >= floppy->track ||
1.1.1.7 root 963: (format_req.head & 0xfffe) || probing) {
964: request_done(0);
965: goto repeat;
966: }
967: head = format_req.head;
968: track = format_req.track;
969: seek_track = track << floppy->stretch;
970: if (seek_track == buffer_track) buffer_track = -1;
971: command = FD_FORMAT;
972: setup_format_params();
1.1.1.4 root 973: }
1.1.1.7 root 974: timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
975: timer_active |= 1 << FLOPPY_TIMER;
1.1.1.4 root 976: if ((seek_track == buffer_track) &&
977: (current_drive == buffer_drive)) {
978: buffer_area = floppy_track_buffer +
979: ((sector + head*floppy->sect)<<9);
980: if (command == FD_READ) {
981: copy_buffer(buffer_area,CURRENT->buffer);
1.1.1.7 root 982: request_done(1);
1.1.1.4 root 983: goto repeat;
1.1.1.7 root 984: } else if (command == FD_WRITE)
1.1.1.4 root 985: copy_buffer(CURRENT->buffer,buffer_area);
986: }
987: if (seek_track != current_track)
988: seek = 1;
989: sector++;
1.1 root 990: add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
991: }
992:
1.1.1.7 root 993: void do_fd_request(void)
994: {
995: cli();
996: while (fdc_busy) sleep_on(&fdc_wait);
997: fdc_busy = 1;
998: sti();
999: redo_fd_request();
1000: }
1001:
1002: static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
1003: unsigned int param)
1004: {
1005: int drive,cnt,okay;
1006: struct floppy_struct *this;
1007:
1.1.1.10! root 1008: switch (cmd) {
! 1009: RO_IOCTLS(inode->i_rdev,param);
! 1010: }
1.1.1.7 root 1011: if (!suser()) return -EPERM;
1012: drive = MINOR(inode->i_rdev);
1013: switch (cmd) {
1014: case FDFMTBEG:
1015: return 0;
1016: case FDFMTEND:
1017: cli();
1018: fake_change |= 1 << (drive & 3);
1019: sti();
1020: drive &= 3;
1021: cmd = FDCLRPRM;
1022: break;
1023: case FDGETPRM:
1024: if (drive > 3) this = &floppy_type[drive >> 2];
1025: else if ((this = current_type[drive & 3]) == NULL)
1026: return -ENODEV;
1027: verify_area((void *) param,sizeof(struct floppy_struct));
1028: for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
1029: put_fs_byte(((char *) this)[cnt],
1030: (char *) param+cnt);
1031: return 0;
1032: case FDFMTTRK:
1033: cli();
1034: while (format_status != FORMAT_NONE)
1035: sleep_on(&format_done);
1036: for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
1037: ((char *) &format_req)[cnt] = get_fs_byte(
1038: (char *) param+cnt);
1039: format_req.device = drive;
1040: format_status = FORMAT_WAIT;
1041: format_errors = 0;
1042: while (format_status != FORMAT_OKAY && format_status !=
1043: FORMAT_ERROR) {
1044: if (fdc_busy) sleep_on(&fdc_wait);
1045: else {
1046: fdc_busy = 1;
1047: redo_fd_request();
1048: }
1049: }
1050: while (format_status != FORMAT_OKAY && format_status !=
1051: FORMAT_ERROR)
1052: sleep_on(&format_done);
1053: sti();
1054: okay = format_status == FORMAT_OKAY;
1055: format_status = FORMAT_NONE;
1056: wake_up(&format_done);
1057: return okay ? 0 : -EIO;
1058: }
1059: if (drive < 0 || drive > 3) return -EINVAL;
1060: switch (cmd) {
1061: case FDCLRPRM:
1062: current_type[drive] = NULL;
1063: floppy_sizes[drive] = MAX_DISK_SIZE;
1064: keep_data[drive] = 0;
1065: break;
1066: case FDSETPRM:
1067: case FDDEFPRM:
1068: for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
1069: ((char *) &user_params[drive])[cnt] =
1070: get_fs_byte((char *) param+cnt);
1071: current_type[drive] = &user_params[drive];
1072: floppy_sizes[drive] = user_params[drive].size >> 1;
1073: if (cmd == FDDEFPRM) keep_data[drive] = -1;
1074: else {
1075: cli();
1076: while (fdc_busy) sleep_on(&fdc_wait);
1077: fdc_busy = 1;
1078: sti();
1079: outb_p((current_DOR & 0xfc) | drive |
1080: (0x10 << drive),FD_DOR);
1081: for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
1082: keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
1083: outb_p(current_DOR,FD_DOR);
1084: fdc_busy = 0;
1085: wake_up(&fdc_wait);
1086: }
1087: break;
1088: case FDMSGON:
1089: ftd_msg[drive] = 1;
1090: break;
1091: case FDMSGOFF:
1092: ftd_msg[drive] = 0;
1093: break;
1.1.1.10! root 1094: case FDSETEMSGTRESH:
! 1095: min_report_error_cnt[drive] = (unsigned short) (param & 0x0f);
! 1096: break;
1.1.1.7 root 1097: default:
1098: return -EINVAL;
1099: }
1100: return 0;
1101: }
1102:
1103: #define CMOS_READ(addr) ({ \
1104: outb_p(0x80|addr,0x70); \
1105: inb_p(0x71); \
1106: })
1107:
1108: static struct floppy_struct *find_base(int drive,int code)
1109: {
1110: struct floppy_struct *base;
1111:
1112: if (code > 0 && code < 5) {
1113: base = &floppy_types[(code-1)*2];
1114: printk("fd%d is %s",drive,base->name);
1115: return base;
1116: }
1117: printk("fd%d is unknown type %d",drive,code);
1118: return NULL;
1119: }
1120:
1121: static void config_types(void)
1122: {
1123: printk("Floppy drive(s): ");
1124: base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
1.1.1.8 root 1125: if (((CMOS_READ(0x14) >> 6) & 1) == 0)
1126: base_type[1] = NULL;
1.1.1.7 root 1127: else {
1128: printk(", ");
1129: base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
1130: }
1131: base_type[2] = base_type[3] = NULL;
1132: printk("\r\n");
1133: }
1134:
1.1.1.10! root 1135: /*
! 1136: * floppy_open check for aliasing (/dev/fd0 can be the same as
! 1137: * /dev/PS0 etc), and disallows simultaneous access to the same
! 1138: * drive with different device numbers.
! 1139: */
1.1.1.7 root 1140: static int floppy_open(struct inode * inode, struct file * filp)
1141: {
1.1.1.10! root 1142: int drive;
! 1143: int old_dev;
! 1144:
! 1145: drive = inode->i_rdev & 3;
! 1146: old_dev = fd_device[drive];
! 1147: if (fd_ref[drive])
! 1148: if (old_dev != inode->i_rdev)
! 1149: return -EBUSY;
! 1150: fd_ref[drive]++;
! 1151: fd_device[drive] = inode->i_rdev;
! 1152: if (old_dev && old_dev != inode->i_rdev)
! 1153: invalidate_buffers(old_dev);
! 1154: if (filp && filp->f_mode)
1.1.1.7 root 1155: check_disk_change(inode->i_rdev);
1156: return 0;
1157: }
1158:
1159: static void floppy_release(struct inode * inode, struct file * filp)
1160: {
1161: sync_dev(inode->i_rdev);
1.1.1.10! root 1162: if (!fd_ref[inode->i_rdev & 3]--) {
! 1163: printk("floppy_release with fd_ref == 0");
! 1164: fd_ref[inode->i_rdev & 3] = 0;
! 1165: }
1.1.1.7 root 1166: }
1167:
1168: static struct file_operations floppy_fops = {
1169: NULL, /* lseek - default */
1170: block_read, /* read - general block-dev read */
1171: block_write, /* write - general block-dev write */
1172: NULL, /* readdir - bad */
1173: NULL, /* select */
1174: fd_ioctl, /* ioctl */
1175: floppy_open, /* open */
1176: floppy_release /* release */
1.1.1.3 root 1177: };
1178:
1.1.1.10! root 1179:
! 1180: /*
! 1181: * The version command is not supposed to generate an interrupt, but
! 1182: * my FDC does, except when booting in SVGA screen mode.
! 1183: * When it does generate an interrupt, it doesn't return any status bytes.
! 1184: * It appears to have something to do with the version command...
! 1185: */
! 1186: static void ignore_interrupt(void)
! 1187: {
! 1188: if (result() != 0) {
! 1189: printk(DEVICE_NAME ": weird interrupt ignored\n");
! 1190: reset = 1;
! 1191: }
! 1192: CLEAR_INTR; /* ignore only once */
! 1193: }
! 1194:
! 1195:
! 1196: static void floppy_interrupt(int unused)
! 1197: {
! 1198: void (*handler)(void) = DEVICE_INTR;
! 1199:
! 1200: DEVICE_INTR = NULL;
! 1201: if (!handler)
! 1202: handler = unexpected_floppy_interrupt;
! 1203: handler();
! 1204: }
! 1205:
! 1206: /*
! 1207: * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags
! 1208: * means we run the IRQ-handler with interrupts disabled.
! 1209: */
! 1210: static struct sigaction floppy_sigaction = {
! 1211: floppy_interrupt,
! 1212: 0,
! 1213: SA_INTERRUPT,
! 1214: NULL
! 1215: };
! 1216:
1.1 root 1217: void floppy_init(void)
1218: {
1.1.1.4 root 1219: outb(current_DOR,FD_DOR);
1.1.1.3 root 1220: blk_size[MAJOR_NR] = floppy_sizes;
1.1 root 1221: blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1.1.1.7 root 1222: blkdev_fops[MAJOR_NR] = &floppy_fops;
1223: timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
1224: timer_active &= ~(1 << FLOPPY_TIMER);
1225: config_types();
1.1.1.10! root 1226: if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
! 1227: printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ);
! 1228:
! 1229: /* Try to determine the floppy controller type */
! 1230: DEVICE_INTR = ignore_interrupt; /* don't ask ... */
! 1231: output_byte(FD_VERSION); /* get FDC version code */
! 1232: if (result() != 1) {
! 1233: printk(DEVICE_NAME ": FDC failed to return version byte\n");
! 1234: fdc_version = FDC_TYPE_STD;
! 1235: } else
! 1236: fdc_version = reply_buffer[0];
! 1237: if (fdc_version != FDC_TYPE_STD)
! 1238: printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);
! 1239: #ifndef FDC_FIFO_UNTESTED
! 1240: fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */
! 1241: #endif
! 1242: configure_fdc_mode();
1.1 root 1243: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.