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