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