mcd.c revision 1379
1174891Sedwin/* 2174891Sedwin * Copyright 1993 by Holger Veit (data part) 3174891Sedwin * Copyright 1993 by Brian Moore (audio part) 4174891Sedwin * Changes Copyright 1993 by Gary Clark II 5174891Sedwin * 6174891Sedwin * Rewrote probe routine to work on newer Mitsumi drives. 7174891Sedwin * Additional changes (C) 1994 by Jordan K. Hubbard 8174891Sedwin * 9174891Sedwin * All rights reserved. 10174891Sedwin * 11174891Sedwin * Redistribution and use in source and binary forms, with or without 12174891Sedwin * modification, are permitted provided that the following conditions 13174891Sedwin * are met: 14174891Sedwin * 1. Redistributions of source code must retain the above copyright 15174891Sedwin * notice, this list of conditions and the following disclaimer. 16174891Sedwin * 2. Redistributions in binary form must reproduce the above copyright 17174891Sedwin * notice, this list of conditions and the following disclaimer in the 18174891Sedwin * documentation and/or other materials provided with the distribution. 19174891Sedwin * 3. All advertising materials mentioning features or use of this software 20174891Sedwin * must display the following acknowledgement: 21174891Sedwin * This software was developed by Holger Veit and Brian Moore 22174891Sedwin * for use with "386BSD" and similar operating systems. 23174891Sedwin * "Similar operating systems" includes mainly non-profit oriented 24174891Sedwin * systems for research and education, including but not restricted to 25174891Sedwin * "NetBSD", "FreeBSD", "Mach" (by CMU). 26174891Sedwin * 4. Neither the name of the developer(s) nor the name "386BSD" 27228992Suqs * may be used to endorse or promote products derived from this 28174891Sedwin * software without specific prior written permission. 29174891Sedwin * 30174891Sedwin * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 31174891Sedwin * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32174891Sedwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33174891Sedwin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 34174891Sedwin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 35174891Sedwin * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 36174891Sedwin * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 37174891Sedwin * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38174891Sedwin * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39174891Sedwin * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 40174891Sedwin * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41174891Sedwin * 42174891Sedwin * $Id: mcd.c,v 1.14 1994/03/21 20:59:55 ats Exp $ 43174891Sedwin */ 44174891Sedwinstatic char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 45174891Sedwin 46174891Sedwin#include "mcd.h" 47174891Sedwin#if NMCD > 0 48174891Sedwin#include "types.h" 49174891Sedwin#include "param.h" 50174891Sedwin#include "systm.h" 51174891Sedwin#include "conf.h" 52174891Sedwin#include "file.h" 53174891Sedwin#include "buf.h" 54174891Sedwin#include "stat.h" 55174891Sedwin#include "uio.h" 56174891Sedwin#include "ioctl.h" 57174891Sedwin#include "cdio.h" 58174891Sedwin#include "errno.h" 59174891Sedwin#include "dkbad.h" 60281501Seadler#include "disklabel.h" 61281501Seadler#include "i386/isa/isa.h" 62281501Seadler#include "i386/isa/isa_device.h" 63281501Seadler#include "mcdreg.h" 64281501Seadler 65281501Seadler/* user definable options */ 66281501Seadler/*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ 67174891Sedwin/*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ 68174891Sedwin 69174891Sedwin 70174891Sedwin#ifdef MCDMINI 71174891Sedwin#define MCD_TRACE(fmt,a,b,c,d) 72174891Sedwin#ifdef MCD_TO_WARNING_ON 73174891Sedwin#undef MCD_TO_WARNING_ON 74174891Sedwin#endif 75224016Sbz#else 76174891Sedwin#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);}} 77174891Sedwin#endif 78174891Sedwin 79174891Sedwin#define mcd_part(dev) ((minor(dev)) & 7) 80174891Sedwin#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) 81174891Sedwin#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) 82174891Sedwin#define RAW_PART 0 83174891Sedwin 84174891Sedwin/* flags */ 85174891Sedwin#define MCDOPEN 0x0001 /* device opened */ 86174891Sedwin#define MCDVALID 0x0002 /* parameters loaded */ 87174891Sedwin#define MCDINIT 0x0004 /* device is init'd */ 88174891Sedwin#define MCDWAIT 0x0008 /* waiting for something */ 89174891Sedwin#define MCDLABEL 0x0010 /* label is read */ 90174891Sedwin#define MCDPROBING 0x0020 /* probing */ 91174891Sedwin#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ 92174891Sedwin#define MCDVOLINFO 0x0080 /* already read volinfo */ 93174891Sedwin#define MCDTOC 0x0100 /* already read toc */ 94281501Seadler#define MCDMBXBSY 0x0200 /* local mbx is busy */ 95174891Sedwin 96174891Sedwin/* status */ 97281501Seadler#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 98174891Sedwin#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 99174891Sedwin#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 100281501Seadler#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 101174891Sedwin 102174891Sedwin/* These are apparently the different states a mitsumi can get up to */ 103174891Sedwin#define MCDCDABSENT 0x0030 104174891Sedwin#define MCDCDPRESENT 0x0020 105174891Sedwin#define MCDSCLOSED 0x0080 106174891Sedwin#define MCDSOPEN 0x00a0 107174891Sedwin 108174891Sedwin/* toc */ 109174891Sedwin#define MCD_MAXTOCS 104 /* from the Linux driver */ 110174891Sedwin#define MCD_LASTPLUS1 170 /* special toc entry */ 111174891Sedwin 112174891Sedwinstruct mcd_mbx { 113174891Sedwin short unit; 114174891Sedwin short port; 115174891Sedwin short retry; 116174891Sedwin short nblk; 117174891Sedwin int sz; 118174891Sedwin u_long skip; 119174891Sedwin struct buf *bp; 120174891Sedwin int p_offset; 121223925Sdelphij short count; 122174891Sedwin}; 123174891Sedwin 124174891Sedwinstruct mcd_data { 125174891Sedwin short config; 126174891Sedwin short flags; 127174891Sedwin short status; 128174891Sedwin int blksize; 129208986Sbz u_long disksize; 130174891Sedwin int iobase; 131174891Sedwin struct disklabel dlabel; 132174891Sedwin int partflags[MAXPARTITIONS]; 133174891Sedwin int openflags; 134174891Sedwin struct mcd_volinfo volinfo; 135174891Sedwin#ifndef MCDMINI 136174891Sedwin struct mcd_qchninfo toc[MCD_MAXTOCS]; 137174891Sedwin short audio_status; 138174891Sedwin struct mcd_read2 lastpb; 139174891Sedwin#endif 140174891Sedwin short debug; 141174891Sedwin struct buf head; /* head of buf queue */ 142174891Sedwin struct mcd_mbx mbx; 143174891Sedwin} mcd_data[NMCD]; 144174891Sedwin 145174891Sedwin/* reader state machine */ 146174891Sedwin#define MCD_S_BEGIN 0 147174891Sedwin#define MCD_S_BEGIN1 1 148174891Sedwin#define MCD_S_WAITSTAT 2 149174891Sedwin#define MCD_S_WAITMODE 3 150174891Sedwin#define MCD_S_WAITREAD 4 151174891Sedwin 152174891Sedwin/* prototypes */ 153174891Sedwinint mcdopen(dev_t dev); 154174891Sedwinint mcdclose(dev_t dev); 155174891Sedwinvoid mcdstrategy(struct buf *bp); 156174891Sedwinint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 157174891Sedwinint mcdsize(dev_t dev); 158174891Sedwinstatic void mcd_done(struct mcd_mbx *mbx); 159174891Sedwinstatic void mcd_start(int unit); 160174891Sedwinstatic int mcd_getdisklabel(int unit); 161174891Sedwinstatic void mcd_configure(struct mcd_data *cd); 162174891Sedwinstatic int mcd_get(int unit, char *buf, int nmax); 163174891Sedwinstatic void mcd_setflags(int unit,struct mcd_data *cd); 164174891Sedwinstatic int mcd_getstat(int unit,int sflg); 165174891Sedwinstatic int mcd_send(int unit, int cmd,int nretrys); 166174891Sedwinstatic int bcd2bin(bcd_t b); 167174891Sedwinstatic bcd_t bin2bcd(int b); 168174891Sedwinstatic void hsg2msf(int hsg, bcd_t *msf); 169174891Sedwinstatic int msf2hsg(bcd_t *msf); 170174891Sedwinstatic int mcd_volinfo(int unit); 171174891Sedwinstatic int mcd_waitrdy(int port,int dly); 172174891Sedwinstatic void mcd_doread(int state, struct mcd_mbx *mbxin); 173174891Sedwin#ifndef MCDMINI 174174891Sedwinstatic int mcd_setmode(int unit, int mode); 175174891Sedwinstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q); 176174891Sedwinstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 177174891Sedwinstatic int mcd_toc_header(int unit, struct ioc_toc_header *th); 178174891Sedwinstatic int mcd_read_toc(int unit); 179174891Sedwinstatic int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); 180174891Sedwinstatic int mcd_stop(int unit); 181174891Sedwinstatic int mcd_playtracks(int unit, struct ioc_play_track *pt); 182174891Sedwinstatic int mcd_play(int unit, struct mcd_read2 *pb); 183174891Sedwinstatic int mcd_pause(int unit); 184174891Sedwinstatic int mcd_resume(int unit); 185174891Sedwin#endif 186174891Sedwin 187174891Sedwinextern int hz; 188174891Sedwinextern int mcd_probe(struct isa_device *dev); 189174891Sedwinextern int mcd_attach(struct isa_device *dev); 190174891Sedwinstruct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 191174891Sedwin 192174891Sedwin#define mcd_put(port,byte) outb(port,byte) 193174891Sedwin 194174891Sedwin#define MCD_RETRYS 5 195174891Sedwin#define MCD_RDRETRYS 8 196174891Sedwin 197174891Sedwin#define MCDBLK 2048 /* for cooked mode */ 198174891Sedwin#define MCDRBLK 2352 /* for raw mode */ 199174891Sedwin 200223925Sdelphij/* several delays */ 201174891Sedwin#define RDELAY_WAITSTAT 300 202174891Sedwin#define RDELAY_WAITMODE 300 203174891Sedwin#define RDELAY_WAITREAD 800 204174891Sedwin 205174891Sedwin#define DELAY_STATUS 10000l /* 10000 * 1us */ 206#define DELAY_GETREPLY 200000l /* 200000 * 2us */ 207#define DELAY_SEEKREAD 20000l /* 20000 * 1us */ 208#define mcd_delay DELAY 209 210int mcd_attach(struct isa_device *dev) 211{ 212 struct mcd_data *cd = mcd_data + dev->id_unit; 213 int i; 214 215 cd->iobase = dev->id_iobase; 216 cd->flags |= MCDINIT; 217 cd->openflags = 0; 218 for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 219 220#ifdef NOTYET 221 /* wire controller for interrupts and dma */ 222 mcd_configure(cd); 223#endif 224 225 return 1; 226} 227 228int mcdopen(dev_t dev) 229{ 230 int unit,part,phys; 231 struct mcd_data *cd; 232 233 unit = mcd_unit(dev); 234 if (unit >= NMCD) 235 return ENXIO; 236 237 cd = mcd_data + unit; 238 part = mcd_part(dev); 239 phys = mcd_phys(dev); 240 241 /* not initialized*/ 242 if (!(cd->flags & MCDINIT)) 243 return ENXIO; 244 245 /* invalidated in the meantime? mark all open part's invalid */ 246 if (!(cd->flags & MCDVALID) && cd->openflags) 247 return ENXIO; 248 249 if (mcd_getstat(unit,1) < 0) 250 return ENXIO; 251 252 /* XXX get a default disklabel */ 253 mcd_getdisklabel(unit); 254 255 if (mcdsize(dev) < 0) { 256 printf("mcd%d: failed to get disk size\n",unit); 257 return ENXIO; 258 } else 259 cd->flags |= MCDVALID; 260 261MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 262 part,cd->disksize,cd->blksize,0); 263 264 if (part == RAW_PART || 265 (part < cd->dlabel.d_npartitions && 266 cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 267 cd->partflags[part] |= MCDOPEN; 268 cd->openflags |= (1<<part); 269 if (part == RAW_PART && phys != 0) 270 cd->partflags[part] |= MCDREADRAW; 271 return 0; 272 } 273 274 return ENXIO; 275} 276 277int mcdclose(dev_t dev) 278{ 279 int unit,part,phys; 280 struct mcd_data *cd; 281 282 unit = mcd_unit(dev); 283 if (unit >= NMCD) 284 return ENXIO; 285 286 cd = mcd_data + unit; 287 part = mcd_part(dev); 288 phys = mcd_phys(dev); 289 290 if (!(cd->flags & MCDINIT)) 291 return ENXIO; 292 293 mcd_getstat(unit,1); /* get status */ 294 295 /* close channel */ 296 cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 297 cd->openflags &= ~(1<<part); 298 MCD_TRACE("close: partition=%d\n",part,0,0,0); 299 300 return 0; 301} 302 303void 304mcdstrategy(struct buf *bp) 305{ 306 struct mcd_data *cd; 307 struct buf *qp; 308 int s; 309 310 int unit = mcd_unit(bp->b_dev); 311 312 cd = mcd_data + unit; 313 314 /* test validity */ 315/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 316 bp,unit,bp->b_blkno,bp->b_bcount);*/ 317 if (unit >= NMCD || bp->b_blkno < 0) { 318 printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 319 unit, bp->b_blkno, bp->b_bcount); 320 pg("mcd: mcdstratregy failure"); 321 bp->b_error = EINVAL; 322 bp->b_flags |= B_ERROR; 323 goto bad; 324 } 325 326 /* if device invalidated (e.g. media change, door open), error */ 327 if (!(cd->flags & MCDVALID)) { 328MCD_TRACE("strategy: drive not valid\n",0,0,0,0); 329 bp->b_error = EIO; 330 goto bad; 331 } 332 333 /* read only */ 334 if (!(bp->b_flags & B_READ)) { 335 bp->b_error = EROFS; 336 goto bad; 337 } 338 339 /* no data to read */ 340 if (bp->b_bcount == 0) 341 goto done; 342 343 /* for non raw access, check partition limits */ 344 if (mcd_part(bp->b_dev) != RAW_PART) { 345 if (!(cd->flags & MCDLABEL)) { 346 bp->b_error = EIO; 347 goto bad; 348 } 349 /* adjust transfer if necessary */ 350 if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 351 goto done; 352 } 353 } else { 354 bp->b_pblkno = bp->b_blkno; 355 bp->b_cylin = 0; 356 } 357 358 /* queue it */ 359 qp = &cd->head; 360 s = splbio(); 361 disksort(qp,bp); 362 splx(s); 363 364 /* now check whether we can perform processing */ 365 mcd_start(unit); 366 return; 367 368bad: 369 bp->b_flags |= B_ERROR; 370done: 371 bp->b_resid = bp->b_bcount; 372 biodone(bp); 373 return; 374} 375 376static void mcd_start(int unit) 377{ 378 struct mcd_data *cd = mcd_data + unit; 379 struct buf *bp, *qp = &cd->head; 380 struct partition *p; 381 int part; 382 register s = splbio(); 383 384 if (cd->flags & MCDMBXBSY) 385 return; 386 387 if ((bp = qp->b_actf) != 0) { 388 /* block found to process, dequeue */ 389 /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 390 qp->b_actf = bp->av_forw; 391 splx(s); 392 } else { 393 /* nothing to do */ 394 splx(s); 395 return; 396 } 397 398 /* changed media? */ 399 if (!(cd->flags & MCDVALID)) { 400 MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 401 return; 402 } 403 404 p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 405 406 cd->flags |= MCDMBXBSY; 407 cd->mbx.unit = unit; 408 cd->mbx.port = cd->iobase; 409 cd->mbx.retry = MCD_RETRYS; 410 cd->mbx.bp = bp; 411 cd->mbx.p_offset = p->p_offset; 412 413 /* calling the read routine */ 414 mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 415 /* triggers mcd_start, when successful finished */ 416 return; 417} 418 419int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 420{ 421 struct mcd_data *cd; 422 int unit,part; 423 424 unit = mcd_unit(dev); 425 part = mcd_part(dev); 426 cd = mcd_data + unit; 427 428#ifdef MCDMINI 429 return ENOTTY; 430#else 431 if (!(cd->flags & MCDVALID)) 432 return EIO; 433MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 434 435 switch (cmd) { 436 case DIOCSBAD: 437 return EINVAL; 438 case DIOCGDINFO: 439 case DIOCGPART: 440 case DIOCWDINFO: 441 case DIOCSDINFO: 442 case DIOCWLABEL: 443 return ENOTTY; 444 case CDIOCPLAYTRACKS: 445 return mcd_playtracks(unit, (struct ioc_play_track *) addr); 446 case CDIOCPLAYBLOCKS: 447 return mcd_play(unit, (struct mcd_read2 *) addr); 448 case CDIOCREADSUBCHANNEL: 449 return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 450 case CDIOREADTOCHEADER: 451 return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 452 case CDIOREADTOCENTRYS: 453 return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); 454 case CDIOCSETPATCH: 455 case CDIOCGETVOL: 456 case CDIOCSETVOL: 457 case CDIOCSETMONO: 458 case CDIOCSETSTERIO: 459 case CDIOCSETMUTE: 460 case CDIOCSETLEFT: 461 case CDIOCSETRIGHT: 462 return EINVAL; 463 case CDIOCRESUME: 464 return mcd_resume(unit); 465 case CDIOCPAUSE: 466 return mcd_pause(unit); 467 case CDIOCSTART: 468 return EINVAL; 469 case CDIOCSTOP: 470 return mcd_stop(unit); 471 case CDIOCEJECT: 472 return EINVAL; 473 case CDIOCSETDEBUG: 474 cd->debug = 1; 475 return 0; 476 case CDIOCCLRDEBUG: 477 cd->debug = 0; 478 return 0; 479 case CDIOCRESET: 480 return EINVAL; 481 default: 482 return ENOTTY; 483 } 484 /*NOTREACHED*/ 485#endif /*!MCDMINI*/ 486} 487 488/* this could have been taken from scsi/cd.c, but it is not clear 489 * whether the scsi cd driver is linked in 490 */ 491static int mcd_getdisklabel(int unit) 492{ 493 struct mcd_data *cd = mcd_data + unit; 494 495 if (cd->flags & MCDLABEL) 496 return -1; 497 498 bzero(&cd->dlabel,sizeof(struct disklabel)); 499 strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); 500 strncpy(cd->dlabel.d_packname,"unknown ",16); 501 cd->dlabel.d_secsize = cd->blksize; 502 cd->dlabel.d_nsectors = 100; 503 cd->dlabel.d_ntracks = 1; 504 cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 505 cd->dlabel.d_secpercyl = 100; 506 cd->dlabel.d_secperunit = cd->disksize; 507 cd->dlabel.d_rpm = 300; 508 cd->dlabel.d_interleave = 1; 509 cd->dlabel.d_flags = D_REMOVABLE; 510 cd->dlabel.d_npartitions= 1; 511 cd->dlabel.d_partitions[0].p_offset = 0; 512 cd->dlabel.d_partitions[0].p_size = cd->disksize; 513 cd->dlabel.d_partitions[0].p_fstype = 9; 514 cd->dlabel.d_magic = DISKMAGIC; 515 cd->dlabel.d_magic2 = DISKMAGIC; 516 cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 517 518 cd->flags |= MCDLABEL; 519 return 0; 520} 521 522int mcdsize(dev_t dev) 523{ 524 int size; 525 int unit = mcd_unit(dev); 526 struct mcd_data *cd = mcd_data + unit; 527 528 if (mcd_volinfo(unit) >= 0) { 529 cd->blksize = MCDBLK; 530 size = msf2hsg(cd->volinfo.vol_msf); 531 cd->disksize = size * (MCDBLK/DEV_BSIZE); 532 return 0; 533 } 534 return -1; 535} 536 537/*************************************************************** 538 * lower level of driver starts here 539 **************************************************************/ 540 541#ifdef NOTDEF 542static char 543irqs[] = { 544 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 545 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 546}; 547 548static char 549drqs[] = { 550 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 551}; 552#endif 553 554static void 555mcd_configure(struct mcd_data *cd) 556{ 557 outb(cd->iobase+mcd_config,cd->config); 558} 559 560/* Wait for non-busy - return 0 on timeout */ 561static int 562twiddle_thumbs(int port, int unit, int count, char *whine) 563{ 564 int i; 565 566 for (i = 0; i < count; i++) { 567 if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) { 568 return 1; 569 } 570 } 571#ifdef MCD_TO_WARNING_ON 572 printf("mcd%d: timeout %s\n", unit, whine); 573#endif 574 return 0; 575} 576 577/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 578 579int 580mcd_probe(struct isa_device *dev) 581{ 582 int port = dev->id_iobase; 583 int unit = dev->id_unit; 584 int i, j; 585 int status; 586 unsigned char stbytes[3]; 587 588 mcd_data[unit].flags = MCDPROBING; 589 590#ifdef NOTDEF 591 /* get irq/drq configuration word */ 592 mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 593#else 594 mcd_data[unit].config = 0; 595#endif 596 597 /* send a reset */ 598 outb(port+MCD_FLAGS, M_RESET); 599 600 /* 601 * delay awhile by getting any pending garbage (old data) and 602 * throwing it away. 603 */ 604 for (i = 1000000; i != 0; i--) { 605 inb(port+MCD_FLAGS); 606 } 607 608 /* Get status */ 609 outb(port+MCD_DATA, MCD_CMDGETSTAT); 610 if (!twiddle_thumbs(port, unit, 1000000, "getting status")) { 611 return 0; /* Timeout */ 612 } 613 status = inb(port+MCD_DATA); 614 if (status != MCDCDABSENT && status != MCDCDPRESENT && 615 status != MCDSOPEN && status != MCDSCLOSED) 616 return 0; /* Not actually a Mitsumi drive here */ 617 /* Get version information */ 618 outb(port+MCD_DATA, MCD_CMDCONTINFO); 619 for (j = 0; j < 3; j++) { 620 if (!twiddle_thumbs(port, unit, 3000, "getting version info")) { 621 return 0; 622 } 623 stbytes[j] = (inb(port+MCD_DATA) & 0xFF); 624 } 625 printf("mcd%d: version information is %x %c %x\n", unit, 626 stbytes[0], stbytes[1], stbytes[2]); 627 if (stbytes[1] >= 4) { 628 outb(port+MCD_CTRL, M_PICKLE); 629 printf("mcd%d: Adjusted for newer drive model\n", unit); 630 } 631 return 4; 632} 633 634 635static int 636mcd_waitrdy(int port,int dly) 637{ 638 int i; 639 640 /* wait until xfer port senses data ready */ 641 for (i=0; i<dly; i++) { 642 if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0) 643 return 0; 644 mcd_delay(1); 645 } 646 return -1; 647} 648 649static int 650mcd_getreply(int unit,int dly) 651{ 652 int i; 653 struct mcd_data *cd = mcd_data + unit; 654 int port = cd->iobase; 655 656 /* wait data to become ready */ 657 if (mcd_waitrdy(port,dly)<0) { 658#ifdef MCD_TO_WARNING_ON 659 printf("mcd%d: timeout getreply\n",unit); 660#endif 661 return -1; 662 } 663 664 /* get the data */ 665 return inb(port+mcd_status) & 0xFF; 666} 667 668static int 669mcd_getstat(int unit,int sflg) 670{ 671 int i; 672 struct mcd_data *cd = mcd_data + unit; 673 int port = cd->iobase; 674 675 /* get the status */ 676 if (sflg) 677 outb(port+mcd_command, MCD_CMDGETSTAT); 678 i = mcd_getreply(unit,DELAY_GETREPLY); 679 if (i<0) return -1; 680 681 cd->status = i; 682 683 mcd_setflags(unit,cd); 684 return cd->status; 685} 686 687static void 688mcd_setflags(int unit, struct mcd_data *cd) 689{ 690 /* check flags */ 691 if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { 692 MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); 693 cd->flags &= ~MCDVALID; 694 } 695 696#ifndef MCDMINI 697 if (cd->status & MCDAUDIOBSY) 698 cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 699 else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 700 cd->audio_status = CD_AS_PLAY_COMPLETED; 701#endif 702} 703 704static int 705mcd_get(int unit, char *buf, int nmax) 706{ 707 int port = mcd_data[unit].iobase; 708 int i,k; 709 710 for (i=0; i<nmax; i++) { 711 /* wait for data */ 712 if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 713#ifdef MCD_TO_WARNING_ON 714 printf("mcd%d: timeout mcd_get\n",unit); 715#endif 716 return -1; 717 } 718 buf[i] = k; 719 } 720 return i; 721} 722 723static int 724mcd_send(int unit, int cmd,int nretrys) 725{ 726 int i,k; 727 int port = mcd_data[unit].iobase; 728 729/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/ 730 for (i=0; i<nretrys; i++) { 731 outb(port+mcd_command, cmd); 732 if ((k=mcd_getstat(unit,0)) != -1) { 733 break; 734 } 735 } 736 if (i == nretrys) { 737 printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 738 return -1; 739 } 740/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/ 741 return 0; 742} 743 744static int 745bcd2bin(bcd_t b) 746{ 747 return (b >> 4) * 10 + (b & 15); 748} 749 750static bcd_t 751bin2bcd(int b) 752{ 753 return ((b / 10) << 4) | (b % 10); 754} 755 756static void 757hsg2msf(int hsg, bcd_t *msf) 758{ 759 hsg += 150; 760 M_msf(msf) = bin2bcd(hsg / 4500); 761 hsg %= 4500; 762 S_msf(msf) = bin2bcd(hsg / 75); 763 F_msf(msf) = bin2bcd(hsg % 75); 764} 765 766static int 767msf2hsg(bcd_t *msf) 768{ 769 return (bcd2bin(M_msf(msf)) * 60 + 770 bcd2bin(S_msf(msf))) * 75 + 771 bcd2bin(F_msf(msf)) - 150; 772} 773 774static int 775mcd_volinfo(int unit) 776{ 777 struct mcd_data *cd = mcd_data + unit; 778 int i; 779 780/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 781 782 /* Get the status, in case the disc has been changed */ 783 if (mcd_getstat(unit, 1) < 0) return EIO; 784 785 /* Just return if we already have it */ 786 if (cd->flags & MCDVOLINFO) return 0; 787 788 /* send volume info command */ 789 if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 790 return -1; 791 792 /* get data */ 793 if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 794 printf("mcd%d: mcd_volinfo: error read data\n",unit); 795 return -1; 796 } 797 798 if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { 799 cd->flags |= MCDVOLINFO; /* volinfo is OK */ 800 return 0; 801 } 802 803 return -1; 804} 805 806void 807mcdintr(unit) 808 int unit; 809{ 810 int port = mcd_data[unit].iobase; 811 u_int i; 812 813 MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); 814 815 /* just read out status and ignore the rest */ 816 if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { 817 i = inb(port+mcd_status); 818 } 819} 820 821/* state machine to process read requests 822 * initialize with MCD_S_BEGIN: calculate sizes, and read status 823 * MCD_S_WAITSTAT: wait for status reply, set mode 824 * MCD_S_WAITMODE: waits for status reply from set mode, set read command 825 * MCD_S_WAITREAD: wait for read ready, read data 826 */ 827static struct mcd_mbx *mbxsave; 828 829static void 830mcd_doread(int state, struct mcd_mbx *mbxin) 831{ 832 struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 833 int unit = mbx->unit; 834 int port = mbx->port; 835 struct buf *bp = mbx->bp; 836 struct mcd_data *cd = mcd_data + unit; 837 838 int rm,i,k; 839 struct mcd_read2 rbuf; 840 int blknum; 841 caddr_t addr; 842 843loop: 844 switch (state) { 845 case MCD_S_BEGIN: 846 mbx = mbxsave = mbxin; 847 848 case MCD_S_BEGIN1: 849 /* get status */ 850 outb(port+mcd_command, MCD_CMDGETSTAT); 851 mbx->count = RDELAY_WAITSTAT; 852 timeout((timeout_func_t)mcd_doread, 853 (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 854 return; 855 case MCD_S_WAITSTAT: 856 untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT); 857 if (mbx->count-- >= 0) { 858 if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 859 timeout((timeout_func_t)mcd_doread, 860 (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 861 return; 862 } 863 mcd_setflags(unit,cd); 864 MCD_TRACE("got WAITSTAT delay=%d\n", 865 RDELAY_WAITSTAT-mbx->count,0,0,0); 866 /* reject, if audio active */ 867 if (cd->status & MCDAUDIOBSY) { 868 printf("mcd%d: audio is active\n",unit); 869 goto readerr; 870 } 871 872 /* to check for raw/cooked mode */ 873 if (cd->flags & MCDREADRAW) { 874 rm = MCD_MD_RAW; 875 mbx->sz = MCDRBLK; 876 } else { 877 rm = MCD_MD_COOKED; 878 mbx->sz = cd->blksize; 879 } 880 881 mbx->count = RDELAY_WAITMODE; 882 883 mcd_put(port+mcd_command, MCD_CMDSETMODE); 884 mcd_put(port+mcd_command, rm); 885 timeout((timeout_func_t)mcd_doread, 886 (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */ 887 return; 888 } else { 889#ifdef MCD_TO_WARNING_ON 890 printf("mcd%d: timeout getstatus\n",unit); 891#endif 892 goto readerr; 893 } 894 895 case MCD_S_WAITMODE: 896 untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE); 897 if (mbx->count-- < 0) { 898#ifdef MCD_TO_WARNING_ON 899 printf("mcd%d: timeout set mode\n",unit); 900#endif 901 goto readerr; 902 } 903 if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 904 timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); 905 return; 906 } 907 mcd_setflags(unit,cd); 908 MCD_TRACE("got WAITMODE delay=%d\n", 909 RDELAY_WAITMODE-mbx->count,0,0,0); 910 /* for first block */ 911 mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 912 mbx->skip = 0; 913 914nextblock: 915 blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 916 + mbx->p_offset + mbx->skip/mbx->sz; 917 918 MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n", 919 blknum,bp,0,0); 920 921 /* build parameter block */ 922 hsg2msf(blknum,rbuf.start_msf); 923 924 /* send the read command */ 925 mcd_put(port+mcd_command,MCD_CMDREAD2); 926 mcd_put(port+mcd_command,rbuf.start_msf[0]); 927 mcd_put(port+mcd_command,rbuf.start_msf[1]); 928 mcd_put(port+mcd_command,rbuf.start_msf[2]); 929 mcd_put(port+mcd_command,0); 930 mcd_put(port+mcd_command,0); 931 mcd_put(port+mcd_command,1); 932 mbx->count = RDELAY_WAITREAD; 933 timeout((timeout_func_t)mcd_doread, 934 (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 935 return; 936 case MCD_S_WAITREAD: 937 untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD); 938 if (mbx->count-- > 0) { 939 k = inb(port+mcd_xfer); 940 if ((k & 2)==0) { 941 MCD_TRACE("got data delay=%d\n", 942 RDELAY_WAITREAD-mbx->count,0,0,0); 943 /* data is ready */ 944 addr = bp->b_un.b_addr + mbx->skip; 945 outb(port+mcd_ctl2,0x04); /* XXX */ 946 for (i=0; i<mbx->sz; i++) 947 *addr++ = inb(port+mcd_rdata); 948 outb(port+mcd_ctl2,0x0c); /* XXX */ 949 950 if (--mbx->nblk > 0) { 951 mbx->skip += mbx->sz; 952 goto nextblock; 953 } 954 955 /* return buffer */ 956 bp->b_resid = 0; 957 biodone(bp); 958 959 cd->flags &= ~MCDMBXBSY; 960 mcd_start(mbx->unit); 961 return; 962 } 963 if ((k & 4)==0) 964 mcd_getstat(unit,0); 965 timeout((timeout_func_t)mcd_doread, 966 (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 967 return; 968 } else { 969#ifdef MCD_TO_WARNING_ON 970 printf("mcd%d: timeout read data\n",unit); 971#endif 972 goto readerr; 973 } 974 } 975 976readerr: 977 if (mbx->retry-- > 0) { 978#ifdef MCD_TO_WARNING_ON 979 printf("mcd%d: retrying\n",unit); 980#endif 981 state = MCD_S_BEGIN1; 982 goto loop; 983 } 984 985 /* invalidate the buffer */ 986 bp->b_flags |= B_ERROR; 987 bp->b_resid = bp->b_bcount; 988 biodone(bp); 989 mcd_start(mbx->unit); 990 return; 991 992#ifdef NOTDEF 993 printf("mcd%d: unit timeout, resetting\n",mbx->unit); 994 outb(mbx->port+mcd_reset,MCD_CMDRESET); 995 DELAY(300000); 996 (void)mcd_getstat(mbx->unit,1); 997 (void)mcd_getstat(mbx->unit,1); 998 /*cd->status &= ~MCDDSKCHNG; */ 999 cd->debug = 1; /* preventive set debug mode */ 1000 1001#endif 1002 1003} 1004 1005#ifndef MCDMINI 1006static int 1007mcd_setmode(int unit, int mode) 1008{ 1009 struct mcd_data *cd = mcd_data + unit; 1010 int port = cd->iobase; 1011 int retry; 1012 1013 printf("mcd%d: setting mode to %d\n", unit, mode); 1014 for(retry=0; retry<MCD_RETRYS; retry++) 1015 { 1016 outb(port+mcd_command, MCD_CMDSETMODE); 1017 outb(port+mcd_command, mode); 1018 if (mcd_getstat(unit, 0) != -1) return 0; 1019 } 1020 1021 return -1; 1022} 1023 1024static int 1025mcd_toc_header(int unit, struct ioc_toc_header *th) 1026{ 1027 struct mcd_data *cd = mcd_data + unit; 1028 1029 if (mcd_volinfo(unit) < 0) { 1030 return ENXIO; 1031 } 1032 1033 th->len = msf2hsg(cd->volinfo.vol_msf); 1034 th->starting_track = bcd2bin(cd->volinfo.trk_low); 1035 th->ending_track = bcd2bin(cd->volinfo.trk_high); 1036 1037 return 0; 1038} 1039 1040static int 1041mcd_read_toc(int unit) 1042{ 1043 struct mcd_data *cd = mcd_data + unit; 1044 struct ioc_toc_header th; 1045 struct mcd_qchninfo q; 1046 int rc, trk, idx, retry; 1047 1048 /* Only read TOC if needed */ 1049 if (cd->flags & MCDTOC) { 1050 return 0; 1051 } 1052 1053 printf("mcd%d: reading toc header\n", unit); 1054 if (mcd_toc_header(unit, &th) != 0) { 1055 return ENXIO; 1056 } 1057 1058 printf("mcd%d: stopping play\n", unit); 1059 if ((rc=mcd_stop(unit)) != 0) { 1060 return rc; 1061 } 1062 1063 /* try setting the mode twice */ 1064 if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1065 return EIO; 1066 } 1067 if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1068 return EIO; 1069 } 1070 1071 printf("mcd%d: get_toc reading qchannel info\n",unit); 1072 for(trk=th.starting_track; trk<=th.ending_track; trk++) 1073 cd->toc[trk].idx_no = 0; 1074 trk = th.ending_track - th.starting_track + 1; 1075 for(retry=0; retry<300 && trk>0; retry++) 1076 { 1077 if (mcd_getqchan(unit, &q) < 0) break; 1078 idx = bcd2bin(q.idx_no); 1079 if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) { 1080 if (cd->toc[idx].idx_no == 0) { 1081 cd->toc[idx] = q; 1082 trk--; 1083 } 1084 } 1085 } 1086 1087 if (mcd_setmode(unit, MCD_MD_COOKED) != 0) { 1088 return EIO; 1089 } 1090 1091 if (trk != 0) { 1092 return ENXIO; 1093 } 1094 1095 /* add a fake last+1 */ 1096 idx = th.ending_track + 1; 1097 cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1098 cd->toc[idx].trk_no = 0; 1099 cd->toc[idx].idx_no = 0xAA; 1100 cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1101 cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1102 cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1103 1104 cd->flags |= MCDTOC; 1105 1106 return 0; 1107} 1108 1109static int 1110mcd_toc_entry(int unit, struct ioc_read_toc_entry *te) 1111{ 1112 struct mcd_data *cd = mcd_data + unit; 1113 struct ret_toc { 1114 struct ioc_toc_header th; 1115 struct cd_toc_entry rt; 1116 } ret_toc; 1117 struct ioc_toc_header th; 1118 int rc, i; 1119 1120 /* Make sure we have a valid toc */ 1121 if ((rc=mcd_read_toc(unit)) != 0) { 1122 return rc; 1123 } 1124 1125 /* find the toc to copy*/ 1126 i = te->starting_track; 1127 if (i == MCD_LASTPLUS1) { 1128 i = bcd2bin(cd->volinfo.trk_high) + 1; 1129 } 1130 1131 /* verify starting track */ 1132 if (i < bcd2bin(cd->volinfo.trk_low) || 1133 i > bcd2bin(cd->volinfo.trk_high)+1) { 1134 return EINVAL; 1135 } 1136 1137 /* do we have room */ 1138 if (te->data_len < sizeof(struct ioc_toc_header) + 1139 sizeof(struct cd_toc_entry)) { 1140 return EINVAL; 1141 } 1142 1143 /* Copy the toc header */ 1144 if (mcd_toc_header(unit, &th) < 0) { 1145 return EIO; 1146 } 1147 ret_toc.th = th; 1148 1149 /* copy the toc data */ 1150 ret_toc.rt.control = cd->toc[i].ctrl_adr; 1151 ret_toc.rt.addr_type = te->address_format; 1152 ret_toc.rt.track = i; 1153 if (te->address_format == CD_MSF_FORMAT) { 1154 ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0]; 1155 ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1]; 1156 ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2]; 1157 } 1158 1159 /* copy the data back */ 1160 copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) 1161 + sizeof(struct ioc_toc_header)); 1162 1163 return 0; 1164} 1165 1166static int 1167mcd_stop(int unit) 1168{ 1169 struct mcd_data *cd = mcd_data + unit; 1170 1171 if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) { 1172 return ENXIO; 1173 } 1174 cd->audio_status = CD_AS_PLAY_COMPLETED; 1175 return 0; 1176} 1177 1178static int 1179mcd_getqchan(int unit, struct mcd_qchninfo *q) 1180{ 1181 struct mcd_data *cd = mcd_data + unit; 1182 1183 if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) { 1184 return -1; 1185 } 1186 if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) { 1187 return -1; 1188 } 1189 if (cd->debug) { 1190 printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", 1191 unit, 1192 q->ctrl_adr, q->trk_no, q->idx_no, 1193 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], 1194 q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); 1195 } 1196 return 0; 1197} 1198 1199static int 1200mcd_subchan(int unit, struct ioc_read_subchannel *sc) 1201{ 1202 struct mcd_data *cd = mcd_data + unit; 1203 struct mcd_qchninfo q; 1204 struct cd_sub_channel_info data; 1205 1206 printf("mcd%d: subchan af=%d, df=%d\n", unit, 1207 sc->address_format, 1208 sc->data_format); 1209 if (sc->address_format != CD_MSF_FORMAT) { 1210 return EIO; 1211 } 1212 if (sc->data_format != CD_CURRENT_POSITION) { 1213 return EIO; 1214 } 1215 if (mcd_getqchan(unit, &q) < 0) { 1216 return EIO; 1217 } 1218 1219 data.header.audio_status = cd->audio_status; 1220 data.what.position.data_format = CD_MSF_FORMAT; 1221 data.what.position.track_number = bcd2bin(q.trk_no); 1222 1223 if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) { 1224 return EFAULT; 1225 } 1226 return 0; 1227} 1228 1229static int 1230mcd_playtracks(int unit, struct ioc_play_track *pt) 1231{ 1232 struct mcd_data *cd = mcd_data + unit; 1233 struct mcd_read2 pb; 1234 int a = pt->start_track; 1235 int z = pt->end_track; 1236 int rc; 1237 1238 if ((rc = mcd_read_toc(unit)) != 0) { 1239 return rc; 1240 } 1241 printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 1242 a, pt->start_index, z, pt->end_index); 1243 1244 if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || 1245 z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) { 1246 return EINVAL; 1247 } 1248 1249 pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; 1250 pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; 1251 pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; 1252 pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; 1253 pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; 1254 pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; 1255 1256 return mcd_play(unit, &pb); 1257} 1258 1259static int 1260mcd_play(int unit, struct mcd_read2 *pb) 1261{ 1262 struct mcd_data *cd = mcd_data + unit; 1263 int port = cd->iobase; 1264 int retry, st; 1265 1266 cd->lastpb = *pb; 1267 for(retry=0; retry<MCD_RETRYS; retry++) { 1268 outb(port+mcd_command, MCD_CMDREAD2); 1269 outb(port+mcd_command, pb->start_msf[0]); 1270 outb(port+mcd_command, pb->start_msf[1]); 1271 outb(port+mcd_command, pb->start_msf[2]); 1272 outb(port+mcd_command, pb->end_msf[0]); 1273 outb(port+mcd_command, pb->end_msf[1]); 1274 outb(port+mcd_command, pb->end_msf[2]); 1275 if ((st=mcd_getstat(unit, 0)) != -1) { 1276 break; 1277 } 1278 } 1279 1280 if (cd->debug) { 1281 printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); 1282 } 1283 if (st == -1) { 1284 return ENXIO; 1285 } 1286 cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1287 return 0; 1288} 1289 1290static int 1291mcd_pause(int unit) 1292{ 1293 struct mcd_data *cd = mcd_data + unit; 1294 struct mcd_qchninfo q; 1295 int rc; 1296 1297 /* Verify current status */ 1298 if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { 1299 printf("mcd%d: pause attempted when not playing\n", unit); 1300 return EINVAL; 1301 } 1302 1303 /* Get the current position */ 1304 if (mcd_getqchan(unit, &q) < 0) { 1305 return EIO; 1306 } 1307 1308 /* Copy it into lastpb */ 1309 cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1310 cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1311 cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1312 1313 /* Stop playing */ 1314 if ((rc=mcd_stop(unit)) != 0) { 1315 return rc; 1316 } 1317 1318 /* Set the proper status and exit */ 1319 cd->audio_status = CD_AS_PLAY_PAUSED; 1320 return 0; 1321} 1322 1323static int 1324mcd_resume(int unit) 1325{ 1326 struct mcd_data *cd = mcd_data + unit; 1327 1328 if (cd->audio_status != CD_AS_PLAY_PAUSED) { 1329 return EINVAL; 1330 } 1331 return mcd_play(unit, &cd->lastpb); 1332} 1333#endif /*!MCDMINI*/ 1334 1335#endif /* NMCD > 0 */ 1336