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