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