root/dev/isa/mcd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mcdattach
  2. mcdlock
  3. mcdunlock
  4. mcdopen
  5. mcdclose
  6. mcdstrategy
  7. mcdstart
  8. mcdread
  9. mcdwrite
  10. mcdioctl
  11. mcdgetdisklabel
  12. mcd_get_parms
  13. mcdsize
  14. mcddump
  15. mcd_find
  16. mcdprobe
  17. mcd_getreply
  18. mcd_getstat
  19. mcd_getresult
  20. mcd_setflags
  21. mcd_send
  22. hsg2msf
  23. msf2hsg
  24. mcd_pseudointr
  25. mcdintr
  26. mcd_soft_reset
  27. mcd_hard_reset
  28. mcd_setmode
  29. mcd_setupc
  30. mcd_toc_header
  31. mcd_read_toc
  32. mcd_toc_entries
  33. mcd_stop
  34. mcd_getqchan
  35. mcd_read_subchannel
  36. mcd_playtracks
  37. mcd_playmsf
  38. mcd_playblocks
  39. mcd_pause
  40. mcd_resume
  41. mcd_eject
  42. mcd_setlock

    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 }

/* [<][>][^][v][top][bottom][index][help] */