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