mcd.c revision 1.1.2.3 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 Gary Clark II (gclarkii (at) freefall.cdrom.com)
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.3 1994/02/01 06:30:28 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;
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(100000);
575
576 /* get any pending status and throw away...*/
577 for (i=10; i; i--)
578 inb(iobase + MCD_DATA);
579
580 delay(1000);
581 outb(iobase + MCD_DATA, MCD_CMDGETSTAT);/* Send get status command */
582 /* Loop looking for avail of status */
583 /* XXX May have to increase for fast machinces */
584 for (i = 1000; i; i--) {
585 if ((inb(iobase + MCD_FLAGS) & 0xf) == STATUS_AVAIL)
586 break;
587 delay(10);
588 }
589 if (!i)
590 return 0;
591
592 /*
593 * The following code uses the 0xDC command, it returns a M from the
594 * second byte and a number in the third. Does anyone know what the
595 * number is for? Better yet, how about someone thats REAL good in
596 * i80x86 asm looking at the Dos driver... Most of this info came
597 * from a friend of mine spending a whole weekend.....
598 */
599
600 delay(2000);
601 outb(iobase + MCD_DATA, MCD_CMDCONTINFO);
602 for (i = 1000; i; i--) {
603 if ((inb(iobase + MCD_FLAGS) & 0xf) == STATUS_AVAIL)
604 break;
605 delay(10);
606 }
607 if (!i)
608 return 0;
609
610 delay(40000);
611 st = inb(iobase + MCD_DATA);
612 delay(500);
613 check = inb(iobase + MCD_DATA);
614 delay(500);
615 junk = inb(iobase + MCD_DATA); /* What is this byte used for? */
616
617 if (check != 'M')
618 return 0;
619
620 /* XXXX check irq and drq */
621 printf("mcd%d: config register says %x\n", cf->cf_unit,
622 inb(iobase + mcd_config));
623
624 return 4;
625 }
626
627 static int
628 mcd_waitrdy(iobase, dly)
629 u_short iobase;
630 int dly;
631 {
632 int i;
633
634 /* wait until xfer port senses data ready */
635 for (i = dly; i; i--) {
636 if ((inb(iobase + mcd_xfer) & MCD_ST_BUSY) == 0)
637 return 0;
638 delay(1);
639 }
640 return -1;
641 }
642
643 static int
644 mcd_getreply(cd, dly)
645 struct mcd_data *cd;
646 int dly;
647 {
648 u_short iobase = cd->iobase;
649
650 /* wait data to become ready */
651 if (mcd_waitrdy(iobase, dly)<0) {
652 printf("%s: timeout getreply\n", cd->sc_dev.dv_xname);
653 return -1;
654 }
655
656 /* get the data */
657 return inb(iobase + mcd_status) & 0xff;
658 }
659
660 static int
661 mcd_getstat(cd, sflg)
662 struct mcd_data *cd;
663 int sflg;
664 {
665 int i;
666 u_short iobase = cd->iobase;
667
668 /* get the status */
669 if (sflg)
670 outb(iobase + mcd_command, MCD_CMDGETSTAT);
671 i = mcd_getreply(cd, DELAY_GETREPLY);
672 if (i < 0)
673 return -1;
674
675 cd->status = i;
676
677 mcd_setflags(cd);
678 return cd->status;
679 }
680
681 static void
682 mcd_setflags(cd)
683 struct mcd_data *cd;
684 {
685
686 /* check flags */
687 if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) {
688 MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n", 0, 0, 0, 0);
689 cd->flags &= ~MCDVALID;
690 }
691
692 if (cd->status & MCDAUDIOBSY)
693 cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
694 else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
695 cd->audio_status = CD_AS_PLAY_COMPLETED;
696 }
697
698 static int
699 mcd_get(cd, buf, nmax)
700 struct mcd_data *cd;
701 char *buf;
702 int nmax;
703 {
704 int i, k;
705
706 for (i = 0; i < nmax; i++) {
707 /* wait for data */
708 if ((k = mcd_getreply(cd, DELAY_GETREPLY)) < 0) {
709 printf("%s: timeout mcd_get\n", cd->sc_dev.dv_xname);
710 return -1;
711 }
712 buf[i] = k;
713 }
714 return i;
715 }
716
717 static int
718 mcd_send(cd, cmd, nretries)
719 struct mcd_data *cd;
720 int cmd, nretries;
721 {
722 int i, k;
723 u_short iobase = cd->iobase;
724
725 /*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/
726 for (i = nretries; i; i--) {
727 outb(iobase + mcd_command, cmd);
728 if ((k = mcd_getstat(cd, 0)) != -1)
729 break;
730 }
731 if (!i) {
732 printf("%s: mcd_send retry cnt exceeded\n",
733 cd->sc_dev.dv_xname);
734 return -1;
735 }
736
737 /*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/
738 return 0;
739 }
740
741 static int
742 bcd2bin(b)
743 bcd_t b;
744 {
745
746 return (b >> 4) * 10 + (b & 15);
747 }
748
749 static bcd_t
750 bin2bcd(b)
751 int b;
752 {
753
754 return ((b / 10) << 4) | (b % 10);
755 }
756
757 static void
758 hsg2msf(hsg, msf)
759 int hsg;
760 bcd_t *msf;
761 {
762
763 hsg += 150;
764 M_msf(msf) = bin2bcd(hsg / 4500);
765 hsg %= 4500;
766 S_msf(msf) = bin2bcd(hsg / 75);
767 F_msf(msf) = bin2bcd(hsg % 75);
768 }
769
770 static int
771 msf2hsg(msf)
772 bcd_t *msf;
773 {
774
775 return (bcd2bin(M_msf(msf)) * 60 +
776 bcd2bin(S_msf(msf))) * 75 +
777 bcd2bin(F_msf(msf)) - 150;
778 }
779
780 static int
781 mcd_volinfo(cd)
782 struct mcd_data *cd;
783 {
784
785 /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
786
787 /* Get the status, in case the disc has been changed */
788 if (mcd_getstat(cd, 1) < 0)
789 return EIO;
790
791 /* Just return if we already have it */
792 if (cd->flags & MCDVOLINFO)
793 return 0;
794
795 /* send volume info command */
796 if (mcd_send(cd, MCD_CMDGETVOLINFO, MCD_RETRIES) < 0)
797 return -1;
798
799 /* get data */
800 if (mcd_get(cd, (char*) &cd->volinfo, sizeof(struct mcd_volinfo)) < 0) {
801 printf("%s: mcd_volinfo: error read data\n",
802 cd->sc_dev.dv_xname);
803 return -1;
804 }
805
806 if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) {
807 cd->flags |= MCDVOLINFO; /* volinfo is OK */
808 return 0;
809 }
810
811 return -1;
812 }
813
814 int
815 mcdintr(arg)
816 caddr_t arg;
817 {
818 struct mcd_data *cd = (void *)arg;
819 u_short iobase = cd->iobase;
820
821 MCD_TRACE("stray interrupt xfer=0x%x\n", inb(iobase + mcd_xfer),
822 0, 0, 0);
823
824 /* just read out status and ignore the rest */
825 if ((inb(iobase + mcd_xfer) & 0xff) != 0xff)
826 (void) inb(iobase + mcd_status);
827 }
828
829 /* state machine to process read requests
830 * initialize with MCD_S_BEGIN: calculate sizes, and read status
831 * MCD_S_WAITSTAT: wait for status reply, set mode
832 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
833 * MCD_S_WAITREAD: wait for read ready, read data
834 */
835 static struct mcd_mbx *mbxsave;
836
837 static void
838 mcd_doread(state, mbxin)
839 int state;
840 struct mcd_mbx *mbxin;
841 {
842 struct mcd_mbx *mbx = (state != MCD_S_BEGIN) ? mbxsave : mbxin;
843 struct mcd_data *cd = mcdcd.cd_devs[mbx->unit];
844 u_short iobase = mbx->iobase;
845 struct buf *bp = mbx->bp;
846
847 int rm, i, k;
848 struct mcd_read2 rbuf;
849 int blkno;
850 caddr_t addr;
851
852 loop:
853 switch (state) {
854 case MCD_S_BEGIN:
855 mbx = mbxsave = mbxin;
856
857 case MCD_S_BEGIN1:
858 /* get status */
859 outb(iobase + mcd_command, MCD_CMDGETSTAT);
860 mbx->count = RDELAY_WAITSTAT;
861 timeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITSTAT,
862 hz/100);
863 return;
864
865 case MCD_S_WAITSTAT:
866 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITSTAT);
867 if (mbx->count-- >= 0) {
868 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
869 timeout((timeout_t) mcd_doread,
870 (caddr_t) MCD_S_WAITSTAT, hz/100);
871 return;
872 }
873 mcd_setflags(cd);
874 MCD_TRACE("got WAITSTAT delay=%d\n",
875 RDELAY_WAITSTAT-mbx->count, 0, 0, 0);
876 /* reject, if audio active */
877 if (cd->status & MCDAUDIOBSY) {
878 printf("%s: audio is active\n",
879 cd->sc_dev.dv_xname);
880 goto readerr;
881 }
882
883 /* to check for raw/cooked mode */
884 if (cd->flags & MCDREADRAW) {
885 rm = MCD_MD_RAW;
886 mbx->sz = MCDRBLK;
887 } else {
888 rm = MCD_MD_COOKED;
889 mbx->sz = cd->blksize;
890 }
891
892 mbx->count = RDELAY_WAITMODE;
893
894 mcd_put(iobase + mcd_command, MCD_CMDSETMODE);
895 mcd_put(iobase + mcd_command, rm);
896 timeout((timeout_t) mcd_doread,
897 (caddr_t) MCD_S_WAITMODE, hz/100);
898 return;
899 } else {
900 printf("%s: timeout getstatus\n", cd->sc_dev.dv_xname);
901 goto readerr;
902 }
903
904 case MCD_S_WAITMODE:
905 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITMODE);
906 if (mbx->count-- < 0) {
907 printf("%s: timeout set mode\n", cd->sc_dev.dv_xname);
908 goto readerr;
909 }
910 if (inb(iobase + mcd_xfer) & MCD_ST_BUSY) {
911 timeout((timeout_t) mcd_doread,
912 (caddr_t) MCD_S_WAITMODE, hz/100);
913 return;
914 }
915 mcd_setflags(cd);
916 MCD_TRACE("got WAITMODE delay=%d\n",
917 RDELAY_WAITMODE-mbx->count, 0, 0, 0);
918 /* for first block */
919 mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz;
920 mbx->skip = 0;
921
922 nextblock:
923 blkno = (bp->b_blkno / (mbx->sz/DEV_BSIZE))
924 + mbx->p_offset + mbx->skip/mbx->sz;
925
926 MCD_TRACE("mcd_doread: read blkno=%d for bp=0x%x\n",
927 blkno, bp, 0, 0);
928
929 /* build parameter block */
930 hsg2msf(blkno, rbuf.start_msf);
931
932 /* send the read command */
933 mcd_put(iobase + mcd_command,MCD_CMDREAD2);
934 mcd_put(iobase + mcd_command,rbuf.start_msf[0]);
935 mcd_put(iobase + mcd_command,rbuf.start_msf[1]);
936 mcd_put(iobase + mcd_command,rbuf.start_msf[2]);
937 mcd_put(iobase + mcd_command,0);
938 mcd_put(iobase + mcd_command,0);
939 mcd_put(iobase + mcd_command,1);
940 mbx->count = RDELAY_WAITREAD;
941 timeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITREAD,
942 hz/100);
943 return;
944
945 case MCD_S_WAITREAD:
946 untimeout((timeout_t) mcd_doread, (caddr_t) MCD_S_WAITREAD);
947 if (mbx->count-- > 0) {
948 k = inb(iobase + mcd_xfer);
949 if ((k & 2)==0) {
950 MCD_TRACE("got data delay=%d\n",
951 RDELAY_WAITREAD-mbx->count, 0, 0, 0);
952 /* data is ready */
953 addr = bp->b_un.b_addr + mbx->skip;
954 outb(iobase + mcd_ctl2,0x04); /* XXX */
955 for (i=0; i<mbx->sz; i++)
956 *addr++ = inb(iobase + mcd_rdata);
957 outb(iobase + mcd_ctl2,0x0c); /* XXX */
958
959 if (--mbx->nblk > 0) {
960 mbx->skip += mbx->sz;
961 goto nextblock;
962 }
963
964 /* return buffer */
965 bp->b_resid = 0;
966 biodone(bp);
967
968 cd->flags &= ~MCDMBXBSY;
969 mcd_start(cd);
970 return;
971 }
972 if ((k & 4) == 0)
973 mcd_getstat(cd, 0);
974 timeout((timeout_t) mcd_doread,
975 (caddr_t) MCD_S_WAITREAD, hz/100);
976 return;
977 } else {
978 printf("%s: timeout read data\n", cd->sc_dev.dv_xname);
979 goto readerr;
980 }
981 }
982
983 readerr:
984 if (mbx->retry-- > 0) {
985 printf("%s: retrying\n", cd->sc_dev.dv_xname);
986 state = MCD_S_BEGIN1;
987 goto loop;
988 }
989
990 /* invalidate the buffer */
991 bp->b_flags |= B_ERROR;
992 bp->b_resid = bp->b_bcount;
993 biodone(bp);
994 mcd_start(cd);
995
996 #ifdef notdef
997 printf("%s: unit timeout, resetting\n", cd->sc_dev.dv_xname);
998 outb(mbx->iobase + mcd_reset,MCD_CMDRESET);
999 delay(300000);
1000 (void)mcd_getstat(cd, 1);
1001 (void)mcd_getstat(cd, 1);
1002 /*cd->status &= ~MCDDSKCHNG; */
1003 cd->debug = 1; /* preventive set debug mode */
1004 #endif
1005 }
1006
1007 static int
1008 mcd_setmode(cd, mode)
1009 struct mcd_data *cd;
1010 int mode;
1011 {
1012 u_short iobase = cd->iobase;
1013 int retry;
1014
1015 printf("%s: setting mode to %d\n", cd->sc_dev.dv_xname, mode);
1016 for(retry = MCD_RETRIES; retry; retry--) {
1017 outb(iobase + mcd_command, MCD_CMDSETMODE);
1018 outb(iobase + mcd_command, mode);
1019 if (mcd_getstat(cd, 0) != -1)
1020 return 0;
1021 }
1022
1023 return -1;
1024 }
1025
1026 static int
1027 mcd_toc_header(cd, th)
1028 struct mcd_data *cd;
1029 struct ioc_toc_header *th;
1030 {
1031
1032 if (mcd_volinfo(cd) < 0)
1033 return ENXIO;
1034
1035 th->len = msf2hsg(cd->volinfo.vol_msf);
1036 th->starting_track = bcd2bin(cd->volinfo.trk_low);
1037 th->ending_track = bcd2bin(cd->volinfo.trk_high);
1038
1039 return 0;
1040 }
1041
1042 static int
1043 mcd_read_toc(cd)
1044 struct mcd_data *cd;
1045 {
1046 struct ioc_toc_header th;
1047 struct mcd_qchninfo q;
1048 int rc, trk, idx, retry;
1049
1050 /* Only read TOC if needed */
1051 if (cd->flags & MCDTOC)
1052 return 0;
1053
1054 printf("%s: reading toc header\n", cd->sc_dev.dv_xname);
1055 if (mcd_toc_header(cd, &th) != 0)
1056 return ENXIO;
1057
1058 printf("%s: stopping play\n", cd->sc_dev.dv_xname);
1059 if ((rc = mcd_stop(cd)) != 0)
1060 return rc;
1061
1062 /* try setting the mode twice */
1063 if (mcd_setmode(cd, MCD_MD_TOC) != 0)
1064 return EIO;
1065 if (mcd_setmode(cd, MCD_MD_TOC) != 0)
1066 return EIO;
1067
1068 printf("%s: get_toc reading qchannel info\n", cd->sc_dev.dv_xname);
1069 for(trk = th.starting_track; trk <= th.ending_track; trk++)
1070 cd->toc[trk].idx_no = 0;
1071 trk = th.ending_track - th.starting_track + 1;
1072 for(retry = 300; retry && trk > 0; retry--) {
1073 if (mcd_getqchan(cd, &q) < 0)
1074 break;
1075 idx = bcd2bin(q.idx_no);
1076 if (idx > 0 && idx < MCD_MAXTOCS && q.trk_no==0)
1077 if (cd->toc[idx].idx_no == 0) {
1078 cd->toc[idx] = q;
1079 trk--;
1080 }
1081 }
1082
1083 if (mcd_setmode(cd, MCD_MD_COOKED) != 0)
1084 return EIO;
1085
1086 if (trk != 0)
1087 return ENXIO;
1088
1089 /* add a fake last+1 */
1090 idx = th.ending_track + 1;
1091 cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr;
1092 cd->toc[idx].trk_no = 0;
1093 cd->toc[idx].idx_no = 0xAA;
1094 cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0];
1095 cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1];
1096 cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2];
1097
1098 cd->flags |= MCDTOC;
1099
1100 return 0;
1101 }
1102
1103 static int
1104 mcd_toc_entry(cd, te)
1105 struct mcd_data *cd;
1106 struct ioc_read_toc_entry *te;
1107 {
1108 struct ret_toc {
1109 struct ioc_toc_header th;
1110 struct cd_toc_entry rt;
1111 } ret_toc;
1112 struct ioc_toc_header th;
1113 int rc, i;
1114
1115 /* Make sure we have a valid toc */
1116 if ((rc = mcd_read_toc(cd)) != 0)
1117 return rc;
1118
1119 /* find the toc to copy*/
1120 i = te->starting_track;
1121 if (i == MCD_LASTPLUS1)
1122 i = bcd2bin(cd->volinfo.trk_high) + 1;
1123
1124 /* verify starting track */
1125 if (i < bcd2bin(cd->volinfo.trk_low) ||
1126 i > bcd2bin(cd->volinfo.trk_high) + 1)
1127 return EINVAL;
1128
1129 /* do we have room */
1130 if (te->data_len < sizeof(struct ioc_toc_header) +
1131 sizeof(struct cd_toc_entry))
1132 return EINVAL;
1133
1134 /* Copy the toc header */
1135 if (mcd_toc_header(cd, &th) < 0)
1136 return EIO;
1137 ret_toc.th = th;
1138
1139 /* copy the toc data */
1140 ret_toc.rt.control = cd->toc[i].ctrl_adr;
1141 ret_toc.rt.addr_type = te->address_format;
1142 ret_toc.rt.track = i;
1143 if (te->address_format == CD_MSF_FORMAT) {
1144 ret_toc.rt.addr[1] = cd->toc[i].hd_pos_msf[0];
1145 ret_toc.rt.addr[2] = cd->toc[i].hd_pos_msf[1];
1146 ret_toc.rt.addr[3] = cd->toc[i].hd_pos_msf[2];
1147 }
1148
1149 /* copy the data back */
1150 copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry)
1151 + sizeof(struct ioc_toc_header));
1152
1153 return 0;
1154 }
1155
1156 static int
1157 mcd_stop(cd)
1158 struct mcd_data *cd;
1159 {
1160
1161 if (mcd_send(cd, MCD_CMDSTOPAUDIO, MCD_RETRIES) < 0)
1162 return ENXIO;
1163 cd->audio_status = CD_AS_PLAY_COMPLETED;
1164 return 0;
1165 }
1166
1167 static int
1168 mcd_getqchan(cd, q)
1169 struct mcd_data *cd;
1170 struct mcd_qchninfo *q;
1171 {
1172
1173 if (mcd_send(cd, MCD_CMDGETQCHN, MCD_RETRIES) < 0)
1174 return -1;
1175 if (mcd_get(cd, (char *) q, sizeof(struct mcd_qchninfo)) < 0)
1176 return -1;
1177 if (cd->debug)
1178 printf("%s: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n",
1179 cd->sc_dev.dv_xname, q->ctrl_adr, q->trk_no, q->idx_no,
1180 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
1181 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
1182 return 0;
1183 }
1184
1185 static int
1186 mcd_subchan(cd, sc)
1187 struct mcd_data *cd;
1188 struct ioc_read_subchannel *sc;
1189 {
1190 struct mcd_qchninfo q;
1191 struct cd_sub_channel_info data;
1192
1193 printf("%s: subchan af=%d, df=%d\n", cd->sc_dev.dv_xname,
1194 sc->address_format, sc->data_format);
1195 if (sc->address_format != CD_MSF_FORMAT)
1196 return EIO;
1197 if (sc->data_format != CD_CURRENT_POSITION)
1198 return EIO;
1199
1200 if (mcd_getqchan(cd, &q) < 0)
1201 return EIO;
1202
1203 data.header.audio_status = cd->audio_status;
1204 data.what.position.data_format = CD_MSF_FORMAT;
1205 data.what.position.track_number = bcd2bin(q.trk_no);
1206
1207 if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info)) != 0)
1208 return EFAULT;
1209 return 0;
1210 }
1211
1212 static int
1213 mcd_playtracks(cd, pt)
1214 struct mcd_data *cd;
1215 struct ioc_play_track *pt;
1216 {
1217 struct mcd_read2 pb;
1218 int a = pt->start_track;
1219 int z = pt->end_track;
1220 int rc;
1221
1222 if ((rc = mcd_read_toc(cd)) != 0)
1223 return rc;
1224
1225 printf("%s: playtracks from %d:%d to %d:%d\n", cd->sc_dev.dv_xname,
1226 a, pt->start_index, z, pt->end_index);
1227
1228 if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z ||
1229 z < cd->volinfo.trk_low || z > cd->volinfo.trk_high)
1230 return EINVAL;
1231
1232 pb.start_msf[0] = cd->toc[a].hd_pos_msf[0];
1233 pb.start_msf[1] = cd->toc[a].hd_pos_msf[1];
1234 pb.start_msf[2] = cd->toc[a].hd_pos_msf[2];
1235 pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0];
1236 pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1];
1237 pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2];
1238
1239 return mcd_play(cd, &pb);
1240 }
1241
1242 static int
1243 mcd_play(cd, pb)
1244 struct mcd_data *cd;
1245 struct mcd_read2 *pb;
1246 {
1247 u_short iobase = cd->iobase;
1248 int retry, st;
1249
1250 cd->lastpb = *pb;
1251 for (retry = MCD_RETRIES; retry; retry--) {
1252 outb(iobase + mcd_command, MCD_CMDREAD2);
1253 outb(iobase + mcd_command, pb->start_msf[0]);
1254 outb(iobase + mcd_command, pb->start_msf[1]);
1255 outb(iobase + mcd_command, pb->start_msf[2]);
1256 outb(iobase + mcd_command, pb->end_msf[0]);
1257 outb(iobase + mcd_command, pb->end_msf[1]);
1258 outb(iobase + mcd_command, pb->end_msf[2]);
1259 if ((st = mcd_getstat(cd, 0)) != -1)
1260 break;
1261 }
1262 if (!retry)
1263 return ENXIO;
1264
1265 cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
1266 return 0;
1267 }
1268
1269 static int
1270 mcd_pause(cd)
1271 struct mcd_data *cd;
1272 {
1273 struct mcd_qchninfo q;
1274 int rc;
1275
1276 /* Verify current status */
1277 if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) {
1278 printf("%s: pause attempted when not playing\n",
1279 cd->sc_dev.dv_xname);
1280 return EINVAL;
1281 }
1282
1283 /* Get the current position */
1284 if (mcd_getqchan(cd, &q) < 0)
1285 return EIO;
1286
1287 /* Copy it into lastpb */
1288 cd->lastpb.start_msf[0] = q.hd_pos_msf[0];
1289 cd->lastpb.start_msf[1] = q.hd_pos_msf[1];
1290 cd->lastpb.start_msf[2] = q.hd_pos_msf[2];
1291
1292 /* Stop playing */
1293 if ((rc = mcd_stop(cd)) != 0)
1294 return rc;
1295
1296 /* Set the proper status and exit */
1297 cd->audio_status = CD_AS_PLAY_PAUSED;
1298 return 0;
1299 }
1300
1301 static int
1302 mcd_resume(cd)
1303 struct mcd_data *cd;
1304 {
1305
1306 if (cd->audio_status != CD_AS_PLAY_PAUSED)
1307 return EINVAL;
1308 return mcd_play(cd, &cd->lastpb);
1309 }
1310