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