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