Annotation of sys/dev/isa/mcd.c, Revision 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