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