[BACK]Return to fdd.c CVS log [TXT][DIR] Up to [local] / prex-old / dev / i386 / pc

Annotation of prex-old/dev/i386/pc/fdd.c, Revision 1.1

1.1     ! nbrk        1: /*-
        !             2:  * Copyright (c) 2005-2006, Kohsuke Ohtani
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. Neither the name of the author nor the names of any co-contributors
        !            14:  *    may be used to endorse or promote products derived from this software
        !            15:  *    without specific prior written permission.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /*
        !            31:  * fdd.c - Floppy disk driver
        !            32:  */
        !            33:
        !            34: /*
        !            35:  *  State transition table:
        !            36:  *
        !            37:  *    State     Interrupt Timeout   Error
        !            38:  *    --------- --------- --------- ---------
        !            39:  *    Off       N/A       On        N/A
        !            40:  *    On        N/A       Reset     N/A
        !            41:  *    Reset     Recal     Off       N/A
        !            42:  *    Recal     Seek      Off       Off
        !            43:  *    Seek      IO        Reset     Off
        !            44:  *    IO        Ready     Reset     Off
        !            45:  *    Ready     N/A       Off       N/A
        !            46:  *
        !            47:  */
        !            48:
        !            49: #include <driver.h>
        !            50: #include <delay.h>
        !            51: #include <cpu.h>
        !            52:
        !            53: #include "dma.h"
        !            54:
        !            55: /* #define DEBUG_FDD */
        !            56:
        !            57: #ifdef DEBUG_FDD
        !            58: #define fdd_printf(fmt, args...)       printk("%s: " fmt, ## args)
        !            59: #else
        !            60: #define fdd_printf(fmt...)             do {} while (0)
        !            61: #endif
        !            62:
        !            63: #define FDD_IRQ                6       /* IRQ6 */
        !            64: #define FDD_DMA                2       /* DMA2 */
        !            65:
        !            66: #define SECTOR_SIZE    512
        !            67: #define TRACK_SIZE     (SECTOR_SIZE * 18)
        !            68: #define INVALID_TRACK  -1
        !            69:
        !            70: /* I/O ports */
        !            71: #define FDC_DOR                0x3f2   /* Digital output register */
        !            72: #define FDC_MSR                0x3f4   /* Main status register (in) */
        !            73: #define FDC_DSR                0x3f4   /* Data rate select register (out) */
        !            74: #define FDC_DAT                0x3f5   /* Data register */
        !            75: #define FDC_DIR                0x3f7   /* Digital input register (in) */
        !            76: #define FDC_CCR                0x3f7   /* Configuration control register (out) */
        !            77:
        !            78: /* Command bytes */
        !            79: #define CMD_SPECIFY    0x03    /* Specify drive timing */
        !            80: #define CMD_DRVSTS     0x04
        !            81: #define CMD_WRITE      0xc5    /* Sector write, multi-track */
        !            82: #define CMD_READ       0xe6    /* Sector read */
        !            83: #define CMD_RECAL      0x07    /* Recalibrate */
        !            84: #define CMD_SENSE      0x08    /* Sense interrupt status */
        !            85: #define CMD_FORMAT     0x4d    /* Format track */
        !            86: #define CMD_SEEK       0x0f    /* Seek track */
        !            87: #define CMD_VERSION    0x10    /* FDC version */
        !            88:
        !            89: /* Floppy Drive Geometries */
        !            90: #define FDG_HEADS      2
        !            91: #define FDG_TRACKS     80
        !            92: #define FDG_SECTORS    18
        !            93: #define FDG_GAP3FMT    0x54
        !            94: #define FDG_GAP3RW     0x1b
        !            95:
        !            96: /* FDC state */
        !            97: #define FDS_OFF                0       /* Motor off */
        !            98: #define FDS_ON         1       /* Motor on */
        !            99: #define FDS_RESET      2       /* Reset */
        !           100: #define FDS_RECAL      3       /* Recalibrate */
        !           101: #define FDS_SEEK       4       /* Seek */
        !           102: #define FDS_IO         5       /* Read/write */
        !           103: #define FDS_READY      6       /* Ready */
        !           104:
        !           105: static void fdc_timeout(u_long);
        !           106: static void fdc_recal(void);
        !           107: static void fdc_off(void);
        !           108: static void fdc_io(void);
        !           109:
        !           110: static int fdd_init(void);
        !           111: static int fdd_open(device_t, int);
        !           112: static int fdd_close(device_t);
        !           113: static int fdd_read(device_t, char *, size_t *, int);
        !           114: static int fdd_write(device_t, char *, size_t *, int);
        !           115:
        !           116: /*
        !           117:  * I/O request
        !           118:  */
        !           119: struct io_req {
        !           120:        int     cmd;
        !           121:        int     nr_retry;
        !           122:        int     blkno;
        !           123:        u_long  blksz;
        !           124:        void    *buf;
        !           125:        int     errno;
        !           126: };
        !           127: typedef struct io_req *ioreq_t;
        !           128:
        !           129: /* I/O command */
        !           130: #define IO_NONE                0
        !           131: #define IO_READ                1
        !           132: #define IO_WRITE       2
        !           133: #define IO_FORMAT      3       /* not supported */
        !           134: #define IO_CANCEL      4
        !           135:
        !           136: /*
        !           137:  * Driver structure
        !           138:  */
        !           139: struct driver fdd_drv = {
        !           140:        /* name */      "Floppy Disk Controller",
        !           141:        /* order */     5,
        !           142:        /* init */      fdd_init,
        !           143: };
        !           144:
        !           145: static struct devio fdd_io = {
        !           146:        /* open */      fdd_open,
        !           147:        /* close */     fdd_close,
        !           148:        /* read */      fdd_read,
        !           149:        /* write */     fdd_write,
        !           150:        /* ioctl */     NULL,
        !           151:        /* event */     NULL,
        !           152: };
        !           153:
        !           154: static device_t fdd_dev;       /* Device object */
        !           155: static int fdd_irq;            /* Interrupt handle */
        !           156: static int fdd_dma;            /* DMA handle */
        !           157: static int nr_open;            /* Open count */
        !           158: static struct timer fdd_tmr;   /* Timer */
        !           159:
        !           160: static int fdc_stat;           /* Current state */
        !           161: static struct io_req ioreq;    /* I/O request */
        !           162: static void *read_buf;         /* DMA buffer for read (1 track) */
        !           163: static void *write_buf;                /* DMA buffer for write (1 sector) */
        !           164: static u_char result[7];       /* Result from fdc */
        !           165: static struct event io_event = EVENT_INIT(io_event, "fdd");
        !           166: static int track_cache;                /* Current track of read buffer */
        !           167:
        !           168: /*
        !           169:  * Send data to FDC
        !           170:  * Return -1 on failure
        !           171:  */
        !           172: static int
        !           173: fdc_out(u_char dat)
        !           174: {
        !           175:        int i;
        !           176:
        !           177:        for (i = 0; i < 100000; i++) {
        !           178:                if ((inb_p(FDC_MSR) & 0xc0) == 0x80) {
        !           179:                        outb_p(dat, FDC_DAT);
        !           180:                        return 0;
        !           181:                }
        !           182:        }
        !           183:        printk("fdc: timeout msr=%x\n", inb(FDC_MSR));
        !           184:        return -1;
        !           185: }
        !           186:
        !           187: /* Return number of result bytes */
        !           188: static int
        !           189: fdc_result(void)
        !           190: {
        !           191:        int i, msr, index = 0;
        !           192:
        !           193:        for (i = 0; i < 50000; i++) {   /* timeout=500msec */
        !           194:                msr = inb_p(FDC_MSR);
        !           195:                if ((msr & 0xd0) == 0x80) {
        !           196:                        return index;
        !           197:                }
        !           198:                if ((msr & 0xd0) == 0xd0) {
        !           199:                        if (index > 6) {
        !           200:                                printk("fdc: overrun\n");
        !           201:                                return -1;
        !           202:                        }
        !           203:                        result[index++] = inb_p(FDC_DAT);
        !           204:                        /*
        !           205:                        fdd_printf("result[%d]=%x\n", index - 1,
        !           206:                                   result[index - 1]);
        !           207:                        */
        !           208:                }
        !           209:                delay_usec(10);
        !           210:        }
        !           211:        printk("fdc: timeout\n");
        !           212:        return -1;
        !           213: }
        !           214:
        !           215: static void
        !           216: fdc_error(int errno)
        !           217: {
        !           218:        printk("fdc: errno=%d\n", errno);
        !           219:
        !           220:        dma_stop(fdd_dma);
        !           221:        ioreq.errno = errno;
        !           222:        sched_wakeup(&io_event);
        !           223:        fdc_off();
        !           224: }
        !           225:
        !           226: /*
        !           227:  * Stop motor. (No interrupt)
        !           228:  */
        !           229: static void
        !           230: fdc_off(void)
        !           231: {
        !           232:        fdd_printf("motor off\n");
        !           233:
        !           234:        fdc_stat = FDS_OFF;
        !           235:        timer_stop(&fdd_tmr);
        !           236:        outb_p(0x0c, FDC_DOR);
        !           237: }
        !           238:
        !           239: /*
        !           240:  * Start motor and wait 250msec. (No interrupt)
        !           241:  */
        !           242: static void
        !           243: fdc_on(void)
        !           244: {
        !           245:        fdd_printf("motor on\n");
        !           246:
        !           247:        fdc_stat = FDS_ON;
        !           248:        outb_p(0x1c, FDC_DOR);
        !           249:        timer_callout(&fdd_tmr, fdc_timeout, 0, 250);
        !           250: }
        !           251:
        !           252: /*
        !           253:  * Reset FDC and wait an intterupt.
        !           254:  * Timeout is 500msec.
        !           255:  */
        !           256: static void
        !           257: fdc_reset(void)
        !           258: {
        !           259:        fdd_printf("reset\n");
        !           260:
        !           261:        fdc_stat = FDS_RESET;
        !           262:        timer_callout(&fdd_tmr, fdc_timeout, 0, 500);
        !           263:        outb_p(0x18, FDC_DOR);  /* Motor0 enable, DMA enable */
        !           264:        delay_usec(20);         /* Wait 20 usec while reset */
        !           265:        outb_p(0x1c, FDC_DOR);  /* Clear reset */
        !           266: }
        !           267:
        !           268: /*
        !           269:  * Recalibrate FDC and wait an interrupt.
        !           270:  * Timeout is 5sec.
        !           271:  */
        !           272: static void
        !           273: fdc_recal(void)
        !           274: {
        !           275:        fdd_printf("recalibrate\n");
        !           276:
        !           277:        fdc_stat = FDS_RECAL;
        !           278:        timer_callout(&fdd_tmr, fdc_timeout, 0, 5000);
        !           279:        fdc_out(CMD_RECAL);
        !           280:        fdc_out(0);             /* Drive 0 */
        !           281: }
        !           282:
        !           283: /*
        !           284:  * Seek FDC and wait an interrupt.
        !           285:  * Timeout is 4sec.
        !           286:  */
        !           287: static void
        !           288: fdc_seek(void)
        !           289: {
        !           290:        u_int head, track;
        !           291:
        !           292:        fdd_printf("seek\n");
        !           293:        fdc_stat = FDS_SEEK;
        !           294:        head = (ioreq.blkno % (FDG_SECTORS * FDG_HEADS)) / FDG_SECTORS;
        !           295:        track = ioreq.blkno / (FDG_SECTORS * FDG_HEADS);
        !           296:
        !           297:        timer_callout(&fdd_tmr, fdc_timeout, 0, 4000);
        !           298:
        !           299:        fdc_out(CMD_SPECIFY);   /* specify command parameter */
        !           300:        fdc_out(0xd1);          /* Step rate = 3msec, Head unload time = 16msec */
        !           301:        fdc_out(0x02);          /* Head load time = 2msec, Dma on (0) */
        !           302:
        !           303:        fdc_out(CMD_SEEK);
        !           304:        fdc_out(head << 2);
        !           305:        fdc_out(track);
        !           306: }
        !           307:
        !           308: /*
        !           309:  * Read/write data and wait an interrupt.
        !           310:  * Timeout is 2sec.
        !           311:  */
        !           312: static void
        !           313: fdc_io(void)
        !           314: {
        !           315:        u_int head, track, sect;
        !           316:        u_long io_size;
        !           317:        int read;
        !           318:
        !           319:        fdd_printf("read/write\n");
        !           320:        fdc_stat = FDS_IO;
        !           321:
        !           322:        head = (ioreq.blkno % (FDG_SECTORS * FDG_HEADS)) / FDG_SECTORS;
        !           323:        track = ioreq.blkno / (FDG_SECTORS * FDG_HEADS);
        !           324:        sect = ioreq.blkno % FDG_SECTORS + 1;
        !           325:        io_size = ioreq.blksz * SECTOR_SIZE;
        !           326:        read = (ioreq.cmd == IO_READ) ? 1 : 0;
        !           327:
        !           328:        fdd_printf("hd=%x trk=%x sec=%x size=%d read=%d\n",
        !           329:                   head, track, sect, io_size, read);
        !           330:
        !           331:        timer_callout(&fdd_tmr, fdc_timeout, 0, 2000);
        !           332:
        !           333:        dma_setup(fdd_dma, (u_long) ioreq.buf, io_size, read);
        !           334:
        !           335:        /* Send command */
        !           336:        fdc_out(read ? CMD_READ : CMD_WRITE);
        !           337:        fdc_out(head << 2);
        !           338:        fdc_out(track);
        !           339:        fdc_out(head);
        !           340:        fdc_out(sect);
        !           341:        fdc_out(2);             /* sector size = 512 bytes */
        !           342:        fdc_out(FDG_SECTORS);
        !           343:        fdc_out(FDG_GAP3RW);
        !           344:        fdc_out(0xff);
        !           345: }
        !           346:
        !           347: /*
        !           348:  * Wake up iorequester.
        !           349:  * FDC motor is set to off after 5sec.
        !           350:  */
        !           351: static void
        !           352: fdc_ready(void)
        !           353: {
        !           354:        fdd_printf("wakeup requester\n");
        !           355:
        !           356:        fdc_stat = FDS_READY;
        !           357:        sched_wakeup(&io_event);
        !           358:        timer_callout(&fdd_tmr, fdc_timeout, 0, 5000);
        !           359: }
        !           360:
        !           361: /*
        !           362:  * Timeout handler
        !           363:  */
        !           364: static void
        !           365: fdc_timeout(u_long unused)
        !           366: {
        !           367:        fdd_printf("fdc_stat=%d\n", fdc_stat);
        !           368:
        !           369:        switch (fdc_stat) {
        !           370:        case FDS_ON:
        !           371:                fdc_reset();
        !           372:                break;
        !           373:        case FDS_RESET:
        !           374:        case FDS_RECAL:
        !           375:                printk("fdc: reset/recal timeout\n");
        !           376:                fdc_error(EIO);
        !           377:                break;
        !           378:        case FDS_SEEK:
        !           379:        case FDS_IO:
        !           380:                printk("fdc: seek/io timeout retry=%d\n", ioreq.nr_retry);
        !           381:                if (++ioreq.nr_retry <= 3)
        !           382:                        fdc_reset();
        !           383:                else
        !           384:                        fdc_error(EIO);
        !           385:                break;
        !           386:        case FDS_READY:
        !           387:                fdc_off();
        !           388:                break;
        !           389:        default:
        !           390:                panic("fdc: unknown timeout\n");
        !           391:        }
        !           392: }
        !           393:
        !           394: /*
        !           395:  * Interrupt service routine
        !           396:  * Do not change the fdc_stat in isr.
        !           397:  */
        !           398: static int
        !           399: fdc_isr(int irq)
        !           400: {
        !           401:        fdd_printf("fdc_stat=%d\n", fdc_stat);
        !           402:
        !           403:        timer_stop(&fdd_tmr);
        !           404:        switch (fdc_stat) {
        !           405:        case FDS_IO:
        !           406:                dma_stop(fdd_dma);
        !           407:                /* Fall through */
        !           408:        case FDS_RESET:
        !           409:        case FDS_RECAL:
        !           410:        case FDS_SEEK:
        !           411:                if (ioreq.cmd == IO_NONE) {
        !           412:                        printk("fdc: invalid interrupt\n");
        !           413:                        timer_stop(&fdd_tmr);
        !           414:                        break;
        !           415:                }
        !           416:                return INT_CONTINUE;
        !           417:        case FDS_OFF:
        !           418:                break;
        !           419:        default:
        !           420:                printk("fdc: unknown interrupt\n");
        !           421:                break;
        !           422:        }
        !           423:        return 0;
        !           424: }
        !           425:
        !           426: /*
        !           427:  * Interrupt service thread
        !           428:  * This is called when command completion.
        !           429:  */
        !           430: static void
        !           431: fdc_ist(int irq)
        !           432: {
        !           433:        int i;
        !           434:
        !           435:        fdd_printf("fdc_stat=%d\n", fdc_stat);
        !           436:        if (ioreq.cmd == IO_NONE)
        !           437:                return;
        !           438:
        !           439:        switch (fdc_stat) {
        !           440:        case FDS_RESET:
        !           441:                /* clear output buffer */
        !           442:                for (i = 0; i < 4; i++) {
        !           443:                        fdc_out(CMD_SENSE);
        !           444:                        fdc_result();
        !           445:                }
        !           446:                fdc_recal();
        !           447:                break;
        !           448:        case FDS_RECAL:
        !           449:                fdc_out(CMD_SENSE);
        !           450:                fdc_result();
        !           451:                if ((result[0] & 0xf8) != 0x20) {
        !           452:                        printk("fdc: recal error\n");
        !           453:                        fdc_error(EIO);
        !           454:                        break;
        !           455:                }
        !           456:                fdc_seek();
        !           457:                break;
        !           458:        case FDS_SEEK:
        !           459:                fdc_out(CMD_SENSE);
        !           460:                fdc_result();
        !           461:                if ((result[0] & 0xf8) != 0x20) {
        !           462:                        printk("fdc: seek error\n");
        !           463:                        if (++ioreq.nr_retry <= 3)
        !           464:                                fdc_reset();
        !           465:                        else
        !           466:                                fdc_error(EIO);
        !           467:                        break;
        !           468:                }
        !           469:                fdc_io();
        !           470:                break;
        !           471:        case FDS_IO:
        !           472:                fdc_result();
        !           473:                if ((result[0] & 0xd8) != 0x00) {
        !           474:                        printk("fdc: i/o error st0=%x st1=%x st2=%x st3=%x retry=%d\n",
        !           475:                             result[0], result[1], result[2], result[3],
        !           476:                             ioreq.nr_retry);
        !           477:                        if (++ioreq.nr_retry <= 3)
        !           478:                                fdc_reset();
        !           479:                        else
        !           480:                                fdc_error(EIO);
        !           481:                        break;
        !           482:                }
        !           483:                fdd_printf("i/o complete\n");
        !           484:                fdc_ready();
        !           485:                break;
        !           486:        case FDS_OFF:
        !           487:                /* Ignore */
        !           488:                break;
        !           489:        default:
        !           490:                ASSERT(0);
        !           491:        }
        !           492:        return;
        !           493: }
        !           494:
        !           495: /*
        !           496:  * Open
        !           497:  */
        !           498: static int
        !           499: fdd_open(device_t dev, int mode)
        !           500: {
        !           501:
        !           502:        nr_open++;
        !           503:        fdd_printf("nr_open=%d\n", nr_open);
        !           504:        return 0;
        !           505: }
        !           506:
        !           507: /*
        !           508:  * Close
        !           509:  */
        !           510: static int
        !           511: fdd_close(device_t dev)
        !           512: {
        !           513:        fdd_printf("dev=%x\n", dev);
        !           514:
        !           515:        if (nr_open < 1)
        !           516:                return EINVAL;
        !           517:        nr_open--;
        !           518:        if (nr_open == 0) {
        !           519:                ioreq.cmd = IO_NONE;
        !           520:                fdc_off();
        !           521:        }
        !           522:        return 0;
        !           523: }
        !           524:
        !           525: /*
        !           526:  * Common routine for read/write
        !           527:  */
        !           528: static int
        !           529: fdd_rw(int cmd, char *buf, u_long blksz, int blkno)
        !           530: {
        !           531:        int err;
        !           532:
        !           533:        fdd_printf("cmd=%x buf=%x blksz=%d blkno=%x\n", cmd, buf, blksz, blkno);
        !           534:        ioreq.cmd = cmd;
        !           535:        ioreq.nr_retry = 0;
        !           536:        ioreq.blkno = blkno;
        !           537:        ioreq.blksz = blksz;
        !           538:        ioreq.buf = buf;
        !           539:        ioreq.errno = 0;
        !           540:
        !           541:        sched_lock();
        !           542:        if (fdc_stat == FDS_OFF)
        !           543:                fdc_on();
        !           544:        else
        !           545:                fdc_seek();
        !           546:
        !           547:        if (sched_sleep(&io_event) == SLP_INTR)
        !           548:                err = EINTR;
        !           549:        else
        !           550:                err = ioreq.errno;
        !           551:
        !           552:        sched_unlock();
        !           553:        return err;
        !           554: }
        !           555:
        !           556: /*
        !           557:  * Read
        !           558:  *
        !           559:  * Error:
        !           560:  *  EINTR   ... Interrupted by signal
        !           561:  *  EIO     ... Low level I/O error
        !           562:  *  ENXIO   ... Write protected
        !           563:  *  EFAULT  ... No physical memory is mapped to buffer
        !           564:  */
        !           565: static int
        !           566: fdd_read(device_t dev, char *buf, size_t *nbyte, int blkno)
        !           567: {
        !           568:        char *kbuf;
        !           569:        int i, track, sect, nr_sect, err;
        !           570:
        !           571:        fdd_printf("read buf=%x nbyte=%d blkno=%x\n", buf, *nbyte, blkno);
        !           572:
        !           573:        /* Check overrun */
        !           574:        if (blkno > FDG_HEADS * FDG_TRACKS * FDG_SECTORS)
        !           575:                return EIO;
        !           576:
        !           577:        /* Translate buffer address to kernel address */
        !           578:        kbuf = kmem_map(buf, *nbyte);
        !           579:        if (kbuf == NULL)
        !           580:                return EFAULT;
        !           581:
        !           582:        nr_sect = *nbyte / SECTOR_SIZE;
        !           583:        err = 0;
        !           584:        for (i = 0; i < nr_sect; i++) {
        !           585:                /* Translate the logical sector# to logical track#/sector#. */
        !           586:                track = blkno / FDG_SECTORS;
        !           587:                sect = blkno % FDG_SECTORS;
        !           588:                /*
        !           589:                 * If target sector does not exist in buffer,
        !           590:                 * read 1 track (18 sectors) at once.
        !           591:                 */
        !           592:                if (track != track_cache) {
        !           593:                        err = fdd_rw(IO_READ, read_buf, FDG_SECTORS,
        !           594:                                     track * FDG_SECTORS);
        !           595:                        if (err) {
        !           596:                                track_cache = INVALID_TRACK;
        !           597:                                break;
        !           598:                        }
        !           599:                        track_cache = track;
        !           600:                }
        !           601:                memcpy(kbuf, (char *)read_buf + sect * SECTOR_SIZE,
        !           602:                       SECTOR_SIZE);
        !           603:                blkno++;
        !           604:                kbuf += SECTOR_SIZE;
        !           605:        }
        !           606:        *nbyte = i * SECTOR_SIZE;
        !           607:        return err;
        !           608: }
        !           609:
        !           610: /*
        !           611:  * Write
        !           612:  *
        !           613:  * Error:
        !           614:  *  EINTR   ... Interrupted by signal
        !           615:  *  EIO     ... Low level I/O error
        !           616:  *  ENXIO   ... Write protected
        !           617:  *  EFAULT  ... No physical memory is mapped to buffer
        !           618:  */
        !           619: static int
        !           620: fdd_write(device_t dev, char *buf, size_t *nbyte, int blkno)
        !           621: {
        !           622:        char *kbuf, *wbuf;
        !           623:        int i, track, sect, nr_sect, err;
        !           624:
        !           625:        fdd_printf("write buf=%x nbyte=%d blkno=%x\n", buf, *nbyte, blkno);
        !           626:
        !           627:        /* Check overrun */
        !           628:        if (blkno > FDG_HEADS * FDG_TRACKS * FDG_SECTORS)
        !           629:                return EIO;
        !           630:
        !           631:        /* Translate buffer address to kernel address */
        !           632:        kbuf = kmem_map(buf, *nbyte);
        !           633:        if (kbuf == NULL)
        !           634:                return EFAULT;
        !           635:
        !           636:        nr_sect = *nbyte / SECTOR_SIZE;
        !           637:        err = 0;
        !           638:        for (i = 0; i < nr_sect; i++) {
        !           639:                /* Translate the logical sector# to track#/sector#. */
        !           640:                track = blkno / FDG_SECTORS;
        !           641:                sect = blkno % FDG_SECTORS;
        !           642:                /*
        !           643:                 * If target sector exists in read buffer, use it as
        !           644:                 * write buffer to keep the cache cohrency.
        !           645:                 */
        !           646:                if (track == track_cache)
        !           647:                        wbuf = (char *)read_buf + sect * SECTOR_SIZE;
        !           648:                else
        !           649:                        wbuf = write_buf;
        !           650:
        !           651:                memcpy(wbuf, kbuf, SECTOR_SIZE);
        !           652:                err = fdd_rw(IO_WRITE, wbuf, 1, blkno);
        !           653:                if (err) {
        !           654:                        track_cache = INVALID_TRACK;
        !           655:                        break;
        !           656:                }
        !           657:                blkno++;
        !           658:                kbuf += SECTOR_SIZE;
        !           659:        }
        !           660:        *nbyte = i * SECTOR_SIZE;
        !           661:
        !           662:        fdd_printf("fdd_write err=%d\n", err);
        !           663:        return err;
        !           664: }
        !           665:
        !           666: /*
        !           667:  * Initialize
        !           668:  */
        !           669: static int
        !           670: fdd_init(void)
        !           671: {
        !           672:        char *buf;
        !           673:        int i;
        !           674:
        !           675:        fdd_printf("fdd_init\n");
        !           676:        if (inb(FDC_MSR) == 0xff) {
        !           677:                printk("Floppy drive not found!\n");
        !           678:                return -1;
        !           679:        }
        !           680:
        !           681:        /* Create device object */
        !           682:        fdd_dev = device_create(&fdd_io, "fd0", DF_BLK);
        !           683:        ASSERT(fdd_dev);
        !           684:
        !           685:        /*
        !           686:         * Allocate physical pages for DMA buffer.
        !           687:         * Buffer: 1 track for read, 1 sector for write.
        !           688:         */
        !           689:        buf = dma_alloc(TRACK_SIZE + SECTOR_SIZE);
        !           690:
        !           691:        ASSERT(buf);
        !           692:        read_buf = buf;
        !           693:        write_buf = buf + TRACK_SIZE;
        !           694:
        !           695:        /* Allocate DMA */
        !           696:        fdd_dma = dma_attach(FDD_DMA);
        !           697:        ASSERT(fdd_dma != -1);
        !           698:
        !           699:        /* Allocate IRQ */
        !           700:        fdd_irq = irq_attach(FDD_IRQ, IPL_BLOCK, 0, fdc_isr, fdc_ist);
        !           701:        ASSERT(fdd_irq != -1);
        !           702:
        !           703:        timer_init(&fdd_tmr);
        !           704:        fdc_stat = FDS_OFF;
        !           705:        ioreq.cmd = IO_NONE;
        !           706:        track_cache = INVALID_TRACK;
        !           707:
        !           708:        /* Reset FDC */
        !           709:        outb_p(0x08, FDC_DOR);
        !           710:        delay_usec(20);
        !           711:        outb_p(0x0C, FDC_DOR);
        !           712:
        !           713:        /* Data rate 500kbps */
        !           714:        outb_p(0x00, FDC_CCR);
        !           715:
        !           716:        /* clear output buffer */
        !           717:        for (i = 0; i < 4; i++) {
        !           718:                fdc_out(CMD_SENSE);
        !           719:                fdc_result();
        !           720:        }
        !           721:        return 0;
        !           722: }

CVSweb