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/mcd/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 /*
    2  * Copyright 1993 by Holger Veit (data part)
    3  * Copyright 1993 by Brian Moore (audio part)
    4  * Changes Copyright 1993 by Gary Clark II
    5  * Changes Copyright (C) 1994-1995 by Andrey A. Chernov, Moscow, Russia
    6  *
    7  * Rewrote probe routine to work on newer Mitsumi drives.
    8  * Additional changes (C) 1994 by Jordan K. Hubbard
    9  *
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This software was developed by Holger Veit and Brian Moore
   23  *      for use with "386BSD" and similar operating systems.
   24  *    "Similar operating systems" includes mainly non-profit oriented
   25  *    systems for research and education, including but not restricted to
   26  *    "NetBSD", "FreeBSD", "Mach" (by CMU).
   27  * 4. Neither the name of the developer(s) nor the name "386BSD"
   28  *    may be used to endorse or promote products derived from this
   29  *    software without specific prior written permission.
   30  *
   31  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
   32  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   34  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER(S) BE
   35  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   36  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
   37  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   38  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   39  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   40  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   42  *
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __FBSDID("$FreeBSD: releng/5.3/sys/dev/mcd/mcd.c 130585 2004-06-16 09:47:26Z phk $");
   47 static const char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/conf.h>
   53 #include <sys/fcntl.h>
   54 #include <sys/bio.h>
   55 #include <sys/cdio.h>
   56 #include <sys/disk.h>
   57 #include <sys/bus.h>
   58 
   59 #include <machine/bus_pio.h>
   60 #include <machine/bus.h>
   61 #include <machine/resource.h>
   62 #include <sys/rman.h>
   63 
   64 #include <isa/isavar.h>
   65   
   66 #include <dev/mcd/mcdreg.h>
   67 #include <dev/mcd/mcdvar.h>
   68 
   69 #define MCD_TRACE(format, args...)                                      \
   70 {                                                                       \
   71         if (sc->debug) {                                                \
   72                 device_printf(sc->dev, "status=0x%02x: ",               \
   73                         sc->data.status);                               \
   74                 printf(format, ## args);                                \
   75         }                                                               \
   76 }
   77 
   78 #define RAW_PART        2
   79 
   80 /* flags */
   81 #define MCDVALID        0x0001  /* parameters loaded */
   82 #define MCDINIT         0x0002  /* device is init'd */
   83 #define MCDNEWMODEL     0x0004  /* device is new model */
   84 #define MCDLABEL        0x0008  /* label is read */
   85 #define MCDPROBING      0x0010  /* probing */
   86 #define MCDREADRAW      0x0020  /* read raw mode (2352 bytes) */
   87 #define MCDVOLINFO      0x0040  /* already read volinfo */
   88 #define MCDTOC          0x0080  /* already read toc */
   89 #define MCDMBXBSY       0x0100  /* local mbx is busy */
   90 
   91 /* status */
   92 #define MCDAUDIOBSY     MCD_ST_AUDIOBSY         /* playing audio */
   93 #define MCDDSKCHNG      MCD_ST_DSKCHNG          /* sensed change of disk */
   94 #define MCDDSKIN        MCD_ST_DSKIN            /* sensed disk in drive */
   95 #define MCDDOOROPEN     MCD_ST_DOOROPEN         /* sensed door open */
   96 
   97 /* These are apparently the different states a mitsumi can get up to */
   98 #define MCDCDABSENT     0x0030
   99 #define MCDCDPRESENT    0x0020
  100 #define MCDSCLOSED      0x0080
  101 #define MCDSOPEN        0x00a0
  102 
  103 #define MCD_MD_UNKNOWN  (-1)
  104 
  105 #define MCD_TYPE_UNKNOWN        0
  106 #define MCD_TYPE_LU002S         1
  107 #define MCD_TYPE_LU005S         2
  108 #define MCD_TYPE_LU006S         3
  109 #define MCD_TYPE_FX001          4
  110 #define MCD_TYPE_FX001D         5
  111 
  112 /* reader state machine */
  113 #define MCD_S_BEGIN     0
  114 #define MCD_S_BEGIN1    1
  115 #define MCD_S_WAITSTAT  2
  116 #define MCD_S_WAITMODE  3
  117 #define MCD_S_WAITREAD  4
  118 
  119 /* prototypes */
  120 static void     mcd_start(struct mcd_softc *);
  121 #ifdef NOTYET
  122 static void     mcd_configure(struct mcd_softc *sc);
  123 #endif
  124 static int      mcd_get(struct mcd_softc *, char *buf, int nmax);
  125 static int      mcd_setflags(struct mcd_softc *);
  126 static int      mcd_getstat(struct mcd_softc *,int sflg);
  127 static int      mcd_send(struct mcd_softc *, int cmd,int nretrys);
  128 static void     hsg2msf(int hsg, bcd_t *msf);
  129 static int      msf2hsg(bcd_t *msf, int relative);
  130 static int      mcd_volinfo(struct mcd_softc *);
  131 static int      mcd_waitrdy(struct mcd_softc *,int dly);
  132 static timeout_t mcd_timeout;
  133 static void     mcd_doread(struct mcd_softc *, int state, struct mcd_mbx *mbxin);
  134 static void     mcd_soft_reset(struct mcd_softc *);
  135 static int      mcd_hard_reset(struct mcd_softc *);
  136 static int      mcd_setmode(struct mcd_softc *, int mode);
  137 static int      mcd_getqchan(struct mcd_softc *, struct mcd_qchninfo *q);
  138 static int      mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc);
  139 static int      mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *th);
  140 static int      mcd_read_toc(struct mcd_softc *);
  141 static int      mcd_toc_entrys(struct mcd_softc *, struct ioc_read_toc_entry *te);
  142 #if 0
  143 static int      mcd_toc_entry(struct mcd_softc *, struct ioc_read_toc_single_entry *te);
  144 #endif
  145 static int      mcd_stop(struct mcd_softc *);
  146 static int      mcd_eject(struct mcd_softc *);
  147 static int      mcd_inject(struct mcd_softc *);
  148 static int      mcd_playtracks(struct mcd_softc *, struct ioc_play_track *pt);
  149 static int      mcd_play(struct mcd_softc *, struct mcd_read2 *pb);
  150 static int      mcd_playmsf(struct mcd_softc *, struct ioc_play_msf *pt);
  151 static int      mcd_playblocks(struct mcd_softc *, struct ioc_play_blocks *);
  152 static int      mcd_pause(struct mcd_softc *);
  153 static int      mcd_resume(struct mcd_softc *);
  154 static int      mcd_lock_door(struct mcd_softc *, int lock);
  155 static int      mcd_close_tray(struct mcd_softc *);
  156 static int      mcd_size(struct cdev *dev);
  157 
  158 static d_open_t         mcdopen;
  159 static d_close_t        mcdclose;
  160 static d_ioctl_t        mcdioctl;
  161 static d_strategy_t     mcdstrategy;
  162 
  163 static struct cdevsw mcd_cdevsw = {
  164         .d_version =    D_VERSION,
  165         .d_open =       mcdopen,
  166         .d_close =      mcdclose,
  167         .d_read =       physread,
  168         .d_ioctl =      mcdioctl,
  169         .d_strategy =   mcdstrategy,
  170         .d_name =       "mcd",
  171         .d_flags =      D_DISK | D_NEEDGIANT,
  172 };
  173 
  174 #define MCD_RETRYS      5
  175 #define MCD_RDRETRYS    8
  176 
  177 #define CLOSE_TRAY_SECS 8
  178 #define DISK_SENSE_SECS 3
  179 #define WAIT_FRAC 4
  180 
  181 /* several delays */
  182 #define RDELAY_WAITSTAT 300
  183 #define RDELAY_WAITMODE 300
  184 #define RDELAY_WAITREAD 800
  185 
  186 #define MIN_DELAY       15
  187 #define DELAY_GETREPLY  5000000
  188 
  189 int
  190 mcd_attach(struct mcd_softc *sc)
  191 {
  192         int unit;
  193 
  194         unit = device_get_unit(sc->dev);
  195 
  196         sc->data.flags |= MCDINIT;
  197         mcd_soft_reset(sc);
  198         bioq_init(&sc->data.head);
  199 
  200 #ifdef NOTYET
  201         /* wire controller for interrupts and dma */
  202         mcd_configure(sc);
  203 #endif
  204         /* name filled in probe */
  205         sc->mcd_dev_t = make_dev(&mcd_cdevsw, 8 * unit,
  206                                  UID_ROOT, GID_OPERATOR, 0640, "mcd%d", unit);
  207 
  208         sc->mcd_dev_t->si_drv1 = (void *)sc;
  209 
  210         return (0);
  211 }
  212 
  213 static int
  214 mcdopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  215 {
  216         struct mcd_softc *sc;
  217         int r,retry;
  218 
  219         sc = (struct mcd_softc *)dev->si_drv1;
  220 
  221         /* not initialized*/
  222         if (!(sc->data.flags & MCDINIT))
  223                 return (ENXIO);
  224 
  225         /* invalidated in the meantime? mark all open part's invalid */
  226         if (!(sc->data.flags & MCDVALID) && sc->data.openflags)
  227                 return (ENXIO);
  228 
  229         if (mcd_getstat(sc, 1) == -1)
  230                 return (EIO);
  231 
  232         if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
  233             || !(sc->data.status & MCDDSKIN))
  234                 for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
  235                         (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn1", hz/WAIT_FRAC);
  236                         if ((r = mcd_getstat(sc, 1)) == -1)
  237                                 return (EIO);
  238                         if (r != -2)
  239                                 break;
  240                 }
  241 
  242         if (sc->data.status & MCDDOOROPEN) {
  243                 device_printf(sc->dev, "door is open\n");
  244                 return (ENXIO);
  245         }
  246         if (!(sc->data.status & MCDDSKIN)) {
  247                 device_printf(sc->dev, "no CD inside\n");
  248                 return (ENXIO);
  249         }
  250         if (sc->data.status & MCDDSKCHNG) {
  251                 device_printf(sc->dev, "CD not sensed\n");
  252                 return (ENXIO);
  253         }
  254 
  255         if (mcd_size(dev) < 0) {
  256                 device_printf(sc->dev, "failed to get disk size\n");
  257                 return (ENXIO);
  258         }
  259 
  260         dev->si_bsize_phys = sc->data.blksize;
  261 
  262         sc->data.openflags = 1;
  263         sc->data.partflags |= MCDREADRAW;
  264         sc->data.flags |= MCDVALID;
  265 
  266         (void) mcd_lock_door(sc, MCD_LK_LOCK);
  267         if (!(sc->data.flags & MCDVALID))
  268                 return (ENXIO);
  269 
  270         return mcd_read_toc(sc);
  271 }
  272 
  273 static int
  274 mcdclose(struct cdev *dev, int flags, int fmt, struct thread *td)
  275 {
  276         struct mcd_softc *sc;
  277 
  278         sc = (struct mcd_softc *)dev->si_drv1;
  279 
  280         if (!(sc->data.flags & MCDINIT) || !sc->data.openflags)
  281                 return (ENXIO);
  282 
  283         (void) mcd_lock_door(sc, MCD_LK_UNLOCK);
  284         sc->data.openflags = 0;
  285         sc->data.partflags &= ~MCDREADRAW;
  286 
  287         return (0);
  288 }
  289 
  290 static void
  291 mcdstrategy(struct bio *bp)
  292 {
  293         struct mcd_softc *sc;
  294         int s;
  295 
  296         sc = (struct mcd_softc *)bp->bio_dev->si_drv1;
  297 
  298         /* if device invalidated (e.g. media change, door open), error */
  299         if (!(sc->data.flags & MCDVALID)) {
  300                 device_printf(sc->dev, "media changed\n");
  301                 bp->bio_error = EIO;
  302                 goto bad;
  303         }
  304 
  305         /* read only */
  306         if (!(bp->bio_cmd == BIO_READ)) {
  307                 bp->bio_error = EROFS;
  308                 goto bad;
  309         }
  310 
  311         /* no data to read */
  312         if (bp->bio_bcount == 0)
  313                 goto done;
  314 
  315         if (!(sc->data.flags & MCDTOC)) {
  316                 bp->bio_error = EIO;
  317                 goto bad;
  318         }
  319 
  320         bp->bio_resid = 0;
  321 
  322         /* queue it */
  323         s = splbio();
  324         bioq_disksort(&sc->data.head, bp);
  325         splx(s);
  326 
  327         /* now check whether we can perform processing */
  328         mcd_start(sc);
  329         return;
  330 
  331 bad:
  332         bp->bio_flags |= BIO_ERROR;
  333 done:
  334         bp->bio_resid = bp->bio_bcount;
  335         biodone(bp);
  336         return;
  337 }
  338 
  339 static void
  340 mcd_start(struct mcd_softc *sc)
  341 {
  342         struct bio *bp;
  343         int s = splbio();
  344 
  345         if (sc->data.flags & MCDMBXBSY) {
  346                 splx(s);
  347                 return;
  348         }
  349 
  350         bp = bioq_first(&sc->data.head);
  351         if (bp != 0) {
  352                 /* block found to process, dequeue */
  353                 /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/
  354                 bioq_remove(&sc->data.head, bp);
  355                 sc->data.flags |= MCDMBXBSY;
  356                 splx(s);
  357         } else {
  358                 /* nothing to do */
  359                 splx(s);
  360                 return;
  361         }
  362 
  363         sc->data.mbx.retry = MCD_RETRYS;
  364         sc->data.mbx.bp = bp;
  365 
  366         mcd_doread(sc, MCD_S_BEGIN,&(sc->data.mbx));
  367         return;
  368 }
  369 
  370 static int
  371 mcdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
  372 {
  373         struct mcd_softc *sc;
  374         int retry,r;
  375 
  376         sc = (struct mcd_softc *)dev->si_drv1;
  377 
  378         if (mcd_getstat(sc, 1) == -1) /* detect disk change too */
  379                 return (EIO);
  380 MCD_TRACE("ioctl called 0x%lx\n", cmd);
  381 
  382         switch (cmd) {
  383         case CDIOCSETPATCH:
  384         case CDIOCGETVOL:
  385         case CDIOCSETVOL:
  386         case CDIOCSETMONO:
  387         case CDIOCSETSTERIO:
  388         case CDIOCSETMUTE:
  389         case CDIOCSETLEFT:
  390         case CDIOCSETRIGHT:
  391                 return (EINVAL);
  392         case CDIOCEJECT:
  393                 return mcd_eject(sc);
  394         case CDIOCSETDEBUG:
  395                 sc->data.debug = 1;
  396                 return (0);
  397         case CDIOCCLRDEBUG:
  398                 sc->data.debug = 0;
  399                 return (0);
  400         case CDIOCRESET:
  401                 return mcd_hard_reset(sc);
  402         case CDIOCALLOW:
  403                 return mcd_lock_door(sc, MCD_LK_UNLOCK);
  404         case CDIOCPREVENT:
  405                 return mcd_lock_door(sc, MCD_LK_LOCK);
  406         case CDIOCCLOSE:
  407                 return mcd_inject(sc);
  408         }
  409 
  410         if (!(sc->data.flags & MCDVALID)) {
  411                 if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
  412                     || !(sc->data.status & MCDDSKIN))
  413                         for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
  414                                 (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC);
  415                                 if ((r = mcd_getstat(sc, 1)) == -1)
  416                                         return (EIO);
  417                                 if (r != -2)
  418                                         break;
  419                         }
  420                 if (   (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG))
  421                     || !(sc->data.status & MCDDSKIN)
  422                     || mcd_size(dev) < 0
  423                    )
  424                         return (ENXIO);
  425                 sc->data.flags |= MCDVALID;
  426                 sc->data.partflags |= MCDREADRAW;
  427                 (void) mcd_lock_door(sc, MCD_LK_LOCK);
  428                 if (!(sc->data.flags & MCDVALID))
  429                         return (ENXIO);
  430         }
  431 
  432         switch (cmd) {
  433         case DIOCGMEDIASIZE:
  434                 *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize;
  435                 return (0);
  436         case DIOCGSECTORSIZE:
  437                 *(u_int *)addr = sc->data.blksize;
  438                 return (0);
  439 
  440         case CDIOCPLAYTRACKS:
  441                 return mcd_playtracks(sc, (struct ioc_play_track *) addr);
  442         case CDIOCPLAYBLOCKS:
  443                 return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
  444         case CDIOCPLAYMSF:
  445                 return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
  446         case CDIOCREADSUBCHANNEL:
  447                 return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
  448         case CDIOREADTOCHEADER:
  449                 return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
  450         case CDIOREADTOCENTRYS:
  451                 return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr);
  452         case CDIOCRESUME:
  453                 return mcd_resume(sc);
  454         case CDIOCPAUSE:
  455                 return mcd_pause(sc);
  456         case CDIOCSTART:
  457                 if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
  458                         return (EIO);
  459                 return (0);
  460         case CDIOCSTOP:
  461                 return mcd_stop(sc);
  462         default:
  463                 return (ENOTTY);
  464         }
  465         /*NOTREACHED*/
  466 }
  467 
  468 static int
  469 mcd_size(struct cdev *dev)
  470 {
  471         struct mcd_softc *sc;
  472         int size;
  473 
  474         sc = (struct mcd_softc *)dev->si_drv1;
  475 
  476         if (mcd_volinfo(sc) == 0) {
  477                 sc->data.blksize = MCDBLK;
  478                 size = msf2hsg(sc->data.volinfo.vol_msf, 0);
  479                 sc->data.disksize = size * (MCDBLK/DEV_BSIZE);
  480                 return (0);
  481         }
  482         return (-1);
  483 }
  484 
  485 /***************************************************************
  486  * lower level of driver starts here
  487  **************************************************************/
  488 
  489 #ifdef NOTDEF
  490 static char
  491 irqs[] = {
  492         0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00,
  493         0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00
  494 };
  495 
  496 static char
  497 drqs[] = {
  498         0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07,
  499 };
  500 #endif
  501 
  502 #ifdef NOT_YET
  503 static void
  504 mcd_configure(struct mcd_softc *sc)
  505 {
  506         MCD_WRITE(sc, MCD_REG_CONFIG, sc->data.config);
  507 }
  508 #endif
  509 
  510 /* Wait for non-busy - return 0 on timeout */
  511 static int
  512 twiddle_thumbs(struct mcd_softc *sc, int count, char *whine)
  513 {
  514         int i;
  515 
  516         for (i = 0; i < count; i++) {
  517                 if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL))
  518                         return (1);
  519                 }
  520         if (bootverbose)
  521                 device_printf(sc->dev, "timeout %s\n", whine);
  522         return (0);
  523 }
  524 
  525 /* check to see if a Mitsumi CD-ROM is attached to the ISA bus */
  526 
  527 int
  528 mcd_probe(struct mcd_softc *sc)
  529 {
  530         int i, j;
  531         unsigned char stbytes[3];
  532 
  533         sc->data.flags = MCDPROBING;
  534 
  535 #ifdef NOTDEF
  536         /* get irq/drq configuration word */
  537         sc->data.config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/
  538 #else
  539         sc->data.config = 0;
  540 #endif
  541 
  542         /* send a reset */
  543         MCD_WRITE(sc, MCD_FLAGS, M_RESET);
  544 
  545         /*
  546          * delay awhile by getting any pending garbage (old data) and
  547          * throwing it away.
  548          */
  549         for (i = 1000000; i != 0; i--)
  550                 (void)MCD_READ(sc, MCD_FLAGS);
  551 
  552         /* Get status */
  553         MCD_WRITE(sc, MCD_DATA, MCD_CMDGETSTAT);
  554         if (!twiddle_thumbs(sc, 1000000, "getting status"))
  555                 return (ENXIO); /* Timeout */
  556         /* Get version information */
  557         MCD_WRITE(sc, MCD_DATA, MCD_CMDCONTINFO);
  558         for (j = 0; j < 3; j++) {
  559                 if (!twiddle_thumbs(sc, 3000, "getting version info"))
  560                         return (ENXIO);
  561                 stbytes[j] = (MCD_READ(sc, MCD_DATA) & 0xFF);
  562         }
  563         if (stbytes[1] == stbytes[2])
  564                 return (ENXIO);
  565         if (stbytes[2] >= 4 || stbytes[1] != 'M') {
  566                 MCD_WRITE(sc, MCD_CTRL, M_PICKLE);
  567                 sc->data.flags |= MCDNEWMODEL;
  568         }
  569         sc->data.read_command = MCD_CMDSINGLESPEEDREAD;
  570         switch (stbytes[1]) {
  571         case 'M':
  572                 if (stbytes[2] <= 2) {
  573                         sc->data.type = MCD_TYPE_LU002S;
  574                         sc->data.name = "Mitsumi LU002S";
  575                 } else if (stbytes[2] <= 5) {
  576                         sc->data.type = MCD_TYPE_LU005S;
  577                         sc->data.name = "Mitsumi LU005S";
  578                 } else {
  579                         sc->data.type = MCD_TYPE_LU006S;
  580                         sc->data.name = "Mitsumi LU006S";
  581                 }
  582                 break;
  583         case 'F':
  584                 sc->data.type = MCD_TYPE_FX001;
  585                 sc->data.name = "Mitsumi FX001";
  586                 break;
  587         case 'D':
  588                 sc->data.type = MCD_TYPE_FX001D;
  589                 sc->data.name = "Mitsumi FX001D";
  590                 sc->data.read_command = MCD_CMDDOUBLESPEEDREAD;
  591                 break;
  592         default:
  593                 sc->data.type = MCD_TYPE_UNKNOWN;
  594                 sc->data.name = "Mitsumi ???";
  595                 break;
  596         }
  597 
  598         if (bootverbose)
  599                 device_printf(sc->dev, "type %s, version info: %c %x\n",
  600                         sc->data.name, stbytes[1], stbytes[2]);
  601 
  602         return (0);
  603 }
  604 
  605 
  606 static int
  607 mcd_waitrdy(struct mcd_softc *sc, int dly)
  608 {
  609         int i;
  610 
  611         /* wait until flag port senses status ready */
  612         for (i=0; i<dly; i+=MIN_DELAY) {
  613                 if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL))
  614                         return (0);
  615                 DELAY(MIN_DELAY);
  616         }
  617         return (-1);
  618 }
  619 
  620 static int
  621 mcd_getreply(struct mcd_softc *sc, int dly)
  622 {
  623 
  624         /* wait data to become ready */
  625         if (mcd_waitrdy(sc, dly)<0) {
  626                 device_printf(sc->dev, "timeout getreply\n");
  627                 return (-1);
  628         }
  629 
  630         /* get the data */
  631         return (MCD_READ(sc, MCD_REG_STATUS) & 0xFF);
  632 }
  633 
  634 static int
  635 mcd_getstat(struct mcd_softc *sc, int sflg)
  636 {
  637         int     i;
  638 
  639         /* get the status */
  640         if (sflg)
  641                 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT);
  642         i = mcd_getreply(sc, DELAY_GETREPLY);
  643         if (i<0 || (i & MCD_ST_CMDCHECK)) {
  644                 sc->data.curr_mode = MCD_MD_UNKNOWN;
  645                 return (-1);
  646         }
  647 
  648         sc->data.status = i;
  649 
  650         if (mcd_setflags(sc) < 0)
  651                 return (-2);
  652         return (sc->data.status);
  653 }
  654 
  655 static int
  656 mcd_setflags(struct mcd_softc *sc)
  657 {
  658 
  659         /* check flags */
  660         if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
  661             || !(sc->data.status & MCDDSKIN)) {
  662                 MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n");
  663                 mcd_soft_reset(sc);
  664                 return (-1);
  665         }
  666 
  667         if (sc->data.status & MCDAUDIOBSY)
  668                 sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS;
  669         else if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS)
  670                 sc->data.audio_status = CD_AS_PLAY_COMPLETED;
  671         return (0);
  672 }
  673 
  674 static int
  675 mcd_get(struct mcd_softc *sc, char *buf, int nmax)
  676 {
  677         int i,k;
  678 
  679         for (i=0; i<nmax; i++) {
  680                 /* wait for data */
  681                 if ((k = mcd_getreply(sc, DELAY_GETREPLY)) < 0) {
  682                         device_printf(sc->dev, "timeout mcd_get\n");
  683                         return (-1);
  684                 }
  685                 buf[i] = k;
  686         }
  687         return (i);
  688 }
  689 
  690 static int
  691 mcd_send(struct mcd_softc *sc, int cmd,int nretrys)
  692 {
  693         int i,k=0;
  694 
  695 /*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/
  696         for (i=0; i<nretrys; i++) {
  697                 MCD_WRITE(sc, MCD_REG_COMMAND, cmd);
  698                 if ((k=mcd_getstat(sc, 0)) != -1)
  699                         break;
  700         }
  701         if (k == -2) {
  702                 device_printf(sc->dev, "media changed\n");
  703                 return (-1);
  704         }
  705         if (i == nretrys) {
  706                 device_printf(sc->dev, "mcd_send retry cnt exceeded\n");
  707                 return (-1);
  708         }
  709 /*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/
  710         return (0);
  711 }
  712 
  713 static void
  714 hsg2msf(int hsg, bcd_t *msf)
  715 {
  716         hsg += 150;
  717         F_msf(msf) = bin2bcd(hsg % 75);
  718         hsg /= 75;
  719         S_msf(msf) = bin2bcd(hsg % 60);
  720         hsg /= 60;
  721         M_msf(msf) = bin2bcd(hsg);
  722 }
  723 
  724 static int
  725 msf2hsg(bcd_t *msf, int relative)
  726 {
  727         return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 +
  728                 bcd2bin(F_msf(msf)) - (!relative) * 150;
  729 }
  730 
  731 static int
  732 mcd_volinfo(struct mcd_softc *sc)
  733 {
  734 
  735         /* Just return if we already have it */
  736         if (sc->data.flags & MCDVOLINFO) return (0);
  737 
  738 /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
  739 
  740         /* send volume info command */
  741         if (mcd_send(sc, MCD_CMDGETVOLINFO,MCD_RETRYS) < 0)
  742                 return (EIO);
  743 
  744         /* get data */
  745         if (mcd_get(sc, (char*) &sc->data.volinfo,sizeof(struct mcd_volinfo)) < 0) {
  746                 device_printf(sc->dev, "mcd_volinfo: error read data\n");
  747                 return (EIO);
  748         }
  749 
  750         if (sc->data.volinfo.trk_low > 0 &&
  751             sc->data.volinfo.trk_high >= sc->data.volinfo.trk_low
  752            ) {
  753                 sc->data.flags |= MCDVOLINFO;   /* volinfo is OK */
  754                 return (0);
  755         }
  756 
  757         return (EINVAL);
  758 }
  759 
  760 /* state machine to process read requests
  761  * initialize with MCD_S_BEGIN: calculate sizes, and read status
  762  * MCD_S_WAITSTAT: wait for status reply, set mode
  763  * MCD_S_WAITMODE: waits for status reply from set mode, set read command
  764  * MCD_S_WAITREAD: wait for read ready, read data
  765  */
  766 static void
  767 mcd_timeout(void *arg)
  768 {
  769         struct mcd_softc *sc;
  770 
  771         sc = (struct mcd_softc *)arg;
  772 
  773         mcd_doread(sc, sc->ch_state, sc->ch_mbxsave);
  774 }
  775 
  776 static void
  777 mcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin)
  778 {
  779         struct mcd_mbx *mbx;
  780         struct bio *bp;
  781         int rm, i, k;
  782         struct mcd_read2 rbuf;
  783         int blknum;
  784         caddr_t addr;
  785 
  786         mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin;
  787         bp = mbx->bp;
  788 
  789 loop:
  790         switch (state) {
  791         case MCD_S_BEGIN:
  792                 mbx = sc->ch_mbxsave = mbxin;
  793 
  794         case MCD_S_BEGIN1:
  795 retry_status:
  796                 /* get status */
  797                 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT);
  798                 mbx->count = RDELAY_WAITSTAT;
  799                 sc->ch_state = MCD_S_WAITSTAT;
  800                 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
  801                 return;
  802         case MCD_S_WAITSTAT:
  803                 sc->ch_state = MCD_S_WAITSTAT;
  804                 untimeout(mcd_timeout,(caddr_t)sc, sc->ch);
  805                 if (mbx->count-- >= 0) {
  806                         if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
  807                                 sc->ch_state = MCD_S_WAITSTAT;
  808                                 timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
  809                                 return;
  810                         }
  811                         sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
  812                         if (sc->data.status & MCD_ST_CMDCHECK)
  813                                 goto retry_status;
  814                         if (mcd_setflags(sc) < 0)
  815                                 goto changed;
  816                         MCD_TRACE("got WAITSTAT delay=%d\n",
  817                                 RDELAY_WAITSTAT-mbx->count);
  818                         /* reject, if audio active */
  819                         if (sc->data.status & MCDAUDIOBSY) {
  820                                 device_printf(sc->dev, "audio is active\n");
  821                                 goto readerr;
  822                         }
  823 
  824 retry_mode:
  825                         /* to check for raw/cooked mode */
  826                         if (sc->data.flags & MCDREADRAW) {
  827                                 rm = MCD_MD_RAW;
  828                                 mbx->sz = MCDRBLK;
  829                         } else {
  830                                 rm = MCD_MD_COOKED;
  831                                 mbx->sz = sc->data.blksize;
  832                         }
  833 
  834                         if (rm == sc->data.curr_mode)
  835                                 goto modedone;
  836 
  837                         mbx->count = RDELAY_WAITMODE;
  838 
  839                         sc->data.curr_mode = MCD_MD_UNKNOWN;
  840                         mbx->mode = rm;
  841                         MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE);
  842                         MCD_WRITE(sc, MCD_REG_COMMAND, rm);
  843 
  844                         sc->ch_state = MCD_S_WAITMODE;
  845                         sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
  846                         return;
  847                 } else {
  848                         device_printf(sc->dev, "timeout getstatus\n");
  849                         goto readerr;
  850                 }
  851 
  852         case MCD_S_WAITMODE:
  853                 sc->ch_state = MCD_S_WAITMODE;
  854                 untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
  855                 if (mbx->count-- < 0) {
  856                         device_printf(sc->dev, "timeout set mode\n");
  857                         goto readerr;
  858                 }
  859                 if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
  860                         sc->ch_state = MCD_S_WAITMODE;
  861                         sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100);
  862                         return;
  863                 }
  864                 sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
  865                 if (sc->data.status & MCD_ST_CMDCHECK) {
  866                         sc->data.curr_mode = MCD_MD_UNKNOWN;
  867                         goto retry_mode;
  868                 }
  869                 if (mcd_setflags(sc) < 0)
  870                         goto changed;
  871                 sc->data.curr_mode = mbx->mode;
  872                 MCD_TRACE("got WAITMODE delay=%d\n",
  873                         RDELAY_WAITMODE-mbx->count);
  874 modedone:
  875                 /* for first block */
  876                 mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz;
  877                 mbx->skip = 0;
  878 
  879 nextblock:
  880                 blknum  = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz;
  881 
  882                 MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n",
  883                         blknum, bp);
  884 
  885                 /* build parameter block */
  886                 hsg2msf(blknum,rbuf.start_msf);
  887 retry_read:
  888                 /* send the read command */
  889                 critical_enter();
  890                 MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command);
  891                 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]);
  892                 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]);
  893                 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]);
  894                 MCD_WRITE(sc, MCD_REG_COMMAND, 0);
  895                 MCD_WRITE(sc, MCD_REG_COMMAND, 0);
  896                 MCD_WRITE(sc, MCD_REG_COMMAND, 1);
  897                 critical_exit();
  898 
  899                 /* Spin briefly (<= 2ms) to avoid missing next block */
  900                 for (i = 0; i < 20; i++) {
  901                         k = MCD_READ(sc, MCD_FLAGS);
  902                         if (!(k & MFL_DATA_NOT_AVAIL))
  903                                 goto got_it;
  904                         DELAY(100);
  905                 }
  906 
  907                 mbx->count = RDELAY_WAITREAD;
  908                 sc->ch_state = MCD_S_WAITREAD;
  909                 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
  910                 return;
  911         case MCD_S_WAITREAD:
  912                 sc->ch_state = MCD_S_WAITREAD;
  913                 untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
  914                 if (mbx->count-- > 0) {
  915                         k = MCD_READ(sc, MCD_FLAGS);
  916                         if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */
  917                                 MCD_TRACE("got data delay=%d\n",
  918                                         RDELAY_WAITREAD-mbx->count);
  919                         got_it:
  920                                 /* data is ready */
  921                                 addr    = bp->bio_data + mbx->skip;
  922 
  923                                 MCD_WRITE(sc, MCD_REG_CTL2,0x04);       /* XXX */
  924                                 for (i=0; i<mbx->sz; i++)
  925                                         *addr++ = MCD_READ(sc, MCD_REG_RDATA);
  926                                 MCD_WRITE(sc, MCD_REG_CTL2,0x0c);       /* XXX */
  927 
  928                                 k = MCD_READ(sc, MCD_FLAGS);
  929                                 /* If we still have some junk, read it too */
  930                                 if (!(k & MFL_DATA_NOT_AVAIL)) {
  931                                         MCD_WRITE(sc, MCD_REG_CTL2, 0x04);       /* XXX */
  932                                         (void)MCD_READ(sc, MCD_REG_RDATA);
  933                                         (void)MCD_READ(sc, MCD_REG_RDATA);
  934                                         MCD_WRITE(sc, MCD_REG_CTL2, 0x0c);       /* XXX */
  935                                 }
  936 
  937                                 if (--mbx->nblk > 0) {
  938                                         mbx->skip += mbx->sz;
  939                                         goto nextblock;
  940                                 }
  941 
  942                                 /* return buffer */
  943                                 bp->bio_resid = 0;
  944                                 biodone(bp);
  945 
  946                                 sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
  947                                 mcd_start(sc);
  948                                 return;
  949                         }
  950                         if (!(k & MFL_STATUS_NOT_AVAIL)) {
  951                                 sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
  952                                 if (sc->data.status & MCD_ST_CMDCHECK)
  953                                         goto retry_read;
  954                                 if (mcd_setflags(sc) < 0)
  955                                         goto changed;
  956                         }
  957                         sc->ch_state = MCD_S_WAITREAD;
  958                         sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
  959                         return;
  960                 } else {
  961                         device_printf(sc->dev, "timeout read data\n");
  962                         goto readerr;
  963                 }
  964         }
  965 
  966 readerr:
  967         if (mbx->retry-- > 0) {
  968                 device_printf(sc->dev, "retrying\n");
  969                 state = MCD_S_BEGIN1;
  970                 goto loop;
  971         }
  972 harderr:
  973         /* invalidate the buffer */
  974         bp->bio_flags |= BIO_ERROR;
  975         bp->bio_resid = bp->bio_bcount;
  976         biodone(bp);
  977 
  978         sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
  979         mcd_start(sc);
  980         return;
  981 
  982 changed:
  983         device_printf(sc->dev, "media changed\n");
  984         goto harderr;
  985 
  986 #ifdef NOTDEF
  987         device_printf(sc->dev, "unit timeout, resetting\n");
  988         MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET);
  989         DELAY(300000);
  990         (void)mcd_getstat(sc, 1);
  991         (void)mcd_getstat(sc, 1);
  992         /*sc->data.status &= ~MCDDSKCHNG; */
  993         sc->data.debug = 1; /* preventive set debug mode */
  994 
  995 #endif
  996 
  997 }
  998 
  999 static int
 1000 mcd_lock_door(struct mcd_softc *sc, int lock)
 1001 {
 1002 
 1003         MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDLOCKDRV);
 1004         MCD_WRITE(sc, MCD_REG_COMMAND, lock);
 1005         if (mcd_getstat(sc, 0) == -1)
 1006                 return (EIO);
 1007         return (0);
 1008 }
 1009 
 1010 static int
 1011 mcd_close_tray(struct mcd_softc *sc)
 1012 {
 1013         int retry, r;
 1014 
 1015         if (mcd_getstat(sc, 1) == -1)
 1016                 return (EIO);
 1017         if (sc->data.status & MCDDOOROPEN) {
 1018                 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDCLOSETRAY);
 1019                 for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) {
 1020                         if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)
 1021                                 (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC);
 1022                         else {
 1023                                 if ((r = mcd_getstat(sc, 0)) == -1)
 1024                                         return (EIO);
 1025                                 return (0);
 1026                         }
 1027                 }
 1028                 return (ENXIO);
 1029         }
 1030         return (0);
 1031 }
 1032 
 1033 static int
 1034 mcd_eject(struct mcd_softc *sc)
 1035 {
 1036         int r;
 1037 
 1038         if (mcd_getstat(sc, 1) == -1)    /* detect disk change too */
 1039                 return (EIO);
 1040         if (sc->data.status & MCDDOOROPEN)
 1041                 return (0);
 1042         if ((r = mcd_stop(sc)) == EIO)
 1043                 return (r);
 1044         MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDEJECTDISK);
 1045         if (mcd_getstat(sc, 0) == -1)
 1046                 return (EIO);
 1047         return (0);
 1048 }
 1049 
 1050 static int
 1051 mcd_inject(struct mcd_softc *sc)
 1052 {
 1053 
 1054         if (mcd_getstat(sc, 1) == -1)    /* detect disk change too */
 1055                 return (EIO);
 1056         if (sc->data.status & MCDDOOROPEN)
 1057                 return mcd_close_tray(sc);
 1058         return (0);
 1059 }
 1060 
 1061 static int
 1062 mcd_hard_reset(struct mcd_softc *sc)
 1063 {
 1064 
 1065         MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET);
 1066         sc->data.curr_mode = MCD_MD_UNKNOWN;
 1067         sc->data.audio_status = CD_AS_AUDIO_INVALID;
 1068         return (0);
 1069 }
 1070 
 1071 static void
 1072 mcd_soft_reset(struct mcd_softc *sc)
 1073 {
 1074 
 1075         sc->data.flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL);
 1076         sc->data.curr_mode = MCD_MD_UNKNOWN;
 1077         sc->data.partflags = 0;
 1078         sc->data.audio_status = CD_AS_AUDIO_INVALID;
 1079 }
 1080 
 1081 static int
 1082 mcd_setmode(struct mcd_softc *sc, int mode)
 1083 {
 1084         int retry, st;
 1085 
 1086         if (sc->data.curr_mode == mode)
 1087                 return (0);
 1088         if (sc->data.debug)
 1089                 device_printf(sc->dev, "setting mode to %d\n", mode);
 1090         for(retry=0; retry<MCD_RETRYS; retry++)
 1091         {
 1092                 sc->data.curr_mode = MCD_MD_UNKNOWN;
 1093                 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE);
 1094                 MCD_WRITE(sc, MCD_REG_COMMAND, mode);
 1095                 if ((st = mcd_getstat(sc, 0)) >= 0) {
 1096                         sc->data.curr_mode = mode;
 1097                         return (0);
 1098                 }
 1099                 if (st == -2) {
 1100                         device_printf(sc->dev, "media changed\n");
 1101                         break;
 1102                 }
 1103         }
 1104 
 1105         return (-1);
 1106 }
 1107 
 1108 static int
 1109 mcd_toc_header(struct mcd_softc *sc, struct ioc_toc_header *th)
 1110 {
 1111         int r;
 1112 
 1113         if ((r = mcd_volinfo(sc)) != 0)
 1114                 return (r);
 1115 
 1116         th->starting_track = bcd2bin(sc->data.volinfo.trk_low);
 1117         th->ending_track = bcd2bin(sc->data.volinfo.trk_high);
 1118         th->len = 2 * sizeof(u_char) /* start & end tracks */ +
 1119                   (th->ending_track + 1 - th->starting_track + 1) *
 1120                   sizeof(struct cd_toc_entry);
 1121 
 1122         return (0);
 1123 }
 1124 
 1125 static int
 1126 mcd_read_toc(struct mcd_softc *sc)
 1127 {
 1128         struct ioc_toc_header th;
 1129         struct mcd_qchninfo q;
 1130         int rc, trk, idx, retry;
 1131 
 1132         /* Only read TOC if needed */
 1133         if (sc->data.flags & MCDTOC)
 1134                 return (0);
 1135 
 1136         if (sc->data.debug)
 1137                 device_printf(sc->dev, "reading toc header\n");
 1138 
 1139         if ((rc = mcd_toc_header(sc, &th)) != 0)
 1140                 return (rc);
 1141 
 1142         if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0)
 1143                 return (EIO);
 1144 
 1145         if (mcd_setmode(sc, MCD_MD_TOC) != 0)
 1146                 return (EIO);
 1147 
 1148         if (sc->data.debug)
 1149                 device_printf(sc->dev, "get_toc reading qchannel info\n");
 1150 
 1151         for(trk=th.starting_track; trk<=th.ending_track; trk++)
 1152                 sc->data.toc[trk].idx_no = 0;
 1153         trk = th.ending_track - th.starting_track + 1;
 1154         for(retry=0; retry<600 && trk>0; retry++)
 1155         {
 1156                 if (mcd_getqchan(sc, &q) < 0) break;
 1157                 idx = bcd2bin(q.idx_no);
 1158                 if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) {
 1159                         if (sc->data.toc[idx].idx_no == 0) {
 1160                                 sc->data.toc[idx] = q;
 1161                                 trk--;
 1162                         }
 1163                 }
 1164         }
 1165 
 1166         if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
 1167                 return (EIO);
 1168 
 1169         if (trk != 0)
 1170                 return (ENXIO);
 1171 
 1172         /* add a fake last+1 */
 1173         idx = th.ending_track + 1;
 1174         sc->data.toc[idx].control = sc->data.toc[idx-1].control;
 1175         sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type;
 1176         sc->data.toc[idx].trk_no = 0;
 1177         sc->data.toc[idx].idx_no = MCD_LASTPLUS1;
 1178         sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0];
 1179         sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1];
 1180         sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2];
 1181 
 1182         if (sc->data.debug)
 1183         { int i;
 1184         for (i = th.starting_track; i <= idx; i++)
 1185                 device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n",
 1186                         i,
 1187                         sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no :
 1188                         bcd2bin(sc->data.toc[i].idx_no),
 1189                         bcd2bin(sc->data.toc[i].hd_pos_msf[0]),
 1190                         bcd2bin(sc->data.toc[i].hd_pos_msf[1]),
 1191                         bcd2bin(sc->data.toc[i].hd_pos_msf[2]));
 1192         }
 1193 
 1194         sc->data.flags |= MCDTOC;
 1195 
 1196         return (0);
 1197 }
 1198 
 1199 #if 0
 1200 static int
 1201 mcd_toc_entry(struct mcd_softc *sc, struct ioc_read_toc_single_entry *te)
 1202 {
 1203         struct ioc_toc_header th;
 1204         int rc, trk;
 1205 
 1206         if (te->address_format != CD_MSF_FORMAT
 1207             && te->address_format != CD_LBA_FORMAT)
 1208                 return (EINVAL);
 1209 
 1210         /* Copy the toc header */
 1211         if ((rc = mcd_toc_header(sc, &th)) != 0)
 1212                 return (rc);
 1213 
 1214         /* verify starting track */
 1215         trk = te->track;
 1216         if (trk == 0)
 1217                 trk = th.starting_track;
 1218         else if (trk == MCD_LASTPLUS1)
 1219                 trk = th.ending_track + 1;
 1220         else if (trk < th.starting_track || trk > th.ending_track + 1)
 1221                 return (EINVAL);
 1222 
 1223         /* Make sure we have a valid toc */
 1224         if ((rc=mcd_read_toc(sc)) != 0)
 1225                 return (rc);
 1226 
 1227         /* Copy the TOC data. */
 1228         if (sc->data.toc[trk].idx_no == 0)
 1229                 return (EIO);
 1230 
 1231         te->entry.control = sc->data.toc[trk].control;
 1232         te->entry.addr_type = sc->data.toc[trk].addr_type;
 1233         te->entry.track =
 1234                 sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no :
 1235                 bcd2bin(sc->data.toc[trk].idx_no);
 1236         switch (te->address_format) {
 1237         case CD_MSF_FORMAT:
 1238                 te->entry.addr.msf.unused = 0;
 1239                 te->entry.addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]);
 1240                 te->entry.addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]);
 1241                 te->entry.addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]);
 1242                 break;
 1243         case CD_LBA_FORMAT:
 1244                 te->entry.addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0));
 1245                 break;
 1246         }
 1247         return (0);
 1248 }
 1249 #endif
 1250 
 1251 static int
 1252 mcd_toc_entrys(struct mcd_softc *sc, struct ioc_read_toc_entry *te)
 1253 {
 1254         struct cd_toc_entry entries[MCD_MAXTOCS];
 1255         struct ioc_toc_header th;
 1256         int rc, n, trk, len;
 1257 
 1258         if (   te->data_len < sizeof(entries[0])
 1259             || (te->data_len % sizeof(entries[0])) != 0
 1260             || (te->address_format != CD_MSF_FORMAT
 1261                 && te->address_format != CD_LBA_FORMAT)
 1262            )
 1263                 return (EINVAL);
 1264 
 1265         /* Copy the toc header */
 1266         if ((rc = mcd_toc_header(sc, &th)) != 0)
 1267                 return (rc);
 1268 
 1269         /* verify starting track */
 1270         trk = te->starting_track;
 1271         if (trk == 0)
 1272                 trk = th.starting_track;
 1273         else if (trk == MCD_LASTPLUS1)
 1274                 trk = th.ending_track + 1;
 1275         else if (trk < th.starting_track || trk > th.ending_track + 1)
 1276                 return (EINVAL);
 1277 
 1278         len = ((th.ending_track + 1 - trk) + 1) *
 1279                 sizeof(entries[0]);
 1280         if (te->data_len < len)
 1281                 len = te->data_len;
 1282         if (len > sizeof(entries))
 1283                 return (EINVAL);
 1284 
 1285         /* Make sure we have a valid toc */
 1286         if ((rc=mcd_read_toc(sc)) != 0)
 1287                 return (rc);
 1288 
 1289         /* Copy the TOC data. */
 1290         for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) {
 1291                 if (sc->data.toc[trk].idx_no == 0)
 1292                         continue;
 1293                 entries[n].control = sc->data.toc[trk].control;
 1294                 entries[n].addr_type = sc->data.toc[trk].addr_type;
 1295                 entries[n].track =
 1296                         sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no :
 1297                         bcd2bin(sc->data.toc[trk].idx_no);
 1298                 switch (te->address_format) {
 1299                 case CD_MSF_FORMAT:
 1300                         entries[n].addr.msf.unused = 0;
 1301                         entries[n].addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]);
 1302                         entries[n].addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]);
 1303                         entries[n].addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]);
 1304                         break;
 1305                 case CD_LBA_FORMAT:
 1306                         entries[n].addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0));
 1307                         break;
 1308                 }
 1309                 len -= sizeof(struct cd_toc_entry);
 1310                 n++;
 1311         }
 1312 
 1313         /* copy the data back */
 1314         return copyout(entries, te->data, n * sizeof(struct cd_toc_entry));
 1315 }
 1316 
 1317 static int
 1318 mcd_stop(struct mcd_softc *sc)
 1319 {
 1320 
 1321         /* Verify current status */
 1322         if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS &&
 1323             sc->data.audio_status != CD_AS_PLAY_PAUSED &&
 1324             sc->data.audio_status != CD_AS_PLAY_COMPLETED) {
 1325                 if (sc->data.debug)
 1326                         device_printf(sc->dev,
 1327                                 "stop attempted when not playing, audio status %d\n",
 1328                                 sc->data.audio_status);
 1329                 return (EINVAL);
 1330         }
 1331         if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS)
 1332                 if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0)
 1333                         return (EIO);
 1334         sc->data.audio_status = CD_AS_PLAY_COMPLETED;
 1335         return (0);
 1336 }
 1337 
 1338 static int
 1339 mcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q)
 1340 {
 1341 
 1342         if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRYS) < 0)
 1343                 return (-1);
 1344         if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0)
 1345                 return (-1);
 1346         if (sc->data.debug) {
 1347                 device_printf(sc->dev,
 1348                         "getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n",
 1349                         q->control, q->addr_type,
 1350                         bcd2bin(q->trk_no),
 1351                         bcd2bin(q->idx_no),
 1352                         bcd2bin(q->trk_size_msf[0]),
 1353                         bcd2bin(q->trk_size_msf[1]),
 1354                         bcd2bin(q->trk_size_msf[2]),
 1355                         bcd2bin(q->hd_pos_msf[0]),
 1356                         bcd2bin(q->hd_pos_msf[1]),
 1357                         bcd2bin(q->hd_pos_msf[2]));
 1358         }
 1359         return (0);
 1360 }
 1361 
 1362 static int
 1363 mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch)
 1364 {
 1365         struct mcd_qchninfo q;
 1366         struct cd_sub_channel_info data;
 1367         int lba;
 1368 
 1369         if (sc->data.debug)
 1370                 device_printf(sc->dev, "subchan af=%d, df=%d\n",
 1371                         sch->address_format,
 1372                         sch->data_format);
 1373 
 1374         if (sch->address_format != CD_MSF_FORMAT &&
 1375             sch->address_format != CD_LBA_FORMAT)
 1376                 return (EINVAL);
 1377 
 1378         if (sch->data_format != CD_CURRENT_POSITION &&
 1379             sch->data_format != CD_MEDIA_CATALOG)
 1380                 return (EINVAL);
 1381 
 1382         if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
 1383                 return (EIO);
 1384 
 1385         if (mcd_getqchan(sc, &q) < 0)
 1386                 return (EIO);
 1387 
 1388         data.header.audio_status = sc->data.audio_status;
 1389         data.what.position.data_format = sch->data_format;
 1390 
 1391         switch (sch->data_format) {
 1392         case CD_MEDIA_CATALOG:
 1393                 data.what.media_catalog.mc_valid = 1;
 1394                 data.what.media_catalog.mc_number[0] = '\0';
 1395                 break;
 1396 
 1397         case CD_CURRENT_POSITION:
 1398                 data.what.position.control = q.control;
 1399                 data.what.position.addr_type = q.addr_type;
 1400                 data.what.position.track_number = bcd2bin(q.trk_no);
 1401                 data.what.position.index_number = bcd2bin(q.idx_no);
 1402                 switch (sch->address_format) {
 1403                 case CD_MSF_FORMAT:
 1404                         data.what.position.reladdr.msf.unused = 0;
 1405                         data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]);
 1406                         data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]);
 1407                         data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]);
 1408                         data.what.position.absaddr.msf.unused = 0;
 1409                         data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]);
 1410                         data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]);
 1411                         data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]);
 1412                         break;
 1413                 case CD_LBA_FORMAT:
 1414                         lba = msf2hsg(q.trk_size_msf, 1);
 1415                         /*
 1416                          * Pre-gap has index number of 0, and decreasing MSF
 1417                          * address.  Must be converted to negative LBA, per
 1418                          * SCSI spec.
 1419                          */
 1420                         if (data.what.position.index_number == 0)
 1421                                 lba = -lba;
 1422                         data.what.position.reladdr.lba = htonl(lba);
 1423                         data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0));
 1424                         break;
 1425                 }
 1426                 break;
 1427         }
 1428 
 1429         return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
 1430 }
 1431 
 1432 static int
 1433 mcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p)
 1434 {
 1435         struct mcd_read2 pb;
 1436 
 1437         if (sc->data.debug)
 1438                 device_printf(sc->dev, "playmsf: from %d:%d.%d to %d:%d.%d\n",
 1439                     p->start_m, p->start_s, p->start_f,
 1440                     p->end_m, p->end_s, p->end_f);
 1441 
 1442         if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
 1443             (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) ||
 1444             (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) >
 1445             M_msf(sc->data.volinfo.vol_msf) * 60 * 75 +
 1446             S_msf(sc->data.volinfo.vol_msf) * 75 +
 1447             F_msf(sc->data.volinfo.vol_msf))
 1448                 return (EINVAL);
 1449 
 1450         pb.start_msf[0] = bin2bcd(p->start_m);
 1451         pb.start_msf[1] = bin2bcd(p->start_s);
 1452         pb.start_msf[2] = bin2bcd(p->start_f);
 1453         pb.end_msf[0] = bin2bcd(p->end_m);
 1454         pb.end_msf[1] = bin2bcd(p->end_s);
 1455         pb.end_msf[2] = bin2bcd(p->end_f);
 1456 
 1457         if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
 1458                 return (EIO);
 1459 
 1460         return mcd_play(sc, &pb);
 1461 }
 1462 
 1463 static int
 1464 mcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *pt)
 1465 {
 1466         struct mcd_read2 pb;
 1467         int a = pt->start_track;
 1468         int z = pt->end_track;
 1469         int rc, i;
 1470 
 1471         if ((rc = mcd_read_toc(sc)) != 0)
 1472                 return (rc);
 1473 
 1474         if (sc->data.debug)
 1475                 device_printf(sc->dev, "playtracks from %d:%d to %d:%d\n",
 1476                         a, pt->start_index, z, pt->end_index);
 1477 
 1478         if (   a < bcd2bin(sc->data.volinfo.trk_low)
 1479             || a > bcd2bin(sc->data.volinfo.trk_high)
 1480             || a > z
 1481             || z < bcd2bin(sc->data.volinfo.trk_low)
 1482             || z > bcd2bin(sc->data.volinfo.trk_high))
 1483                 return (EINVAL);
 1484 
 1485         for (i = 0; i < 3; i++) {
 1486                 pb.start_msf[i] = sc->data.toc[a].hd_pos_msf[i];
 1487                 pb.end_msf[i] = sc->data.toc[z+1].hd_pos_msf[i];
 1488         }
 1489 
 1490         if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
 1491                 return (EIO);
 1492 
 1493         return mcd_play(sc, &pb);
 1494 }
 1495 
 1496 static int
 1497 mcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p)
 1498 {
 1499         struct mcd_read2 pb;
 1500 
 1501         if (sc->data.debug)
 1502                 device_printf(sc->dev, "playblocks: blkno %d length %d\n",
 1503                     p->blk, p->len);
 1504 
 1505         if (p->blk > sc->data.disksize || p->len > sc->data.disksize ||
 1506             p->blk < 0 || p->len < 0 ||
 1507             (p->blk + p->len) > sc->data.disksize)
 1508                 return (EINVAL);
 1509 
 1510         hsg2msf(p->blk, pb.start_msf);
 1511         hsg2msf(p->blk + p->len, pb.end_msf);
 1512 
 1513         if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
 1514                 return (EIO);
 1515 
 1516         return mcd_play(sc, &pb);
 1517 }
 1518 
 1519 static int
 1520 mcd_play(struct mcd_softc *sc, struct mcd_read2 *pb)
 1521 {
 1522         int retry, st = -1, status;
 1523 
 1524         sc->data.lastpb = *pb;
 1525         for(retry=0; retry<MCD_RETRYS; retry++) {
 1526 
 1527                 critical_enter();
 1528                 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSINGLESPEEDREAD);
 1529                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[0]);
 1530                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[1]);
 1531                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[2]);
 1532                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[0]);
 1533                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[1]);
 1534                 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[2]);
 1535                 critical_exit();
 1536 
 1537                 status=mcd_getstat(sc, 0);
 1538                 if (status == -1)
 1539                         continue;
 1540                 else if (status != -2)
 1541                         st = 0;
 1542                 break;
 1543         }
 1544 
 1545         if (status == -2) {
 1546                 device_printf(sc->dev, "media changed\n");
 1547                 return (ENXIO);
 1548         }
 1549         if (sc->data.debug)
 1550                 device_printf(sc->dev,
 1551                         "mcd_play retry=%d, status=0x%02x\n", retry, status);
 1552         if (st < 0)
 1553                 return (ENXIO);
 1554         sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS;
 1555         return (0);
 1556 }
 1557 
 1558 static int
 1559 mcd_pause(struct mcd_softc *sc)
 1560 {
 1561         struct mcd_qchninfo q;
 1562         int rc;
 1563 
 1564         /* Verify current status */
 1565         if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS &&
 1566             sc->data.audio_status != CD_AS_PLAY_PAUSED) {
 1567                 if (sc->data.debug)
 1568                         device_printf(sc->dev,
 1569                                 "pause attempted when not playing, audio status %d\n",
 1570                                 sc->data.audio_status);
 1571                 return (EINVAL);
 1572         }
 1573 
 1574         /* Get the current position */
 1575         if (mcd_getqchan(sc, &q) < 0)
 1576                 return (EIO);
 1577 
 1578         /* Copy it into lastpb */
 1579         sc->data.lastpb.start_msf[0] = q.hd_pos_msf[0];
 1580         sc->data.lastpb.start_msf[1] = q.hd_pos_msf[1];
 1581         sc->data.lastpb.start_msf[2] = q.hd_pos_msf[2];
 1582 
 1583         /* Stop playing */
 1584         if ((rc=mcd_stop(sc)) != 0)
 1585                 return (rc);
 1586 
 1587         /* Set the proper status and exit */
 1588         sc->data.audio_status = CD_AS_PLAY_PAUSED;
 1589         return (0);
 1590 }
 1591 
 1592 static int
 1593 mcd_resume(struct mcd_softc *sc)
 1594 {
 1595 
 1596         if (sc->data.audio_status != CD_AS_PLAY_PAUSED)
 1597                 return (EINVAL);
 1598         return mcd_play(sc, &sc->data.lastpb);
 1599 }

Cache object: 84c34e12a74ca9aa440e1ef31b81e249


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