Annotation of sys/dev/isa/mcd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mcd.c,v 1.49 2007/06/20 18:15:46 deraadt Exp $ */
2: /* $NetBSD: mcd.c,v 1.60 1998/01/14 12:14:41 drochner Exp $ */
3:
4: /*
5: * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. 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 product includes software developed by Charles M. Hannum.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * Copyright 1993 by Holger Veit (data part)
22: * Copyright 1993 by Brian Moore (audio part)
23: * All rights reserved.
24: *
25: * Redistribution and use in source and binary forms, with or without
26: * modification, are permitted provided that the following conditions
27: * are met:
28: * 1. Redistributions of source code must retain the above copyright
29: * notice, this list of conditions and the following disclaimer.
30: * 2. Redistributions in binary form must reproduce the above copyright
31: * notice, this list of conditions and the following disclaimer in the
32: * documentation and/or other materials provided with the distribution.
33: * 3. All advertising materials mentioning features or use of this software
34: * must display the following acknowledgement:
35: * This software was developed by Holger Veit and Brian Moore
36: * for use with "386BSD" and similar operating systems.
37: * "Similar operating systems" includes mainly non-profit oriented
38: * systems for research and education, including but not restricted to
39: * "NetBSD", "FreeBSD", "Mach" (by CMU).
40: * 4. Neither the name of the developer(s) nor the name "386BSD"
41: * may be used to endorse or promote products derived from this
42: * software without specific prior written permission.
43: *
44: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
45: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
48: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
49: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
50: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
51: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
52: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
53: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55: */
56:
57: /*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
58:
59: #include <sys/param.h>
60: #include <sys/systm.h>
61: #include <sys/kernel.h>
62: #include <sys/proc.h>
63: #include <sys/conf.h>
64: #include <sys/file.h>
65: #include <sys/buf.h>
66: #include <sys/stat.h>
67: #include <sys/uio.h>
68: #include <sys/ioctl.h>
69: #include <sys/mtio.h>
70: #include <sys/cdio.h>
71: #include <sys/errno.h>
72: #include <sys/disklabel.h>
73: #include <sys/device.h>
74: #include <sys/disk.h>
75: #include <sys/timeout.h>
76:
77: #include <machine/cpu.h>
78: #include <machine/intr.h>
79: #include <machine/bus.h>
80:
81: #include <dev/isa/isavar.h>
82: #include <dev/isa/mcdreg.h>
83: #include <dev/isa/opti.h>
84:
85: #ifndef MCDDEBUG
86: #define MCD_TRACE(fmt,a,b,c,d)
87: #else
88: #define MCD_TRACE(fmt,a,b,c,d) {if (sc->debug) {printf("%s: st=%02x: ", sc->sc_dev.dv_xname, sc->status); printf(fmt,a,b,c,d);}}
89: #endif
90:
91: /* toc */
92: #define MCD_MAXTOCS 104 /* from the Linux driver */
93:
94: struct mcd_mbx {
95: int retry, count;
96: struct buf *bp;
97: daddr64_t blkno;
98: int nblk;
99: int sz;
100: u_long skip;
101: int state;
102: #define MCD_S_IDLE 0
103: #define MCD_S_BEGIN 1
104: #define MCD_S_WAITMODE 2
105: #define MCD_S_WAITREAD 3
106: int mode;
107: };
108:
109: struct mcd_softc {
110: struct device sc_dev;
111: struct disk sc_dk;
112: void *sc_ih;
113: struct timeout sc_pi_tmo;
114:
115: bus_space_tag_t sc_iot;
116: bus_space_handle_t sc_ioh;
117:
118: int irq, drq;
119:
120: char *type;
121: int flags;
122: #define MCDF_LOCKED 0x01
123: #define MCDF_WANTED 0x02
124: #define MCDF_WLABEL 0x04 /* label is writable */
125: #define MCDF_LABELLING 0x08 /* writing label */
126: #define MCDF_LOADED 0x10 /* parameters loaded */
127: #define MCDF_EJECTING 0x20 /* please eject at close */
128: short status;
129: short audio_status;
130: int blksize;
131: u_long disksize;
132: struct mcd_volinfo volinfo;
133: union mcd_qchninfo toc[MCD_MAXTOCS];
134: struct mcd_command lastpb;
135: struct mcd_mbx mbx;
136: int lastmode;
137: #define MCD_MD_UNKNOWN -1
138: int lastupc;
139: #define MCD_UPC_UNKNOWN -1
140: struct buf buf_queue;
141: u_char readcmd;
142: u_char debug;
143: u_char probe;
144: };
145:
146: /* prototypes */
147: /* XXX does not belong here */
148: cdev_decl(mcd);
149: bdev_decl(mcd);
150:
151: u_int8_t const __bcd2bin[] = {
152: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
153: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
154: 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
155: 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
156: 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
157: 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
158: 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
159: 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
160: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
161: 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
162: };
163:
164: u_int8_t const __bin2bcd[] = {
165: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
166: 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
167: 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
168: 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
169: 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
170: 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
171: 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
172: 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
173: 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
174: 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
175: };
176: #define bcd2bin(b) (__bcd2bin[(b)&0xff])
177: #define bin2bcd(b) (__bin2bcd[(b)&0xff])
178:
179: static void hsg2msf(int, bcd_t *);
180: static daddr64_t msf2hsg(bcd_t *, int);
181:
182: int mcd_playtracks(struct mcd_softc *, struct ioc_play_track *);
183: int mcd_playmsf(struct mcd_softc *, struct ioc_play_msf *);
184: int mcd_playblocks(struct mcd_softc *, struct ioc_play_blocks *);
185: int mcd_stop(struct mcd_softc *);
186: int mcd_eject(struct mcd_softc *);
187: int mcd_read_subchannel(struct mcd_softc *, struct ioc_read_subchannel *);
188: int mcd_pause(struct mcd_softc *);
189: int mcd_resume(struct mcd_softc *);
190: int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *);
191: int mcd_toc_entries(struct mcd_softc *, struct ioc_read_toc_entry *);
192:
193: int mcd_getreply(struct mcd_softc *);
194: int mcd_getstat(struct mcd_softc *);
195: int mcd_getresult(struct mcd_softc *, struct mcd_result *);
196: void mcd_setflags(struct mcd_softc *);
197: int mcd_get(struct mcd_softc *, char *, int);
198: int mcd_send(struct mcd_softc *, struct mcd_mbox *, int);
199: int mcdintr(void *);
200: void mcd_soft_reset(struct mcd_softc *);
201: int mcd_hard_reset(struct mcd_softc *);
202: int mcd_setmode(struct mcd_softc *, int);
203: int mcd_setupc(struct mcd_softc *, int);
204: int mcd_read_toc(struct mcd_softc *);
205: int mcd_getqchan(struct mcd_softc *, union mcd_qchninfo *, int);
206: int mcd_setlock(struct mcd_softc *, int);
207:
208: int mcd_find(bus_space_tag_t, bus_space_handle_t, struct mcd_softc *);
209: int mcdprobe(struct device *, void *, void *);
210: void mcdattach(struct device *, struct device *, void *);
211:
212: struct cfattach mcd_ca = {
213: sizeof(struct mcd_softc), mcdprobe, mcdattach
214: };
215:
216: struct cfdriver mcd_cd = {
217: NULL, "mcd", DV_DISK
218: };
219:
220: void mcdgetdisklabel(dev_t, struct mcd_softc *, struct disklabel *, int);
221: int mcd_get_parms(struct mcd_softc *);
222: void mcdstrategy(struct buf *);
223: void mcdstart(struct mcd_softc *);
224: int mcdlock(struct mcd_softc *);
225: void mcdunlock(struct mcd_softc *);
226: void mcd_pseudointr(void *);
227:
228: struct dkdriver mcddkdriver = { mcdstrategy };
229:
230: #define MCD_RETRIES 3
231: #define MCD_RDRETRIES 3
232:
233: /* several delays */
234: #define RDELAY_WAITMODE 300
235: #define RDELAY_WAITREAD 800
236:
237: #define DELAY_GRANULARITY 25 /* 25us */
238: #define DELAY_GETREPLY 100000 /* 100000 * 25us */
239:
240: void
241: mcdattach(parent, self, aux)
242: struct device *parent, *self;
243: void *aux;
244: {
245: struct mcd_softc *sc = (void *)self;
246: struct isa_attach_args *ia = aux;
247: bus_space_tag_t iot = ia->ia_iot;
248: bus_space_handle_t ioh;
249: struct mcd_mbox mbx;
250:
251: /* Map i/o space */
252: if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh)) {
253: printf(": can't map i/o space\n");
254: return;
255: }
256:
257: sc->sc_iot = iot;
258: sc->sc_ioh = ioh;
259:
260: sc->probe = 0;
261: sc->debug = 0;
262:
263: if (!mcd_find(iot, ioh, sc)) {
264: printf(": mcd_find failed\n");
265: return;
266: }
267:
268: timeout_set(&sc->sc_pi_tmo, mcd_pseudointr, sc);
269:
270: /*
271: * Initialize and attach the disk structure.
272: */
273: sc->sc_dk.dk_driver = &mcddkdriver;
274: sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
275: disk_attach(&sc->sc_dk);
276:
277: printf(": model %s\n", sc->type != 0 ? sc->type : "unknown");
278:
279: (void) mcd_setlock(sc, MCD_LK_UNLOCK);
280:
281: mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
282: mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
283: mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE;
284: mbx.cmd.data.config.data1 = 0x01;
285: mbx.res.length = 0;
286: (void) mcd_send(sc, &mbx, 0);
287:
288: mcd_soft_reset(sc);
289:
290: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
291: IPL_BIO, mcdintr, sc, sc->sc_dev.dv_xname);
292: }
293:
294: /*
295: * Wait interruptibly for an exclusive lock.
296: *
297: * XXX
298: * Several drivers do this; it should be abstracted and made MP-safe.
299: */
300: int
301: mcdlock(sc)
302: struct mcd_softc *sc;
303: {
304: int error;
305:
306: while ((sc->flags & MCDF_LOCKED) != 0) {
307: sc->flags |= MCDF_WANTED;
308: if ((error = tsleep(sc, PRIBIO | PCATCH, "mcdlck", 0)) != 0)
309: return error;
310: }
311: sc->flags |= MCDF_LOCKED;
312: return 0;
313: }
314:
315: /*
316: * Unlock and wake up any waiters.
317: */
318: void
319: mcdunlock(sc)
320: struct mcd_softc *sc;
321: {
322:
323: sc->flags &= ~MCDF_LOCKED;
324: if ((sc->flags & MCDF_WANTED) != 0) {
325: sc->flags &= ~MCDF_WANTED;
326: wakeup(sc);
327: }
328: }
329:
330: int
331: mcdopen(dev, flag, fmt, p)
332: dev_t dev;
333: int flag, fmt;
334: struct proc *p;
335: {
336: int error;
337: int unit, part;
338: struct mcd_softc *sc;
339:
340: unit = DISKUNIT(dev);
341: if (unit >= mcd_cd.cd_ndevs)
342: return ENXIO;
343: sc = mcd_cd.cd_devs[unit];
344: if (!sc)
345: return ENXIO;
346:
347: if ((error = mcdlock(sc)) != 0)
348: return error;
349:
350: if (sc->sc_dk.dk_openmask != 0) {
351: /*
352: * If any partition is open, but the disk has been invalidated,
353: * disallow further opens.
354: */
355: if ((sc->flags & MCDF_LOADED) == 0) {
356: error = EIO;
357: goto bad3;
358: }
359: } else {
360: /*
361: * Lock the drawer. This will also notice any pending disk
362: * change or door open indicator and clear the MCDF_LOADED bit
363: * if necessary.
364: */
365: (void) mcd_setlock(sc, MCD_LK_LOCK);
366:
367: if ((sc->flags & MCDF_LOADED) == 0) {
368: /* Partially reset the state. */
369: sc->lastmode = MCD_MD_UNKNOWN;
370: sc->lastupc = MCD_UPC_UNKNOWN;
371:
372: sc->flags |= MCDF_LOADED;
373:
374: /* Set the mode, causing the disk to spin up. */
375: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
376: goto bad2;
377:
378: /* Load the physical device parameters. */
379: if (mcd_get_parms(sc) != 0) {
380: error = ENXIO;
381: goto bad2;
382: }
383:
384: /* Read the table of contents. */
385: if ((error = mcd_read_toc(sc)) != 0)
386: goto bad2;
387:
388: /* Fabricate a disk label. */
389: mcdgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
390: }
391: }
392:
393: MCD_TRACE("open: partition=%d disksize=%d blksize=%d\n", part,
394: sc->disksize, sc->blksize, 0);
395:
396: part = DISKPART(dev);
397:
398: /* Check that the partition exists. */
399: if (part != RAW_PART &&
400: (part >= sc->sc_dk.dk_label->d_npartitions ||
401: sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
402: error = ENXIO;
403: goto bad;
404: }
405:
406: /* Insure only one open at a time. */
407: switch (fmt) {
408: case S_IFCHR:
409: sc->sc_dk.dk_copenmask |= (1 << part);
410: break;
411: case S_IFBLK:
412: sc->sc_dk.dk_bopenmask |= (1 << part);
413: break;
414: }
415: sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
416:
417: mcdunlock(sc);
418: return 0;
419:
420: bad2:
421: sc->flags &= ~MCDF_LOADED;
422:
423: bad:
424: if (sc->sc_dk.dk_openmask == 0) {
425: #if 0
426: (void) mcd_setmode(sc, MCD_MD_SLEEP);
427: #endif
428: (void) mcd_setlock(sc, MCD_LK_UNLOCK);
429: }
430:
431: bad3:
432: mcdunlock(sc);
433: return error;
434: }
435:
436: int
437: mcdclose(dev, flag, fmt, p)
438: dev_t dev;
439: int flag, fmt;
440: struct proc *p;
441: {
442: struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(dev)];
443: int part = DISKPART(dev);
444: int error;
445:
446: MCD_TRACE("close: partition=%d\n", part, 0, 0, 0);
447:
448: if ((error = mcdlock(sc)) != 0)
449: return error;
450:
451: switch (fmt) {
452: case S_IFCHR:
453: sc->sc_dk.dk_copenmask &= ~(1 << part);
454: break;
455: case S_IFBLK:
456: sc->sc_dk.dk_bopenmask &= ~(1 << part);
457: break;
458: }
459: sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
460:
461: if (sc->sc_dk.dk_openmask == 0) {
462: /* XXXX Must wait for I/O to complete! */
463:
464: #if 0
465: (void) mcd_setmode(sc, MCD_MD_SLEEP);
466: #endif
467: (void) mcd_setlock(sc, MCD_LK_UNLOCK);
468: if (sc->flags & MCDF_EJECTING) {
469: mcd_eject(sc);
470: sc->flags &= ~MCDF_EJECTING;
471: }
472: }
473: mcdunlock(sc);
474: return 0;
475: }
476:
477: void
478: mcdstrategy(bp)
479: struct buf *bp;
480: {
481: struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(bp->b_dev)];
482: int s;
483:
484: /* Test validity. */
485: MCD_TRACE("strategy: buf=0x%lx blkno=%ld bcount=%ld\n", bp,
486: bp->b_blkno, bp->b_bcount, 0);
487: if (bp->b_blkno < 0 ||
488: (bp->b_bcount % sc->blksize) != 0) {
489: printf("%s: strategy: blkno = %d bcount = %ld\n",
490: sc->sc_dev.dv_xname, bp->b_blkno, bp->b_bcount);
491: bp->b_error = EINVAL;
492: goto bad;
493: }
494:
495: /* If device invalidated (e.g. media change, door open), error. */
496: if ((sc->flags & MCDF_LOADED) == 0) {
497: MCD_TRACE("strategy: drive not valid\n", 0, 0, 0, 0);
498: bp->b_error = EIO;
499: goto bad;
500: }
501:
502: /* No data to read. */
503: if (bp->b_bcount == 0)
504: goto done;
505:
506: /*
507: * Do bounds checking, adjust transfer. if error, process.
508: * If end of partition, just return.
509: */
510: if (DISKPART(bp->b_dev) != RAW_PART &&
511: bounds_check_with_label(bp, sc->sc_dk.dk_label,
512: (sc->flags & (MCDF_WLABEL|MCDF_LABELLING)) != 0) <= 0)
513: goto done;
514:
515: /* Queue it. */
516: s = splbio();
517: disksort(&sc->buf_queue, bp);
518: splx(s);
519: if (!sc->buf_queue.b_active)
520: mcdstart(sc);
521: return;
522:
523: bad:
524: bp->b_flags |= B_ERROR;
525: done:
526: bp->b_resid = bp->b_bcount;
527: s = splbio();
528: biodone(bp);
529: splx(s);
530: }
531:
532: void
533: mcdstart(sc)
534: struct mcd_softc *sc;
535: {
536: struct buf *bp, *dp = &sc->buf_queue;
537: int s;
538:
539: loop:
540: s = splbio();
541:
542: bp = dp->b_actf;
543: if (bp == NULL) {
544: /* Nothing to do. */
545: dp->b_active = 0;
546: splx(s);
547: return;
548: }
549:
550: /* Block found to process; dequeue. */
551: MCD_TRACE("start: found block bp=0x%x\n", bp, 0, 0, 0);
552: dp->b_actf = bp->b_actf;
553: splx(s);
554:
555: /* Changed media? */
556: if ((sc->flags & MCDF_LOADED) == 0) {
557: MCD_TRACE("start: drive not valid\n", 0, 0, 0, 0);
558: bp->b_error = EIO;
559: bp->b_flags |= B_ERROR;
560: s = splbio();
561: biodone(bp);
562: splx(s);
563: goto loop;
564: }
565:
566: dp->b_active = 1;
567:
568: /* Instrumentation. */
569: s = splbio();
570: disk_busy(&sc->sc_dk);
571: splx(s);
572:
573: sc->mbx.retry = MCD_RDRETRIES;
574: sc->mbx.bp = bp;
575: sc->mbx.blkno = bp->b_blkno / (sc->blksize / DEV_BSIZE);
576: if (DISKPART(bp->b_dev) != RAW_PART) {
577: struct partition *p;
578: p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
579: sc->mbx.blkno += DL_GETPOFFSET(p);
580: }
581: sc->mbx.nblk = bp->b_bcount / sc->blksize;
582: sc->mbx.sz = sc->blksize;
583: sc->mbx.skip = 0;
584: sc->mbx.state = MCD_S_BEGIN;
585: sc->mbx.mode = MCD_MD_COOKED;
586:
587: s = splbio();
588: (void) mcdintr(sc);
589: splx(s);
590: }
591:
592: int
593: mcdread(dev, uio, flags)
594: dev_t dev;
595: struct uio *uio;
596: int flags;
597: {
598:
599: return (physio(mcdstrategy, NULL, dev, B_READ, minphys, uio));
600: }
601:
602: int
603: mcdwrite(dev, uio, flags)
604: dev_t dev;
605: struct uio *uio;
606: int flags;
607: {
608:
609: return (physio(mcdstrategy, NULL, dev, B_WRITE, minphys, uio));
610: }
611:
612: int
613: mcdioctl(dev, cmd, addr, flag, p)
614: dev_t dev;
615: u_long cmd;
616: caddr_t addr;
617: int flag;
618: struct proc *p;
619: {
620: struct mcd_softc *sc = mcd_cd.cd_devs[DISKUNIT(dev)];
621: struct disklabel *lp;
622: int error;
623:
624: MCD_TRACE("ioctl: cmd=0x%x\n", cmd, 0, 0, 0);
625:
626: if ((sc->flags & MCDF_LOADED) == 0)
627: return EIO;
628:
629: switch (cmd) {
630: case DIOCRLDINFO:
631: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
632: mcdgetdisklabel(dev, sc, lp, 0);
633: bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp));
634: free(lp, M_TEMP);
635: return 0;
636:
637: case DIOCGDINFO:
638: case DIOCGPDINFO:
639: *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
640: return 0;
641:
642: case DIOCGPART:
643: ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
644: ((struct partinfo *)addr)->part =
645: &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
646: return 0;
647:
648: case DIOCWDINFO:
649: case DIOCSDINFO:
650: if ((flag & FWRITE) == 0)
651: return EBADF;
652:
653: if ((error = mcdlock(sc)) != 0)
654: return error;
655: sc->flags |= MCDF_LABELLING;
656:
657: error = setdisklabel(sc->sc_dk.dk_label,
658: (struct disklabel *)addr, /*sc->sc_dk.dk_openmask : */0);
659: if (error == 0) {
660: }
661:
662: sc->flags &= ~MCDF_LABELLING;
663: mcdunlock(sc);
664: return error;
665:
666: case DIOCWLABEL:
667: return EBADF;
668:
669: case CDIOCPLAYTRACKS:
670: return mcd_playtracks(sc, (struct ioc_play_track *)addr);
671: case CDIOCPLAYMSF:
672: return mcd_playmsf(sc, (struct ioc_play_msf *)addr);
673: case CDIOCPLAYBLOCKS:
674: return mcd_playblocks(sc, (struct ioc_play_blocks *)addr);
675: case CDIOCREADSUBCHANNEL:
676: return mcd_read_subchannel(sc, (struct ioc_read_subchannel *)addr);
677: case CDIOREADTOCHEADER:
678: return mcd_toc_header(sc, (struct ioc_toc_header *)addr);
679: case CDIOREADTOCENTRYS:
680: return mcd_toc_entries(sc, (struct ioc_read_toc_entry *)addr);
681: case CDIOCSETPATCH:
682: case CDIOCGETVOL:
683: case CDIOCSETVOL:
684: case CDIOCSETMONO:
685: case CDIOCSETSTEREO:
686: case CDIOCSETMUTE:
687: case CDIOCSETLEFT:
688: case CDIOCSETRIGHT:
689: return EINVAL;
690: case CDIOCRESUME:
691: return mcd_resume(sc);
692: case CDIOCPAUSE:
693: return mcd_pause(sc);
694: case CDIOCSTART:
695: return EINVAL;
696: case CDIOCSTOP:
697: return mcd_stop(sc);
698: case MTIOCTOP:
699: if (((struct mtop *)addr)->mt_op != MTOFFL)
700: return EIO;
701: /* FALLTHROUGH */
702: case CDIOCEJECT: /* FALLTHROUGH */
703: case DIOCEJECT:
704: sc->flags |= MCDF_EJECTING;
705: return (0);
706: case CDIOCALLOW:
707: return mcd_setlock(sc, MCD_LK_UNLOCK);
708: case CDIOCPREVENT:
709: return mcd_setlock(sc, MCD_LK_LOCK);
710: case DIOCLOCK:
711: return mcd_setlock(sc,
712: (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK);
713: case CDIOCSETDEBUG:
714: sc->debug = 1;
715: return 0;
716: case CDIOCCLRDEBUG:
717: sc->debug = 0;
718: return 0;
719: case CDIOCRESET:
720: return mcd_hard_reset(sc);
721:
722: default:
723: return ENOTTY;
724: }
725:
726: #ifdef DIAGNOSTIC
727: panic("mcdioctl: impossible");
728: #endif
729: }
730:
731: void
732: mcdgetdisklabel(dev, sc, lp, spoofonly)
733: dev_t dev;
734: struct mcd_softc *sc;
735: struct disklabel *lp;
736: int spoofonly;
737: {
738: char *errstring;
739:
740: bzero(lp, sizeof(struct disklabel));
741:
742: lp->d_secsize = sc->blksize;
743: lp->d_ntracks = 1;
744: lp->d_nsectors = 100;
745: lp->d_ncylinders = (sc->disksize / 100) + 1;
746: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
747: if (lp->d_secpercyl == 0) {
748: lp->d_secpercyl = 100;
749: /* as long as it's not 0 - readdisklabel divides by it */
750: }
751:
752: strncpy(lp->d_typename, "Mitsumi CD-ROM", sizeof lp->d_typename);
753: lp->d_type = DTYPE_SCSI; /* XXX */
754: strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname);
755: DL_SETDSIZE(lp, sc->disksize);
756: lp->d_rpm = 300;
757: lp->d_interleave = 1;
758: lp->d_version = 1;
759:
760: lp->d_magic = DISKMAGIC;
761: lp->d_magic2 = DISKMAGIC;
762: lp->d_checksum = dkcksum(lp);
763:
764: /*
765: * Call the generic disklabel extraction routine
766: */
767: errstring = readdisklabel(DISKLABELDEV(dev), mcdstrategy, lp, spoofonly);
768: if (errstring) {
769: /*printf("%s: %s\n", sc->sc_dev.dv_xname, errstring);*/
770: return;
771: }
772: }
773:
774: int
775: mcd_get_parms(sc)
776: struct mcd_softc *sc;
777: {
778: struct mcd_mbox mbx;
779: daddr64_t size;
780: int error;
781:
782: /* Send volume info command. */
783: mbx.cmd.opcode = MCD_CMDGETVOLINFO;
784: mbx.cmd.length = 0;
785: mbx.res.length = sizeof(mbx.res.data.volinfo);
786: if ((error = mcd_send(sc, &mbx, 1)) != 0)
787: return error;
788:
789: if (mbx.res.data.volinfo.trk_low == 0x00 &&
790: mbx.res.data.volinfo.trk_high == 0x00)
791: return EINVAL;
792:
793: /* Volinfo is OK. */
794: sc->volinfo = mbx.res.data.volinfo;
795: sc->blksize = MCD_BLKSIZE_COOKED;
796: size = msf2hsg(sc->volinfo.vol_msf, 0);
797: sc->disksize = size * (MCD_BLKSIZE_COOKED / DEV_BSIZE);
798: return 0;
799: }
800:
801: daddr64_t
802: mcdsize(dev)
803: dev_t dev;
804: {
805:
806: /* CD-ROMs are read-only. */
807: return -1;
808: }
809:
810: int
811: mcddump(dev, blkno, va, size)
812: dev_t dev;
813: daddr64_t blkno;
814: caddr_t va;
815: size_t size;
816: {
817:
818: /* Not implemented. */
819: return ENXIO;
820: }
821:
822: /*
823: * Find the board and fill in the softc.
824: */
825: int
826: mcd_find(iot, ioh, sc)
827: bus_space_tag_t iot;
828: bus_space_handle_t ioh;
829: struct mcd_softc *sc;
830: {
831: int i;
832: struct mcd_mbox mbx;
833:
834: sc->sc_iot = iot;
835: sc->sc_ioh = ioh;
836:
837: /* Send a reset. */
838: bus_space_write_1(iot, ioh, MCD_RESET, 0);
839: delay(1000000);
840: /* Get any pending status and throw away. */
841: for (i = 10; i; i--)
842: bus_space_read_1(iot, ioh, MCD_STATUS);
843: delay(1000);
844:
845: /* Send get status command. */
846: mbx.cmd.opcode = MCD_CMDGETSTAT;
847: mbx.cmd.length = 0;
848: mbx.res.length = 0;
849: if (mcd_send(sc, &mbx, 0) != 0)
850: return 0;
851:
852: /* Get info about the drive. */
853: mbx.cmd.opcode = MCD_CMDCONTINFO;
854: mbx.cmd.length = 0;
855: mbx.res.length = sizeof(mbx.res.data.continfo);
856: if (mcd_send(sc, &mbx, 0) != 0)
857: return 0;
858:
859: /*
860: * The following is code which is not guaranteed to work for all
861: * drives, because the meaning of the expected 'M' is not clear
862: * (M_itsumi is an obvious assumption, but I don't trust that).
863: * Also, the original hack had a bogus condition that always
864: * returned true.
865: *
866: * Note: Which models support interrupts? >=LU005S?
867: */
868: sc->readcmd = MCD_CMDREADSINGLESPEED;
869: switch (mbx.res.data.continfo.code) {
870: case 'M':
871: if (mbx.res.data.continfo.version <= 2)
872: sc->type = "LU002S";
873: else if (mbx.res.data.continfo.version <= 5)
874: sc->type = "LU005S";
875: else
876: sc->type = "LU006S";
877: break;
878: case 'F':
879: sc->type = "FX001";
880: break;
881: case 'D':
882: sc->type = "FX001D";
883: sc->readcmd = MCD_CMDREADDOUBLESPEED;
884: break;
885: default:
886: #ifdef MCDDEBUG
887: printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n",
888: sc->sc_dev.dv_xname,
889: mbx.res.data.continfo.code, mbx.res.data.continfo.version);
890: #endif
891: sc->type = 0;
892: break;
893: }
894:
895: return 1;
896:
897: }
898:
899: int
900: mcdprobe(parent, match, aux)
901: struct device *parent;
902: void *match;
903: void *aux;
904: {
905: struct isa_attach_args *ia = aux;
906: struct mcd_softc sc;
907: bus_space_tag_t iot = ia->ia_iot;
908: bus_space_handle_t ioh;
909: int rv;
910:
911: /* Disallow wildcarded i/o address. */
912: if (ia->ia_iobase == -1 /*ISACF_PORT_DEFAULT*/)
913: return (0);
914:
915: /* Map i/o space */
916: if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh))
917: return 0;
918:
919: if (!opti_cd_setup(OPTI_MITSUMI, ia->ia_iobase, ia->ia_irq, ia->ia_drq))
920: /* printf("mcdprobe: could not setup OPTi chipset.\n") */;
921:
922: bzero(&sc, sizeof sc);
923: sc.debug = 0;
924: sc.probe = 1;
925:
926: rv = mcd_find(iot, ioh, &sc);
927:
928: bus_space_unmap(iot, ioh, MCD_NPORT);
929:
930: if (rv) {
931: ia->ia_iosize = MCD_NPORT;
932: ia->ia_msize = 0;
933: }
934:
935: return (rv);
936: }
937:
938: int
939: mcd_getreply(sc)
940: struct mcd_softc *sc;
941: {
942: bus_space_tag_t iot = sc->sc_iot;
943: bus_space_handle_t ioh = sc->sc_ioh;
944: int i;
945:
946: /* Wait until xfer port senses data ready. */
947: for (i = DELAY_GETREPLY; i; i--) {
948: if ((bus_space_read_1(iot, ioh, MCD_XFER) &
949: MCD_XF_STATUSUNAVAIL) == 0)
950: break;
951: delay(DELAY_GRANULARITY);
952: }
953: if (!i)
954: return -1;
955:
956: /* Get the data. */
957: return bus_space_read_1(iot, ioh, MCD_STATUS);
958: }
959:
960: int
961: mcd_getstat(sc)
962: struct mcd_softc *sc;
963: {
964: struct mcd_mbox mbx;
965:
966: mbx.cmd.opcode = MCD_CMDGETSTAT;
967: mbx.cmd.length = 0;
968: mbx.res.length = 0;
969: return mcd_send(sc, &mbx, 1);
970: }
971:
972: int
973: mcd_getresult(sc, res)
974: struct mcd_softc *sc;
975: struct mcd_result *res;
976: {
977: int i, x;
978:
979: if (sc->debug)
980: printf("%s: mcd_getresult: %d", sc->sc_dev.dv_xname,
981: res->length);
982:
983: if ((x = mcd_getreply(sc)) < 0) {
984: if (sc->debug)
985: printf(" timeout\n");
986: else if (sc->probe == 0)
987: printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
988: return EIO;
989: }
990: if (sc->debug)
991: printf(" %02x", (u_int)x);
992: sc->status = x;
993: mcd_setflags(sc);
994:
995: if ((sc->status & MCD_ST_CMDCHECK) != 0)
996: return EINVAL;
997:
998: for (i = 0; i < res->length; i++) {
999: if ((x = mcd_getreply(sc)) < 0) {
1000: if (sc->debug)
1001: printf(" timeout\n");
1002: else
1003: printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname);
1004: return EIO;
1005: }
1006: if (sc->debug)
1007: printf(" %02x", (u_int)x);
1008: res->data.raw.data[i] = x;
1009: }
1010:
1011: if (sc->debug)
1012: printf(" succeeded\n");
1013:
1014: #ifdef MCDDEBUG
1015: delay(10);
1016: while ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_XFER) &
1017: MCD_XF_STATUSUNAVAIL) == 0) {
1018: x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_STATUS);
1019: printf("%s: got extra byte %02x during getstatus\n",
1020: sc->sc_dev.dv_xname, (u_int)x);
1021: delay(10);
1022: }
1023: #endif
1024:
1025: return 0;
1026: }
1027:
1028: void
1029: mcd_setflags(sc)
1030: struct mcd_softc *sc;
1031: {
1032:
1033: /* Check flags. */
1034: if ((sc->flags & MCDF_LOADED) != 0 &&
1035: (sc->status & (MCD_ST_DSKCHNG | MCD_ST_DSKIN | MCD_ST_DOOROPEN)) !=
1036: MCD_ST_DSKIN) {
1037: if ((sc->status & MCD_ST_DOOROPEN) != 0)
1038: printf("%s: door open\n", sc->sc_dev.dv_xname);
1039: else if ((sc->status & MCD_ST_DSKIN) == 0)
1040: printf("%s: no disk present\n", sc->sc_dev.dv_xname);
1041: else if ((sc->status & MCD_ST_DSKCHNG) != 0)
1042: printf("%s: media change\n", sc->sc_dev.dv_xname);
1043: sc->flags &= ~MCDF_LOADED;
1044: }
1045:
1046: if ((sc->status & MCD_ST_AUDIOBSY) != 0)
1047: sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
1048: else if (sc->audio_status == CD_AS_PLAY_IN_PROGRESS ||
1049: sc->audio_status == CD_AS_AUDIO_INVALID)
1050: sc->audio_status = CD_AS_PLAY_COMPLETED;
1051: }
1052:
1053: int
1054: mcd_send(sc, mbx, diskin)
1055: struct mcd_softc *sc;
1056: struct mcd_mbox *mbx;
1057: int diskin;
1058: {
1059: int retry, i, error;
1060: bus_space_tag_t iot = sc->sc_iot;
1061: bus_space_handle_t ioh = sc->sc_ioh;
1062:
1063: if (sc->debug) {
1064: printf("%s: mcd_send: %d %02x", sc->sc_dev.dv_xname,
1065: mbx->cmd.length, (u_int)mbx->cmd.opcode);
1066: for (i = 0; i < mbx->cmd.length; i++)
1067: printf(" %02x", (u_int)mbx->cmd.data.raw.data[i]);
1068: printf("\n");
1069: }
1070:
1071: for (retry = MCD_RETRIES; retry; retry--) {
1072: bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.opcode);
1073: for (i = 0; i < mbx->cmd.length; i++)
1074: bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.data.raw.data[i]);
1075: if ((error = mcd_getresult(sc, &mbx->res)) == 0)
1076: break;
1077: if (error == EINVAL)
1078: return error;
1079: }
1080: if (!retry)
1081: return error;
1082: if (diskin && (sc->flags & MCDF_LOADED) == 0)
1083: return EIO;
1084:
1085: return 0;
1086: }
1087:
1088: static void
1089: hsg2msf(hsg, msf)
1090: int hsg;
1091: bcd_t *msf;
1092: {
1093:
1094: hsg += 150;
1095: F_msf(msf) = bin2bcd(hsg % 75);
1096: hsg /= 75;
1097: S_msf(msf) = bin2bcd(hsg % 60);
1098: hsg /= 60;
1099: M_msf(msf) = bin2bcd(hsg);
1100: }
1101:
1102: static daddr64_t
1103: msf2hsg(msf, relative)
1104: bcd_t *msf;
1105: int relative;
1106: {
1107: daddr64_t blkno;
1108:
1109: blkno = bcd2bin(M_msf(msf)) * 75 * 60 +
1110: bcd2bin(S_msf(msf)) * 75 +
1111: bcd2bin(F_msf(msf));
1112: if (!relative)
1113: blkno -= 150;
1114: return blkno;
1115: }
1116:
1117: void
1118: mcd_pseudointr(v)
1119: void *v;
1120: {
1121: struct mcd_softc *sc = v;
1122: int s;
1123:
1124: s = splbio();
1125: (void) mcdintr(sc);
1126: splx(s);
1127: }
1128:
1129: /*
1130: * State machine to process read requests.
1131: * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
1132: * MCD_S_WAITMODE: waits for status reply from set mode, set read command
1133: * MCD_S_WAITREAD: wait for read ready, read data.
1134: */
1135: int
1136: mcdintr(arg)
1137: void *arg;
1138: {
1139: struct mcd_softc *sc = arg;
1140: struct mcd_mbx *mbx = &sc->mbx;
1141: struct buf *bp = mbx->bp;
1142: bus_space_tag_t iot = sc->sc_iot;
1143: bus_space_handle_t ioh = sc->sc_ioh;
1144:
1145: int i;
1146: u_char x;
1147: bcd_t msf[3];
1148:
1149: switch (mbx->state) {
1150: case MCD_S_IDLE:
1151: return 0;
1152:
1153: case MCD_S_BEGIN:
1154: tryagain:
1155: if (mbx->mode == sc->lastmode)
1156: goto firstblock;
1157:
1158: sc->lastmode = MCD_MD_UNKNOWN;
1159: bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE);
1160: bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode);
1161:
1162: mbx->count = RDELAY_WAITMODE;
1163: mbx->state = MCD_S_WAITMODE;
1164:
1165: case MCD_S_WAITMODE:
1166: timeout_del(&sc->sc_pi_tmo);
1167: for (i = 20; i; i--) {
1168: x = bus_space_read_1(iot, ioh, MCD_XFER);
1169: if ((x & MCD_XF_STATUSUNAVAIL) == 0)
1170: break;
1171: delay(50);
1172: }
1173: if (i == 0)
1174: goto hold;
1175: sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
1176: mcd_setflags(sc);
1177: if ((sc->flags & MCDF_LOADED) == 0)
1178: goto changed;
1179: MCD_TRACE("doread: got WAITMODE delay=%d\n",
1180: RDELAY_WAITMODE - mbx->count, 0, 0, 0);
1181:
1182: sc->lastmode = mbx->mode;
1183:
1184: firstblock:
1185: MCD_TRACE("doread: read blkno=%d for bp=0x%x\n", mbx->blkno,
1186: bp, 0, 0);
1187:
1188: /* Build parameter block. */
1189: hsg2msf(mbx->blkno, msf);
1190:
1191: /* Send the read command. */
1192: bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd);
1193: bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]);
1194: bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]);
1195: bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]);
1196: bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
1197: bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
1198: bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk);
1199:
1200: mbx->count = RDELAY_WAITREAD;
1201: mbx->state = MCD_S_WAITREAD;
1202:
1203: case MCD_S_WAITREAD:
1204: timeout_del(&sc->sc_pi_tmo);
1205: nextblock:
1206: loop:
1207: for (i = 20; i; i--) {
1208: x = bus_space_read_1(iot, ioh, MCD_XFER);
1209: if ((x & MCD_XF_DATAUNAVAIL) == 0)
1210: goto gotblock;
1211: if ((x & MCD_XF_STATUSUNAVAIL) == 0)
1212: break;
1213: delay(50);
1214: }
1215: if (i == 0)
1216: goto hold;
1217: sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
1218: mcd_setflags(sc);
1219: if ((sc->flags & MCDF_LOADED) == 0)
1220: goto changed;
1221: #if 0
1222: printf("%s: got status byte %02x during read\n",
1223: sc->sc_dev.dv_xname, (u_int)sc->status);
1224: #endif
1225: goto loop;
1226:
1227: gotblock:
1228: MCD_TRACE("doread: got data delay=%d\n",
1229: RDELAY_WAITREAD - mbx->count, 0, 0, 0);
1230:
1231: /* Data is ready. */
1232: bus_space_write_1(iot, ioh, MCD_CTL2, 0x04); /* XXX */
1233: bus_space_read_multi_1(iot, ioh, MCD_RDATA,
1234: bp->b_data + mbx->skip, mbx->sz);
1235: bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c); /* XXX */
1236: mbx->blkno += 1;
1237: mbx->skip += mbx->sz;
1238: if (--mbx->nblk > 0)
1239: goto nextblock;
1240:
1241: mbx->state = MCD_S_IDLE;
1242:
1243: /* Return buffer. */
1244: bp->b_resid = 0;
1245: disk_unbusy(&sc->sc_dk, bp->b_bcount, (bp->b_flags & B_READ));
1246: biodone(bp);
1247:
1248: mcdstart(sc);
1249: return 1;
1250:
1251: hold:
1252: if (mbx->count-- < 0) {
1253: printf("%s: timeout in state %d",
1254: sc->sc_dev.dv_xname, mbx->state);
1255: goto readerr;
1256: }
1257:
1258: #if 0
1259: printf("%s: sleep in state %d\n", sc->sc_dev.dv_xname,
1260: mbx->state);
1261: #endif
1262: timeout_add(&sc->sc_pi_tmo, hz / 100);
1263: return -1;
1264: }
1265:
1266: readerr:
1267: if (mbx->retry-- > 0) {
1268: printf("; retrying\n");
1269: goto tryagain;
1270: } else
1271: printf("; giving up\n");
1272:
1273: changed:
1274: /* Invalidate the buffer. */
1275: bp->b_flags |= B_ERROR;
1276: bp->b_resid = bp->b_bcount - mbx->skip;
1277: disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
1278: (bp->b_flags & B_READ));
1279: biodone(bp);
1280:
1281: mcdstart(sc);
1282: return -1;
1283:
1284: #ifdef notyet
1285: printf("%s: unit timeout; resetting\n", sc->sc_dev.dv_xname);
1286: bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET);
1287: delay(300000);
1288: (void) mcd_getstat(sc, 1);
1289: (void) mcd_getstat(sc, 1);
1290: /*sc->status &= ~MCD_ST_DSKCHNG; */
1291: sc->debug = 1; /* preventive set debug mode */
1292: #endif
1293: }
1294:
1295: void
1296: mcd_soft_reset(sc)
1297: struct mcd_softc *sc;
1298: {
1299:
1300: sc->debug = 0;
1301: sc->flags = 0;
1302: sc->lastmode = MCD_MD_UNKNOWN;
1303: sc->lastupc = MCD_UPC_UNKNOWN;
1304: sc->audio_status = CD_AS_AUDIO_INVALID;
1305: bus_space_write_1(sc->sc_iot, sc->sc_ioh, MCD_CTL2, 0x0c); /* XXX */
1306: }
1307:
1308: int
1309: mcd_hard_reset(sc)
1310: struct mcd_softc *sc;
1311: {
1312: struct mcd_mbox mbx;
1313:
1314: mcd_soft_reset(sc);
1315:
1316: mbx.cmd.opcode = MCD_CMDRESET;
1317: mbx.cmd.length = 0;
1318: mbx.res.length = 0;
1319: return mcd_send(sc, &mbx, 0);
1320: }
1321:
1322: int
1323: mcd_setmode(sc, mode)
1324: struct mcd_softc *sc;
1325: int mode;
1326: {
1327: struct mcd_mbox mbx;
1328: int error;
1329:
1330: if (sc->lastmode == mode)
1331: return 0;
1332: if (sc->debug)
1333: printf("%s: setting mode to %d\n", sc->sc_dev.dv_xname, mode);
1334: sc->lastmode = MCD_MD_UNKNOWN;
1335:
1336: mbx.cmd.opcode = MCD_CMDSETMODE;
1337: mbx.cmd.length = sizeof(mbx.cmd.data.datamode);
1338: mbx.cmd.data.datamode.mode = mode;
1339: mbx.res.length = 0;
1340: if ((error = mcd_send(sc, &mbx, 1)) != 0)
1341: return error;
1342:
1343: sc->lastmode = mode;
1344: return 0;
1345: }
1346:
1347: int
1348: mcd_setupc(sc, upc)
1349: struct mcd_softc *sc;
1350: int upc;
1351: {
1352: struct mcd_mbox mbx;
1353: int error;
1354:
1355: if (sc->lastupc == upc)
1356: return 0;
1357: if (sc->debug)
1358: printf("%s: setting upc to %d\n", sc->sc_dev.dv_xname, upc);
1359: sc->lastupc = MCD_UPC_UNKNOWN;
1360:
1361: mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
1362: mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
1363: mbx.cmd.data.config.subcommand = MCD_CF_READUPC;
1364: mbx.cmd.data.config.data1 = upc;
1365: mbx.res.length = 0;
1366: if ((error = mcd_send(sc, &mbx, 1)) != 0)
1367: return error;
1368:
1369: sc->lastupc = upc;
1370: return 0;
1371: }
1372:
1373: int
1374: mcd_toc_header(sc, th)
1375: struct mcd_softc *sc;
1376: struct ioc_toc_header *th;
1377: {
1378:
1379: if (sc->debug)
1380: printf("%s: mcd_toc_header: reading toc header\n",
1381: sc->sc_dev.dv_xname);
1382:
1383: th->len = msf2hsg(sc->volinfo.vol_msf, 0);
1384: th->starting_track = bcd2bin(sc->volinfo.trk_low);
1385: th->ending_track = bcd2bin(sc->volinfo.trk_high);
1386:
1387: return 0;
1388: }
1389:
1390: int
1391: mcd_read_toc(sc)
1392: struct mcd_softc *sc;
1393: {
1394: struct ioc_toc_header th;
1395: union mcd_qchninfo q;
1396: int error, trk, idx, retry;
1397:
1398: if ((error = mcd_toc_header(sc, &th)) != 0)
1399: return error;
1400:
1401: if ((error = mcd_stop(sc)) != 0)
1402: return error;
1403:
1404: if (sc->debug)
1405: printf("%s: read_toc: reading qchannel info\n",
1406: sc->sc_dev.dv_xname);
1407:
1408: for (trk = th.starting_track; trk <= th.ending_track; trk++)
1409: sc->toc[trk].toc.idx_no = 0x00;
1410: trk = th.ending_track - th.starting_track + 1;
1411: for (retry = 300; retry && trk > 0; retry--) {
1412: if (mcd_getqchan(sc, &q, CD_TRACK_INFO) != 0)
1413: break;
1414: if (q.toc.trk_no != 0x00 || q.toc.idx_no == 0x00)
1415: continue;
1416: idx = bcd2bin(q.toc.idx_no);
1417: if (idx < MCD_MAXTOCS &&
1418: sc->toc[idx].toc.idx_no == 0x00) {
1419: sc->toc[idx] = q;
1420: trk--;
1421: }
1422: }
1423:
1424: /* Inform the drive that we're finished so it turns off the light. */
1425: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1426: return error;
1427:
1428: if (trk != 0)
1429: return EINVAL;
1430:
1431: /* Add a fake last+1 for mcd_playtracks(). */
1432: idx = th.ending_track + 1;
1433: sc->toc[idx].toc.control = sc->toc[idx-1].toc.control;
1434: sc->toc[idx].toc.addr_type = sc->toc[idx-1].toc.addr_type;
1435: sc->toc[idx].toc.trk_no = 0x00;
1436: sc->toc[idx].toc.idx_no = 0xaa;
1437: sc->toc[idx].toc.absolute_pos[0] = sc->volinfo.vol_msf[0];
1438: sc->toc[idx].toc.absolute_pos[1] = sc->volinfo.vol_msf[1];
1439: sc->toc[idx].toc.absolute_pos[2] = sc->volinfo.vol_msf[2];
1440:
1441: return 0;
1442: }
1443:
1444: int
1445: mcd_toc_entries(sc, te)
1446: struct mcd_softc *sc;
1447: struct ioc_read_toc_entry *te;
1448: {
1449: int len = te->data_len;
1450: struct ret_toc {
1451: struct ioc_toc_header header;
1452: struct cd_toc_entry entries[MCD_MAXTOCS];
1453: } data;
1454: u_char trk;
1455: daddr64_t lba;
1456: int error, n;
1457:
1458: if (len > sizeof(data.entries) ||
1459: len < sizeof(struct cd_toc_entry))
1460: return EINVAL;
1461: if (te->address_format != CD_MSF_FORMAT &&
1462: te->address_format != CD_LBA_FORMAT)
1463: return EINVAL;
1464:
1465: /* Copy the TOC header. */
1466: if ((error = mcd_toc_header(sc, &data.header)) != 0)
1467: return error;
1468:
1469: /* Verify starting track. */
1470: trk = te->starting_track;
1471: if (trk == 0x00)
1472: trk = data.header.starting_track;
1473: else if (trk == 0xaa)
1474: trk = data.header.ending_track + 1;
1475: else if (trk < data.header.starting_track ||
1476: trk > data.header.ending_track + 1)
1477: return EINVAL;
1478:
1479: /* Copy the TOC data. */
1480: for (n = 0; trk <= data.header.ending_track + 1; trk++) {
1481: if (sc->toc[trk].toc.idx_no == 0x00)
1482: continue;
1483: data.entries[n].control = sc->toc[trk].toc.control;
1484: data.entries[n].addr_type = sc->toc[trk].toc.addr_type;
1485: data.entries[n].track = bcd2bin(sc->toc[trk].toc.idx_no);
1486: switch (te->address_format) {
1487: case CD_MSF_FORMAT:
1488: data.entries[n].addr.addr[0] = 0;
1489: data.entries[n].addr.addr[1] =
1490: bcd2bin(sc->toc[trk].toc.absolute_pos[0]);
1491: data.entries[n].addr.addr[2] =
1492: bcd2bin(sc->toc[trk].toc.absolute_pos[1]);
1493: data.entries[n].addr.addr[3] =
1494: bcd2bin(sc->toc[trk].toc.absolute_pos[2]);
1495: break;
1496: case CD_LBA_FORMAT:
1497: lba = msf2hsg(sc->toc[trk].toc.absolute_pos, 0);
1498: data.entries[n].addr.addr[0] = lba >> 24;
1499: data.entries[n].addr.addr[1] = lba >> 16;
1500: data.entries[n].addr.addr[2] = lba >> 8;
1501: data.entries[n].addr.addr[3] = lba;
1502: break;
1503: }
1504: n++;
1505: }
1506:
1507: len = min(len, n * sizeof(struct cd_toc_entry));
1508:
1509: /* Copy the data back. */
1510: return copyout(&data.entries[0], te->data, len);
1511: }
1512:
1513: int
1514: mcd_stop(sc)
1515: struct mcd_softc *sc;
1516: {
1517: struct mcd_mbox mbx;
1518: int error;
1519:
1520: if (sc->debug)
1521: printf("%s: mcd_stop: stopping play\n", sc->sc_dev.dv_xname);
1522:
1523: mbx.cmd.opcode = MCD_CMDSTOPAUDIO;
1524: mbx.cmd.length = 0;
1525: mbx.res.length = 0;
1526: if ((error = mcd_send(sc, &mbx, 1)) != 0)
1527: return error;
1528:
1529: sc->audio_status = CD_AS_PLAY_COMPLETED;
1530: return 0;
1531: }
1532:
1533: int
1534: mcd_getqchan(sc, q, qchn)
1535: struct mcd_softc *sc;
1536: union mcd_qchninfo *q;
1537: int qchn;
1538: {
1539: struct mcd_mbox mbx;
1540: int error;
1541:
1542: if (qchn == CD_TRACK_INFO) {
1543: if ((error = mcd_setmode(sc, MCD_MD_TOC)) != 0)
1544: return error;
1545: } else {
1546: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1547: return error;
1548: }
1549: if (qchn == CD_MEDIA_CATALOG) {
1550: if ((error = mcd_setupc(sc, MCD_UPC_ENABLE)) != 0)
1551: return error;
1552: } else {
1553: if ((error = mcd_setupc(sc, MCD_UPC_DISABLE)) != 0)
1554: return error;
1555: }
1556:
1557: mbx.cmd.opcode = MCD_CMDGETQCHN;
1558: mbx.cmd.length = 0;
1559: mbx.res.length = sizeof(mbx.res.data.qchninfo);
1560: if ((error = mcd_send(sc, &mbx, 1)) != 0)
1561: return error;
1562:
1563: *q = mbx.res.data.qchninfo;
1564: return 0;
1565: }
1566:
1567: int
1568: mcd_read_subchannel(sc, ch)
1569: struct mcd_softc *sc;
1570: struct ioc_read_subchannel *ch;
1571: {
1572: int len = ch->data_len;
1573: union mcd_qchninfo q;
1574: struct cd_sub_channel_info data;
1575: daddr64_t lba;
1576: int error;
1577:
1578: if (sc->debug)
1579: printf("%s: subchan: af=%d df=%d\n", sc->sc_dev.dv_xname,
1580: ch->address_format, ch->data_format);
1581:
1582: if (len > sizeof(data) ||
1583: len < sizeof(struct cd_sub_channel_header))
1584: return EINVAL;
1585: if (ch->address_format != CD_MSF_FORMAT &&
1586: ch->address_format != CD_LBA_FORMAT)
1587: return EINVAL;
1588: if (ch->data_format != CD_CURRENT_POSITION &&
1589: ch->data_format != CD_MEDIA_CATALOG)
1590: return EINVAL;
1591:
1592: if ((error = mcd_getqchan(sc, &q, ch->data_format)) != 0)
1593: return error;
1594:
1595: data.header.audio_status = sc->audio_status;
1596: data.what.media_catalog.data_format = ch->data_format;
1597:
1598: switch (ch->data_format) {
1599: case CD_MEDIA_CATALOG:
1600: data.what.media_catalog.mc_valid = 1;
1601: #if 0
1602: data.what.media_catalog.mc_number =
1603: #endif
1604: break;
1605:
1606: case CD_CURRENT_POSITION:
1607: data.what.position.track_number = bcd2bin(q.current.trk_no);
1608: data.what.position.index_number = bcd2bin(q.current.idx_no);
1609: switch (ch->address_format) {
1610: case CD_MSF_FORMAT:
1611: data.what.position.reladdr.addr[0] = 0;
1612: data.what.position.reladdr.addr[1] =
1613: bcd2bin(q.current.relative_pos[0]);
1614: data.what.position.reladdr.addr[2] =
1615: bcd2bin(q.current.relative_pos[1]);
1616: data.what.position.reladdr.addr[3] =
1617: bcd2bin(q.current.relative_pos[2]);
1618: data.what.position.absaddr.addr[0] = 0;
1619: data.what.position.absaddr.addr[1] =
1620: bcd2bin(q.current.absolute_pos[0]);
1621: data.what.position.absaddr.addr[2] =
1622: bcd2bin(q.current.absolute_pos[1]);
1623: data.what.position.absaddr.addr[3] =
1624: bcd2bin(q.current.absolute_pos[2]);
1625: break;
1626: case CD_LBA_FORMAT:
1627: lba = msf2hsg(q.current.relative_pos, 1);
1628: /*
1629: * Pre-gap has index number of 0, and decreasing MSF
1630: * address. Must be converted to negative LBA, per
1631: * SCSI spec.
1632: */
1633: if (data.what.position.index_number == 0x00)
1634: lba = -lba;
1635: data.what.position.reladdr.addr[0] = lba >> 24;
1636: data.what.position.reladdr.addr[1] = lba >> 16;
1637: data.what.position.reladdr.addr[2] = lba >> 8;
1638: data.what.position.reladdr.addr[3] = lba;
1639: lba = msf2hsg(q.current.absolute_pos, 0);
1640: data.what.position.absaddr.addr[0] = lba >> 24;
1641: data.what.position.absaddr.addr[1] = lba >> 16;
1642: data.what.position.absaddr.addr[2] = lba >> 8;
1643: data.what.position.absaddr.addr[3] = lba;
1644: break;
1645: }
1646: break;
1647: }
1648:
1649: return copyout(&data, ch->data, len);
1650: }
1651:
1652: int
1653: mcd_playtracks(sc, p)
1654: struct mcd_softc *sc;
1655: struct ioc_play_track *p;
1656: {
1657: struct mcd_mbox mbx;
1658: int a = p->start_track;
1659: int z = p->end_track;
1660: int error;
1661:
1662: if (sc->debug)
1663: printf("%s: playtracks: from %d:%d to %d:%d\n",
1664: sc->sc_dev.dv_xname,
1665: a, p->start_index, z, p->end_index);
1666:
1667: if (a < bcd2bin(sc->volinfo.trk_low) ||
1668: a > bcd2bin(sc->volinfo.trk_high) ||
1669: a > z ||
1670: z < bcd2bin(sc->volinfo.trk_low) ||
1671: z > bcd2bin(sc->volinfo.trk_high))
1672: return EINVAL;
1673:
1674: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1675: return error;
1676:
1677: mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1678: mbx.cmd.length = sizeof(mbx.cmd.data.play);
1679: mbx.cmd.data.play.start_msf[0] = sc->toc[a].toc.absolute_pos[0];
1680: mbx.cmd.data.play.start_msf[1] = sc->toc[a].toc.absolute_pos[1];
1681: mbx.cmd.data.play.start_msf[2] = sc->toc[a].toc.absolute_pos[2];
1682: mbx.cmd.data.play.end_msf[0] = sc->toc[z+1].toc.absolute_pos[0];
1683: mbx.cmd.data.play.end_msf[1] = sc->toc[z+1].toc.absolute_pos[1];
1684: mbx.cmd.data.play.end_msf[2] = sc->toc[z+1].toc.absolute_pos[2];
1685: sc->lastpb = mbx.cmd;
1686: mbx.res.length = 0;
1687: return mcd_send(sc, &mbx, 1);
1688: }
1689:
1690: int
1691: mcd_playmsf(sc, p)
1692: struct mcd_softc *sc;
1693: struct ioc_play_msf *p;
1694: {
1695: struct mcd_mbox mbx;
1696: int error;
1697:
1698: if (sc->debug)
1699: printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n",
1700: sc->sc_dev.dv_xname,
1701: p->start_m, p->start_s, p->start_f,
1702: p->end_m, p->end_s, p->end_f);
1703:
1704: if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
1705: (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f))
1706: return EINVAL;
1707:
1708: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1709: return error;
1710:
1711: mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1712: mbx.cmd.length = sizeof(mbx.cmd.data.play);
1713: mbx.cmd.data.play.start_msf[0] = bin2bcd(p->start_m);
1714: mbx.cmd.data.play.start_msf[1] = bin2bcd(p->start_s);
1715: mbx.cmd.data.play.start_msf[2] = bin2bcd(p->start_f);
1716: mbx.cmd.data.play.end_msf[0] = bin2bcd(p->end_m);
1717: mbx.cmd.data.play.end_msf[1] = bin2bcd(p->end_s);
1718: mbx.cmd.data.play.end_msf[2] = bin2bcd(p->end_f);
1719: sc->lastpb = mbx.cmd;
1720: mbx.res.length = 0;
1721: return mcd_send(sc, &mbx, 1);
1722: }
1723:
1724: int
1725: mcd_playblocks(sc, p)
1726: struct mcd_softc *sc;
1727: struct ioc_play_blocks *p;
1728: {
1729: struct mcd_mbox mbx;
1730: int error;
1731:
1732: if (sc->debug)
1733: printf("%s: playblocks: blkno %d length %d\n",
1734: sc->sc_dev.dv_xname, p->blk, p->len);
1735:
1736: if (p->blk > sc->disksize || p->len > sc->disksize ||
1737: (p->blk + p->len) > sc->disksize)
1738: return 0;
1739:
1740: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1741: return error;
1742:
1743: mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
1744: mbx.cmd.length = sizeof(mbx.cmd.data.play);
1745: hsg2msf(p->blk, mbx.cmd.data.play.start_msf);
1746: hsg2msf(p->blk + p->len, mbx.cmd.data.play.end_msf);
1747: sc->lastpb = mbx.cmd;
1748: mbx.res.length = 0;
1749: return mcd_send(sc, &mbx, 1);
1750: }
1751:
1752: int
1753: mcd_pause(sc)
1754: struct mcd_softc *sc;
1755: {
1756: union mcd_qchninfo q;
1757: int error;
1758:
1759: /* Verify current status. */
1760: if (sc->audio_status != CD_AS_PLAY_IN_PROGRESS) {
1761: printf("%s: pause: attempted when not playing\n",
1762: sc->sc_dev.dv_xname);
1763: return EINVAL;
1764: }
1765:
1766: /* Get the current position. */
1767: if ((error = mcd_getqchan(sc, &q, CD_CURRENT_POSITION)) != 0)
1768: return error;
1769:
1770: /* Copy it into lastpb. */
1771: sc->lastpb.data.seek.start_msf[0] = q.current.absolute_pos[0];
1772: sc->lastpb.data.seek.start_msf[1] = q.current.absolute_pos[1];
1773: sc->lastpb.data.seek.start_msf[2] = q.current.absolute_pos[2];
1774:
1775: /* Stop playing. */
1776: if ((error = mcd_stop(sc)) != 0)
1777: return error;
1778:
1779: /* Set the proper status and exit. */
1780: sc->audio_status = CD_AS_PLAY_PAUSED;
1781: return 0;
1782: }
1783:
1784: int
1785: mcd_resume(sc)
1786: struct mcd_softc *sc;
1787: {
1788: struct mcd_mbox mbx;
1789: int error;
1790:
1791: if (sc->audio_status != CD_AS_PLAY_PAUSED)
1792: return EINVAL;
1793:
1794: if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
1795: return error;
1796:
1797: mbx.cmd = sc->lastpb;
1798: mbx.res.length = 0;
1799: return mcd_send(sc, &mbx, 1);
1800: }
1801:
1802: int
1803: mcd_eject(sc)
1804: struct mcd_softc *sc;
1805: {
1806: struct mcd_mbox mbx;
1807:
1808: mbx.cmd.opcode = MCD_CMDEJECTDISK;
1809: mbx.cmd.length = 0;
1810: mbx.res.length = 0;
1811: return mcd_send(sc, &mbx, 0);
1812: }
1813:
1814: int
1815: mcd_setlock(sc, mode)
1816: struct mcd_softc *sc;
1817: int mode;
1818: {
1819: struct mcd_mbox mbx;
1820:
1821: mbx.cmd.opcode = MCD_CMDSETLOCK;
1822: mbx.cmd.length = sizeof(mbx.cmd.data.lockmode);
1823: mbx.cmd.data.lockmode.mode = mode;
1824: mbx.res.length = 0;
1825: return mcd_send(sc, &mbx, 1);
1826: }
CVSweb