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

Cache object: 2bc20f505bb48724f2b5a1a0f10c5eea


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