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