mcd.c revision 1.1.2.4 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.4 1994/02/02 07:00:15 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/disk.h>
61 #include <sys/device.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 (cd->debug) {printf("%s: st=%02x: ", cd->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_data {
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 cfdata *, 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_data) };
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_data *));
158 int mcdioctl __P((dev_t, int, caddr_t, int));
159 static int mcd_getdisklabel __P((struct mcd_data *));
160 int mcdsize __P((dev_t));
161 static void mcd_configure __P((struct mcd_data *));
162 static int mcd_waitrdy __P((u_short, int));
163 static int mcd_getreply __P((struct mcd_data *, int));
164 static int mcd_getstat __P((struct mcd_data *, int));
165 static void mcd_setflags __P((struct mcd_data *));
166 static int mcd_get __P((struct mcd_data *, char *, int));
167 static int mcd_send __P((struct mcd_data *, 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_data *));
173 int mcdintr __P((caddr_t));
174 static void mcd_doread __P((int, struct mcd_mbx *));
175 static int mcd_setmode __P((struct mcd_data *, int));
176 static int mcd_toc_header __P((struct mcd_data *, struct ioc_toc_header *));
177 static int mcd_read_toc __P((struct mcd_data *));
178 static int mcd_toc_entry __P((struct mcd_data *, struct ioc_read_toc_entry *));
179 static int mcd_stop __P((struct mcd_data *));
180 static int mcd_getqchan __P((struct mcd_data *, struct mcd_qchninfo *));
181 static int mcd_subchan __P((struct mcd_data *, struct ioc_read_subchannel *));
182 static int mcd_playtracks __P((struct mcd_data *, struct ioc_play_track *));
183 static int mcd_play __P((struct mcd_data *, struct mcd_read2 *));
184 static int mcd_pause __P((struct mcd_data *));
185 static int mcd_resume __P((struct mcd_data *));
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 mcd_data *cd = (void *)self;
210 struct isa_attach_args *ia = aux;
211
212 cd->iobase = ia->ia_iobase;
213 cd->flags = MCDINIT;
214
215 #ifdef notyet
216 /* get irq/drq configuration word */
217 cd->config = irqs[ia->ia_irq]; /* | drqs[ia->ia_drq];*/
218 /* wire controller for interrupts and dma */
219 mcd_configure(cd);
220 #endif
221
222 printf(": Mitsumi CD-ROM\n");
223
224 isa_establish(&cd->sc_id, &cd->sc_dev);
225 cd->sc_ih.ih_fun = mcdintr;
226 cd->sc_ih.ih_arg = cd;
227 intr_establish(ia->ia_irq, &cd->sc_ih, DV_DISK);
228 cd->sc_dk.dk_driver = &mcddkdriver;
229 dk_establish(&cd->sc_dk, &cd->sc_dev);
230 }
231
232 int
233 mcdopen(dev)
234 dev_t dev;
235 {
236 int unit, part, phys;
237 struct mcd_data *cd;
238
239 unit = MCDUNIT(dev);
240 part = MCDPART(dev);
241 phys = MCDPHYS(dev);
242
243 if (unit >= mcdcd.cd_ndevs)
244 return ENXIO;
245 cd = mcdcd.cd_devs[unit];
246 if (!cd || !(cd->flags & MCDINIT))
247 return ENXIO;
248
249 /* invalidated in the meantime? mark all open part's invalid */
250 if (!(cd->flags & MCDVALID) && cd->openflags)
251 return EBUSY;
252
253 if (mcd_getstat(cd, 1) < 0)
254 return ENXIO;
255
256 /* XXX get a default disklabel */
257 mcd_getdisklabel(cd);
258
259 if (mcdsize(dev) < 0) {
260 printf("%s: failed to get disk size\n", cd->sc_dev.dv_xname);
261 return ENXIO;
262 } else
263 cd->flags |= MCDVALID;
264
265 MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n",
266 part,cd->disksize,cd->blksize,0);
267
268 if (part == RAW_PART ||
269 (part < cd->dlabel.d_npartitions &&
270 cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) {
271 cd->partflags[part] |= MCDOPEN;
272 cd->openflags |= (1<<part);
273 if (part == RAW_PART && phys != 0)
274 cd->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_data *cd;
287
288 unit = MCDUNIT(dev);
289 part = MCDPART(dev);
290 cd = mcdcd.cd_devs[unit];
291
292 mcd_getstat(cd, 1); /* get status */
293
294 /* close channel */
295 cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW);
296 cd->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_data *cd;
307 struct buf *qp;
308 int s;
309
310 cd = 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, cd->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 cd->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 (!(cd->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 (!(cd->flags & MCDLABEL)) {
343 bp->b_error = EIO;
344 goto bad;
345 }
346 /* adjust transfer if necessary */
347 if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
348 goto done;
349 }
350 }
351
352 /* queue it */
353 qp = &cd->head;
354 s = splbio();
355 disksort(qp,bp);
356 splx(s);
357
358 /* now check whether we can perform processing */
359 mcd_start(cd);
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(cd)
372 struct mcd_data *cd;
373 {
374 struct buf *bp, *qp = &cd->head;
375 struct partition *p;
376 int s = splbio();
377
378 if (cd->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 (!(cd->flags & MCDVALID)) {
394 MCD_TRACE("mcd_start: drive not valid\n", 0, 0, 0, 0);
395 return;
396 }
397
398 p = &cd->sc_dk.dk_label.d_partitions[MCDPART(bp->b_dev)];
399
400 cd->flags |= MCDMBXBSY;
401 cd->mbx.unit = cd->sc_dev.dv_unit;
402 cd->mbx.iobase = cd->iobase;
403 cd->mbx.retry = MCD_RETRIES;
404 cd->mbx.bp = bp;
405 cd->mbx.p_offset = p->p_offset;
406
407 /* calling the read routine */
408 mcd_doread(MCD_S_BEGIN, &cd->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_data *cd;
419 int unit;
420
421 unit = MCDUNIT(dev);
422 cd = mcdcd.cd_devs[unit];
423
424 if (!(cd->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(cd, (struct ioc_play_track *) addr);
439 case CDIOCPLAYBLOCKS:
440 return mcd_play(cd, (struct mcd_read2 *) addr);
441 case CDIOCREADSUBCHANNEL:
442 return mcd_subchan(cd, (struct ioc_read_subchannel *) addr);
443 case CDIOREADTOCHEADER:
444 return mcd_toc_header(cd, (struct ioc_toc_header *) addr);
445 case CDIOREADTOCENTRYS:
446 return mcd_toc_entry(cd, (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(cd);
458 case CDIOCPAUSE:
459 return mcd_pause(cd);
460 case CDIOCSTART:
461 return EINVAL;
462 case CDIOCSTOP:
463 return mcd_stop(cd);
464 case CDIOCEJECT:
465 return EINVAL;
466 case CDIOCSETDEBUG:
467 cd->debug = 1;
468 return 0;
469 case CDIOCCLRDEBUG:
470 cd->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(cd)
487 struct mcd_data *cd;
488 {
489
490 if (cd->flags & MCDLABEL)
491 return -1;
492
493 bzero(&cd->sc_dk.dk_label, sizeof(struct disklabel));
494 bzero(&cd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
495 strncpy(cd->sc_dk.dk_label.d_typename, "Mitsumi CD ROM ", 16);
496 strncpy(cd->sc_dk.dk_label.d_packname, "unknown ", 16);
497 cd->sc_dk.dk_label.d_secsize = cd->blksize;
498 cd->sc_dk.dk_label.d_nsectors = 100;
499 cd->sc_dk.dk_label.d_ntracks = 1;
500 cd->sc_dk.dk_label.d_ncylinders = (cd->disksize/100)+1;
501 cd->sc_dk.dk_label.d_secpercyl = 100;
502 cd->sc_dk.dk_label.d_secperunit = cd->disksize;
503 cd->sc_dk.dk_label.d_rpm = 300;
504 cd->sc_dk.dk_label.d_interleave = 1;
505 cd->sc_dk.dk_label.d_flags = D_REMOVABLE;
506 cd->sc_dk.dk_label.d_npartitions= 1;
507 cd->sc_dk.dk_label.d_partitions[0].p_offset = 0;
508 cd->sc_dk.dk_label.d_partitions[0].p_size = cd->disksize;
509 cd->sc_dk.dk_label.d_partitions[0].p_fstype = 9;
510 cd->sc_dk.dk_label.d_magic = DISKMAGIC;
511 cd->sc_dk.dk_label.d_magic2 = DISKMAGIC;
512 cd->sc_dk.dk_label.d_checksum = dkcksum(&cd->sc_dk.dk_label);
513
514 cd->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_data *cd = mcdcd.cd_devs[unit];
525
526 if (mcd_volinfo(cd) >= 0) {
527 cd->blksize = MCDBLK;
528 size = msf2hsg(cd->volinfo.vol_msf);
529 cd->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(cd)
552 struct mcd_data *cd;
553 {
554
555 outb(cd->iobase + mcd_config, cd->config);
556 }
557
558 int
559 mcdprobe(parent, cf, aux)
560 struct device *parent;
561 struct cfdata *cf;
562 void *aux;
563 {
564 struct isa_attach_args *ia = aux;
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", cf->cf_unit,
606 inb(iobase + mcd_config));
607
608 return 1;
609 }
610
611 static int
612 mcd_waitrdy(iobase, dly)
613 u_short iobase;
614 int dly;
615 {
616 int i;
617
618 /* wait until xfer port senses data ready */
619 for (i = dly; i; i--) {
620 if ((inb(iobase + mcd_xfer) & MCD_ST_BUSY) == 0)
621 return 0;
622 delay(1);
623 }
624 return -1;
625 }
626
627 static int
628 mcd_getreply(cd, dly)
629 struct mcd_data *cd;
630 int dly;
631 {
632 u_short iobase = cd->iobase;
633
634 /* wait data to become ready */
635 if (mcd_waitrdy(iobase, dly)<0) {
636 printf("%s: timeout getreply\n", cd->sc_dev.dv_xname);
637 return -1;
638 }
639
640 /* get the data */
641 return inb(iobase + mcd_status) & 0xff;
642 }
643
644 static int
645 mcd_getstat(cd, sflg)
646 struct mcd_data *cd;
647 int sflg;
648 {
649 int i;
650 u_short iobase = cd->iobase;
651
652 /* get the status */
653 if (sflg)
654 outb(iobase + mcd_command, MCD_CMDGETSTAT);
655 i = mcd_getreply(cd, DELAY_GETREPLY);
656 if (i < 0)
657 return -1;
658
659 cd->status = i;
660
661 mcd_setflags(cd);
662 return cd->status;
663 }
664
665 static void
666 mcd_setflags(cd)
667 struct mcd_data *cd;
668 {
669
670 /* check flags */
671 if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) {
672 MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n", 0, 0, 0, 0);
673 cd->flags &= ~MCDVALID;
674 }
675
676 if (cd->status & MCDAUDIOBSY)
677 cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
678 else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
679 cd->audio_status = CD_AS_PLAY_COMPLETED;
680 }
681
682 static int
683 mcd_get(cd, buf, nmax)
684 struct mcd_data *cd;
685 char *buf;
686 int nmax;
687 {
688 int i, k;
689
690 for (i = 0; i < nmax; i++) {
691 /* wait for data */
692 if ((k = mcd_getreply(cd, DELAY_GETREPLY)) < 0) {
693 printf("%s: timeout mcd_get\n", cd->sc_dev.dv_xname);
694 return -1;
695 }
696 buf[i] = k;
697 }
698 return i;
699 }
700
701 static int
702 mcd_send(cd, cmd, nretries)
703 struct mcd_data *cd;
704 int cmd, nretries;
705 {
706 int i, k;
707 u_short iobase = cd->iobase;
708
709 /*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/
710 for (i = nretries; i; i--) {
711 outb(iobase + mcd_command, cmd);
712 if ((k = mcd_getstat(cd, 0)) != -1)
713 break;
714 }
715 if (!i) {
716 printf("%s: mcd_send retry cnt exceeded\n",
717 cd->sc_dev.dv_xname);
718 return -1;
719 }
720
721 /*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/
722 return 0;
723 }
724
725 static int
726 bcd2bin(b)
727 bcd_t b;
728 {
729
730 return (b >> 4) * 10 + (b & 15);
731 }
732
733 static bcd_t
734 bin2bcd(b)
735 int b;
736 {
737
738 return ((b / 10) << 4) | (b % 10);
739 }
740
741 static void
742 hsg2msf(hsg, msf)
743 int hsg;
744 bcd_t *msf;
745 {
746
747 hsg += 150;
748 M_msf(msf) = bin2bcd(hsg / 4500);
749 hsg %= 4500;
750 S_msf(msf) = bin2bcd(hsg / 75);
751 F_msf(msf) = bin2bcd(hsg % 75);
752 }
753
754 static int
755 msf2hsg(msf)
756 bcd_t *msf;
757 {
758
759 return (bcd2bin(M_msf(msf)) * 60 +
760 bcd2bin(S_msf(msf))) * 75 +
761 bcd2bin(F_msf(msf)) - 150;
762 }
763
764 static int
765 mcd_volinfo(cd)
766 struct mcd_data *cd;
767 {
768
769 /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
770
771 /* Get the status, in case the disc has been changed */
772 if (mcd_getstat(cd, 1) < 0)
773 return EIO;
774
775 /* Just return if we already have it */
776 if (cd->flags & MCDVOLINFO)
777 return 0;
778
779 /* send volume info command */
780 if (mcd_send(cd, MCD_CMDGETVOLINFO, MCD_RETRIES) < 0)
781 return -1;
782
783 /* get data */
784 if (mcd_get(cd, (char*) &cd->volinfo, sizeof(struct mcd_volinfo)) < 0) {
785 printf("%s: mcd_volinfo: error read data\n",
786 cd->sc_dev.dv_xname);
787 return -1;
788 }
789
790 if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) {
791 cd->flags |= MCDVOLINFO; /* volinfo is OK */
792 return 0;
793 }
794
795 return -1;
796 }
797
798 int
799 mcdintr(arg)
800 caddr_t arg;
801 {
802 struct mcd_data *cd = (void *)arg;
803 u_short iobase = cd->iobase;
804
805 MCD_TRACE("stray interrupt xfer=0x%x\n", inb(iobase + mcd_xfer),
806 0, 0, 0);
807
808 /* just read out status and ignore the rest */
809 if ((inb(iobase + mcd_xfer) & 0xff) != 0xff)
810 (void) inb(iobase + mcd_status);
811 }
812
813 /* state machine to process read requests
814 * initialize with MCD_S_BEGIN: calculate sizes, and read status
815 * MCD_S_WAITSTAT: wait for status reply, set mode
816 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
817 * MCD_S_WAITREAD: wait for read ready, read data
818 */
819 static struct mcd_mbx *mbxsave;
820
821 static void
822 mcd_doread(state, mbxin)
823 int state;
824 struct mcd_mbx *mbxin;
825 {
826 struct mcd_mbx *mbx = (state != MCD_S_BEGIN) ? mbxsave : mbxin;
827 struct mcd_data *cd = mcdcd.cd_devs[mbx->unit];
828 u_short iobase = mbx->iobase;
829 struct buf *bp = mbx->bp;
830
831 int rm, i, k;
832 struct mcd_read2 rbuf;
833 int blkno;
834 caddr_t addr;
835
836 loop:
837 switch (state) {
838 case MCD_S_BEGIN:
839 mbx = mbxsave = mbxin;
840
841 case MCD_S_BEGIN1:
842 /* get status */
843 outb(iobase + mcd_command, MCD_CMDGETSTAT);
844 mbx->count = RDELAY_WAITSTAT;
845 timeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITSTAT,
846 hz/100);
847 return;
848
849 case MCD_S_WAITSTAT:
850 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITSTAT);
851 if (mbx->count-- >= 0) {
852 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
853 timeout((timeout_t) mcd_doread,
854 (caddr_t) MCD_S_WAITSTAT, hz/100);
855 return;
856 }
857 mcd_setflags(cd);
858 MCD_TRACE("got WAITSTAT delay=%d\n",
859 RDELAY_WAITSTAT-mbx->count, 0, 0, 0);
860 /* reject, if audio active */
861 if (cd->status & MCDAUDIOBSY) {
862 printf("%s: audio is active\n",
863 cd->sc_dev.dv_xname);
864 goto readerr;
865 }
866
867 /* to check for raw/cooked mode */
868 if (cd->flags & MCDREADRAW) {
869 rm = MCD_MD_RAW;
870 mbx->sz = MCDRBLK;
871 } else {
872 rm = MCD_MD_COOKED;
873 mbx->sz = cd->blksize;
874 }
875
876 mbx->count = RDELAY_WAITMODE;
877
878 mcd_put(iobase + mcd_command, MCD_CMDSETMODE);
879 mcd_put(iobase + mcd_command, rm);
880 timeout((timeout_t) mcd_doread,
881 (caddr_t) MCD_S_WAITMODE, hz/100);
882 return;
883 } else {
884 printf("%s: timeout getstatus\n", cd->sc_dev.dv_xname);
885 goto readerr;
886 }
887
888 case MCD_S_WAITMODE:
889 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITMODE);
890 if (mbx->count-- < 0) {
891 printf("%s: timeout set mode\n", cd->sc_dev.dv_xname);
892 goto readerr;
893 }
894 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
895 timeout((timeout_t) mcd_doread,
896 (caddr_t) MCD_S_WAITMODE, hz/100);
897 return;
898 }
899 mcd_setflags(cd);
900 MCD_TRACE("got WAITMODE delay=%d\n",
901 RDELAY_WAITMODE-mbx->count, 0, 0, 0);
902 /* for first block */
903 mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz;
904 mbx->skip = 0;
905
906 nextblock:
907 blkno = (bp->b_blkno / (mbx->sz/DEV_BSIZE))
908 + mbx->p_offset + mbx->skip/mbx->sz;
909
910 MCD_TRACE("mcd_doread: read blkno=%d for bp=0x%x\n",
911 blkno, bp, 0, 0);
912
913 /* build parameter block */
914 hsg2msf(blkno, rbuf.start_msf);
915
916 /* send the read command */
917 mcd_put(iobase + mcd_command,MCD_CMDREAD2);
918 mcd_put(iobase + mcd_command,rbuf.start_msf[0]);
919 mcd_put(iobase + mcd_command,rbuf.start_msf[1]);
920 mcd_put(iobase + mcd_command,rbuf.start_msf[2]);
921 mcd_put(iobase + mcd_command,0);
922 mcd_put(iobase + mcd_command,0);
923 mcd_put(iobase + mcd_command,1);
924 mbx->count = RDELAY_WAITREAD;
925 timeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITREAD,
926 hz/100);
927 return;
928
929 case MCD_S_WAITREAD:
930 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITREAD);
931 if (mbx->count-- > 0) {
932 k = inb(iobase + mcd_xfer);
933 if ((k & 2)==0) {
934 MCD_TRACE("got data delay=%d\n",
935 RDELAY_WAITREAD-mbx->count, 0, 0, 0);
936 /* data is ready */
937 addr = bp->b_un.b_addr + mbx->skip;
938 outb(iobase + mcd_ctl2,0x04); /* XXX */
939 for (i=0; i<mbx->sz; i++)
940 *addr++ = inb(iobase + mcd_rdata);
941 outb(iobase + mcd_ctl2,0x0c); /* XXX */
942
943 if (--mbx->nblk > 0) {
944 mbx->skip += mbx->sz;
945 goto nextblock;
946 }
947
948 /* return buffer */
949 bp->b_resid = 0;
950 biodone(bp);
951
952 cd->flags &= ~MCDMBXBSY;
953 mcd_start(cd);
954 return;
955 }
956 if ((k & 4) == 0)
957 mcd_getstat(cd, 0);
958 timeout((timeout_t) mcd_doread,
959 (caddr_t) MCD_S_WAITREAD, hz/100);
960 return;
961 } else {
962 printf("%s: timeout read data\n", cd->sc_dev.dv_xname);
963 goto readerr;
964 }
965 }
966
967 readerr:
968 if (mbx->retry-- > 0) {
969 printf("%s: retrying\n", cd->sc_dev.dv_xname);
970 state = MCD_S_BEGIN1;
971 goto loop;
972 }
973
974 /* invalidate the buffer */
975 bp->b_flags |= B_ERROR;
976 bp->b_resid = bp->b_bcount;
977 biodone(bp);
978 mcd_start(cd);
979
980 #ifdef notdef
981 printf("%s: unit timeout, resetting\n", cd->sc_dev.dv_xname);
982 outb(mbx->iobase + mcd_reset,MCD_CMDRESET);
983 delay(300000);
984 (void)mcd_getstat(cd, 1);
985 (void)mcd_getstat(cd, 1);
986 /*cd->status &= ~MCDDSKCHNG; */
987 cd->debug = 1; /* preventive set debug mode */
988 #endif
989 }
990
991 static int
992 mcd_setmode(cd, mode)
993 struct mcd_data *cd;
994 int mode;
995 {
996 u_short iobase = cd->iobase;
997 int retry;
998
999 printf("%s: setting mode to %d\n", cd->sc_dev.dv_xname, mode);
1000 for(retry = MCD_RETRIES; retry; retry--) {
1001 outb(iobase + mcd_command, MCD_CMDSETMODE);
1002 outb(iobase + mcd_command, mode);
1003 if (mcd_getstat(cd, 0) != -1)
1004 return 0;
1005 }
1006
1007 return -1;
1008 }
1009
1010 static int
1011 mcd_toc_header(cd, th)
1012 struct mcd_data *cd;
1013 struct ioc_toc_header *th;
1014 {
1015
1016 if (mcd_volinfo(cd) < 0)
1017 return ENXIO;
1018
1019 th->len = msf2hsg(cd->volinfo.vol_msf);
1020 th->starting_track = bcd2bin(cd->volinfo.trk_low);
1021 th->ending_track = bcd2bin(cd->volinfo.trk_high);
1022
1023 return 0;
1024 }
1025
1026 static int
1027 mcd_read_toc(cd)
1028 struct mcd_data *cd;
1029 {
1030 struct ioc_toc_header th;
1031 struct mcd_qchninfo q;
1032 int rc, trk, idx, retry;
1033
1034 /* Only read TOC if needed */
1035 if (cd->flags & MCDTOC)
1036 return 0;
1037
1038 printf("%s: reading toc header\n", cd->sc_dev.dv_xname);
1039 if (mcd_toc_header(cd, &th) != 0)
1040 return ENXIO;
1041
1042 printf("%s: stopping play\n", cd->sc_dev.dv_xname);
1043 if ((rc = mcd_stop(cd)) != 0)
1044 return rc;
1045
1046 /* try setting the mode twice */
1047 if (mcd_setmode(cd, MCD_MD_TOC) != 0)
1048 return EIO;
1049 if (mcd_setmode(cd, MCD_MD_TOC) != 0)
1050 return EIO;
1051
1052 printf("%s: get_toc reading qchannel info\n", cd->sc_dev.dv_xname);
1053 for(trk = th.starting_track; trk <= th.ending_track; trk++)
1054 cd->toc[trk].idx_no = 0;
1055 trk = th.ending_track - th.starting_track + 1;
1056 for(retry = 300; retry && trk > 0; retry--) {
1057 if (mcd_getqchan(cd, &q) < 0)
1058 break;
1059 idx = bcd2bin(q.idx_no);
1060 if (idx > 0 && idx < MCD_MAXTOCS && q.trk_no==0)
1061 if (cd->toc[idx].idx_no == 0) {
1062 cd->toc[idx] = q;
1063 trk--;
1064 }
1065 }
1066
1067 if (mcd_setmode(cd, MCD_MD_COOKED) != 0)
1068 return EIO;
1069
1070 if (trk != 0)
1071 return ENXIO;
1072
1073 /* add a fake last+1 */
1074 idx = th.ending_track + 1;
1075 cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr;
1076 cd->toc[idx].trk_no = 0;
1077 cd->toc[idx].idx_no = 0xAA;
1078 cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0];
1079 cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1];
1080 cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2];
1081
1082 cd->flags |= MCDTOC;
1083
1084 return 0;
1085 }
1086
1087 static int
1088 mcd_toc_entry(cd, te)
1089 struct mcd_data *cd;
1090 struct ioc_read_toc_entry *te;
1091 {
1092 struct ret_toc {
1093 struct ioc_toc_header th;
1094 struct cd_toc_entry rt;
1095 } ret_toc;
1096 struct ioc_toc_header th;
1097 int rc, i;
1098
1099 /* Make sure we have a valid toc */
1100 if ((rc = mcd_read_toc(cd)) != 0)
1101 return rc;
1102
1103 /* find the toc to copy*/
1104 i = te->starting_track;
1105 if (i == MCD_LASTPLUS1)
1106 i = bcd2bin(cd->volinfo.trk_high) + 1;
1107
1108 /* verify starting track */
1109 if (i < bcd2bin(cd->volinfo.trk_low) ||
1110 i > bcd2bin(cd->volinfo.trk_high) + 1)
1111 return EINVAL;
1112
1113 /* do we have room */
1114 if (te->data_len < sizeof(struct ioc_toc_header) +
1115 sizeof(struct cd_toc_entry))
1116 return EINVAL;
1117
1118 /* Copy the toc header */
1119 if (mcd_toc_header(cd, &th) < 0)
1120 return EIO;
1121 ret_toc.th = th;
1122
1123 /* copy the toc data */
1124 ret_toc.rt.control = cd->toc[i].ctrl_adr;
1125 ret_toc.rt.addr_type = te->address_format;
1126 ret_toc.rt.track = i;
1127 if (te->address_format == CD_MSF_FORMAT) {
1128 ret_toc.rt.addr[1] = cd->toc[i].hd_pos_msf[0];
1129 ret_toc.rt.addr[2] = cd->toc[i].hd_pos_msf[1];
1130 ret_toc.rt.addr[3] = cd->toc[i].hd_pos_msf[2];
1131 }
1132
1133 /* copy the data back */
1134 copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry)
1135 + sizeof(struct ioc_toc_header));
1136
1137 return 0;
1138 }
1139
1140 static int
1141 mcd_stop(cd)
1142 struct mcd_data *cd;
1143 {
1144
1145 if (mcd_send(cd, MCD_CMDSTOPAUDIO, MCD_RETRIES) < 0)
1146 return ENXIO;
1147 cd->audio_status = CD_AS_PLAY_COMPLETED;
1148 return 0;
1149 }
1150
1151 static int
1152 mcd_getqchan(cd, q)
1153 struct mcd_data *cd;
1154 struct mcd_qchninfo *q;
1155 {
1156
1157 if (mcd_send(cd, MCD_CMDGETQCHN, MCD_RETRIES) < 0)
1158 return -1;
1159 if (mcd_get(cd, (char *) q, sizeof(struct mcd_qchninfo)) < 0)
1160 return -1;
1161 if (cd->debug)
1162 printf("%s: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n",
1163 cd->sc_dev.dv_xname, q->ctrl_adr, q->trk_no, q->idx_no,
1164 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
1165 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
1166 return 0;
1167 }
1168
1169 static int
1170 mcd_subchan(cd, sc)
1171 struct mcd_data *cd;
1172 struct ioc_read_subchannel *sc;
1173 {
1174 struct mcd_qchninfo q;
1175 struct cd_sub_channel_info data;
1176
1177 printf("%s: subchan af=%d, df=%d\n", cd->sc_dev.dv_xname,
1178 sc->address_format, sc->data_format);
1179 if (sc->address_format != CD_MSF_FORMAT)
1180 return EIO;
1181 if (sc->data_format != CD_CURRENT_POSITION)
1182 return EIO;
1183
1184 if (mcd_getqchan(cd, &q) < 0)
1185 return EIO;
1186
1187 data.header.audio_status = cd->audio_status;
1188 data.what.position.data_format = CD_MSF_FORMAT;
1189 data.what.position.track_number = bcd2bin(q.trk_no);
1190
1191 if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info)) != 0)
1192 return EFAULT;
1193 return 0;
1194 }
1195
1196 static int
1197 mcd_playtracks(cd, pt)
1198 struct mcd_data *cd;
1199 struct ioc_play_track *pt;
1200 {
1201 struct mcd_read2 pb;
1202 int a = pt->start_track;
1203 int z = pt->end_track;
1204 int rc;
1205
1206 if ((rc = mcd_read_toc(cd)) != 0)
1207 return rc;
1208
1209 printf("%s: playtracks from %d:%d to %d:%d\n", cd->sc_dev.dv_xname,
1210 a, pt->start_index, z, pt->end_index);
1211
1212 if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z ||
1213 z < cd->volinfo.trk_low || z > cd->volinfo.trk_high)
1214 return EINVAL;
1215
1216 pb.start_msf[0] = cd->toc[a].hd_pos_msf[0];
1217 pb.start_msf[1] = cd->toc[a].hd_pos_msf[1];
1218 pb.start_msf[2] = cd->toc[a].hd_pos_msf[2];
1219 pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0];
1220 pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1];
1221 pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2];
1222
1223 return mcd_play(cd, &pb);
1224 }
1225
1226 static int
1227 mcd_play(cd, pb)
1228 struct mcd_data *cd;
1229 struct mcd_read2 *pb;
1230 {
1231 u_short iobase = cd->iobase;
1232 int retry, st;
1233
1234 cd->lastpb = *pb;
1235 for (retry = MCD_RETRIES; retry; retry--) {
1236 outb(iobase + mcd_command, MCD_CMDREAD2);
1237 outb(iobase + mcd_command, pb->start_msf[0]);
1238 outb(iobase + mcd_command, pb->start_msf[1]);
1239 outb(iobase + mcd_command, pb->start_msf[2]);
1240 outb(iobase + mcd_command, pb->end_msf[0]);
1241 outb(iobase + mcd_command, pb->end_msf[1]);
1242 outb(iobase + mcd_command, pb->end_msf[2]);
1243 if ((st = mcd_getstat(cd, 0)) != -1)
1244 break;
1245 }
1246 if (!retry)
1247 return ENXIO;
1248
1249 cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
1250 return 0;
1251 }
1252
1253 static int
1254 mcd_pause(cd)
1255 struct mcd_data *cd;
1256 {
1257 struct mcd_qchninfo q;
1258 int rc;
1259
1260 /* Verify current status */
1261 if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) {
1262 printf("%s: pause attempted when not playing\n",
1263 cd->sc_dev.dv_xname);
1264 return EINVAL;
1265 }
1266
1267 /* Get the current position */
1268 if (mcd_getqchan(cd, &q) < 0)
1269 return EIO;
1270
1271 /* Copy it into lastpb */
1272 cd->lastpb.start_msf[0] = q.hd_pos_msf[0];
1273 cd->lastpb.start_msf[1] = q.hd_pos_msf[1];
1274 cd->lastpb.start_msf[2] = q.hd_pos_msf[2];
1275
1276 /* Stop playing */
1277 if ((rc = mcd_stop(cd)) != 0)
1278 return rc;
1279
1280 /* Set the proper status and exit */
1281 cd->audio_status = CD_AS_PLAY_PAUSED;
1282 return 0;
1283 }
1284
1285 static int
1286 mcd_resume(cd)
1287 struct mcd_data *cd;
1288 {
1289
1290 if (cd->audio_status != CD_AS_PLAY_PAUSED)
1291 return EINVAL;
1292 return mcd_play(cd, &cd->lastpb);
1293 }
1294