1 /* 2 * Copyright 1993 by Holger Veit (data part) 3 * Copyright 1993 by Brian Moore (audio part) 4 * CHANGES Copyright 1993 Gary Clark II (gclarkii@freefall.cdrom.com) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This software was developed by Holger Veit and Brian Moore 18 * for use with "386BSD" and similar operating systems. 19 * "Similar operating systems" includes mainly non-profit oriented 20 * systems for research and education, including but not restricted to 21 * "NetBSD", "FreeBSD", "Mach" (by CMU). 22 * 4. Neither the name of the developer(s) nor the name "386BSD" 23 * may be used to endorse or promote products derived from this 24 * software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 * $Id: mcd.c,v 1.2 1993/11/17 12:22:50 cgd Exp $ 39 */ 40 41 static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 42 43 #include "mcd.h" 44 #if NMCD > 0 45 #include "types.h" 46 #include "param.h" 47 #include "systm.h" 48 #include "conf.h" 49 #include "file.h" 50 #include "buf.h" 51 #include "stat.h" 52 #include "uio.h" 53 #include "ioctl.h" 54 #include "cdio.h" 55 #include "errno.h" 56 #include "dkbad.h" 57 #include "disklabel.h" 58 #include "i386/isa/isa.h" 59 #include "i386/isa/isa_device.h" 60 #include "mcdreg.h" 61 62 /* user definable options */ 63 /*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ 64 /*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ 65 66 67 #ifdef MCDMINI 68 #define MCD_TRACE(fmt,a,b,c,d) 69 #ifdef MCD_TO_WARNING_ON 70 #undef MCD_TO_WARNING_ON 71 #endif 72 #else 73 #define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d st=%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}} 74 #endif 75 76 #define mcd_part(dev) ((minor(dev)) & 7) 77 #define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) 78 #define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) 79 #define RAW_PART 3 80 81 /* flags */ 82 #define MCDOPEN 0x0001 /* device opened */ 83 #define MCDVALID 0x0002 /* parameters loaded */ 84 #define MCDINIT 0x0004 /* device is init'd */ 85 #define MCDWAIT 0x0008 /* waiting for something */ 86 #define MCDLABEL 0x0010 /* label is read */ 87 #define MCDPROBING 0x0020 /* probing */ 88 #define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ 89 #define MCDVOLINFO 0x0080 /* already read volinfo */ 90 #define MCDTOC 0x0100 /* already read toc */ 91 #define MCDMBXBSY 0x0200 /* local mbx is busy */ 92 93 /* status */ 94 #define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 95 #define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 96 #define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 97 #define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 98 99 /* toc */ 100 #define MCD_MAXTOCS 104 /* from the Linux driver */ 101 #define MCD_LASTPLUS1 170 /* special toc entry */ 102 103 struct mcd_mbx { 104 short unit; 105 short port; 106 short retry; 107 short nblk; 108 int sz; 109 u_long skip; 110 struct buf *bp; 111 int p_offset; 112 short count; 113 }; 114 115 struct mcd_data { 116 short config; 117 short flags; 118 short status; 119 int blksize; 120 u_long disksize; 121 int iobase; 122 struct disklabel dlabel; 123 int partflags[MAXPARTITIONS]; 124 int openflags; 125 struct mcd_volinfo volinfo; 126 #ifndef MCDMINI 127 struct mcd_qchninfo toc[MCD_MAXTOCS]; 128 short audio_status; 129 struct mcd_read2 lastpb; 130 #endif 131 short debug; 132 struct buf head; /* head of buf queue */ 133 struct mcd_mbx mbx; 134 } mcd_data[NMCD]; 135 136 /* reader state machine */ 137 #define MCD_S_BEGIN 0 138 #define MCD_S_BEGIN1 1 139 #define MCD_S_WAITSTAT 2 140 #define MCD_S_WAITMODE 3 141 #define MCD_S_WAITREAD 4 142 143 /* prototypes */ 144 int mcdopen(dev_t dev); 145 int mcdclose(dev_t dev); 146 int mcdstrategy(struct buf *bp); 147 int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 148 int mcdsize(dev_t dev); 149 static void mcd_done(struct mcd_mbx *mbx); 150 static void mcd_start(int unit); 151 static int mcd_getdisklabel(int unit); 152 static void mcd_configure(struct mcd_data *cd); 153 static int mcd_get(int unit, char *buf, int nmax); 154 static void mcd_setflags(int unit,struct mcd_data *cd); 155 static int mcd_getstat(int unit,int sflg); 156 static int mcd_send(int unit, int cmd,int nretrys); 157 static int bcd2bin(bcd_t b); 158 static bcd_t bin2bcd(int b); 159 static void hsg2msf(int hsg, bcd_t *msf); 160 static int msf2hsg(bcd_t *msf); 161 static int mcd_volinfo(int unit); 162 static int mcd_waitrdy(int port,int dly); 163 static void mcd_doread(int state, struct mcd_mbx *mbxin); 164 #ifndef MCDMINI 165 static int mcd_setmode(int unit, int mode); 166 static int mcd_getqchan(int unit, struct mcd_qchninfo *q); 167 static int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 168 static int mcd_toc_header(int unit, struct ioc_toc_header *th); 169 static int mcd_read_toc(int unit); 170 static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); 171 static int mcd_stop(int unit); 172 static int mcd_playtracks(int unit, struct ioc_play_track *pt); 173 static int mcd_play(int unit, struct mcd_read2 *pb); 174 static int mcd_pause(int unit); 175 static int mcd_resume(int unit); 176 #endif 177 178 extern int hz; 179 extern int mcd_probe(struct isa_device *dev); 180 extern int mcd_attach(struct isa_device *dev); 181 struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 182 183 #define mcd_put(port,byte) outb(port,byte) 184 185 #define MCD_RETRYS 5 186 #define MCD_RDRETRYS 8 187 188 #define MCDBLK 2048 /* for cooked mode */ 189 #define MCDRBLK 2352 /* for raw mode */ 190 191 /* several delays */ 192 #define RDELAY_WAITSTAT 300 193 #define RDELAY_WAITMODE 300 194 #define RDELAY_WAITREAD 800 195 196 #define DELAY_STATUS 10000l /* 10000 * 1us */ 197 #define DELAY_GETREPLY 200000l /* 200000 * 2us */ 198 #define DELAY_SEEKREAD 20000l /* 20000 * 1us */ 199 #define mcd_delay DELAY 200 201 int mcd_attach(struct isa_device *dev) 202 { 203 struct mcd_data *cd = mcd_data + dev->id_unit; 204 int i; 205 206 cd->iobase = dev->id_iobase; 207 cd->flags |= MCDINIT; 208 cd->openflags = 0; 209 for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 210 211 #ifdef NOTYET 212 /* wire controller for interrupts and dma */ 213 mcd_configure(cd); 214 #endif 215 216 return 1; 217 } 218 219 int mcdopen(dev_t dev) 220 { 221 int unit,part,phys; 222 struct mcd_data *cd; 223 224 unit = mcd_unit(dev); 225 if (unit >= NMCD) 226 return ENXIO; 227 228 cd = mcd_data + unit; 229 part = mcd_part(dev); 230 phys = mcd_phys(dev); 231 232 /* not initialized*/ 233 if (!(cd->flags & MCDINIT)) 234 return ENXIO; 235 236 /* invalidated in the meantime? mark all open part's invalid */ 237 if (!(cd->flags & MCDVALID) && cd->openflags) 238 return ENXIO; 239 240 if (mcd_getstat(unit,1) < 0) 241 return ENXIO; 242 243 /* XXX get a default disklabel */ 244 mcd_getdisklabel(unit); 245 246 if (mcdsize(dev) < 0) { 247 printf("mcd%d: failed to get disk size\n",unit); 248 return ENXIO; 249 } else 250 cd->flags |= MCDVALID; 251 252 MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 253 part,cd->disksize,cd->blksize,0); 254 255 if (part == RAW_PART || 256 (part < cd->dlabel.d_npartitions && 257 cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 258 cd->partflags[part] |= MCDOPEN; 259 cd->openflags |= (1<<part); 260 if (part == RAW_PART && phys != 0) 261 cd->partflags[part] |= MCDREADRAW; 262 return 0; 263 } 264 265 return ENXIO; 266 } 267 268 int mcdclose(dev_t dev) 269 { 270 int unit,part,phys; 271 struct mcd_data *cd; 272 273 unit = mcd_unit(dev); 274 if (unit >= NMCD) 275 return ENXIO; 276 277 cd = mcd_data + unit; 278 part = mcd_part(dev); 279 phys = mcd_phys(dev); 280 281 if (!(cd->flags & MCDINIT)) 282 return ENXIO; 283 284 mcd_getstat(unit,1); /* get status */ 285 286 /* close channel */ 287 cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 288 cd->openflags &= ~(1<<part); 289 MCD_TRACE("close: partition=%d\n",part,0,0,0); 290 291 return 0; 292 } 293 294 int mcdstrategy(struct buf *bp) 295 { 296 struct mcd_data *cd; 297 struct buf *qp; 298 int s; 299 300 int unit = mcd_unit(bp->b_dev); 301 302 cd = mcd_data + unit; 303 304 /* test validity */ 305 /*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 306 bp,unit,bp->b_blkno,bp->b_bcount);*/ 307 if (unit >= NMCD || bp->b_blkno < 0) { 308 printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 309 unit, bp->b_blkno, bp->b_bcount); 310 pg("mcd: mcdstratregy failure"); 311 bp->b_error = EINVAL; 312 bp->b_flags |= B_ERROR; 313 goto bad; 314 } 315 316 /* if device invalidated (e.g. media change, door open), error */ 317 if (!(cd->flags & MCDVALID)) { 318 MCD_TRACE("strategy: drive not valid\n",0,0,0,0); 319 bp->b_error = EIO; 320 goto bad; 321 } 322 323 /* read only */ 324 if (!(bp->b_flags & B_READ)) { 325 bp->b_error = EROFS; 326 goto bad; 327 } 328 329 /* no data to read */ 330 if (bp->b_bcount == 0) 331 goto done; 332 333 /* for non raw access, check partition limits */ 334 if (mcd_part(bp->b_dev) != RAW_PART) { 335 if (!(cd->flags & MCDLABEL)) { 336 bp->b_error = EIO; 337 goto bad; 338 } 339 /* adjust transfer if necessary */ 340 if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 341 goto done; 342 } 343 } 344 345 /* queue it */ 346 qp = &cd->head; 347 s = splbio(); 348 disksort(qp,bp); 349 splx(s); 350 351 /* now check whether we can perform processing */ 352 mcd_start(unit); 353 return; 354 355 bad: 356 bp->b_flags |= B_ERROR; 357 done: 358 bp->b_resid = bp->b_bcount; 359 biodone(bp); 360 return; 361 } 362 363 static void mcd_start(int unit) 364 { 365 struct mcd_data *cd = mcd_data + unit; 366 struct buf *bp, *qp = &cd->head; 367 struct partition *p; 368 int part; 369 register s = splbio(); 370 371 if (cd->flags & MCDMBXBSY) 372 return; 373 374 if ((bp = qp->b_actf) != 0) { 375 /* block found to process, dequeue */ 376 /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 377 qp->b_actf = bp->av_forw; 378 splx(s); 379 } else { 380 /* nothing to do */ 381 splx(s); 382 return; 383 } 384 385 /* changed media? */ 386 if (!(cd->flags & MCDVALID)) { 387 MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 388 return; 389 } 390 391 p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 392 393 cd->flags |= MCDMBXBSY; 394 cd->mbx.unit = unit; 395 cd->mbx.port = cd->iobase; 396 cd->mbx.retry = MCD_RETRYS; 397 cd->mbx.bp = bp; 398 cd->mbx.p_offset = p->p_offset; 399 400 /* calling the read routine */ 401 mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 402 /* triggers mcd_start, when successful finished */ 403 return; 404 } 405 406 int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 407 { 408 struct mcd_data *cd; 409 int unit,part; 410 411 unit = mcd_unit(dev); 412 part = mcd_part(dev); 413 cd = mcd_data + unit; 414 415 #ifdef MCDMINI 416 return ENOTTY; 417 #else 418 if (!(cd->flags & MCDVALID)) 419 return EIO; 420 MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 421 422 switch (cmd) { 423 case DIOCSBAD: 424 return EINVAL; 425 case DIOCGDINFO: 426 case DIOCGPART: 427 case DIOCWDINFO: 428 case DIOCSDINFO: 429 case DIOCWLABEL: 430 return ENOTTY; 431 case CDIOCPLAYTRACKS: 432 return mcd_playtracks(unit, (struct ioc_play_track *) addr); 433 case CDIOCPLAYBLOCKS: 434 return mcd_play(unit, (struct mcd_read2 *) addr); 435 case CDIOCREADSUBCHANNEL: 436 return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 437 case CDIOREADTOCHEADER: 438 return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 439 case CDIOREADTOCENTRYS: 440 return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); 441 case CDIOCSETPATCH: 442 case CDIOCGETVOL: 443 case CDIOCSETVOL: 444 case CDIOCSETMONO: 445 case CDIOCSETSTERIO: 446 case CDIOCSETMUTE: 447 case CDIOCSETLEFT: 448 case CDIOCSETRIGHT: 449 return EINVAL; 450 case CDIOCRESUME: 451 return mcd_resume(unit); 452 case CDIOCPAUSE: 453 return mcd_pause(unit); 454 case CDIOCSTART: 455 return EINVAL; 456 case CDIOCSTOP: 457 return mcd_stop(unit); 458 case CDIOCEJECT: 459 return EINVAL; 460 case CDIOCSETDEBUG: 461 cd->debug = 1; 462 return 0; 463 case CDIOCCLRDEBUG: 464 cd->debug = 0; 465 return 0; 466 case CDIOCRESET: 467 return EINVAL; 468 default: 469 return ENOTTY; 470 } 471 /*NOTREACHED*/ 472 #endif /*!MCDMINI*/ 473 } 474 475 /* this could have been taken from scsi/cd.c, but it is not clear 476 * whether the scsi cd driver is linked in 477 */ 478 static int mcd_getdisklabel(int unit) 479 { 480 struct mcd_data *cd = mcd_data + unit; 481 482 if (cd->flags & MCDLABEL) 483 return -1; 484 485 bzero(&cd->dlabel,sizeof(struct disklabel)); 486 strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); 487 strncpy(cd->dlabel.d_packname,"unknown ",16); 488 cd->dlabel.d_secsize = cd->blksize; 489 cd->dlabel.d_nsectors = 100; 490 cd->dlabel.d_ntracks = 1; 491 cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 492 cd->dlabel.d_secpercyl = 100; 493 cd->dlabel.d_secperunit = cd->disksize; 494 cd->dlabel.d_rpm = 300; 495 cd->dlabel.d_interleave = 1; 496 cd->dlabel.d_flags = D_REMOVABLE; 497 cd->dlabel.d_npartitions= 1; 498 cd->dlabel.d_partitions[0].p_offset = 0; 499 cd->dlabel.d_partitions[0].p_size = cd->disksize; 500 cd->dlabel.d_partitions[0].p_fstype = 9; 501 cd->dlabel.d_magic = DISKMAGIC; 502 cd->dlabel.d_magic2 = DISKMAGIC; 503 cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 504 505 cd->flags |= MCDLABEL; 506 return 0; 507 } 508 509 int mcdsize(dev_t dev) 510 { 511 int size; 512 int unit = mcd_unit(dev); 513 struct mcd_data *cd = mcd_data + unit; 514 515 if (mcd_volinfo(unit) >= 0) { 516 cd->blksize = MCDBLK; 517 size = msf2hsg(cd->volinfo.vol_msf); 518 cd->disksize = size * (MCDBLK/DEV_BSIZE); 519 return 0; 520 } 521 return -1; 522 } 523 524 /*************************************************************** 525 * lower level of driver starts here 526 **************************************************************/ 527 528 #ifdef NOTDEF 529 static char irqs[] = { 530 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 531 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 532 }; 533 534 static char drqs[] = { 535 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 536 }; 537 #endif 538 539 static void mcd_configure(struct mcd_data *cd) 540 { 541 outb(cd->iobase+mcd_config,cd->config); 542 } 543 544 /* check if there is a cdrom */ 545 /* Heavly hacked by gclarkii@sugar.neosoft.com */ 546 547 int mcd_probe(struct isa_device *dev) 548 { 549 int port = dev->id_iobase; 550 int unit = dev->id_unit; 551 int i; 552 int st; 553 int check; 554 int junk; 555 556 mcd_data[unit].flags = MCDPROBING; 557 558 #ifdef NOTDEF 559 /* get irq/drq configuration word */ 560 mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 561 #else 562 mcd_data[unit].config = 0; 563 #endif 564 565 /* send a reset */ 566 outb(port+MCD_FLAGS,0); 567 DELAY(100000); 568 /* get any pending status and throw away...*/ 569 for (i=10; i != 0; i--) { 570 inb(port+MCD_DATA); 571 } 572 DELAY(1000); 573 574 outb(port+MCD_DATA,MCD_CMDGETSTAT); /* Send get status command */ 575 576 /* Loop looking for avail of status */ 577 /* XXX May have to increase for fast machinces */ 578 for (i = 1000; i != 0; i--) { 579 if ((inb(port+MCD_FLAGS) & 0xF ) == STATUS_AVAIL) { 580 break; 581 } 582 DELAY(10); 583 } 584 /* get status */ 585 586 if (i == 0) { 587 #ifdef DEBUG 588 printf ("Mitsumi drive NOT detected\n"); 589 #endif 590 return 0; 591 } 592 593 /* 594 * The following code uses the 0xDC command, it returns a M from the 595 * second byte and a number in the third. Does anyone know what the 596 * number is for? Better yet, how about someone thats REAL good in 597 * i80x86 asm looking at the Dos driver... Most of this info came 598 * from a friend of mine spending a whole weekend..... 599 */ 600 601 DELAY (2000); 602 outb(port+MCD_DATA,MCD_CMDCONTINFO); 603 for (i = 0; i < 100000; i++) { 604 if ((inb(port+MCD_FLAGS) & 0xF) == STATUS_AVAIL) 605 break; 606 } 607 if (i > 100000) { 608 #ifdef DEBUG 609 printf ("Mitsumi drive error\n"); 610 #endif 611 return 0; 612 } 613 DELAY (40000); 614 st = inb(port+MCD_DATA); 615 DELAY (500); 616 check = inb(port+MCD_DATA); 617 DELAY (500); 618 junk = inb(port+MCD_DATA); /* What is byte used for?!?!? */ 619 620 if (check = 'M') { 621 #ifdef DEBUG 622 printf("Mitsumi drive detected\n"); 623 #endif 624 return 4; 625 } else { 626 printf("Mitsumi drive NOT detected\n"); 627 printf("Mitsumi drive error\n"); 628 return 0; 629 } 630 } 631 632 static int mcd_waitrdy(int port,int dly) 633 { 634 int i; 635 636 /* wait until xfer port senses data ready */ 637 for (i=0; i<dly; i++) { 638 if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0) 639 return 0; 640 mcd_delay(1); 641 } 642 return -1; 643 } 644 645 static int mcd_getreply(int unit,int dly) 646 { 647 int i; 648 struct mcd_data *cd = mcd_data + unit; 649 int port = cd->iobase; 650 651 /* wait data to become ready */ 652 if (mcd_waitrdy(port,dly)<0) { 653 #ifdef MCD_TO_WARNING_ON 654 printf("mcd%d: timeout getreply\n",unit); 655 #endif 656 return -1; 657 } 658 659 /* get the data */ 660 return inb(port+mcd_status) & 0xFF; 661 } 662 663 static int mcd_getstat(int unit,int sflg) 664 { 665 int i; 666 struct mcd_data *cd = mcd_data + unit; 667 int port = cd->iobase; 668 669 /* get the status */ 670 if (sflg) 671 outb(port+mcd_command, MCD_CMDGETSTAT); 672 i = mcd_getreply(unit,DELAY_GETREPLY); 673 if (i<0) return -1; 674 675 cd->status = i; 676 677 mcd_setflags(unit,cd); 678 return cd->status; 679 } 680 681 static void mcd_setflags(int unit, struct mcd_data *cd) 682 { 683 /* check flags */ 684 if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { 685 MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); 686 cd->flags &= ~MCDVALID; 687 } 688 689 #ifndef MCDMINI 690 if (cd->status & MCDAUDIOBSY) 691 cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 692 else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 693 cd->audio_status = CD_AS_PLAY_COMPLETED; 694 #endif 695 } 696 697 static int mcd_get(int unit, char *buf, int nmax) 698 { 699 int port = mcd_data[unit].iobase; 700 int i,k; 701 702 for (i=0; i<nmax; i++) { 703 704 /* wait for data */ 705 if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 706 #ifdef MCD_TO_WARNING_ON 707 printf("mcd%d: timeout mcd_get\n",unit); 708 #endif 709 return -1; 710 } 711 buf[i] = k; 712 } 713 return i; 714 } 715 716 static int mcd_send(int unit, int cmd,int nretrys) 717 { 718 int i,k; 719 int port = mcd_data[unit].iobase; 720 721 /*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/ 722 for (i=0; i<nretrys; i++) { 723 outb(port+mcd_command, cmd); 724 if ((k=mcd_getstat(unit,0)) != -1) 725 break; 726 } 727 if (i == nretrys) { 728 printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 729 return -1; 730 } 731 /*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/ 732 return 0; 733 } 734 735 static int bcd2bin(bcd_t b) 736 { 737 return (b >> 4) * 10 + (b & 15); 738 } 739 740 static bcd_t bin2bcd(int b) 741 { 742 return ((b / 10) << 4) | (b % 10); 743 } 744 745 static void hsg2msf(int hsg, bcd_t *msf) 746 { 747 hsg += 150; 748 M_msf(msf) = bin2bcd(hsg / 4500); 749 hsg %= 4500; 750 S_msf(msf) = bin2bcd(hsg / 75); 751 F_msf(msf) = bin2bcd(hsg % 75); 752 } 753 754 static int msf2hsg(bcd_t *msf) 755 { 756 return (bcd2bin(M_msf(msf)) * 60 + 757 bcd2bin(S_msf(msf))) * 75 + 758 bcd2bin(F_msf(msf)) - 150; 759 } 760 761 static int mcd_volinfo(int unit) 762 { 763 struct mcd_data *cd = mcd_data + unit; 764 int i; 765 766 /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 767 768 /* Get the status, in case the disc has been changed */ 769 if (mcd_getstat(unit, 1) < 0) return EIO; 770 771 /* Just return if we already have it */ 772 if (cd->flags & MCDVOLINFO) return 0; 773 774 /* send volume info command */ 775 if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 776 return -1; 777 778 /* get data */ 779 if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 780 printf("mcd%d: mcd_volinfo: error read data\n",unit); 781 return -1; 782 } 783 784 if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { 785 cd->flags |= MCDVOLINFO; /* volinfo is OK */ 786 return 0; 787 } 788 789 return -1; 790 } 791 792 int mcdintr(unit) 793 { 794 int port = mcd_data[unit].iobase; 795 u_int i; 796 797 MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); 798 799 /* just read out status and ignore the rest */ 800 if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { 801 i = inb(port+mcd_status); 802 } 803 } 804 805 /* state machine to process read requests 806 * initialize with MCD_S_BEGIN: calculate sizes, and read status 807 * MCD_S_WAITSTAT: wait for status reply, set mode 808 * MCD_S_WAITMODE: waits for status reply from set mode, set read command 809 * MCD_S_WAITREAD: wait for read ready, read data 810 */ 811 static struct mcd_mbx *mbxsave; 812 813 static void mcd_doread(int state, struct mcd_mbx *mbxin) 814 { 815 struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 816 int unit = mbx->unit; 817 int port = mbx->port; 818 struct buf *bp = mbx->bp; 819 struct mcd_data *cd = mcd_data + unit; 820 821 int rm,i,k; 822 struct mcd_read2 rbuf; 823 int blknum; 824 caddr_t addr; 825 826 loop: 827 switch (state) { 828 case MCD_S_BEGIN: 829 mbx = mbxsave = mbxin; 830 831 case MCD_S_BEGIN1: 832 /* get status */ 833 outb(port+mcd_command, MCD_CMDGETSTAT); 834 mbx->count = RDELAY_WAITSTAT; 835 timeout((timeout_t) mcd_doread,(caddr_t) MCD_S_WAITSTAT,hz/100); 836 return; 837 case MCD_S_WAITSTAT: 838 untimeout((timeout_t) mcd_doread,(caddr_t) MCD_S_WAITSTAT); 839 if (mbx->count-- >= 0) { 840 if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 841 timeout((timeout_t) mcd_doread, 842 (caddr_t) MCD_S_WAITSTAT,hz/100); 843 return; 844 } 845 mcd_setflags(unit,cd); 846 MCD_TRACE("got WAITSTAT delay=%d\n",RDELAY_WAITSTAT-mbx->count,0,0,0); 847 /* reject, if audio active */ 848 if (cd->status & MCDAUDIOBSY) { 849 printf("mcd%d: audio is active\n",unit); 850 goto readerr; 851 } 852 853 /* to check for raw/cooked mode */ 854 if (cd->flags & MCDREADRAW) { 855 rm = MCD_MD_RAW; 856 mbx->sz = MCDRBLK; 857 } else { 858 rm = MCD_MD_COOKED; 859 mbx->sz = cd->blksize; 860 } 861 862 mbx->count = RDELAY_WAITMODE; 863 864 mcd_put(port+mcd_command, MCD_CMDSETMODE); 865 mcd_put(port+mcd_command, rm); 866 timeout((timeout_t) mcd_doread, 867 (caddr_t) MCD_S_WAITMODE,hz/100); 868 return; 869 } else { 870 #ifdef MCD_TO_WARNING_ON 871 printf("mcd%d: timeout getstatus\n",unit); 872 #endif 873 goto readerr; 874 } 875 876 case MCD_S_WAITMODE: 877 untimeout((timeout_t) mcd_doread,(caddr_t) MCD_S_WAITMODE); 878 if (mbx->count-- < 0) { 879 #ifdef MCD_TO_WARNING_ON 880 printf("mcd%d: timeout set mode\n",unit); 881 #endif 882 goto readerr; 883 } 884 if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 885 timeout((timeout_t) mcd_doread, 886 (caddr_t) MCD_S_WAITMODE,hz/100); 887 return; 888 } 889 mcd_setflags(unit,cd); 890 MCD_TRACE("got WAITMODE delay=%d\n",RDELAY_WAITMODE-mbx->count,0,0,0); 891 /* for first block */ 892 mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 893 mbx->skip = 0; 894 895 nextblock: 896 blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 897 + mbx->p_offset + mbx->skip/mbx->sz; 898 899 MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",blknum,bp,0,0); 900 901 /* build parameter block */ 902 hsg2msf(blknum,rbuf.start_msf); 903 904 /* send the read command */ 905 mcd_put(port+mcd_command,MCD_CMDREAD2); 906 mcd_put(port+mcd_command,rbuf.start_msf[0]); 907 mcd_put(port+mcd_command,rbuf.start_msf[1]); 908 mcd_put(port+mcd_command,rbuf.start_msf[2]); 909 mcd_put(port+mcd_command,0); 910 mcd_put(port+mcd_command,0); 911 mcd_put(port+mcd_command,1); 912 mbx->count = RDELAY_WAITREAD; 913 timeout((timeout_t) mcd_doread,(caddr_t) MCD_S_WAITREAD,hz/100); 914 return; 915 case MCD_S_WAITREAD: 916 untimeout((timeout_t) mcd_doread,(caddr_t) MCD_S_WAITREAD); 917 if (mbx->count-- > 0) { 918 k = inb(port+mcd_xfer); 919 if ((k & 2)==0) { 920 MCD_TRACE("got data delay=%d\n",RDELAY_WAITREAD-mbx->count,0,0,0); 921 /* data is ready */ 922 addr = bp->b_un.b_addr + mbx->skip; 923 outb(port+mcd_ctl2,0x04); /* XXX */ 924 for (i=0; i<mbx->sz; i++) 925 *addr++ = inb(port+mcd_rdata); 926 outb(port+mcd_ctl2,0x0c); /* XXX */ 927 928 if (--mbx->nblk > 0) { 929 mbx->skip += mbx->sz; 930 goto nextblock; 931 } 932 933 /* return buffer */ 934 bp->b_resid = 0; 935 biodone(bp); 936 937 cd->flags &= ~MCDMBXBSY; 938 mcd_start(mbx->unit); 939 return; 940 } 941 if ((k & 4)==0) 942 mcd_getstat(unit,0); 943 timeout((timeout_t) mcd_doread, 944 (caddr_t) MCD_S_WAITREAD,hz/100); 945 return; 946 } else { 947 #ifdef MCD_TO_WARNING_ON 948 printf("mcd%d: timeout read data\n",unit); 949 #endif 950 goto readerr; 951 } 952 } 953 954 readerr: 955 if (mbx->retry-- > 0) { 956 #ifdef MCD_TO_WARNING_ON 957 printf("mcd%d: retrying\n",unit); 958 #endif 959 state = MCD_S_BEGIN1; 960 goto loop; 961 } 962 963 /* invalidate the buffer */ 964 bp->b_flags |= B_ERROR; 965 bp->b_resid = bp->b_bcount; 966 biodone(bp); 967 mcd_start(mbx->unit); 968 return; 969 970 #ifdef NOTDEF 971 printf("mcd%d: unit timeout, resetting\n",mbx->unit); 972 outb(mbx->port+mcd_reset,MCD_CMDRESET); 973 DELAY(300000); 974 (void)mcd_getstat(mbx->unit,1); 975 (void)mcd_getstat(mbx->unit,1); 976 /*cd->status &= ~MCDDSKCHNG; */ 977 cd->debug = 1; /* preventive set debug mode */ 978 979 #endif 980 981 } 982 983 #ifndef MCDMINI 984 static int mcd_setmode(int unit, int mode) 985 { 986 struct mcd_data *cd = mcd_data + unit; 987 int port = cd->iobase; 988 int retry; 989 990 printf("mcd%d: setting mode to %d\n", unit, mode); 991 for(retry=0; retry<MCD_RETRYS; retry++) 992 { 993 outb(port+mcd_command, MCD_CMDSETMODE); 994 outb(port+mcd_command, mode); 995 if (mcd_getstat(unit, 0) != -1) return 0; 996 } 997 998 return -1; 999 } 1000 1001 static int mcd_toc_header(int unit, struct ioc_toc_header *th) 1002 { 1003 struct mcd_data *cd = mcd_data + unit; 1004 1005 if (mcd_volinfo(unit) < 0) 1006 return ENXIO; 1007 1008 th->len = msf2hsg(cd->volinfo.vol_msf); 1009 th->starting_track = bcd2bin(cd->volinfo.trk_low); 1010 th->ending_track = bcd2bin(cd->volinfo.trk_high); 1011 1012 return 0; 1013 } 1014 1015 static int mcd_read_toc(int unit) 1016 { 1017 struct mcd_data *cd = mcd_data + unit; 1018 struct ioc_toc_header th; 1019 struct mcd_qchninfo q; 1020 int rc, trk, idx, retry; 1021 1022 /* Only read TOC if needed */ 1023 if (cd->flags & MCDTOC) return 0; 1024 1025 printf("mcd%d: reading toc header\n", unit); 1026 if (mcd_toc_header(unit, &th) != 0) 1027 return ENXIO; 1028 1029 printf("mcd%d: stopping play\n", unit); 1030 if ((rc=mcd_stop(unit)) != 0) 1031 return rc; 1032 1033 /* try setting the mode twice */ 1034 if (mcd_setmode(unit, MCD_MD_TOC) != 0) 1035 return EIO; 1036 if (mcd_setmode(unit, MCD_MD_TOC) != 0) 1037 return EIO; 1038 1039 printf("mcd%d: get_toc reading qchannel info\n",unit); 1040 for(trk=th.starting_track; trk<=th.ending_track; trk++) 1041 cd->toc[trk].idx_no = 0; 1042 trk = th.ending_track - th.starting_track + 1; 1043 for(retry=0; retry<300 && trk>0; retry++) 1044 { 1045 if (mcd_getqchan(unit, &q) < 0) break; 1046 idx = bcd2bin(q.idx_no); 1047 if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) 1048 if (cd->toc[idx].idx_no == 0) 1049 { 1050 cd->toc[idx] = q; 1051 trk--; 1052 } 1053 } 1054 1055 if (mcd_setmode(unit, MCD_MD_COOKED) != 0) 1056 return EIO; 1057 1058 if (trk != 0) return ENXIO; 1059 1060 /* add a fake last+1 */ 1061 idx = th.ending_track + 1; 1062 cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1063 cd->toc[idx].trk_no = 0; 1064 cd->toc[idx].idx_no = 0xAA; 1065 cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1066 cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1067 cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1068 1069 cd->flags |= MCDTOC; 1070 1071 return 0; 1072 } 1073 1074 static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te) 1075 { 1076 struct mcd_data *cd = mcd_data + unit; 1077 struct ret_toc 1078 { 1079 struct ioc_toc_header th; 1080 struct cd_toc_entry rt; 1081 } ret_toc; 1082 struct ioc_toc_header th; 1083 int rc, i; 1084 1085 /* Make sure we have a valid toc */ 1086 if ((rc=mcd_read_toc(unit)) != 0) 1087 return rc; 1088 1089 /* find the toc to copy*/ 1090 i = te->starting_track; 1091 if (i == MCD_LASTPLUS1) 1092 i = bcd2bin(cd->volinfo.trk_high) + 1; 1093 1094 /* verify starting track */ 1095 if (i < bcd2bin(cd->volinfo.trk_low) || 1096 i > bcd2bin(cd->volinfo.trk_high)+1) 1097 return EINVAL; 1098 1099 /* do we have room */ 1100 if (te->data_len < sizeof(struct ioc_toc_header) + 1101 sizeof(struct cd_toc_entry)) return EINVAL; 1102 1103 /* Copy the toc header */ 1104 if (mcd_toc_header(unit, &th) < 0) return EIO; 1105 ret_toc.th = th; 1106 1107 /* copy the toc data */ 1108 ret_toc.rt.control = cd->toc[i].ctrl_adr; 1109 ret_toc.rt.addr_type = te->address_format; 1110 ret_toc.rt.track = i; 1111 if (te->address_format == CD_MSF_FORMAT) 1112 { 1113 ret_toc.rt.addr[1] = cd->toc[i].hd_pos_msf[0]; 1114 ret_toc.rt.addr[2] = cd->toc[i].hd_pos_msf[1]; 1115 ret_toc.rt.addr[3] = cd->toc[i].hd_pos_msf[2]; 1116 } 1117 1118 /* copy the data back */ 1119 copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) 1120 + sizeof(struct ioc_toc_header)); 1121 1122 return 0; 1123 } 1124 1125 static int mcd_stop(int unit) 1126 { 1127 struct mcd_data *cd = mcd_data + unit; 1128 1129 if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1130 return ENXIO; 1131 cd->audio_status = CD_AS_PLAY_COMPLETED; 1132 return 0; 1133 } 1134 1135 static int mcd_getqchan(int unit, struct mcd_qchninfo *q) 1136 { 1137 struct mcd_data *cd = mcd_data + unit; 1138 1139 if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1140 return -1; 1141 if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1142 return -1; 1143 if (cd->debug) 1144 printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", 1145 unit, 1146 q->ctrl_adr, q->trk_no, q->idx_no, 1147 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], 1148 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); 1149 return 0; 1150 } 1151 1152 static int mcd_subchan(int unit, struct ioc_read_subchannel *sc) 1153 { 1154 struct mcd_data *cd = mcd_data + unit; 1155 struct mcd_qchninfo q; 1156 struct cd_sub_channel_info data; 1157 1158 printf("mcd%d: subchan af=%d, df=%d\n", unit, 1159 sc->address_format, 1160 sc->data_format); 1161 if (sc->address_format != CD_MSF_FORMAT) return EIO; 1162 if (sc->data_format != CD_CURRENT_POSITION) return EIO; 1163 1164 if (mcd_getqchan(unit, &q) < 0) return EIO; 1165 1166 data.header.audio_status = cd->audio_status; 1167 data.what.position.data_format = CD_MSF_FORMAT; 1168 data.what.position.track_number = bcd2bin(q.trk_no); 1169 1170 if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) 1171 return EFAULT; 1172 return 0; 1173 } 1174 1175 static int mcd_playtracks(int unit, struct ioc_play_track *pt) 1176 { 1177 struct mcd_data *cd = mcd_data + unit; 1178 struct mcd_read2 pb; 1179 int a = pt->start_track; 1180 int z = pt->end_track; 1181 int rc; 1182 1183 if ((rc = mcd_read_toc(unit)) != 0) return rc; 1184 1185 printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 1186 a, pt->start_index, z, pt->end_index); 1187 1188 if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || 1189 z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) 1190 return EINVAL; 1191 1192 pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; 1193 pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; 1194 pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; 1195 pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; 1196 pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; 1197 pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; 1198 1199 return mcd_play(unit, &pb); 1200 } 1201 1202 static int mcd_play(int unit, struct mcd_read2 *pb) 1203 { 1204 struct mcd_data *cd = mcd_data + unit; 1205 int port = cd->iobase; 1206 int retry, st; 1207 1208 cd->lastpb = *pb; 1209 for(retry=0; retry<MCD_RETRYS; retry++) 1210 { 1211 outb(port+mcd_command, MCD_CMDREAD2); 1212 outb(port+mcd_command, pb->start_msf[0]); 1213 outb(port+mcd_command, pb->start_msf[1]); 1214 outb(port+mcd_command, pb->start_msf[2]); 1215 outb(port+mcd_command, pb->end_msf[0]); 1216 outb(port+mcd_command, pb->end_msf[1]); 1217 outb(port+mcd_command, pb->end_msf[2]); 1218 if ((st=mcd_getstat(unit, 0)) != -1) break; 1219 } 1220 1221 if (cd->debug) 1222 printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); 1223 if (st == -1) return ENXIO; 1224 cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1225 return 0; 1226 } 1227 1228 static int mcd_pause(int unit) 1229 { 1230 struct mcd_data *cd = mcd_data + unit; 1231 struct mcd_qchninfo q; 1232 int rc; 1233 1234 /* Verify current status */ 1235 if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) 1236 { 1237 printf("mcd%d: pause attempted when not playing\n", unit); 1238 return EINVAL; 1239 } 1240 1241 /* Get the current position */ 1242 if (mcd_getqchan(unit, &q) < 0) return EIO; 1243 1244 /* Copy it into lastpb */ 1245 cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1246 cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1247 cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1248 1249 /* Stop playing */ 1250 if ((rc=mcd_stop(unit)) != 0) return rc; 1251 1252 /* Set the proper status and exit */ 1253 cd->audio_status = CD_AS_PLAY_PAUSED; 1254 return 0; 1255 } 1256 1257 static int mcd_resume(int unit) 1258 { 1259 struct mcd_data *cd = mcd_data + unit; 1260 1261 if (cd->audio_status != CD_AS_PLAY_PAUSED) return EINVAL; 1262 return mcd_play(unit, &cd->lastpb); 1263 } 1264 #endif /*!MCDMINI*/ 1265 1266 #endif /* NMCD > 0 */ 1267