mcd.c revision 1.19 1 /*
2 * Copyright (c) 1993, 1994 Charles Hannum.
3 * Copyright 1993 by Holger Veit (data part)
4 * Copyright 1993 by Brian Moore (audio part)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This software was developed by Holger Veit and Brian Moore
18 * for use with "386BSD" and similar operating systems.
19 * "Similar operating systems" includes mainly non-profit oriented
20 * systems for research and education, including but not restricted to
21 * "NetBSD", "FreeBSD", "Mach" (by CMU).
22 * 4. Neither the name of the developer(s) nor the name "386BSD"
23 * may be used to endorse or promote products derived from this
24 * software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 * $Id: mcd.c,v 1.19 1994/10/14 18:26:53 cgd Exp $
39 */
40
41 /*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/proc.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/buf.h>
51 #include <sys/stat.h>
52 #include <sys/uio.h>
53 #include <sys/ioctl.h>
54 #include <sys/cdio.h>
55 #include <sys/errno.h>
56 #include <sys/dkbad.h>
57 #include <sys/disklabel.h>
58 #include <sys/device.h>
59
60 #include <machine/cpu.h>
61 #include <machine/pio.h>
62
63 #include <i386/isa/isavar.h>
64 #include <i386/isa/mcdreg.h>
65
66 #ifndef MCDDEBUG
67 #define MCD_TRACE(fmt,a,b,c,d)
68 #else
69 #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);}}
70 #endif
71
72 #define MCDPART(dev) ((minor(dev) & 0x7f) % MAXPARTITONS)
73 #define MCDUNIT(dev) ((minor(dev) & 0x7f) / MAXPARTITONS)
74 #define MCDPHYS(dev) (minor(dev) & 0x80)
75
76 /* flags */
77 #define MCDOPEN 0x0001 /* device opened */
78 #define MCDVALID 0x0002 /* parameters loaded */
79 #define MCDWAIT 0x0004 /* waiting for something */
80 #define MCDLABEL 0x0008 /* label is read */
81 #define MCDREADRAW 0x0010 /* read raw mode (2352 bytes) */
82 #define MCDVOLINFO 0x0020 /* already read volinfo */
83 #define MCDTOC 0x0040 /* already read toc */
84 #define MCDMBXBSY 0x0080 /* local mbx is busy */
85
86 /* status */
87 #define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */
88 #define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */
89 #define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */
90 #define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */
91
92 /* toc */
93 #define MCD_MAXTOCS 104 /* from the Linux driver */
94 #define MCD_LASTPLUS1 170 /* special toc entry */
95
96 struct mcd_mbx {
97 short unit;
98 short retry;
99 short nblk;
100 int sz;
101 u_long skip;
102 struct buf *bp;
103 int p_offset;
104 short count;
105 short state;
106 };
107
108 struct mcd_softc {
109 struct device sc_dev;
110 struct intrhand sc_ih;
111
112 u_short iobase;
113 short config;
114 short flags;
115 short status;
116 int blksize;
117 u_long disksize;
118 struct disklabel dlabel;
119 int partflags[MAXPARTITIONS];
120 int openflags;
121 struct mcd_volinfo volinfo;
122 struct mcd_qchninfo toc[MCD_MAXTOCS];
123 short audio_status;
124 struct mcd_read2 lastpb;
125 short debug;
126 struct buf head; /* head of buf queue */
127 struct mcd_mbx mbx;
128 };
129
130 /* prototypes */
131 int mcdopen __P((dev_t));
132 int mcdclose __P((dev_t));
133 int mcd_start __P((struct mcd_softc *));
134 int mcdioctl __P((dev_t, int, caddr_t, int, struct proc *));
135 int mcd_getdisklabel __P((struct mcd_softc *));
136 int mcdsize __P((dev_t));
137 void mcd_configure __P((struct mcd_softc *));
138 int mcd_waitrdy __P((u_short, int));
139 int mcd_getreply __P((struct mcd_softc *, int));
140 int mcd_getstat __P((struct mcd_softc *, int));
141 void mcd_setflags __P((struct mcd_softc *));
142 int mcd_get __P((struct mcd_softc *, char *, int));
143 int mcd_send __P((struct mcd_softc *, int, int));
144 int bcd2bin __P((bcd_t));
145 bcd_t bin2bcd __P((int));
146 void hsg2msf __P((int, bcd_t *));
147 int msf2hsg __P((bcd_t *));
148 int mcd_volinfo __P((struct mcd_softc *));
149 int mcdintr __P((struct mcd_softc *));
150 int mcd_setmode __P((struct mcd_softc *, int));
151 void mcd_doread __P((void *));
152 int mcd_toc_header __P((struct mcd_softc *, struct ioc_toc_header *));
153 int mcd_read_toc __P((struct mcd_softc *));
154 int mcd_toc_entry __P((struct mcd_softc *, struct ioc_read_toc_entry *));
155 int mcd_stop __P((struct mcd_softc *));
156 int mcd_getqchan __P((struct mcd_softc *, struct mcd_qchninfo *));
157 int mcd_subchan __P((struct mcd_softc *, struct ioc_read_subchannel *));
158 int mcd_playtracks __P((struct mcd_softc *, struct ioc_play_track *));
159 int mcd_play __P((struct mcd_softc *, struct mcd_read2 *));
160 int mcd_pause __P((struct mcd_softc *));
161 int mcd_resume __P((struct mcd_softc *));
162
163 int mcdprobe();
164 void mcdattach();
165
166 struct cfdriver mcdcd = {
167 NULL, "mcd", mcdprobe, mcdattach, DV_DISK, sizeof(struct mcd_softc)
168 };
169
170 #define mcd_put(port,byte) outb(port,byte)
171
172 #define MCD_RETRIES 5
173 #define MCD_RDRETRIES 8
174
175 #define MCDBLK 2048 /* for cooked mode */
176 #define MCDRBLK 2352 /* for raw mode */
177
178 /* several delays */
179 #define RDELAY_WAITSTAT 300
180 #define RDELAY_WAITMODE 300
181 #define RDELAY_WAITREAD 800
182
183 #define DELAY_STATUS 10000l /* 10000 * 1us */
184 #define DELAY_GETREPLY 200000l /* 200000 * 2us */
185 #define DELAY_SEEKREAD 20000l /* 20000 * 1us */
186
187 /* reader state machine */
188 #define MCD_S_BEGIN 0
189 #define MCD_S_WAITSTAT 1
190 #define MCD_S_WAITMODE 2
191 #define MCD_S_WAITREAD 3
192
193 void
194 mcdattach(parent, self, aux)
195 struct device *parent, *self;
196 void *aux;
197 {
198 struct mcd_softc *sc = (void *)self;
199 struct isa_attach_args *ia = aux;
200
201 #ifdef notyet
202 /* Wire controller for interrupts and DMA. */
203 mcd_configure(sc);
204 #endif
205
206 printf("\n");
207
208 sc->flags = 0;
209
210 sc->sc_ih.ih_fun = mcdintr;
211 sc->sc_ih.ih_arg = sc;
212 sc->sc_ih.ih_level = IPL_BIO;
213 intr_establish(ia->ia_irq, &sc->sc_ih);
214 }
215
216 int
217 mcdopen(dev)
218 dev_t dev;
219 {
220 int unit, part, phys;
221 struct mcd_softc *sc;
222
223 unit = MCDUNIT(dev);
224 if (unit >= mcdcd.cd_ndevs)
225 return ENXIO;
226 sc = mcdcd.cd_devs[unit];
227 if (!sc)
228 return ENXIO;
229
230 part = MCDPART(dev);
231 phys = MCDPHYS(dev);
232
233 /* Invalidated in the meantime? Mark all open part's invalid. */
234 if (!(sc->flags & MCDVALID) && sc->openflags)
235 return ENXIO;
236
237 if (mcd_getstat(sc, 1) < 0)
238 return ENXIO;
239
240 /* XXX Get a default disklabel. */
241 mcd_getdisklabel(sc);
242
243 if (mcdsize(dev) < 0) {
244 printf("%s: failed to get disk size\n", sc->sc_dev.dv_xname);
245 return ENXIO;
246 } else
247 sc->flags |= MCDVALID;
248
249 MCD_TRACE("open: partition=%d disksize=%d blksize=%d\n", part,
250 sc->disksize, sc->blksize, 0);
251
252 if (part != RAW_PART &&
253 (part >= sc->dlabel.d_npartitions ||
254 sc->dlabel.d_partitions[part].p_fstype == FS_UNUSED))
255 return ENXIO;
256
257 sc->partflags[part] |= MCDOPEN;
258 sc->openflags |= (1 << part);
259 if (part == RAW_PART && phys != 0)
260 sc->partflags[part] |= MCDREADRAW;
261 return 0;
262 }
263
264 int
265 mcdclose(dev)
266 dev_t dev;
267 {
268 int unit, part;
269 struct mcd_softc *sc;
270
271 unit = MCDUNIT(dev);
272 part = MCDPART(dev);
273 sc = mcdcd.cd_devs[unit];
274
275 /* Get status. */
276 mcd_getstat(sc, 1);
277
278 /* Close channel. */
279 sc->partflags[part] &= ~(MCDOPEN | MCDREADRAW);
280 sc->openflags &= ~(1 << part);
281 MCD_TRACE("close: partition=%d\n", part, 0, 0, 0);
282
283 return 0;
284 }
285
286 void
287 mcdstrategy(bp)
288 struct buf *bp;
289 {
290 struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(bp->b_dev)];
291 struct buf *qp;
292 int s;
293
294 /* Test validity. */
295 MCD_TRACE("strategy: buf=0x%lx blkno=%ld bcount=%ld\n", bp,
296 bp->b_blkno, bp->b_bcount, 0);
297 if (bp->b_blkno < 0) {
298 printf("%s: strategy: blkno=%d bcount=%d\n",
299 sc->sc_dev.dv_xname, bp->b_blkno, bp->b_bcount);
300 bp->b_error = EINVAL;
301 bp->b_flags |= B_ERROR;
302 goto bad;
303 }
304
305 /* If device invalidated (e.g. media change, door open), error. */
306 if (!(sc->flags & MCDVALID)) {
307 MCD_TRACE("strategy: drive not valid\n", 0, 0, 0, 0);
308 bp->b_error = EIO;
309 goto bad;
310 }
311
312 /* Check for read only. */
313 if (!(bp->b_flags & B_READ)) {
314 bp->b_error = EROFS;
315 goto bad;
316 }
317
318 /* No data to read. */
319 if (bp->b_bcount == 0)
320 goto done;
321
322 /* For non raw access, check partition limits. */
323 if (MCDPART(bp->b_dev) != RAW_PART) {
324 if (!(sc->flags & MCDLABEL)) {
325 bp->b_error = EIO;
326 goto bad;
327 }
328 /* Adjust transfer if necessary. */
329 if (bounds_check_with_label(bp, &sc->dlabel, 1) <= 0)
330 goto done;
331 }
332
333 /* Queue it. */
334 qp = &sc->head;
335 s = splbio();
336 disksort(qp, bp);
337 splx(s);
338
339 /* Now check whether we can perform processing. */
340 mcd_start(sc);
341 return;
342
343 bad:
344 bp->b_flags |= B_ERROR;
345 done:
346 bp->b_resid = bp->b_bcount;
347 biodone(bp);
348 return;
349 }
350
351 int
352 mcd_start(sc)
353 struct mcd_softc *sc;
354 {
355 struct buf *bp, *qp = &sc->head;
356 struct partition *p;
357 int s = splbio();
358
359 if (sc->flags & MCDMBXBSY) {
360 splx(s);
361 return;
362 }
363
364 if ((bp = qp->b_actf) != 0) {
365 /* Block found to process; dequeue. */
366 MCD_TRACE("start: found block bp=0x%x\n", bp, 0, 0, 0);
367 qp->b_actf = bp->b_actf;
368 splx(s);
369 } else {
370 /* Nothing to do; */
371 splx(s);
372 return;
373 }
374
375 /* Changed media? */
376 if (!(sc->flags & MCDVALID)) {
377 MCD_TRACE("start: drive not valid\n", 0, 0, 0, 0);
378 return;
379 }
380
381 p = &sc->dlabel.d_partitions[MCDPART(bp->b_dev)];
382
383 sc->flags |= MCDMBXBSY;
384 sc->mbx.unit = sc->sc_dev.dv_unit;
385 sc->mbx.retry = MCD_RETRIES;
386 sc->mbx.bp = bp;
387 sc->mbx.p_offset = p->p_offset;
388
389 /* Calling the read routine. */
390 sc->mbx.state = MCD_S_BEGIN;
391 mcd_doread(&sc->mbx);
392 /* triggers mcd_start, when successful finished. */
393 }
394
395 int
396 mcdioctl(dev, cmd, addr, flags, p)
397 dev_t dev;
398 int cmd;
399 caddr_t addr;
400 int flags;
401 struct proc *p;
402 {
403 struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(dev)];
404
405 if (!(sc->flags & MCDVALID))
406 return EIO;
407 MCD_TRACE("ioctl: cmd=0x%x\n", cmd, 0, 0, 0);
408
409 switch (cmd) {
410 case DIOCSBAD:
411 return EINVAL;
412 case DIOCGDINFO:
413 case DIOCGPART:
414 case DIOCWDINFO:
415 case DIOCSDINFO:
416 case DIOCWLABEL:
417 return ENOTTY;
418 case CDIOCPLAYTRACKS:
419 return mcd_playtracks(sc, (struct ioc_play_track *) addr);
420 case CDIOCPLAYBLOCKS:
421 return mcd_play(sc, (struct mcd_read2 *) addr);
422 case CDIOCREADSUBCHANNEL:
423 return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
424 case CDIOREADTOCHEADER:
425 return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
426 case CDIOREADTOCENTRYS:
427 return mcd_toc_entry(sc, (struct ioc_read_toc_entry *) addr);
428 case CDIOCSETPATCH:
429 case CDIOCGETVOL:
430 case CDIOCSETVOL:
431 case CDIOCSETMONO:
432 case CDIOCSETSTEREO:
433 case CDIOCSETMUTE:
434 case CDIOCSETLEFT:
435 case CDIOCSETRIGHT:
436 return EINVAL;
437 case CDIOCRESUME:
438 return mcd_resume(sc);
439 case CDIOCPAUSE:
440 return mcd_pause(sc);
441 case CDIOCSTART:
442 return EINVAL;
443 case CDIOCSTOP:
444 return mcd_stop(sc);
445 case CDIOCEJECT:
446 return EINVAL;
447 case CDIOCSETDEBUG:
448 sc->debug = 1;
449 return 0;
450 case CDIOCCLRDEBUG:
451 sc->debug = 0;
452 return 0;
453 case CDIOCRESET:
454 return EINVAL;
455 default:
456 return ENOTTY;
457 }
458 #ifdef DIAGNOSTIC
459 panic("mcdioctl: impossible");
460 #endif
461 }
462
463 /*
464 * This could have been taken from scsi/cd.c, but it is not clear
465 * whether the scsi cd driver is linked in.
466 */
467 int
468 mcd_getdisklabel(sc)
469 struct mcd_softc *sc;
470 {
471
472 if (sc->flags & MCDLABEL)
473 return -1;
474
475 bzero(&sc->dlabel, sizeof(struct disklabel));
476 strncpy(sc->dlabel.d_typename, "Mitsumi CD ROM ", 16);
477 strncpy(sc->dlabel.d_packname, "unknown ", 16);
478 sc->dlabel.d_secsize = sc->blksize;
479 sc->dlabel.d_nsectors = 100;
480 sc->dlabel.d_ntracks = 1;
481 sc->dlabel.d_ncylinders = (sc->disksize /100) + 1;
482 sc->dlabel.d_secpercyl = 100;
483 sc->dlabel.d_secperunit = sc->disksize;
484 sc->dlabel.d_rpm = 300;
485 sc->dlabel.d_interleave = 1;
486 sc->dlabel.d_flags = D_REMOVABLE;
487 sc->dlabel.d_npartitions= 1;
488 sc->dlabel.d_partitions[0].p_offset = 0;
489 sc->dlabel.d_partitions[0].p_size = sc->disksize;
490 sc->dlabel.d_partitions[0].p_fstype = 9;
491 sc->dlabel.d_magic = DISKMAGIC;
492 sc->dlabel.d_magic2 = DISKMAGIC;
493 sc->dlabel.d_checksum = dkcksum(&sc->dlabel);
494
495 sc->flags |= MCDLABEL;
496 return 0;
497 }
498
499 int
500 mcdsize(dev)
501 dev_t dev;
502 {
503 int size;
504 struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(dev)];
505
506 if (mcd_volinfo(sc) >= 0) {
507 sc->blksize = MCDBLK;
508 size = msf2hsg(sc->volinfo.vol_msf);
509 sc->disksize = size * (MCDBLK / DEV_BSIZE);
510 return 0;
511 }
512 return -1;
513 }
514
515 int
516 mcddump()
517 {
518
519 /* Not implemented. */
520 return EINVAL;
521 }
522
523 /***************************************************************
524 * lower level of driver starts here
525 **************************************************************/
526
527 #ifdef notyet
528 static char irqs[] = {
529 0x00, 0x00, 0x10, 0x20, 0x00, 0x30, 0x00, 0x00,
530 0x00, 0x10, 0x40, 0x50, 0x00, 0x00, 0x00, 0x00
531 };
532
533 static char drqs[] = {
534 0x00, 0x01, 0x00, 0x03, 0x00, 0x05, 0x06, 0x07
535 };
536 #endif
537
538 void
539 mcd_configure(sc)
540 struct mcd_softc *sc;
541 {
542
543 outb(sc->iobase + mcd_config, sc->config);
544 }
545
546 int
547 mcdprobe(parent, self, aux)
548 struct device *parent, *self;
549 void *aux;
550 {
551 struct mcd_softc *sc = (void *)self;
552 struct isa_attach_args *ia = aux;
553 u_short iobase = ia->ia_iobase;
554 int i;
555 int st, check, version;
556
557 #ifdef notyet
558 /* Get irq/drq configuration word. */
559 sc->config = irqs[ia->ia_irq];
560 #endif
561 sc->iobase = iobase;
562
563 /* Send a reset. */
564 outb(iobase + mcd_reset, 0);
565 delay(1000000);
566 /* Get any pending status and throw away. */
567 for (i = 10; i; i--)
568 inb(iobase + mcd_status);
569 delay(1000);
570
571 /* Send get status command. */
572 outb(iobase + mcd_command, MCD_CMDGETSTAT);
573 st = mcd_getreply(sc, DELAY_GETREPLY);
574
575 if (st < 0) {
576 #ifdef DEBUG
577 printf("Mitsumi drive NOT detected\n");
578 #endif
579 return 0;
580 }
581
582 /*
583 * The following code uses the 0xDC command, it returns a M from the
584 * second byte and a number in the third.
585 * (I hope you have the right drive for that, most drives don't do!)
586 * Whole code entirely rewriten by veit (at) gmd.de, the changes accessed
587 * the drive in an illegal way. Proper way is to use the timeout
588 * driven routines mcd_getreply etc. rather than arbitrary delays.
589 */
590
591 delay(2000);
592 outb(iobase + mcd_command, MCD_CMDCONTINFO);
593 st = mcd_getreply(sc, DELAY_GETREPLY);
594
595 if (st < 0) {
596 #ifdef DEBUG
597 printf("Mitsumi drive error\n");
598 #endif
599 return 0;
600 }
601 check = mcd_getreply(sc, DELAY_GETREPLY);
602 if (check < 0)
603 return 0;
604 version = mcd_getreply(sc, DELAY_GETREPLY);
605 if (version < 0)
606 return 0;
607 /* Flush junk. */
608 (void) mcd_getreply(sc, DELAY_GETREPLY);
609
610 /*
611 * The following is code which is not guaranteed to work for all
612 * drives, because the meaning of the expected 'M' is not clear
613 * (M_itsumi is an obvious assumption, but I don't trust that).
614 * Also, the original hack had a bogus condition that always
615 * returned true.
616 */
617 if (check != 'D' && check != 'M') {
618 printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n",
619 sc->sc_dev.dv_xname, check, version);
620 }
621
622 #ifdef DEBUG
623 printf("Mitsumi drive detected\n");
624 #endif
625 ia->ia_iosize = 4;
626 ia->ia_msize = 0;
627 return 1;
628 }
629
630 int
631 mcd_waitrdy(iobase, dly)
632 u_short iobase;
633 int dly;
634 {
635 int i;
636
637 /* Wait until xfer port senses data ready. */
638 for (i = dly; i; i--) {
639 if ((inb(iobase + mcd_xfer) & MCD_ST_BUSY) == 0)
640 return 0;
641 delay(1);
642 }
643 return -1;
644 }
645
646 int
647 mcd_getreply(sc, dly)
648 struct mcd_softc *sc;
649 int dly;
650 {
651 u_short iobase = sc->iobase;
652
653 /* Wait data to become ready. */
654 if (mcd_waitrdy(iobase, dly) < 0) {
655 printf("%s: timeout in getreply\n", sc->sc_dev.dv_xname);
656 return -1;
657 }
658
659 /* Get the data. */
660 return inb(iobase + mcd_status);
661 }
662
663 int
664 mcd_getstat(sc, sflg)
665 struct mcd_softc *sc;
666 int sflg;
667 {
668 int i;
669 u_short iobase = sc->iobase;
670
671 /* Get the status. */
672 if (sflg)
673 outb(iobase + mcd_command, MCD_CMDGETSTAT);
674 i = mcd_getreply(sc, DELAY_GETREPLY);
675 if (i < 0) {
676 printf("%s: timeout in getstat\n", sc->sc_dev.dv_xname);
677 return -1;
678 }
679
680 sc->status = i;
681
682 mcd_setflags(sc);
683 return sc->status;
684 }
685
686 void
687 mcd_setflags(sc)
688 struct mcd_softc *sc;
689 {
690
691 /* Check flags. */
692 if (sc->status & (MCDDSKCHNG | MCDDOOROPEN)) {
693 MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n", 0, 0, 0, 0);
694 sc->flags &= ~MCDVALID;
695 }
696
697 if (sc->status & MCDAUDIOBSY)
698 sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
699 else if (sc->audio_status == CD_AS_PLAY_IN_PROGRESS)
700 sc->audio_status = CD_AS_PLAY_COMPLETED;
701 }
702
703 int
704 mcd_get(sc, buf, nmax)
705 struct mcd_softc *sc;
706 char *buf;
707 int nmax;
708 {
709 int i, k;
710
711 for (i = 0; i < nmax; i++) {
712 /* Wait for data. */
713 if ((k = mcd_getreply(sc, DELAY_GETREPLY)) < 0) {
714 printf("%s: timeout in get\n", sc->sc_dev.dv_xname);
715 return -1;
716 }
717 buf[i] = k;
718 }
719 return i;
720 }
721
722 int
723 mcd_send(sc, cmd, nretries)
724 struct mcd_softc *sc;
725 int cmd, nretries;
726 {
727 int i, k;
728 u_short iobase = sc->iobase;
729
730 MCD_TRACE("send: cmd=0x%x\n", cmd, 0, 0, 0);
731
732 for (i = nretries; i; i--) {
733 outb(iobase + mcd_command, cmd);
734 if ((k = mcd_getstat(sc, 0)) != -1)
735 break;
736 }
737 if (!i) {
738 printf("%s: send: retry count exceeded\n", sc->sc_dev.dv_xname);
739 return -1;
740 }
741
742 MCD_TRACE("send: status=0x%x\n", k, 0, 0, 0);
743
744 return 0;
745 }
746
747 int
748 bcd2bin(b)
749 bcd_t b;
750 {
751
752 return (b >> 4) * 10 + (b & 15);
753 }
754
755 bcd_t
756 bin2bcd(b)
757 int b;
758 {
759
760 return ((b / 10) << 4) | (b % 10);
761 }
762
763 void
764 hsg2msf(hsg, msf)
765 int hsg;
766 bcd_t *msf;
767 {
768
769 hsg += 150;
770 M_msf(msf) = bin2bcd(hsg / 4500);
771 hsg %= 4500;
772 S_msf(msf) = bin2bcd(hsg / 75);
773 F_msf(msf) = bin2bcd(hsg % 75);
774 }
775
776 int
777 msf2hsg(msf)
778 bcd_t *msf;
779 {
780
781 return (bcd2bin(M_msf(msf)) * 60 +
782 bcd2bin(S_msf(msf))) * 75 +
783 bcd2bin(F_msf(msf)) - 150;
784 }
785
786 int
787 mcd_volinfo(sc)
788 struct mcd_softc *sc;
789 {
790
791 MCD_TRACE("volinfo: enter\n", 0, 0, 0, 0);
792
793 /* Get the status, in case the disc has been changed. */
794 if (mcd_getstat(sc, 1) < 0)
795 return EIO;
796
797 /* Just return if we already have it. */
798 if (sc->flags & MCDVOLINFO)
799 return 0;
800
801 /* Send volume info command. */
802 if (mcd_send(sc, MCD_CMDGETVOLINFO, MCD_RETRIES) < 0)
803 return -1;
804
805 /* Get the data. */
806 if (mcd_get(sc, (char*) &sc->volinfo, sizeof(struct mcd_volinfo)) < 0) {
807 printf("%s: volinfo: error reading data\n",
808 sc->sc_dev.dv_xname);
809 return -1;
810 }
811
812 if (sc->volinfo.trk_low != 0 || sc->volinfo.trk_high != 0) {
813 /* Volinfo is OK. */
814 sc->flags |= MCDVOLINFO;
815 return 0;
816 }
817
818 return -1;
819 }
820
821 int
822 mcdintr(sc)
823 struct mcd_softc *sc;
824 {
825 u_short iobase = sc->iobase;
826
827 MCD_TRACE("stray interrupt xfer=0x%x\n", inb(iobase + mcd_xfer),
828 0, 0, 0);
829
830 /* Just read out status and ignore the rest. */
831 if (inb(iobase + mcd_xfer) != 0xff)
832 (void) inb(iobase + mcd_status);
833
834 return -1;
835 }
836
837 /*
838 * State machine to process read requests.
839 * Initialize with MCD_S_BEGIN: calculate sizes, and read status
840 * MCD_S_WAITSTAT: wait for status reply, set mode
841 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
842 * MCD_S_WAITREAD: wait for read ready, read data.
843 */
844 void
845 mcd_doread(arg)
846 void *arg;
847 {
848 struct mcd_mbx *mbx = arg;
849 struct mcd_softc *sc = mcdcd.cd_devs[mbx->unit];
850 u_short iobase = sc->iobase;
851 struct buf *bp = mbx->bp;
852
853 int rm, i, k;
854 struct mcd_read2 rbuf;
855 int blkno;
856 caddr_t addr;
857
858 loop:
859 switch (mbx->state) {
860 case MCD_S_BEGIN:
861 /* Get status. */
862 outb(iobase + mcd_command, MCD_CMDGETSTAT);
863
864 mbx->count = RDELAY_WAITSTAT;
865 mbx->state = MCD_S_WAITSTAT;
866 timeout(mcd_doread, mbx, hz / 100);
867 return;
868
869 case MCD_S_WAITSTAT:
870 untimeout(mcd_doread, mbx);
871 if (mbx->count-- < 0) {
872 printf("%s: timeout getting status\n",
873 sc->sc_dev.dv_xname);
874 goto readerr;
875 }
876 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
877 timeout(mcd_doread, mbx, hz / 100);
878 return;
879 }
880 mcd_setflags(sc);
881 MCD_TRACE("doread: got WAITSTAT delay=%d\n",
882 RDELAY_WAITSTAT - mbx->count, 0, 0, 0);
883
884 /* Reject, if audio active. */
885 if (sc->status & MCDAUDIOBSY) {
886 printf("%s: audio is active\n",
887 sc->sc_dev.dv_xname);
888 goto readerr;
889 }
890
891 /* Check for raw/cooked mode. */
892 if (sc->flags & MCDREADRAW) {
893 rm = MCD_MD_RAW;
894 mbx->sz = MCDRBLK;
895 } else {
896 rm = MCD_MD_COOKED;
897 mbx->sz = sc->blksize;
898 }
899
900 mcd_put(iobase + mcd_command, MCD_CMDSETMODE);
901 mcd_put(iobase + mcd_command, rm);
902
903 mbx->count = RDELAY_WAITMODE;
904 mbx->state = MCD_S_WAITMODE;
905 timeout(mcd_doread, mbx, hz / 100);
906 return;
907
908 case MCD_S_WAITMODE:
909 untimeout(mcd_doread, mbx);
910 if (mbx->count-- < 0) {
911 printf("%s: timeout setting mode\n",
912 sc->sc_dev.dv_xname);
913 goto readerr;
914 }
915 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
916 timeout(mcd_doread, mbx, hz / 100);
917 return;
918 }
919 mcd_setflags(sc);
920 MCD_TRACE("doread: got WAITMODE delay=%d\n",
921 RDELAY_WAITMODE - mbx->count, 0, 0, 0);
922
923 /* For first block. */
924 mbx->nblk = (bp->b_bcount + (mbx->sz - 1)) / mbx->sz;
925 mbx->skip = 0;
926
927 nextblock:
928 blkno = (bp->b_blkno / (mbx->sz / DEV_BSIZE)) + mbx->p_offset +
929 (mbx->skip / mbx->sz);
930
931 MCD_TRACE("doread: read blkno=%d for bp=0x%x\n", blkno, bp, 0,
932 0);
933
934 /* Build parameter block. */
935 hsg2msf(blkno, rbuf.start_msf);
936
937 /* Send the read command. */
938 mcd_put(iobase + mcd_command, MCD_CMDREAD2);
939 mcd_put(iobase + mcd_command, rbuf.start_msf[0]);
940 mcd_put(iobase + mcd_command, rbuf.start_msf[1]);
941 mcd_put(iobase + mcd_command, rbuf.start_msf[2]);
942 mcd_put(iobase + mcd_command, 0);
943 mcd_put(iobase + mcd_command, 0);
944 mcd_put(iobase + mcd_command, 1);
945
946 mbx->count = RDELAY_WAITREAD;
947 mbx->state = MCD_S_WAITREAD;
948 timeout(mcd_doread, mbx, hz / 100);
949 return;
950
951 case MCD_S_WAITREAD:
952 untimeout(mcd_doread, mbx);
953 if (mbx->count-- < 0) {
954 printf("%s: timeout reading data\n",
955 sc->sc_dev.dv_xname);
956 goto readerr;
957 }
958
959 k = inb(iobase + mcd_xfer);
960 if ((k & 2) == 0) { /* XXX MCD_ST_AUDIOBSY? */
961 MCD_TRACE("doread: got data delay=%d\n",
962 RDELAY_WAITREAD - mbx->count, 0, 0, 0);
963 /* Data is ready. */
964 addr = bp->b_data + mbx->skip;
965 outb(iobase + mcd_ctl2, 0x04); /* XXX */
966 for (i = 0; i < mbx->sz; i++)
967 *addr++ = inb(iobase + mcd_rdata);
968 outb(iobase + mcd_ctl2, 0x0c); /* XXX */
969
970 if (--mbx->nblk > 0) {
971 mbx->skip += mbx->sz;
972 goto nextblock;
973 }
974
975 /* Return buffer. */
976 bp->b_resid = 0;
977 biodone(bp);
978
979 sc->flags &= ~MCDMBXBSY;
980 mcd_start(sc);
981 return;
982 }
983 if ((k & MCD_ST_BUSY) == 0)
984 mcd_getstat(sc, 0);
985 timeout(mcd_doread, mbx, hz / 100);
986 return;
987 }
988
989 readerr:
990 if (mbx->retry-- > 0) {
991 printf("%s: retrying\n", sc->sc_dev.dv_xname);
992 mbx->state = MCD_S_BEGIN;
993 goto loop;
994 }
995
996 /* Invalidate the buffer. */
997 bp->b_flags |= B_ERROR;
998 bp->b_resid = bp->b_bcount;
999 biodone(bp);
1000 mcd_start(sc);
1001
1002 #ifdef notyet
1003 printf("%s: unit timeout; resetting\n", sc->sc_dev.dv_xname);
1004 outb(mbx->iobase + mcd_reset, MCD_CMDRESET);
1005 delay(300000);
1006 (void)mcd_getstat(sc, 1);
1007 (void)mcd_getstat(sc, 1);
1008 /*sc->status &= ~MCDDSKCHNG; */
1009 sc->debug = 1; /* preventive set debug mode */
1010 #endif
1011 }
1012
1013 int
1014 mcd_setmode(sc, mode)
1015 struct mcd_softc *sc;
1016 int mode;
1017 {
1018 u_short iobase = sc->iobase;
1019 int retry;
1020
1021 printf("%s: setting mode to %d\n", sc->sc_dev.dv_xname, mode);
1022 for (retry = MCD_RETRIES; retry; retry--) {
1023 outb(iobase + mcd_command, MCD_CMDSETMODE);
1024 outb(iobase + mcd_command, mode);
1025 if (mcd_getstat(sc, 0) != -1)
1026 return 0;
1027 }
1028
1029 return -1;
1030 }
1031
1032 int
1033 mcd_toc_header(sc, th)
1034 struct mcd_softc *sc;
1035 struct ioc_toc_header *th;
1036 {
1037
1038 if (mcd_volinfo(sc) < 0)
1039 return ENXIO;
1040
1041 th->len = msf2hsg(sc->volinfo.vol_msf);
1042 th->starting_track = bcd2bin(sc->volinfo.trk_low);
1043 th->ending_track = bcd2bin(sc->volinfo.trk_high);
1044
1045 return 0;
1046 }
1047
1048 int
1049 mcd_read_toc(sc)
1050 struct mcd_softc *sc;
1051 {
1052 struct ioc_toc_header th;
1053 struct mcd_qchninfo q;
1054 int rc, trk, idx, retry;
1055
1056 /* Only read TOC if needed. */
1057 if (sc->flags & MCDTOC)
1058 return 0;
1059
1060 if (sc->debug)
1061 printf("%s: read_toc: reading toc header\n",
1062 sc->sc_dev.dv_xname);
1063 if (mcd_toc_header(sc, &th) != 0)
1064 return ENXIO;
1065
1066 if (sc->debug)
1067 printf("%s: read_toc: stopping play\n", sc->sc_dev.dv_xname);
1068 if ((rc = mcd_stop(sc)) != 0)
1069 return rc;
1070
1071 /* Try setting the mode twice. */
1072 if (mcd_setmode(sc, MCD_MD_TOC) != 0)
1073 return EIO;
1074 if (mcd_setmode(sc, MCD_MD_TOC) != 0)
1075 return EIO;
1076
1077 if (sc->debug)
1078 printf("%s: read_toc: reading qchannel info\n",
1079 sc->sc_dev.dv_xname);
1080 for (trk = th.starting_track; trk <= th.ending_track; trk++)
1081 sc->toc[trk].idx_no = 0;
1082 trk = th.ending_track - th.starting_track + 1;
1083 for (retry = 300; retry && trk > 0; retry--) {
1084 if (mcd_getqchan(sc, &q) < 0)
1085 break;
1086 idx = bcd2bin(q.idx_no);
1087 if (idx > 0 && idx < MCD_MAXTOCS && q.trk_no == 0 &&
1088 sc->toc[idx].idx_no == 0) {
1089 sc->toc[idx] = q;
1090 trk--;
1091 }
1092 }
1093
1094 if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
1095 return EIO;
1096
1097 if (trk != 0)
1098 return ENXIO;
1099
1100 /* Add a fake last+1. */
1101 idx = th.ending_track + 1;
1102 sc->toc[idx].ctrl_adr = sc->toc[idx-1].ctrl_adr;
1103 sc->toc[idx].trk_no = 0;
1104 sc->toc[idx].idx_no = 0xaa;
1105 sc->toc[idx].hd_pos_msf[0] = sc->volinfo.vol_msf[0];
1106 sc->toc[idx].hd_pos_msf[1] = sc->volinfo.vol_msf[1];
1107 sc->toc[idx].hd_pos_msf[2] = sc->volinfo.vol_msf[2];
1108
1109 sc->flags |= MCDTOC;
1110
1111 return 0;
1112 }
1113
1114 int
1115 mcd_toc_entry(sc, te)
1116 struct mcd_softc *sc;
1117 struct ioc_read_toc_entry *te;
1118 {
1119 struct ret_toc {
1120 struct ioc_toc_header th;
1121 struct cd_toc_entry rt;
1122 } ret_toc;
1123 struct ioc_toc_header th;
1124 int rc, i;
1125
1126 /* Make sure we have a valid TOC. */
1127 if ((rc = mcd_read_toc(sc)) != 0)
1128 return rc;
1129
1130 /* Find the TOC to copy. */
1131 i = te->starting_track;
1132 if (i == MCD_LASTPLUS1)
1133 i = bcd2bin(sc->volinfo.trk_high) + 1;
1134
1135 /* Verify starting track. */
1136 if (i < bcd2bin(sc->volinfo.trk_low) ||
1137 i > bcd2bin(sc->volinfo.trk_high) + 1)
1138 return EINVAL;
1139
1140 /* Do we have room? */
1141 if (te->data_len < sizeof(struct ioc_toc_header) +
1142 sizeof(struct cd_toc_entry))
1143 return EINVAL;
1144
1145 /* Copy the TOC header. */
1146 if (mcd_toc_header(sc, &th) < 0)
1147 return EIO;
1148 ret_toc.th = th;
1149
1150 /* Copy the TOC data. */
1151 ret_toc.rt.control = sc->toc[i].ctrl_adr;
1152 ret_toc.rt.addr_type = te->address_format;
1153 ret_toc.rt.track = i;
1154 if (te->address_format == CD_MSF_FORMAT) {
1155 ret_toc.rt.addr[1] = sc->toc[i].hd_pos_msf[0];
1156 ret_toc.rt.addr[2] = sc->toc[i].hd_pos_msf[1];
1157 ret_toc.rt.addr[3] = sc->toc[i].hd_pos_msf[2];
1158 }
1159
1160 /* Copy the data back. */
1161 copyout(&ret_toc, te->data,
1162 sizeof(struct cd_toc_entry) + sizeof(struct ioc_toc_header));
1163
1164 return 0;
1165 }
1166
1167 int
1168 mcd_stop(sc)
1169 struct mcd_softc *sc;
1170 {
1171
1172 if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRIES) < 0)
1173 return ENXIO;
1174 sc->audio_status = CD_AS_PLAY_COMPLETED;
1175 return 0;
1176 }
1177
1178 int
1179 mcd_getqchan(sc, q)
1180 struct mcd_softc *sc;
1181 struct mcd_qchninfo *q;
1182 {
1183
1184 if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRIES) < 0)
1185 return -1;
1186 if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0)
1187 return -1;
1188 if (sc->debug)
1189 printf("%s: getqchan: ctl=%d t=%d i=%d ttm=%d:%d.%d dtm=%d:%d.%d\n",
1190 sc->sc_dev.dv_xname, q->ctrl_adr, q->trk_no, q->idx_no,
1191 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
1192 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
1193 return 0;
1194 }
1195
1196 int
1197 mcd_subchan(sc, ch)
1198 struct mcd_softc *sc;
1199 struct ioc_read_subchannel *ch;
1200 {
1201 struct mcd_qchninfo q;
1202 struct cd_sub_channel_info data;
1203
1204 if (sc->debug)
1205 printf("%s: subchan: af=%d df=%d\n", sc->sc_dev.dv_xname,
1206 ch->address_format, ch->data_format);
1207
1208 if (ch->address_format != CD_MSF_FORMAT)
1209 return EIO;
1210 if (ch->data_format != CD_CURRENT_POSITION)
1211 return EIO;
1212 if (mcd_getqchan(sc, &q) < 0)
1213 return EIO;
1214
1215 data.header.audio_status = sc->audio_status;
1216 data.what.position.data_format = CD_MSF_FORMAT;
1217 data.what.position.track_number = bcd2bin(q.trk_no);
1218
1219 if (copyout(&data, ch->data, sizeof(struct cd_sub_channel_info)) != 0)
1220 return EFAULT;
1221 return 0;
1222 }
1223
1224 int
1225 mcd_playtracks(sc, pt)
1226 struct mcd_softc *sc;
1227 struct ioc_play_track *pt;
1228 {
1229 struct mcd_read2 pb;
1230 int a = pt->start_track;
1231 int z = pt->end_track;
1232 int rc;
1233
1234 if ((rc = mcd_read_toc(sc)) != 0)
1235 return rc;
1236
1237 printf("%s: playtracks: from %d:%d to %d:%d\n", sc->sc_dev.dv_xname,
1238 a, pt->start_index, z, pt->end_index);
1239
1240 if (a < sc->volinfo.trk_low || a > sc->volinfo.trk_high || a > z ||
1241 z < sc->volinfo.trk_low || z > sc->volinfo.trk_high)
1242 return EINVAL;
1243
1244 pb.start_msf[0] = sc->toc[a].hd_pos_msf[0];
1245 pb.start_msf[1] = sc->toc[a].hd_pos_msf[1];
1246 pb.start_msf[2] = sc->toc[a].hd_pos_msf[2];
1247 pb.end_msf[0] = sc->toc[z+1].hd_pos_msf[0];
1248 pb.end_msf[1] = sc->toc[z+1].hd_pos_msf[1];
1249 pb.end_msf[2] = sc->toc[z+1].hd_pos_msf[2];
1250
1251 return mcd_play(sc, &pb);
1252 }
1253
1254 int
1255 mcd_play(sc, pb)
1256 struct mcd_softc *sc;
1257 struct mcd_read2 *pb;
1258 {
1259 u_short iobase = sc->iobase;
1260 int retry, st;
1261
1262 sc->lastpb = *pb;
1263 for (retry = MCD_RETRIES; retry; retry--) {
1264 outb(iobase + mcd_command, MCD_CMDREAD2);
1265 outb(iobase + mcd_command, pb->start_msf[0]);
1266 outb(iobase + mcd_command, pb->start_msf[1]);
1267 outb(iobase + mcd_command, pb->start_msf[2]);
1268 outb(iobase + mcd_command, pb->end_msf[0]);
1269 outb(iobase + mcd_command, pb->end_msf[1]);
1270 outb(iobase + mcd_command, pb->end_msf[2]);
1271 if ((st = mcd_getstat(sc, 0)) != -1)
1272 break;
1273 }
1274 if (sc->debug)
1275 printf("%s: play: retry=%d status=%d\n", sc->sc_dev.dv_xname,
1276 retry, st);
1277 if (!retry)
1278 return ENXIO;
1279
1280 sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
1281 return 0;
1282 }
1283
1284 int
1285 mcd_pause(sc)
1286 struct mcd_softc *sc;
1287 {
1288 struct mcd_qchninfo q;
1289 int rc;
1290
1291 /* Verify current status. */
1292 if (sc->audio_status != CD_AS_PLAY_IN_PROGRESS) {
1293 printf("%s: pause: attempted when not playing\n",
1294 sc->sc_dev.dv_xname);
1295 return EINVAL;
1296 }
1297
1298 /* Get the current position. */
1299 if (mcd_getqchan(sc, &q) < 0)
1300 return EIO;
1301
1302 /* Copy it into lastpb. */
1303 sc->lastpb.start_msf[0] = q.hd_pos_msf[0];
1304 sc->lastpb.start_msf[1] = q.hd_pos_msf[1];
1305 sc->lastpb.start_msf[2] = q.hd_pos_msf[2];
1306
1307 /* Stop playing. */
1308 if ((rc = mcd_stop(sc)) != 0)
1309 return rc;
1310
1311 /* Set the proper status and exit. */
1312 sc->audio_status = CD_AS_PLAY_PAUSED;
1313 return 0;
1314 }
1315
1316 int
1317 mcd_resume(sc)
1318 struct mcd_softc *sc;
1319 {
1320
1321 if (sc->audio_status != CD_AS_PLAY_PAUSED)
1322 return EINVAL;
1323 return mcd_play(sc, &sc->lastpb);
1324 }
1325