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