[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     ! 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