File:  [DragonFly] / src / sys / dev / disk / mcd / Attic / mcd.c
Revision 1.9: download - view: text, annotated - select for diffs
Wed May 19 22:52:41 2004 UTC (10 years, 3 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

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