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