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