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