Annotation of linux/kernel/blk_drv/floppy.c, revision 1.1.1.10

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.