mcd.c revision 1197
1578Srgrimes/* 2578Srgrimes * Copyright 1993 by Holger Veit (data part) 3578Srgrimes * Copyright 1993 by Brian Moore (audio part) 41197Srgrimes * Changes Copyright 1993 by Gary Clark II 51197Srgrimes * 61197Srgrimes * Rewrote probe routine to work on newer Mitsumi drives. 71197Srgrimes * Additional changes (C) 1994 by Jordan K. Hubbard 81197Srgrimes * 9578Srgrimes * All rights reserved. 10578Srgrimes * 11578Srgrimes * Redistribution and use in source and binary forms, with or without 12578Srgrimes * modification, are permitted provided that the following conditions 13578Srgrimes * are met: 14578Srgrimes * 1. Redistributions of source code must retain the above copyright 15578Srgrimes * notice, this list of conditions and the following disclaimer. 16578Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 17578Srgrimes * notice, this list of conditions and the following disclaimer in the 18578Srgrimes * documentation and/or other materials provided with the distribution. 19578Srgrimes * 3. All advertising materials mentioning features or use of this software 20578Srgrimes * must display the following acknowledgement: 21578Srgrimes * This software was developed by Holger Veit and Brian Moore 221197Srgrimes * for use with "386BSD" and similar operating systems. 23578Srgrimes * "Similar operating systems" includes mainly non-profit oriented 24578Srgrimes * systems for research and education, including but not restricted to 25578Srgrimes * "NetBSD", "FreeBSD", "Mach" (by CMU). 26578Srgrimes * 4. Neither the name of the developer(s) nor the name "386BSD" 27578Srgrimes * may be used to endorse or promote products derived from this 28578Srgrimes * software without specific prior written permission. 29578Srgrimes * 30578Srgrimes * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 31578Srgrimes * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32578Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33578Srgrimes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 34578Srgrimes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 35578Srgrimes * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 36578Srgrimes * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 37578Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38578Srgrimes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39578Srgrimes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 40578Srgrimes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41578Srgrimes * 421197Srgrimes * $Id: mcd.c,v 1.9 1994/02/07 15:46:22 davidg Exp $ 43578Srgrimes */ 44578Srgrimesstatic char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 45578Srgrimes 46578Srgrimes#include "mcd.h" 47578Srgrimes#if NMCD > 0 48578Srgrimes#include "types.h" 49578Srgrimes#include "param.h" 50578Srgrimes#include "systm.h" 51578Srgrimes#include "conf.h" 52578Srgrimes#include "file.h" 53578Srgrimes#include "buf.h" 54578Srgrimes#include "stat.h" 55578Srgrimes#include "uio.h" 56578Srgrimes#include "ioctl.h" 57578Srgrimes#include "cdio.h" 58578Srgrimes#include "errno.h" 59578Srgrimes#include "dkbad.h" 60578Srgrimes#include "disklabel.h" 61578Srgrimes#include "i386/isa/isa.h" 62578Srgrimes#include "i386/isa/isa_device.h" 63578Srgrimes#include "mcdreg.h" 64578Srgrimes 65578Srgrimes/* user definable options */ 66578Srgrimes/*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ 67578Srgrimes/*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ 68578Srgrimes 69578Srgrimes 70578Srgrimes#ifdef MCDMINI 71578Srgrimes#define MCD_TRACE(fmt,a,b,c,d) 72578Srgrimes#ifdef MCD_TO_WARNING_ON 73578Srgrimes#undef MCD_TO_WARNING_ON 74578Srgrimes#endif 75578Srgrimes#else 76978Sjkh#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);}} 77578Srgrimes#endif 78578Srgrimes 79578Srgrimes#define mcd_part(dev) ((minor(dev)) & 7) 80578Srgrimes#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) 81578Srgrimes#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) 82578Srgrimes#define RAW_PART 3 83578Srgrimes 84578Srgrimes/* flags */ 85578Srgrimes#define MCDOPEN 0x0001 /* device opened */ 86578Srgrimes#define MCDVALID 0x0002 /* parameters loaded */ 87578Srgrimes#define MCDINIT 0x0004 /* device is init'd */ 88578Srgrimes#define MCDWAIT 0x0008 /* waiting for something */ 89578Srgrimes#define MCDLABEL 0x0010 /* label is read */ 90578Srgrimes#define MCDPROBING 0x0020 /* probing */ 91578Srgrimes#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ 92578Srgrimes#define MCDVOLINFO 0x0080 /* already read volinfo */ 93578Srgrimes#define MCDTOC 0x0100 /* already read toc */ 94578Srgrimes#define MCDMBXBSY 0x0200 /* local mbx is busy */ 95578Srgrimes 96578Srgrimes/* status */ 97578Srgrimes#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 98578Srgrimes#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 99578Srgrimes#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 100578Srgrimes#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 101578Srgrimes 102578Srgrimes/* toc */ 103578Srgrimes#define MCD_MAXTOCS 104 /* from the Linux driver */ 104578Srgrimes#define MCD_LASTPLUS1 170 /* special toc entry */ 105578Srgrimes 106578Srgrimesstruct mcd_mbx { 107578Srgrimes short unit; 108578Srgrimes short port; 109578Srgrimes short retry; 110578Srgrimes short nblk; 111578Srgrimes int sz; 112578Srgrimes u_long skip; 113578Srgrimes struct buf *bp; 114578Srgrimes int p_offset; 115578Srgrimes short count; 116578Srgrimes}; 117578Srgrimes 118578Srgrimesstruct mcd_data { 119578Srgrimes short config; 120578Srgrimes short flags; 121578Srgrimes short status; 122578Srgrimes int blksize; 123578Srgrimes u_long disksize; 124578Srgrimes int iobase; 125578Srgrimes struct disklabel dlabel; 126578Srgrimes int partflags[MAXPARTITIONS]; 127578Srgrimes int openflags; 128578Srgrimes struct mcd_volinfo volinfo; 129578Srgrimes#ifndef MCDMINI 130578Srgrimes struct mcd_qchninfo toc[MCD_MAXTOCS]; 131578Srgrimes short audio_status; 132578Srgrimes struct mcd_read2 lastpb; 133578Srgrimes#endif 134578Srgrimes short debug; 135578Srgrimes struct buf head; /* head of buf queue */ 136578Srgrimes struct mcd_mbx mbx; 137578Srgrimes} mcd_data[NMCD]; 138578Srgrimes 139578Srgrimes/* reader state machine */ 140578Srgrimes#define MCD_S_BEGIN 0 141578Srgrimes#define MCD_S_BEGIN1 1 142578Srgrimes#define MCD_S_WAITSTAT 2 143578Srgrimes#define MCD_S_WAITMODE 3 144578Srgrimes#define MCD_S_WAITREAD 4 145578Srgrimes 146578Srgrimes/* prototypes */ 147578Srgrimesint mcdopen(dev_t dev); 148578Srgrimesint mcdclose(dev_t dev); 149798Swollmanvoid mcdstrategy(struct buf *bp); 150578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 151578Srgrimesint mcdsize(dev_t dev); 152578Srgrimesstatic void mcd_done(struct mcd_mbx *mbx); 153578Srgrimesstatic void mcd_start(int unit); 154578Srgrimesstatic int mcd_getdisklabel(int unit); 155578Srgrimesstatic void mcd_configure(struct mcd_data *cd); 156578Srgrimesstatic int mcd_get(int unit, char *buf, int nmax); 157578Srgrimesstatic void mcd_setflags(int unit,struct mcd_data *cd); 158578Srgrimesstatic int mcd_getstat(int unit,int sflg); 159578Srgrimesstatic int mcd_send(int unit, int cmd,int nretrys); 160578Srgrimesstatic int bcd2bin(bcd_t b); 161578Srgrimesstatic bcd_t bin2bcd(int b); 162578Srgrimesstatic void hsg2msf(int hsg, bcd_t *msf); 163578Srgrimesstatic int msf2hsg(bcd_t *msf); 164578Srgrimesstatic int mcd_volinfo(int unit); 165578Srgrimesstatic int mcd_waitrdy(int port,int dly); 166978Sjkhstatic void mcd_doread(int state, struct mcd_mbx *mbxin); 167578Srgrimes#ifndef MCDMINI 168578Srgrimesstatic int mcd_setmode(int unit, int mode); 169578Srgrimesstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q); 170578Srgrimesstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 171578Srgrimesstatic int mcd_toc_header(int unit, struct ioc_toc_header *th); 172578Srgrimesstatic int mcd_read_toc(int unit); 173578Srgrimesstatic int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); 174578Srgrimesstatic int mcd_stop(int unit); 175578Srgrimesstatic int mcd_playtracks(int unit, struct ioc_play_track *pt); 176578Srgrimesstatic int mcd_play(int unit, struct mcd_read2 *pb); 177578Srgrimesstatic int mcd_pause(int unit); 178578Srgrimesstatic int mcd_resume(int unit); 179578Srgrimes#endif 180578Srgrimes 181578Srgrimesextern int hz; 182578Srgrimesextern int mcd_probe(struct isa_device *dev); 183578Srgrimesextern int mcd_attach(struct isa_device *dev); 184578Srgrimesstruct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 185578Srgrimes 186578Srgrimes#define mcd_put(port,byte) outb(port,byte) 187578Srgrimes 188578Srgrimes#define MCD_RETRYS 5 189578Srgrimes#define MCD_RDRETRYS 8 190578Srgrimes 191578Srgrimes#define MCDBLK 2048 /* for cooked mode */ 192578Srgrimes#define MCDRBLK 2352 /* for raw mode */ 193578Srgrimes 194578Srgrimes/* several delays */ 195578Srgrimes#define RDELAY_WAITSTAT 300 196578Srgrimes#define RDELAY_WAITMODE 300 197578Srgrimes#define RDELAY_WAITREAD 800 198578Srgrimes 199578Srgrimes#define DELAY_STATUS 10000l /* 10000 * 1us */ 200578Srgrimes#define DELAY_GETREPLY 200000l /* 200000 * 2us */ 201578Srgrimes#define DELAY_SEEKREAD 20000l /* 20000 * 1us */ 202578Srgrimes#define mcd_delay DELAY 203578Srgrimes 204578Srgrimesint mcd_attach(struct isa_device *dev) 205578Srgrimes{ 206578Srgrimes struct mcd_data *cd = mcd_data + dev->id_unit; 207578Srgrimes int i; 208578Srgrimes 209578Srgrimes cd->iobase = dev->id_iobase; 210578Srgrimes cd->flags |= MCDINIT; 211578Srgrimes cd->openflags = 0; 212578Srgrimes for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 213578Srgrimes 214578Srgrimes#ifdef NOTYET 215578Srgrimes /* wire controller for interrupts and dma */ 216578Srgrimes mcd_configure(cd); 217578Srgrimes#endif 218578Srgrimes 219578Srgrimes return 1; 220578Srgrimes} 221578Srgrimes 222578Srgrimesint mcdopen(dev_t dev) 223578Srgrimes{ 224578Srgrimes int unit,part,phys; 225578Srgrimes struct mcd_data *cd; 226578Srgrimes 227578Srgrimes unit = mcd_unit(dev); 228578Srgrimes if (unit >= NMCD) 229578Srgrimes return ENXIO; 230578Srgrimes 231578Srgrimes cd = mcd_data + unit; 232578Srgrimes part = mcd_part(dev); 233578Srgrimes phys = mcd_phys(dev); 234578Srgrimes 235578Srgrimes /* not initialized*/ 236578Srgrimes if (!(cd->flags & MCDINIT)) 237578Srgrimes return ENXIO; 238578Srgrimes 239578Srgrimes /* invalidated in the meantime? mark all open part's invalid */ 240578Srgrimes if (!(cd->flags & MCDVALID) && cd->openflags) 241578Srgrimes return ENXIO; 242578Srgrimes 243578Srgrimes if (mcd_getstat(unit,1) < 0) 244578Srgrimes return ENXIO; 245578Srgrimes 246578Srgrimes /* XXX get a default disklabel */ 247578Srgrimes mcd_getdisklabel(unit); 248578Srgrimes 249578Srgrimes if (mcdsize(dev) < 0) { 250578Srgrimes printf("mcd%d: failed to get disk size\n",unit); 251578Srgrimes return ENXIO; 252578Srgrimes } else 253578Srgrimes cd->flags |= MCDVALID; 254578Srgrimes 255578SrgrimesMCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 256578Srgrimes part,cd->disksize,cd->blksize,0); 257578Srgrimes 258578Srgrimes if (part == RAW_PART || 259578Srgrimes (part < cd->dlabel.d_npartitions && 260578Srgrimes cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 261578Srgrimes cd->partflags[part] |= MCDOPEN; 262578Srgrimes cd->openflags |= (1<<part); 263578Srgrimes if (part == RAW_PART && phys != 0) 264578Srgrimes cd->partflags[part] |= MCDREADRAW; 265578Srgrimes return 0; 266578Srgrimes } 267578Srgrimes 268578Srgrimes return ENXIO; 269578Srgrimes} 270578Srgrimes 271578Srgrimesint mcdclose(dev_t dev) 272578Srgrimes{ 273578Srgrimes int unit,part,phys; 274578Srgrimes struct mcd_data *cd; 275578Srgrimes 276578Srgrimes unit = mcd_unit(dev); 277578Srgrimes if (unit >= NMCD) 278578Srgrimes return ENXIO; 279578Srgrimes 280578Srgrimes cd = mcd_data + unit; 281578Srgrimes part = mcd_part(dev); 282578Srgrimes phys = mcd_phys(dev); 283578Srgrimes 284578Srgrimes if (!(cd->flags & MCDINIT)) 285578Srgrimes return ENXIO; 286578Srgrimes 287578Srgrimes mcd_getstat(unit,1); /* get status */ 288578Srgrimes 289578Srgrimes /* close channel */ 290578Srgrimes cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 291578Srgrimes cd->openflags &= ~(1<<part); 292578Srgrimes MCD_TRACE("close: partition=%d\n",part,0,0,0); 293578Srgrimes 294578Srgrimes return 0; 295578Srgrimes} 296578Srgrimes 297798Swollmanvoid 298798Swollmanmcdstrategy(struct buf *bp) 299578Srgrimes{ 300578Srgrimes struct mcd_data *cd; 301578Srgrimes struct buf *qp; 302578Srgrimes int s; 303578Srgrimes 304578Srgrimes int unit = mcd_unit(bp->b_dev); 305578Srgrimes 306578Srgrimes cd = mcd_data + unit; 307578Srgrimes 308578Srgrimes /* test validity */ 309578Srgrimes/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 310578Srgrimes bp,unit,bp->b_blkno,bp->b_bcount);*/ 311578Srgrimes if (unit >= NMCD || bp->b_blkno < 0) { 312578Srgrimes printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 313578Srgrimes unit, bp->b_blkno, bp->b_bcount); 314578Srgrimes pg("mcd: mcdstratregy failure"); 315578Srgrimes bp->b_error = EINVAL; 316578Srgrimes bp->b_flags |= B_ERROR; 317578Srgrimes goto bad; 318578Srgrimes } 319578Srgrimes 320578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 321578Srgrimes if (!(cd->flags & MCDVALID)) { 322578SrgrimesMCD_TRACE("strategy: drive not valid\n",0,0,0,0); 323578Srgrimes bp->b_error = EIO; 324578Srgrimes goto bad; 325578Srgrimes } 326578Srgrimes 327578Srgrimes /* read only */ 328578Srgrimes if (!(bp->b_flags & B_READ)) { 329578Srgrimes bp->b_error = EROFS; 330578Srgrimes goto bad; 331578Srgrimes } 332578Srgrimes 333578Srgrimes /* no data to read */ 334578Srgrimes if (bp->b_bcount == 0) 335578Srgrimes goto done; 336578Srgrimes 337578Srgrimes /* for non raw access, check partition limits */ 338578Srgrimes if (mcd_part(bp->b_dev) != RAW_PART) { 339578Srgrimes if (!(cd->flags & MCDLABEL)) { 340578Srgrimes bp->b_error = EIO; 341578Srgrimes goto bad; 342578Srgrimes } 343578Srgrimes /* adjust transfer if necessary */ 344578Srgrimes if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 345578Srgrimes goto done; 346578Srgrimes } 347578Srgrimes } 348578Srgrimes 349578Srgrimes /* queue it */ 350578Srgrimes qp = &cd->head; 351578Srgrimes s = splbio(); 352578Srgrimes disksort(qp,bp); 353578Srgrimes splx(s); 354578Srgrimes 355578Srgrimes /* now check whether we can perform processing */ 356578Srgrimes mcd_start(unit); 357578Srgrimes return; 358578Srgrimes 359578Srgrimesbad: 360578Srgrimes bp->b_flags |= B_ERROR; 361578Srgrimesdone: 362578Srgrimes bp->b_resid = bp->b_bcount; 363578Srgrimes biodone(bp); 364578Srgrimes return; 365578Srgrimes} 366578Srgrimes 367578Srgrimesstatic void mcd_start(int unit) 368578Srgrimes{ 369578Srgrimes struct mcd_data *cd = mcd_data + unit; 370578Srgrimes struct buf *bp, *qp = &cd->head; 371578Srgrimes struct partition *p; 372578Srgrimes int part; 373578Srgrimes register s = splbio(); 374578Srgrimes 375578Srgrimes if (cd->flags & MCDMBXBSY) 376578Srgrimes return; 377578Srgrimes 378578Srgrimes if ((bp = qp->b_actf) != 0) { 379578Srgrimes /* block found to process, dequeue */ 380578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 381578Srgrimes qp->b_actf = bp->av_forw; 382578Srgrimes splx(s); 383578Srgrimes } else { 384578Srgrimes /* nothing to do */ 385578Srgrimes splx(s); 386578Srgrimes return; 387578Srgrimes } 388578Srgrimes 389578Srgrimes /* changed media? */ 390578Srgrimes if (!(cd->flags & MCDVALID)) { 391578Srgrimes MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 392578Srgrimes return; 393578Srgrimes } 394578Srgrimes 395578Srgrimes p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 396578Srgrimes 397578Srgrimes cd->flags |= MCDMBXBSY; 398578Srgrimes cd->mbx.unit = unit; 399578Srgrimes cd->mbx.port = cd->iobase; 400578Srgrimes cd->mbx.retry = MCD_RETRYS; 401578Srgrimes cd->mbx.bp = bp; 402578Srgrimes cd->mbx.p_offset = p->p_offset; 403578Srgrimes 404578Srgrimes /* calling the read routine */ 405978Sjkh mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 406578Srgrimes /* triggers mcd_start, when successful finished */ 407578Srgrimes return; 408578Srgrimes} 409578Srgrimes 410578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 411578Srgrimes{ 412578Srgrimes struct mcd_data *cd; 413578Srgrimes int unit,part; 414578Srgrimes 415578Srgrimes unit = mcd_unit(dev); 416578Srgrimes part = mcd_part(dev); 417578Srgrimes cd = mcd_data + unit; 418578Srgrimes 419578Srgrimes#ifdef MCDMINI 420578Srgrimes return ENOTTY; 421578Srgrimes#else 422578Srgrimes if (!(cd->flags & MCDVALID)) 423578Srgrimes return EIO; 424578SrgrimesMCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 425578Srgrimes 426578Srgrimes switch (cmd) { 427578Srgrimes case DIOCSBAD: 428578Srgrimes return EINVAL; 429578Srgrimes case DIOCGDINFO: 430578Srgrimes case DIOCGPART: 431578Srgrimes case DIOCWDINFO: 432578Srgrimes case DIOCSDINFO: 433578Srgrimes case DIOCWLABEL: 434578Srgrimes return ENOTTY; 435578Srgrimes case CDIOCPLAYTRACKS: 436578Srgrimes return mcd_playtracks(unit, (struct ioc_play_track *) addr); 437578Srgrimes case CDIOCPLAYBLOCKS: 438578Srgrimes return mcd_play(unit, (struct mcd_read2 *) addr); 439578Srgrimes case CDIOCREADSUBCHANNEL: 440578Srgrimes return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 441578Srgrimes case CDIOREADTOCHEADER: 442578Srgrimes return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 443578Srgrimes case CDIOREADTOCENTRYS: 444578Srgrimes return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); 445578Srgrimes case CDIOCSETPATCH: 446578Srgrimes case CDIOCGETVOL: 447578Srgrimes case CDIOCSETVOL: 448578Srgrimes case CDIOCSETMONO: 449578Srgrimes case CDIOCSETSTERIO: 450578Srgrimes case CDIOCSETMUTE: 451578Srgrimes case CDIOCSETLEFT: 452578Srgrimes case CDIOCSETRIGHT: 453578Srgrimes return EINVAL; 454578Srgrimes case CDIOCRESUME: 455578Srgrimes return mcd_resume(unit); 456578Srgrimes case CDIOCPAUSE: 457578Srgrimes return mcd_pause(unit); 458578Srgrimes case CDIOCSTART: 459578Srgrimes return EINVAL; 460578Srgrimes case CDIOCSTOP: 461578Srgrimes return mcd_stop(unit); 462578Srgrimes case CDIOCEJECT: 463578Srgrimes return EINVAL; 464578Srgrimes case CDIOCSETDEBUG: 465578Srgrimes cd->debug = 1; 466578Srgrimes return 0; 467578Srgrimes case CDIOCCLRDEBUG: 468578Srgrimes cd->debug = 0; 469578Srgrimes return 0; 470578Srgrimes case CDIOCRESET: 471578Srgrimes return EINVAL; 472578Srgrimes default: 473578Srgrimes return ENOTTY; 474578Srgrimes } 475578Srgrimes /*NOTREACHED*/ 476578Srgrimes#endif /*!MCDMINI*/ 477578Srgrimes} 478578Srgrimes 479578Srgrimes/* this could have been taken from scsi/cd.c, but it is not clear 480578Srgrimes * whether the scsi cd driver is linked in 481578Srgrimes */ 482578Srgrimesstatic int mcd_getdisklabel(int unit) 483578Srgrimes{ 484578Srgrimes struct mcd_data *cd = mcd_data + unit; 485578Srgrimes 486578Srgrimes if (cd->flags & MCDLABEL) 487578Srgrimes return -1; 488578Srgrimes 489578Srgrimes bzero(&cd->dlabel,sizeof(struct disklabel)); 490578Srgrimes strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); 491578Srgrimes strncpy(cd->dlabel.d_packname,"unknown ",16); 492578Srgrimes cd->dlabel.d_secsize = cd->blksize; 493578Srgrimes cd->dlabel.d_nsectors = 100; 494578Srgrimes cd->dlabel.d_ntracks = 1; 495578Srgrimes cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 496578Srgrimes cd->dlabel.d_secpercyl = 100; 497578Srgrimes cd->dlabel.d_secperunit = cd->disksize; 498578Srgrimes cd->dlabel.d_rpm = 300; 499578Srgrimes cd->dlabel.d_interleave = 1; 500578Srgrimes cd->dlabel.d_flags = D_REMOVABLE; 501578Srgrimes cd->dlabel.d_npartitions= 1; 502578Srgrimes cd->dlabel.d_partitions[0].p_offset = 0; 503578Srgrimes cd->dlabel.d_partitions[0].p_size = cd->disksize; 504578Srgrimes cd->dlabel.d_partitions[0].p_fstype = 9; 505578Srgrimes cd->dlabel.d_magic = DISKMAGIC; 506578Srgrimes cd->dlabel.d_magic2 = DISKMAGIC; 507578Srgrimes cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 508578Srgrimes 509578Srgrimes cd->flags |= MCDLABEL; 510578Srgrimes return 0; 511578Srgrimes} 512578Srgrimes 513578Srgrimesint mcdsize(dev_t dev) 514578Srgrimes{ 515578Srgrimes int size; 516578Srgrimes int unit = mcd_unit(dev); 517578Srgrimes struct mcd_data *cd = mcd_data + unit; 518578Srgrimes 519578Srgrimes if (mcd_volinfo(unit) >= 0) { 520578Srgrimes cd->blksize = MCDBLK; 521578Srgrimes size = msf2hsg(cd->volinfo.vol_msf); 522578Srgrimes cd->disksize = size * (MCDBLK/DEV_BSIZE); 523578Srgrimes return 0; 524578Srgrimes } 525578Srgrimes return -1; 526578Srgrimes} 527578Srgrimes 528578Srgrimes/*************************************************************** 529578Srgrimes * lower level of driver starts here 530578Srgrimes **************************************************************/ 531578Srgrimes 532578Srgrimes#ifdef NOTDEF 5331197Srgrimesstatic char 5341197Srgrimesirqs[] = { 535578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 536578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 537578Srgrimes}; 538578Srgrimes 5391197Srgrimesstatic char 5401197Srgrimesdrqs[] = { 541578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 542578Srgrimes}; 543578Srgrimes#endif 544578Srgrimes 5451197Srgrimesstatic void 5461197Srgrimesmcd_configure(struct mcd_data *cd) 547578Srgrimes{ 548578Srgrimes outb(cd->iobase+mcd_config,cd->config); 549578Srgrimes} 550578Srgrimes 5511197Srgrimes/* Wait for non-busy - return 0 on timeout */ 5521197Srgrimesstatic int 5531197Srgrimestwiddle_thumbs(int port, int unit, int count, char *whine) 5541197Srgrimes{ 5551197Srgrimes int i; 5561197Srgrimes 5571197Srgrimes for (i = 0; i < count; i++) { 5581197Srgrimes if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) { 5591197Srgrimes return 1; 5601197Srgrimes } 5611197Srgrimes } 5621197Srgrimes#ifdef MCD_TO_WARNING_ON 5631197Srgrimes printf("mcd%d: timeout %s\n", unit, whine); 5641197Srgrimes#endif 5651197Srgrimes return 0; 5661197Srgrimes} 5671197Srgrimes 568978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 569578Srgrimes 5701197Srgrimesint 5711197Srgrimesmcd_probe(struct isa_device *dev) 572578Srgrimes{ 573578Srgrimes int port = dev->id_iobase; 574578Srgrimes int unit = dev->id_unit; 5751197Srgrimes int i, j; 5761197Srgrimes int status; 5771197Srgrimes unsigned char stbytes[3]; 578578Srgrimes 579578Srgrimes mcd_data[unit].flags = MCDPROBING; 580578Srgrimes 581578Srgrimes#ifdef NOTDEF 582578Srgrimes /* get irq/drq configuration word */ 583578Srgrimes mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 584578Srgrimes#else 585578Srgrimes mcd_data[unit].config = 0; 586578Srgrimes#endif 587578Srgrimes 588578Srgrimes /* send a reset */ 5891197Srgrimes outb(port+MCD_FLAGS, M_RESET); 590578Srgrimes 5911197Srgrimes /* 5921197Srgrimes * delay awhile by getting any pending garbage (old data) and 5931197Srgrimes * throwing it away. 5941197Srgrimes */ 5951197Srgrimes for (i = 1000000; i != 0; i--) { 5961197Srgrimes inb(port+MCD_FLAGS); 5971197Srgrimes } 598578Srgrimes 5991197Srgrimes /* Get status */ 6001197Srgrimes outb(port+MCD_DATA, MCD_CMDGETSTAT); 6011197Srgrimes if (!twiddle_thumbs(port, unit, 1000000, "getting status")) { 6021197Srgrimes return 0; /* Timeout */ 6031197Srgrimes } 6041197Srgrimes status = inb(port+MCD_DATA); 605578Srgrimes 6061197Srgrimes /* Get version information */ 6071197Srgrimes outb(port+MCD_DATA, MCD_CMDCONTINFO); 6081197Srgrimes for (j = 0; j < 3; j++) { 6091197Srgrimes if (!twiddle_thumbs(port, unit, 3000, "getting version info")) { 6101197Srgrimes return 0; 6111197Srgrimes } 6121197Srgrimes stbytes[j] = (inb(port+MCD_DATA) & 0xFF); 6131197Srgrimes } 6141197Srgrimes printf("mcd%d: version information is %x %c %x\n", unit, 6151197Srgrimes stbytes[0], stbytes[1], stbytes[2]); 6161197Srgrimes if (stbytes[1] >= 4) { 6171197Srgrimes outb(port+MCD_CTRL, M_PICKLE); 6181197Srgrimes printf("mcd%d: Adjusted for newer drive model\n", unit); 6191197Srgrimes } 6201197Srgrimes return 4; 621578Srgrimes} 622578Srgrimes 623978Sjkh 6241197Srgrimesstatic int 6251197Srgrimesmcd_waitrdy(int port,int dly) 626578Srgrimes{ 627578Srgrimes int i; 628578Srgrimes 629578Srgrimes /* wait until xfer port senses data ready */ 630578Srgrimes for (i=0; i<dly; i++) { 631578Srgrimes if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0) 632578Srgrimes return 0; 633578Srgrimes mcd_delay(1); 634578Srgrimes } 635578Srgrimes return -1; 636578Srgrimes} 637578Srgrimes 6381197Srgrimesstatic int 6391197Srgrimesmcd_getreply(int unit,int dly) 640578Srgrimes{ 641578Srgrimes int i; 642578Srgrimes struct mcd_data *cd = mcd_data + unit; 643578Srgrimes int port = cd->iobase; 644578Srgrimes 645578Srgrimes /* wait data to become ready */ 646578Srgrimes if (mcd_waitrdy(port,dly)<0) { 647578Srgrimes#ifdef MCD_TO_WARNING_ON 648578Srgrimes printf("mcd%d: timeout getreply\n",unit); 649578Srgrimes#endif 650578Srgrimes return -1; 651578Srgrimes } 652578Srgrimes 653578Srgrimes /* get the data */ 654578Srgrimes return inb(port+mcd_status) & 0xFF; 655578Srgrimes} 656578Srgrimes 6571197Srgrimesstatic int 6581197Srgrimesmcd_getstat(int unit,int sflg) 659578Srgrimes{ 660578Srgrimes int i; 661578Srgrimes struct mcd_data *cd = mcd_data + unit; 662578Srgrimes int port = cd->iobase; 663578Srgrimes 664578Srgrimes /* get the status */ 665578Srgrimes if (sflg) 666578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 667578Srgrimes i = mcd_getreply(unit,DELAY_GETREPLY); 668578Srgrimes if (i<0) return -1; 669578Srgrimes 670578Srgrimes cd->status = i; 671578Srgrimes 672578Srgrimes mcd_setflags(unit,cd); 673578Srgrimes return cd->status; 674578Srgrimes} 675578Srgrimes 6761197Srgrimesstatic void 6771197Srgrimesmcd_setflags(int unit, struct mcd_data *cd) 678578Srgrimes{ 679578Srgrimes /* check flags */ 680578Srgrimes if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { 681578Srgrimes MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); 682578Srgrimes cd->flags &= ~MCDVALID; 683578Srgrimes } 684578Srgrimes 685578Srgrimes#ifndef MCDMINI 686578Srgrimes if (cd->status & MCDAUDIOBSY) 687578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 688578Srgrimes else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 689578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 690578Srgrimes#endif 691578Srgrimes} 692578Srgrimes 6931197Srgrimesstatic int 6941197Srgrimesmcd_get(int unit, char *buf, int nmax) 695578Srgrimes{ 696578Srgrimes int port = mcd_data[unit].iobase; 697578Srgrimes int i,k; 698578Srgrimes 699578Srgrimes for (i=0; i<nmax; i++) { 700578Srgrimes /* wait for data */ 701578Srgrimes if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 702578Srgrimes#ifdef MCD_TO_WARNING_ON 703578Srgrimes printf("mcd%d: timeout mcd_get\n",unit); 704578Srgrimes#endif 705578Srgrimes return -1; 706578Srgrimes } 707578Srgrimes buf[i] = k; 708578Srgrimes } 709578Srgrimes return i; 710578Srgrimes} 711578Srgrimes 7121197Srgrimesstatic int 7131197Srgrimesmcd_send(int unit, int cmd,int nretrys) 714578Srgrimes{ 715578Srgrimes int i,k; 716578Srgrimes int port = mcd_data[unit].iobase; 717578Srgrimes 718578Srgrimes/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/ 719578Srgrimes for (i=0; i<nretrys; i++) { 720578Srgrimes outb(port+mcd_command, cmd); 7211197Srgrimes if ((k=mcd_getstat(unit,0)) != -1) { 722578Srgrimes break; 7231197Srgrimes } 724578Srgrimes } 725578Srgrimes if (i == nretrys) { 726578Srgrimes printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 727578Srgrimes return -1; 728578Srgrimes } 729578Srgrimes/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/ 730578Srgrimes return 0; 731578Srgrimes} 732578Srgrimes 7331197Srgrimesstatic int 7341197Srgrimesbcd2bin(bcd_t b) 735578Srgrimes{ 736578Srgrimes return (b >> 4) * 10 + (b & 15); 737578Srgrimes} 738578Srgrimes 7391197Srgrimesstatic bcd_t 7401197Srgrimesbin2bcd(int b) 741578Srgrimes{ 742578Srgrimes return ((b / 10) << 4) | (b % 10); 743578Srgrimes} 744578Srgrimes 7451197Srgrimesstatic void 7461197Srgrimeshsg2msf(int hsg, bcd_t *msf) 747578Srgrimes{ 748578Srgrimes hsg += 150; 749578Srgrimes M_msf(msf) = bin2bcd(hsg / 4500); 750578Srgrimes hsg %= 4500; 751578Srgrimes S_msf(msf) = bin2bcd(hsg / 75); 752578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 753578Srgrimes} 754578Srgrimes 7551197Srgrimesstatic int 7561197Srgrimesmsf2hsg(bcd_t *msf) 757578Srgrimes{ 758578Srgrimes return (bcd2bin(M_msf(msf)) * 60 + 759578Srgrimes bcd2bin(S_msf(msf))) * 75 + 760578Srgrimes bcd2bin(F_msf(msf)) - 150; 761578Srgrimes} 762578Srgrimes 7631197Srgrimesstatic int 7641197Srgrimesmcd_volinfo(int unit) 765578Srgrimes{ 766578Srgrimes struct mcd_data *cd = mcd_data + unit; 767578Srgrimes int i; 768578Srgrimes 769578Srgrimes/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 770578Srgrimes 771578Srgrimes /* Get the status, in case the disc has been changed */ 772578Srgrimes if (mcd_getstat(unit, 1) < 0) return EIO; 773578Srgrimes 774578Srgrimes /* Just return if we already have it */ 775578Srgrimes if (cd->flags & MCDVOLINFO) return 0; 776578Srgrimes 777578Srgrimes /* send volume info command */ 778578Srgrimes if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 779578Srgrimes return -1; 780578Srgrimes 781578Srgrimes /* get data */ 782578Srgrimes if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 783578Srgrimes printf("mcd%d: mcd_volinfo: error read data\n",unit); 784578Srgrimes return -1; 785578Srgrimes } 786578Srgrimes 787578Srgrimes if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { 788578Srgrimes cd->flags |= MCDVOLINFO; /* volinfo is OK */ 789578Srgrimes return 0; 790578Srgrimes } 791578Srgrimes 792578Srgrimes return -1; 793578Srgrimes} 794578Srgrimes 795798Swollmanvoid 796798Swollmanmcdintr(unit) 797798Swollman int unit; 798578Srgrimes{ 799578Srgrimes int port = mcd_data[unit].iobase; 800578Srgrimes u_int i; 801578Srgrimes 802578Srgrimes MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); 803578Srgrimes 804578Srgrimes /* just read out status and ignore the rest */ 805578Srgrimes if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { 806578Srgrimes i = inb(port+mcd_status); 807578Srgrimes } 808578Srgrimes} 809578Srgrimes 810578Srgrimes/* state machine to process read requests 811578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 812578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 813578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 814578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 815578Srgrimes */ 816578Srgrimesstatic struct mcd_mbx *mbxsave; 817578Srgrimes 8181197Srgrimesstatic void 8191197Srgrimesmcd_doread(int state, struct mcd_mbx *mbxin) 820578Srgrimes{ 821578Srgrimes struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 822578Srgrimes int unit = mbx->unit; 823578Srgrimes int port = mbx->port; 824578Srgrimes struct buf *bp = mbx->bp; 825578Srgrimes struct mcd_data *cd = mcd_data + unit; 826578Srgrimes 827578Srgrimes int rm,i,k; 828578Srgrimes struct mcd_read2 rbuf; 829578Srgrimes int blknum; 830578Srgrimes caddr_t addr; 831578Srgrimes 832578Srgrimesloop: 833578Srgrimes switch (state) { 834578Srgrimes case MCD_S_BEGIN: 835578Srgrimes mbx = mbxsave = mbxin; 836578Srgrimes 837578Srgrimes case MCD_S_BEGIN1: 838578Srgrimes /* get status */ 839578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 840578Srgrimes mbx->count = RDELAY_WAITSTAT; 8411197Srgrimes timeout((timeout_func_t)mcd_doread, 8421197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 843578Srgrimes return; 844578Srgrimes case MCD_S_WAITSTAT: 8451000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT); 846578Srgrimes if (mbx->count-- >= 0) { 847578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 8481197Srgrimes timeout((timeout_func_t)mcd_doread, 8491197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 850578Srgrimes return; 851578Srgrimes } 852578Srgrimes mcd_setflags(unit,cd); 8531197Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n", 8541197Srgrimes RDELAY_WAITSTAT-mbx->count,0,0,0); 855578Srgrimes /* reject, if audio active */ 856578Srgrimes if (cd->status & MCDAUDIOBSY) { 857578Srgrimes printf("mcd%d: audio is active\n",unit); 858578Srgrimes goto readerr; 859578Srgrimes } 860578Srgrimes 861578Srgrimes /* to check for raw/cooked mode */ 862578Srgrimes if (cd->flags & MCDREADRAW) { 863578Srgrimes rm = MCD_MD_RAW; 864578Srgrimes mbx->sz = MCDRBLK; 865578Srgrimes } else { 866578Srgrimes rm = MCD_MD_COOKED; 867578Srgrimes mbx->sz = cd->blksize; 868578Srgrimes } 869578Srgrimes 870578Srgrimes mbx->count = RDELAY_WAITMODE; 871578Srgrimes 872578Srgrimes mcd_put(port+mcd_command, MCD_CMDSETMODE); 873578Srgrimes mcd_put(port+mcd_command, rm); 8741197Srgrimes timeout((timeout_func_t)mcd_doread, 8751197Srgrimes (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */ 876578Srgrimes return; 877578Srgrimes } else { 878578Srgrimes#ifdef MCD_TO_WARNING_ON 879578Srgrimes printf("mcd%d: timeout getstatus\n",unit); 880578Srgrimes#endif 881578Srgrimes goto readerr; 882578Srgrimes } 883578Srgrimes 884578Srgrimes case MCD_S_WAITMODE: 8851000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE); 886578Srgrimes if (mbx->count-- < 0) { 887578Srgrimes#ifdef MCD_TO_WARNING_ON 888578Srgrimes printf("mcd%d: timeout set mode\n",unit); 889578Srgrimes#endif 890578Srgrimes goto readerr; 891578Srgrimes } 892578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 893798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); 894578Srgrimes return; 895578Srgrimes } 896578Srgrimes mcd_setflags(unit,cd); 8971197Srgrimes MCD_TRACE("got WAITMODE delay=%d\n", 8981197Srgrimes RDELAY_WAITMODE-mbx->count,0,0,0); 899578Srgrimes /* for first block */ 900578Srgrimes mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 901578Srgrimes mbx->skip = 0; 902578Srgrimes 903578Srgrimesnextblock: 904578Srgrimes blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 905578Srgrimes + mbx->p_offset + mbx->skip/mbx->sz; 906578Srgrimes 9071197Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n", 9081197Srgrimes blknum,bp,0,0); 909578Srgrimes 910578Srgrimes /* build parameter block */ 911578Srgrimes hsg2msf(blknum,rbuf.start_msf); 912578Srgrimes 913578Srgrimes /* send the read command */ 914578Srgrimes mcd_put(port+mcd_command,MCD_CMDREAD2); 915578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[0]); 916578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[1]); 917578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[2]); 918578Srgrimes mcd_put(port+mcd_command,0); 919578Srgrimes mcd_put(port+mcd_command,0); 920578Srgrimes mcd_put(port+mcd_command,1); 921578Srgrimes mbx->count = RDELAY_WAITREAD; 9221197Srgrimes timeout((timeout_func_t)mcd_doread, 9231197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 924578Srgrimes return; 925578Srgrimes case MCD_S_WAITREAD: 9261000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD); 927578Srgrimes if (mbx->count-- > 0) { 928578Srgrimes k = inb(port+mcd_xfer); 929578Srgrimes if ((k & 2)==0) { 9301197Srgrimes MCD_TRACE("got data delay=%d\n", 9311197Srgrimes RDELAY_WAITREAD-mbx->count,0,0,0); 932578Srgrimes /* data is ready */ 933578Srgrimes addr = bp->b_un.b_addr + mbx->skip; 934578Srgrimes outb(port+mcd_ctl2,0x04); /* XXX */ 935578Srgrimes for (i=0; i<mbx->sz; i++) 936578Srgrimes *addr++ = inb(port+mcd_rdata); 937578Srgrimes outb(port+mcd_ctl2,0x0c); /* XXX */ 938578Srgrimes 939578Srgrimes if (--mbx->nblk > 0) { 940578Srgrimes mbx->skip += mbx->sz; 941578Srgrimes goto nextblock; 942578Srgrimes } 943578Srgrimes 944578Srgrimes /* return buffer */ 945578Srgrimes bp->b_resid = 0; 946578Srgrimes biodone(bp); 947578Srgrimes 948578Srgrimes cd->flags &= ~MCDMBXBSY; 949578Srgrimes mcd_start(mbx->unit); 950578Srgrimes return; 951578Srgrimes } 952578Srgrimes if ((k & 4)==0) 953578Srgrimes mcd_getstat(unit,0); 9541197Srgrimes timeout((timeout_func_t)mcd_doread, 9551197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 956578Srgrimes return; 957578Srgrimes } else { 958578Srgrimes#ifdef MCD_TO_WARNING_ON 959578Srgrimes printf("mcd%d: timeout read data\n",unit); 960578Srgrimes#endif 961578Srgrimes goto readerr; 962578Srgrimes } 963578Srgrimes } 964578Srgrimes 965578Srgrimesreaderr: 966578Srgrimes if (mbx->retry-- > 0) { 967578Srgrimes#ifdef MCD_TO_WARNING_ON 968578Srgrimes printf("mcd%d: retrying\n",unit); 969578Srgrimes#endif 970578Srgrimes state = MCD_S_BEGIN1; 971578Srgrimes goto loop; 972578Srgrimes } 973578Srgrimes 974578Srgrimes /* invalidate the buffer */ 975578Srgrimes bp->b_flags |= B_ERROR; 976578Srgrimes bp->b_resid = bp->b_bcount; 977578Srgrimes biodone(bp); 978578Srgrimes mcd_start(mbx->unit); 979578Srgrimes return; 980578Srgrimes 981578Srgrimes#ifdef NOTDEF 982578Srgrimes printf("mcd%d: unit timeout, resetting\n",mbx->unit); 983578Srgrimes outb(mbx->port+mcd_reset,MCD_CMDRESET); 984578Srgrimes DELAY(300000); 985578Srgrimes (void)mcd_getstat(mbx->unit,1); 986578Srgrimes (void)mcd_getstat(mbx->unit,1); 987578Srgrimes /*cd->status &= ~MCDDSKCHNG; */ 988578Srgrimes cd->debug = 1; /* preventive set debug mode */ 989578Srgrimes 990578Srgrimes#endif 991578Srgrimes 992578Srgrimes} 993578Srgrimes 994578Srgrimes#ifndef MCDMINI 9951197Srgrimesstatic int 9961197Srgrimesmcd_setmode(int unit, int mode) 997578Srgrimes{ 998578Srgrimes struct mcd_data *cd = mcd_data + unit; 999578Srgrimes int port = cd->iobase; 1000578Srgrimes int retry; 1001578Srgrimes 1002578Srgrimes printf("mcd%d: setting mode to %d\n", unit, mode); 1003578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1004578Srgrimes { 1005578Srgrimes outb(port+mcd_command, MCD_CMDSETMODE); 1006578Srgrimes outb(port+mcd_command, mode); 1007578Srgrimes if (mcd_getstat(unit, 0) != -1) return 0; 1008578Srgrimes } 1009578Srgrimes 1010578Srgrimes return -1; 1011578Srgrimes} 1012578Srgrimes 10131197Srgrimesstatic int 10141197Srgrimesmcd_toc_header(int unit, struct ioc_toc_header *th) 1015578Srgrimes{ 1016578Srgrimes struct mcd_data *cd = mcd_data + unit; 1017578Srgrimes 10181197Srgrimes if (mcd_volinfo(unit) < 0) { 1019578Srgrimes return ENXIO; 10201197Srgrimes } 1021578Srgrimes 1022578Srgrimes th->len = msf2hsg(cd->volinfo.vol_msf); 1023578Srgrimes th->starting_track = bcd2bin(cd->volinfo.trk_low); 1024578Srgrimes th->ending_track = bcd2bin(cd->volinfo.trk_high); 1025578Srgrimes 1026578Srgrimes return 0; 1027578Srgrimes} 1028578Srgrimes 10291197Srgrimesstatic int 10301197Srgrimesmcd_read_toc(int unit) 1031578Srgrimes{ 1032578Srgrimes struct mcd_data *cd = mcd_data + unit; 1033578Srgrimes struct ioc_toc_header th; 1034578Srgrimes struct mcd_qchninfo q; 1035578Srgrimes int rc, trk, idx, retry; 1036578Srgrimes 1037578Srgrimes /* Only read TOC if needed */ 10381197Srgrimes if (cd->flags & MCDTOC) { 10391197Srgrimes return 0; 10401197Srgrimes } 1041578Srgrimes 1042578Srgrimes printf("mcd%d: reading toc header\n", unit); 10431197Srgrimes if (mcd_toc_header(unit, &th) != 0) { 1044578Srgrimes return ENXIO; 10451197Srgrimes } 1046578Srgrimes 1047578Srgrimes printf("mcd%d: stopping play\n", unit); 10481197Srgrimes if ((rc=mcd_stop(unit)) != 0) { 1049578Srgrimes return rc; 10501197Srgrimes } 1051578Srgrimes 1052578Srgrimes /* try setting the mode twice */ 10531197Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1054578Srgrimes return EIO; 10551197Srgrimes } 10561197Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1057578Srgrimes return EIO; 10581197Srgrimes } 1059578Srgrimes 1060578Srgrimes printf("mcd%d: get_toc reading qchannel info\n",unit); 1061578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1062578Srgrimes cd->toc[trk].idx_no = 0; 1063578Srgrimes trk = th.ending_track - th.starting_track + 1; 1064578Srgrimes for(retry=0; retry<300 && trk>0; retry++) 1065578Srgrimes { 1066578Srgrimes if (mcd_getqchan(unit, &q) < 0) break; 1067578Srgrimes idx = bcd2bin(q.idx_no); 10681197Srgrimes if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) { 10691197Srgrimes if (cd->toc[idx].idx_no == 0) { 1070578Srgrimes cd->toc[idx] = q; 1071578Srgrimes trk--; 1072578Srgrimes } 10731197Srgrimes } 1074578Srgrimes } 1075578Srgrimes 10761197Srgrimes if (mcd_setmode(unit, MCD_MD_COOKED) != 0) { 1077578Srgrimes return EIO; 10781197Srgrimes } 1079578Srgrimes 10801197Srgrimes if (trk != 0) { 10811197Srgrimes return ENXIO; 10821197Srgrimes } 1083578Srgrimes 1084578Srgrimes /* add a fake last+1 */ 1085578Srgrimes idx = th.ending_track + 1; 1086578Srgrimes cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1087578Srgrimes cd->toc[idx].trk_no = 0; 1088578Srgrimes cd->toc[idx].idx_no = 0xAA; 1089578Srgrimes cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1090578Srgrimes cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1091578Srgrimes cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1092578Srgrimes 1093578Srgrimes cd->flags |= MCDTOC; 1094578Srgrimes 1095578Srgrimes return 0; 1096578Srgrimes} 1097578Srgrimes 10981197Srgrimesstatic int 10991197Srgrimesmcd_toc_entry(int unit, struct ioc_read_toc_entry *te) 1100578Srgrimes{ 1101578Srgrimes struct mcd_data *cd = mcd_data + unit; 11021197Srgrimes struct ret_toc { 1103578Srgrimes struct ioc_toc_header th; 1104578Srgrimes struct cd_toc_entry rt; 1105578Srgrimes } ret_toc; 1106578Srgrimes struct ioc_toc_header th; 1107578Srgrimes int rc, i; 1108578Srgrimes 1109578Srgrimes /* Make sure we have a valid toc */ 11101197Srgrimes if ((rc=mcd_read_toc(unit)) != 0) { 1111578Srgrimes return rc; 11121197Srgrimes } 1113578Srgrimes 1114578Srgrimes /* find the toc to copy*/ 1115578Srgrimes i = te->starting_track; 11161197Srgrimes if (i == MCD_LASTPLUS1) { 1117578Srgrimes i = bcd2bin(cd->volinfo.trk_high) + 1; 11181197Srgrimes } 1119578Srgrimes 1120578Srgrimes /* verify starting track */ 1121578Srgrimes if (i < bcd2bin(cd->volinfo.trk_low) || 11221197Srgrimes i > bcd2bin(cd->volinfo.trk_high)+1) { 1123578Srgrimes return EINVAL; 11241197Srgrimes } 1125578Srgrimes 1126578Srgrimes /* do we have room */ 1127578Srgrimes if (te->data_len < sizeof(struct ioc_toc_header) + 11281197Srgrimes sizeof(struct cd_toc_entry)) { 11291197Srgrimes return EINVAL; 11301197Srgrimes } 1131578Srgrimes 1132578Srgrimes /* Copy the toc header */ 11331197Srgrimes if (mcd_toc_header(unit, &th) < 0) { 11341197Srgrimes return EIO; 11351197Srgrimes } 1136578Srgrimes ret_toc.th = th; 1137578Srgrimes 1138578Srgrimes /* copy the toc data */ 1139578Srgrimes ret_toc.rt.control = cd->toc[i].ctrl_adr; 1140578Srgrimes ret_toc.rt.addr_type = te->address_format; 1141578Srgrimes ret_toc.rt.track = i; 11421197Srgrimes if (te->address_format == CD_MSF_FORMAT) { 11431097Srgrimes ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0]; 11441097Srgrimes ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1]; 11451097Srgrimes ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2]; 1146578Srgrimes } 1147578Srgrimes 1148578Srgrimes /* copy the data back */ 1149578Srgrimes copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) 1150578Srgrimes + sizeof(struct ioc_toc_header)); 1151578Srgrimes 1152578Srgrimes return 0; 1153578Srgrimes} 1154578Srgrimes 11551197Srgrimesstatic int 11561197Srgrimesmcd_stop(int unit) 1157578Srgrimes{ 1158578Srgrimes struct mcd_data *cd = mcd_data + unit; 1159578Srgrimes 11601197Srgrimes if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) { 1161578Srgrimes return ENXIO; 11621197Srgrimes } 1163578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 1164578Srgrimes return 0; 1165578Srgrimes} 1166578Srgrimes 11671197Srgrimesstatic int 11681197Srgrimesmcd_getqchan(int unit, struct mcd_qchninfo *q) 1169578Srgrimes{ 1170578Srgrimes struct mcd_data *cd = mcd_data + unit; 1171578Srgrimes 11721197Srgrimes if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) { 1173578Srgrimes return -1; 11741197Srgrimes } 11751197Srgrimes if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) { 1176578Srgrimes return -1; 11771197Srgrimes } 11781197Srgrimes if (cd->debug) { 11791197Srgrimes printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", 1180578Srgrimes unit, 1181578Srgrimes q->ctrl_adr, q->trk_no, q->idx_no, 1182578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], 1183578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); 11841197Srgrimes } 1185578Srgrimes return 0; 1186578Srgrimes} 1187578Srgrimes 11881197Srgrimesstatic int 11891197Srgrimesmcd_subchan(int unit, struct ioc_read_subchannel *sc) 1190578Srgrimes{ 1191578Srgrimes struct mcd_data *cd = mcd_data + unit; 1192578Srgrimes struct mcd_qchninfo q; 1193578Srgrimes struct cd_sub_channel_info data; 1194578Srgrimes 1195578Srgrimes printf("mcd%d: subchan af=%d, df=%d\n", unit, 1196578Srgrimes sc->address_format, 1197578Srgrimes sc->data_format); 11981197Srgrimes if (sc->address_format != CD_MSF_FORMAT) { 11991197Srgrimes return EIO; 12001197Srgrimes } 12011197Srgrimes if (sc->data_format != CD_CURRENT_POSITION) { 12021197Srgrimes return EIO; 12031197Srgrimes } 12041197Srgrimes if (mcd_getqchan(unit, &q) < 0) { 12051197Srgrimes return EIO; 12061197Srgrimes } 1207578Srgrimes 1208578Srgrimes data.header.audio_status = cd->audio_status; 1209578Srgrimes data.what.position.data_format = CD_MSF_FORMAT; 1210578Srgrimes data.what.position.track_number = bcd2bin(q.trk_no); 1211578Srgrimes 12121197Srgrimes if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) { 1213578Srgrimes return EFAULT; 12141197Srgrimes } 1215578Srgrimes return 0; 1216578Srgrimes} 1217578Srgrimes 12181197Srgrimesstatic int 12191197Srgrimesmcd_playtracks(int unit, struct ioc_play_track *pt) 1220578Srgrimes{ 1221578Srgrimes struct mcd_data *cd = mcd_data + unit; 1222578Srgrimes struct mcd_read2 pb; 1223578Srgrimes int a = pt->start_track; 1224578Srgrimes int z = pt->end_track; 1225578Srgrimes int rc; 1226578Srgrimes 12271197Srgrimes if ((rc = mcd_read_toc(unit)) != 0) { 12281197Srgrimes return rc; 12291197Srgrimes } 1230578Srgrimes printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 1231578Srgrimes a, pt->start_index, z, pt->end_index); 1232578Srgrimes 1233578Srgrimes if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || 12341197Srgrimes z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) { 1235578Srgrimes return EINVAL; 12361197Srgrimes } 1237578Srgrimes 1238578Srgrimes pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; 1239578Srgrimes pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; 1240578Srgrimes pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; 1241578Srgrimes pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; 1242578Srgrimes pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; 1243578Srgrimes pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; 1244578Srgrimes 1245578Srgrimes return mcd_play(unit, &pb); 1246578Srgrimes} 1247578Srgrimes 12481197Srgrimesstatic int 12491197Srgrimesmcd_play(int unit, struct mcd_read2 *pb) 1250578Srgrimes{ 1251578Srgrimes struct mcd_data *cd = mcd_data + unit; 1252578Srgrimes int port = cd->iobase; 1253578Srgrimes int retry, st; 1254578Srgrimes 1255578Srgrimes cd->lastpb = *pb; 12561197Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) { 1257578Srgrimes outb(port+mcd_command, MCD_CMDREAD2); 1258578Srgrimes outb(port+mcd_command, pb->start_msf[0]); 1259578Srgrimes outb(port+mcd_command, pb->start_msf[1]); 1260578Srgrimes outb(port+mcd_command, pb->start_msf[2]); 1261578Srgrimes outb(port+mcd_command, pb->end_msf[0]); 1262578Srgrimes outb(port+mcd_command, pb->end_msf[1]); 1263578Srgrimes outb(port+mcd_command, pb->end_msf[2]); 12641197Srgrimes if ((st=mcd_getstat(unit, 0)) != -1) { 12651197Srgrimes break; 12661197Srgrimes } 1267578Srgrimes } 1268578Srgrimes 12691197Srgrimes if (cd->debug) { 12701197Srgrimes printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); 12711197Srgrimes } 12721197Srgrimes if (st == -1) { 12731197Srgrimes return ENXIO; 12741197Srgrimes } 1275578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1276578Srgrimes return 0; 1277578Srgrimes} 1278578Srgrimes 12791197Srgrimesstatic int 12801197Srgrimesmcd_pause(int unit) 1281578Srgrimes{ 1282578Srgrimes struct mcd_data *cd = mcd_data + unit; 1283578Srgrimes struct mcd_qchninfo q; 1284578Srgrimes int rc; 1285578Srgrimes 1286578Srgrimes /* Verify current status */ 12871197Srgrimes if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { 1288578Srgrimes printf("mcd%d: pause attempted when not playing\n", unit); 1289578Srgrimes return EINVAL; 1290578Srgrimes } 1291578Srgrimes 1292578Srgrimes /* Get the current position */ 12931197Srgrimes if (mcd_getqchan(unit, &q) < 0) { 12941197Srgrimes return EIO; 12951197Srgrimes } 1296578Srgrimes 1297578Srgrimes /* Copy it into lastpb */ 1298578Srgrimes cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1299578Srgrimes cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1300578Srgrimes cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1301578Srgrimes 1302578Srgrimes /* Stop playing */ 13031197Srgrimes if ((rc=mcd_stop(unit)) != 0) { 13041197Srgrimes return rc; 13051197Srgrimes } 1306578Srgrimes 1307578Srgrimes /* Set the proper status and exit */ 1308578Srgrimes cd->audio_status = CD_AS_PLAY_PAUSED; 1309578Srgrimes return 0; 1310578Srgrimes} 1311578Srgrimes 13121197Srgrimesstatic int 13131197Srgrimesmcd_resume(int unit) 1314578Srgrimes{ 1315578Srgrimes struct mcd_data *cd = mcd_data + unit; 1316578Srgrimes 13171197Srgrimes if (cd->audio_status != CD_AS_PLAY_PAUSED) { 13181197Srgrimes return EINVAL; 13191197Srgrimes } 1320578Srgrimes return mcd_play(unit, &cd->lastpb); 1321578Srgrimes} 1322578Srgrimes#endif /*!MCDMINI*/ 1323578Srgrimes 1324578Srgrimes#endif /* NMCD > 0 */ 1325