xref: /netbsd-src/sys/dev/isa/mcd.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: mcd.c,v 1.67 2000/07/06 02:02:48 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Charles M. Hannum.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * Copyright 1993 by Holger Veit (data part)
21  * Copyright 1993 by Brian Moore (audio part)
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions
26  * are met:
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright
30  *    notice, this list of conditions and the following disclaimer in the
31  *    documentation and/or other materials provided with the distribution.
32  * 3. All advertising materials mentioning features or use of this software
33  *    must display the following acknowledgement:
34  *	This software was developed by Holger Veit and Brian Moore
35  *      for use with "386BSD" and similar operating systems.
36  *    "Similar operating systems" includes mainly non-profit oriented
37  *    systems for research and education, including but not restricted to
38  *    "NetBSD", "FreeBSD", "Mach" (by CMU).
39  * 4. Neither the name of the developer(s) nor the name "386BSD"
40  *    may be used to endorse or promote products derived from this
41  *    software without specific prior written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
44  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER(S) BE
47  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
48  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
49  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
51  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55 
56 /*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
57 
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/callout.h>
62 #include <sys/kernel.h>
63 #include <sys/proc.h>
64 #include <sys/conf.h>
65 #include <sys/file.h>
66 #include <sys/buf.h>
67 #include <sys/stat.h>
68 #include <sys/uio.h>
69 #include <sys/ioctl.h>
70 #include <sys/cdio.h>
71 #include <sys/errno.h>
72 #include <sys/disklabel.h>
73 #include <sys/device.h>
74 #include <sys/disk.h>
75 
76 #include <machine/cpu.h>
77 #include <machine/intr.h>
78 #include <machine/bus.h>
79 
80 #include <dev/isa/isavar.h>
81 #include <dev/isa/mcdreg.h>
82 
83 #ifndef MCDDEBUG
84 #define MCD_TRACE(fmt,a,b,c,d)
85 #else
86 #define MCD_TRACE(fmt,a,b,c,d)	{if (sc->debug) {printf("%s: st=%02x: ", sc->sc_dev.dv_xname, sc->status); printf(fmt,a,b,c,d);}}
87 #endif
88 
89 #define	MCDPART(dev)	DISKPART(dev)
90 #define	MCDUNIT(dev)	DISKUNIT(dev)
91 
92 /* toc */
93 #define MCD_MAXTOCS	104	/* from the Linux driver */
94 
95 /* control promiscuous match */
96 #include "opt_mcd_promisc.h"
97 
98 #ifdef MCD_PROMISC
99 int mcd_promisc = 1;
100 #else
101 int mcd_promisc = 0;
102 #endif
103 
104 struct mcd_mbx {
105 	int		retry, count;
106 	struct buf	*bp;
107 	daddr_t		blkno;
108 	int		nblk;
109 	int		sz;
110 	u_long		skip;
111 	int		state;
112 #define	MCD_S_IDLE	0
113 #define MCD_S_BEGIN	1
114 #define MCD_S_WAITMODE	2
115 #define MCD_S_WAITREAD	3
116 	int		mode;
117 };
118 
119 struct mcd_softc {
120 	struct	device sc_dev;
121 	struct	disk sc_dk;
122 	void *sc_ih;
123 
124 	struct callout sc_pintr_ch;
125 
126 	bus_space_tag_t		sc_iot;
127 	bus_space_handle_t	sc_ioh;
128 
129 	int	irq, drq;
130 
131 	char	*type;
132 	int	flags;
133 #define	MCDF_LOCKED	0x01
134 #define	MCDF_WANTED	0x02
135 #define	MCDF_WLABEL	0x04	/* label is writable */
136 #define	MCDF_LABELLING	0x08	/* writing label */
137 #define	MCDF_LOADED	0x10	/* parameters loaded */
138 	short	status;
139 	short	audio_status;
140 	int	blksize;
141 	u_long	disksize;
142 	struct	mcd_volinfo volinfo;
143 	union	mcd_qchninfo toc[MCD_MAXTOCS];
144 	struct	mcd_command lastpb;
145 	struct	mcd_mbx mbx;
146 	int	lastmode;
147 #define	MCD_MD_UNKNOWN	-1
148 	int	lastupc;
149 #define	MCD_UPC_UNKNOWN	-1
150 	struct buf_queue buf_queue;
151 	int	active;
152 	u_char	readcmd;
153 	u_char	debug;
154 	u_char	probe;
155 };
156 
157 /* prototypes */
158 /* XXX does not belong here */
159 cdev_decl(mcd);
160 bdev_decl(mcd);
161 
162 static int bcd2bin __P((bcd_t));
163 static bcd_t bin2bcd __P((int));
164 static void hsg2msf __P((int, bcd_t *));
165 static daddr_t msf2hsg __P((bcd_t *, int));
166 
167 int mcd_playtracks __P((struct mcd_softc *, struct ioc_play_track *));
168 int mcd_playmsf __P((struct mcd_softc *, struct ioc_play_msf *));
169 int mcd_playblocks __P((struct mcd_softc *, struct ioc_play_blocks *));
170 int mcd_stop __P((struct mcd_softc *));
171 int mcd_eject __P((struct mcd_softc *));
172 int mcd_read_subchannel __P((struct mcd_softc *, struct ioc_read_subchannel *));
173 int mcd_pause __P((struct mcd_softc *));
174 int mcd_resume __P((struct mcd_softc *));
175 int mcd_toc_header __P((struct mcd_softc *, struct ioc_toc_header *));
176 int mcd_toc_entries __P((struct mcd_softc *, struct ioc_read_toc_entry *));
177 
178 int mcd_getreply __P((struct mcd_softc *));
179 int mcd_getstat __P((struct mcd_softc *));
180 int mcd_getresult __P((struct mcd_softc *, struct mcd_result *));
181 void mcd_setflags __P((struct mcd_softc *));
182 int mcd_get __P((struct mcd_softc *, char *, int));
183 int mcd_send __P((struct mcd_softc *, struct mcd_mbox *, int));
184 int mcdintr __P((void *));
185 void mcd_soft_reset __P((struct mcd_softc *));
186 int mcd_hard_reset __P((struct mcd_softc *));
187 int mcd_setmode __P((struct mcd_softc *, int));
188 int mcd_setupc __P((struct mcd_softc *, int));
189 int mcd_read_toc __P((struct mcd_softc *));
190 int mcd_getqchan __P((struct mcd_softc *, union mcd_qchninfo *, int));
191 int mcd_setlock __P((struct mcd_softc *, int));
192 
193 int mcd_find __P((bus_space_tag_t, bus_space_handle_t, struct mcd_softc *));
194 int mcdprobe __P((struct device *, struct cfdata *, void *));
195 void mcdattach __P((struct device *, struct device *, void *));
196 
197 struct cfattach mcd_ca = {
198 	sizeof(struct mcd_softc), mcdprobe, mcdattach
199 };
200 
201 extern struct cfdriver mcd_cd;
202 
203 void	mcdgetdefaultlabel __P((struct mcd_softc *, struct disklabel *));
204 void	mcdgetdisklabel __P((struct mcd_softc *));
205 int	mcd_get_parms __P((struct mcd_softc *));
206 void	mcdstrategy __P((struct buf *));
207 void	mcdstart __P((struct mcd_softc *));
208 int	mcdlock __P((struct mcd_softc *));
209 void	mcdunlock __P((struct mcd_softc *));
210 void	mcd_pseudointr __P((void *));
211 
212 struct dkdriver mcddkdriver = { mcdstrategy };
213 
214 #define MCD_RETRIES	3
215 #define MCD_RDRETRIES	3
216 
217 /* several delays */
218 #define RDELAY_WAITMODE	300
219 #define RDELAY_WAITREAD	800
220 
221 #define	DELAY_GRANULARITY	25	/* 25us */
222 #define DELAY_GETREPLY		100000	/* 100000 * 25us */
223 
224 void
225 mcdattach(parent, self, aux)
226 	struct device *parent, *self;
227 	void *aux;
228 {
229 	struct mcd_softc *sc = (void *)self;
230 	struct isa_attach_args *ia = aux;
231 	bus_space_tag_t iot = ia->ia_iot;
232 	bus_space_handle_t ioh;
233 	struct mcd_mbox mbx;
234 
235 	/* Map i/o space */
236 	if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh)) {
237 		printf(": can't map i/o space\n");
238 		return;
239 	}
240 
241 	sc->sc_iot = iot;
242 	sc->sc_ioh = ioh;
243 
244 	sc->probe = 0;
245 	sc->debug = 0;
246 
247 	if (!mcd_find(iot, ioh, sc)) {
248 		printf(": mcd_find failed\n");
249 		return;
250 	}
251 
252 	BUFQ_INIT(&sc->buf_queue);
253 	callout_init(&sc->sc_pintr_ch);
254 
255 	/*
256 	 * Initialize and attach the disk structure.
257 	 */
258 	sc->sc_dk.dk_driver = &mcddkdriver;
259 	sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
260 	disk_attach(&sc->sc_dk);
261 
262 	printf(": model %s\n", sc->type != 0 ? sc->type : "unknown");
263 
264 	(void) mcd_setlock(sc, MCD_LK_UNLOCK);
265 
266 	mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
267 	mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
268 	mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE;
269 	mbx.cmd.data.config.data1 = 0x01;
270 	mbx.res.length = 0;
271 	(void) mcd_send(sc, &mbx, 0);
272 
273 	mcd_soft_reset(sc);
274 
275 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
276 	    IPL_BIO, mcdintr, sc);
277 }
278 
279 /*
280  * Wait interruptibly for an exclusive lock.
281  *
282  * XXX
283  * Several drivers do this; it should be abstracted and made MP-safe.
284  */
285 int
286 mcdlock(sc)
287 	struct mcd_softc *sc;
288 {
289 	int error;
290 
291 	while ((sc->flags & MCDF_LOCKED) != 0) {
292 		sc->flags |= MCDF_WANTED;
293 		if ((error = tsleep(sc, PRIBIO | PCATCH, "mcdlck", 0)) != 0)
294 			return error;
295 	}
296 	sc->flags |= MCDF_LOCKED;
297 	return 0;
298 }
299 
300 /*
301  * Unlock and wake up any waiters.
302  */
303 void
304 mcdunlock(sc)
305 	struct mcd_softc *sc;
306 {
307 
308 	sc->flags &= ~MCDF_LOCKED;
309 	if ((sc->flags & MCDF_WANTED) != 0) {
310 		sc->flags &= ~MCDF_WANTED;
311 		wakeup(sc);
312 	}
313 }
314 
315 int
316 mcdopen(dev, flag, fmt, p)
317 	dev_t dev;
318 	int flag, fmt;
319 	struct proc *p;
320 {
321 	int error, part;
322 	struct mcd_softc *sc;
323 
324 	sc = device_lookup(&mcd_cd, MCDUNIT(dev));
325 	if (sc == NULL)
326 		return ENXIO;
327 
328 	if ((error = mcdlock(sc)) != 0)
329 		return error;
330 
331 	if (sc->sc_dk.dk_openmask != 0) {
332 		/*
333 		 * If any partition is open, but the disk has been invalidated,
334 		 * disallow further opens.
335 		 */
336 		if ((sc->flags & MCDF_LOADED) == 0) {
337 			error = EIO;
338 			goto bad3;
339 		}
340 	} else {
341 		/*
342 		 * Lock the drawer.  This will also notice any pending disk
343 		 * change or door open indicator and clear the MCDF_LOADED bit
344 		 * if necessary.
345 		 */
346 		(void) mcd_setlock(sc, MCD_LK_LOCK);
347 
348 		if ((sc->flags & MCDF_LOADED) == 0) {
349 			/* Partially reset the state. */
350 			sc->lastmode = MCD_MD_UNKNOWN;
351 			sc->lastupc = MCD_UPC_UNKNOWN;
352 
353 			sc->flags |= MCDF_LOADED;
354 
355 			/* Set the mode, causing the disk to spin up. */
356 			if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
357 				goto bad2;
358 
359 			/* Load the physical device parameters. */
360 			if (mcd_get_parms(sc) != 0) {
361 				error = ENXIO;
362 				goto bad2;
363 			}
364 
365 			/* Read the table of contents. */
366 			if ((error = mcd_read_toc(sc)) != 0)
367 				goto bad2;
368 
369 			/* Fabricate a disk label. */
370 			mcdgetdisklabel(sc);
371 		}
372 	}
373 
374 	MCD_TRACE("open: partition=%d disksize=%d blksize=%d\n", part,
375 	    sc->disksize, sc->blksize, 0);
376 
377 	part = MCDPART(dev);
378 
379 	/* Check that the partition exists. */
380 	if (part != RAW_PART &&
381 	    (part >= sc->sc_dk.dk_label->d_npartitions ||
382 	     sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
383 		error = ENXIO;
384 		goto bad;
385 	}
386 
387 	/* Insure only one open at a time. */
388 	switch (fmt) {
389 	case S_IFCHR:
390 		sc->sc_dk.dk_copenmask |= (1 << part);
391 		break;
392 	case S_IFBLK:
393 		sc->sc_dk.dk_bopenmask |= (1 << part);
394 		break;
395 	}
396 	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
397 
398 	mcdunlock(sc);
399 	return 0;
400 
401 bad2:
402 	sc->flags &= ~MCDF_LOADED;
403 
404 bad:
405 	if (sc->sc_dk.dk_openmask == 0) {
406 #if 0
407 		(void) mcd_setmode(sc, MCD_MD_SLEEP);
408 #endif
409 		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
410 	}
411 
412 bad3:
413 	mcdunlock(sc);
414 	return error;
415 }
416 
417 int
418 mcdclose(dev, flag, fmt, p)
419 	dev_t dev;
420 	int flag, fmt;
421 	struct proc *p;
422 {
423 	struct mcd_softc *sc = device_lookup(&mcd_cd, MCDUNIT(dev));
424 	int part = MCDPART(dev);
425 	int error;
426 
427 	MCD_TRACE("close: partition=%d\n", part, 0, 0, 0);
428 
429 	if ((error = mcdlock(sc)) != 0)
430 		return error;
431 
432 	switch (fmt) {
433 	case S_IFCHR:
434 		sc->sc_dk.dk_copenmask &= ~(1 << part);
435 		break;
436 	case S_IFBLK:
437 		sc->sc_dk.dk_bopenmask &= ~(1 << part);
438 		break;
439 	}
440 	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
441 
442 	if (sc->sc_dk.dk_openmask == 0) {
443 		/* XXXX Must wait for I/O to complete! */
444 
445 #if 0
446 		(void) mcd_setmode(sc, MCD_MD_SLEEP);
447 #endif
448 		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
449 	}
450 
451 	mcdunlock(sc);
452 	return 0;
453 }
454 
455 void
456 mcdstrategy(bp)
457 	struct buf *bp;
458 {
459 	struct mcd_softc *sc = device_lookup(&mcd_cd, MCDUNIT(bp->b_dev));
460 	struct disklabel *lp = sc->sc_dk.dk_label;
461 	daddr_t blkno;
462 	int s;
463 
464 	/* Test validity. */
465 	MCD_TRACE("strategy: buf=0x%lx blkno=%ld bcount=%ld\n", bp,
466 	    bp->b_blkno, bp->b_bcount, 0);
467 	if (bp->b_blkno < 0 ||
468 	    (bp->b_bcount % sc->blksize) != 0) {
469 		printf("%s: strategy: blkno = %d bcount = %ld\n",
470 		    sc->sc_dev.dv_xname, bp->b_blkno, bp->b_bcount);
471 		bp->b_error = EINVAL;
472 		goto bad;
473 	}
474 
475 	/* If device invalidated (e.g. media change, door open), error. */
476 	if ((sc->flags & MCDF_LOADED) == 0) {
477 		MCD_TRACE("strategy: drive not valid\n", 0, 0, 0, 0);
478 		bp->b_error = EIO;
479 		goto bad;
480 	}
481 
482 	/* No data to read. */
483 	if (bp->b_bcount == 0)
484 		goto done;
485 
486 	/*
487 	 * Do bounds checking, adjust transfer. if error, process.
488 	 * If end of partition, just return.
489 	 */
490 	if (MCDPART(bp->b_dev) != RAW_PART &&
491 	    bounds_check_with_label(bp, lp,
492 	    (sc->flags & (MCDF_WLABEL|MCDF_LABELLING)) != 0) <= 0)
493 		goto done;
494 
495 	/*
496 	 * Now convert the block number to absolute and put it in
497 	 * terms of the device's logical block size.
498 	 */
499 	blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
500 	if (MCDPART(bp->b_dev) != RAW_PART)
501 		blkno += lp->d_partitions[MCDPART(bp->b_dev)].p_offset;
502 
503 	bp->b_rawblkno = blkno;
504 
505 	/* Queue it. */
506 	s = splbio();
507 	disksort_blkno(&sc->buf_queue, bp);
508 	splx(s);
509 	if (!sc->active)
510 		mcdstart(sc);
511 	return;
512 
513 bad:
514 	bp->b_flags |= B_ERROR;
515 done:
516 	bp->b_resid = bp->b_bcount;
517 	biodone(bp);
518 }
519 
520 void
521 mcdstart(sc)
522 	struct mcd_softc *sc;
523 {
524 	struct buf *bp;
525 	int s;
526 
527 loop:
528 	s = splbio();
529 
530 	if ((bp = BUFQ_FIRST(&sc->buf_queue)) == NULL) {
531 		/* Nothing to do. */
532 		sc->active = 0;
533 		splx(s);
534 		return;
535 	}
536 
537 	/* Block found to process; dequeue. */
538 	MCD_TRACE("start: found block bp=0x%x\n", bp, 0, 0, 0);
539 	BUFQ_REMOVE(&sc->buf_queue, bp);
540 	splx(s);
541 
542 	/* Changed media? */
543 	if ((sc->flags & MCDF_LOADED) == 0) {
544 		MCD_TRACE("start: drive not valid\n", 0, 0, 0, 0);
545 		bp->b_error = EIO;
546 		bp->b_flags |= B_ERROR;
547 		biodone(bp);
548 		goto loop;
549 	}
550 
551 	sc->active = 1;
552 
553 	/* Instrumentation. */
554 	s = splbio();
555 	disk_busy(&sc->sc_dk);
556 	splx(s);
557 
558 	sc->mbx.retry = MCD_RDRETRIES;
559 	sc->mbx.bp = bp;
560 	sc->mbx.blkno = bp->b_rawblkno;
561 	sc->mbx.nblk = bp->b_bcount / sc->blksize;
562 	sc->mbx.sz = sc->blksize;
563 	sc->mbx.skip = 0;
564 	sc->mbx.state = MCD_S_BEGIN;
565 	sc->mbx.mode = MCD_MD_COOKED;
566 
567 	s = splbio();
568 	(void) mcdintr(sc);
569 	splx(s);
570 }
571 
572 int
573 mcdread(dev, uio, flags)
574 	dev_t dev;
575 	struct uio *uio;
576 	int flags;
577 {
578 
579 	return (physio(mcdstrategy, NULL, dev, B_READ, minphys, uio));
580 }
581 
582 int
583 mcdwrite(dev, uio, flags)
584 	dev_t dev;
585 	struct uio *uio;
586 	int flags;
587 {
588 
589 	return (physio(mcdstrategy, NULL, dev, B_WRITE, minphys, uio));
590 }
591 
592 int
593 mcdioctl(dev, cmd, addr, flag, p)
594 	dev_t dev;
595 	u_long cmd;
596 	caddr_t addr;
597 	int flag;
598 	struct proc *p;
599 {
600 	struct mcd_softc *sc = device_lookup(&mcd_cd, MCDUNIT(dev));
601 	int error;
602 	int part;
603 
604 	MCD_TRACE("ioctl: cmd=0x%x\n", cmd, 0, 0, 0);
605 
606 	if ((sc->flags & MCDF_LOADED) == 0)
607 		return EIO;
608 
609 	part = MCDPART(dev);
610 	switch (cmd) {
611 	case DIOCGDINFO:
612 		*(struct disklabel *)addr = *(sc->sc_dk.dk_label);
613 		return 0;
614 
615 	case DIOCGPART:
616 		((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
617 		((struct partinfo *)addr)->part =
618 		    &sc->sc_dk.dk_label->d_partitions[part];
619 		return 0;
620 
621 	case DIOCWDINFO:
622 	case DIOCSDINFO:
623 		if ((flag & FWRITE) == 0)
624 			return EBADF;
625 
626 		if ((error = mcdlock(sc)) != 0)
627 			return error;
628 		sc->flags |= MCDF_LABELLING;
629 
630 		error = setdisklabel(sc->sc_dk.dk_label,
631 		    (struct disklabel *)addr, /*sc->sc_dk.dk_openmask : */0,
632 		    sc->sc_dk.dk_cpulabel);
633 		if (error == 0) {
634 		}
635 
636 		sc->flags &= ~MCDF_LABELLING;
637 		mcdunlock(sc);
638 		return error;
639 
640 	case DIOCWLABEL:
641 		return EBADF;
642 
643 	case DIOCGDEFLABEL:
644 		mcdgetdefaultlabel(sc, (struct disklabel *)addr);
645 		return 0;
646 
647 	case CDIOCPLAYTRACKS:
648 		return mcd_playtracks(sc, (struct ioc_play_track *)addr);
649 	case CDIOCPLAYMSF:
650 		return mcd_playmsf(sc, (struct ioc_play_msf *)addr);
651 	case CDIOCPLAYBLOCKS:
652 		return mcd_playblocks(sc, (struct ioc_play_blocks *)addr);
653 	case CDIOCREADSUBCHANNEL:
654 		return mcd_read_subchannel(sc, (struct ioc_read_subchannel *)addr);
655 	case CDIOREADTOCHEADER:
656 		return mcd_toc_header(sc, (struct ioc_toc_header *)addr);
657 	case CDIOREADTOCENTRYS:
658 		return mcd_toc_entries(sc, (struct ioc_read_toc_entry *)addr);
659 	case CDIOCSETPATCH:
660 	case CDIOCGETVOL:
661 	case CDIOCSETVOL:
662 	case CDIOCSETMONO:
663 	case CDIOCSETSTEREO:
664 	case CDIOCSETMUTE:
665 	case CDIOCSETLEFT:
666 	case CDIOCSETRIGHT:
667 		return EINVAL;
668 	case CDIOCRESUME:
669 		return mcd_resume(sc);
670 	case CDIOCPAUSE:
671 		return mcd_pause(sc);
672 	case CDIOCSTART:
673 		return EINVAL;
674 	case CDIOCSTOP:
675 		return mcd_stop(sc);
676 	case DIOCEJECT:
677 		if (*(int *)addr == 0) {
678 			/*
679 			 * Don't force eject: check that we are the only
680 			 * partition open. If so, unlock it.
681 			 */
682 			if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
683 			    sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask ==
684 			    sc->sc_dk.dk_openmask) {
685 				error = mcd_setlock(sc, MCD_LK_UNLOCK);
686 				if (error)
687 					return (error);
688 			} else {
689 				return (EBUSY);
690 			}
691 		}
692 		/* FALLTHROUGH */
693 	case CDIOCEJECT: /* FALLTHROUGH */
694 	case ODIOCEJECT:
695 		return mcd_eject(sc);
696 	case CDIOCALLOW:
697 		return mcd_setlock(sc, MCD_LK_UNLOCK);
698 	case CDIOCPREVENT:
699 		return mcd_setlock(sc, MCD_LK_LOCK);
700 	case DIOCLOCK:
701 		return mcd_setlock(sc,
702 		    (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK);
703 	case CDIOCSETDEBUG:
704 		sc->debug = 1;
705 		return 0;
706 	case CDIOCCLRDEBUG:
707 		sc->debug = 0;
708 		return 0;
709 	case CDIOCRESET:
710 		return mcd_hard_reset(sc);
711 
712 	default:
713 		return ENOTTY;
714 	}
715 
716 #ifdef DIAGNOSTIC
717 	panic("mcdioctl: impossible");
718 #endif
719 }
720 
721 void
722 mcdgetdefaultlabel(sc, lp)
723 	struct mcd_softc *sc;
724 	struct disklabel *lp;
725 {
726 
727 	bzero(lp, sizeof(struct disklabel));
728 
729 	lp->d_secsize = sc->blksize;
730 	lp->d_ntracks = 1;
731 	lp->d_nsectors = 100;
732 	lp->d_ncylinders = (sc->disksize / 100) + 1;
733 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
734 
735 	strncpy(lp->d_typename, "Mitsumi CD-ROM", 16);
736 	lp->d_type = 0;	/* XXX */
737 	strncpy(lp->d_packname, "fictitious", 16);
738 	lp->d_secperunit = sc->disksize;
739 	lp->d_rpm = 300;
740 	lp->d_interleave = 1;
741 	lp->d_flags = D_REMOVABLE;
742 
743 	lp->d_partitions[0].p_offset = 0;
744 	lp->d_partitions[0].p_size =
745 	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
746 	lp->d_partitions[0].p_fstype = FS_ISO9660;
747 	lp->d_partitions[RAW_PART].p_offset = 0;
748 	lp->d_partitions[RAW_PART].p_size =
749 	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
750 	lp->d_partitions[RAW_PART].p_fstype = FS_ISO9660;
751 	lp->d_npartitions = RAW_PART + 1;
752 
753 	lp->d_magic = DISKMAGIC;
754 	lp->d_magic2 = DISKMAGIC;
755 	lp->d_checksum = dkcksum(lp);
756 }
757 
758 /*
759  * This could have been taken from scsi/cd.c, but it is not clear
760  * whether the scsi cd driver is linked in.
761  */
762 void
763 mcdgetdisklabel(sc)
764 	struct mcd_softc *sc;
765 {
766 	struct disklabel *lp = sc->sc_dk.dk_label;
767 
768 	bzero(sc->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
769 
770 	mcdgetdefaultlabel(sc, lp);
771 }
772 
773 int
774 mcd_get_parms(sc)
775 	struct mcd_softc *sc;
776 {
777 	struct mcd_mbox mbx;
778 	daddr_t size;
779 	int error;
780 
781 	/* Send volume info command. */
782 	mbx.cmd.opcode = MCD_CMDGETVOLINFO;
783 	mbx.cmd.length = 0;
784 	mbx.res.length = sizeof(mbx.res.data.volinfo);
785 	if ((error = mcd_send(sc, &mbx, 1)) != 0)
786 		return error;
787 
788 	if (mbx.res.data.volinfo.trk_low == 0x00 &&
789 	    mbx.res.data.volinfo.trk_high == 0x00)
790 		return EINVAL;
791 
792 	/* Volinfo is OK. */
793 	sc->volinfo = mbx.res.data.volinfo;
794 	sc->blksize = MCD_BLKSIZE_COOKED;
795 	size = msf2hsg(sc->volinfo.vol_msf, 0);
796 	sc->disksize = size * (MCD_BLKSIZE_COOKED / DEV_BSIZE);
797 	return 0;
798 }
799 
800 int
801 mcdsize(dev)
802 	dev_t dev;
803 {
804 
805 	/* CD-ROMs are read-only. */
806 	return -1;
807 }
808 
809 int
810 mcddump(dev, blkno, va, size)
811 	dev_t dev;
812 	daddr_t blkno;
813 	caddr_t va;
814 	size_t size;
815 {
816 
817 	/* Not implemented. */
818 	return ENXIO;
819 }
820 
821 /*
822  * Find the board and fill in the softc.
823  */
824 int
825 mcd_find(iot, ioh, sc)
826 	bus_space_tag_t iot;
827 	bus_space_handle_t ioh;
828 	struct mcd_softc *sc;
829 {
830 	int i;
831 	struct mcd_mbox mbx;
832 
833         sc->sc_iot = iot;
834 	sc->sc_ioh = ioh;
835 
836 	/* Send a reset. */
837 	bus_space_write_1(iot, ioh, MCD_RESET, 0);
838 	delay(1000000);
839 	/* Get any pending status and throw away. */
840 	for (i = 10; i; i--)
841 		bus_space_read_1(iot, ioh, MCD_STATUS);
842 	delay(1000);
843 
844 	/* Send get status command. */
845 	mbx.cmd.opcode = MCD_CMDGETSTAT;
846 	mbx.cmd.length = 0;
847 	mbx.res.length = 0;
848 	if (mcd_send(sc, &mbx, 0) != 0)
849 		return 0;
850 
851 	/* Get info about the drive. */
852 	mbx.cmd.opcode = MCD_CMDCONTINFO;
853 	mbx.cmd.length = 0;
854 	mbx.res.length = sizeof(mbx.res.data.continfo);
855 	if (mcd_send(sc, &mbx, 0) != 0)
856 		return 0;
857 
858 	/*
859 	 * The following is code which is not guaranteed to work for all
860 	 * drives, because the meaning of the expected 'M' is not clear
861 	 * (M_itsumi is an obvious assumption, but I don't trust that).
862 	 * Also, the original hack had a bogus condition that always
863 	 * returned true.
864 	 *
865 	 * Note:  Which models support interrupts?  >=LU005S?
866 	 */
867 	sc->readcmd = MCD_CMDREADSINGLESPEED;
868 	switch (mbx.res.data.continfo.code) {
869 	case 'M':
870 		if (mbx.res.data.continfo.version <= 2)
871 			sc->type = "LU002S";
872 		else if (mbx.res.data.continfo.version <= 5)
873 			sc->type = "LU005S";
874 		else
875 			sc->type = "LU006S";
876 		break;
877 	case 'F':
878 		sc->type = "FX001";
879 		break;
880 	case 'D':
881 		sc->type = "FX001D";
882 		sc->readcmd = MCD_CMDREADDOUBLESPEED;
883 		break;
884 	default:
885 		/*
886 		 * mcd_send() says the  response looked OK but the
887 		 * drive type is unknown. If mcd_promisc,  match anyway.
888 		 */
889 		if (mcd_promisc != 0)
890 			return 0;
891 
892 #ifdef MCDDEBUG
893 		printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n",
894 		    sc->sc_dev.dv_xname,
895 		    mbx.res.data.continfo.code, mbx.res.data.continfo.version);
896 #endif
897 		sc->type = 0;
898 		break;
899 	}
900 
901 	return 1;
902 
903 }
904 
905 int
906 mcdprobe(parent, match, aux)
907 	struct device *parent;
908 	struct cfdata *match;
909 	void *aux;
910 {
911 	struct isa_attach_args *ia = aux;
912 	struct mcd_softc sc;
913 	bus_space_tag_t iot = ia->ia_iot;
914 	bus_space_handle_t ioh;
915 	int rv;
916 
917 	/* Disallow wildcarded i/o address. */
918 	if (ia->ia_iobase == ISACF_PORT_DEFAULT)
919 		return (0);
920 
921 	/* Map i/o space */
922 	if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh))
923 		return 0;
924 
925 	sc.debug = 0;
926 	sc.probe = 1;
927 
928 	rv = mcd_find(iot, ioh, &sc);
929 
930 	bus_space_unmap(iot, ioh, MCD_NPORT);
931 
932 	if (rv)	{
933 		ia->ia_iosize = MCD_NPORT;
934 		ia->ia_msize = 0;
935 	}
936 
937 	return (rv);
938 }
939 
940 int
941 mcd_getreply(sc)
942 	struct mcd_softc *sc;
943 {
944 	bus_space_tag_t iot = sc->sc_iot;
945 	bus_space_handle_t ioh = sc->sc_ioh;
946 	int i;
947 
948 	/* Wait until xfer port senses data ready. */
949 	for (i = DELAY_GETREPLY; i; i--) {
950 		if ((bus_space_read_1(iot, ioh, MCD_XFER) &
951 		    MCD_XF_STATUSUNAVAIL) == 0)
952 			break;
953 		delay(DELAY_GRANULARITY);
954 	}
955 	if (!i)
956 		return -1;
957 
958 	/* Get the data. */
959 	return bus_space_read_1(iot, ioh, MCD_STATUS);
960 }
961 
962 int
963 mcd_getstat(sc)
964 	struct mcd_softc *sc;
965 {
966 	struct mcd_mbox mbx;
967 
968 	mbx.cmd.opcode = MCD_CMDGETSTAT;
969 	mbx.cmd.length = 0;
970 	mbx.res.length = 0;
971 	return mcd_send(sc, &mbx, 1);
972 }
973 
974 int
975 mcd_getresult(sc, res)
976 	struct mcd_softc *sc;
977 	struct mcd_result *res;
978 {
979 	int i, x;
980 
981 	if (sc->debug)
982 		printf("%s: mcd_getresult: %d", sc->sc_dev.dv_xname,
983 		    res->length);
984 
985 	if ((x = mcd_getreply(sc)) < 0) {
986 		if (sc->debug)
987 			printf(" timeout\n");
988 		else if (!sc->probe)
989 			printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
990 		return EIO;
991 	}
992 	if (sc->debug)
993 		printf(" %02x", (u_int)x);
994 	sc->status = x;
995 	mcd_setflags(sc);
996 
997 	if ((sc->status & MCD_ST_CMDCHECK) != 0)
998 		return EINVAL;
999 
1000 	for (i = 0; i < res->length; i++) {
1001 		if ((x = mcd_getreply(sc)) < 0) {
1002 			if (sc->debug)
1003 				printf(" timeout\n");
1004 			else
1005 				printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
1006 			return EIO;
1007 		}
1008 		if (sc->debug)
1009 			printf(" %02x", (u_int)x);
1010 		res->data.raw.data[i] = x;
1011 	}
1012 
1013 	if (sc->debug)
1014 		printf(" succeeded\n");
1015 
1016 #ifdef MCDDEBUG
1017 	delay(10);
1018 	while ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_XFER) &
1019 	    MCD_XF_STATUSUNAVAIL) == 0) {
1020 		x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_STATUS);
1021 		printf("%s: got extra byte %02x during getstatus\n",
1022 		    sc->sc_dev.dv_xname, (u_int)x);
1023 		delay(10);
1024 	}
1025 #endif
1026 
1027 	return 0;
1028 }
1029 
1030 void
1031 mcd_setflags(sc)
1032 	struct mcd_softc *sc;
1033 {
1034 
1035 	/* Check flags. */
1036 	if ((sc->flags & MCDF_LOADED) != 0 &&
1037 	    (sc->status & (MCD_ST_DSKCHNG | MCD_ST_DSKIN | MCD_ST_DOOROPEN)) !=
1038 	    MCD_ST_DSKIN) {
1039 		if ((sc->status & MCD_ST_DOOROPEN) != 0)
1040 			printf("%s: door open\n", sc->sc_dev.dv_xname);
1041 		else if ((sc->status & MCD_ST_DSKIN) == 0)
1042 			printf("%s: no disk present\n", sc->sc_dev.dv_xname);
1043 		else if ((sc->status & MCD_ST_DSKCHNG) != 0)
1044 			printf("%s: media change\n", sc->sc_dev.dv_xname);
1045 		sc->flags &= ~MCDF_LOADED;
1046 	}
1047 
1048 	if ((sc->status & MCD_ST_AUDIOBSY) != 0)
1049 		sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
1050 	else if (sc->audio_status == CD_AS_PLAY_IN_PROGRESS ||
1051 		 sc->audio_status == CD_AS_AUDIO_INVALID)
1052 		sc->audio_status = CD_AS_PLAY_COMPLETED;
1053 }
1054 
1055 int
1056 mcd_send(sc, mbx, diskin)
1057 	struct mcd_softc *sc;
1058 	struct mcd_mbox *mbx;
1059 	int diskin;
1060 {
1061 	int retry, i, error;
1062 	bus_space_tag_t iot = sc->sc_iot;
1063 	bus_space_handle_t ioh = sc->sc_ioh;
1064 
1065 	if (sc->debug) {
1066 		printf("%s: mcd_send: %d %02x", sc->sc_dev.dv_xname,
1067 		    mbx->cmd.length, (u_int)mbx->cmd.opcode);
1068 		for (i = 0; i < mbx->cmd.length; i++)
1069 			printf(" %02x", (u_int)mbx->cmd.data.raw.data[i]);
1070 		printf("\n");
1071 	}
1072 
1073 	for (retry = MCD_RETRIES; retry; retry--) {
1074 		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.opcode);
1075 		for (i = 0; i < mbx->cmd.length; i++)
1076 			bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.data.raw.data[i]);
1077 		if ((error = mcd_getresult(sc, &mbx->res)) == 0)
1078 			break;
1079 		if (error == EINVAL)
1080 			return error;
1081 	}
1082 	if (!retry)
1083 		return error;
1084 	if (diskin && (sc->flags & MCDF_LOADED) == 0)
1085 		return EIO;
1086 
1087 	return 0;
1088 }
1089 
1090 static int
1091 bcd2bin(b)
1092 	bcd_t b;
1093 {
1094 
1095 	return (b >> 4) * 10 + (b & 15);
1096 }
1097 
1098 static bcd_t
1099 bin2bcd(b)
1100 	int b;
1101 {
1102 
1103 	return ((b / 10) << 4) | (b % 10);
1104 }
1105 
1106 static void
1107 hsg2msf(hsg, msf)
1108 	int hsg;
1109 	bcd_t *msf;
1110 {
1111 
1112 	hsg += 150;
1113 	F_msf(msf) = bin2bcd(hsg % 75);
1114 	hsg /= 75;
1115 	S_msf(msf) = bin2bcd(hsg % 60);
1116 	hsg /= 60;
1117 	M_msf(msf) = bin2bcd(hsg);
1118 }
1119 
1120 static daddr_t
1121 msf2hsg(msf, relative)
1122 	bcd_t *msf;
1123 	int relative;
1124 {
1125 	daddr_t blkno;
1126 
1127 	blkno = bcd2bin(M_msf(msf)) * 75 * 60 +
1128 		bcd2bin(S_msf(msf)) * 75 +
1129 		bcd2bin(F_msf(msf));
1130 	if (!relative)
1131 		blkno -= 150;
1132 	return blkno;
1133 }
1134 
1135 void
1136 mcd_pseudointr(v)
1137 	void *v;
1138 {
1139 	struct mcd_softc *sc = v;
1140 	int s;
1141 
1142 	s = splbio();
1143 	(void) mcdintr(sc);
1144 	splx(s);
1145 }
1146 
1147 /*
1148  * State machine to process read requests.
1149  * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
1150  * MCD_S_WAITMODE: waits for status reply from set mode, set read command
1151  * MCD_S_WAITREAD: wait for read ready, read data.
1152  */
1153 int
1154 mcdintr(arg)
1155 	void *arg;
1156 {
1157 	struct mcd_softc *sc = arg;
1158 	struct mcd_mbx *mbx = &sc->mbx;
1159 	struct buf *bp = mbx->bp;
1160 	bus_space_tag_t iot = sc->sc_iot;
1161 	bus_space_handle_t ioh = sc->sc_ioh;
1162 
1163 	int i;
1164 	u_char x;
1165 	bcd_t msf[3];
1166 
1167 	switch (mbx->state) {
1168 	case MCD_S_IDLE:
1169 		return 0;
1170 
1171 	case MCD_S_BEGIN:
1172 	tryagain:
1173 		if (mbx->mode == sc->lastmode)
1174 			goto firstblock;
1175 
1176 		sc->lastmode = MCD_MD_UNKNOWN;
1177 		bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE);
1178 		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode);
1179 
1180 		mbx->count = RDELAY_WAITMODE;
1181 		mbx->state = MCD_S_WAITMODE;
1182 
1183 	case MCD_S_WAITMODE:
1184 		callout_stop(&sc->sc_pintr_ch);
1185 		for (i = 20; i; i--) {
1186 			x = bus_space_read_1(iot, ioh, MCD_XFER);
1187 			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
1188 				break;
1189 			delay(50);
1190 		}
1191 		if (i == 0)
1192 			goto hold;
1193 		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
1194 		mcd_setflags(sc);
1195 		if ((sc->flags & MCDF_LOADED) == 0)
1196 			goto changed;
1197 		MCD_TRACE("doread: got WAITMODE delay=%d\n",
1198 		    RDELAY_WAITMODE - mbx->count, 0, 0, 0);
1199 
1200 		sc->lastmode = mbx->mode;
1201 
1202 	firstblock:
1203 		MCD_TRACE("doread: read blkno=%d for bp=0x%x\n", mbx->blkno,
1204 		    bp, 0, 0);
1205 
1206 		/* Build parameter block. */
1207 		hsg2msf(mbx->blkno, msf);
1208 
1209 		/* Send the read command. */
1210 		bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd);
1211 		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]);
1212 		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]);
1213 		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]);
1214 		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
1215 		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
1216 		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk);
1217 
1218 		mbx->count = RDELAY_WAITREAD;
1219 		mbx->state = MCD_S_WAITREAD;
1220 
1221 	case MCD_S_WAITREAD:
1222 		callout_stop(&sc->sc_pintr_ch);
1223 	nextblock:
1224 	loop:
1225 		for (i = 20; i; i--) {
1226 			x = bus_space_read_1(iot, ioh, MCD_XFER);
1227 			if ((x & MCD_XF_DATAUNAVAIL) == 0)
1228 				goto gotblock;
1229 			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
1230 				break;
1231 			delay(50);
1232 		}
1233 		if (i == 0)
1234 			goto hold;
1235 		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
1236 		mcd_setflags(sc);
1237 		if ((sc->flags & MCDF_LOADED) == 0)
1238 			goto changed;
1239 #if 0
1240 		printf("%s: got status byte %02x during read\n",
1241 		    sc->sc_dev.dv_xname, (u_int)sc->status);
1242 #endif
1243 		goto loop;
1244 
1245 	gotblock:
1246 		MCD_TRACE("doread: got data delay=%d\n",
1247 		    RDELAY_WAITREAD - mbx->count, 0, 0, 0);
1248 
1249 		/* Data is ready. */
1250 		bus_space_write_1(iot, ioh, MCD_CTL2, 0x04);	/* XXX */
1251 		bus_space_read_multi_1(iot, ioh, MCD_RDATA,
1252 		    bp->b_data + mbx->skip, mbx->sz);
1253 		bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c);	/* XXX */
1254 		mbx->blkno += 1;
1255 		mbx->skip += mbx->sz;
1256 		if (--mbx->nblk > 0)
1257 			goto nextblock;
1258 
1259 		mbx->state = MCD_S_IDLE;
1260 
1261 		/* Return buffer. */
1262 		bp->b_resid = 0;
1263 		disk_unbusy(&sc->sc_dk, bp->b_bcount);
1264 		biodone(bp);
1265 
1266 		mcdstart(sc);
1267 		return 1;
1268 
1269 	hold:
1270 		if (mbx->count-- < 0) {
1271 			printf("%s: timeout in state %d",
1272 			    sc->sc_dev.dv_xname, mbx->state);
1273 			goto readerr;
1274 		}
1275 
1276 #if 0
1277 		printf("%s: sleep in state %d\n", sc->sc_dev.dv_xname,
1278 		    mbx->state);
1279 #endif
1280 		callout_reset(&sc->sc_pintr_ch, hz / 100,
1281 		    mcd_pseudointr, sc);
1282 		return -1;
1283 	}
1284 
1285 readerr:
1286 	if (mbx->retry-- > 0) {
1287 		printf("; retrying\n");
1288 		goto tryagain;
1289 	} else
1290 		printf("; giving up\n");
1291 
1292 changed:
1293 	/* Invalidate the buffer. */
1294 	bp->b_flags |= B_ERROR;
1295 	bp->b_resid = bp->b_bcount - mbx->skip;
1296 	disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid));
1297 	biodone(bp);
1298 
1299 	mcdstart(sc);
1300 	return -1;
1301 
1302 #ifdef notyet
1303 	printf("%s: unit timeout; resetting\n", sc->sc_dev.dv_xname);
1304 	bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET);
1305 	delay(300000);
1306 	(void) mcd_getstat(sc, 1);
1307 	(void) mcd_getstat(sc, 1);
1308 	/*sc->status &= ~MCD_ST_DSKCHNG; */
1309 	sc->debug = 1; /* preventive set debug mode */
1310 #endif
1311 }
1312 
1313 void
1314 mcd_soft_reset(sc)
1315 	struct mcd_softc *sc;
1316 {
1317 
1318 	sc->debug = 0;
1319 	sc->flags = 0;
1320 	sc->lastmode = MCD_MD_UNKNOWN;
1321 	sc->lastupc = MCD_UPC_UNKNOWN;
1322 	sc->audio_status = CD_AS_AUDIO_INVALID;
1323 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MCD_CTL2, 0x0c); /* XXX */
1324 }
1325 
1326 int
1327 mcd_hard_reset(sc)
1328 	struct mcd_softc *sc;
1329 {
1330 	struct mcd_mbox mbx;
1331 
1332 	mcd_soft_reset(sc);
1333 
1334 	mbx.cmd.opcode = MCD_CMDRESET;
1335 	mbx.cmd.length = 0;
1336 	mbx.res.length = 0;
1337 	return mcd_send(sc, &mbx, 0);
1338 }
1339 
1340 int
1341 mcd_setmode(sc, mode)
1342 	struct mcd_softc *sc;
1343 	int mode;
1344 {
1345 	struct mcd_mbox mbx;
1346 	int error;
1347 
1348 	if (sc->lastmode == mode)
1349 		return 0;
1350 	if (sc->debug)
1351 		printf("%s: setting mode to %d\n", sc->sc_dev.dv_xname, mode);
1352 	sc->lastmode = MCD_MD_UNKNOWN;
1353 
1354 	mbx.cmd.opcode = MCD_CMDSETMODE;
1355 	mbx.cmd.length = sizeof(mbx.cmd.data.datamode);
1356 	mbx.cmd.data.datamode.mode = mode;
1357 	mbx.res.length = 0;
1358 	if ((error = mcd_send(sc, &mbx, 1)) != 0)
1359 		return error;
1360 
1361 	sc->lastmode = mode;
1362 	return 0;
1363 }
1364 
1365 int
1366 mcd_setupc(sc, upc)
1367 	struct mcd_softc *sc;
1368 	int upc;
1369 {
1370 	struct mcd_mbox mbx;
1371 	int error;
1372 
1373 	if (sc->lastupc == upc)
1374 		return 0;
1375 	if (sc->debug)
1376 		printf("%s: setting upc to %d\n", sc->sc_dev.dv_xname, upc);
1377 	sc->lastupc = MCD_UPC_UNKNOWN;
1378 
1379 	mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
1380 	mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
1381 	mbx.cmd.data.config.subcommand = MCD_CF_READUPC;
1382 	mbx.cmd.data.config.data1 = upc;
1383 	mbx.res.length = 0;
1384 	if ((error = mcd_send(sc, &mbx, 1)) != 0)
1385 		return error;
1386 
1387 	sc->lastupc = upc;
1388 	return 0;
1389 }
1390 
1391 int
1392 mcd_toc_header(sc, th)
1393 	struct mcd_softc *sc;
1394 	struct ioc_toc_header *th;
1395 {
1396 
1397 	if (sc->debug)
1398 		printf("%s: mcd_toc_header: reading toc header\n",
1399 		    sc->sc_dev.dv_xname);
1400 
1401 	th->len = msf2hsg(sc->volinfo.vol_msf, 0);
1402 	th->starting_track = bcd2bin(sc->volinfo.trk_low);
1403 	th->ending_track = bcd2bin(sc->volinfo.trk_high);
1404 
1405 	return 0;
1406 }
1407 
1408 int
1409 mcd_read_toc(sc)
1410 	struct mcd_softc *sc;
1411 {
1412 	struct ioc_toc_header th;
1413 	union mcd_qchninfo q;
1414 	int error, trk, idx, retry;
1415 
1416 	if ((error = mcd_toc_header(sc, &th)) != 0)
1417 		return error;
1418 
1419 	if ((error = mcd_stop(sc)) != 0)
1420 		return error;
1421 
1422 	if (sc->debug)
1423 		printf("%s: read_toc: reading qchannel info\n",
1424 		    sc->sc_dev.dv_xname);
1425 
1426 	for (trk = th.starting_track; trk <= th.ending_track; trk++)
1427 		sc->toc[trk].toc.idx_no = 0x00;
1428 	trk = th.ending_track - th.starting_track + 1;
1429 	for (retry = 300; retry && trk > 0; retry--) {
1430 		if (mcd_getqchan(sc, &q, CD_TRACK_INFO) != 0)
1431 			break;
1432 		if (q.toc.trk_no != 0x00 || q.toc.idx_no == 0x00)
1433 			continue;
1434 		idx = bcd2bin(q.toc.idx_no);
1435 		if (idx < MCD_MAXTOCS &&
1436 		    sc->toc[idx].toc.idx_no == 0x00) {
1437 			sc->toc[idx] = q;
1438 			trk--;
1439 		}
1440 	}
1441 
1442 	/* Inform the drive that we're finished so it turns off the light. */
1443 	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1444 		return error;
1445 
1446 	if (trk != 0)
1447 		return EINVAL;
1448 
1449 	/* Add a fake last+1 for mcd_playtracks(). */
1450 	idx = th.ending_track + 1;
1451 	sc->toc[idx].toc.control = sc->toc[idx-1].toc.control;
1452 	sc->toc[idx].toc.addr_type = sc->toc[idx-1].toc.addr_type;
1453 	sc->toc[idx].toc.trk_no = 0x00;
1454 	sc->toc[idx].toc.idx_no = 0xaa;
1455 	sc->toc[idx].toc.absolute_pos[0] = sc->volinfo.vol_msf[0];
1456 	sc->toc[idx].toc.absolute_pos[1] = sc->volinfo.vol_msf[1];
1457 	sc->toc[idx].toc.absolute_pos[2] = sc->volinfo.vol_msf[2];
1458 
1459 	return 0;
1460 }
1461 
1462 int
1463 mcd_toc_entries(sc, te)
1464 	struct mcd_softc *sc;
1465 	struct ioc_read_toc_entry *te;
1466 {
1467 	int len = te->data_len;
1468 	struct ret_toc {
1469 		struct ioc_toc_header header;
1470 		struct cd_toc_entry entries[MCD_MAXTOCS];
1471 	} data;
1472 	u_char trk;
1473 	daddr_t lba;
1474 	int error, n;
1475 
1476 	if (len > sizeof(data.entries) ||
1477 	    len < sizeof(struct cd_toc_entry))
1478 		return EINVAL;
1479 	if (te->address_format != CD_MSF_FORMAT &&
1480 	    te->address_format != CD_LBA_FORMAT)
1481 		return EINVAL;
1482 
1483 	/* Copy the TOC header. */
1484 	if ((error = mcd_toc_header(sc, &data.header)) != 0)
1485 		return error;
1486 
1487 	/* Verify starting track. */
1488 	trk = te->starting_track;
1489 	if (trk == 0x00)
1490 		trk = data.header.starting_track;
1491 	else if (trk == 0xaa)
1492 		trk = data.header.ending_track + 1;
1493 	else if (trk < data.header.starting_track ||
1494 		 trk > data.header.ending_track + 1)
1495 		return EINVAL;
1496 
1497 	/* Copy the TOC data. */
1498 	for (n = 0; trk <= data.header.ending_track + 1; trk++) {
1499 		if (sc->toc[trk].toc.idx_no == 0x00)
1500 			continue;
1501 		data.entries[n].control = sc->toc[trk].toc.control;
1502 		data.entries[n].addr_type = sc->toc[trk].toc.addr_type;
1503 		data.entries[n].track = bcd2bin(sc->toc[trk].toc.idx_no);
1504 		switch (te->address_format) {
1505 		case CD_MSF_FORMAT:
1506 			data.entries[n].addr.addr[0] = 0;
1507 			data.entries[n].addr.addr[1] = bcd2bin(sc->toc[trk].toc.absolute_pos[0]);
1508 			data.entries[n].addr.addr[2] = bcd2bin(sc->toc[trk].toc.absolute_pos[1]);
1509 			data.entries[n].addr.addr[3] = bcd2bin(sc->toc[trk].toc.absolute_pos[2]);
1510 			break;
1511 		case CD_LBA_FORMAT:
1512 			lba = msf2hsg(sc->toc[trk].toc.absolute_pos, 0);
1513 			data.entries[n].addr.addr[0] = lba >> 24;
1514 			data.entries[n].addr.addr[1] = lba >> 16;
1515 			data.entries[n].addr.addr[2] = lba >> 8;
1516 			data.entries[n].addr.addr[3] = lba;
1517 			break;
1518 		}
1519 		n++;
1520 	}
1521 
1522 	len = min(len, n * sizeof(struct cd_toc_entry));
1523 
1524 	/* Copy the data back. */
1525 	return copyout(&data.entries[0], te->data, len);
1526 }
1527 
1528 int
1529 mcd_stop(sc)
1530 	struct mcd_softc *sc;
1531 {
1532 	struct mcd_mbox mbx;
1533 	int error;
1534 
1535 	if (sc->debug)
1536 		printf("%s: mcd_stop: stopping play\n", sc->sc_dev.dv_xname);
1537 
1538 	mbx.cmd.opcode = MCD_CMDSTOPAUDIO;
1539 	mbx.cmd.length = 0;
1540 	mbx.res.length = 0;
1541 	if ((error = mcd_send(sc, &mbx, 1)) != 0)
1542 		return error;
1543 
1544 	sc->audio_status = CD_AS_PLAY_COMPLETED;
1545 	return 0;
1546 }
1547 
1548 int
1549 mcd_getqchan(sc, q, qchn)
1550 	struct mcd_softc *sc;
1551 	union mcd_qchninfo *q;
1552 	int qchn;
1553 {
1554 	struct mcd_mbox mbx;
1555 	int error;
1556 
1557 	if (qchn == CD_TRACK_INFO) {
1558 		if ((error = mcd_setmode(sc, MCD_MD_TOC)) != 0)
1559 			return error;
1560 	} else {
1561 		if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1562 			return error;
1563 	}
1564 	if (qchn == CD_MEDIA_CATALOG) {
1565 		if ((error = mcd_setupc(sc, MCD_UPC_ENABLE)) != 0)
1566 			return error;
1567 	} else {
1568 		if ((error = mcd_setupc(sc, MCD_UPC_DISABLE)) != 0)
1569 			return error;
1570 	}
1571 
1572 	mbx.cmd.opcode = MCD_CMDGETQCHN;
1573 	mbx.cmd.length = 0;
1574 	mbx.res.length = sizeof(mbx.res.data.qchninfo);
1575 	if ((error = mcd_send(sc, &mbx, 1)) != 0)
1576 		return error;
1577 
1578 	*q = mbx.res.data.qchninfo;
1579 	return 0;
1580 }
1581 
1582 int
1583 mcd_read_subchannel(sc, ch)
1584 	struct mcd_softc *sc;
1585 	struct ioc_read_subchannel *ch;
1586 {
1587 	int len = ch->data_len;
1588 	union mcd_qchninfo q;
1589 	struct cd_sub_channel_info data;
1590 	daddr_t lba;
1591 	int error;
1592 
1593 	if (sc->debug)
1594 		printf("%s: subchan: af=%d df=%d\n", sc->sc_dev.dv_xname,
1595 		    ch->address_format, ch->data_format);
1596 
1597 	if (len > sizeof(data) ||
1598 	    len < sizeof(struct cd_sub_channel_header))
1599 		return EINVAL;
1600 	if (ch->address_format != CD_MSF_FORMAT &&
1601 	    ch->address_format != CD_LBA_FORMAT)
1602 		return EINVAL;
1603 	if (ch->data_format != CD_CURRENT_POSITION &&
1604 	    ch->data_format != CD_MEDIA_CATALOG)
1605 		return EINVAL;
1606 
1607 	if ((error = mcd_getqchan(sc, &q, ch->data_format)) != 0)
1608 		return error;
1609 
1610 	data.header.audio_status = sc->audio_status;
1611 	data.what.media_catalog.data_format = ch->data_format;
1612 
1613 	switch (ch->data_format) {
1614 	case CD_MEDIA_CATALOG:
1615 		data.what.media_catalog.mc_valid = 1;
1616 #if 0
1617 		data.what.media_catalog.mc_number =
1618 #endif
1619 		break;
1620 
1621 	case CD_CURRENT_POSITION:
1622 		data.what.position.track_number = bcd2bin(q.current.trk_no);
1623 		data.what.position.index_number = bcd2bin(q.current.idx_no);
1624 		switch (ch->address_format) {
1625 		case CD_MSF_FORMAT:
1626 			data.what.position.reladdr.addr[0] = 0;
1627 			data.what.position.reladdr.addr[1] = bcd2bin(q.current.relative_pos[0]);
1628 			data.what.position.reladdr.addr[2] = bcd2bin(q.current.relative_pos[1]);
1629 			data.what.position.reladdr.addr[3] = bcd2bin(q.current.relative_pos[2]);
1630 			data.what.position.absaddr.addr[0] = 0;
1631 			data.what.position.absaddr.addr[1] = bcd2bin(q.current.absolute_pos[0]);
1632 			data.what.position.absaddr.addr[2] = bcd2bin(q.current.absolute_pos[1]);
1633 			data.what.position.absaddr.addr[3] = bcd2bin(q.current.absolute_pos[2]);
1634 			break;
1635 		case CD_LBA_FORMAT:
1636 			lba = msf2hsg(q.current.relative_pos, 1);
1637 			/*
1638 			 * Pre-gap has index number of 0, and decreasing MSF
1639 			 * address.  Must be converted to negative LBA, per
1640 			 * SCSI spec.
1641 			 */
1642 			if (data.what.position.index_number == 0x00)
1643 				lba = -lba;
1644 			data.what.position.reladdr.addr[0] = lba >> 24;
1645 			data.what.position.reladdr.addr[1] = lba >> 16;
1646 			data.what.position.reladdr.addr[2] = lba >> 8;
1647 			data.what.position.reladdr.addr[3] = lba;
1648 			lba = msf2hsg(q.current.absolute_pos, 0);
1649 			data.what.position.absaddr.addr[0] = lba >> 24;
1650 			data.what.position.absaddr.addr[1] = lba >> 16;
1651 			data.what.position.absaddr.addr[2] = lba >> 8;
1652 			data.what.position.absaddr.addr[3] = lba;
1653 			break;
1654 		}
1655 		break;
1656 	}
1657 
1658 	return copyout(&data, ch->data, len);
1659 }
1660 
1661 int
1662 mcd_playtracks(sc, p)
1663 	struct mcd_softc *sc;
1664 	struct ioc_play_track *p;
1665 {
1666 	struct mcd_mbox mbx;
1667 	int a = p->start_track;
1668 	int z = p->end_track;
1669 	int error;
1670 
1671 	if (sc->debug)
1672 		printf("%s: playtracks: from %d:%d to %d:%d\n",
1673 		    sc->sc_dev.dv_xname,
1674 		    a, p->start_index, z, p->end_index);
1675 
1676 	if (a < bcd2bin(sc->volinfo.trk_low) ||
1677 	    a > bcd2bin(sc->volinfo.trk_high) ||
1678 	    a > z ||
1679 	    z < bcd2bin(sc->volinfo.trk_low) ||
1680 	    z > bcd2bin(sc->volinfo.trk_high))
1681 		return EINVAL;
1682 
1683 	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1684 		return error;
1685 
1686 	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1687 	mbx.cmd.length = sizeof(mbx.cmd.data.play);
1688 	mbx.cmd.data.play.start_msf[0] = sc->toc[a].toc.absolute_pos[0];
1689 	mbx.cmd.data.play.start_msf[1] = sc->toc[a].toc.absolute_pos[1];
1690 	mbx.cmd.data.play.start_msf[2] = sc->toc[a].toc.absolute_pos[2];
1691 	mbx.cmd.data.play.end_msf[0] = sc->toc[z+1].toc.absolute_pos[0];
1692 	mbx.cmd.data.play.end_msf[1] = sc->toc[z+1].toc.absolute_pos[1];
1693 	mbx.cmd.data.play.end_msf[2] = sc->toc[z+1].toc.absolute_pos[2];
1694 	sc->lastpb = mbx.cmd;
1695 	mbx.res.length = 0;
1696 	return mcd_send(sc, &mbx, 1);
1697 }
1698 
1699 int
1700 mcd_playmsf(sc, p)
1701 	struct mcd_softc *sc;
1702 	struct ioc_play_msf *p;
1703 {
1704 	struct mcd_mbox mbx;
1705 	int error;
1706 
1707 	if (sc->debug)
1708 		printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n",
1709 		    sc->sc_dev.dv_xname,
1710 		    p->start_m, p->start_s, p->start_f,
1711 		    p->end_m, p->end_s, p->end_f);
1712 
1713 	if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
1714 	    (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f))
1715 		return EINVAL;
1716 
1717 	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1718 		return error;
1719 
1720 	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1721 	mbx.cmd.length = sizeof(mbx.cmd.data.play);
1722 	mbx.cmd.data.play.start_msf[0] = bin2bcd(p->start_m);
1723 	mbx.cmd.data.play.start_msf[1] = bin2bcd(p->start_s);
1724 	mbx.cmd.data.play.start_msf[2] = bin2bcd(p->start_f);
1725 	mbx.cmd.data.play.end_msf[0] = bin2bcd(p->end_m);
1726 	mbx.cmd.data.play.end_msf[1] = bin2bcd(p->end_s);
1727 	mbx.cmd.data.play.end_msf[2] = bin2bcd(p->end_f);
1728 	sc->lastpb = mbx.cmd;
1729 	mbx.res.length = 0;
1730 	return mcd_send(sc, &mbx, 1);
1731 }
1732 
1733 int
1734 mcd_playblocks(sc, p)
1735 	struct mcd_softc *sc;
1736 	struct ioc_play_blocks *p;
1737 {
1738 	struct mcd_mbox mbx;
1739 	int error;
1740 
1741 	if (sc->debug)
1742 		printf("%s: playblocks: blkno %d length %d\n",
1743 		    sc->sc_dev.dv_xname, p->blk, p->len);
1744 
1745 	if (p->blk > sc->disksize || p->len > sc->disksize ||
1746 	    (p->blk + p->len) > sc->disksize)
1747 		return 0;
1748 
1749 	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1750 		return error;
1751 
1752 	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1753 	mbx.cmd.length = sizeof(mbx.cmd.data.play);
1754 	hsg2msf(p->blk, mbx.cmd.data.play.start_msf);
1755 	hsg2msf(p->blk + p->len, mbx.cmd.data.play.end_msf);
1756 	sc->lastpb = mbx.cmd;
1757 	mbx.res.length = 0;
1758 	return mcd_send(sc, &mbx, 1);
1759 }
1760 
1761 int
1762 mcd_pause(sc)
1763 	struct mcd_softc *sc;
1764 {
1765 	union mcd_qchninfo q;
1766 	int error;
1767 
1768 	/* Verify current status. */
1769 	if (sc->audio_status != CD_AS_PLAY_IN_PROGRESS)	{
1770 		printf("%s: pause: attempted when not playing\n",
1771 		    sc->sc_dev.dv_xname);
1772 		return EINVAL;
1773 	}
1774 
1775 	/* Get the current position. */
1776 	if ((error = mcd_getqchan(sc, &q, CD_CURRENT_POSITION)) != 0)
1777 		return error;
1778 
1779 	/* Copy it into lastpb. */
1780 	sc->lastpb.data.seek.start_msf[0] = q.current.absolute_pos[0];
1781 	sc->lastpb.data.seek.start_msf[1] = q.current.absolute_pos[1];
1782 	sc->lastpb.data.seek.start_msf[2] = q.current.absolute_pos[2];
1783 
1784 	/* Stop playing. */
1785 	if ((error = mcd_stop(sc)) != 0)
1786 		return error;
1787 
1788 	/* Set the proper status and exit. */
1789 	sc->audio_status = CD_AS_PLAY_PAUSED;
1790 	return 0;
1791 }
1792 
1793 int
1794 mcd_resume(sc)
1795 	struct mcd_softc *sc;
1796 {
1797 	struct mcd_mbox mbx;
1798 	int error;
1799 
1800 	if (sc->audio_status != CD_AS_PLAY_PAUSED)
1801 		return EINVAL;
1802 
1803 	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1804 		return error;
1805 
1806 	mbx.cmd = sc->lastpb;
1807 	mbx.res.length = 0;
1808 	return mcd_send(sc, &mbx, 1);
1809 }
1810 
1811 int
1812 mcd_eject(sc)
1813 	struct mcd_softc *sc;
1814 {
1815 	struct mcd_mbox mbx;
1816 
1817 	mbx.cmd.opcode = MCD_CMDEJECTDISK;
1818 	mbx.cmd.length = 0;
1819 	mbx.res.length = 0;
1820 	return mcd_send(sc, &mbx, 0);
1821 }
1822 
1823 int
1824 mcd_setlock(sc, mode)
1825 	struct mcd_softc *sc;
1826 	int mode;
1827 {
1828 	struct mcd_mbox mbx;
1829 
1830 	mbx.cmd.opcode = MCD_CMDSETLOCK;
1831 	mbx.cmd.length = sizeof(mbx.cmd.data.lockmode);
1832 	mbx.cmd.data.lockmode.mode = mode;
1833 	mbx.res.length = 0;
1834 	return mcd_send(sc, &mbx, 1);
1835 }
1836