[BACK]Return to fd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / atari / dev

Annotation of src/sys/arch/atari/dev/fd.c, Revision 1.1.1.1

1.1       leo         1: /*     $NetBSD$        */
                      2:
                      3: /*
                      4:  * Copyright (c) 1995 Leo Weppelman.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *      This product includes software developed by Leo Weppelman.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * This file contains a driver for the Floppy Disk Controller (FDC)
                     35:  * on the Atari TT. It uses the WD 1772 chip, modified for steprates.
                     36:  *
                     37:  * The ST floppy disk controller shares the access to the DMA circuitry
                     38:  * with other devices. For this reason the floppy disk controller makes
                     39:  * use of some special DMA accessing code.
                     40:  *
                     41:  * Interrupts from the FDC are in fact DMA interrupts which get their
                     42:  * first level handling in 'dma.c' . If the floppy driver is currently
                     43:  * using DMA the interrupt is signalled to 'fdcint'.
                     44:  *
                     45:  * TODO:
                     46:  *   - Test it with 2 drives (I don't have them)
                     47:  *   - Test it with an HD-drive (Don't have that either)
                     48:  *   - Finish ioctl's
                     49:  */
                     50:
                     51: #include       <sys/param.h>
                     52: #include       <sys/systm.h>
                     53: #include       <sys/kernel.h>
                     54: #include       <sys/malloc.h>
                     55: #include       <sys/buf.h>
                     56: #include       <sys/device.h>
                     57: #include       <sys/ioctl.h>
                     58: #include       <sys/fcntl.h>
                     59: #include       <sys/conf.h>
                     60: #include       <sys/disklabel.h>
                     61: #include       <sys/disk.h>
                     62: #include       <sys/dkbad.h>
                     63: #include       <atari/atari/device.h>
                     64: #include       <machine/disklabel.h>
                     65: #include       <machine/iomap.h>
                     66: #include       <machine/mfp.h>
                     67: #include       <machine/dma.h>
                     68: #include       <machine/video.h>
                     69: #include       <atari/dev/fdreg.h>
                     70:
                     71: /*
                     72:  * Be verbose for debugging
                     73:  */
                     74: /*#define FLP_DEBUG            1 */
                     75:
                     76: #define        FDC_DELAY       64      /* for dma[rw]dat()                     */
                     77: #define        FDC_MAX_DMA_AD  0x1000000       /* No DMA possible beyond       */
                     78:
                     79: /* Parameters for the disk drive. */
                     80: #define SECTOR_SIZE    512     /* physical sector size in bytes        */
                     81: #define NR_DRIVES      2       /* maximum number of drives             */
                     82: #define NR_TYPES       3       /* number of diskette/drive combinations*/
                     83: #define MAX_ERRORS     10      /* how often to try rd/wt before quitting*/
                     84: #define STEP_DELAY     6000    /* 6ms (6000us) delay after stepping    */
                     85:
                     86:
                     87: #define        INV_TRK         32000   /* Should fit in unsigned short         */
                     88: #define        INV_PART        NR_TYPES
                     89:
                     90: /*
                     91:  * Driver states
                     92:  */
                     93: #define        FLP_IDLE        0x00    /* floppy is idle                       */
                     94: #define        FLP_MON         0x01    /* idle with motor on                   */
                     95: #define        FLP_STAT        0x02    /* determine floppy status              */
                     96: #define        FLP_XFER        0x04    /* read/write data from floppy          */
                     97:
                     98: /*
                     99:  * Timer delay's
                    100:  */
                    101: #define        FLP_MONDELAY    (3 * hz)        /* motor-on delay               */
                    102: #define        FLP_XFERDELAY   (2 * hz)        /* timeout on transfer          */
                    103:
                    104:
                    105: #define        b_block         b_resid         /* FIXME: this is not the place */
                    106:
                    107: /*
                    108:  * Global data for all physical floppy devices
                    109:  */
                    110: static short   selected = 0;           /* drive/head currently selected*/
                    111: static short   motoron  = 0;           /* motor is spinning            */
                    112: static short   nopens   = 0;           /* Number of opens executed     */
                    113:
                    114: static short   fd_state = FLP_IDLE;/* Current driver state             */
                    115: static short   fd_in_dma= 0;           /* 1: dmagrab() called          */
                    116: static short   fd_cmd   = 0;           /* command being executed       */
                    117: static char    *fd_error= NULL;        /* error from fd_xfer_ok()      */
                    118:
                    119: /*
                    120:  * Private per device data
                    121:  */
                    122: struct fd_softc {
                    123:        struct dkdevice dkdev;
                    124:        struct buf      bufq;           /* queue of buf's               */
                    125:        int             unit;           /* unit for atari controlling hw*/
                    126:        int             nheads;         /* number of heads in use       */
                    127:        int             nsectors;       /* number of sectors/track      */
                    128:        int             nblocks;        /* number of blocks on disk     */
                    129:        int             curtrk;         /* track head positioned on     */
                    130:        short           flags;          /* misc flags                   */
                    131:        short           part;           /* Current open partition       */
                    132:        int             sector;         /* logical sector for I/O       */
                    133:        caddr_t         io_data;        /* KVA for data transfer        */
                    134:        int             io_bytes;       /* bytes left for I/O           */
                    135:        int             io_dir;         /* B_READ/B_WRITE               */
                    136:        int             errcnt;         /* current error count          */
                    137:        u_char          *bounceb;       /* Bounce buffer                */
                    138:
                    139: };
                    140:
                    141: /*
                    142:  * Flags in fd_softc:
                    143:  */
                    144: #define FLPF_NOTRESP   0x01            /* Unit not responding          */
                    145: #define FLPF_ISOPEN    0x02            /* Unit is open                 */
                    146: #define FLPF_ISHD      0x04            /* Use High Density             */
                    147: #define FLPF_HAVELAB   0x08            /* We have a valid label        */
                    148: #define FLPF_BOUNCE    0x10            /* Now using the  bounce buffer */
                    149:
                    150: struct fd_types {
                    151:        int             nheads;         /* Heads in use                 */
                    152:        int             nsectors;       /* sectors per track            */
                    153:        int             nblocks;        /* number of blocks             */
                    154: } fdtypes[NR_TYPES] = {
                    155:                { 1,  9,  720 },        /* 360  Kb      */
                    156:                { 2,  9, 1440 },        /* 720  Kb      */
                    157:                { 1, 18, 2880 },        /* 1.44 Mb      */
                    158: };
                    159:
                    160: typedef void   (*FPV)();
                    161:
                    162: /*
                    163:  * Private drive functions....
                    164:  */
                    165: static void    fdstart __P((struct fd_softc *));
                    166: static void    fddone __P((struct fd_softc *));
                    167: static void    fd_xfer __P((struct fd_softc *));
                    168: static int     fdcint __P((struct fd_softc *));
                    169: static int     fd_xfer_ok __P((struct fd_softc *));
                    170: static void    fdmotoroff __P((struct fd_softc *));
                    171: static int     fdminphys __P((struct buf *));
                    172: static void    fdtestdrv __P((struct fd_softc *));
                    173: static int     fdgetdisklabel __P((struct fd_softc *, dev_t));
                    174:
                    175: /*
                    176:  * Autoconfig stuff....
                    177:  */
                    178: static int     fdcmatch __P((struct device *, struct cfdata *, void *));
                    179: static int     fdcprint __P((void *, char *));
                    180: static void    fdcattach __P((struct device *, struct device *, void *));
                    181:
                    182: struct cfdriver fdccd = {
                    183:        NULL, "fdc", (cfmatch_t)fdcmatch, fdcattach, DV_DULL,
                    184:        sizeof(struct device), NULL, 0 };
                    185:
                    186: static int
                    187: fdcmatch(pdp, cfp, auxp)
                    188: struct device  *pdp;
                    189: struct cfdata  *cfp;
                    190: void           *auxp;
                    191: {
                    192:        if(strcmp("fdc", auxp) || cfp->cf_unit != 0)
                    193:                return(0);
                    194:        return(1);
                    195: }
                    196:
                    197: static void
                    198: fdcattach(pdp, dp, auxp)
                    199: struct device  *pdp, *dp;
                    200: void           *auxp;
                    201: {
                    202:        struct fd_softc fdsoftc;
                    203:        int             i, nfound = 0;
                    204:
                    205:        printf("\n");
                    206:        for(i = 0; i < NR_DRIVES; i++) {
                    207:
                    208:                /*
                    209:                 * Test if unit is present
                    210:                 */
                    211:                fdsoftc.unit  = i;
                    212:                fdsoftc.flags = 0;
                    213:                dmagrab(fdcint, fdtestdrv, &fdsoftc);
                    214:                dmafree();
                    215:
                    216:                if(!(fdsoftc.flags & FLPF_NOTRESP)) {
                    217:                        nfound++;
                    218:                        config_found(dp, (void*)i, fdcprint);
                    219:                }
                    220:        }
                    221:
                    222:        if(nfound) {
                    223:                /*
                    224:                 * enable disk related interrupts
                    225:                 */
                    226:                MFP->mf_ierb  |= IB_DINT;
                    227:                MFP->mf_iprb  &= ~IB_DINT;
                    228:                MFP->mf_imrb  |= IB_DINT;
                    229:        }
                    230: }
                    231:
                    232: static int
                    233: fdcprint(auxp, pnp)
                    234: void   *auxp;
                    235: char   *pnp;
                    236: {
                    237:        return(UNCONF);
                    238: }
                    239:
                    240: static int     fdmatch __P((struct device *, struct cfdata *, void *));
                    241: static void    fdattach __P((struct device *, struct device *, void *));
                    242:           void fdstrategy __P((struct buf *));
                    243: struct dkdriver fddkdriver = { fdstrategy };
                    244:
                    245: struct cfdriver fdcd = {
                    246:        NULL, "fd", (cfmatch_t)fdmatch, fdattach, DV_DISK,
                    247:        sizeof(struct fd_softc), NULL, 0 };
                    248:
                    249: static int
                    250: fdmatch(pdp, cfp, auxp)
                    251: struct device  *pdp;
                    252: struct cfdata  *cfp;
                    253: void           *auxp;
                    254: {
                    255:        int     unit = (int)auxp;
                    256:        return(1);
                    257: }
                    258:
                    259: static void
                    260: fdattach(pdp, dp, auxp)
                    261: struct device  *pdp, *dp;
                    262: void           *auxp;
                    263: {
                    264:        struct fd_softc *sc;
                    265:
                    266:        sc = (struct fd_softc *)dp;
                    267:
                    268:        printf("\n");
                    269:
                    270:        sc->dkdev.dk_driver = &fddkdriver;
                    271: }
                    272:
                    273: fdioctl(dev, cmd, addr, flag, p)
                    274: dev_t          dev;
                    275: u_long         cmd;
                    276: int            flag;
                    277: caddr_t                addr;
                    278: struct proc    *p;
                    279: {
                    280:        struct fd_softc *sc;
                    281:        void            *data;
                    282:
                    283:        sc = getsoftc(fdcd, DISKUNIT(dev));
                    284:
                    285:        if((sc->flags & FLPF_HAVELAB) == 0)
                    286:                return(EBADF);
                    287:
                    288:        switch(cmd) {
                    289:                case DIOCSBAD:
                    290:                        return(EINVAL);
                    291:                case DIOCGDINFO:
                    292:                        *(struct disklabel *)addr = sc->dkdev.dk_label;
                    293:                        return(0);
                    294:                case DIOCGPART:
                    295:                        ((struct partinfo *)addr)->disklab =
                    296:                                &sc->dkdev.dk_label;
                    297:                        ((struct partinfo *)addr)->part =
                    298:                                &sc->dkdev.dk_label.d_partitions[DISKPART(dev)];
                    299:                        return(0);
                    300: #ifdef notyet /* XXX LWP */
                    301:                case DIOCSRETRIES:
                    302:                case DIOCSSTEP:
                    303:                case DIOCSDINFO:
                    304:                case DIOCWDINFO:
                    305:                case DIOCWLABEL:
                    306: #endif /* notyet */
                    307:                default:
                    308:                        return(ENOTTY);
                    309:        }
                    310: }
                    311:
                    312: /*
                    313:  * Open the device. If this is the first open on both the floppy devices,
                    314:  * intialize the controller.
                    315:  * Note that partition info on the floppy device is used to distinguise
                    316:  * between 780Kb and 360Kb floppy's.
                    317:  *     partition 0: 360Kb
                    318:  *  partition 1: 780Kb
                    319:  */
                    320: Fdopen(dev, flags, devtype, proc)
                    321: dev_t          dev;
                    322: int            flags, devtype;
                    323: struct proc    *proc;
                    324: {
                    325:        struct fd_softc *sc;
                    326:        int             sps;
                    327:
                    328: #ifdef FLP_DEBUG
                    329:        printf("Fdopen dev=0x%x\n", dev);
                    330: #endif
                    331:
                    332:        if(DISKPART(dev) >= NR_TYPES)
                    333:                return(ENXIO);
                    334:
                    335:        if((sc = getsoftc(fdcd, DISKUNIT(dev))) == NULL)
                    336:                return(ENXIO);
                    337:
                    338:        /*
                    339:         * If no floppy currently open, reset the controller and select
                    340:         * floppy type.
                    341:         */
                    342:        if(!nopens) {
                    343:
                    344: #ifdef FLP_DEBUG
                    345:                printf("Fdopen device not yet open\n");
                    346: #endif
                    347:                nopens++;
                    348:                dmawdat(FDC_CS, IRUPT, FDC_DELAY);
                    349:        }
                    350:
                    351:        if(!(sc->flags & FLPF_ISOPEN)) {
                    352:                /*
                    353:                 * Initialise some driver values.
                    354:                 */
                    355:                int     part = DISKPART(dev);
                    356:                void    *addr;
                    357:
                    358:                sc->bufq.b_actf = NULL;
                    359:                sc->unit        = DISKUNIT(dev);
                    360:                sc->part        = part;
                    361:                sc->nheads      = fdtypes[part].nheads;
                    362:                sc->nsectors    = fdtypes[part].nsectors;
                    363:                sc->nblocks     = fdtypes[part].nblocks;
                    364:                sc->curtrk      = INV_TRK;
                    365:                sc->sector      = 0;
                    366:                sc->errcnt      = 0;
                    367:                sc->bounceb     = (u_char*)alloc_stmem(SECTOR_SIZE, &addr);
                    368:                if(sc->bounceb == NULL)
                    369:                        return(ENOMEM); /* XXX */
                    370:                if(sc->nsectors > 9) /* XXX */
                    371:                        sc->flags |= FLPF_ISHD;
                    372:
                    373:                sc->flags       = FLPF_ISOPEN;
                    374:        }
                    375:        else {
                    376:                /*
                    377:                 * Multiply opens are granted when accessing the same type of
                    378:                 * floppy (eq. the same partition).
                    379:                 */
                    380:                if(sc->part != DISKPART(dev))
                    381:                        return(ENXIO);  /* XXX temporarely out of business */
                    382:        }
                    383:        fdgetdisklabel(sc, dev);
                    384: #ifdef FLP_DEBUG
                    385:        printf("Fdopen open succeeded on type %d\n", sc->part);
                    386: #endif
                    387: }
                    388:
                    389: Fdclose(dev, flags, devtype, proc)
                    390: dev_t          dev;
                    391: int            flags, devtype;
                    392: struct proc    *proc;
                    393: {
                    394:        struct fd_softc *sc;
                    395:
                    396:        sc = getsoftc(fdcd, DISKUNIT(dev));
                    397:        free_stmem(sc->bounceb);
                    398:        sc->flags = 0;
                    399:        nopens--;
                    400:
                    401: #ifdef FLP_DEBUG
                    402:        printf("Closed floppy device -- nopens: %d\n", nopens);
                    403: #endif
                    404: }
                    405:
                    406: void
                    407: fdstrategy(bp)
                    408: struct buf     *bp;
                    409: {
                    410:        struct fd_softc *sc;
                    411:        int             sps, nblocks;
                    412:
                    413:        sc   = getsoftc(fdcd, DISKUNIT(bp->b_dev));
                    414:
                    415: #ifdef FLP_DEBUG
                    416:        printf("fdstrategy: 0x%x\n", bp);
                    417: #endif
                    418:
                    419:        /*
                    420:         * check for valid partition and bounds
                    421:         */
                    422:        nblocks = (bp->b_bcount + SECTOR_SIZE - 1) / SECTOR_SIZE;
                    423:        if((bp->b_blkno < 0) || ((bp->b_blkno + nblocks) >= sc->nblocks)) {
                    424:                if((bp->b_blkno == sc->nblocks) && (bp->b_flags & B_READ)) {
                    425:                        /*
                    426:                         * Read 1 block beyond, return EOF
                    427:                         */
                    428:                        bp->b_resid = bp->b_bcount;
                    429:                        goto done;
                    430:                }
                    431:                /*
                    432:                 * Try to limit the size of the transaction, adjust count
                    433:                 * if we succeed.
                    434:                 */
                    435:                nblocks = sc->nblocks - bp->b_blkno;
                    436:                if((nblocks <= 0) || (bp->b_blkno < 0)) {
                    437:                        bp->b_error  = EINVAL;
                    438:                        bp->b_flags |= B_ERROR;
                    439:                        goto done;
                    440:                }
                    441:                bp->b_bcount = nblocks * SECTOR_SIZE;
                    442:        }
                    443:        if(bp->b_bcount == 0)
                    444:                goto done;
                    445:
                    446:        /*
                    447:         * Set order info for disksort
                    448:         */
                    449:        bp->b_block = bp->b_blkno / (sc->nsectors * sc->nheads);
                    450:
                    451:        /*
                    452:         * queue the buf and kick the low level code
                    453:         */
                    454:        sps = splbio();
                    455:        disksort(&sc->bufq, bp);
                    456:        if(!fd_in_dma) {
                    457:                if(fd_state & FLP_MON)
                    458:                        untimeout((FPV)fdmotoroff, (void*)sc);
                    459:                fd_state = FLP_IDLE;
                    460:                fd_in_dma = 1; dmagrab(fdcint, fdstart, sc);
                    461:        }
                    462:        splx(sps);
                    463:
                    464:        return;
                    465: done:
                    466:        bp->b_resid = bp->b_bcount;
                    467:        biodone(bp);
                    468: }
                    469:
                    470: /*
                    471:  * no dumps to floppy disks thank you.
                    472:  */
                    473: int
                    474: fdsize(dev)
                    475: dev_t dev;
                    476: {
                    477:        return(-1);
                    478: }
                    479:
                    480: int
                    481: fdread(dev, uio)
                    482: dev_t          dev;
                    483: struct uio     *uio;
                    484: {
                    485:        return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
                    486:            dev, B_READ, fdminphys, uio));
                    487: }
                    488:
                    489: int
                    490: fdwrite(dev, uio)
                    491: dev_t          dev;
                    492: struct uio     *uio;
                    493: {
                    494:        return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
                    495:            dev, B_WRITE, fdminphys, uio));
                    496: }
                    497:
                    498: /*
                    499:  * Called through the dma-dispatcher. So we know we are the only ones
                    500:  * messing with the floppy-controler.
                    501:  * Initialize some fields in the fdsoftc for the state-machine and get
                    502:  * it going.
                    503:  */
                    504: static void
                    505: fdstart(sc)
                    506: struct fd_softc        *sc;
                    507: {
                    508:        struct buf      *bp;
                    509:
                    510:        bp           = sc->bufq.b_actf;
                    511:        sc->sector   = bp->b_blkno;     /* Start sector for I/O         */
                    512:        sc->io_data  = bp->b_data;      /* KVA base for I/O             */
                    513:        sc->io_bytes = bp->b_bcount;    /* Transfer size in bytes       */
                    514:        sc->io_dir   = bp->b_flags & B_READ;/* Direction of transfer    */
                    515:        sc->errcnt   = 0;               /* No errors yet                */
                    516:        fd_state     = FLP_XFER;        /* Yes, we're going to transfer */
                    517:
                    518:        /*
                    519:         * Make sure the floppy controller is the correct density mode
                    520:         */
                    521:        if(sc->flags & FLPF_ISHD)
                    522:                DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG);
                    523:        else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
                    524:        fd_xfer(sc);
                    525: }
                    526:
                    527: /*
                    528:  * The current transaction is finished (for good or bad). Let go of
                    529:  * the the dma-resources. Call biodone() to finish the transaction.
                    530:  * Find a new transaction to work on.
                    531:  */
                    532: static void
                    533: fddone(sc)
                    534: register struct fd_softc       *sc;
                    535: {
                    536:        struct buf      *bp, *dp;
                    537:        struct fd_softc *sc1;
                    538:        int             i;
                    539:
                    540:        /*
                    541:         * Lower clock frequency of FDC (better for some old ones).
                    542:         */
                    543:        DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
                    544:
                    545:        dp = &sc->bufq;
                    546:        bp = dp->b_actf;
                    547:        if(bp == NULL)
                    548:                panic("fddone");
                    549:        dp->b_actf = bp->b_actf;
                    550:
                    551: #ifdef FLP_DEBUG
                    552:        printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp,
                    553:                                                        sc->io_bytes);
                    554: #endif
                    555:        /*
                    556:         * Give others a chance to use the dma.
                    557:         */
                    558:        fd_in_dma = 0; dmafree();
                    559:
                    560:        /*
                    561:         * Finish current transaction.
                    562:         */
                    563:        bp->b_resid = sc->io_bytes;
                    564:        biodone(bp);
                    565:
                    566:        if(fd_in_dma)
                    567:                return;         /* XXX Is this possible?        */
                    568:
                    569:        /*
                    570:         * Find a new transaction on round-robin basis.
                    571:         */
                    572:        for(i = sc->unit + 1; ;i++) {
                    573:                if(i >= fdcd.cd_ndevs)
                    574:                        i = 0;
                    575:                if((sc1 = fdcd.cd_devs[i]) == NULL)
                    576:                        continue;
                    577:                if(sc1->bufq.b_actf)
                    578:                        break;
                    579:                if(i == sc->unit) {
                    580:                        timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY);
                    581: #ifdef FLP_DEBUG
                    582:                        printf("fddone: Nothing to do\n");
                    583: #endif
                    584:                        return; /* No work */
                    585:                }
                    586:        }
                    587:        fd_state = FLP_IDLE;
                    588: #ifdef FLP_DEBUG
                    589:        printf("fddone: Staring job on unit %d\n", sc1->unit);
                    590: #endif
                    591:        fd_in_dma = 1; dmagrab(fdcint, fdstart, sc1);
                    592: }
                    593:
                    594: /****************************************************************************
                    595:  * The following functions assume to be running as a result of a            *
                    596:  * disk-interrupt (e.q. spl = splbio).                                     *
                    597:  * They form the finit-state machine, the actual driver.                    *
                    598:  *                                                                          *
                    599:  *     fdstart()/ --> fd_xfer() -> activate hardware                       *
                    600:  *  fdopen()          ^                                                     *
                    601:  *                    |                                                     *
                    602:  *                    +-- not ready -<------------+                         *
                    603:  *                                                |                         *
                    604:  *  fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+                         *
                    605:  *  h/w interrupt                 |                                         *
                    606:  *                               \|/                                        *
                    607:  *                            finished ---> fdone()                         *
                    608:  *                                                                          *
                    609:  ****************************************************************************/
                    610: static void
                    611: fd_xfer(sc)
                    612: struct fd_softc        *sc;
                    613: {
                    614:        register int    head = 0;
                    615:        register int    track, sector, hbit;
                    616:                 int    i;
                    617:                 u_long phys_addr;
                    618:
                    619:        if(fd_state != FLP_XFER)
                    620:                panic("fd_xfer: wrong state (0x%x)", fd_state);
                    621:
                    622:        /*
                    623:         * Calculate head/track values
                    624:         */
                    625:        track  = sc->sector / sc->nsectors;
                    626:        head   = track % sc->nheads;
                    627:        track  = track / sc->nheads;
                    628: #ifdef FLP_DEBUG
                    629:        printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,track);
                    630: #endif
                    631:
                    632:        /*
                    633:         * Determine if the controller should check spin-up.
                    634:         */
                    635:        hbit = motoron ? HBIT : 0;
                    636:        motoron = 1;
                    637:
                    638:        /*
                    639:         * Select the right unit and head.
                    640:         */
                    641:        i = (sc->unit ? PA_FLOP1 : PA_FLOP0) | head;
                    642:        if(i != selected) {
                    643:                selected = i;
                    644:                SOUND->sd_selr = YM_IOA;
                    645:                SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
                    646:        }
                    647:
                    648:        if(sc->curtrk == INV_TRK) {
                    649:                /*
                    650:                 * Recalibrate, since we lost track of head positioning.
                    651:                 * The floppy disk controller has no way of determining its
                    652:                 * absolute arm position (track).  Instead, it steps the
                    653:                 * arm a track at a time and keeps track of where it
                    654:                 * thinks it is (in software).  However, after a SEEK, the
                    655:                 * hardware reads information from the diskette telling
                    656:                 * where the arm actually is.  If the arm is in the wrong place,
                    657:                 * a recalibration is done, which forces the arm to track 0.
                    658:                 * This way the controller can get back into sync with reality.
                    659:                 */
                    660:                dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
                    661:                fd_cmd = RESTORE;
                    662:                timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
                    663:
                    664: #ifdef FLP_DEBUG
                    665:                printf("fd_xfer:Recalibrating drive %d\n", sc->unit);
                    666: #endif
                    667:                return;
                    668:        }
                    669:
                    670:        dmawdat(FDC_TR, sc->curtrk, FDC_DELAY);
                    671:
                    672:        /*
                    673:         * Issue a SEEK command on the indicated drive unless the arm is
                    674:         * already positioned on the correct track.
                    675:         */
                    676:        if(track != sc->curtrk) {
                    677:                sc->curtrk = track;     /* be optimistic */
                    678:                dmawdat(FDC_DR, track, FDC_DELAY);
                    679:                dmawdat(FDC_CS, SEEK|RATE6|VBIT|hbit, FDC_DELAY);
                    680:                timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
                    681:                fd_cmd = SEEK;
                    682: #ifdef FLP_DEBUG
                    683:                printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit);
                    684: #endif
                    685:                return;
                    686:        }
                    687:
                    688:        /*
                    689:         * The drive is now on the proper track. Read or write 1 block.
                    690:         */
                    691:        sector = sc->sector % sc->nsectors;
                    692:        sector++;       /* start numbering at 1 */
                    693:
                    694:        dmawdat(FDC_SR, sector, FDC_DELAY);
                    695:
                    696:        phys_addr = (u_long)kvtop(sc->io_data);
                    697:        if(phys_addr >= FDC_MAX_DMA_AD) {
                    698:                /*
                    699:                 * We _must_ bounce this address
                    700:                 */
                    701:                phys_addr = (u_long)kvtop(sc->bounceb);
                    702:                if(sc->io_dir == B_WRITE)
                    703:                        bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE);
                    704:                sc->flags |= FLPF_BOUNCE;
                    705:        }
                    706:        dmaaddr(phys_addr);     /* DMA address setup */
                    707:
                    708: #ifdef FLP_DEBUG
                    709:        printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data));
                    710: #endif
                    711:
                    712:        if(sc->io_dir == B_READ) {
                    713:                /* Issue the command */
                    714:                dmacomm(FDC | SCREG, 1, 0);
                    715:                dmawdat(FDC_CS, F_READ|hbit, FDC_DELAY);
                    716:                fd_cmd = F_READ;
                    717:        }
                    718:        else {
                    719:                /* Issue the command */
                    720:                dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY);
                    721:                dmawdat(WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT, FDC_DELAY);
                    722:                fd_cmd = F_WRITE;
                    723:        }
                    724:        timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
                    725: }
                    726:
                    727: /* return values of fd_xfer_ok(): */
                    728: #define X_OK                   0
                    729: #define X_AGAIN                        1
                    730: #define X_ERROR                        2
                    731: #define X_FAIL                 3
                    732:
                    733: /*
                    734:  * Hardware interrupt function.
                    735:  */
                    736: static int
                    737: fdcint(sc)
                    738: struct fd_softc        *sc;
                    739: {
                    740:        struct  buf     *bp;
                    741:
                    742: #ifdef FLP_DEBUG
                    743:        printf("fdcint: unit = %d\n", sc->unit);
                    744: #endif
                    745:
                    746:        /*
                    747:         * Cancel timeout (we made it, didn't we)
                    748:         */
                    749:        untimeout((FPV)fdmotoroff, (void*)sc);
                    750:
                    751:        switch(fd_xfer_ok(sc)) {
                    752:                case X_ERROR :
                    753:                        if(++(sc->errcnt) < MAX_ERRORS) {
                    754:                                /*
                    755:                                 * Command failed but still retries left.
                    756:                                 */
                    757:                                break;
                    758:                        }
                    759:                        /* FALL THROUGH */
                    760:                case X_FAIL  :
                    761:                        /*
                    762:                         * Non recoverable error. Fall back to motor-on
                    763:                         * idle-state.
                    764:                         */
                    765:                        bp = sc->bufq.b_actf;
                    766:
                    767:                        bp->b_error  = EIO;
                    768:                        bp->b_flags |= B_ERROR;
                    769:                        fd_state = FLP_MON;
                    770:                        if(fd_error != NULL) {
                    771:                                printf("Floppy error: %s\n", fd_error);
                    772:                                fd_error = NULL;
                    773:                        }
                    774:
                    775:                        break;
                    776:                case X_AGAIN:
                    777:                        /*
                    778:                         * Start next part of state machine.
                    779:                         */
                    780:                        break;
                    781:                case X_OK:
                    782:                        /*
                    783:                         * Command ok and finished. Reset error-counter.
                    784:                         * If there are no more bytes to transfer fall back
                    785:                         * to motor-on idle state.
                    786:                         */
                    787:                        sc->errcnt = 0;
                    788:                        if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ))
                    789:                                bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE);
                    790:                        sc->flags &= ~FLPF_BOUNCE;
                    791:
                    792:                        sc->sector++;
                    793:                        sc->io_data  += SECTOR_SIZE;
                    794:                        sc->io_bytes -= SECTOR_SIZE;
                    795:                        if(sc->io_bytes <= 0)
                    796:                                fd_state = FLP_MON;
                    797:        }
                    798:        if(fd_state == FLP_MON)
                    799:                fddone(sc);
                    800:        else fd_xfer(sc);
                    801: }
                    802:
                    803: /*
                    804:  * Determine status of last command. Should only be called through
                    805:  * 'fdcint()'.
                    806:  * Returns:
                    807:  *     X_ERROR : Error on command; might succeed next time.
                    808:  *     X_FAIL  : Error on command; will never succeed.
                    809:  *     X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete.
                    810:  *     X_OK    : Command succeeded and is complete.
                    811:  *
                    812:  * This function only affects sc->curtrk.
                    813:  */
                    814: static int
                    815: fd_xfer_ok(sc)
                    816: register struct fd_softc       *sc;
                    817: {
                    818:        register int    status;
                    819:
                    820:        switch(fd_cmd) {
                    821:                case IRUPT:
                    822:                        /*
                    823:                         * Timeout. Force a recalibrate before we try again.
                    824:                         */
                    825:                        fd_error = "Timeout";
                    826:                        sc->curtrk = INV_TRK;
                    827:                        return(X_ERROR);
                    828:                case F_READ:
                    829:                        /*
                    830:                         * Test for DMA error
                    831:                         */
                    832:                        status = dmastat(FDC_CS | SCREG, 0);
                    833:                        if(!(status & DMAOK)) {
                    834:                                fd_error = "Dma error";
                    835:                                return(X_ERROR);
                    836:                        }
                    837:                        /*
                    838:                         * Get controller status and check for errors.
                    839:                         */
                    840:                        status = dmardat(FDC_CS, FDC_DELAY);
                    841:                        if(status & (RNF | CRCERR | LD_T00)) {
                    842:                                fd_error = "Read error";
                    843:                                if(status & RNF)
                    844:                                        sc->curtrk = INV_TRK;
                    845:                                return(X_ERROR);
                    846:                        }
                    847:                        break;
                    848:                case F_WRITE:
                    849:                        /*
                    850:                         * Get controller status and check for errors.
                    851:                         */
                    852:                        status = dmardat(WRBIT | FDC_CS, FDC_DELAY);
                    853:                        if(status & WRI_PRO) {
                    854:                                fd_error = "Write protected";
                    855:                                return(X_FAIL);
                    856:                        }
                    857:                        if(status & (RNF | CRCERR | LD_T00)) {
                    858:                                fd_error = "Write error";
                    859:                                sc->curtrk = INV_TRK;
                    860:                                return(X_ERROR);
                    861:                        }
                    862:                        break;
                    863:                case SEEK:
                    864:                        status = dmardat(FDC_CS, FDC_DELAY);
                    865:                        if(status & (RNF | CRCERR)) {
                    866:                                fd_error = "Seek error";
                    867:                                sc->curtrk = INV_TRK;
                    868:                                return(X_ERROR);
                    869:                        }
                    870:                        return(X_AGAIN);
                    871:                case RESTORE:
                    872:                        /*
                    873:                         * Determine if the recalibration succeeded.
                    874:                         */
                    875:                        status = dmardat(FDC_CS, FDC_DELAY);
                    876:                        if(status & RNF) {
                    877:                                fd_error = "Recalibrate error";
                    878:                                /* reset controller */
                    879:                                dmawdat(FDC_CS, IRUPT, FDC_DELAY);
                    880:                                sc->curtrk = INV_TRK;
                    881:                                return(X_ERROR);
                    882:                        }
                    883:                        sc->curtrk = 0;
                    884:                        return(X_AGAIN);
                    885:                default:
                    886:                        fd_error = "Driver error: fd_xfer_ok : Unknown state";
                    887:                        return(X_FAIL);
                    888:        }
                    889:        return(X_OK);
                    890: }
                    891:
                    892: /*
                    893:  * All timeouts will call this function.
                    894:  */
                    895: static void
                    896: fdmotoroff(sc)
                    897: struct fd_softc        *sc;
                    898: {
                    899:        int     sps, wrbit;
                    900:
                    901:        /*
                    902:         * Get at harware interrupt level
                    903:         */
                    904:        sps = splbio();
                    905:
                    906: #if FLP_DEBUG
                    907:        printf("fdmotoroff, state = 0x%x\n", fd_state);
                    908: #endif
                    909:
                    910:        switch(fd_state) {
                    911:                case FLP_XFER :
                    912:                        /*
                    913:                         * Timeout during a transfer; cancel transaction
                    914:                         * set command to 'IRUPT'.
                    915:                         * A drive-interrupt is simulated to trigger the state
                    916:                         * machine.
                    917:                         */
                    918:                        /*
                    919:                         * Cancel current transaction
                    920:                         */
                    921:                        wrbit = (fd_cmd == F_WRITE) ? WRBIT : 0;
                    922:                        fd_cmd = IRUPT;
                    923:                        dmawdat(FDC_CS, wrbit|IRUPT, FDC_DELAY);
                    924:
                    925:                        /*
                    926:                         * Simulate floppy interrupt.
                    927:                         */
                    928:                        fdcint(sc);
                    929:                        return;
                    930:                case FLP_MON  :
                    931:                        /*
                    932:                         * Turn motor off.
                    933:                         */
                    934:                        if(selected) {
                    935:                                SOUND->sd_selr = YM_IOA;
                    936:                                SOUND->sd_wdat = SOUND->sd_rdat | 0x07;
                    937:                                motoron = selected = 0;
                    938:                        }
                    939:                        fd_state = FLP_IDLE;
                    940:                        break;
                    941:        }
                    942:        splx(sps);
                    943: }
                    944:
                    945: /*
                    946:  * min byte count to whats left of the track in question
                    947:  */
                    948: static int
                    949: fdminphys(bp)
                    950: struct buf     *bp;
                    951: {
                    952:        struct fd_softc *sc;
                    953:        int             sec, toff, tsz;
                    954:
                    955:        if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL)
                    956:                return(ENXIO);
                    957:
                    958:        sec  = bp->b_blkno % (sc->nsectors * sc->nheads);
                    959:        toff = sec * SECTOR_SIZE;
                    960:        tsz  = sc->nsectors * sc->nheads * SECTOR_SIZE;
                    961:
                    962: #ifdef FLP_DEBUG
                    963:        printf("fdminphys: before %d", bp->b_bcount);
                    964: #endif
                    965:
                    966:        bp->b_bcount = min(bp->b_bcount, tsz - toff);
                    967:
                    968: #ifdef FLP_DEBUG
                    969:        printf(" after %d\n", bp->b_bcount);
                    970: #endif
                    971:
                    972:        return(bp->b_bcount);
                    973: }
                    974:
                    975: /*
                    976:  * Used to find out wich drives are actually connected. We do this by issueing
                    977:  * is 'RESTORE' command and check if the 'track-0' bit is set. This also works
                    978:  * if the drive is present but no floppy is inserted.
                    979:  */
                    980: static void
                    981: fdtestdrv(fdsoftc)
                    982: struct fd_softc        *fdsoftc;
                    983: {
                    984:        int             i, status;
                    985:
                    986:        /*
                    987:         * Select the right unit and head.
                    988:         */
                    989:        i = fdsoftc->unit ? PA_FLOP1 : PA_FLOP0;
                    990:        if(i != selected) {
                    991:                selected = i;
                    992:                SOUND->sd_selr = YM_IOA;
                    993:                SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
                    994:        }
                    995:
                    996:        dmawdat(FDC_CS, RESTORE|VBIT|HBIT, FDC_DELAY);
                    997:
                    998:        /*
                    999:         * Wait for about 2 seconds.
                   1000:         */
                   1001:        delay(2000000);
                   1002:
                   1003:        status = dmardat(FDC_CS, FDC_DELAY);
                   1004:        if(status & (RNF|BUSY))
                   1005:                dmawdat(FDC_CS, IRUPT, FDC_DELAY);      /* reset controller */
                   1006:
                   1007:        if(!(status & LD_T00))
                   1008:                fdsoftc->flags |= FLPF_NOTRESP;
                   1009: }
                   1010:
                   1011: /*
                   1012:  * Build disk label. For now we only create a label from what we know
                   1013:  * from 'sc'.
                   1014:  */
                   1015: static int
                   1016: fdgetdisklabel(sc, dev)
                   1017: struct fd_softc *sc;
                   1018: dev_t                  dev;
                   1019: {
                   1020:        struct disklabel        *lp, *dlp;
                   1021:        int                     part;
                   1022:
                   1023:        /*
                   1024:         * If we already got one, get out.
                   1025:         */
                   1026:        if(sc->flags & FLPF_HAVELAB)
                   1027:                return(0);
                   1028:
                   1029: #ifdef FLP_DEBUG
                   1030:        printf("fdgetdisklabel()\n");
                   1031: #endif
                   1032:
                   1033:        part = DISKPART(dev);
                   1034:        lp   = &sc->dkdev.dk_label;
                   1035:        bzero(lp, sizeof(struct disklabel));
                   1036:
                   1037:        lp->d_secsize     = SECTOR_SIZE;
                   1038:        lp->d_ntracks     = sc->nheads;
                   1039:        lp->d_nsectors    = sc->nsectors;
                   1040:        lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
                   1041:        lp->d_ncylinders  = sc->nblocks / lp->d_secpercyl;
                   1042:        lp->d_secperunit  = sc->nblocks;
                   1043:
                   1044:        lp->d_type        = DTYPE_FLOPPY;
                   1045:        lp->d_rpm         = 300;        /* good guess I suppose.        */
                   1046:        lp->d_interleave  = 1;          /* FIXME: is this OK?           */
                   1047:        lp->d_bbsize      = 0;
                   1048:        lp->d_sbsize      = 0;
                   1049:        lp->d_npartitions = part + 1;
                   1050:        lp->d_trkseek     = STEP_DELAY;
                   1051:        lp->d_magic       = DISKMAGIC;
                   1052:        lp->d_magic2      = DISKMAGIC;
                   1053:        lp->d_checksum    = dkcksum(lp);
                   1054:        lp->d_partitions[part].p_size   = lp->d_secperunit;
                   1055:        lp->d_partitions[part].p_fstype = FS_UNUSED;
                   1056:        lp->d_partitions[part].p_fsize  = 1024;
                   1057:        lp->d_partitions[part].p_frag   = 8;
                   1058:        sc->flags        |= FLPF_HAVELAB;
                   1059:
                   1060:        return(0);
                   1061: }

CVSweb <webmaster@jp.NetBSD.org>