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