The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/mcd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1e855f5db402e39e0d7e1a1c677e3032


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.