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