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/i386/isa/mcd.c

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

    1 /*
    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  * $FreeBSD$
   44  */
   45 static const char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
   46 
   47 #include "mcd.h"
   48 #if NMCD > 0
   49 #include "opt_devfs.h"
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/conf.h>
   54 #include <sys/fcntl.h>
   55 #include <sys/buf.h>
   56 #include <sys/cdio.h>
   57 #include <sys/dkbad.h>
   58 #include <sys/disklabel.h>
   59 #include <sys/kernel.h>
   60 #ifdef DEVFS
   61 #include <sys/devfsext.h>
   62 #endif /*DEVFS*/
   63 
   64 #include <machine/clock.h>
   65 
   66 #include <i386/isa/isa_device.h>
   67 #include <i386/isa/mcdreg.h>
   68 
   69 #define MCD_TRACE(format, args...)                                              \
   70 {                                                                       \
   71         if (mcd_data[unit].debug) {                                     \
   72                 printf("mcd%d: status=0x%02x: ",                        \
   73                         unit, mcd_data[unit].status);                   \
   74                 printf(format, ## args);                                \
   75         }                                                               \
   76 }
   77 
   78 #define mcd_part(dev)   ((minor(dev)) & 7)
   79 #define mcd_unit(dev)   (((minor(dev)) & 0x38) >> 3)
   80 #define mcd_phys(dev)   (((minor(dev)) & 0x40) >> 6)
   81 #define RAW_PART        2
   82 
   83 /* flags */
   84 #define MCDVALID        0x0001  /* parameters loaded */
   85 #define MCDINIT         0x0002  /* device is init'd */
   86 #define MCDNEWMODEL     0x0004  /* device is new model */
   87 #define MCDLABEL        0x0008  /* label is read */
   88 #define MCDPROBING      0x0010  /* probing */
   89 #define MCDREADRAW      0x0020  /* read raw mode (2352 bytes) */
   90 #define MCDVOLINFO      0x0040  /* already read volinfo */
   91 #define MCDTOC          0x0080  /* already read toc */
   92 #define MCDMBXBSY       0x0100  /* local mbx is busy */
   93 
   94 /* status */
   95 #define MCDAUDIOBSY     MCD_ST_AUDIOBSY         /* playing audio */
   96 #define MCDDSKCHNG      MCD_ST_DSKCHNG          /* sensed change of disk */
   97 #define MCDDSKIN        MCD_ST_DSKIN            /* sensed disk in drive */
   98 #define MCDDOOROPEN     MCD_ST_DOOROPEN         /* sensed door open */
   99 
  100 /* These are apparently the different states a mitsumi can get up to */
  101 #define MCDCDABSENT     0x0030
  102 #define MCDCDPRESENT    0x0020
  103 #define MCDSCLOSED      0x0080
  104 #define MCDSOPEN        0x00a0
  105 
  106 #define MCD_MD_UNKNOWN  (-1)
  107 
  108 /* toc */
  109 #define MCD_MAXTOCS     104     /* from the Linux driver */
  110 #define MCD_LASTPLUS1   170     /* special toc entry */
  111 
  112 #define MCD_TYPE_UNKNOWN        0
  113 #define MCD_TYPE_LU002S         1
  114 #define MCD_TYPE_LU005S         2
  115 #define MCD_TYPE_LU006S         3
  116 #define MCD_TYPE_FX001          4
  117 #define MCD_TYPE_FX001D         5
  118 
  119 struct mcd_mbx {
  120         short           unit;
  121         short           port;
  122         short           retry;
  123         short           nblk;
  124         int             sz;
  125         u_long          skip;
  126         struct buf      *bp;
  127         int             p_offset;
  128         short           count;
  129         short           mode;
  130 };
  131 
  132 static struct mcd_data {
  133         short   type;
  134         char    *name;
  135         short   config;
  136         short   flags;
  137         u_char  read_command;
  138         short   status;
  139         int     blksize;
  140         u_long  disksize;
  141         int     iobase;
  142         struct disklabel dlabel;
  143         int     partflags[MAXPARTITIONS];
  144         int     openflags;
  145         struct mcd_volinfo volinfo;
  146         struct mcd_qchninfo toc[MCD_MAXTOCS];
  147         short   audio_status;
  148         short   curr_mode;
  149         struct mcd_read2 lastpb;
  150         short   debug;
  151         struct buf_queue_head head;             /* head of buf queue */
  152         struct mcd_mbx mbx;
  153 #ifdef  DEVFS
  154         void *ra_devfs_token;           /* store the devfs handle here */
  155         void *rc_devfs_token;           /* store the devfs handle here */
  156         void *a_devfs_token;            /* store the devfs handle here */
  157         void *c_devfs_token;            /* store the devfs handle here */
  158 #endif
  159 } mcd_data[NMCD];
  160 
  161 /* reader state machine */
  162 #define MCD_S_BEGIN     0
  163 #define MCD_S_BEGIN1    1
  164 #define MCD_S_WAITSTAT  2
  165 #define MCD_S_WAITMODE  3
  166 #define MCD_S_WAITREAD  4
  167 
  168 /* prototypes */
  169 static  void    mcd_start(int unit);
  170 static  int     mcd_getdisklabel(int unit);
  171 #ifdef NOTYET
  172 static  void    mcd_configure(struct mcd_data *cd);
  173 #endif
  174 static  int     mcd_get(int unit, char *buf, int nmax);
  175 static  int     mcd_setflags(int unit,struct mcd_data *cd);
  176 static  int     mcd_getstat(int unit,int sflg);
  177 static  int     mcd_send(int unit, int cmd,int nretrys);
  178 static  void    hsg2msf(int hsg, bcd_t *msf);
  179 static  int     msf2hsg(bcd_t *msf, int relative);
  180 static  int     mcd_volinfo(int unit);
  181 static  ointhand2_t     mcdintr;
  182 static  int     mcd_waitrdy(int port,int dly);
  183 static  timeout_t mcd_timeout;
  184 static  void    mcd_doread(int state, struct mcd_mbx *mbxin);
  185 static  void    mcd_soft_reset(int unit);
  186 static  int     mcd_hard_reset(int unit);
  187 static  int     mcd_setmode(int unit, int mode);
  188 static  int     mcd_getqchan(int unit, struct mcd_qchninfo *q);
  189 static  int     mcd_subchan(int unit, struct ioc_read_subchannel *sc);
  190 static  int     mcd_toc_header(int unit, struct ioc_toc_header *th);
  191 static  int     mcd_read_toc(int unit);
  192 static  int     mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te);
  193 #if 0
  194 static  int     mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te);
  195 #endif
  196 static  int     mcd_stop(int unit);
  197 static  int     mcd_eject(int unit);
  198 static  int     mcd_inject(int unit);
  199 static  int     mcd_playtracks(int unit, struct ioc_play_track *pt);
  200 static  int     mcd_play(int unit, struct mcd_read2 *pb);
  201 static  int     mcd_playmsf(int unit, struct ioc_play_msf *pt);
  202 static  int     mcd_playblocks(int unit, struct ioc_play_blocks *);
  203 static  int     mcd_pause(int unit);
  204 static  int     mcd_resume(int unit);
  205 static  int     mcd_lock_door(int unit, int lock);
  206 static  int     mcd_close_tray(int unit);
  207 
  208 static  int     mcd_probe(struct isa_device *dev);
  209 static  int     mcd_attach(struct isa_device *dev);
  210 struct  isa_driver      mcddriver = { mcd_probe, mcd_attach, "mcd" };
  211 
  212 static  d_open_t        mcdopen;
  213 static  d_read_t        mcdread;
  214 static  d_close_t       mcdclose;
  215 static  d_ioctl_t       mcdioctl;
  216 static  d_psize_t       mcdsize;
  217 static  d_strategy_t    mcdstrategy;
  218 
  219 #define CDEV_MAJOR 29
  220 #define BDEV_MAJOR 7
  221 
  222 
  223 
  224 static struct cdevsw mcd_cdevsw = {
  225           mcdopen,      mcdclose,       mcdread,        nowrite,
  226           mcdioctl,     nostop,         nullreset,      nodevtotty,
  227           seltrue,      nommap,         mcdstrategy,    "mcd",
  228           NULL,         -1,             nodump,         nopsize,
  229           D_DISK,       0,              NODEV };
  230 
  231 #define mcd_put(port,byte)      outb(port,byte)
  232 
  233 #define MCD_RETRYS      5
  234 #define MCD_RDRETRYS    8
  235 
  236 #define CLOSE_TRAY_SECS 8
  237 #define DISK_SENSE_SECS 3
  238 #define WAIT_FRAC 4
  239 
  240 /* several delays */
  241 #define RDELAY_WAITSTAT 300
  242 #define RDELAY_WAITMODE 300
  243 #define RDELAY_WAITREAD 800
  244 
  245 #define MIN_DELAY       15
  246 #define DELAY_GETREPLY  5000000
  247 
  248 int mcd_attach(struct isa_device *dev)
  249 {
  250         int     unit = dev->id_unit;
  251         struct mcd_data *cd = mcd_data + unit;
  252 
  253         dev->id_ointr = mcdintr;
  254         cd->iobase = dev->id_iobase;
  255         cd->flags |= MCDINIT;
  256         mcd_soft_reset(unit);
  257         bufq_init(&cd->head);
  258 
  259 #ifdef NOTYET
  260         /* wire controller for interrupts and dma */
  261         mcd_configure(cd);
  262 #endif
  263         /* name filled in probe */
  264 #ifdef DEVFS
  265         cd->ra_devfs_token = 
  266                 devfs_add_devswf(&mcd_cdevsw, dkmakeminor(unit, 0, 0),
  267                                  DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  268                                  "rmcd%da", unit);
  269         cd->rc_devfs_token = 
  270                 devfs_add_devswf(&mcd_cdevsw, dkmakeminor(unit, 0, RAW_PART),
  271                                  DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  272                                  "rmcd%dc", unit);
  273         cd->a_devfs_token = 
  274                 devfs_add_devswf(&mcd_cdevsw, dkmakeminor(unit, 0, 0),
  275                                  DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  276                                  "mcd%da", unit);
  277         cd->c_devfs_token = 
  278                 devfs_add_devswf(&mcd_cdevsw, dkmakeminor(unit, 0, RAW_PART),
  279                                  DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  280                                  "mcd%dc", unit);
  281 #endif
  282         return 1;
  283 }
  284 
  285 int mcdopen(dev_t dev, int flags, int fmt, struct proc *p)
  286 {
  287         int unit,part,phys,r,retry;
  288         struct mcd_data *cd;
  289 
  290         unit = mcd_unit(dev);
  291         if (unit >= NMCD)
  292                 return ENXIO;
  293 
  294         cd = mcd_data + unit;
  295         part = mcd_part(dev);
  296         phys = mcd_phys(dev);
  297 
  298         /* not initialized*/
  299         if (!(cd->flags & MCDINIT))
  300                 return ENXIO;
  301 
  302         /* invalidated in the meantime? mark all open part's invalid */
  303         if (!(cd->flags & MCDVALID) && cd->openflags)
  304                 return ENXIO;
  305 
  306         if (mcd_getstat(unit,1) == -1)
  307                 return EIO;
  308 
  309         if (    (cd->status & (MCDDSKCHNG|MCDDOOROPEN))
  310             || !(cd->status & MCDDSKIN))
  311                 for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
  312                         (void) tsleep((caddr_t)cd, PSOCK | PCATCH, "mcdsn1", hz/WAIT_FRAC);
  313                         if ((r = mcd_getstat(unit,1)) == -1)
  314                                 return EIO;
  315                         if (r != -2)
  316                                 break;
  317                 }
  318 
  319         if ((   (cd->status & (MCDDOOROPEN|MCDDSKCHNG))
  320              || !(cd->status & MCDDSKIN)
  321             )
  322             && major(dev) == CDEV_MAJOR && part == RAW_PART
  323            ) {
  324                 cd->openflags |= (1<<part);
  325                 if (phys)
  326                         cd->partflags[part] |= MCDREADRAW;
  327                 return 0;
  328         }
  329         if (cd->status & MCDDOOROPEN) {
  330                 printf("mcd%d: door is open\n", unit);
  331                 return ENXIO;
  332         }
  333         if (!(cd->status & MCDDSKIN)) {
  334                 printf("mcd%d: no CD inside\n", unit);
  335                 return ENXIO;
  336         }
  337         if (cd->status & MCDDSKCHNG) {
  338                 printf("mcd%d: CD not sensed\n", unit);
  339                 return ENXIO;
  340         }
  341 
  342         if (mcdsize(dev) < 0) {
  343                 if (major(dev) == CDEV_MAJOR && part == RAW_PART) {
  344                         cd->openflags |= (1<<part);
  345                         if (phys)
  346                                 cd->partflags[part] |= MCDREADRAW;
  347                         return 0;
  348                 }
  349                 printf("mcd%d: failed to get disk size\n",unit);
  350                 return ENXIO;
  351         } else
  352                 cd->flags |= MCDVALID;
  353 
  354         /* XXX get a default disklabel */
  355         mcd_getdisklabel(unit);
  356 
  357 MCD_TRACE("open: partition=%d, disksize = %ld, blksize=%d\n",
  358         part, cd->disksize, cd->blksize);
  359 
  360         if (part == RAW_PART ||
  361                 (part < cd->dlabel.d_npartitions &&
  362                 cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) {
  363                 cd->openflags |= (1<<part);
  364                 if (part == RAW_PART && phys)
  365                         cd->partflags[part] |= MCDREADRAW;
  366                 (void) mcd_lock_door(unit, MCD_LK_LOCK);
  367                 if (!(cd->flags & MCDVALID))
  368                         return ENXIO;
  369                 return 0;
  370         }
  371 
  372         return ENXIO;
  373 }
  374 
  375 int mcdclose(dev_t dev, int flags, int fmt, struct proc *p)
  376 {
  377         int unit,part;
  378         struct mcd_data *cd;
  379 
  380         unit = mcd_unit(dev);
  381         if (unit >= NMCD)
  382                 return ENXIO;
  383 
  384         cd = mcd_data + unit;
  385         part = mcd_part(dev);
  386 
  387         if (!(cd->flags & MCDINIT) || !(cd->openflags & (1<<part)))
  388                 return ENXIO;
  389 
  390         MCD_TRACE("close: partition=%d\n", part);
  391 
  392         (void) mcd_lock_door(unit, MCD_LK_UNLOCK);
  393         cd->openflags &= ~(1<<part);
  394         cd->partflags[part] &= ~MCDREADRAW;
  395 
  396         return 0;
  397 }
  398 
  399 static int
  400 mcdread(dev_t dev, struct uio *uio, int ioflag)
  401 {
  402         return (physio(mcdstrategy, NULL, dev, 1, minphys, uio));
  403 }
  404 
  405 void
  406 mcdstrategy(struct buf *bp)
  407 {
  408         struct mcd_data *cd;
  409         int s;
  410 
  411         int unit = mcd_unit(bp->b_dev);
  412 
  413         cd = mcd_data + unit;
  414 
  415         /* test validity */
  416 /*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n",
  417         bp,unit,bp->b_blkno,bp->b_bcount);*/
  418         if (unit >= NMCD || bp->b_blkno < 0) {
  419                 printf("mcdstrategy: unit = %d, blkno = %ld, bcount = %ld\n",
  420                         unit, (long)bp->b_blkno, bp->b_bcount);
  421                 printf("mcd: mcdstratregy failure");
  422                 bp->b_error = EINVAL;
  423                 bp->b_flags |= B_ERROR;
  424                 goto bad;
  425         }
  426 
  427         /* if device invalidated (e.g. media change, door open), error */
  428         if (!(cd->flags & MCDVALID)) {
  429 MCD_TRACE("strategy: drive not valid\n");
  430                 bp->b_error = EIO;
  431                 goto bad;
  432         }
  433 
  434         /* read only */
  435         if (!(bp->b_flags & B_READ)) {
  436                 bp->b_error = EROFS;
  437                 goto bad;
  438         }
  439 
  440         /* no data to read */
  441         if (bp->b_bcount == 0)
  442                 goto done;
  443 
  444         /* for non raw access, check partition limits */
  445         if (mcd_part(bp->b_dev) != RAW_PART) {
  446                 if (!(cd->flags & MCDLABEL)) {
  447                         bp->b_error = EIO;
  448                         goto bad;
  449                 }
  450                 /* adjust transfer if necessary */
  451                 if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
  452                         goto done;
  453                 }
  454         } else {
  455                 bp->b_pblkno = bp->b_blkno;
  456                 bp->b_resid = 0;
  457         }
  458 
  459         /* queue it */
  460         s = splbio();
  461         bufqdisksort(&cd->head, bp);
  462         splx(s);
  463 
  464         /* now check whether we can perform processing */
  465         mcd_start(unit);
  466         return;
  467 
  468 bad:
  469         bp->b_flags |= B_ERROR;
  470 done:
  471         bp->b_resid = bp->b_bcount;
  472         biodone(bp);
  473         return;
  474 }
  475 
  476 static void mcd_start(int unit)
  477 {
  478         struct mcd_data *cd = mcd_data + unit;
  479         struct partition *p;
  480         struct buf *bp;
  481         register s = splbio();
  482 
  483         if (cd->flags & MCDMBXBSY) {
  484                 splx(s);
  485                 return;
  486         }
  487 
  488         bp = bufq_first(&cd->head);
  489         if (bp != 0) {
  490                 /* block found to process, dequeue */
  491                 /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/
  492                 bufq_remove(&cd->head, bp);
  493                 splx(s);
  494         } else {
  495                 /* nothing to do */
  496                 splx(s);
  497                 return;
  498         }
  499 
  500         /* changed media? */
  501         if (!(cd->flags & MCDVALID)) {
  502                 MCD_TRACE("mcd_start: drive not valid\n");
  503                 return;
  504         }
  505 
  506         p = cd->dlabel.d_partitions + mcd_part(bp->b_dev);
  507 
  508         cd->flags |= MCDMBXBSY;
  509         if (cd->partflags[mcd_part(bp->b_dev)] & MCDREADRAW)
  510                 cd->flags |= MCDREADRAW;
  511         cd->mbx.unit = unit;
  512         cd->mbx.port = cd->iobase;
  513         cd->mbx.retry = MCD_RETRYS;
  514         cd->mbx.bp = bp;
  515         cd->mbx.p_offset = p->p_offset;
  516 
  517         /* calling the read routine */
  518         mcd_doread(MCD_S_BEGIN,&(cd->mbx));
  519         /* triggers mcd_start, when successful finished */
  520         return;
  521 }
  522 
  523 int mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
  524 {
  525         struct mcd_data *cd;
  526         int unit,part,retry,r;
  527 
  528         unit = mcd_unit(dev);
  529         part = mcd_part(dev);
  530         cd = mcd_data + unit;
  531 
  532         if (mcd_getstat(unit, 1) == -1) /* detect disk change too */
  533                 return EIO;
  534 MCD_TRACE("ioctl called 0x%lx\n", cmd);
  535 
  536         switch (cmd) {
  537         case CDIOCSETPATCH:
  538         case CDIOCGETVOL:
  539         case CDIOCSETVOL:
  540         case CDIOCSETMONO:
  541         case CDIOCSETSTERIO:
  542         case CDIOCSETMUTE:
  543         case CDIOCSETLEFT:
  544         case CDIOCSETRIGHT:
  545                 return EINVAL;
  546         case CDIOCEJECT:
  547                 return mcd_eject(unit);
  548         case CDIOCSETDEBUG:
  549                 cd->debug = 1;
  550                 return 0;
  551         case CDIOCCLRDEBUG:
  552                 cd->debug = 0;
  553                 return 0;
  554         case CDIOCRESET:
  555                 return mcd_hard_reset(unit);
  556         case CDIOCALLOW:
  557                 return mcd_lock_door(unit, MCD_LK_UNLOCK);
  558         case CDIOCPREVENT:
  559                 return mcd_lock_door(unit, MCD_LK_LOCK);
  560         case CDIOCCLOSE:
  561                 return mcd_inject(unit);
  562         }
  563 
  564         if (!(cd->flags & MCDVALID)) {
  565                 if (   major(dev) != CDEV_MAJOR
  566                     || part != RAW_PART
  567                     || !(cd->openflags & (1<<RAW_PART))
  568                    )
  569                         return ENXIO;
  570                 if (    (cd->status & (MCDDSKCHNG|MCDDOOROPEN))
  571                     || !(cd->status & MCDDSKIN))
  572                         for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
  573                                 (void) tsleep((caddr_t)cd, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC);
  574                                 if ((r = mcd_getstat(unit,1)) == -1)
  575                                         return EIO;
  576                                 if (r != -2)
  577                                         break;
  578                         }
  579                 if (   (cd->status & (MCDDOOROPEN|MCDDSKCHNG))
  580                     || !(cd->status & MCDDSKIN)
  581                     || mcdsize(dev) < 0
  582                    )
  583                         return ENXIO;
  584                 cd->flags |= MCDVALID;
  585                 mcd_getdisklabel(unit);
  586                 if (mcd_phys(dev))
  587                         cd->partflags[part] |= MCDREADRAW;
  588                 (void) mcd_lock_door(unit, MCD_LK_LOCK);
  589                 if (!(cd->flags & MCDVALID))
  590                         return ENXIO;
  591         }
  592 
  593         switch (cmd) {
  594         case DIOCSBAD:
  595                 return EINVAL;
  596         case DIOCGDINFO:
  597                 *(struct disklabel *) addr = cd->dlabel;
  598                 return 0;
  599         case DIOCGPART:
  600                 ((struct partinfo *) addr)->disklab = &cd->dlabel;
  601                 ((struct partinfo *) addr)->part =
  602                     &cd->dlabel.d_partitions[mcd_part(dev)];
  603                 return 0;
  604 
  605                 /*
  606                  * a bit silly, but someone might want to test something on a
  607                  * section of cdrom.
  608                  */
  609         case DIOCWDINFO:
  610         case DIOCSDINFO:
  611                 if ((flags & FWRITE) == 0)
  612                         return EBADF;
  613                 else {
  614                         return setdisklabel(&cd->dlabel,
  615                             (struct disklabel *) addr,
  616                             0);
  617                 }
  618         case DIOCWLABEL:
  619                 return EBADF;
  620         case CDIOCPLAYTRACKS:
  621                 return mcd_playtracks(unit, (struct ioc_play_track *) addr);
  622         case CDIOCPLAYBLOCKS:
  623                 return mcd_playblocks(unit, (struct ioc_play_blocks *) addr);
  624         case CDIOCPLAYMSF:
  625                 return mcd_playmsf(unit, (struct ioc_play_msf *) addr);
  626         case CDIOCREADSUBCHANNEL:
  627                 return mcd_subchan(unit, (struct ioc_read_subchannel *) addr);
  628         case CDIOREADTOCHEADER:
  629                 return mcd_toc_header(unit, (struct ioc_toc_header *) addr);
  630         case CDIOREADTOCENTRYS:
  631                 return mcd_toc_entrys(unit, (struct ioc_read_toc_entry *) addr);
  632         case CDIOCRESUME:
  633                 return mcd_resume(unit);
  634         case CDIOCPAUSE:
  635                 return mcd_pause(unit);
  636         case CDIOCSTART:
  637                 if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
  638                         return EIO;
  639                 return 0;
  640         case CDIOCSTOP:
  641                 return mcd_stop(unit);
  642         default:
  643                 return ENOTTY;
  644         }
  645         /*NOTREACHED*/
  646 }
  647 
  648 /* this could have been taken from scsi/cd.c, but it is not clear
  649  * whether the scsi cd driver is linked in
  650  */
  651 static int mcd_getdisklabel(int unit)
  652 {
  653         struct mcd_data *cd = mcd_data + unit;
  654 
  655         if (cd->flags & MCDLABEL)
  656                 return -1;
  657 
  658         bzero(&cd->dlabel,sizeof(struct disklabel));
  659         /* filled with spaces first */
  660         strncpy(cd->dlabel.d_typename,"               ",
  661                 sizeof(cd->dlabel.d_typename));
  662         strncpy(cd->dlabel.d_typename, cd->name,
  663                 min(strlen(cd->name), sizeof(cd->dlabel.d_typename) - 1));
  664         strncpy(cd->dlabel.d_packname,"unknown        ",
  665                 sizeof(cd->dlabel.d_packname));
  666         cd->dlabel.d_secsize    = cd->blksize;
  667         cd->dlabel.d_nsectors   = 100;
  668         cd->dlabel.d_ntracks    = 1;
  669         cd->dlabel.d_ncylinders = (cd->disksize/100)+1;
  670         cd->dlabel.d_secpercyl  = 100;
  671         cd->dlabel.d_secperunit = cd->disksize;
  672         cd->dlabel.d_rpm        = 300;
  673         cd->dlabel.d_interleave = 1;
  674         cd->dlabel.d_flags      = D_REMOVABLE;
  675         cd->dlabel.d_npartitions= 1;
  676         cd->dlabel.d_partitions[0].p_offset = 0;
  677         cd->dlabel.d_partitions[0].p_size = cd->disksize;
  678         cd->dlabel.d_partitions[0].p_fstype = 9;
  679         cd->dlabel.d_magic      = DISKMAGIC;
  680         cd->dlabel.d_magic2     = DISKMAGIC;
  681         cd->dlabel.d_checksum   = dkcksum(&cd->dlabel);
  682 
  683         cd->flags |= MCDLABEL;
  684         return 0;
  685 }
  686 
  687 int mcdsize(dev_t dev)
  688 {
  689         int size;
  690         int unit = mcd_unit(dev);
  691         struct mcd_data *cd = mcd_data + unit;
  692 
  693         if (mcd_volinfo(unit) == 0) {
  694                 cd->blksize = MCDBLK;
  695                 size = msf2hsg(cd->volinfo.vol_msf, 0);
  696                 cd->disksize = size * (MCDBLK/DEV_BSIZE);
  697                 return 0;
  698         }
  699         return -1;
  700 }
  701 
  702 /***************************************************************
  703  * lower level of driver starts here
  704  **************************************************************/
  705 
  706 #ifdef NOTDEF
  707 static char
  708 irqs[] = {
  709         0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00,
  710         0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00
  711 };
  712 
  713 static char
  714 drqs[] = {
  715         0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07,
  716 };
  717 #endif
  718 
  719 #ifdef NOT_YET
  720 static void
  721 mcd_configure(struct mcd_data *cd)
  722 {
  723         outb(cd->iobase+mcd_config,cd->config);
  724 }
  725 #endif
  726 
  727 /* Wait for non-busy - return 0 on timeout */
  728 static int
  729 twiddle_thumbs(int port, int unit, int count, char *whine)
  730 {
  731         int i;
  732 
  733         for (i = 0; i < count; i++) {
  734                 if (!(inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL))
  735                         return 1;
  736                 }
  737         if (bootverbose)
  738                 printf("mcd%d: timeout %s\n", unit, whine);
  739         return 0;
  740 }
  741 
  742 /* check to see if a Mitsumi CD-ROM is attached to the ISA bus */
  743 
  744 int
  745 mcd_probe(struct isa_device *dev)
  746 {
  747         int port = dev->id_iobase;
  748         int unit = dev->id_unit;
  749         int i, j;
  750         unsigned char stbytes[3];
  751 
  752         mcd_data[unit].flags = MCDPROBING;
  753 
  754 #ifdef NOTDEF
  755         /* get irq/drq configuration word */
  756         mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/
  757 #else
  758         mcd_data[unit].config = 0;
  759 #endif
  760 
  761         /* send a reset */
  762         outb(port+MCD_FLAGS, M_RESET);
  763 
  764         /*
  765          * delay awhile by getting any pending garbage (old data) and
  766          * throwing it away.
  767          */
  768         for (i = 1000000; i != 0; i--)
  769                 inb(port+MCD_FLAGS);
  770 
  771         /* Get status */
  772         outb(port+MCD_DATA, MCD_CMDGETSTAT);
  773         if (!twiddle_thumbs(port, unit, 1000000, "getting status"))
  774                 return 0;       /* Timeout */
  775         /* Get version information */
  776         outb(port+MCD_DATA, MCD_CMDCONTINFO);
  777         for (j = 0; j < 3; j++) {
  778                 if (!twiddle_thumbs(port, unit, 3000, "getting version info"))
  779                         return 0;
  780                 stbytes[j] = (inb(port+MCD_DATA) & 0xFF);
  781         }
  782         if (stbytes[1] == stbytes[2])
  783                 return 0;
  784         if (stbytes[2] >= 4 || stbytes[1] != 'M') {
  785                 outb(port+MCD_CTRL, M_PICKLE);
  786                 mcd_data[unit].flags |= MCDNEWMODEL;
  787         }
  788         mcd_data[unit].read_command = MCD_CMDSINGLESPEEDREAD;
  789         switch (stbytes[1]) {
  790         case 'M':
  791                 if (stbytes[2] <= 2) {
  792                         mcd_data[unit].type = MCD_TYPE_LU002S;
  793                         mcd_data[unit].name = "Mitsumi LU002S";
  794                 } else if (stbytes[2] <= 5) {
  795                         mcd_data[unit].type = MCD_TYPE_LU005S;
  796                         mcd_data[unit].name = "Mitsumi LU005S";
  797                 } else {
  798                         mcd_data[unit].type = MCD_TYPE_LU006S;
  799                         mcd_data[unit].name = "Mitsumi LU006S";
  800                 }
  801                 break;
  802         case 'F':
  803                 mcd_data[unit].type = MCD_TYPE_FX001;
  804                 mcd_data[unit].name = "Mitsumi FX001";
  805                 break;
  806         case 'D':
  807                 mcd_data[unit].type = MCD_TYPE_FX001D;
  808                 mcd_data[unit].name = "Mitsumi FX001D";
  809                 mcd_data[unit].read_command = MCD_CMDDOUBLESPEEDREAD;
  810                 break;
  811         default:
  812                 mcd_data[unit].type = MCD_TYPE_UNKNOWN;
  813                 mcd_data[unit].name = "Mitsumi ???";
  814                 break;
  815         }
  816         printf("mcd%d: type %s, version info: %c %x\n", unit, mcd_data[unit].name,
  817                 stbytes[1], stbytes[2]);
  818 
  819         return 4;
  820 }
  821 
  822 
  823 static int
  824 mcd_waitrdy(int port,int dly)
  825 {
  826         int i;
  827 
  828         /* wait until flag port senses status ready */
  829         for (i=0; i<dly; i+=MIN_DELAY) {
  830                 if (!(inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL))
  831                         return 0;
  832                 DELAY(MIN_DELAY);
  833         }
  834         return -1;
  835 }
  836 
  837 static int
  838 mcd_getreply(int unit,int dly)
  839 {
  840         struct  mcd_data *cd = mcd_data + unit;
  841         int     port = cd->iobase;
  842 
  843         /* wait data to become ready */
  844         if (mcd_waitrdy(port,dly)<0) {
  845                 printf("mcd%d: timeout getreply\n",unit);
  846                 return -1;
  847         }
  848 
  849         /* get the data */
  850         return inb(port+mcd_status) & 0xFF;
  851 }
  852 
  853 static int
  854 mcd_getstat(int unit,int sflg)
  855 {
  856         int     i;
  857         struct  mcd_data *cd = mcd_data + unit;
  858         int     port = cd->iobase;
  859 
  860         /* get the status */
  861         if (sflg)
  862                 outb(port+mcd_command, MCD_CMDGETSTAT);
  863         i = mcd_getreply(unit,DELAY_GETREPLY);
  864         if (i<0 || (i & MCD_ST_CMDCHECK)) {
  865                 cd->curr_mode = MCD_MD_UNKNOWN;
  866                 return -1;
  867         }
  868 
  869         cd->status = i;
  870 
  871         if (mcd_setflags(unit,cd) < 0)
  872                 return -2;
  873         return cd->status;
  874 }
  875 
  876 static int
  877 mcd_setflags(int unit, struct mcd_data *cd)
  878 {
  879         /* check flags */
  880         if (    (cd->status & (MCDDSKCHNG|MCDDOOROPEN))
  881             || !(cd->status & MCDDSKIN)) {
  882                 MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n");
  883                 mcd_soft_reset(unit);
  884                 return -1;
  885         }
  886 
  887         if (cd->status & MCDAUDIOBSY)
  888                 cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
  889         else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
  890                 cd->audio_status = CD_AS_PLAY_COMPLETED;
  891         return 0;
  892 }
  893 
  894 static int
  895 mcd_get(int unit, char *buf, int nmax)
  896 {
  897         int i,k;
  898 
  899         for (i=0; i<nmax; i++) {
  900                 /* wait for data */
  901                 if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) {
  902                         printf("mcd%d: timeout mcd_get\n",unit);
  903                         return -1;
  904                 }
  905                 buf[i] = k;
  906         }
  907         return i;
  908 }
  909 
  910 static int
  911 mcd_send(int unit, int cmd,int nretrys)
  912 {
  913         int i,k=0;
  914         int port = mcd_data[unit].iobase;
  915 
  916 /*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/
  917         for (i=0; i<nretrys; i++) {
  918                 outb(port+mcd_command, cmd);
  919                 if ((k=mcd_getstat(unit,0)) != -1)
  920                         break;
  921         }
  922         if (k == -2) {
  923                 printf("mcd%d: media changed\n",unit);
  924                 return -1;
  925         }
  926         if (i == nretrys) {
  927                 printf("mcd%d: mcd_send retry cnt exceeded\n",unit);
  928                 return -1;
  929         }
  930 /*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/
  931         return 0;
  932 }
  933 
  934 static void
  935 hsg2msf(int hsg, bcd_t *msf)
  936 {
  937         hsg += 150;
  938         F_msf(msf) = bin2bcd(hsg % 75);
  939         hsg /= 75;
  940         S_msf(msf) = bin2bcd(hsg % 60);
  941         hsg /= 60;
  942         M_msf(msf) = bin2bcd(hsg);
  943 }
  944 
  945 static int
  946 msf2hsg(bcd_t *msf, int relative)
  947 {
  948         return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 +
  949                 bcd2bin(F_msf(msf)) - (!relative) * 150;
  950 }
  951 
  952 static int
  953 mcd_volinfo(int unit)
  954 {
  955         struct mcd_data *cd = mcd_data + unit;
  956 
  957         /* Just return if we already have it */
  958         if (cd->flags & MCDVOLINFO) return 0;
  959 
  960 /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
  961 
  962         /* send volume info command */
  963         if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0)
  964                 return EIO;
  965 
  966         /* get data */
  967         if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) {
  968                 printf("mcd%d: mcd_volinfo: error read data\n",unit);
  969                 return EIO;
  970         }
  971 
  972         if (cd->volinfo.trk_low > 0 &&
  973             cd->volinfo.trk_high >= cd->volinfo.trk_low
  974            ) {
  975                 cd->flags |= MCDVOLINFO;        /* volinfo is OK */
  976                 return 0;
  977         }
  978 
  979         return EINVAL;
  980 }
  981 
  982 static void
  983 mcdintr(unit)
  984         int unit;
  985 {
  986         MCD_TRACE("stray interrupt\n");
  987 }
  988 
  989 /* state machine to process read requests
  990  * initialize with MCD_S_BEGIN: calculate sizes, and read status
  991  * MCD_S_WAITSTAT: wait for status reply, set mode
  992  * MCD_S_WAITMODE: waits for status reply from set mode, set read command
  993  * MCD_S_WAITREAD: wait for read ready, read data
  994  */
  995 static struct mcd_mbx *mbxsave;
  996 static struct callout_handle tohandle = CALLOUT_HANDLE_INITIALIZER(&tohandle);
  997 
  998 static void
  999 mcd_timeout(void *arg)
 1000 {
 1001         mcd_doread((int)arg, mbxsave);
 1002 }
 1003 
 1004 static void
 1005 mcd_doread(int state, struct mcd_mbx *mbxin)
 1006 {
 1007         struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin;
 1008         int     unit = mbx->unit;
 1009         int     port = mbx->port;
 1010         int     com_port = mbx->port + mcd_command;
 1011         int     data_port = mbx->port + mcd_rdata;
 1012         struct  buf *bp = mbx->bp;
 1013         struct  mcd_data *cd = mcd_data + unit;
 1014 
 1015         int     rm,i,k;
 1016         struct mcd_read2 rbuf;
 1017         int     blknum;
 1018         caddr_t addr;
 1019 
 1020 loop:
 1021         switch (state) {
 1022         case MCD_S_BEGIN:
 1023                 mbx = mbxsave = mbxin;
 1024 
 1025         case MCD_S_BEGIN1:
 1026 retry_status:
 1027                 /* get status */
 1028                 outb(com_port, MCD_CMDGETSTAT);
 1029                 mbx->count = RDELAY_WAITSTAT;
 1030                 tohandle = timeout(mcd_timeout,
 1031                                    (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
 1032                 return;
 1033         case MCD_S_WAITSTAT:
 1034                 untimeout(mcd_timeout,(caddr_t)MCD_S_WAITSTAT, tohandle);
 1035                 if (mbx->count-- >= 0) {
 1036                         if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
 1037                                 timeout(mcd_timeout,
 1038                                     (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
 1039                                 return;
 1040                         }
 1041                         cd->status = inb(port+mcd_status) & 0xFF;
 1042                         if (cd->status & MCD_ST_CMDCHECK)
 1043                                 goto retry_status;
 1044                         if (mcd_setflags(unit,cd) < 0)
 1045                                 goto changed;
 1046                         MCD_TRACE("got WAITSTAT delay=%d\n",
 1047                                 RDELAY_WAITSTAT-mbx->count);
 1048                         /* reject, if audio active */
 1049                         if (cd->status & MCDAUDIOBSY) {
 1050                                 printf("mcd%d: audio is active\n",unit);
 1051                                 goto readerr;
 1052                         }
 1053 
 1054 retry_mode:
 1055                         /* to check for raw/cooked mode */
 1056                         if (cd->flags & MCDREADRAW) {
 1057                                 rm = MCD_MD_RAW;
 1058                                 mbx->sz = MCDRBLK;
 1059                         } else {
 1060                                 rm = MCD_MD_COOKED;
 1061                                 mbx->sz = cd->blksize;
 1062                         }
 1063 
 1064                         if (rm == cd->curr_mode)
 1065                                 goto modedone;
 1066 
 1067                         mbx->count = RDELAY_WAITMODE;
 1068 
 1069                         cd->curr_mode = MCD_MD_UNKNOWN;
 1070                         mbx->mode = rm;
 1071                         mcd_put(com_port, MCD_CMDSETMODE);
 1072                         mcd_put(com_port, rm);
 1073 
 1074                         tohandle = timeout(mcd_timeout,
 1075                                            (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */
 1076                         return;
 1077                 } else {
 1078                         printf("mcd%d: timeout getstatus\n",unit);
 1079                         goto readerr;
 1080                 }
 1081 
 1082         case MCD_S_WAITMODE:
 1083                 untimeout(mcd_timeout,(caddr_t)MCD_S_WAITMODE, tohandle);
 1084                 if (mbx->count-- < 0) {
 1085                         printf("mcd%d: timeout set mode\n",unit);
 1086                         goto readerr;
 1087                 }
 1088                 if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
 1089                         tohandle = timeout(mcd_timeout,
 1090                                            (caddr_t)MCD_S_WAITMODE,hz/100);
 1091                         return;
 1092                 }
 1093                 cd->status = inb(port+mcd_status) & 0xFF;
 1094                 if (cd->status & MCD_ST_CMDCHECK) {
 1095                         cd->curr_mode = MCD_MD_UNKNOWN;
 1096                         goto retry_mode;
 1097                 }
 1098                 if (mcd_setflags(unit,cd) < 0)
 1099                         goto changed;
 1100                 cd->curr_mode = mbx->mode;
 1101                 MCD_TRACE("got WAITMODE delay=%d\n",
 1102                         RDELAY_WAITMODE-mbx->count);
 1103 modedone:
 1104                 /* for first block */
 1105                 mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz;
 1106                 mbx->skip = 0;
 1107 
 1108 nextblock:
 1109                 blknum  = (bp->b_blkno / (mbx->sz/DEV_BSIZE))
 1110                         + mbx->p_offset + mbx->skip/mbx->sz;
 1111 
 1112                 MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n",
 1113                         blknum, bp);
 1114 
 1115                 /* build parameter block */
 1116                 hsg2msf(blknum,rbuf.start_msf);
 1117 retry_read:
 1118                 /* send the read command */
 1119                 disable_intr();
 1120                 mcd_put(com_port,cd->read_command);
 1121                 mcd_put(com_port,rbuf.start_msf[0]);
 1122                 mcd_put(com_port,rbuf.start_msf[1]);
 1123                 mcd_put(com_port,rbuf.start_msf[2]);
 1124                 mcd_put(com_port,0);
 1125                 mcd_put(com_port,0);
 1126                 mcd_put(com_port,1);
 1127                 enable_intr();
 1128 
 1129                 /* Spin briefly (<= 2ms) to avoid missing next block */
 1130                 for (i = 0; i < 20; i++) {
 1131                         k = inb(port+MCD_FLAGS);
 1132                         if (!(k & MFL_DATA_NOT_AVAIL))
 1133                                 goto got_it;
 1134                         DELAY(100);
 1135                 }
 1136 
 1137                 mbx->count = RDELAY_WAITREAD;
 1138                 tohandle = timeout(mcd_timeout,
 1139                                    (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
 1140                 return;
 1141         case MCD_S_WAITREAD:
 1142                 untimeout(mcd_timeout,(caddr_t)MCD_S_WAITREAD, tohandle);
 1143                 if (mbx->count-- > 0) {
 1144                         k = inb(port+MCD_FLAGS);
 1145                         if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */
 1146                                 MCD_TRACE("got data delay=%d\n",
 1147                                         RDELAY_WAITREAD-mbx->count);
 1148                         got_it:
 1149                                 /* data is ready */
 1150                                 addr    = bp->b_data + mbx->skip;
 1151 
 1152                                 outb(port+mcd_ctl2,0x04);       /* XXX */
 1153                                 for (i=0; i<mbx->sz; i++)
 1154                                         *addr++ = inb(data_port);
 1155                                 outb(port+mcd_ctl2,0x0c);       /* XXX */
 1156 
 1157                                 k = inb(port+MCD_FLAGS);
 1158                                 /* If we still have some junk, read it too */
 1159                                 if (!(k & MFL_DATA_NOT_AVAIL)) {
 1160                                         outb(port+mcd_ctl2,0x04);       /* XXX */
 1161                                         (void)inb(data_port);
 1162                                         (void)inb(data_port);
 1163                                         outb(port+mcd_ctl2,0x0c);       /* XXX */
 1164                                 }
 1165 
 1166                                 if (--mbx->nblk > 0) {
 1167                                         mbx->skip += mbx->sz;
 1168                                         goto nextblock;
 1169                                 }
 1170 
 1171                                 /* return buffer */
 1172                                 bp->b_resid = 0;
 1173                                 biodone(bp);
 1174 
 1175                                 cd->flags &= ~(MCDMBXBSY|MCDREADRAW);
 1176                                 mcd_start(mbx->unit);
 1177                                 return;
 1178                         }
 1179                         if (!(k & MFL_STATUS_NOT_AVAIL)) {
 1180                                 cd->status = inb(port+mcd_status) & 0xFF;
 1181                                 if (cd->status & MCD_ST_CMDCHECK)
 1182                                         goto retry_read;
 1183                                 if (mcd_setflags(unit,cd) < 0)
 1184                                         goto changed;
 1185                         }
 1186                         tohandle = timeout(mcd_timeout,
 1187                                            (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
 1188                         return;
 1189                 } else {
 1190                         printf("mcd%d: timeout read data\n",unit);
 1191                         goto readerr;
 1192                 }
 1193         }
 1194 
 1195 readerr:
 1196         if (mbx->retry-- > 0) {
 1197                 printf("mcd%d: retrying\n",unit);
 1198                 state = MCD_S_BEGIN1;
 1199                 goto loop;
 1200         }
 1201 harderr:
 1202         /* invalidate the buffer */
 1203         bp->b_flags |= B_ERROR;
 1204         bp->b_resid = bp->b_bcount;
 1205         biodone(bp);
 1206 
 1207         cd->flags &= ~(MCDMBXBSY|MCDREADRAW);
 1208         mcd_start(mbx->unit);
 1209         return;
 1210 
 1211 changed:
 1212         printf("mcd%d: media changed\n", unit);
 1213         goto harderr;
 1214 
 1215 #ifdef NOTDEF
 1216         printf("mcd%d: unit timeout, resetting\n",mbx->unit);
 1217         outb(mbx->port+mcd_reset,MCD_CMDRESET);
 1218         DELAY(300000);
 1219         (void)mcd_getstat(mbx->unit,1);
 1220         (void)mcd_getstat(mbx->unit,1);
 1221         /*cd->status &= ~MCDDSKCHNG; */
 1222         cd->debug = 1; /* preventive set debug mode */
 1223 
 1224 #endif
 1225 
 1226 }
 1227 
 1228 static int
 1229 mcd_lock_door(int unit, int lock)
 1230 {
 1231         struct mcd_data *cd = mcd_data + unit;
 1232         int port = cd->iobase;
 1233 
 1234         outb(port+mcd_command, MCD_CMDLOCKDRV);
 1235         outb(port+mcd_command, lock);
 1236         if (mcd_getstat(unit,0) == -1)
 1237                 return EIO;
 1238         return 0;
 1239 }
 1240 
 1241 static int
 1242 mcd_close_tray(int unit)
 1243 {
 1244         struct mcd_data *cd = mcd_data + unit;
 1245         int port = cd->iobase;
 1246         int retry, r;
 1247 
 1248         if (mcd_getstat(unit,1) == -1)
 1249                 return EIO;
 1250         if (cd->status & MCDDOOROPEN) {
 1251                 outb(port+mcd_command, MCD_CMDCLOSETRAY);
 1252                 for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) {
 1253                         if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)
 1254                                 (void) tsleep((caddr_t)cd, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC);
 1255                         else {
 1256                                 if ((r = mcd_getstat(unit,0)) == -1)
 1257                                         return EIO;
 1258                                 return 0;
 1259                         }
 1260                 }
 1261                 return ENXIO;
 1262         }
 1263         return 0;
 1264 }
 1265 
 1266 static int
 1267 mcd_eject(int unit)
 1268 {
 1269         struct mcd_data *cd = mcd_data + unit;
 1270         int port = cd->iobase, r;
 1271 
 1272         if (mcd_getstat(unit,1) == -1)    /* detect disk change too */
 1273                 return EIO;
 1274         if (cd->status & MCDDOOROPEN)
 1275                 return 0;
 1276         if ((r = mcd_stop(unit)) == EIO)
 1277                 return r;
 1278         outb(port+mcd_command, MCD_CMDEJECTDISK);
 1279         if (mcd_getstat(unit,0) == -1)
 1280                 return EIO;
 1281         return 0;
 1282 }
 1283 
 1284 static int
 1285 mcd_inject(int unit)
 1286 {
 1287         struct mcd_data *cd = mcd_data + unit;
 1288 
 1289         if (mcd_getstat(unit,1) == -1)    /* detect disk change too */
 1290                 return EIO;
 1291         if (cd->status & MCDDOOROPEN)
 1292                 return mcd_close_tray(unit);
 1293         return 0;
 1294 }
 1295 
 1296 static int
 1297 mcd_hard_reset(int unit)
 1298 {
 1299         struct mcd_data *cd = mcd_data + unit;
 1300         int port = cd->iobase;
 1301 
 1302         outb(port+mcd_reset,MCD_CMDRESET);
 1303         cd->curr_mode = MCD_MD_UNKNOWN;
 1304         cd->audio_status = CD_AS_AUDIO_INVALID;
 1305         return 0;
 1306 }
 1307 
 1308 static void
 1309 mcd_soft_reset(int unit)
 1310 {
 1311         struct mcd_data *cd = mcd_data + unit;
 1312         int i;
 1313 
 1314         cd->flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL);
 1315         cd->curr_mode = MCD_MD_UNKNOWN;
 1316         for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0;
 1317         cd->audio_status = CD_AS_AUDIO_INVALID;
 1318 }
 1319 
 1320 static int
 1321 mcd_setmode(int unit, int mode)
 1322 {
 1323         struct mcd_data *cd = mcd_data + unit;
 1324         int port = cd->iobase;
 1325         int retry, st;
 1326 
 1327         if (cd->curr_mode == mode)
 1328                 return 0;
 1329         if (cd->debug)
 1330                 printf("mcd%d: setting mode to %d\n", unit, mode);
 1331         for(retry=0; retry<MCD_RETRYS; retry++)
 1332         {
 1333                 cd->curr_mode = MCD_MD_UNKNOWN;
 1334                 outb(port+mcd_command, MCD_CMDSETMODE);
 1335                 outb(port+mcd_command, mode);
 1336                 if ((st = mcd_getstat(unit, 0)) >= 0) {
 1337                         cd->curr_mode = mode;
 1338                         return 0;
 1339                 }
 1340                 if (st == -2) {
 1341                         printf("mcd%d: media changed\n", unit);
 1342                         break;
 1343                 }
 1344         }
 1345 
 1346         return -1;
 1347 }
 1348 
 1349 static int
 1350 mcd_toc_header(int unit, struct ioc_toc_header *th)
 1351 {
 1352         struct mcd_data *cd = mcd_data + unit;
 1353         int r;
 1354 
 1355         if ((r = mcd_volinfo(unit)) != 0)
 1356                 return r;
 1357 
 1358         th->starting_track = bcd2bin(cd->volinfo.trk_low);
 1359         th->ending_track = bcd2bin(cd->volinfo.trk_high);
 1360         th->len = 2 * sizeof(u_char) /* start & end tracks */ +
 1361                   (th->ending_track + 1 - th->starting_track + 1) *
 1362                   sizeof(struct cd_toc_entry);
 1363 
 1364         return 0;
 1365 }
 1366 
 1367 static int
 1368 mcd_read_toc(int unit)
 1369 {
 1370         struct mcd_data *cd = mcd_data + unit;
 1371         struct ioc_toc_header th;
 1372         struct mcd_qchninfo q;
 1373         int rc, trk, idx, retry;
 1374 
 1375         /* Only read TOC if needed */
 1376         if (cd->flags & MCDTOC)
 1377                 return 0;
 1378 
 1379         if (cd->debug)
 1380                 printf("mcd%d: reading toc header\n", unit);
 1381 
 1382         if ((rc = mcd_toc_header(unit, &th)) != 0)
 1383                 return rc;
 1384 
 1385         if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0)
 1386                 return EIO;
 1387 
 1388         if (mcd_setmode(unit, MCD_MD_TOC) != 0)
 1389                 return EIO;
 1390 
 1391         if (cd->debug)
 1392                 printf("mcd%d: get_toc reading qchannel info\n",unit);
 1393 
 1394         for(trk=th.starting_track; trk<=th.ending_track; trk++)
 1395                 cd->toc[trk].idx_no = 0;
 1396         trk = th.ending_track - th.starting_track + 1;
 1397         for(retry=0; retry<600 && trk>0; retry++)
 1398         {
 1399                 if (mcd_getqchan(unit, &q) < 0) break;
 1400                 idx = bcd2bin(q.idx_no);
 1401                 if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) {
 1402                         if (cd->toc[idx].idx_no == 0) {
 1403                                 cd->toc[idx] = q;
 1404                                 trk--;
 1405                         }
 1406                 }
 1407         }
 1408 
 1409         if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
 1410                 return EIO;
 1411 
 1412         if (trk != 0)
 1413                 return ENXIO;
 1414 
 1415         /* add a fake last+1 */
 1416         idx = th.ending_track + 1;
 1417         cd->toc[idx].control = cd->toc[idx-1].control;
 1418         cd->toc[idx].addr_type = cd->toc[idx-1].addr_type;
 1419         cd->toc[idx].trk_no = 0;
 1420         cd->toc[idx].idx_no = MCD_LASTPLUS1;
 1421         cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0];
 1422         cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1];
 1423         cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2];
 1424 
 1425         if (cd->debug)
 1426         { int i;
 1427         for (i = th.starting_track; i <= idx; i++)
 1428                 printf("mcd%d: trk %d idx %d pos %d %d %d\n",
 1429                         unit, i,
 1430                         cd->toc[i].idx_no > 0x99 ? cd->toc[i].idx_no :
 1431                         bcd2bin(cd->toc[i].idx_no),
 1432                         bcd2bin(cd->toc[i].hd_pos_msf[0]),
 1433                         bcd2bin(cd->toc[i].hd_pos_msf[1]),
 1434                         bcd2bin(cd->toc[i].hd_pos_msf[2]));
 1435         }
 1436 
 1437         cd->flags |= MCDTOC;
 1438 
 1439         return 0;
 1440 }
 1441 
 1442 #if 0
 1443 static int
 1444 mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te)
 1445 {
 1446         struct mcd_data *cd = mcd_data + unit;
 1447         struct ioc_toc_header th;
 1448         int rc, trk;
 1449 
 1450         if (te->address_format != CD_MSF_FORMAT
 1451             && te->address_format != CD_LBA_FORMAT)
 1452                 return EINVAL;
 1453 
 1454         /* Copy the toc header */
 1455         if ((rc = mcd_toc_header(unit, &th)) != 0)
 1456                 return rc;
 1457 
 1458         /* verify starting track */
 1459         trk = te->track;
 1460         if (trk == 0)
 1461                 trk = th.starting_track;
 1462         else if (trk == MCD_LASTPLUS1)
 1463                 trk = th.ending_track + 1;
 1464         else if (trk < th.starting_track || trk > th.ending_track + 1)
 1465                 return EINVAL;
 1466 
 1467         /* Make sure we have a valid toc */
 1468         if ((rc=mcd_read_toc(unit)) != 0)
 1469                 return rc;
 1470 
 1471         /* Copy the TOC data. */
 1472         if (cd->toc[trk].idx_no == 0)
 1473                 return EIO;
 1474 
 1475         te->entry.control = cd->toc[trk].control;
 1476         te->entry.addr_type = cd->toc[trk].addr_type;
 1477         te->entry.track =
 1478                 cd->toc[trk].idx_no > 0x99 ? cd->toc[trk].idx_no :
 1479                 bcd2bin(cd->toc[trk].idx_no);
 1480         switch (te->address_format) {
 1481         case CD_MSF_FORMAT:
 1482                 te->entry.addr.msf.unused = 0;
 1483                 te->entry.addr.msf.minute = bcd2bin(cd->toc[trk].hd_pos_msf[0]);
 1484                 te->entry.addr.msf.second = bcd2bin(cd->toc[trk].hd_pos_msf[1]);
 1485                 te->entry.addr.msf.frame = bcd2bin(cd->toc[trk].hd_pos_msf[2]);
 1486                 break;
 1487         case CD_LBA_FORMAT:
 1488                 te->entry.addr.lba = htonl(msf2hsg(cd->toc[trk].hd_pos_msf, 0));
 1489                 break;
 1490         }
 1491         return 0;
 1492 }
 1493 #endif
 1494 
 1495 static int
 1496 mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te)
 1497 {
 1498         struct mcd_data *cd = mcd_data + unit;
 1499         struct cd_toc_entry entries[MCD_MAXTOCS];
 1500         struct ioc_toc_header th;
 1501         int rc, n, trk, len;
 1502 
 1503         if (   te->data_len < sizeof(entries[0])
 1504             || (te->data_len % sizeof(entries[0])) != 0
 1505             || te->address_format != CD_MSF_FORMAT
 1506             && te->address_format != CD_LBA_FORMAT
 1507            )
 1508                 return EINVAL;
 1509 
 1510         /* Copy the toc header */
 1511         if ((rc = mcd_toc_header(unit, &th)) != 0)
 1512                 return rc;
 1513 
 1514         /* verify starting track */
 1515         trk = te->starting_track;
 1516         if (trk == 0)
 1517                 trk = th.starting_track;
 1518         else if (trk == MCD_LASTPLUS1)
 1519                 trk = th.ending_track + 1;
 1520         else if (trk < th.starting_track || trk > th.ending_track + 1)
 1521                 return EINVAL;
 1522 
 1523         len = ((th.ending_track + 1 - trk) + 1) *
 1524                 sizeof(entries[0]);
 1525         if (te->data_len < len)
 1526                 len = te->data_len;
 1527         if (len > sizeof(entries))
 1528                 return EINVAL;
 1529 
 1530         /* Make sure we have a valid toc */
 1531         if ((rc=mcd_read_toc(unit)) != 0)
 1532                 return rc;
 1533 
 1534         /* Copy the TOC data. */
 1535         for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) {
 1536                 if (cd->toc[trk].idx_no == 0)
 1537                         continue;
 1538                 entries[n].control = cd->toc[trk].control;
 1539                 entries[n].addr_type = cd->toc[trk].addr_type;
 1540                 entries[n].track =
 1541                         cd->toc[trk].idx_no > 0x99 ? cd->toc[trk].idx_no :
 1542                         bcd2bin(cd->toc[trk].idx_no);
 1543                 switch (te->address_format) {
 1544                 case CD_MSF_FORMAT:
 1545                         entries[n].addr.msf.unused = 0;
 1546                         entries[n].addr.msf.minute = bcd2bin(cd->toc[trk].hd_pos_msf[0]);
 1547                         entries[n].addr.msf.second = bcd2bin(cd->toc[trk].hd_pos_msf[1]);
 1548                         entries[n].addr.msf.frame = bcd2bin(cd->toc[trk].hd_pos_msf[2]);
 1549                         break;
 1550                 case CD_LBA_FORMAT:
 1551                         entries[n].addr.lba = htonl(msf2hsg(cd->toc[trk].hd_pos_msf, 0));
 1552                         break;
 1553                 }
 1554                 len -= sizeof(struct cd_toc_entry);
 1555                 n++;
 1556         }
 1557 
 1558         /* copy the data back */
 1559         return copyout(entries, te->data, n * sizeof(struct cd_toc_entry));
 1560 }
 1561 
 1562 static int
 1563 mcd_stop(int unit)
 1564 {
 1565         struct mcd_data *cd = mcd_data + unit;
 1566 
 1567         /* Verify current status */
 1568         if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS &&
 1569             cd->audio_status != CD_AS_PLAY_PAUSED &&
 1570             cd->audio_status != CD_AS_PLAY_COMPLETED) {
 1571                 if (cd->debug)
 1572                         printf("mcd%d: stop attempted when not playing, audio status %d\n",
 1573                                 unit, cd->audio_status);
 1574                 return EINVAL;
 1575         }
 1576         if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
 1577                 if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0)
 1578                         return EIO;
 1579         cd->audio_status = CD_AS_PLAY_COMPLETED;
 1580         return 0;
 1581 }
 1582 
 1583 static int
 1584 mcd_getqchan(int unit, struct mcd_qchninfo *q)
 1585 {
 1586         struct mcd_data *cd = mcd_data + unit;
 1587 
 1588         if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0)
 1589                 return -1;
 1590         if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0)
 1591                 return -1;
 1592         if (cd->debug) {
 1593                 printf("mcd%d: getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n",
 1594                 unit,
 1595                 q->control, q->addr_type, bcd2bin(q->trk_no),
 1596                 bcd2bin(q->idx_no),
 1597                 bcd2bin(q->trk_size_msf[0]), bcd2bin(q->trk_size_msf[1]),
 1598                 bcd2bin(q->trk_size_msf[2]),
 1599                 bcd2bin(q->hd_pos_msf[0]), bcd2bin(q->hd_pos_msf[1]),
 1600                 bcd2bin(q->hd_pos_msf[2]));
 1601         }
 1602         return 0;
 1603 }
 1604 
 1605 static int
 1606 mcd_subchan(int unit, struct ioc_read_subchannel *sc)
 1607 {
 1608         struct mcd_data *cd = mcd_data + unit;
 1609         struct mcd_qchninfo q;
 1610         struct cd_sub_channel_info data;
 1611         int lba;
 1612 
 1613         if (cd->debug)
 1614                 printf("mcd%d: subchan af=%d, df=%d\n", unit,
 1615                         sc->address_format,
 1616                         sc->data_format);
 1617 
 1618         if (sc->address_format != CD_MSF_FORMAT &&
 1619             sc->address_format != CD_LBA_FORMAT)
 1620                 return EINVAL;
 1621 
 1622         if (sc->data_format != CD_CURRENT_POSITION &&
 1623             sc->data_format != CD_MEDIA_CATALOG)
 1624                 return EINVAL;
 1625 
 1626         if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
 1627                 return EIO;
 1628 
 1629         if (mcd_getqchan(unit, &q) < 0)
 1630                 return EIO;
 1631 
 1632         data.header.audio_status = cd->audio_status;
 1633         data.what.position.data_format = sc->data_format;
 1634 
 1635         switch (sc->data_format) {
 1636         case CD_MEDIA_CATALOG:
 1637                 data.what.media_catalog.mc_valid = 1;
 1638                 data.what.media_catalog.mc_number[0] = '\0';
 1639                 break;
 1640 
 1641         case CD_CURRENT_POSITION:
 1642                 data.what.position.control = q.control;
 1643                 data.what.position.addr_type = q.addr_type;
 1644                 data.what.position.track_number = bcd2bin(q.trk_no);
 1645                 data.what.position.index_number = bcd2bin(q.idx_no);
 1646                 switch (sc->address_format) {
 1647                 case CD_MSF_FORMAT:
 1648                         data.what.position.reladdr.msf.unused = 0;
 1649                         data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]);
 1650                         data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]);
 1651                         data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]);
 1652                         data.what.position.absaddr.msf.unused = 0;
 1653                         data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]);
 1654                         data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]);
 1655                         data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]);
 1656                         break;
 1657                 case CD_LBA_FORMAT:
 1658                         lba = msf2hsg(q.trk_size_msf, 1);
 1659                         /*
 1660                          * Pre-gap has index number of 0, and decreasing MSF
 1661                          * address.  Must be converted to negative LBA, per
 1662                          * SCSI spec.
 1663                          */
 1664                         if (data.what.position.index_number == 0)
 1665                                 lba = -lba;
 1666                         data.what.position.reladdr.lba = htonl(lba);
 1667                         data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0));
 1668                         break;
 1669                 }
 1670                 break;
 1671         }
 1672 
 1673         return copyout(&data, sc->data, min(sizeof(struct cd_sub_channel_info), sc->data_len));
 1674 }
 1675 
 1676 static int
 1677 mcd_playmsf(int unit, struct ioc_play_msf *p)
 1678 {
 1679         struct mcd_data *cd = mcd_data + unit;
 1680         struct mcd_read2 pb;
 1681 
 1682         if (cd->debug)
 1683                 printf("mcd%d: playmsf: from %d:%d.%d to %d:%d.%d\n",
 1684                     unit,
 1685                     p->start_m, p->start_s, p->start_f,
 1686                     p->end_m, p->end_s, p->end_f);
 1687 
 1688         if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
 1689             (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) ||
 1690             (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) >
 1691             M_msf(cd->volinfo.vol_msf) * 60 * 75 +
 1692             S_msf(cd->volinfo.vol_msf) * 75 +
 1693             F_msf(cd->volinfo.vol_msf))
 1694                 return EINVAL;
 1695 
 1696         pb.start_msf[0] = bin2bcd(p->start_m);
 1697         pb.start_msf[1] = bin2bcd(p->start_s);
 1698         pb.start_msf[2] = bin2bcd(p->start_f);
 1699         pb.end_msf[0] = bin2bcd(p->end_m);
 1700         pb.end_msf[1] = bin2bcd(p->end_s);
 1701         pb.end_msf[2] = bin2bcd(p->end_f);
 1702 
 1703         if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
 1704                 return EIO;
 1705 
 1706         return mcd_play(unit, &pb);
 1707 }
 1708 
 1709 static int
 1710 mcd_playtracks(int unit, struct ioc_play_track *pt)
 1711 {
 1712         struct mcd_data *cd = mcd_data + unit;
 1713         struct mcd_read2 pb;
 1714         int a = pt->start_track;
 1715         int z = pt->end_track;
 1716         int rc, i;
 1717 
 1718         if ((rc = mcd_read_toc(unit)) != 0)
 1719                 return rc;
 1720 
 1721         if (cd->debug)
 1722                 printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit,
 1723                         a, pt->start_index, z, pt->end_index);
 1724 
 1725         if (   a < bcd2bin(cd->volinfo.trk_low)
 1726             || a > bcd2bin(cd->volinfo.trk_high)
 1727             || a > z
 1728             || z < bcd2bin(cd->volinfo.trk_low)
 1729             || z > bcd2bin(cd->volinfo.trk_high))
 1730                 return EINVAL;
 1731 
 1732         for (i = 0; i < 3; i++) {
 1733                 pb.start_msf[i] = cd->toc[a].hd_pos_msf[i];
 1734                 pb.end_msf[i] = cd->toc[z+1].hd_pos_msf[i];
 1735         }
 1736 
 1737         if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
 1738                 return EIO;
 1739 
 1740         return mcd_play(unit, &pb);
 1741 }
 1742 
 1743 static int
 1744 mcd_playblocks(int unit, struct ioc_play_blocks *p)
 1745 {
 1746         struct mcd_data *cd = mcd_data + unit;
 1747         struct mcd_read2 pb;
 1748 
 1749         if (cd->debug)
 1750                 printf("mcd%d: playblocks: blkno %d length %d\n",
 1751                     unit, p->blk, p->len);
 1752 
 1753         if (p->blk > cd->disksize || p->len > cd->disksize ||
 1754             p->blk < 0 || p->len < 0 ||
 1755             (p->blk + p->len) > cd->disksize)
 1756                 return EINVAL;
 1757 
 1758         hsg2msf(p->blk, pb.start_msf);
 1759         hsg2msf(p->blk + p->len, pb.end_msf);
 1760 
 1761         if (mcd_setmode(unit, MCD_MD_COOKED) != 0)
 1762                 return EIO;
 1763 
 1764         return mcd_play(unit, &pb);
 1765 }
 1766 
 1767 static int
 1768 mcd_play(int unit, struct mcd_read2 *pb)
 1769 {
 1770         struct mcd_data *cd = mcd_data + unit;
 1771         int com_port = cd->iobase + mcd_command;
 1772         int retry, st = -1, status;
 1773 
 1774         cd->lastpb = *pb;
 1775         for(retry=0; retry<MCD_RETRYS; retry++) {
 1776 
 1777                 disable_intr();
 1778                 outb(com_port, MCD_CMDSINGLESPEEDREAD);
 1779                 outb(com_port, pb->start_msf[0]);
 1780                 outb(com_port, pb->start_msf[1]);
 1781                 outb(com_port, pb->start_msf[2]);
 1782                 outb(com_port, pb->end_msf[0]);
 1783                 outb(com_port, pb->end_msf[1]);
 1784                 outb(com_port, pb->end_msf[2]);
 1785                 enable_intr();
 1786 
 1787                 status=mcd_getstat(unit, 0);
 1788                 if (status == -1)
 1789                         continue;
 1790                 else if (status != -2)
 1791                         st = 0;
 1792                 break;
 1793         }
 1794 
 1795         if (status == -2) {
 1796                 printf("mcd%d: media changed\n", unit);
 1797                 return ENXIO;
 1798         }
 1799         if (cd->debug)
 1800                 printf("mcd%d: mcd_play retry=%d, status=0x%02x\n", unit, retry, status);
 1801         if (st < 0)
 1802                 return ENXIO;
 1803         cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
 1804         return 0;
 1805 }
 1806 
 1807 static int
 1808 mcd_pause(int unit)
 1809 {
 1810         struct mcd_data *cd = mcd_data + unit;
 1811         struct mcd_qchninfo q;
 1812         int rc;
 1813 
 1814         /* Verify current status */
 1815         if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS &&
 1816             cd->audio_status != CD_AS_PLAY_PAUSED) {
 1817                 if (cd->debug)
 1818                         printf("mcd%d: pause attempted when not playing, audio status %d\n",
 1819                                unit, cd->audio_status);
 1820                 return EINVAL;
 1821         }
 1822 
 1823         /* Get the current position */
 1824         if (mcd_getqchan(unit, &q) < 0)
 1825                 return EIO;
 1826 
 1827         /* Copy it into lastpb */
 1828         cd->lastpb.start_msf[0] = q.hd_pos_msf[0];
 1829         cd->lastpb.start_msf[1] = q.hd_pos_msf[1];
 1830         cd->lastpb.start_msf[2] = q.hd_pos_msf[2];
 1831 
 1832         /* Stop playing */
 1833         if ((rc=mcd_stop(unit)) != 0)
 1834                 return rc;
 1835 
 1836         /* Set the proper status and exit */
 1837         cd->audio_status = CD_AS_PLAY_PAUSED;
 1838         return 0;
 1839 }
 1840 
 1841 static int
 1842 mcd_resume(int unit)
 1843 {
 1844         struct mcd_data *cd = mcd_data + unit;
 1845 
 1846         if (cd->audio_status != CD_AS_PLAY_PAUSED)
 1847                 return EINVAL;
 1848         return mcd_play(unit, &cd->lastpb);
 1849 }
 1850 
 1851 
 1852 static mcd_devsw_installed = 0;
 1853 
 1854 static void     mcd_drvinit(void *unused)
 1855 {
 1856 
 1857         if( ! mcd_devsw_installed ) {
 1858                 cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &mcd_cdevsw);
 1859                 mcd_devsw_installed = 1;
 1860         }
 1861 }
 1862 
 1863 SYSINIT(mcddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mcd_drvinit,NULL)
 1864 
 1865 
 1866 #endif /* NMCD > 0 */

Cache object: 2f619628d88b673c2df1a67529750485


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