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

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

unix.superglobalmegacorp.com

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