mcd.c revision 119418
1/* 2 * Copyright 1993 by Holger Veit (data part) 3 * Copyright 1993 by Brian Moore (audio part) 4 * Changes Copyright 1993 by Gary Clark II 5 * Changes Copyright (C) 1994-1995 by Andrey A. Chernov, Moscow, Russia 6 * 7 * Rewrote probe routine to work on newer Mitsumi drives. 8 * Additional changes (C) 1994 by Jordan K. Hubbard 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This software was developed by Holger Veit and Brian Moore 23 * for use with "386BSD" and similar operating systems. 24 * "Similar operating systems" includes mainly non-profit oriented 25 * systems for research and education, including but not restricted to 26 * "NetBSD", "FreeBSD", "Mach" (by CMU). 27 * 4. Neither the name of the developer(s) nor the name "386BSD" 28 * may be used to endorse or promote products derived from this 29 * software without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 32 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 35 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 36 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 37 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 38 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 * 43 */ 44 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/sys/dev/mcd/mcd.c 119418 2003-08-24 17:55:58Z obrien $"); 47static const char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/conf.h> 53#include <sys/fcntl.h> 54#include <sys/bio.h> 55#include <sys/cdio.h> 56#include <sys/disk.h> 57#include <sys/bus.h> 58 59#include <machine/bus_pio.h> 60#include <machine/bus.h> 61#include <machine/resource.h> 62#include <sys/rman.h> 63 64#include <isa/isavar.h> 65 66#include <dev/mcd/mcdreg.h> 67#include <dev/mcd/mcdvar.h> 68 69#define MCD_TRACE(format, args...) \ 70{ \ 71 if (sc->debug) { \ 72 device_printf(sc->dev, "status=0x%02x: ", \ 73 sc->data.status); \ 74 printf(format, ## args); \ 75 } \ 76} 77 78#define RAW_PART 2 79 80/* flags */ 81#define MCDVALID 0x0001 /* parameters loaded */ 82#define MCDINIT 0x0002 /* device is init'd */ 83#define MCDNEWMODEL 0x0004 /* device is new model */ 84#define MCDLABEL 0x0008 /* label is read */ 85#define MCDPROBING 0x0010 /* probing */ 86#define MCDREADRAW 0x0020 /* read raw mode (2352 bytes) */ 87#define MCDVOLINFO 0x0040 /* already read volinfo */ 88#define MCDTOC 0x0080 /* already read toc */ 89#define MCDMBXBSY 0x0100 /* local mbx is busy */ 90 91/* status */ 92#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 93#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 94#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 95#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 96 97/* These are apparently the different states a mitsumi can get up to */ 98#define MCDCDABSENT 0x0030 99#define MCDCDPRESENT 0x0020 100#define MCDSCLOSED 0x0080 101#define MCDSOPEN 0x00a0 102 103#define MCD_MD_UNKNOWN (-1) 104 105#define MCD_TYPE_UNKNOWN 0 106#define MCD_TYPE_LU002S 1 107#define MCD_TYPE_LU005S 2 108#define MCD_TYPE_LU006S 3 109#define MCD_TYPE_FX001 4 110#define MCD_TYPE_FX001D 5 111 112/* reader state machine */ 113#define MCD_S_BEGIN 0 114#define MCD_S_BEGIN1 1 115#define MCD_S_WAITSTAT 2 116#define MCD_S_WAITMODE 3 117#define MCD_S_WAITREAD 4 118 119/* prototypes */ 120static void mcd_start(struct mcd_softc *); 121#ifdef NOTYET 122static void mcd_configure(struct mcd_softc *sc); 123#endif 124static int mcd_get(struct mcd_softc *, char *buf, int nmax); 125static int mcd_setflags(struct mcd_softc *); 126static int mcd_getstat(struct mcd_softc *,int sflg); 127static int mcd_send(struct mcd_softc *, int cmd,int nretrys); 128static void hsg2msf(int hsg, bcd_t *msf); 129static int msf2hsg(bcd_t *msf, int relative); 130static int mcd_volinfo(struct mcd_softc *); 131static int mcd_waitrdy(struct mcd_softc *,int dly); 132static timeout_t mcd_timeout; 133static void mcd_doread(struct mcd_softc *, int state, struct mcd_mbx *mbxin); 134static void mcd_soft_reset(struct mcd_softc *); 135static int mcd_hard_reset(struct mcd_softc *); 136static int mcd_setmode(struct mcd_softc *, int mode); 137static int mcd_getqchan(struct mcd_softc *, struct mcd_qchninfo *q); 138static int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc); 139static int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *th); 140static int mcd_read_toc(struct mcd_softc *); 141static int mcd_toc_entrys(struct mcd_softc *, struct ioc_read_toc_entry *te); 142#if 0 143static int mcd_toc_entry(struct mcd_softc *, struct ioc_read_toc_single_entry *te); 144#endif 145static int mcd_stop(struct mcd_softc *); 146static int mcd_eject(struct mcd_softc *); 147static int mcd_inject(struct mcd_softc *); 148static int mcd_playtracks(struct mcd_softc *, struct ioc_play_track *pt); 149static int mcd_play(struct mcd_softc *, struct mcd_read2 *pb); 150static int mcd_playmsf(struct mcd_softc *, struct ioc_play_msf *pt); 151static int mcd_playblocks(struct mcd_softc *, struct ioc_play_blocks *); 152static int mcd_pause(struct mcd_softc *); 153static int mcd_resume(struct mcd_softc *); 154static int mcd_lock_door(struct mcd_softc *, int lock); 155static int mcd_close_tray(struct mcd_softc *); 156static int mcd_size(dev_t dev); 157 158static d_open_t mcdopen; 159static d_close_t mcdclose; 160static d_ioctl_t mcdioctl; 161static d_strategy_t mcdstrategy; 162 163#define CDEV_MAJOR 29 164 165static struct cdevsw mcd_cdevsw = { 166 .d_open = mcdopen, 167 .d_close = mcdclose, 168 .d_read = physread, 169 .d_ioctl = mcdioctl, 170 .d_strategy = mcdstrategy, 171 .d_name = "mcd", 172 .d_maj = CDEV_MAJOR, 173 .d_flags = D_DISK, 174}; 175 176#define MCD_RETRYS 5 177#define MCD_RDRETRYS 8 178 179#define CLOSE_TRAY_SECS 8 180#define DISK_SENSE_SECS 3 181#define WAIT_FRAC 4 182 183/* several delays */ 184#define RDELAY_WAITSTAT 300 185#define RDELAY_WAITMODE 300 186#define RDELAY_WAITREAD 800 187 188#define MIN_DELAY 15 189#define DELAY_GETREPLY 5000000 190 191int 192mcd_attach(struct mcd_softc *sc) 193{ 194 int unit; 195 196 unit = device_get_unit(sc->dev); 197 198 sc->data.flags |= MCDINIT; 199 mcd_soft_reset(sc); 200 bioq_init(&sc->data.head); 201 202#ifdef NOTYET 203 /* wire controller for interrupts and dma */ 204 mcd_configure(sc); 205#endif 206 /* name filled in probe */ 207 sc->mcd_dev_t = make_dev(&mcd_cdevsw, 8 * unit, 208 UID_ROOT, GID_OPERATOR, 0640, "mcd%d", unit); 209 210 sc->mcd_dev_t->si_drv1 = (void *)sc; 211 212 return (0); 213} 214 215static int 216mcdopen(dev_t dev, int flags, int fmt, struct thread *td) 217{ 218 struct mcd_softc *sc; 219 int r,retry; 220 221 sc = (struct mcd_softc *)dev->si_drv1; 222 223 /* not initialized*/ 224 if (!(sc->data.flags & MCDINIT)) 225 return (ENXIO); 226 227 /* invalidated in the meantime? mark all open part's invalid */ 228 if (!(sc->data.flags & MCDVALID) && sc->data.openflags) 229 return (ENXIO); 230 231 if (mcd_getstat(sc, 1) == -1) 232 return (EIO); 233 234 if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 235 || !(sc->data.status & MCDDSKIN)) 236 for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 237 (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn1", hz/WAIT_FRAC); 238 if ((r = mcd_getstat(sc, 1)) == -1) 239 return (EIO); 240 if (r != -2) 241 break; 242 } 243 244 if (sc->data.status & MCDDOOROPEN) { 245 device_printf(sc->dev, "door is open\n"); 246 return (ENXIO); 247 } 248 if (!(sc->data.status & MCDDSKIN)) { 249 device_printf(sc->dev, "no CD inside\n"); 250 return (ENXIO); 251 } 252 if (sc->data.status & MCDDSKCHNG) { 253 device_printf(sc->dev, "CD not sensed\n"); 254 return (ENXIO); 255 } 256 257 if (mcd_size(dev) < 0) { 258 device_printf(sc->dev, "failed to get disk size\n"); 259 return (ENXIO); 260 } 261 262 dev->si_bsize_phys = sc->data.blksize; 263 264 sc->data.openflags = 1; 265 sc->data.partflags |= MCDREADRAW; 266 sc->data.flags |= MCDVALID; 267 268 (void) mcd_lock_door(sc, MCD_LK_LOCK); 269 if (!(sc->data.flags & MCDVALID)) 270 return (ENXIO); 271 272 return mcd_read_toc(sc); 273} 274 275static int 276mcdclose(dev_t dev, int flags, int fmt, struct thread *td) 277{ 278 struct mcd_softc *sc; 279 280 sc = (struct mcd_softc *)dev->si_drv1; 281 282 if (!(sc->data.flags & MCDINIT) || !sc->data.openflags) 283 return (ENXIO); 284 285 (void) mcd_lock_door(sc, MCD_LK_UNLOCK); 286 sc->data.openflags = 0; 287 sc->data.partflags &= ~MCDREADRAW; 288 289 return (0); 290} 291 292static void 293mcdstrategy(struct bio *bp) 294{ 295 struct mcd_softc *sc; 296 int s; 297 298 sc = (struct mcd_softc *)bp->bio_dev->si_drv1; 299 300 /* test validity */ 301/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 302 bp,unit,bp->bio_blkno,bp->bio_bcount);*/ 303 304 if (bp->bio_blkno < 0) { 305 device_printf(sc->dev, "strategy failure: blkno = %ld, bcount = %ld\n", 306 (long)bp->bio_blkno, bp->bio_bcount); 307 bp->bio_error = EINVAL; 308 bp->bio_flags |= BIO_ERROR; 309 goto bad; 310 } 311 312 /* if device invalidated (e.g. media change, door open), error */ 313 if (!(sc->data.flags & MCDVALID)) { 314 device_printf(sc->dev, "media changed\n"); 315 bp->bio_error = EIO; 316 goto bad; 317 } 318 319 /* read only */ 320 if (!(bp->bio_cmd == BIO_READ)) { 321 bp->bio_error = EROFS; 322 goto bad; 323 } 324 325 /* no data to read */ 326 if (bp->bio_bcount == 0) 327 goto done; 328 329 if (!(sc->data.flags & MCDTOC)) { 330 bp->bio_error = EIO; 331 goto bad; 332 } 333 334 bp->bio_pblkno = bp->bio_blkno; 335 bp->bio_resid = 0; 336 337 /* queue it */ 338 s = splbio(); 339 bioq_disksort(&sc->data.head, bp); 340 splx(s); 341 342 /* now check whether we can perform processing */ 343 mcd_start(sc); 344 return; 345 346bad: 347 bp->bio_flags |= BIO_ERROR; 348done: 349 bp->bio_resid = bp->bio_bcount; 350 biodone(bp); 351 return; 352} 353 354static void 355mcd_start(struct mcd_softc *sc) 356{ 357 struct bio *bp; 358 int s = splbio(); 359 360 if (sc->data.flags & MCDMBXBSY) { 361 splx(s); 362 return; 363 } 364 365 bp = bioq_first(&sc->data.head); 366 if (bp != 0) { 367 /* block found to process, dequeue */ 368 /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 369 bioq_remove(&sc->data.head, bp); 370 sc->data.flags |= MCDMBXBSY; 371 splx(s); 372 } else { 373 /* nothing to do */ 374 splx(s); 375 return; 376 } 377 378 sc->data.mbx.retry = MCD_RETRYS; 379 sc->data.mbx.bp = bp; 380 381 mcd_doread(sc, MCD_S_BEGIN,&(sc->data.mbx)); 382 return; 383} 384 385static int 386mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 387{ 388 struct mcd_softc *sc; 389 int retry,r; 390 391 sc = (struct mcd_softc *)dev->si_drv1; 392 393 if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 394 return (EIO); 395MCD_TRACE("ioctl called 0x%lx\n", cmd); 396 397 switch (cmd) { 398 case CDIOCSETPATCH: 399 case CDIOCGETVOL: 400 case CDIOCSETVOL: 401 case CDIOCSETMONO: 402 case CDIOCSETSTERIO: 403 case CDIOCSETMUTE: 404 case CDIOCSETLEFT: 405 case CDIOCSETRIGHT: 406 return (EINVAL); 407 case CDIOCEJECT: 408 return mcd_eject(sc); 409 case CDIOCSETDEBUG: 410 sc->data.debug = 1; 411 return (0); 412 case CDIOCCLRDEBUG: 413 sc->data.debug = 0; 414 return (0); 415 case CDIOCRESET: 416 return mcd_hard_reset(sc); 417 case CDIOCALLOW: 418 return mcd_lock_door(sc, MCD_LK_UNLOCK); 419 case CDIOCPREVENT: 420 return mcd_lock_door(sc, MCD_LK_LOCK); 421 case CDIOCCLOSE: 422 return mcd_inject(sc); 423 } 424 425 if (!(sc->data.flags & MCDVALID)) { 426 if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 427 || !(sc->data.status & MCDDSKIN)) 428 for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 429 (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC); 430 if ((r = mcd_getstat(sc, 1)) == -1) 431 return (EIO); 432 if (r != -2) 433 break; 434 } 435 if ( (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG)) 436 || !(sc->data.status & MCDDSKIN) 437 || mcd_size(dev) < 0 438 ) 439 return (ENXIO); 440 sc->data.flags |= MCDVALID; 441 sc->data.partflags |= MCDREADRAW; 442 (void) mcd_lock_door(sc, MCD_LK_LOCK); 443 if (!(sc->data.flags & MCDVALID)) 444 return (ENXIO); 445 } 446 447 switch (cmd) { 448 case DIOCGMEDIASIZE: 449 *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; 450 return (0); 451 case DIOCGSECTORSIZE: 452 *(u_int *)addr = sc->data.blksize; 453 return (0); 454 455 case CDIOCPLAYTRACKS: 456 return mcd_playtracks(sc, (struct ioc_play_track *) addr); 457 case CDIOCPLAYBLOCKS: 458 return mcd_playblocks(sc, (struct ioc_play_blocks *) addr); 459 case CDIOCPLAYMSF: 460 return mcd_playmsf(sc, (struct ioc_play_msf *) addr); 461 case CDIOCREADSUBCHANNEL: 462 return mcd_subchan(sc, (struct ioc_read_subchannel *) addr); 463 case CDIOREADTOCHEADER: 464 return mcd_toc_header(sc, (struct ioc_toc_header *) addr); 465 case CDIOREADTOCENTRYS: 466 return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr); 467 case CDIOCRESUME: 468 return mcd_resume(sc); 469 case CDIOCPAUSE: 470 return mcd_pause(sc); 471 case CDIOCSTART: 472 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 473 return (EIO); 474 return (0); 475 case CDIOCSTOP: 476 return mcd_stop(sc); 477 default: 478 return (ENOTTY); 479 } 480 /*NOTREACHED*/ 481} 482 483static int 484mcd_size(dev_t dev) 485{ 486 struct mcd_softc *sc; 487 int size; 488 489 sc = (struct mcd_softc *)dev->si_drv1; 490 491 if (mcd_volinfo(sc) == 0) { 492 sc->data.blksize = MCDBLK; 493 size = msf2hsg(sc->data.volinfo.vol_msf, 0); 494 sc->data.disksize = size * (MCDBLK/DEV_BSIZE); 495 return (0); 496 } 497 return (-1); 498} 499 500/*************************************************************** 501 * lower level of driver starts here 502 **************************************************************/ 503 504#ifdef NOTDEF 505static char 506irqs[] = { 507 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 508 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 509}; 510 511static char 512drqs[] = { 513 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 514}; 515#endif 516 517#ifdef NOT_YET 518static void 519mcd_configure(struct mcd_softc *sc) 520{ 521 MCD_WRITE(sc, MCD_REG_CONFIG, sc->data.config); 522} 523#endif 524 525/* Wait for non-busy - return 0 on timeout */ 526static int 527twiddle_thumbs(struct mcd_softc *sc, int count, char *whine) 528{ 529 int i; 530 531 for (i = 0; i < count; i++) { 532 if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 533 return (1); 534 } 535 if (bootverbose) 536 device_printf(sc->dev, "timeout %s\n", whine); 537 return (0); 538} 539 540/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 541 542int 543mcd_probe(struct mcd_softc *sc) 544{ 545 int i, j; 546 unsigned char stbytes[3]; 547 548 sc->data.flags = MCDPROBING; 549 550#ifdef NOTDEF 551 /* get irq/drq configuration word */ 552 sc->data.config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 553#else 554 sc->data.config = 0; 555#endif 556 557 /* send a reset */ 558 MCD_WRITE(sc, MCD_FLAGS, M_RESET); 559 560 /* 561 * delay awhile by getting any pending garbage (old data) and 562 * throwing it away. 563 */ 564 for (i = 1000000; i != 0; i--) 565 (void)MCD_READ(sc, MCD_FLAGS); 566 567 /* Get status */ 568 MCD_WRITE(sc, MCD_DATA, MCD_CMDGETSTAT); 569 if (!twiddle_thumbs(sc, 1000000, "getting status")) 570 return (ENXIO); /* Timeout */ 571 /* Get version information */ 572 MCD_WRITE(sc, MCD_DATA, MCD_CMDCONTINFO); 573 for (j = 0; j < 3; j++) { 574 if (!twiddle_thumbs(sc, 3000, "getting version info")) 575 return (ENXIO); 576 stbytes[j] = (MCD_READ(sc, MCD_DATA) & 0xFF); 577 } 578 if (stbytes[1] == stbytes[2]) 579 return (ENXIO); 580 if (stbytes[2] >= 4 || stbytes[1] != 'M') { 581 MCD_WRITE(sc, MCD_CTRL, M_PICKLE); 582 sc->data.flags |= MCDNEWMODEL; 583 } 584 sc->data.read_command = MCD_CMDSINGLESPEEDREAD; 585 switch (stbytes[1]) { 586 case 'M': 587 if (stbytes[2] <= 2) { 588 sc->data.type = MCD_TYPE_LU002S; 589 sc->data.name = "Mitsumi LU002S"; 590 } else if (stbytes[2] <= 5) { 591 sc->data.type = MCD_TYPE_LU005S; 592 sc->data.name = "Mitsumi LU005S"; 593 } else { 594 sc->data.type = MCD_TYPE_LU006S; 595 sc->data.name = "Mitsumi LU006S"; 596 } 597 break; 598 case 'F': 599 sc->data.type = MCD_TYPE_FX001; 600 sc->data.name = "Mitsumi FX001"; 601 break; 602 case 'D': 603 sc->data.type = MCD_TYPE_FX001D; 604 sc->data.name = "Mitsumi FX001D"; 605 sc->data.read_command = MCD_CMDDOUBLESPEEDREAD; 606 break; 607 default: 608 sc->data.type = MCD_TYPE_UNKNOWN; 609 sc->data.name = "Mitsumi ???"; 610 break; 611 } 612 613 if (bootverbose) 614 device_printf(sc->dev, "type %s, version info: %c %x\n", 615 sc->data.name, stbytes[1], stbytes[2]); 616 617 return (0); 618} 619 620 621static int 622mcd_waitrdy(struct mcd_softc *sc, int dly) 623{ 624 int i; 625 626 /* wait until flag port senses status ready */ 627 for (i=0; i<dly; i+=MIN_DELAY) { 628 if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 629 return (0); 630 DELAY(MIN_DELAY); 631 } 632 return (-1); 633} 634 635static int 636mcd_getreply(struct mcd_softc *sc, int dly) 637{ 638 639 /* wait data to become ready */ 640 if (mcd_waitrdy(sc, dly)<0) { 641 device_printf(sc->dev, "timeout getreply\n"); 642 return (-1); 643 } 644 645 /* get the data */ 646 return (MCD_READ(sc, MCD_REG_STATUS) & 0xFF); 647} 648 649static int 650mcd_getstat(struct mcd_softc *sc, int sflg) 651{ 652 int i; 653 654 /* get the status */ 655 if (sflg) 656 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 657 i = mcd_getreply(sc, DELAY_GETREPLY); 658 if (i<0 || (i & MCD_ST_CMDCHECK)) { 659 sc->data.curr_mode = MCD_MD_UNKNOWN; 660 return (-1); 661 } 662 663 sc->data.status = i; 664 665 if (mcd_setflags(sc) < 0) 666 return (-2); 667 return (sc->data.status); 668} 669 670static int 671mcd_setflags(struct mcd_softc *sc) 672{ 673 674 /* check flags */ 675 if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 676 || !(sc->data.status & MCDDSKIN)) { 677 MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n"); 678 mcd_soft_reset(sc); 679 return (-1); 680 } 681 682 if (sc->data.status & MCDAUDIOBSY) 683 sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 684 else if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 685 sc->data.audio_status = CD_AS_PLAY_COMPLETED; 686 return (0); 687} 688 689static int 690mcd_get(struct mcd_softc *sc, char *buf, int nmax) 691{ 692 int i,k; 693 694 for (i=0; i<nmax; i++) { 695 /* wait for data */ 696 if ((k = mcd_getreply(sc, DELAY_GETREPLY)) < 0) { 697 device_printf(sc->dev, "timeout mcd_get\n"); 698 return (-1); 699 } 700 buf[i] = k; 701 } 702 return (i); 703} 704 705static int 706mcd_send(struct mcd_softc *sc, int cmd,int nretrys) 707{ 708 int i,k=0; 709 710/*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/ 711 for (i=0; i<nretrys; i++) { 712 MCD_WRITE(sc, MCD_REG_COMMAND, cmd); 713 if ((k=mcd_getstat(sc, 0)) != -1) 714 break; 715 } 716 if (k == -2) { 717 device_printf(sc->dev, "media changed\n"); 718 return (-1); 719 } 720 if (i == nretrys) { 721 device_printf(sc->dev, "mcd_send retry cnt exceeded\n"); 722 return (-1); 723 } 724/*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/ 725 return (0); 726} 727 728static void 729hsg2msf(int hsg, bcd_t *msf) 730{ 731 hsg += 150; 732 F_msf(msf) = bin2bcd(hsg % 75); 733 hsg /= 75; 734 S_msf(msf) = bin2bcd(hsg % 60); 735 hsg /= 60; 736 M_msf(msf) = bin2bcd(hsg); 737} 738 739static int 740msf2hsg(bcd_t *msf, int relative) 741{ 742 return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 + 743 bcd2bin(F_msf(msf)) - (!relative) * 150; 744} 745 746static int 747mcd_volinfo(struct mcd_softc *sc) 748{ 749 750 /* Just return if we already have it */ 751 if (sc->data.flags & MCDVOLINFO) return (0); 752 753/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 754 755 /* send volume info command */ 756 if (mcd_send(sc, MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 757 return (EIO); 758 759 /* get data */ 760 if (mcd_get(sc, (char*) &sc->data.volinfo,sizeof(struct mcd_volinfo)) < 0) { 761 device_printf(sc->dev, "mcd_volinfo: error read data\n"); 762 return (EIO); 763 } 764 765 if (sc->data.volinfo.trk_low > 0 && 766 sc->data.volinfo.trk_high >= sc->data.volinfo.trk_low 767 ) { 768 sc->data.flags |= MCDVOLINFO; /* volinfo is OK */ 769 return (0); 770 } 771 772 return (EINVAL); 773} 774 775/* state machine to process read requests 776 * initialize with MCD_S_BEGIN: calculate sizes, and read status 777 * MCD_S_WAITSTAT: wait for status reply, set mode 778 * MCD_S_WAITMODE: waits for status reply from set mode, set read command 779 * MCD_S_WAITREAD: wait for read ready, read data 780 */ 781static void 782mcd_timeout(void *arg) 783{ 784 struct mcd_softc *sc; 785 786 sc = (struct mcd_softc *)arg; 787 788 mcd_doread(sc, sc->ch_state, sc->ch_mbxsave); 789} 790 791static void 792mcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin) 793{ 794 struct mcd_mbx *mbx; 795 struct bio *bp; 796 int rm, i, k; 797 struct mcd_read2 rbuf; 798 int blknum; 799 caddr_t addr; 800 801 mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; 802 bp = mbx->bp; 803 804loop: 805 switch (state) { 806 case MCD_S_BEGIN: 807 mbx = sc->ch_mbxsave = mbxin; 808 809 case MCD_S_BEGIN1: 810retry_status: 811 /* get status */ 812 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 813 mbx->count = RDELAY_WAITSTAT; 814 sc->ch_state = MCD_S_WAITSTAT; 815 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 816 return; 817 case MCD_S_WAITSTAT: 818 sc->ch_state = MCD_S_WAITSTAT; 819 untimeout(mcd_timeout,(caddr_t)sc, sc->ch); 820 if (mbx->count-- >= 0) { 821 if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 822 sc->ch_state = MCD_S_WAITSTAT; 823 timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 824 return; 825 } 826 sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 827 if (sc->data.status & MCD_ST_CMDCHECK) 828 goto retry_status; 829 if (mcd_setflags(sc) < 0) 830 goto changed; 831 MCD_TRACE("got WAITSTAT delay=%d\n", 832 RDELAY_WAITSTAT-mbx->count); 833 /* reject, if audio active */ 834 if (sc->data.status & MCDAUDIOBSY) { 835 device_printf(sc->dev, "audio is active\n"); 836 goto readerr; 837 } 838 839retry_mode: 840 /* to check for raw/cooked mode */ 841 if (sc->data.flags & MCDREADRAW) { 842 rm = MCD_MD_RAW; 843 mbx->sz = MCDRBLK; 844 } else { 845 rm = MCD_MD_COOKED; 846 mbx->sz = sc->data.blksize; 847 } 848 849 if (rm == sc->data.curr_mode) 850 goto modedone; 851 852 mbx->count = RDELAY_WAITMODE; 853 854 sc->data.curr_mode = MCD_MD_UNKNOWN; 855 mbx->mode = rm; 856 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 857 MCD_WRITE(sc, MCD_REG_COMMAND, rm); 858 859 sc->ch_state = MCD_S_WAITMODE; 860 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 861 return; 862 } else { 863 device_printf(sc->dev, "timeout getstatus\n"); 864 goto readerr; 865 } 866 867 case MCD_S_WAITMODE: 868 sc->ch_state = MCD_S_WAITMODE; 869 untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 870 if (mbx->count-- < 0) { 871 device_printf(sc->dev, "timeout set mode\n"); 872 goto readerr; 873 } 874 if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 875 sc->ch_state = MCD_S_WAITMODE; 876 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); 877 return; 878 } 879 sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 880 if (sc->data.status & MCD_ST_CMDCHECK) { 881 sc->data.curr_mode = MCD_MD_UNKNOWN; 882 goto retry_mode; 883 } 884 if (mcd_setflags(sc) < 0) 885 goto changed; 886 sc->data.curr_mode = mbx->mode; 887 MCD_TRACE("got WAITMODE delay=%d\n", 888 RDELAY_WAITMODE-mbx->count); 889modedone: 890 /* for first block */ 891 mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; 892 mbx->skip = 0; 893 894nextblock: 895 blknum = (bp->bio_blkno / (mbx->sz/DEV_BSIZE)) 896 + mbx->skip/mbx->sz; 897 898 MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n", 899 blknum, bp); 900 901 /* build parameter block */ 902 hsg2msf(blknum,rbuf.start_msf); 903retry_read: 904 /* send the read command */ 905 critical_enter(); 906 MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command); 907 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]); 908 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]); 909 MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]); 910 MCD_WRITE(sc, MCD_REG_COMMAND, 0); 911 MCD_WRITE(sc, MCD_REG_COMMAND, 0); 912 MCD_WRITE(sc, MCD_REG_COMMAND, 1); 913 critical_exit(); 914 915 /* Spin briefly (<= 2ms) to avoid missing next block */ 916 for (i = 0; i < 20; i++) { 917 k = MCD_READ(sc, MCD_FLAGS); 918 if (!(k & MFL_DATA_NOT_AVAIL)) 919 goto got_it; 920 DELAY(100); 921 } 922 923 mbx->count = RDELAY_WAITREAD; 924 sc->ch_state = MCD_S_WAITREAD; 925 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 926 return; 927 case MCD_S_WAITREAD: 928 sc->ch_state = MCD_S_WAITREAD; 929 untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 930 if (mbx->count-- > 0) { 931 k = MCD_READ(sc, MCD_FLAGS); 932 if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */ 933 MCD_TRACE("got data delay=%d\n", 934 RDELAY_WAITREAD-mbx->count); 935 got_it: 936 /* data is ready */ 937 addr = bp->bio_data + mbx->skip; 938 939 MCD_WRITE(sc, MCD_REG_CTL2,0x04); /* XXX */ 940 for (i=0; i<mbx->sz; i++) 941 *addr++ = MCD_READ(sc, MCD_REG_RDATA); 942 MCD_WRITE(sc, MCD_REG_CTL2,0x0c); /* XXX */ 943 944 k = MCD_READ(sc, MCD_FLAGS); 945 /* If we still have some junk, read it too */ 946 if (!(k & MFL_DATA_NOT_AVAIL)) { 947 MCD_WRITE(sc, MCD_REG_CTL2, 0x04); /* XXX */ 948 (void)MCD_READ(sc, MCD_REG_RDATA); 949 (void)MCD_READ(sc, MCD_REG_RDATA); 950 MCD_WRITE(sc, MCD_REG_CTL2, 0x0c); /* XXX */ 951 } 952 953 if (--mbx->nblk > 0) { 954 mbx->skip += mbx->sz; 955 goto nextblock; 956 } 957 958 /* return buffer */ 959 bp->bio_resid = 0; 960 biodone(bp); 961 962 sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 963 mcd_start(sc); 964 return; 965 } 966 if (!(k & MFL_STATUS_NOT_AVAIL)) { 967 sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 968 if (sc->data.status & MCD_ST_CMDCHECK) 969 goto retry_read; 970 if (mcd_setflags(sc) < 0) 971 goto changed; 972 } 973 sc->ch_state = MCD_S_WAITREAD; 974 sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 975 return; 976 } else { 977 device_printf(sc->dev, "timeout read data\n"); 978 goto readerr; 979 } 980 } 981 982readerr: 983 if (mbx->retry-- > 0) { 984 device_printf(sc->dev, "retrying\n"); 985 state = MCD_S_BEGIN1; 986 goto loop; 987 } 988harderr: 989 /* invalidate the buffer */ 990 bp->bio_flags |= BIO_ERROR; 991 bp->bio_resid = bp->bio_bcount; 992 biodone(bp); 993 994 sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 995 mcd_start(sc); 996 return; 997 998changed: 999 device_printf(sc->dev, "media changed\n"); 1000 goto harderr; 1001 1002#ifdef NOTDEF 1003 device_printf(sc->dev, "unit timeout, resetting\n"); 1004 MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 1005 DELAY(300000); 1006 (void)mcd_getstat(sc, 1); 1007 (void)mcd_getstat(sc, 1); 1008 /*sc->data.status &= ~MCDDSKCHNG; */ 1009 sc->data.debug = 1; /* preventive set debug mode */ 1010 1011#endif 1012 1013} 1014 1015static int 1016mcd_lock_door(struct mcd_softc *sc, int lock) 1017{ 1018 1019 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDLOCKDRV); 1020 MCD_WRITE(sc, MCD_REG_COMMAND, lock); 1021 if (mcd_getstat(sc, 0) == -1) 1022 return (EIO); 1023 return (0); 1024} 1025 1026static int 1027mcd_close_tray(struct mcd_softc *sc) 1028{ 1029 int retry, r; 1030 1031 if (mcd_getstat(sc, 1) == -1) 1032 return (EIO); 1033 if (sc->data.status & MCDDOOROPEN) { 1034 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDCLOSETRAY); 1035 for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) { 1036 if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) 1037 (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC); 1038 else { 1039 if ((r = mcd_getstat(sc, 0)) == -1) 1040 return (EIO); 1041 return (0); 1042 } 1043 } 1044 return (ENXIO); 1045 } 1046 return (0); 1047} 1048 1049static int 1050mcd_eject(struct mcd_softc *sc) 1051{ 1052 int r; 1053 1054 if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1055 return (EIO); 1056 if (sc->data.status & MCDDOOROPEN) 1057 return (0); 1058 if ((r = mcd_stop(sc)) == EIO) 1059 return (r); 1060 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDEJECTDISK); 1061 if (mcd_getstat(sc, 0) == -1) 1062 return (EIO); 1063 return (0); 1064} 1065 1066static int 1067mcd_inject(struct mcd_softc *sc) 1068{ 1069 1070 if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1071 return (EIO); 1072 if (sc->data.status & MCDDOOROPEN) 1073 return mcd_close_tray(sc); 1074 return (0); 1075} 1076 1077static int 1078mcd_hard_reset(struct mcd_softc *sc) 1079{ 1080 1081 MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 1082 sc->data.curr_mode = MCD_MD_UNKNOWN; 1083 sc->data.audio_status = CD_AS_AUDIO_INVALID; 1084 return (0); 1085} 1086 1087static void 1088mcd_soft_reset(struct mcd_softc *sc) 1089{ 1090 1091 sc->data.flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL); 1092 sc->data.curr_mode = MCD_MD_UNKNOWN; 1093 sc->data.partflags = 0; 1094 sc->data.audio_status = CD_AS_AUDIO_INVALID; 1095} 1096 1097static int 1098mcd_setmode(struct mcd_softc *sc, int mode) 1099{ 1100 int retry, st; 1101 1102 if (sc->data.curr_mode == mode) 1103 return (0); 1104 if (sc->data.debug) 1105 device_printf(sc->dev, "setting mode to %d\n", mode); 1106 for(retry=0; retry<MCD_RETRYS; retry++) 1107 { 1108 sc->data.curr_mode = MCD_MD_UNKNOWN; 1109 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 1110 MCD_WRITE(sc, MCD_REG_COMMAND, mode); 1111 if ((st = mcd_getstat(sc, 0)) >= 0) { 1112 sc->data.curr_mode = mode; 1113 return (0); 1114 } 1115 if (st == -2) { 1116 device_printf(sc->dev, "media changed\n"); 1117 break; 1118 } 1119 } 1120 1121 return (-1); 1122} 1123 1124static int 1125mcd_toc_header(struct mcd_softc *sc, struct ioc_toc_header *th) 1126{ 1127 int r; 1128 1129 if ((r = mcd_volinfo(sc)) != 0) 1130 return (r); 1131 1132 th->starting_track = bcd2bin(sc->data.volinfo.trk_low); 1133 th->ending_track = bcd2bin(sc->data.volinfo.trk_high); 1134 th->len = 2 * sizeof(u_char) /* start & end tracks */ + 1135 (th->ending_track + 1 - th->starting_track + 1) * 1136 sizeof(struct cd_toc_entry); 1137 1138 return (0); 1139} 1140 1141static int 1142mcd_read_toc(struct mcd_softc *sc) 1143{ 1144 struct ioc_toc_header th; 1145 struct mcd_qchninfo q; 1146 int rc, trk, idx, retry; 1147 1148 /* Only read TOC if needed */ 1149 if (sc->data.flags & MCDTOC) 1150 return (0); 1151 1152 if (sc->data.debug) 1153 device_printf(sc->dev, "reading toc header\n"); 1154 1155 if ((rc = mcd_toc_header(sc, &th)) != 0) 1156 return (rc); 1157 1158 if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1159 return (EIO); 1160 1161 if (mcd_setmode(sc, MCD_MD_TOC) != 0) 1162 return (EIO); 1163 1164 if (sc->data.debug) 1165 device_printf(sc->dev, "get_toc reading qchannel info\n"); 1166 1167 for(trk=th.starting_track; trk<=th.ending_track; trk++) 1168 sc->data.toc[trk].idx_no = 0; 1169 trk = th.ending_track - th.starting_track + 1; 1170 for(retry=0; retry<600 && trk>0; retry++) 1171 { 1172 if (mcd_getqchan(sc, &q) < 0) break; 1173 idx = bcd2bin(q.idx_no); 1174 if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) { 1175 if (sc->data.toc[idx].idx_no == 0) { 1176 sc->data.toc[idx] = q; 1177 trk--; 1178 } 1179 } 1180 } 1181 1182 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1183 return (EIO); 1184 1185 if (trk != 0) 1186 return (ENXIO); 1187 1188 /* add a fake last+1 */ 1189 idx = th.ending_track + 1; 1190 sc->data.toc[idx].control = sc->data.toc[idx-1].control; 1191 sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type; 1192 sc->data.toc[idx].trk_no = 0; 1193 sc->data.toc[idx].idx_no = MCD_LASTPLUS1; 1194 sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0]; 1195 sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1]; 1196 sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2]; 1197 1198 if (sc->data.debug) 1199 { int i; 1200 for (i = th.starting_track; i <= idx; i++) 1201 device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n", 1202 i, 1203 sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no : 1204 bcd2bin(sc->data.toc[i].idx_no), 1205 bcd2bin(sc->data.toc[i].hd_pos_msf[0]), 1206 bcd2bin(sc->data.toc[i].hd_pos_msf[1]), 1207 bcd2bin(sc->data.toc[i].hd_pos_msf[2])); 1208 } 1209 1210 sc->data.flags |= MCDTOC; 1211 1212 return (0); 1213} 1214 1215#if 0 1216static int 1217mcd_toc_entry(struct mcd_softc *sc, struct ioc_read_toc_single_entry *te) 1218{ 1219 struct ioc_toc_header th; 1220 int rc, trk; 1221 1222 if (te->address_format != CD_MSF_FORMAT 1223 && te->address_format != CD_LBA_FORMAT) 1224 return (EINVAL); 1225 1226 /* Copy the toc header */ 1227 if ((rc = mcd_toc_header(sc, &th)) != 0) 1228 return (rc); 1229 1230 /* verify starting track */ 1231 trk = te->track; 1232 if (trk == 0) 1233 trk = th.starting_track; 1234 else if (trk == MCD_LASTPLUS1) 1235 trk = th.ending_track + 1; 1236 else if (trk < th.starting_track || trk > th.ending_track + 1) 1237 return (EINVAL); 1238 1239 /* Make sure we have a valid toc */ 1240 if ((rc=mcd_read_toc(sc)) != 0) 1241 return (rc); 1242 1243 /* Copy the TOC data. */ 1244 if (sc->data.toc[trk].idx_no == 0) 1245 return (EIO); 1246 1247 te->entry.control = sc->data.toc[trk].control; 1248 te->entry.addr_type = sc->data.toc[trk].addr_type; 1249 te->entry.track = 1250 sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1251 bcd2bin(sc->data.toc[trk].idx_no); 1252 switch (te->address_format) { 1253 case CD_MSF_FORMAT: 1254 te->entry.addr.msf.unused = 0; 1255 te->entry.addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1256 te->entry.addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1257 te->entry.addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 1258 break; 1259 case CD_LBA_FORMAT: 1260 te->entry.addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 1261 break; 1262 } 1263 return (0); 1264} 1265#endif 1266 1267static int 1268mcd_toc_entrys(struct mcd_softc *sc, struct ioc_read_toc_entry *te) 1269{ 1270 struct cd_toc_entry entries[MCD_MAXTOCS]; 1271 struct ioc_toc_header th; 1272 int rc, n, trk, len; 1273 1274 if ( te->data_len < sizeof(entries[0]) 1275 || (te->data_len % sizeof(entries[0])) != 0 1276 || (te->address_format != CD_MSF_FORMAT 1277 && te->address_format != CD_LBA_FORMAT) 1278 ) 1279 return (EINVAL); 1280 1281 /* Copy the toc header */ 1282 if ((rc = mcd_toc_header(sc, &th)) != 0) 1283 return (rc); 1284 1285 /* verify starting track */ 1286 trk = te->starting_track; 1287 if (trk == 0) 1288 trk = th.starting_track; 1289 else if (trk == MCD_LASTPLUS1) 1290 trk = th.ending_track + 1; 1291 else if (trk < th.starting_track || trk > th.ending_track + 1) 1292 return (EINVAL); 1293 1294 len = ((th.ending_track + 1 - trk) + 1) * 1295 sizeof(entries[0]); 1296 if (te->data_len < len) 1297 len = te->data_len; 1298 if (len > sizeof(entries)) 1299 return (EINVAL); 1300 1301 /* Make sure we have a valid toc */ 1302 if ((rc=mcd_read_toc(sc)) != 0) 1303 return (rc); 1304 1305 /* Copy the TOC data. */ 1306 for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) { 1307 if (sc->data.toc[trk].idx_no == 0) 1308 continue; 1309 entries[n].control = sc->data.toc[trk].control; 1310 entries[n].addr_type = sc->data.toc[trk].addr_type; 1311 entries[n].track = 1312 sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1313 bcd2bin(sc->data.toc[trk].idx_no); 1314 switch (te->address_format) { 1315 case CD_MSF_FORMAT: 1316 entries[n].addr.msf.unused = 0; 1317 entries[n].addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1318 entries[n].addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1319 entries[n].addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 1320 break; 1321 case CD_LBA_FORMAT: 1322 entries[n].addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 1323 break; 1324 } 1325 len -= sizeof(struct cd_toc_entry); 1326 n++; 1327 } 1328 1329 /* copy the data back */ 1330 return copyout(entries, te->data, n * sizeof(struct cd_toc_entry)); 1331} 1332 1333static int 1334mcd_stop(struct mcd_softc *sc) 1335{ 1336 1337 /* Verify current status */ 1338 if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1339 sc->data.audio_status != CD_AS_PLAY_PAUSED && 1340 sc->data.audio_status != CD_AS_PLAY_COMPLETED) { 1341 if (sc->data.debug) 1342 device_printf(sc->dev, 1343 "stop attempted when not playing, audio status %d\n", 1344 sc->data.audio_status); 1345 return (EINVAL); 1346 } 1347 if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 1348 if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1349 return (EIO); 1350 sc->data.audio_status = CD_AS_PLAY_COMPLETED; 1351 return (0); 1352} 1353 1354static int 1355mcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q) 1356{ 1357 1358 if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1359 return (-1); 1360 if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1361 return (-1); 1362 if (sc->data.debug) { 1363 device_printf(sc->dev, 1364 "getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n", 1365 q->control, q->addr_type, 1366 bcd2bin(q->trk_no), 1367 bcd2bin(q->idx_no), 1368 bcd2bin(q->trk_size_msf[0]), 1369 bcd2bin(q->trk_size_msf[1]), 1370 bcd2bin(q->trk_size_msf[2]), 1371 bcd2bin(q->hd_pos_msf[0]), 1372 bcd2bin(q->hd_pos_msf[1]), 1373 bcd2bin(q->hd_pos_msf[2])); 1374 } 1375 return (0); 1376} 1377 1378static int 1379mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch) 1380{ 1381 struct mcd_qchninfo q; 1382 struct cd_sub_channel_info data; 1383 int lba; 1384 1385 if (sc->data.debug) 1386 device_printf(sc->dev, "subchan af=%d, df=%d\n", 1387 sch->address_format, 1388 sch->data_format); 1389 1390 if (sch->address_format != CD_MSF_FORMAT && 1391 sch->address_format != CD_LBA_FORMAT) 1392 return (EINVAL); 1393 1394 if (sch->data_format != CD_CURRENT_POSITION && 1395 sch->data_format != CD_MEDIA_CATALOG) 1396 return (EINVAL); 1397 1398 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1399 return (EIO); 1400 1401 if (mcd_getqchan(sc, &q) < 0) 1402 return (EIO); 1403 1404 data.header.audio_status = sc->data.audio_status; 1405 data.what.position.data_format = sch->data_format; 1406 1407 switch (sch->data_format) { 1408 case CD_MEDIA_CATALOG: 1409 data.what.media_catalog.mc_valid = 1; 1410 data.what.media_catalog.mc_number[0] = '\0'; 1411 break; 1412 1413 case CD_CURRENT_POSITION: 1414 data.what.position.control = q.control; 1415 data.what.position.addr_type = q.addr_type; 1416 data.what.position.track_number = bcd2bin(q.trk_no); 1417 data.what.position.index_number = bcd2bin(q.idx_no); 1418 switch (sch->address_format) { 1419 case CD_MSF_FORMAT: 1420 data.what.position.reladdr.msf.unused = 0; 1421 data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]); 1422 data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]); 1423 data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]); 1424 data.what.position.absaddr.msf.unused = 0; 1425 data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]); 1426 data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]); 1427 data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]); 1428 break; 1429 case CD_LBA_FORMAT: 1430 lba = msf2hsg(q.trk_size_msf, 1); 1431 /* 1432 * Pre-gap has index number of 0, and decreasing MSF 1433 * address. Must be converted to negative LBA, per 1434 * SCSI spec. 1435 */ 1436 if (data.what.position.index_number == 0) 1437 lba = -lba; 1438 data.what.position.reladdr.lba = htonl(lba); 1439 data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0)); 1440 break; 1441 } 1442 break; 1443 } 1444 1445 return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 1446} 1447 1448static int 1449mcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p) 1450{ 1451 struct mcd_read2 pb; 1452 1453 if (sc->data.debug) 1454 device_printf(sc->dev, "playmsf: from %d:%d.%d to %d:%d.%d\n", 1455 p->start_m, p->start_s, p->start_f, 1456 p->end_m, p->end_s, p->end_f); 1457 1458 if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >= 1459 (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) || 1460 (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) > 1461 M_msf(sc->data.volinfo.vol_msf) * 60 * 75 + 1462 S_msf(sc->data.volinfo.vol_msf) * 75 + 1463 F_msf(sc->data.volinfo.vol_msf)) 1464 return (EINVAL); 1465 1466 pb.start_msf[0] = bin2bcd(p->start_m); 1467 pb.start_msf[1] = bin2bcd(p->start_s); 1468 pb.start_msf[2] = bin2bcd(p->start_f); 1469 pb.end_msf[0] = bin2bcd(p->end_m); 1470 pb.end_msf[1] = bin2bcd(p->end_s); 1471 pb.end_msf[2] = bin2bcd(p->end_f); 1472 1473 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1474 return (EIO); 1475 1476 return mcd_play(sc, &pb); 1477} 1478 1479static int 1480mcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *pt) 1481{ 1482 struct mcd_read2 pb; 1483 int a = pt->start_track; 1484 int z = pt->end_track; 1485 int rc, i; 1486 1487 if ((rc = mcd_read_toc(sc)) != 0) 1488 return (rc); 1489 1490 if (sc->data.debug) 1491 device_printf(sc->dev, "playtracks from %d:%d to %d:%d\n", 1492 a, pt->start_index, z, pt->end_index); 1493 1494 if ( a < bcd2bin(sc->data.volinfo.trk_low) 1495 || a > bcd2bin(sc->data.volinfo.trk_high) 1496 || a > z 1497 || z < bcd2bin(sc->data.volinfo.trk_low) 1498 || z > bcd2bin(sc->data.volinfo.trk_high)) 1499 return (EINVAL); 1500 1501 for (i = 0; i < 3; i++) { 1502 pb.start_msf[i] = sc->data.toc[a].hd_pos_msf[i]; 1503 pb.end_msf[i] = sc->data.toc[z+1].hd_pos_msf[i]; 1504 } 1505 1506 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1507 return (EIO); 1508 1509 return mcd_play(sc, &pb); 1510} 1511 1512static int 1513mcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p) 1514{ 1515 struct mcd_read2 pb; 1516 1517 if (sc->data.debug) 1518 device_printf(sc->dev, "playblocks: blkno %d length %d\n", 1519 p->blk, p->len); 1520 1521 if (p->blk > sc->data.disksize || p->len > sc->data.disksize || 1522 p->blk < 0 || p->len < 0 || 1523 (p->blk + p->len) > sc->data.disksize) 1524 return (EINVAL); 1525 1526 hsg2msf(p->blk, pb.start_msf); 1527 hsg2msf(p->blk + p->len, pb.end_msf); 1528 1529 if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1530 return (EIO); 1531 1532 return mcd_play(sc, &pb); 1533} 1534 1535static int 1536mcd_play(struct mcd_softc *sc, struct mcd_read2 *pb) 1537{ 1538 int retry, st = -1, status; 1539 1540 sc->data.lastpb = *pb; 1541 for(retry=0; retry<MCD_RETRYS; retry++) { 1542 1543 critical_enter(); 1544 MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSINGLESPEEDREAD); 1545 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[0]); 1546 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[1]); 1547 MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[2]); 1548 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[0]); 1549 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[1]); 1550 MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[2]); 1551 critical_exit(); 1552 1553 status=mcd_getstat(sc, 0); 1554 if (status == -1) 1555 continue; 1556 else if (status != -2) 1557 st = 0; 1558 break; 1559 } 1560 1561 if (status == -2) { 1562 device_printf(sc->dev, "media changed\n"); 1563 return (ENXIO); 1564 } 1565 if (sc->data.debug) 1566 device_printf(sc->dev, 1567 "mcd_play retry=%d, status=0x%02x\n", retry, status); 1568 if (st < 0) 1569 return (ENXIO); 1570 sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 1571 return (0); 1572} 1573 1574static int 1575mcd_pause(struct mcd_softc *sc) 1576{ 1577 struct mcd_qchninfo q; 1578 int rc; 1579 1580 /* Verify current status */ 1581 if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1582 sc->data.audio_status != CD_AS_PLAY_PAUSED) { 1583 if (sc->data.debug) 1584 device_printf(sc->dev, 1585 "pause attempted when not playing, audio status %d\n", 1586 sc->data.audio_status); 1587 return (EINVAL); 1588 } 1589 1590 /* Get the current position */ 1591 if (mcd_getqchan(sc, &q) < 0) 1592 return (EIO); 1593 1594 /* Copy it into lastpb */ 1595 sc->data.lastpb.start_msf[0] = q.hd_pos_msf[0]; 1596 sc->data.lastpb.start_msf[1] = q.hd_pos_msf[1]; 1597 sc->data.lastpb.start_msf[2] = q.hd_pos_msf[2]; 1598 1599 /* Stop playing */ 1600 if ((rc=mcd_stop(sc)) != 0) 1601 return (rc); 1602 1603 /* Set the proper status and exit */ 1604 sc->data.audio_status = CD_AS_PLAY_PAUSED; 1605 return (0); 1606} 1607 1608static int 1609mcd_resume(struct mcd_softc *sc) 1610{ 1611 1612 if (sc->data.audio_status != CD_AS_PLAY_PAUSED) 1613 return (EINVAL); 1614 return mcd_play(sc, &sc->data.lastpb); 1615} 1616