[BACK]Return to mcd.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/mcd.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: mcd.c,v 1.49 2007/06/20 18:15:46 deraadt Exp $ */
                      2: /*     $NetBSD: mcd.c,v 1.60 1998/01/14 12:14:41 drochner Exp $        */
                      3:
                      4: /*
                      5:  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  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 Charles M. Hannum.
                     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:  * Copyright 1993 by Holger Veit (data part)
                     22:  * Copyright 1993 by Brian Moore (audio part)
                     23:  * All rights reserved.
                     24:  *
                     25:  * Redistribution and use in source and binary forms, with or without
                     26:  * modification, are permitted provided that the following conditions
                     27:  * are met:
                     28:  * 1. Redistributions of source code must retain the above copyright
                     29:  *    notice, this list of conditions and the following disclaimer.
                     30:  * 2. Redistributions in binary form must reproduce the above copyright
                     31:  *    notice, this list of conditions and the following disclaimer in the
                     32:  *    documentation and/or other materials provided with the distribution.
                     33:  * 3. All advertising materials mentioning features or use of this software
                     34:  *    must display the following acknowledgement:
                     35:  *     This software was developed by Holger Veit and Brian Moore
                     36:  *      for use with "386BSD" and similar operating systems.
                     37:  *    "Similar operating systems" includes mainly non-profit oriented
                     38:  *    systems for research and education, including but not restricted to
                     39:  *    "NetBSD", "FreeBSD", "Mach" (by CMU).
                     40:  * 4. Neither the name of the developer(s) nor the name "386BSD"
                     41:  *    may be used to endorse or promote products derived from this
                     42:  *    software without specific prior written permission.
                     43:  *
                     44:  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
                     45:  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     46:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     47:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER(S) BE
                     48:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
                     49:  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
                     50:  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     51:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     52:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     53:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     54:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     55:  */
                     56:
                     57: /*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
                     58:
                     59: #include <sys/param.h>
                     60: #include <sys/systm.h>
                     61: #include <sys/kernel.h>
                     62: #include <sys/proc.h>
                     63: #include <sys/conf.h>
                     64: #include <sys/file.h>
                     65: #include <sys/buf.h>
                     66: #include <sys/stat.h>
                     67: #include <sys/uio.h>
                     68: #include <sys/ioctl.h>
                     69: #include <sys/mtio.h>
                     70: #include <sys/cdio.h>
                     71: #include <sys/errno.h>
                     72: #include <sys/disklabel.h>
                     73: #include <sys/device.h>
                     74: #include <sys/disk.h>
                     75: #include <sys/timeout.h>
                     76:
                     77: #include <machine/cpu.h>
                     78: #include <machine/intr.h>
                     79: #include <machine/bus.h>
                     80:
                     81: #include <dev/isa/isavar.h>
                     82: #include <dev/isa/mcdreg.h>
                     83: #include <dev/isa/opti.h>
                     84:
                     85: #ifndef MCDDEBUG
                     86: #define MCD_TRACE(fmt,a,b,c,d)
                     87: #else
                     88: #define MCD_TRACE(fmt,a,b,c,d) {if (sc->debug) {printf("%s: st=%02x: ", sc->sc_dev.dv_xname, sc->status); printf(fmt,a,b,c,d);}}
                     89: #endif
                     90:
                     91: /* toc */
                     92: #define MCD_MAXTOCS    104     /* from the Linux driver */
                     93:
                     94: struct mcd_mbx {
                     95:        int             retry, count;
                     96:        struct buf      *bp;
                     97:        daddr64_t               blkno;
                     98:        int             nblk;
                     99:        int             sz;
                    100:        u_long          skip;
                    101:        int             state;
                    102: #define        MCD_S_IDLE      0
                    103: #define MCD_S_BEGIN    1
                    104: #define MCD_S_WAITMODE 2
                    105: #define MCD_S_WAITREAD 3
                    106:        int             mode;
                    107: };
                    108:
                    109: struct mcd_softc {
                    110:        struct  device sc_dev;
                    111:        struct  disk sc_dk;
                    112:        void *sc_ih;
                    113:        struct timeout sc_pi_tmo;
                    114:
                    115:        bus_space_tag_t         sc_iot;
                    116:        bus_space_handle_t      sc_ioh;
                    117:
                    118:        int     irq, drq;
                    119:
                    120:        char    *type;
                    121:        int     flags;
                    122: #define        MCDF_LOCKED     0x01
                    123: #define        MCDF_WANTED     0x02
                    124: #define        MCDF_WLABEL     0x04    /* label is writable */
                    125: #define        MCDF_LABELLING  0x08    /* writing label */
                    126: #define        MCDF_LOADED     0x10    /* parameters loaded */
                    127: #define        MCDF_EJECTING   0x20    /* please eject at close */
                    128:        short   status;
                    129:        short   audio_status;
                    130:        int     blksize;
                    131:        u_long  disksize;
                    132:        struct  mcd_volinfo volinfo;
                    133:        union   mcd_qchninfo toc[MCD_MAXTOCS];
                    134:        struct  mcd_command lastpb;
                    135:        struct  mcd_mbx mbx;
                    136:        int     lastmode;
                    137: #define        MCD_MD_UNKNOWN  -1
                    138:        int     lastupc;
                    139: #define        MCD_UPC_UNKNOWN -1
                    140:        struct  buf buf_queue;
                    141:        u_char  readcmd;
                    142:        u_char  debug;
                    143:        u_char  probe;
                    144: };
                    145:
                    146: /* prototypes */
                    147: /* XXX does not belong here */
                    148: cdev_decl(mcd);
                    149: bdev_decl(mcd);
                    150:
                    151: u_int8_t const __bcd2bin[] = {
                    152:        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 0, 0, 0, 0, 0, 0,
                    153:        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
                    154:        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
                    155:        30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
                    156:        40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
                    157:        50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
                    158:        60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
                    159:        70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
                    160:        80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
                    161:        90, 91, 92, 93, 94, 95, 96, 97, 98, 99
                    162: };
                    163:
                    164: u_int8_t const __bin2bcd[] = {
                    165:        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                    166:        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
                    167:        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
                    168:        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
                    169:        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
                    170:        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
                    171:        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
                    172:        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
                    173:        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
                    174:        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
                    175: };
                    176: #define        bcd2bin(b)      (__bcd2bin[(b)&0xff])
                    177: #define        bin2bcd(b)      (__bin2bcd[(b)&0xff])
                    178:
                    179: static void hsg2msf(int, bcd_t *);
                    180: static daddr64_t msf2hsg(bcd_t *, int);
                    181:
                    182: int mcd_playtracks(struct mcd_softc *, struct ioc_play_track *);
                    183: int mcd_playmsf(struct mcd_softc *, struct ioc_play_msf *);
                    184: int mcd_playblocks(struct mcd_softc *, struct ioc_play_blocks *);
                    185: int mcd_stop(struct mcd_softc *);
                    186: int mcd_eject(struct mcd_softc *);
                    187: int mcd_read_subchannel(struct mcd_softc *, struct ioc_read_subchannel *);
                    188: int mcd_pause(struct mcd_softc *);
                    189: int mcd_resume(struct mcd_softc *);
                    190: int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *);
                    191: int mcd_toc_entries(struct mcd_softc *, struct ioc_read_toc_entry *);
                    192:
                    193: int mcd_getreply(struct mcd_softc *);
                    194: int mcd_getstat(struct mcd_softc *);
                    195: int mcd_getresult(struct mcd_softc *, struct mcd_result *);
                    196: void mcd_setflags(struct mcd_softc *);
                    197: int mcd_get(struct mcd_softc *, char *, int);
                    198: int mcd_send(struct mcd_softc *, struct mcd_mbox *, int);
                    199: int mcdintr(void *);
                    200: void mcd_soft_reset(struct mcd_softc *);
                    201: int mcd_hard_reset(struct mcd_softc *);
                    202: int mcd_setmode(struct mcd_softc *, int);
                    203: int mcd_setupc(struct mcd_softc *, int);
                    204: int mcd_read_toc(struct mcd_softc *);
                    205: int mcd_getqchan(struct mcd_softc *, union mcd_qchninfo *, int);
                    206: int mcd_setlock(struct mcd_softc *, int);
                    207:
                    208: int mcd_find(bus_space_tag_t, bus_space_handle_t, struct mcd_softc *);
                    209: int mcdprobe(struct device *, void *, void *);
                    210: void mcdattach(struct device *, struct device *, void *);
                    211:
                    212: struct cfattach mcd_ca = {
                    213:        sizeof(struct mcd_softc), mcdprobe, mcdattach
                    214: };
                    215:
                    216: struct cfdriver mcd_cd = {
                    217:        NULL, "mcd", DV_DISK
                    218: };
                    219:
                    220: void   mcdgetdisklabel(dev_t, struct mcd_softc *, struct disklabel *, int);
                    221: int    mcd_get_parms(struct mcd_softc *);
                    222: void   mcdstrategy(struct buf *);
                    223: void   mcdstart(struct mcd_softc *);
                    224: int    mcdlock(struct mcd_softc *);
                    225: void   mcdunlock(struct mcd_softc *);
                    226: void   mcd_pseudointr(void *);
                    227:
                    228: struct dkdriver mcddkdriver = { mcdstrategy };
                    229:
                    230: #define MCD_RETRIES    3
                    231: #define MCD_RDRETRIES  3
                    232:
                    233: /* several delays */
                    234: #define RDELAY_WAITMODE        300
                    235: #define RDELAY_WAITREAD        800
                    236:
                    237: #define        DELAY_GRANULARITY       25      /* 25us */
                    238: #define DELAY_GETREPLY         100000  /* 100000 * 25us */
                    239:
                    240: void
                    241: mcdattach(parent, self, aux)
                    242:        struct device *parent, *self;
                    243:        void *aux;
                    244: {
                    245:        struct mcd_softc *sc = (void *)self;
                    246:        struct isa_attach_args *ia = aux;
                    247:        bus_space_tag_t iot = ia->ia_iot;
                    248:        bus_space_handle_t ioh;
                    249:        struct mcd_mbox mbx;
                    250:
                    251:        /* Map i/o space */
                    252:        if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh)) {
                    253:                printf(": can't map i/o space\n");
                    254:                return;
                    255:        }
                    256:
                    257:        sc->sc_iot = iot;
                    258:        sc->sc_ioh = ioh;
                    259:
                    260:        sc->probe = 0;
                    261:        sc->debug = 0;
                    262:
                    263:        if (!mcd_find(iot, ioh, sc)) {
                    264:                printf(": mcd_find failed\n");
                    265:                return;
                    266:        }
                    267:
                    268:        timeout_set(&sc->sc_pi_tmo, mcd_pseudointr, sc);
                    269:
                    270:        /*
                    271:         * Initialize and attach the disk structure.
                    272:         */
                    273:        sc->sc_dk.dk_driver = &mcddkdriver;
                    274:        sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
                    275:        disk_attach(&sc->sc_dk);
                    276:
                    277:        printf(": model %s\n", sc->type != 0 ? sc->type : "unknown");
                    278:
                    279:        (void) mcd_setlock(sc, MCD_LK_UNLOCK);
                    280:
                    281:        mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
                    282:        mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
                    283:        mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE;
                    284:        mbx.cmd.data.config.data1 = 0x01;
                    285:        mbx.res.length = 0;
                    286:        (void) mcd_send(sc, &mbx, 0);
                    287:
                    288:        mcd_soft_reset(sc);
                    289:
                    290:        sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
                    291:            IPL_BIO, mcdintr, sc, sc->sc_dev.dv_xname);
                    292: }
                    293:
                    294: /*
                    295:  * Wait interruptibly for an exclusive lock.
                    296:  *
                    297:  * XXX
                    298:  * Several drivers do this; it should be abstracted and made MP-safe.
                    299:  */
                    300: int
                    301: mcdlock(sc)
                    302:        struct mcd_softc *sc;
                    303: {
                    304:        int error;
                    305:
                    306:        while ((sc->flags & MCDF_LOCKED) != 0) {
                    307:                sc->flags |= MCDF_WANTED;
                    308:                if ((error = tsleep(sc, PRIBIO | PCATCH, "mcdlck", 0)) != 0)
                    309:                        return error;
                    310:        }
                    311:        sc->flags |= MCDF_LOCKED;
                    312:        return 0;
                    313: }
                    314:
                    315: /*
                    316:  * Unlock and wake up any waiters.
                    317:  */
                    318: void
                    319: mcdunlock(sc)
                    320:        struct mcd_softc *sc;
                    321: {
                    322:
                    323:        sc->flags &= ~MCDF_LOCKED;
                    324:        if ((sc->flags & MCDF_WANTED) != 0) {
                    325:                sc->flags &= ~MCDF_WANTED;
                    326:                wakeup(sc);
                    327:        }
                    328: }
                    329:
                    330: int
                    331: mcdopen(dev, flag, fmt, p)
                    332:        dev_t dev;
                    333:        int flag, fmt;
                    334:        struct proc *p;
                    335: {
                    336:        int error;
                    337:        int unit, part;
                    338:        struct mcd_softc *sc;
                    339:
                    340:        unit = DISKUNIT(dev);
                    341:        if (unit >= mcd_cd.cd_ndevs)
                    342:                return ENXIO;
                    343:        sc = mcd_cd.cd_devs[unit];
                    344:        if (!sc)
                    345:                return ENXIO;
                    346:
                    347:        if ((error = mcdlock(sc)) != 0)
                    348:                return error;
                    349:
                    350:        if (sc->sc_dk.dk_openmask != 0) {
                    351:                /*
                    352:                 * If any partition is open, but the disk has been invalidated,
                    353:                 * disallow further opens.
                    354:                 */
                    355:                if ((sc->flags & MCDF_LOADED) == 0) {
                    356:                        error = EIO;
                    357:                        goto bad3;
                    358:                }
                    359:        } else {
                    360:                /*
                    361:                 * Lock the drawer.  This will also notice any pending disk
                    362:                 * change or door open indicator and clear the MCDF_LOADED bit
                    363:                 * if necessary.
                    364:                 */
                    365:                (void) mcd_setlock(sc, MCD_LK_LOCK);
                    366:
                    367:                if ((sc->flags & MCDF_LOADED) == 0) {
                    368:                        /* Partially reset the state. */
                    369:                        sc->lastmode = MCD_MD_UNKNOWN;
                    370:                        sc->lastupc = MCD_UPC_UNKNOWN;
                    371:
                    372:                        sc->flags |= MCDF_LOADED;
                    373:
                    374:                        /* Set the mode, causing the disk to spin up. */
                    375:                        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                    376:                                goto bad2;
                    377:
                    378:                        /* Load the physical device parameters. */
                    379:                        if (mcd_get_parms(sc) != 0) {
                    380:                                error = ENXIO;
                    381:                                goto bad2;
                    382:                        }
                    383:
                    384:                        /* Read the table of contents. */
                    385:                        if ((error = mcd_read_toc(sc)) != 0)
                    386:                                goto bad2;
                    387:
                    388:                        /* Fabricate a disk label. */
                    389:                        mcdgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
                    390:                }
                    391:        }
                    392:
                    393:        MCD_TRACE("open: partition=%d disksize=%d blksize=%d\n", part,
                    394:            sc->disksize, sc->blksize, 0);
                    395:
                    396:        part = DISKPART(dev);
                    397:
                    398:        /* Check that the partition exists. */
                    399:        if (part != RAW_PART &&
                    400:            (part >= sc->sc_dk.dk_label->d_npartitions ||
                    401:             sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
                    402:                error = ENXIO;
                    403:                goto bad;
                    404:        }
                    405:
                    406:        /* Insure only one open at a time. */
                    407:        switch (fmt) {
                    408:        case S_IFCHR:
                    409:                sc->sc_dk.dk_copenmask |= (1 << part);
                    410:                break;
                    411:        case S_IFBLK:
                    412:                sc->sc_dk.dk_bopenmask |= (1 << part);
                    413:                break;
                    414:        }
                    415:        sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
                    416:
                    417:        mcdunlock(sc);
                    418:        return 0;
                    419:
                    420: bad2:
                    421:        sc->flags &= ~MCDF_LOADED;
                    422:
                    423: bad:
                    424:        if (sc->sc_dk.dk_openmask == 0) {
                    425: #if 0
                    426:                (void) mcd_setmode(sc, MCD_MD_SLEEP);
                    427: #endif
                    428:                (void) mcd_setlock(sc, MCD_LK_UNLOCK);
                    429:        }
                    430:
                    431: bad3:
                    432:        mcdunlock(sc);
                    433:        return error;
                    434: }
                    435:
                    436: int
                    437: mcdclose(dev, flag, fmt, p)
                    438:        dev_t dev;
                    439:        int flag, fmt;
                    440:        struct proc *p;
                    441: {
                    442:        struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(dev)];
                    443:        int part = DISKPART(dev);
                    444:        int error;
                    445:
                    446:        MCD_TRACE("close: partition=%d\n", part, 0, 0, 0);
                    447:
                    448:        if ((error = mcdlock(sc)) != 0)
                    449:                return error;
                    450:
                    451:        switch (fmt) {
                    452:        case S_IFCHR:
                    453:                sc->sc_dk.dk_copenmask &= ~(1 << part);
                    454:                break;
                    455:        case S_IFBLK:
                    456:                sc->sc_dk.dk_bopenmask &= ~(1 << part);
                    457:                break;
                    458:        }
                    459:        sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
                    460:
                    461:        if (sc->sc_dk.dk_openmask == 0) {
                    462:                /* XXXX Must wait for I/O to complete! */
                    463:
                    464: #if 0
                    465:                (void) mcd_setmode(sc, MCD_MD_SLEEP);
                    466: #endif
                    467:                (void) mcd_setlock(sc, MCD_LK_UNLOCK);
                    468:                if (sc->flags & MCDF_EJECTING) {
                    469:                        mcd_eject(sc);
                    470:                        sc->flags &= ~MCDF_EJECTING;
                    471:                }
                    472:        }
                    473:        mcdunlock(sc);
                    474:        return 0;
                    475: }
                    476:
                    477: void
                    478: mcdstrategy(bp)
                    479:        struct buf *bp;
                    480: {
                    481:        struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(bp->b_dev)];
                    482:        int s;
                    483:
                    484:        /* Test validity. */
                    485:        MCD_TRACE("strategy: buf=0x%lx blkno=%ld bcount=%ld\n", bp,
                    486:            bp->b_blkno, bp->b_bcount, 0);
                    487:        if (bp->b_blkno < 0 ||
                    488:            (bp->b_bcount % sc->blksize) != 0) {
                    489:                printf("%s: strategy: blkno = %d bcount = %ld\n",
                    490:                    sc->sc_dev.dv_xname, bp->b_blkno, bp->b_bcount);
                    491:                bp->b_error = EINVAL;
                    492:                goto bad;
                    493:        }
                    494:
                    495:        /* If device invalidated (e.g. media change, door open), error. */
                    496:        if ((sc->flags & MCDF_LOADED) == 0) {
                    497:                MCD_TRACE("strategy: drive not valid\n", 0, 0, 0, 0);
                    498:                bp->b_error = EIO;
                    499:                goto bad;
                    500:        }
                    501:
                    502:        /* No data to read. */
                    503:        if (bp->b_bcount == 0)
                    504:                goto done;
                    505:
                    506:        /*
                    507:         * Do bounds checking, adjust transfer. if error, process.
                    508:         * If end of partition, just return.
                    509:         */
                    510:        if (DISKPART(bp->b_dev) != RAW_PART &&
                    511:            bounds_check_with_label(bp, sc->sc_dk.dk_label,
                    512:            (sc->flags & (MCDF_WLABEL|MCDF_LABELLING)) != 0) <= 0)
                    513:                goto done;
                    514:
                    515:        /* Queue it. */
                    516:        s = splbio();
                    517:        disksort(&sc->buf_queue, bp);
                    518:        splx(s);
                    519:        if (!sc->buf_queue.b_active)
                    520:                mcdstart(sc);
                    521:        return;
                    522:
                    523: bad:
                    524:        bp->b_flags |= B_ERROR;
                    525: done:
                    526:        bp->b_resid = bp->b_bcount;
                    527:        s = splbio();
                    528:        biodone(bp);
                    529:        splx(s);
                    530: }
                    531:
                    532: void
                    533: mcdstart(sc)
                    534:        struct mcd_softc *sc;
                    535: {
                    536:        struct buf *bp, *dp = &sc->buf_queue;
                    537:        int s;
                    538:
                    539: loop:
                    540:        s = splbio();
                    541:
                    542:        bp = dp->b_actf;
                    543:        if (bp == NULL) {
                    544:                /* Nothing to do. */
                    545:                dp->b_active = 0;
                    546:                splx(s);
                    547:                return;
                    548:        }
                    549:
                    550:        /* Block found to process; dequeue. */
                    551:        MCD_TRACE("start: found block bp=0x%x\n", bp, 0, 0, 0);
                    552:        dp->b_actf = bp->b_actf;
                    553:        splx(s);
                    554:
                    555:        /* Changed media? */
                    556:        if ((sc->flags & MCDF_LOADED) == 0) {
                    557:                MCD_TRACE("start: drive not valid\n", 0, 0, 0, 0);
                    558:                bp->b_error = EIO;
                    559:                bp->b_flags |= B_ERROR;
                    560:                s = splbio();
                    561:                biodone(bp);
                    562:                splx(s);
                    563:                goto loop;
                    564:        }
                    565:
                    566:        dp->b_active = 1;
                    567:
                    568:        /* Instrumentation. */
                    569:        s = splbio();
                    570:        disk_busy(&sc->sc_dk);
                    571:        splx(s);
                    572:
                    573:        sc->mbx.retry = MCD_RDRETRIES;
                    574:        sc->mbx.bp = bp;
                    575:        sc->mbx.blkno = bp->b_blkno / (sc->blksize / DEV_BSIZE);
                    576:        if (DISKPART(bp->b_dev) != RAW_PART) {
                    577:                struct partition *p;
                    578:                p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
                    579:                sc->mbx.blkno += DL_GETPOFFSET(p);
                    580:        }
                    581:        sc->mbx.nblk = bp->b_bcount / sc->blksize;
                    582:        sc->mbx.sz = sc->blksize;
                    583:        sc->mbx.skip = 0;
                    584:        sc->mbx.state = MCD_S_BEGIN;
                    585:        sc->mbx.mode = MCD_MD_COOKED;
                    586:
                    587:        s = splbio();
                    588:        (void) mcdintr(sc);
                    589:        splx(s);
                    590: }
                    591:
                    592: int
                    593: mcdread(dev, uio, flags)
                    594:        dev_t dev;
                    595:        struct uio *uio;
                    596:        int flags;
                    597: {
                    598:
                    599:        return (physio(mcdstrategy, NULL, dev, B_READ, minphys, uio));
                    600: }
                    601:
                    602: int
                    603: mcdwrite(dev, uio, flags)
                    604:        dev_t dev;
                    605:        struct uio *uio;
                    606:        int flags;
                    607: {
                    608:
                    609:        return (physio(mcdstrategy, NULL, dev, B_WRITE, minphys, uio));
                    610: }
                    611:
                    612: int
                    613: mcdioctl(dev, cmd, addr, flag, p)
                    614:        dev_t dev;
                    615:        u_long cmd;
                    616:        caddr_t addr;
                    617:        int flag;
                    618:        struct proc *p;
                    619: {
                    620:        struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(dev)];
                    621:        struct disklabel *lp;
                    622:        int error;
                    623:
                    624:        MCD_TRACE("ioctl: cmd=0x%x\n", cmd, 0, 0, 0);
                    625:
                    626:        if ((sc->flags & MCDF_LOADED) == 0)
                    627:                return EIO;
                    628:
                    629:        switch (cmd) {
                    630:        case DIOCRLDINFO:
                    631:                lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
                    632:                mcdgetdisklabel(dev, sc, lp, 0);
                    633:                bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp));
                    634:                free(lp, M_TEMP);
                    635:                return 0;
                    636:
                    637:        case DIOCGDINFO:
                    638:        case DIOCGPDINFO:
                    639:                *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
                    640:                return 0;
                    641:
                    642:        case DIOCGPART:
                    643:                ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
                    644:                ((struct partinfo *)addr)->part =
                    645:                    &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
                    646:                return 0;
                    647:
                    648:        case DIOCWDINFO:
                    649:        case DIOCSDINFO:
                    650:                if ((flag & FWRITE) == 0)
                    651:                        return EBADF;
                    652:
                    653:                if ((error = mcdlock(sc)) != 0)
                    654:                        return error;
                    655:                sc->flags |= MCDF_LABELLING;
                    656:
                    657:                error = setdisklabel(sc->sc_dk.dk_label,
                    658:                    (struct disklabel *)addr, /*sc->sc_dk.dk_openmask : */0);
                    659:                if (error == 0) {
                    660:                }
                    661:
                    662:                sc->flags &= ~MCDF_LABELLING;
                    663:                mcdunlock(sc);
                    664:                return error;
                    665:
                    666:        case DIOCWLABEL:
                    667:                return EBADF;
                    668:
                    669:        case CDIOCPLAYTRACKS:
                    670:                return mcd_playtracks(sc, (struct ioc_play_track *)addr);
                    671:        case CDIOCPLAYMSF:
                    672:                return mcd_playmsf(sc, (struct ioc_play_msf *)addr);
                    673:        case CDIOCPLAYBLOCKS:
                    674:                return mcd_playblocks(sc, (struct ioc_play_blocks *)addr);
                    675:        case CDIOCREADSUBCHANNEL:
                    676:                return mcd_read_subchannel(sc, (struct ioc_read_subchannel *)addr);
                    677:        case CDIOREADTOCHEADER:
                    678:                return mcd_toc_header(sc, (struct ioc_toc_header *)addr);
                    679:        case CDIOREADTOCENTRYS:
                    680:                return mcd_toc_entries(sc, (struct ioc_read_toc_entry *)addr);
                    681:        case CDIOCSETPATCH:
                    682:        case CDIOCGETVOL:
                    683:        case CDIOCSETVOL:
                    684:        case CDIOCSETMONO:
                    685:        case CDIOCSETSTEREO:
                    686:        case CDIOCSETMUTE:
                    687:        case CDIOCSETLEFT:
                    688:        case CDIOCSETRIGHT:
                    689:                return EINVAL;
                    690:        case CDIOCRESUME:
                    691:                return mcd_resume(sc);
                    692:        case CDIOCPAUSE:
                    693:                return mcd_pause(sc);
                    694:        case CDIOCSTART:
                    695:                return EINVAL;
                    696:        case CDIOCSTOP:
                    697:                return mcd_stop(sc);
                    698:        case MTIOCTOP:
                    699:                if (((struct mtop *)addr)->mt_op != MTOFFL)
                    700:                        return EIO;
                    701:                /* FALLTHROUGH */
                    702:        case CDIOCEJECT: /* FALLTHROUGH */
                    703:        case DIOCEJECT:
                    704:                sc->flags |= MCDF_EJECTING;
                    705:                return (0);
                    706:        case CDIOCALLOW:
                    707:                return mcd_setlock(sc, MCD_LK_UNLOCK);
                    708:        case CDIOCPREVENT:
                    709:                return mcd_setlock(sc, MCD_LK_LOCK);
                    710:        case DIOCLOCK:
                    711:                return mcd_setlock(sc,
                    712:                    (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK);
                    713:        case CDIOCSETDEBUG:
                    714:                sc->debug = 1;
                    715:                return 0;
                    716:        case CDIOCCLRDEBUG:
                    717:                sc->debug = 0;
                    718:                return 0;
                    719:        case CDIOCRESET:
                    720:                return mcd_hard_reset(sc);
                    721:
                    722:        default:
                    723:                return ENOTTY;
                    724:        }
                    725:
                    726: #ifdef DIAGNOSTIC
                    727:        panic("mcdioctl: impossible");
                    728: #endif
                    729: }
                    730:
                    731: void
                    732: mcdgetdisklabel(dev, sc, lp, spoofonly)
                    733:        dev_t dev;
                    734:        struct mcd_softc *sc;
                    735:        struct disklabel *lp;
                    736:        int spoofonly;
                    737: {
                    738:        char *errstring;
                    739:
                    740:        bzero(lp, sizeof(struct disklabel));
                    741:
                    742:        lp->d_secsize = sc->blksize;
                    743:        lp->d_ntracks = 1;
                    744:        lp->d_nsectors = 100;
                    745:        lp->d_ncylinders = (sc->disksize / 100) + 1;
                    746:        lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
                    747:        if (lp->d_secpercyl == 0) {
                    748:                lp->d_secpercyl = 100;
                    749:                /* as long as it's not 0 - readdisklabel divides by it */
                    750:        }
                    751:
                    752:        strncpy(lp->d_typename, "Mitsumi CD-ROM", sizeof lp->d_typename);
                    753:        lp->d_type = DTYPE_SCSI;        /* XXX */
                    754:        strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname);
                    755:        DL_SETDSIZE(lp, sc->disksize);
                    756:        lp->d_rpm = 300;
                    757:        lp->d_interleave = 1;
                    758:        lp->d_version = 1;
                    759:
                    760:        lp->d_magic = DISKMAGIC;
                    761:        lp->d_magic2 = DISKMAGIC;
                    762:        lp->d_checksum = dkcksum(lp);
                    763:
                    764:        /*
                    765:         * Call the generic disklabel extraction routine
                    766:         */
                    767:        errstring = readdisklabel(DISKLABELDEV(dev), mcdstrategy, lp, spoofonly);
                    768:        if (errstring) {
                    769:                /*printf("%s: %s\n", sc->sc_dev.dv_xname, errstring);*/
                    770:                return;
                    771:        }
                    772: }
                    773:
                    774: int
                    775: mcd_get_parms(sc)
                    776:        struct mcd_softc *sc;
                    777: {
                    778:        struct mcd_mbox mbx;
                    779:        daddr64_t size;
                    780:        int error;
                    781:
                    782:        /* Send volume info command. */
                    783:        mbx.cmd.opcode = MCD_CMDGETVOLINFO;
                    784:        mbx.cmd.length = 0;
                    785:        mbx.res.length = sizeof(mbx.res.data.volinfo);
                    786:        if ((error = mcd_send(sc, &mbx, 1)) != 0)
                    787:                return error;
                    788:
                    789:        if (mbx.res.data.volinfo.trk_low == 0x00 &&
                    790:            mbx.res.data.volinfo.trk_high == 0x00)
                    791:                return EINVAL;
                    792:
                    793:        /* Volinfo is OK. */
                    794:        sc->volinfo = mbx.res.data.volinfo;
                    795:        sc->blksize = MCD_BLKSIZE_COOKED;
                    796:        size = msf2hsg(sc->volinfo.vol_msf, 0);
                    797:        sc->disksize = size * (MCD_BLKSIZE_COOKED / DEV_BSIZE);
                    798:        return 0;
                    799: }
                    800:
                    801: daddr64_t
                    802: mcdsize(dev)
                    803:        dev_t dev;
                    804: {
                    805:
                    806:        /* CD-ROMs are read-only. */
                    807:        return -1;
                    808: }
                    809:
                    810: int
                    811: mcddump(dev, blkno, va, size)
                    812:        dev_t dev;
                    813:        daddr64_t blkno;
                    814:        caddr_t va;
                    815:        size_t size;
                    816: {
                    817:
                    818:        /* Not implemented. */
                    819:        return ENXIO;
                    820: }
                    821:
                    822: /*
                    823:  * Find the board and fill in the softc.
                    824:  */
                    825: int
                    826: mcd_find(iot, ioh, sc)
                    827:        bus_space_tag_t iot;
                    828:        bus_space_handle_t ioh;
                    829:        struct mcd_softc *sc;
                    830: {
                    831:        int i;
                    832:        struct mcd_mbox mbx;
                    833:
                    834:         sc->sc_iot = iot;
                    835:        sc->sc_ioh = ioh;
                    836:
                    837:        /* Send a reset. */
                    838:        bus_space_write_1(iot, ioh, MCD_RESET, 0);
                    839:        delay(1000000);
                    840:        /* Get any pending status and throw away. */
                    841:        for (i = 10; i; i--)
                    842:                bus_space_read_1(iot, ioh, MCD_STATUS);
                    843:        delay(1000);
                    844:
                    845:        /* Send get status command. */
                    846:        mbx.cmd.opcode = MCD_CMDGETSTAT;
                    847:        mbx.cmd.length = 0;
                    848:        mbx.res.length = 0;
                    849:        if (mcd_send(sc, &mbx, 0) != 0)
                    850:                return 0;
                    851:
                    852:        /* Get info about the drive. */
                    853:        mbx.cmd.opcode = MCD_CMDCONTINFO;
                    854:        mbx.cmd.length = 0;
                    855:        mbx.res.length = sizeof(mbx.res.data.continfo);
                    856:        if (mcd_send(sc, &mbx, 0) != 0)
                    857:                return 0;
                    858:
                    859:        /*
                    860:         * The following is code which is not guaranteed to work for all
                    861:         * drives, because the meaning of the expected 'M' is not clear
                    862:         * (M_itsumi is an obvious assumption, but I don't trust that).
                    863:         * Also, the original hack had a bogus condition that always
                    864:         * returned true.
                    865:         *
                    866:         * Note:  Which models support interrupts?  >=LU005S?
                    867:         */
                    868:        sc->readcmd = MCD_CMDREADSINGLESPEED;
                    869:        switch (mbx.res.data.continfo.code) {
                    870:        case 'M':
                    871:                if (mbx.res.data.continfo.version <= 2)
                    872:                        sc->type = "LU002S";
                    873:                else if (mbx.res.data.continfo.version <= 5)
                    874:                        sc->type = "LU005S";
                    875:                else
                    876:                        sc->type = "LU006S";
                    877:                break;
                    878:        case 'F':
                    879:                sc->type = "FX001";
                    880:                break;
                    881:        case 'D':
                    882:                sc->type = "FX001D";
                    883:                sc->readcmd = MCD_CMDREADDOUBLESPEED;
                    884:                break;
                    885:        default:
                    886: #ifdef MCDDEBUG
                    887:                printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n",
                    888:                    sc->sc_dev.dv_xname,
                    889:                    mbx.res.data.continfo.code, mbx.res.data.continfo.version);
                    890: #endif
                    891:                sc->type = 0;
                    892:                break;
                    893:        }
                    894:
                    895:        return 1;
                    896:
                    897: }
                    898:
                    899: int
                    900: mcdprobe(parent, match, aux)
                    901:        struct device *parent;
                    902:        void *match;
                    903:        void *aux;
                    904: {
                    905:        struct isa_attach_args *ia = aux;
                    906:        struct mcd_softc sc;
                    907:        bus_space_tag_t iot = ia->ia_iot;
                    908:        bus_space_handle_t ioh;
                    909:        int rv;
                    910:
                    911:        /* Disallow wildcarded i/o address. */
                    912:        if (ia->ia_iobase == -1 /*ISACF_PORT_DEFAULT*/)
                    913:                return (0);
                    914:
                    915:        /* Map i/o space */
                    916:        if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh))
                    917:                return 0;
                    918:
                    919:        if (!opti_cd_setup(OPTI_MITSUMI, ia->ia_iobase, ia->ia_irq, ia->ia_drq))
                    920:                /* printf("mcdprobe: could not setup OPTi chipset.\n") */;
                    921:
                    922:        bzero(&sc, sizeof sc);
                    923:        sc.debug = 0;
                    924:        sc.probe = 1;
                    925:
                    926:        rv = mcd_find(iot, ioh, &sc);
                    927:
                    928:        bus_space_unmap(iot, ioh, MCD_NPORT);
                    929:
                    930:        if (rv) {
                    931:                ia->ia_iosize = MCD_NPORT;
                    932:                ia->ia_msize = 0;
                    933:        }
                    934:
                    935:        return (rv);
                    936: }
                    937:
                    938: int
                    939: mcd_getreply(sc)
                    940:        struct mcd_softc *sc;
                    941: {
                    942:        bus_space_tag_t iot = sc->sc_iot;
                    943:        bus_space_handle_t ioh = sc->sc_ioh;
                    944:        int i;
                    945:
                    946:        /* Wait until xfer port senses data ready. */
                    947:        for (i = DELAY_GETREPLY; i; i--) {
                    948:                if ((bus_space_read_1(iot, ioh, MCD_XFER) &
                    949:                    MCD_XF_STATUSUNAVAIL) == 0)
                    950:                        break;
                    951:                delay(DELAY_GRANULARITY);
                    952:        }
                    953:        if (!i)
                    954:                return -1;
                    955:
                    956:        /* Get the data. */
                    957:        return bus_space_read_1(iot, ioh, MCD_STATUS);
                    958: }
                    959:
                    960: int
                    961: mcd_getstat(sc)
                    962:        struct mcd_softc *sc;
                    963: {
                    964:        struct mcd_mbox mbx;
                    965:
                    966:        mbx.cmd.opcode = MCD_CMDGETSTAT;
                    967:        mbx.cmd.length = 0;
                    968:        mbx.res.length = 0;
                    969:        return mcd_send(sc, &mbx, 1);
                    970: }
                    971:
                    972: int
                    973: mcd_getresult(sc, res)
                    974:        struct mcd_softc *sc;
                    975:        struct mcd_result *res;
                    976: {
                    977:        int i, x;
                    978:
                    979:        if (sc->debug)
                    980:                printf("%s: mcd_getresult: %d", sc->sc_dev.dv_xname,
                    981:                    res->length);
                    982:
                    983:        if ((x = mcd_getreply(sc)) < 0) {
                    984:                if (sc->debug)
                    985:                        printf(" timeout\n");
                    986:                else if (sc->probe == 0)
                    987:                        printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
                    988:                return EIO;
                    989:        }
                    990:        if (sc->debug)
                    991:                printf(" %02x", (u_int)x);
                    992:        sc->status = x;
                    993:        mcd_setflags(sc);
                    994:
                    995:        if ((sc->status & MCD_ST_CMDCHECK) != 0)
                    996:                return EINVAL;
                    997:
                    998:        for (i = 0; i < res->length; i++) {
                    999:                if ((x = mcd_getreply(sc)) < 0) {
                   1000:                        if (sc->debug)
                   1001:                                printf(" timeout\n");
                   1002:                        else
                   1003:                                printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
                   1004:                        return EIO;
                   1005:                }
                   1006:                if (sc->debug)
                   1007:                        printf(" %02x", (u_int)x);
                   1008:                res->data.raw.data[i] = x;
                   1009:        }
                   1010:
                   1011:        if (sc->debug)
                   1012:                printf(" succeeded\n");
                   1013:
                   1014: #ifdef MCDDEBUG
                   1015:        delay(10);
                   1016:        while ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_XFER) &
                   1017:            MCD_XF_STATUSUNAVAIL) == 0) {
                   1018:                x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_STATUS);
                   1019:                printf("%s: got extra byte %02x during getstatus\n",
                   1020:                    sc->sc_dev.dv_xname, (u_int)x);
                   1021:                delay(10);
                   1022:        }
                   1023: #endif
                   1024:
                   1025:        return 0;
                   1026: }
                   1027:
                   1028: void
                   1029: mcd_setflags(sc)
                   1030:        struct mcd_softc *sc;
                   1031: {
                   1032:
                   1033:        /* Check flags. */
                   1034:        if ((sc->flags & MCDF_LOADED) != 0 &&
                   1035:            (sc->status & (MCD_ST_DSKCHNG | MCD_ST_DSKIN | MCD_ST_DOOROPEN)) !=
                   1036:            MCD_ST_DSKIN) {
                   1037:                if ((sc->status & MCD_ST_DOOROPEN) != 0)
                   1038:                        printf("%s: door open\n", sc->sc_dev.dv_xname);
                   1039:                else if ((sc->status & MCD_ST_DSKIN) == 0)
                   1040:                        printf("%s: no disk present\n", sc->sc_dev.dv_xname);
                   1041:                else if ((sc->status & MCD_ST_DSKCHNG) != 0)
                   1042:                        printf("%s: media change\n", sc->sc_dev.dv_xname);
                   1043:                sc->flags &= ~MCDF_LOADED;
                   1044:        }
                   1045:
                   1046:        if ((sc->status & MCD_ST_AUDIOBSY) != 0)
                   1047:                sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
                   1048:        else if (sc->audio_status == CD_AS_PLAY_IN_PROGRESS ||
                   1049:                 sc->audio_status == CD_AS_AUDIO_INVALID)
                   1050:                sc->audio_status = CD_AS_PLAY_COMPLETED;
                   1051: }
                   1052:
                   1053: int
                   1054: mcd_send(sc, mbx, diskin)
                   1055:        struct mcd_softc *sc;
                   1056:        struct mcd_mbox *mbx;
                   1057:        int diskin;
                   1058: {
                   1059:        int retry, i, error;
                   1060:        bus_space_tag_t iot = sc->sc_iot;
                   1061:        bus_space_handle_t ioh = sc->sc_ioh;
                   1062:
                   1063:        if (sc->debug) {
                   1064:                printf("%s: mcd_send: %d %02x", sc->sc_dev.dv_xname,
                   1065:                    mbx->cmd.length, (u_int)mbx->cmd.opcode);
                   1066:                for (i = 0; i < mbx->cmd.length; i++)
                   1067:                        printf(" %02x", (u_int)mbx->cmd.data.raw.data[i]);
                   1068:                printf("\n");
                   1069:        }
                   1070:
                   1071:        for (retry = MCD_RETRIES; retry; retry--) {
                   1072:                bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.opcode);
                   1073:                for (i = 0; i < mbx->cmd.length; i++)
                   1074:                        bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.data.raw.data[i]);
                   1075:                if ((error = mcd_getresult(sc, &mbx->res)) == 0)
                   1076:                        break;
                   1077:                if (error == EINVAL)
                   1078:                        return error;
                   1079:        }
                   1080:        if (!retry)
                   1081:                return error;
                   1082:        if (diskin && (sc->flags & MCDF_LOADED) == 0)
                   1083:                return EIO;
                   1084:
                   1085:        return 0;
                   1086: }
                   1087:
                   1088: static void
                   1089: hsg2msf(hsg, msf)
                   1090:        int hsg;
                   1091:        bcd_t *msf;
                   1092: {
                   1093:
                   1094:        hsg += 150;
                   1095:        F_msf(msf) = bin2bcd(hsg % 75);
                   1096:        hsg /= 75;
                   1097:        S_msf(msf) = bin2bcd(hsg % 60);
                   1098:        hsg /= 60;
                   1099:        M_msf(msf) = bin2bcd(hsg);
                   1100: }
                   1101:
                   1102: static daddr64_t
                   1103: msf2hsg(msf, relative)
                   1104:        bcd_t *msf;
                   1105:        int relative;
                   1106: {
                   1107:        daddr64_t blkno;
                   1108:
                   1109:        blkno = bcd2bin(M_msf(msf)) * 75 * 60 +
                   1110:                bcd2bin(S_msf(msf)) * 75 +
                   1111:                bcd2bin(F_msf(msf));
                   1112:        if (!relative)
                   1113:                blkno -= 150;
                   1114:        return blkno;
                   1115: }
                   1116:
                   1117: void
                   1118: mcd_pseudointr(v)
                   1119:        void *v;
                   1120: {
                   1121:        struct mcd_softc *sc = v;
                   1122:        int s;
                   1123:
                   1124:        s = splbio();
                   1125:        (void) mcdintr(sc);
                   1126:        splx(s);
                   1127: }
                   1128:
                   1129: /*
                   1130:  * State machine to process read requests.
                   1131:  * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
                   1132:  * MCD_S_WAITMODE: waits for status reply from set mode, set read command
                   1133:  * MCD_S_WAITREAD: wait for read ready, read data.
                   1134:  */
                   1135: int
                   1136: mcdintr(arg)
                   1137:        void *arg;
                   1138: {
                   1139:        struct mcd_softc *sc = arg;
                   1140:        struct mcd_mbx *mbx = &sc->mbx;
                   1141:        struct buf *bp = mbx->bp;
                   1142:        bus_space_tag_t iot = sc->sc_iot;
                   1143:        bus_space_handle_t ioh = sc->sc_ioh;
                   1144:
                   1145:        int i;
                   1146:        u_char x;
                   1147:        bcd_t msf[3];
                   1148:
                   1149:        switch (mbx->state) {
                   1150:        case MCD_S_IDLE:
                   1151:                return 0;
                   1152:
                   1153:        case MCD_S_BEGIN:
                   1154:        tryagain:
                   1155:                if (mbx->mode == sc->lastmode)
                   1156:                        goto firstblock;
                   1157:
                   1158:                sc->lastmode = MCD_MD_UNKNOWN;
                   1159:                bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE);
                   1160:                bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode);
                   1161:
                   1162:                mbx->count = RDELAY_WAITMODE;
                   1163:                mbx->state = MCD_S_WAITMODE;
                   1164:
                   1165:        case MCD_S_WAITMODE:
                   1166:                timeout_del(&sc->sc_pi_tmo);
                   1167:                for (i = 20; i; i--) {
                   1168:                        x = bus_space_read_1(iot, ioh, MCD_XFER);
                   1169:                        if ((x & MCD_XF_STATUSUNAVAIL) == 0)
                   1170:                                break;
                   1171:                        delay(50);
                   1172:                }
                   1173:                if (i == 0)
                   1174:                        goto hold;
                   1175:                sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
                   1176:                mcd_setflags(sc);
                   1177:                if ((sc->flags & MCDF_LOADED) == 0)
                   1178:                        goto changed;
                   1179:                MCD_TRACE("doread: got WAITMODE delay=%d\n",
                   1180:                    RDELAY_WAITMODE - mbx->count, 0, 0, 0);
                   1181:
                   1182:                sc->lastmode = mbx->mode;
                   1183:
                   1184:        firstblock:
                   1185:                MCD_TRACE("doread: read blkno=%d for bp=0x%x\n", mbx->blkno,
                   1186:                    bp, 0, 0);
                   1187:
                   1188:                /* Build parameter block. */
                   1189:                hsg2msf(mbx->blkno, msf);
                   1190:
                   1191:                /* Send the read command. */
                   1192:                bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd);
                   1193:                bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]);
                   1194:                bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]);
                   1195:                bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]);
                   1196:                bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
                   1197:                bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
                   1198:                bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk);
                   1199:
                   1200:                mbx->count = RDELAY_WAITREAD;
                   1201:                mbx->state = MCD_S_WAITREAD;
                   1202:
                   1203:        case MCD_S_WAITREAD:
                   1204:                timeout_del(&sc->sc_pi_tmo);
                   1205:        nextblock:
                   1206:        loop:
                   1207:                for (i = 20; i; i--) {
                   1208:                        x = bus_space_read_1(iot, ioh, MCD_XFER);
                   1209:                        if ((x & MCD_XF_DATAUNAVAIL) == 0)
                   1210:                                goto gotblock;
                   1211:                        if ((x & MCD_XF_STATUSUNAVAIL) == 0)
                   1212:                                break;
                   1213:                        delay(50);
                   1214:                }
                   1215:                if (i == 0)
                   1216:                        goto hold;
                   1217:                sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
                   1218:                mcd_setflags(sc);
                   1219:                if ((sc->flags & MCDF_LOADED) == 0)
                   1220:                        goto changed;
                   1221: #if 0
                   1222:                printf("%s: got status byte %02x during read\n",
                   1223:                    sc->sc_dev.dv_xname, (u_int)sc->status);
                   1224: #endif
                   1225:                goto loop;
                   1226:
                   1227:        gotblock:
                   1228:                MCD_TRACE("doread: got data delay=%d\n",
                   1229:                    RDELAY_WAITREAD - mbx->count, 0, 0, 0);
                   1230:
                   1231:                /* Data is ready. */
                   1232:                bus_space_write_1(iot, ioh, MCD_CTL2, 0x04);    /* XXX */
                   1233:                bus_space_read_multi_1(iot, ioh, MCD_RDATA,
                   1234:                    bp->b_data + mbx->skip, mbx->sz);
                   1235:                bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c);    /* XXX */
                   1236:                mbx->blkno += 1;
                   1237:                mbx->skip += mbx->sz;
                   1238:                if (--mbx->nblk > 0)
                   1239:                        goto nextblock;
                   1240:
                   1241:                mbx->state = MCD_S_IDLE;
                   1242:
                   1243:                /* Return buffer. */
                   1244:                bp->b_resid = 0;
                   1245:                disk_unbusy(&sc->sc_dk, bp->b_bcount, (bp->b_flags & B_READ));
                   1246:                biodone(bp);
                   1247:
                   1248:                mcdstart(sc);
                   1249:                return 1;
                   1250:
                   1251:        hold:
                   1252:                if (mbx->count-- < 0) {
                   1253:                        printf("%s: timeout in state %d",
                   1254:                            sc->sc_dev.dv_xname, mbx->state);
                   1255:                        goto readerr;
                   1256:                }
                   1257:
                   1258: #if 0
                   1259:                printf("%s: sleep in state %d\n", sc->sc_dev.dv_xname,
                   1260:                    mbx->state);
                   1261: #endif
                   1262:                timeout_add(&sc->sc_pi_tmo, hz / 100);
                   1263:                return -1;
                   1264:        }
                   1265:
                   1266: readerr:
                   1267:        if (mbx->retry-- > 0) {
                   1268:                printf("; retrying\n");
                   1269:                goto tryagain;
                   1270:        } else
                   1271:                printf("; giving up\n");
                   1272:
                   1273: changed:
                   1274:        /* Invalidate the buffer. */
                   1275:        bp->b_flags |= B_ERROR;
                   1276:        bp->b_resid = bp->b_bcount - mbx->skip;
                   1277:        disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
                   1278:            (bp->b_flags & B_READ));
                   1279:        biodone(bp);
                   1280:
                   1281:        mcdstart(sc);
                   1282:        return -1;
                   1283:
                   1284: #ifdef notyet
                   1285:        printf("%s: unit timeout; resetting\n", sc->sc_dev.dv_xname);
                   1286:        bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET);
                   1287:        delay(300000);
                   1288:        (void) mcd_getstat(sc, 1);
                   1289:        (void) mcd_getstat(sc, 1);
                   1290:        /*sc->status &= ~MCD_ST_DSKCHNG; */
                   1291:        sc->debug = 1; /* preventive set debug mode */
                   1292: #endif
                   1293: }
                   1294:
                   1295: void
                   1296: mcd_soft_reset(sc)
                   1297:        struct mcd_softc *sc;
                   1298: {
                   1299:
                   1300:        sc->debug = 0;
                   1301:        sc->flags = 0;
                   1302:        sc->lastmode = MCD_MD_UNKNOWN;
                   1303:        sc->lastupc = MCD_UPC_UNKNOWN;
                   1304:        sc->audio_status = CD_AS_AUDIO_INVALID;
                   1305:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, MCD_CTL2, 0x0c); /* XXX */
                   1306: }
                   1307:
                   1308: int
                   1309: mcd_hard_reset(sc)
                   1310:        struct mcd_softc *sc;
                   1311: {
                   1312:        struct mcd_mbox mbx;
                   1313:
                   1314:        mcd_soft_reset(sc);
                   1315:
                   1316:        mbx.cmd.opcode = MCD_CMDRESET;
                   1317:        mbx.cmd.length = 0;
                   1318:        mbx.res.length = 0;
                   1319:        return mcd_send(sc, &mbx, 0);
                   1320: }
                   1321:
                   1322: int
                   1323: mcd_setmode(sc, mode)
                   1324:        struct mcd_softc *sc;
                   1325:        int mode;
                   1326: {
                   1327:        struct mcd_mbox mbx;
                   1328:        int error;
                   1329:
                   1330:        if (sc->lastmode == mode)
                   1331:                return 0;
                   1332:        if (sc->debug)
                   1333:                printf("%s: setting mode to %d\n", sc->sc_dev.dv_xname, mode);
                   1334:        sc->lastmode = MCD_MD_UNKNOWN;
                   1335:
                   1336:        mbx.cmd.opcode = MCD_CMDSETMODE;
                   1337:        mbx.cmd.length = sizeof(mbx.cmd.data.datamode);
                   1338:        mbx.cmd.data.datamode.mode = mode;
                   1339:        mbx.res.length = 0;
                   1340:        if ((error = mcd_send(sc, &mbx, 1)) != 0)
                   1341:                return error;
                   1342:
                   1343:        sc->lastmode = mode;
                   1344:        return 0;
                   1345: }
                   1346:
                   1347: int
                   1348: mcd_setupc(sc, upc)
                   1349:        struct mcd_softc *sc;
                   1350:        int upc;
                   1351: {
                   1352:        struct mcd_mbox mbx;
                   1353:        int error;
                   1354:
                   1355:        if (sc->lastupc == upc)
                   1356:                return 0;
                   1357:        if (sc->debug)
                   1358:                printf("%s: setting upc to %d\n", sc->sc_dev.dv_xname, upc);
                   1359:        sc->lastupc = MCD_UPC_UNKNOWN;
                   1360:
                   1361:        mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
                   1362:        mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
                   1363:        mbx.cmd.data.config.subcommand = MCD_CF_READUPC;
                   1364:        mbx.cmd.data.config.data1 = upc;
                   1365:        mbx.res.length = 0;
                   1366:        if ((error = mcd_send(sc, &mbx, 1)) != 0)
                   1367:                return error;
                   1368:
                   1369:        sc->lastupc = upc;
                   1370:        return 0;
                   1371: }
                   1372:
                   1373: int
                   1374: mcd_toc_header(sc, th)
                   1375:        struct mcd_softc *sc;
                   1376:        struct ioc_toc_header *th;
                   1377: {
                   1378:
                   1379:        if (sc->debug)
                   1380:                printf("%s: mcd_toc_header: reading toc header\n",
                   1381:                    sc->sc_dev.dv_xname);
                   1382:
                   1383:        th->len = msf2hsg(sc->volinfo.vol_msf, 0);
                   1384:        th->starting_track = bcd2bin(sc->volinfo.trk_low);
                   1385:        th->ending_track = bcd2bin(sc->volinfo.trk_high);
                   1386:
                   1387:        return 0;
                   1388: }
                   1389:
                   1390: int
                   1391: mcd_read_toc(sc)
                   1392:        struct mcd_softc *sc;
                   1393: {
                   1394:        struct ioc_toc_header th;
                   1395:        union mcd_qchninfo q;
                   1396:        int error, trk, idx, retry;
                   1397:
                   1398:        if ((error = mcd_toc_header(sc, &th)) != 0)
                   1399:                return error;
                   1400:
                   1401:        if ((error = mcd_stop(sc)) != 0)
                   1402:                return error;
                   1403:
                   1404:        if (sc->debug)
                   1405:                printf("%s: read_toc: reading qchannel info\n",
                   1406:                    sc->sc_dev.dv_xname);
                   1407:
                   1408:        for (trk = th.starting_track; trk <= th.ending_track; trk++)
                   1409:                sc->toc[trk].toc.idx_no = 0x00;
                   1410:        trk = th.ending_track - th.starting_track + 1;
                   1411:        for (retry = 300; retry && trk > 0; retry--) {
                   1412:                if (mcd_getqchan(sc, &q, CD_TRACK_INFO) != 0)
                   1413:                        break;
                   1414:                if (q.toc.trk_no != 0x00 || q.toc.idx_no == 0x00)
                   1415:                        continue;
                   1416:                idx = bcd2bin(q.toc.idx_no);
                   1417:                if (idx < MCD_MAXTOCS &&
                   1418:                    sc->toc[idx].toc.idx_no == 0x00) {
                   1419:                        sc->toc[idx] = q;
                   1420:                        trk--;
                   1421:                }
                   1422:        }
                   1423:
                   1424:        /* Inform the drive that we're finished so it turns off the light. */
                   1425:        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1426:                return error;
                   1427:
                   1428:        if (trk != 0)
                   1429:                return EINVAL;
                   1430:
                   1431:        /* Add a fake last+1 for mcd_playtracks(). */
                   1432:        idx = th.ending_track + 1;
                   1433:        sc->toc[idx].toc.control = sc->toc[idx-1].toc.control;
                   1434:        sc->toc[idx].toc.addr_type = sc->toc[idx-1].toc.addr_type;
                   1435:        sc->toc[idx].toc.trk_no = 0x00;
                   1436:        sc->toc[idx].toc.idx_no = 0xaa;
                   1437:        sc->toc[idx].toc.absolute_pos[0] = sc->volinfo.vol_msf[0];
                   1438:        sc->toc[idx].toc.absolute_pos[1] = sc->volinfo.vol_msf[1];
                   1439:        sc->toc[idx].toc.absolute_pos[2] = sc->volinfo.vol_msf[2];
                   1440:
                   1441:        return 0;
                   1442: }
                   1443:
                   1444: int
                   1445: mcd_toc_entries(sc, te)
                   1446:        struct mcd_softc *sc;
                   1447:        struct ioc_read_toc_entry *te;
                   1448: {
                   1449:        int len = te->data_len;
                   1450:        struct ret_toc {
                   1451:                struct ioc_toc_header header;
                   1452:                struct cd_toc_entry entries[MCD_MAXTOCS];
                   1453:        } data;
                   1454:        u_char trk;
                   1455:        daddr64_t lba;
                   1456:        int error, n;
                   1457:
                   1458:        if (len > sizeof(data.entries) ||
                   1459:            len < sizeof(struct cd_toc_entry))
                   1460:                return EINVAL;
                   1461:        if (te->address_format != CD_MSF_FORMAT &&
                   1462:            te->address_format != CD_LBA_FORMAT)
                   1463:                return EINVAL;
                   1464:
                   1465:        /* Copy the TOC header. */
                   1466:        if ((error = mcd_toc_header(sc, &data.header)) != 0)
                   1467:                return error;
                   1468:
                   1469:        /* Verify starting track. */
                   1470:        trk = te->starting_track;
                   1471:        if (trk == 0x00)
                   1472:                trk = data.header.starting_track;
                   1473:        else if (trk == 0xaa)
                   1474:                trk = data.header.ending_track + 1;
                   1475:        else if (trk < data.header.starting_track ||
                   1476:                 trk > data.header.ending_track + 1)
                   1477:                return EINVAL;
                   1478:
                   1479:        /* Copy the TOC data. */
                   1480:        for (n = 0; trk <= data.header.ending_track + 1; trk++) {
                   1481:                if (sc->toc[trk].toc.idx_no == 0x00)
                   1482:                        continue;
                   1483:                data.entries[n].control = sc->toc[trk].toc.control;
                   1484:                data.entries[n].addr_type = sc->toc[trk].toc.addr_type;
                   1485:                data.entries[n].track = bcd2bin(sc->toc[trk].toc.idx_no);
                   1486:                switch (te->address_format) {
                   1487:                case CD_MSF_FORMAT:
                   1488:                        data.entries[n].addr.addr[0] = 0;
                   1489:                        data.entries[n].addr.addr[1] =
                   1490:                            bcd2bin(sc->toc[trk].toc.absolute_pos[0]);
                   1491:                        data.entries[n].addr.addr[2] =
                   1492:                            bcd2bin(sc->toc[trk].toc.absolute_pos[1]);
                   1493:                        data.entries[n].addr.addr[3] =
                   1494:                            bcd2bin(sc->toc[trk].toc.absolute_pos[2]);
                   1495:                        break;
                   1496:                case CD_LBA_FORMAT:
                   1497:                        lba = msf2hsg(sc->toc[trk].toc.absolute_pos, 0);
                   1498:                        data.entries[n].addr.addr[0] = lba >> 24;
                   1499:                        data.entries[n].addr.addr[1] = lba >> 16;
                   1500:                        data.entries[n].addr.addr[2] = lba >> 8;
                   1501:                        data.entries[n].addr.addr[3] = lba;
                   1502:                        break;
                   1503:                }
                   1504:                n++;
                   1505:        }
                   1506:
                   1507:        len = min(len, n * sizeof(struct cd_toc_entry));
                   1508:
                   1509:        /* Copy the data back. */
                   1510:        return copyout(&data.entries[0], te->data, len);
                   1511: }
                   1512:
                   1513: int
                   1514: mcd_stop(sc)
                   1515:        struct mcd_softc *sc;
                   1516: {
                   1517:        struct mcd_mbox mbx;
                   1518:        int error;
                   1519:
                   1520:        if (sc->debug)
                   1521:                printf("%s: mcd_stop: stopping play\n", sc->sc_dev.dv_xname);
                   1522:
                   1523:        mbx.cmd.opcode = MCD_CMDSTOPAUDIO;
                   1524:        mbx.cmd.length = 0;
                   1525:        mbx.res.length = 0;
                   1526:        if ((error = mcd_send(sc, &mbx, 1)) != 0)
                   1527:                return error;
                   1528:
                   1529:        sc->audio_status = CD_AS_PLAY_COMPLETED;
                   1530:        return 0;
                   1531: }
                   1532:
                   1533: int
                   1534: mcd_getqchan(sc, q, qchn)
                   1535:        struct mcd_softc *sc;
                   1536:        union mcd_qchninfo *q;
                   1537:        int qchn;
                   1538: {
                   1539:        struct mcd_mbox mbx;
                   1540:        int error;
                   1541:
                   1542:        if (qchn == CD_TRACK_INFO) {
                   1543:                if ((error = mcd_setmode(sc, MCD_MD_TOC)) != 0)
                   1544:                        return error;
                   1545:        } else {
                   1546:                if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1547:                        return error;
                   1548:        }
                   1549:        if (qchn == CD_MEDIA_CATALOG) {
                   1550:                if ((error = mcd_setupc(sc, MCD_UPC_ENABLE)) != 0)
                   1551:                        return error;
                   1552:        } else {
                   1553:                if ((error = mcd_setupc(sc, MCD_UPC_DISABLE)) != 0)
                   1554:                        return error;
                   1555:        }
                   1556:
                   1557:        mbx.cmd.opcode = MCD_CMDGETQCHN;
                   1558:        mbx.cmd.length = 0;
                   1559:        mbx.res.length = sizeof(mbx.res.data.qchninfo);
                   1560:        if ((error = mcd_send(sc, &mbx, 1)) != 0)
                   1561:                return error;
                   1562:
                   1563:        *q = mbx.res.data.qchninfo;
                   1564:        return 0;
                   1565: }
                   1566:
                   1567: int
                   1568: mcd_read_subchannel(sc, ch)
                   1569:        struct mcd_softc *sc;
                   1570:        struct ioc_read_subchannel *ch;
                   1571: {
                   1572:        int len = ch->data_len;
                   1573:        union mcd_qchninfo q;
                   1574:        struct cd_sub_channel_info data;
                   1575:        daddr64_t lba;
                   1576:        int error;
                   1577:
                   1578:        if (sc->debug)
                   1579:                printf("%s: subchan: af=%d df=%d\n", sc->sc_dev.dv_xname,
                   1580:                    ch->address_format, ch->data_format);
                   1581:
                   1582:        if (len > sizeof(data) ||
                   1583:            len < sizeof(struct cd_sub_channel_header))
                   1584:                return EINVAL;
                   1585:        if (ch->address_format != CD_MSF_FORMAT &&
                   1586:            ch->address_format != CD_LBA_FORMAT)
                   1587:                return EINVAL;
                   1588:        if (ch->data_format != CD_CURRENT_POSITION &&
                   1589:            ch->data_format != CD_MEDIA_CATALOG)
                   1590:                return EINVAL;
                   1591:
                   1592:        if ((error = mcd_getqchan(sc, &q, ch->data_format)) != 0)
                   1593:                return error;
                   1594:
                   1595:        data.header.audio_status = sc->audio_status;
                   1596:        data.what.media_catalog.data_format = ch->data_format;
                   1597:
                   1598:        switch (ch->data_format) {
                   1599:        case CD_MEDIA_CATALOG:
                   1600:                data.what.media_catalog.mc_valid = 1;
                   1601: #if 0
                   1602:                data.what.media_catalog.mc_number =
                   1603: #endif
                   1604:                break;
                   1605:
                   1606:        case CD_CURRENT_POSITION:
                   1607:                data.what.position.track_number = bcd2bin(q.current.trk_no);
                   1608:                data.what.position.index_number = bcd2bin(q.current.idx_no);
                   1609:                switch (ch->address_format) {
                   1610:                case CD_MSF_FORMAT:
                   1611:                        data.what.position.reladdr.addr[0] = 0;
                   1612:                        data.what.position.reladdr.addr[1] =
                   1613:                            bcd2bin(q.current.relative_pos[0]);
                   1614:                        data.what.position.reladdr.addr[2] =
                   1615:                            bcd2bin(q.current.relative_pos[1]);
                   1616:                        data.what.position.reladdr.addr[3] =
                   1617:                            bcd2bin(q.current.relative_pos[2]);
                   1618:                        data.what.position.absaddr.addr[0] = 0;
                   1619:                        data.what.position.absaddr.addr[1] =
                   1620:                            bcd2bin(q.current.absolute_pos[0]);
                   1621:                        data.what.position.absaddr.addr[2] =
                   1622:                            bcd2bin(q.current.absolute_pos[1]);
                   1623:                        data.what.position.absaddr.addr[3] =
                   1624:                            bcd2bin(q.current.absolute_pos[2]);
                   1625:                        break;
                   1626:                case CD_LBA_FORMAT:
                   1627:                        lba = msf2hsg(q.current.relative_pos, 1);
                   1628:                        /*
                   1629:                         * Pre-gap has index number of 0, and decreasing MSF
                   1630:                         * address.  Must be converted to negative LBA, per
                   1631:                         * SCSI spec.
                   1632:                         */
                   1633:                        if (data.what.position.index_number == 0x00)
                   1634:                                lba = -lba;
                   1635:                        data.what.position.reladdr.addr[0] = lba >> 24;
                   1636:                        data.what.position.reladdr.addr[1] = lba >> 16;
                   1637:                        data.what.position.reladdr.addr[2] = lba >> 8;
                   1638:                        data.what.position.reladdr.addr[3] = lba;
                   1639:                        lba = msf2hsg(q.current.absolute_pos, 0);
                   1640:                        data.what.position.absaddr.addr[0] = lba >> 24;
                   1641:                        data.what.position.absaddr.addr[1] = lba >> 16;
                   1642:                        data.what.position.absaddr.addr[2] = lba >> 8;
                   1643:                        data.what.position.absaddr.addr[3] = lba;
                   1644:                        break;
                   1645:                }
                   1646:                break;
                   1647:        }
                   1648:
                   1649:        return copyout(&data, ch->data, len);
                   1650: }
                   1651:
                   1652: int
                   1653: mcd_playtracks(sc, p)
                   1654:        struct mcd_softc *sc;
                   1655:        struct ioc_play_track *p;
                   1656: {
                   1657:        struct mcd_mbox mbx;
                   1658:        int a = p->start_track;
                   1659:        int z = p->end_track;
                   1660:        int error;
                   1661:
                   1662:        if (sc->debug)
                   1663:                printf("%s: playtracks: from %d:%d to %d:%d\n",
                   1664:                    sc->sc_dev.dv_xname,
                   1665:                    a, p->start_index, z, p->end_index);
                   1666:
                   1667:        if (a < bcd2bin(sc->volinfo.trk_low) ||
                   1668:            a > bcd2bin(sc->volinfo.trk_high) ||
                   1669:            a > z ||
                   1670:            z < bcd2bin(sc->volinfo.trk_low) ||
                   1671:            z > bcd2bin(sc->volinfo.trk_high))
                   1672:                return EINVAL;
                   1673:
                   1674:        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1675:                return error;
                   1676:
                   1677:        mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
                   1678:        mbx.cmd.length = sizeof(mbx.cmd.data.play);
                   1679:        mbx.cmd.data.play.start_msf[0] = sc->toc[a].toc.absolute_pos[0];
                   1680:        mbx.cmd.data.play.start_msf[1] = sc->toc[a].toc.absolute_pos[1];
                   1681:        mbx.cmd.data.play.start_msf[2] = sc->toc[a].toc.absolute_pos[2];
                   1682:        mbx.cmd.data.play.end_msf[0] = sc->toc[z+1].toc.absolute_pos[0];
                   1683:        mbx.cmd.data.play.end_msf[1] = sc->toc[z+1].toc.absolute_pos[1];
                   1684:        mbx.cmd.data.play.end_msf[2] = sc->toc[z+1].toc.absolute_pos[2];
                   1685:        sc->lastpb = mbx.cmd;
                   1686:        mbx.res.length = 0;
                   1687:        return mcd_send(sc, &mbx, 1);
                   1688: }
                   1689:
                   1690: int
                   1691: mcd_playmsf(sc, p)
                   1692:        struct mcd_softc *sc;
                   1693:        struct ioc_play_msf *p;
                   1694: {
                   1695:        struct mcd_mbox mbx;
                   1696:        int error;
                   1697:
                   1698:        if (sc->debug)
                   1699:                printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n",
                   1700:                    sc->sc_dev.dv_xname,
                   1701:                    p->start_m, p->start_s, p->start_f,
                   1702:                    p->end_m, p->end_s, p->end_f);
                   1703:
                   1704:        if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
                   1705:            (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f))
                   1706:                return EINVAL;
                   1707:
                   1708:        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1709:                return error;
                   1710:
                   1711:        mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
                   1712:        mbx.cmd.length = sizeof(mbx.cmd.data.play);
                   1713:        mbx.cmd.data.play.start_msf[0] = bin2bcd(p->start_m);
                   1714:        mbx.cmd.data.play.start_msf[1] = bin2bcd(p->start_s);
                   1715:        mbx.cmd.data.play.start_msf[2] = bin2bcd(p->start_f);
                   1716:        mbx.cmd.data.play.end_msf[0] = bin2bcd(p->end_m);
                   1717:        mbx.cmd.data.play.end_msf[1] = bin2bcd(p->end_s);
                   1718:        mbx.cmd.data.play.end_msf[2] = bin2bcd(p->end_f);
                   1719:        sc->lastpb = mbx.cmd;
                   1720:        mbx.res.length = 0;
                   1721:        return mcd_send(sc, &mbx, 1);
                   1722: }
                   1723:
                   1724: int
                   1725: mcd_playblocks(sc, p)
                   1726:        struct mcd_softc *sc;
                   1727:        struct ioc_play_blocks *p;
                   1728: {
                   1729:        struct mcd_mbox mbx;
                   1730:        int error;
                   1731:
                   1732:        if (sc->debug)
                   1733:                printf("%s: playblocks: blkno %d length %d\n",
                   1734:                    sc->sc_dev.dv_xname, p->blk, p->len);
                   1735:
                   1736:        if (p->blk > sc->disksize || p->len > sc->disksize ||
                   1737:            (p->blk + p->len) > sc->disksize)
                   1738:                return 0;
                   1739:
                   1740:        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1741:                return error;
                   1742:
                   1743:        mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
                   1744:        mbx.cmd.length = sizeof(mbx.cmd.data.play);
                   1745:        hsg2msf(p->blk, mbx.cmd.data.play.start_msf);
                   1746:        hsg2msf(p->blk + p->len, mbx.cmd.data.play.end_msf);
                   1747:        sc->lastpb = mbx.cmd;
                   1748:        mbx.res.length = 0;
                   1749:        return mcd_send(sc, &mbx, 1);
                   1750: }
                   1751:
                   1752: int
                   1753: mcd_pause(sc)
                   1754:        struct mcd_softc *sc;
                   1755: {
                   1756:        union mcd_qchninfo q;
                   1757:        int error;
                   1758:
                   1759:        /* Verify current status. */
                   1760:        if (sc->audio_status != CD_AS_PLAY_IN_PROGRESS) {
                   1761:                printf("%s: pause: attempted when not playing\n",
                   1762:                    sc->sc_dev.dv_xname);
                   1763:                return EINVAL;
                   1764:        }
                   1765:
                   1766:        /* Get the current position. */
                   1767:        if ((error = mcd_getqchan(sc, &q, CD_CURRENT_POSITION)) != 0)
                   1768:                return error;
                   1769:
                   1770:        /* Copy it into lastpb. */
                   1771:        sc->lastpb.data.seek.start_msf[0] = q.current.absolute_pos[0];
                   1772:        sc->lastpb.data.seek.start_msf[1] = q.current.absolute_pos[1];
                   1773:        sc->lastpb.data.seek.start_msf[2] = q.current.absolute_pos[2];
                   1774:
                   1775:        /* Stop playing. */
                   1776:        if ((error = mcd_stop(sc)) != 0)
                   1777:                return error;
                   1778:
                   1779:        /* Set the proper status and exit. */
                   1780:        sc->audio_status = CD_AS_PLAY_PAUSED;
                   1781:        return 0;
                   1782: }
                   1783:
                   1784: int
                   1785: mcd_resume(sc)
                   1786:        struct mcd_softc *sc;
                   1787: {
                   1788:        struct mcd_mbox mbx;
                   1789:        int error;
                   1790:
                   1791:        if (sc->audio_status != CD_AS_PLAY_PAUSED)
                   1792:                return EINVAL;
                   1793:
                   1794:        if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
                   1795:                return error;
                   1796:
                   1797:        mbx.cmd = sc->lastpb;
                   1798:        mbx.res.length = 0;
                   1799:        return mcd_send(sc, &mbx, 1);
                   1800: }
                   1801:
                   1802: int
                   1803: mcd_eject(sc)
                   1804:        struct mcd_softc *sc;
                   1805: {
                   1806:        struct mcd_mbox mbx;
                   1807:
                   1808:        mbx.cmd.opcode = MCD_CMDEJECTDISK;
                   1809:        mbx.cmd.length = 0;
                   1810:        mbx.res.length = 0;
                   1811:        return mcd_send(sc, &mbx, 0);
                   1812: }
                   1813:
                   1814: int
                   1815: mcd_setlock(sc, mode)
                   1816:        struct mcd_softc *sc;
                   1817:        int mode;
                   1818: {
                   1819:        struct mcd_mbox mbx;
                   1820:
                   1821:        mbx.cmd.opcode = MCD_CMDSETLOCK;
                   1822:        mbx.cmd.length = sizeof(mbx.cmd.data.lockmode);
                   1823:        mbx.cmd.data.lockmode.mode = mode;
                   1824:        mbx.res.length = 0;
                   1825:        return mcd_send(sc, &mbx, 1);
                   1826: }

CVSweb