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