mcd.c revision 1097
1578Srgrimes/* 2578Srgrimes * Copyright 1993 by Holger Veit (data part) 3578Srgrimes * Copyright 1993 by Brian Moore (audio part) 4978Sjkh * Changes Copyright 1993 by Gary Clark II 5578Srgrimes * All rights reserved. 6578Srgrimes * 7578Srgrimes * Redistribution and use in source and binary forms, with or without 8578Srgrimes * modification, are permitted provided that the following conditions 9578Srgrimes * are met: 10578Srgrimes * 1. Redistributions of source code must retain the above copyright 11578Srgrimes * notice, this list of conditions and the following disclaimer. 12578Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 13578Srgrimes * notice, this list of conditions and the following disclaimer in the 14578Srgrimes * documentation and/or other materials provided with the distribution. 15578Srgrimes * 3. All advertising materials mentioning features or use of this software 16578Srgrimes * must display the following acknowledgement: 17578Srgrimes * This software was developed by Holger Veit and Brian Moore 18578Srgrimes * for use with "386BSD" and similar operating systems. 19578Srgrimes * "Similar operating systems" includes mainly non-profit oriented 20578Srgrimes * systems for research and education, including but not restricted to 21578Srgrimes * "NetBSD", "FreeBSD", "Mach" (by CMU). 22578Srgrimes * 4. Neither the name of the developer(s) nor the name "386BSD" 23578Srgrimes * may be used to endorse or promote products derived from this 24578Srgrimes * software without specific prior written permission. 25578Srgrimes * 26578Srgrimes * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 27578Srgrimes * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28578Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29578Srgrimes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 30578Srgrimes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31578Srgrimes * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 32578Srgrimes * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 33578Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34578Srgrimes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35578Srgrimes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36578Srgrimes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37578Srgrimes * 381097Srgrimes * $Id: mcd.c,v 1.7 1994/01/22 18:00:54 ats Exp $ 39578Srgrimes */ 40578Srgrimesstatic char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 41578Srgrimes 42578Srgrimes#include "mcd.h" 43578Srgrimes#if NMCD > 0 44578Srgrimes#include "types.h" 45578Srgrimes#include "param.h" 46578Srgrimes#include "systm.h" 47578Srgrimes#include "conf.h" 48578Srgrimes#include "file.h" 49578Srgrimes#include "buf.h" 50578Srgrimes#include "stat.h" 51578Srgrimes#include "uio.h" 52578Srgrimes#include "ioctl.h" 53578Srgrimes#include "cdio.h" 54578Srgrimes#include "errno.h" 55578Srgrimes#include "dkbad.h" 56578Srgrimes#include "disklabel.h" 57578Srgrimes#include "i386/isa/isa.h" 58578Srgrimes#include "i386/isa/isa_device.h" 59578Srgrimes#include "mcdreg.h" 60578Srgrimes 61578Srgrimes/* user definable options */ 62578Srgrimes/*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ 63578Srgrimes/*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ 64578Srgrimes 65578Srgrimes 66578Srgrimes#ifdef MCDMINI 67578Srgrimes#define MCD_TRACE(fmt,a,b,c,d) 68578Srgrimes#ifdef MCD_TO_WARNING_ON 69578Srgrimes#undef MCD_TO_WARNING_ON 70578Srgrimes#endif 71578Srgrimes#else 72978Sjkh#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);}} 73578Srgrimes#endif 74578Srgrimes 75578Srgrimes#define mcd_part(dev) ((minor(dev)) & 7) 76578Srgrimes#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) 77578Srgrimes#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) 78578Srgrimes#define RAW_PART 3 79578Srgrimes 80578Srgrimes/* flags */ 81578Srgrimes#define MCDOPEN 0x0001 /* device opened */ 82578Srgrimes#define MCDVALID 0x0002 /* parameters loaded */ 83578Srgrimes#define MCDINIT 0x0004 /* device is init'd */ 84578Srgrimes#define MCDWAIT 0x0008 /* waiting for something */ 85578Srgrimes#define MCDLABEL 0x0010 /* label is read */ 86578Srgrimes#define MCDPROBING 0x0020 /* probing */ 87578Srgrimes#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ 88578Srgrimes#define MCDVOLINFO 0x0080 /* already read volinfo */ 89578Srgrimes#define MCDTOC 0x0100 /* already read toc */ 90578Srgrimes#define MCDMBXBSY 0x0200 /* local mbx is busy */ 91578Srgrimes 92578Srgrimes/* status */ 93578Srgrimes#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 94578Srgrimes#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 95578Srgrimes#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 96578Srgrimes#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 97578Srgrimes 98578Srgrimes/* toc */ 99578Srgrimes#define MCD_MAXTOCS 104 /* from the Linux driver */ 100578Srgrimes#define MCD_LASTPLUS1 170 /* special toc entry */ 101578Srgrimes 102578Srgrimesstruct mcd_mbx { 103578Srgrimes short unit; 104578Srgrimes short port; 105578Srgrimes short retry; 106578Srgrimes short nblk; 107578Srgrimes int sz; 108578Srgrimes u_long skip; 109578Srgrimes struct buf *bp; 110578Srgrimes int p_offset; 111578Srgrimes short count; 112578Srgrimes}; 113578Srgrimes 114578Srgrimesstruct mcd_data { 115578Srgrimes short config; 116578Srgrimes short flags; 117578Srgrimes short status; 118578Srgrimes int blksize; 119578Srgrimes u_long disksize; 120578Srgrimes int iobase; 121578Srgrimes struct disklabel dlabel; 122578Srgrimes int partflags[MAXPARTITIONS]; 123578Srgrimes int openflags; 124578Srgrimes struct mcd_volinfo volinfo; 125578Srgrimes#ifndef MCDMINI 126578Srgrimes struct mcd_qchninfo toc[MCD_MAXTOCS]; 127578Srgrimes short audio_status; 128578Srgrimes struct mcd_read2 lastpb; 129578Srgrimes#endif 130578Srgrimes short debug; 131578Srgrimes struct buf head; /* head of buf queue */ 132578Srgrimes struct mcd_mbx mbx; 133578Srgrimes} mcd_data[NMCD]; 134578Srgrimes 135578Srgrimes/* reader state machine */ 136578Srgrimes#define MCD_S_BEGIN 0 137578Srgrimes#define MCD_S_BEGIN1 1 138578Srgrimes#define MCD_S_WAITSTAT 2 139578Srgrimes#define MCD_S_WAITMODE 3 140578Srgrimes#define MCD_S_WAITREAD 4 141578Srgrimes 142578Srgrimes/* prototypes */ 143578Srgrimesint mcdopen(dev_t dev); 144578Srgrimesint mcdclose(dev_t dev); 145798Swollmanvoid mcdstrategy(struct buf *bp); 146578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 147578Srgrimesint mcdsize(dev_t dev); 148578Srgrimesstatic void mcd_done(struct mcd_mbx *mbx); 149578Srgrimesstatic void mcd_start(int unit); 150578Srgrimesstatic int mcd_getdisklabel(int unit); 151578Srgrimesstatic void mcd_configure(struct mcd_data *cd); 152578Srgrimesstatic int mcd_get(int unit, char *buf, int nmax); 153578Srgrimesstatic void mcd_setflags(int unit,struct mcd_data *cd); 154578Srgrimesstatic int mcd_getstat(int unit,int sflg); 155578Srgrimesstatic int mcd_send(int unit, int cmd,int nretrys); 156578Srgrimesstatic int bcd2bin(bcd_t b); 157578Srgrimesstatic bcd_t bin2bcd(int b); 158578Srgrimesstatic void hsg2msf(int hsg, bcd_t *msf); 159578Srgrimesstatic int msf2hsg(bcd_t *msf); 160578Srgrimesstatic int mcd_volinfo(int unit); 161578Srgrimesstatic int mcd_waitrdy(int port,int dly); 162978Sjkhstatic void mcd_doread(int state, struct mcd_mbx *mbxin); 163578Srgrimes#ifndef MCDMINI 164578Srgrimesstatic int mcd_setmode(int unit, int mode); 165578Srgrimesstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q); 166578Srgrimesstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 167578Srgrimesstatic int mcd_toc_header(int unit, struct ioc_toc_header *th); 168578Srgrimesstatic int mcd_read_toc(int unit); 169578Srgrimesstatic int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); 170578Srgrimesstatic int mcd_stop(int unit); 171578Srgrimesstatic int mcd_playtracks(int unit, struct ioc_play_track *pt); 172578Srgrimesstatic int mcd_play(int unit, struct mcd_read2 *pb); 173578Srgrimesstatic int mcd_pause(int unit); 174578Srgrimesstatic int mcd_resume(int unit); 175578Srgrimes#endif 176578Srgrimes 177578Srgrimesextern int hz; 178578Srgrimesextern int mcd_probe(struct isa_device *dev); 179578Srgrimesextern int mcd_attach(struct isa_device *dev); 180578Srgrimesstruct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 181578Srgrimes 182578Srgrimes#define mcd_put(port,byte) outb(port,byte) 183578Srgrimes 184578Srgrimes#define MCD_RETRYS 5 185578Srgrimes#define MCD_RDRETRYS 8 186578Srgrimes 187578Srgrimes#define MCDBLK 2048 /* for cooked mode */ 188578Srgrimes#define MCDRBLK 2352 /* for raw mode */ 189578Srgrimes 190578Srgrimes/* several delays */ 191578Srgrimes#define RDELAY_WAITSTAT 300 192578Srgrimes#define RDELAY_WAITMODE 300 193578Srgrimes#define RDELAY_WAITREAD 800 194578Srgrimes 195578Srgrimes#define DELAY_STATUS 10000l /* 10000 * 1us */ 196578Srgrimes#define DELAY_GETREPLY 200000l /* 200000 * 2us */ 197578Srgrimes#define DELAY_SEEKREAD 20000l /* 20000 * 1us */ 198578Srgrimes#define mcd_delay DELAY 199578Srgrimes 200578Srgrimesint mcd_attach(struct isa_device *dev) 201578Srgrimes{ 202578Srgrimes struct mcd_data *cd = mcd_data + dev->id_unit; 203578Srgrimes int i; 204578Srgrimes 205578Srgrimes cd->iobase = dev->id_iobase; 206578Srgrimes cd->flags |= MCDINIT; 207578Srgrimes cd->openflags = 0; 208578Srgrimes for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 209578Srgrimes 210578Srgrimes#ifdef NOTYET 211578Srgrimes /* wire controller for interrupts and dma */ 212578Srgrimes mcd_configure(cd); 213578Srgrimes#endif 214578Srgrimes 215578Srgrimes return 1; 216578Srgrimes} 217578Srgrimes 218578Srgrimesint mcdopen(dev_t dev) 219578Srgrimes{ 220578Srgrimes int unit,part,phys; 221578Srgrimes struct mcd_data *cd; 222578Srgrimes 223578Srgrimes unit = mcd_unit(dev); 224578Srgrimes if (unit >= NMCD) 225578Srgrimes return ENXIO; 226578Srgrimes 227578Srgrimes cd = mcd_data + unit; 228578Srgrimes part = mcd_part(dev); 229578Srgrimes phys = mcd_phys(dev); 230578Srgrimes 231578Srgrimes /* not initialized*/ 232578Srgrimes if (!(cd->flags & MCDINIT)) 233578Srgrimes return ENXIO; 234578Srgrimes 235578Srgrimes /* invalidated in the meantime? mark all open part's invalid */ 236578Srgrimes if (!(cd->flags & MCDVALID) && cd->openflags) 237578Srgrimes return ENXIO; 238578Srgrimes 239578Srgrimes if (mcd_getstat(unit,1) < 0) 240578Srgrimes return ENXIO; 241578Srgrimes 242578Srgrimes /* XXX get a default disklabel */ 243578Srgrimes mcd_getdisklabel(unit); 244578Srgrimes 245578Srgrimes if (mcdsize(dev) < 0) { 246578Srgrimes printf("mcd%d: failed to get disk size\n",unit); 247578Srgrimes return ENXIO; 248578Srgrimes } else 249578Srgrimes cd->flags |= MCDVALID; 250578Srgrimes 251578SrgrimesMCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 252578Srgrimes part,cd->disksize,cd->blksize,0); 253578Srgrimes 254578Srgrimes if (part == RAW_PART || 255578Srgrimes (part < cd->dlabel.d_npartitions && 256578Srgrimes cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 257578Srgrimes cd->partflags[part] |= MCDOPEN; 258578Srgrimes cd->openflags |= (1<<part); 259578Srgrimes if (part == RAW_PART && phys != 0) 260578Srgrimes cd->partflags[part] |= MCDREADRAW; 261578Srgrimes return 0; 262578Srgrimes } 263578Srgrimes 264578Srgrimes return ENXIO; 265578Srgrimes} 266578Srgrimes 267578Srgrimesint mcdclose(dev_t dev) 268578Srgrimes{ 269578Srgrimes int unit,part,phys; 270578Srgrimes struct mcd_data *cd; 271578Srgrimes 272578Srgrimes unit = mcd_unit(dev); 273578Srgrimes if (unit >= NMCD) 274578Srgrimes return ENXIO; 275578Srgrimes 276578Srgrimes cd = mcd_data + unit; 277578Srgrimes part = mcd_part(dev); 278578Srgrimes phys = mcd_phys(dev); 279578Srgrimes 280578Srgrimes if (!(cd->flags & MCDINIT)) 281578Srgrimes return ENXIO; 282578Srgrimes 283578Srgrimes mcd_getstat(unit,1); /* get status */ 284578Srgrimes 285578Srgrimes /* close channel */ 286578Srgrimes cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 287578Srgrimes cd->openflags &= ~(1<<part); 288578Srgrimes MCD_TRACE("close: partition=%d\n",part,0,0,0); 289578Srgrimes 290578Srgrimes return 0; 291578Srgrimes} 292578Srgrimes 293798Swollmanvoid 294798Swollmanmcdstrategy(struct buf *bp) 295578Srgrimes{ 296578Srgrimes struct mcd_data *cd; 297578Srgrimes struct buf *qp; 298578Srgrimes int s; 299578Srgrimes 300578Srgrimes int unit = mcd_unit(bp->b_dev); 301578Srgrimes 302578Srgrimes cd = mcd_data + unit; 303578Srgrimes 304578Srgrimes /* test validity */ 305578Srgrimes/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 306578Srgrimes bp,unit,bp->b_blkno,bp->b_bcount);*/ 307578Srgrimes if (unit >= NMCD || bp->b_blkno < 0) { 308578Srgrimes printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 309578Srgrimes unit, bp->b_blkno, bp->b_bcount); 310578Srgrimes pg("mcd: mcdstratregy failure"); 311578Srgrimes bp->b_error = EINVAL; 312578Srgrimes bp->b_flags |= B_ERROR; 313578Srgrimes goto bad; 314578Srgrimes } 315578Srgrimes 316578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 317578Srgrimes if (!(cd->flags & MCDVALID)) { 318578SrgrimesMCD_TRACE("strategy: drive not valid\n",0,0,0,0); 319578Srgrimes bp->b_error = EIO; 320578Srgrimes goto bad; 321578Srgrimes } 322578Srgrimes 323578Srgrimes /* read only */ 324578Srgrimes if (!(bp->b_flags & B_READ)) { 325578Srgrimes bp->b_error = EROFS; 326578Srgrimes goto bad; 327578Srgrimes } 328578Srgrimes 329578Srgrimes /* no data to read */ 330578Srgrimes if (bp->b_bcount == 0) 331578Srgrimes goto done; 332578Srgrimes 333578Srgrimes /* for non raw access, check partition limits */ 334578Srgrimes if (mcd_part(bp->b_dev) != RAW_PART) { 335578Srgrimes if (!(cd->flags & MCDLABEL)) { 336578Srgrimes bp->b_error = EIO; 337578Srgrimes goto bad; 338578Srgrimes } 339578Srgrimes /* adjust transfer if necessary */ 340578Srgrimes if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 341578Srgrimes goto done; 342578Srgrimes } 343578Srgrimes } 344578Srgrimes 345578Srgrimes /* queue it */ 346578Srgrimes qp = &cd->head; 347578Srgrimes s = splbio(); 348578Srgrimes disksort(qp,bp); 349578Srgrimes splx(s); 350578Srgrimes 351578Srgrimes /* now check whether we can perform processing */ 352578Srgrimes mcd_start(unit); 353578Srgrimes return; 354578Srgrimes 355578Srgrimesbad: 356578Srgrimes bp->b_flags |= B_ERROR; 357578Srgrimesdone: 358578Srgrimes bp->b_resid = bp->b_bcount; 359578Srgrimes biodone(bp); 360578Srgrimes return; 361578Srgrimes} 362578Srgrimes 363578Srgrimesstatic void mcd_start(int unit) 364578Srgrimes{ 365578Srgrimes struct mcd_data *cd = mcd_data + unit; 366578Srgrimes struct buf *bp, *qp = &cd->head; 367578Srgrimes struct partition *p; 368578Srgrimes int part; 369578Srgrimes register s = splbio(); 370578Srgrimes 371578Srgrimes if (cd->flags & MCDMBXBSY) 372578Srgrimes return; 373578Srgrimes 374578Srgrimes if ((bp = qp->b_actf) != 0) { 375578Srgrimes /* block found to process, dequeue */ 376578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 377578Srgrimes qp->b_actf = bp->av_forw; 378578Srgrimes splx(s); 379578Srgrimes } else { 380578Srgrimes /* nothing to do */ 381578Srgrimes splx(s); 382578Srgrimes return; 383578Srgrimes } 384578Srgrimes 385578Srgrimes /* changed media? */ 386578Srgrimes if (!(cd->flags & MCDVALID)) { 387578Srgrimes MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 388578Srgrimes return; 389578Srgrimes } 390578Srgrimes 391578Srgrimes p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 392578Srgrimes 393578Srgrimes cd->flags |= MCDMBXBSY; 394578Srgrimes cd->mbx.unit = unit; 395578Srgrimes cd->mbx.port = cd->iobase; 396578Srgrimes cd->mbx.retry = MCD_RETRYS; 397578Srgrimes cd->mbx.bp = bp; 398578Srgrimes cd->mbx.p_offset = p->p_offset; 399578Srgrimes 400578Srgrimes /* calling the read routine */ 401978Sjkh mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 402578Srgrimes /* triggers mcd_start, when successful finished */ 403578Srgrimes return; 404578Srgrimes} 405578Srgrimes 406578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 407578Srgrimes{ 408578Srgrimes struct mcd_data *cd; 409578Srgrimes int unit,part; 410578Srgrimes 411578Srgrimes unit = mcd_unit(dev); 412578Srgrimes part = mcd_part(dev); 413578Srgrimes cd = mcd_data + unit; 414578Srgrimes 415578Srgrimes#ifdef MCDMINI 416578Srgrimes return ENOTTY; 417578Srgrimes#else 418578Srgrimes if (!(cd->flags & MCDVALID)) 419578Srgrimes return EIO; 420578SrgrimesMCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 421578Srgrimes 422578Srgrimes switch (cmd) { 423578Srgrimes case DIOCSBAD: 424578Srgrimes return EINVAL; 425578Srgrimes case DIOCGDINFO: 426578Srgrimes case DIOCGPART: 427578Srgrimes case DIOCWDINFO: 428578Srgrimes case DIOCSDINFO: 429578Srgrimes case DIOCWLABEL: 430578Srgrimes return ENOTTY; 431578Srgrimes case CDIOCPLAYTRACKS: 432578Srgrimes return mcd_playtracks(unit, (struct ioc_play_track *) addr); 433578Srgrimes case CDIOCPLAYBLOCKS: 434578Srgrimes return mcd_play(unit, (struct mcd_read2 *) addr); 435578Srgrimes case CDIOCREADSUBCHANNEL: 436578Srgrimes return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 437578Srgrimes case CDIOREADTOCHEADER: 438578Srgrimes return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 439578Srgrimes case CDIOREADTOCENTRYS: 440578Srgrimes return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); 441578Srgrimes case CDIOCSETPATCH: 442578Srgrimes case CDIOCGETVOL: 443578Srgrimes case CDIOCSETVOL: 444578Srgrimes case CDIOCSETMONO: 445578Srgrimes case CDIOCSETSTERIO: 446578Srgrimes case CDIOCSETMUTE: 447578Srgrimes case CDIOCSETLEFT: 448578Srgrimes case CDIOCSETRIGHT: 449578Srgrimes return EINVAL; 450578Srgrimes case CDIOCRESUME: 451578Srgrimes return mcd_resume(unit); 452578Srgrimes case CDIOCPAUSE: 453578Srgrimes return mcd_pause(unit); 454578Srgrimes case CDIOCSTART: 455578Srgrimes return EINVAL; 456578Srgrimes case CDIOCSTOP: 457578Srgrimes return mcd_stop(unit); 458578Srgrimes case CDIOCEJECT: 459578Srgrimes return EINVAL; 460578Srgrimes case CDIOCSETDEBUG: 461578Srgrimes cd->debug = 1; 462578Srgrimes return 0; 463578Srgrimes case CDIOCCLRDEBUG: 464578Srgrimes cd->debug = 0; 465578Srgrimes return 0; 466578Srgrimes case CDIOCRESET: 467578Srgrimes return EINVAL; 468578Srgrimes default: 469578Srgrimes return ENOTTY; 470578Srgrimes } 471578Srgrimes /*NOTREACHED*/ 472578Srgrimes#endif /*!MCDMINI*/ 473578Srgrimes} 474578Srgrimes 475578Srgrimes/* this could have been taken from scsi/cd.c, but it is not clear 476578Srgrimes * whether the scsi cd driver is linked in 477578Srgrimes */ 478578Srgrimesstatic int mcd_getdisklabel(int unit) 479578Srgrimes{ 480578Srgrimes struct mcd_data *cd = mcd_data + unit; 481578Srgrimes 482578Srgrimes if (cd->flags & MCDLABEL) 483578Srgrimes return -1; 484578Srgrimes 485578Srgrimes bzero(&cd->dlabel,sizeof(struct disklabel)); 486578Srgrimes strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); 487578Srgrimes strncpy(cd->dlabel.d_packname,"unknown ",16); 488578Srgrimes cd->dlabel.d_secsize = cd->blksize; 489578Srgrimes cd->dlabel.d_nsectors = 100; 490578Srgrimes cd->dlabel.d_ntracks = 1; 491578Srgrimes cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 492578Srgrimes cd->dlabel.d_secpercyl = 100; 493578Srgrimes cd->dlabel.d_secperunit = cd->disksize; 494578Srgrimes cd->dlabel.d_rpm = 300; 495578Srgrimes cd->dlabel.d_interleave = 1; 496578Srgrimes cd->dlabel.d_flags = D_REMOVABLE; 497578Srgrimes cd->dlabel.d_npartitions= 1; 498578Srgrimes cd->dlabel.d_partitions[0].p_offset = 0; 499578Srgrimes cd->dlabel.d_partitions[0].p_size = cd->disksize; 500578Srgrimes cd->dlabel.d_partitions[0].p_fstype = 9; 501578Srgrimes cd->dlabel.d_magic = DISKMAGIC; 502578Srgrimes cd->dlabel.d_magic2 = DISKMAGIC; 503578Srgrimes cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 504578Srgrimes 505578Srgrimes cd->flags |= MCDLABEL; 506578Srgrimes return 0; 507578Srgrimes} 508578Srgrimes 509578Srgrimesint mcdsize(dev_t dev) 510578Srgrimes{ 511578Srgrimes int size; 512578Srgrimes int unit = mcd_unit(dev); 513578Srgrimes struct mcd_data *cd = mcd_data + unit; 514578Srgrimes 515578Srgrimes if (mcd_volinfo(unit) >= 0) { 516578Srgrimes cd->blksize = MCDBLK; 517578Srgrimes size = msf2hsg(cd->volinfo.vol_msf); 518578Srgrimes cd->disksize = size * (MCDBLK/DEV_BSIZE); 519578Srgrimes return 0; 520578Srgrimes } 521578Srgrimes return -1; 522578Srgrimes} 523578Srgrimes 524578Srgrimes/*************************************************************** 525578Srgrimes * lower level of driver starts here 526578Srgrimes **************************************************************/ 527578Srgrimes 528578Srgrimes#ifdef NOTDEF 529578Srgrimesstatic char irqs[] = { 530578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 531578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 532578Srgrimes}; 533578Srgrimes 534578Srgrimesstatic char drqs[] = { 535578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 536578Srgrimes}; 537578Srgrimes#endif 538578Srgrimes 539578Srgrimesstatic void mcd_configure(struct mcd_data *cd) 540578Srgrimes{ 541578Srgrimes outb(cd->iobase+mcd_config,cd->config); 542578Srgrimes} 543578Srgrimes 544978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 545578Srgrimes 546578Srgrimesint mcd_probe(struct isa_device *dev) 547578Srgrimes{ 548578Srgrimes int port = dev->id_iobase; 549578Srgrimes int unit = dev->id_unit; 550978Sjkh int i,j; 551578Srgrimes int st; 552578Srgrimes int check; 553578Srgrimes int junk; 554578Srgrimes 555578Srgrimes mcd_data[unit].flags = MCDPROBING; 556578Srgrimes 557578Srgrimes#ifdef NOTDEF 558578Srgrimes /* get irq/drq configuration word */ 559578Srgrimes mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 560578Srgrimes#else 561578Srgrimes mcd_data[unit].config = 0; 562578Srgrimes#endif 563578Srgrimes 564578Srgrimes /* send a reset */ 565978Sjkh outb(port+MCD_FLAGS,M_RESET); 566982Snate DELAY(3000); 567578Srgrimes 568978Sjkh for (j=3; j != 0; j--) { 569578Srgrimes 570978Sjkh /* get any pending garbage (old data) and throw away...*/ 571978Sjkh for (i=10; i != 0; i--) { 572978Sjkh inb(port+MCD_DATA); 573978Sjkh } 574578Srgrimes 575578Srgrimes DELAY (2000); 576578Srgrimes outb(port+MCD_DATA,MCD_CMDCONTINFO); 577982Snate for (i = 0; i < 30000; i++) { 578978Sjkh if ((inb(port+MCD_FLAGS) & M_STATUS_AVAIL) == M_STATUS_AVAIL) 579978Sjkh { 580982Snate DELAY (600); 581978Sjkh st = inb(port+MCD_DATA); 582978Sjkh DELAY (500); 583978Sjkh check = inb(port+MCD_DATA); 584978Sjkh DELAY (500); 585978Sjkh junk = inb(port+MCD_DATA); /* What is byte used for?!?!? */ 586978Sjkh 587978Sjkh if (check = 'M') { 588578Srgrimes#ifdef DEBUG 589578Srgrimes printf("Mitsumi drive detected\n"); 590578Srgrimes#endif 591578Srgrimes return 4; 592978Sjkh } else { 593578Srgrimes printf("Mitsumi drive NOT detected\n"); 594578Srgrimes return 0; 595978Sjkh } 596978Sjkh } 597978Sjkh } 598978Sjkh } 5991000Sats return 0; 600578Srgrimes} 601578Srgrimes 602978Sjkh 603578Srgrimesstatic int mcd_waitrdy(int port,int dly) 604578Srgrimes{ 605578Srgrimes int i; 606578Srgrimes 607578Srgrimes /* wait until xfer port senses data ready */ 608578Srgrimes for (i=0; i<dly; i++) { 609578Srgrimes if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0) 610578Srgrimes return 0; 611578Srgrimes mcd_delay(1); 612578Srgrimes } 613578Srgrimes return -1; 614578Srgrimes} 615578Srgrimes 616578Srgrimesstatic int mcd_getreply(int unit,int dly) 617578Srgrimes{ 618578Srgrimes int i; 619578Srgrimes struct mcd_data *cd = mcd_data + unit; 620578Srgrimes int port = cd->iobase; 621578Srgrimes 622578Srgrimes /* wait data to become ready */ 623578Srgrimes if (mcd_waitrdy(port,dly)<0) { 624578Srgrimes#ifdef MCD_TO_WARNING_ON 625578Srgrimes printf("mcd%d: timeout getreply\n",unit); 626578Srgrimes#endif 627578Srgrimes return -1; 628578Srgrimes } 629578Srgrimes 630578Srgrimes /* get the data */ 631578Srgrimes return inb(port+mcd_status) & 0xFF; 632578Srgrimes} 633578Srgrimes 634578Srgrimesstatic int mcd_getstat(int unit,int sflg) 635578Srgrimes{ 636578Srgrimes int i; 637578Srgrimes struct mcd_data *cd = mcd_data + unit; 638578Srgrimes int port = cd->iobase; 639578Srgrimes 640578Srgrimes /* get the status */ 641578Srgrimes if (sflg) 642578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 643578Srgrimes i = mcd_getreply(unit,DELAY_GETREPLY); 644578Srgrimes if (i<0) return -1; 645578Srgrimes 646578Srgrimes cd->status = i; 647578Srgrimes 648578Srgrimes mcd_setflags(unit,cd); 649578Srgrimes return cd->status; 650578Srgrimes} 651578Srgrimes 652578Srgrimesstatic void mcd_setflags(int unit, struct mcd_data *cd) 653578Srgrimes{ 654578Srgrimes /* check flags */ 655578Srgrimes if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { 656578Srgrimes MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); 657578Srgrimes cd->flags &= ~MCDVALID; 658578Srgrimes } 659578Srgrimes 660578Srgrimes#ifndef MCDMINI 661578Srgrimes if (cd->status & MCDAUDIOBSY) 662578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 663578Srgrimes else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 664578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 665578Srgrimes#endif 666578Srgrimes} 667578Srgrimes 668578Srgrimesstatic int mcd_get(int unit, char *buf, int nmax) 669578Srgrimes{ 670578Srgrimes int port = mcd_data[unit].iobase; 671578Srgrimes int i,k; 672578Srgrimes 673578Srgrimes for (i=0; i<nmax; i++) { 674578Srgrimes 675578Srgrimes /* wait for data */ 676578Srgrimes if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 677578Srgrimes#ifdef MCD_TO_WARNING_ON 678578Srgrimes printf("mcd%d: timeout mcd_get\n",unit); 679578Srgrimes#endif 680578Srgrimes return -1; 681578Srgrimes } 682578Srgrimes buf[i] = k; 683578Srgrimes } 684578Srgrimes return i; 685578Srgrimes} 686578Srgrimes 687578Srgrimesstatic int mcd_send(int unit, int cmd,int nretrys) 688578Srgrimes{ 689578Srgrimes int i,k; 690578Srgrimes int port = mcd_data[unit].iobase; 691578Srgrimes 692578Srgrimes/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/ 693578Srgrimes for (i=0; i<nretrys; i++) { 694578Srgrimes outb(port+mcd_command, cmd); 695578Srgrimes if ((k=mcd_getstat(unit,0)) != -1) 696578Srgrimes break; 697578Srgrimes } 698578Srgrimes if (i == nretrys) { 699578Srgrimes printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 700578Srgrimes return -1; 701578Srgrimes } 702578Srgrimes/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/ 703578Srgrimes return 0; 704578Srgrimes} 705578Srgrimes 706578Srgrimesstatic int bcd2bin(bcd_t b) 707578Srgrimes{ 708578Srgrimes return (b >> 4) * 10 + (b & 15); 709578Srgrimes} 710578Srgrimes 711578Srgrimesstatic bcd_t bin2bcd(int b) 712578Srgrimes{ 713578Srgrimes return ((b / 10) << 4) | (b % 10); 714578Srgrimes} 715578Srgrimes 716578Srgrimesstatic void hsg2msf(int hsg, bcd_t *msf) 717578Srgrimes{ 718578Srgrimes hsg += 150; 719578Srgrimes M_msf(msf) = bin2bcd(hsg / 4500); 720578Srgrimes hsg %= 4500; 721578Srgrimes S_msf(msf) = bin2bcd(hsg / 75); 722578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 723578Srgrimes} 724578Srgrimes 725578Srgrimesstatic int msf2hsg(bcd_t *msf) 726578Srgrimes{ 727578Srgrimes return (bcd2bin(M_msf(msf)) * 60 + 728578Srgrimes bcd2bin(S_msf(msf))) * 75 + 729578Srgrimes bcd2bin(F_msf(msf)) - 150; 730578Srgrimes} 731578Srgrimes 732578Srgrimesstatic int mcd_volinfo(int unit) 733578Srgrimes{ 734578Srgrimes struct mcd_data *cd = mcd_data + unit; 735578Srgrimes int i; 736578Srgrimes 737578Srgrimes/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 738578Srgrimes 739578Srgrimes /* Get the status, in case the disc has been changed */ 740578Srgrimes if (mcd_getstat(unit, 1) < 0) return EIO; 741578Srgrimes 742578Srgrimes /* Just return if we already have it */ 743578Srgrimes if (cd->flags & MCDVOLINFO) return 0; 744578Srgrimes 745578Srgrimes /* send volume info command */ 746578Srgrimes if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 747578Srgrimes return -1; 748578Srgrimes 749578Srgrimes /* get data */ 750578Srgrimes if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 751578Srgrimes printf("mcd%d: mcd_volinfo: error read data\n",unit); 752578Srgrimes return -1; 753578Srgrimes } 754578Srgrimes 755578Srgrimes if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { 756578Srgrimes cd->flags |= MCDVOLINFO; /* volinfo is OK */ 757578Srgrimes return 0; 758578Srgrimes } 759578Srgrimes 760578Srgrimes return -1; 761578Srgrimes} 762578Srgrimes 763798Swollmanvoid 764798Swollmanmcdintr(unit) 765798Swollman int unit; 766578Srgrimes{ 767578Srgrimes int port = mcd_data[unit].iobase; 768578Srgrimes u_int i; 769578Srgrimes 770578Srgrimes MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); 771578Srgrimes 772578Srgrimes /* just read out status and ignore the rest */ 773578Srgrimes if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { 774578Srgrimes i = inb(port+mcd_status); 775578Srgrimes } 776578Srgrimes} 777578Srgrimes 778578Srgrimes/* state machine to process read requests 779578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 780578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 781578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 782578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 783578Srgrimes */ 784578Srgrimesstatic struct mcd_mbx *mbxsave; 785578Srgrimes 786978Sjkhstatic void mcd_doread(int state, struct mcd_mbx *mbxin) 787578Srgrimes{ 788578Srgrimes struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 789578Srgrimes int unit = mbx->unit; 790578Srgrimes int port = mbx->port; 791578Srgrimes struct buf *bp = mbx->bp; 792578Srgrimes struct mcd_data *cd = mcd_data + unit; 793578Srgrimes 794578Srgrimes int rm,i,k; 795578Srgrimes struct mcd_read2 rbuf; 796578Srgrimes int blknum; 797578Srgrimes caddr_t addr; 798578Srgrimes 799578Srgrimesloop: 800578Srgrimes switch (state) { 801578Srgrimes case MCD_S_BEGIN: 802578Srgrimes mbx = mbxsave = mbxin; 803578Srgrimes 804578Srgrimes case MCD_S_BEGIN1: 805578Srgrimes /* get status */ 806578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 807578Srgrimes mbx->count = RDELAY_WAITSTAT; 808798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 809578Srgrimes return; 810578Srgrimes case MCD_S_WAITSTAT: 8111000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT); 812578Srgrimes if (mbx->count-- >= 0) { 813578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 814798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 815578Srgrimes return; 816578Srgrimes } 817578Srgrimes mcd_setflags(unit,cd); 818578Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n",RDELAY_WAITSTAT-mbx->count,0,0,0); 819578Srgrimes /* reject, if audio active */ 820578Srgrimes if (cd->status & MCDAUDIOBSY) { 821578Srgrimes printf("mcd%d: audio is active\n",unit); 822578Srgrimes goto readerr; 823578Srgrimes } 824578Srgrimes 825578Srgrimes /* to check for raw/cooked mode */ 826578Srgrimes if (cd->flags & MCDREADRAW) { 827578Srgrimes rm = MCD_MD_RAW; 828578Srgrimes mbx->sz = MCDRBLK; 829578Srgrimes } else { 830578Srgrimes rm = MCD_MD_COOKED; 831578Srgrimes mbx->sz = cd->blksize; 832578Srgrimes } 833578Srgrimes 834578Srgrimes mbx->count = RDELAY_WAITMODE; 835578Srgrimes 836578Srgrimes mcd_put(port+mcd_command, MCD_CMDSETMODE); 837578Srgrimes mcd_put(port+mcd_command, rm); 838798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */ 839578Srgrimes return; 840578Srgrimes } else { 841578Srgrimes#ifdef MCD_TO_WARNING_ON 842578Srgrimes printf("mcd%d: timeout getstatus\n",unit); 843578Srgrimes#endif 844578Srgrimes goto readerr; 845578Srgrimes } 846578Srgrimes 847578Srgrimes case MCD_S_WAITMODE: 8481000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE); 849578Srgrimes if (mbx->count-- < 0) { 850578Srgrimes#ifdef MCD_TO_WARNING_ON 851578Srgrimes printf("mcd%d: timeout set mode\n",unit); 852578Srgrimes#endif 853578Srgrimes goto readerr; 854578Srgrimes } 855578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 856798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); 857578Srgrimes return; 858578Srgrimes } 859578Srgrimes mcd_setflags(unit,cd); 860578Srgrimes MCD_TRACE("got WAITMODE delay=%d\n",RDELAY_WAITMODE-mbx->count,0,0,0); 861578Srgrimes /* for first block */ 862578Srgrimes mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 863578Srgrimes mbx->skip = 0; 864578Srgrimes 865578Srgrimesnextblock: 866578Srgrimes blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 867578Srgrimes + mbx->p_offset + mbx->skip/mbx->sz; 868578Srgrimes 869578Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",blknum,bp,0,0); 870578Srgrimes 871578Srgrimes /* build parameter block */ 872578Srgrimes hsg2msf(blknum,rbuf.start_msf); 873578Srgrimes 874578Srgrimes /* send the read command */ 875578Srgrimes mcd_put(port+mcd_command,MCD_CMDREAD2); 876578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[0]); 877578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[1]); 878578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[2]); 879578Srgrimes mcd_put(port+mcd_command,0); 880578Srgrimes mcd_put(port+mcd_command,0); 881578Srgrimes mcd_put(port+mcd_command,1); 882578Srgrimes mbx->count = RDELAY_WAITREAD; 883798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 884578Srgrimes return; 885578Srgrimes case MCD_S_WAITREAD: 8861000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD); 887578Srgrimes if (mbx->count-- > 0) { 888578Srgrimes k = inb(port+mcd_xfer); 889578Srgrimes if ((k & 2)==0) { 890578Srgrimes MCD_TRACE("got data delay=%d\n",RDELAY_WAITREAD-mbx->count,0,0,0); 891578Srgrimes /* data is ready */ 892578Srgrimes addr = bp->b_un.b_addr + mbx->skip; 893578Srgrimes outb(port+mcd_ctl2,0x04); /* XXX */ 894578Srgrimes for (i=0; i<mbx->sz; i++) 895578Srgrimes *addr++ = inb(port+mcd_rdata); 896578Srgrimes outb(port+mcd_ctl2,0x0c); /* XXX */ 897578Srgrimes 898578Srgrimes if (--mbx->nblk > 0) { 899578Srgrimes mbx->skip += mbx->sz; 900578Srgrimes goto nextblock; 901578Srgrimes } 902578Srgrimes 903578Srgrimes /* return buffer */ 904578Srgrimes bp->b_resid = 0; 905578Srgrimes biodone(bp); 906578Srgrimes 907578Srgrimes cd->flags &= ~MCDMBXBSY; 908578Srgrimes mcd_start(mbx->unit); 909578Srgrimes return; 910578Srgrimes } 911578Srgrimes if ((k & 4)==0) 912578Srgrimes mcd_getstat(unit,0); 913798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 914578Srgrimes return; 915578Srgrimes } else { 916578Srgrimes#ifdef MCD_TO_WARNING_ON 917578Srgrimes printf("mcd%d: timeout read data\n",unit); 918578Srgrimes#endif 919578Srgrimes goto readerr; 920578Srgrimes } 921578Srgrimes } 922578Srgrimes 923578Srgrimesreaderr: 924578Srgrimes if (mbx->retry-- > 0) { 925578Srgrimes#ifdef MCD_TO_WARNING_ON 926578Srgrimes printf("mcd%d: retrying\n",unit); 927578Srgrimes#endif 928578Srgrimes state = MCD_S_BEGIN1; 929578Srgrimes goto loop; 930578Srgrimes } 931578Srgrimes 932578Srgrimes /* invalidate the buffer */ 933578Srgrimes bp->b_flags |= B_ERROR; 934578Srgrimes bp->b_resid = bp->b_bcount; 935578Srgrimes biodone(bp); 936578Srgrimes mcd_start(mbx->unit); 937578Srgrimes return; 938578Srgrimes 939578Srgrimes#ifdef NOTDEF 940578Srgrimes printf("mcd%d: unit timeout, resetting\n",mbx->unit); 941578Srgrimes outb(mbx->port+mcd_reset,MCD_CMDRESET); 942578Srgrimes DELAY(300000); 943578Srgrimes (void)mcd_getstat(mbx->unit,1); 944578Srgrimes (void)mcd_getstat(mbx->unit,1); 945578Srgrimes /*cd->status &= ~MCDDSKCHNG; */ 946578Srgrimes cd->debug = 1; /* preventive set debug mode */ 947578Srgrimes 948578Srgrimes#endif 949578Srgrimes 950578Srgrimes} 951578Srgrimes 952578Srgrimes#ifndef MCDMINI 953578Srgrimesstatic int mcd_setmode(int unit, int mode) 954578Srgrimes{ 955578Srgrimes struct mcd_data *cd = mcd_data + unit; 956578Srgrimes int port = cd->iobase; 957578Srgrimes int retry; 958578Srgrimes 959578Srgrimes printf("mcd%d: setting mode to %d\n", unit, mode); 960578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 961578Srgrimes { 962578Srgrimes outb(port+mcd_command, MCD_CMDSETMODE); 963578Srgrimes outb(port+mcd_command, mode); 964578Srgrimes if (mcd_getstat(unit, 0) != -1) return 0; 965578Srgrimes } 966578Srgrimes 967578Srgrimes return -1; 968578Srgrimes} 969578Srgrimes 970578Srgrimesstatic int mcd_toc_header(int unit, struct ioc_toc_header *th) 971578Srgrimes{ 972578Srgrimes struct mcd_data *cd = mcd_data + unit; 973578Srgrimes 974578Srgrimes if (mcd_volinfo(unit) < 0) 975578Srgrimes return ENXIO; 976578Srgrimes 977578Srgrimes th->len = msf2hsg(cd->volinfo.vol_msf); 978578Srgrimes th->starting_track = bcd2bin(cd->volinfo.trk_low); 979578Srgrimes th->ending_track = bcd2bin(cd->volinfo.trk_high); 980578Srgrimes 981578Srgrimes return 0; 982578Srgrimes} 983578Srgrimes 984578Srgrimesstatic int mcd_read_toc(int unit) 985578Srgrimes{ 986578Srgrimes struct mcd_data *cd = mcd_data + unit; 987578Srgrimes struct ioc_toc_header th; 988578Srgrimes struct mcd_qchninfo q; 989578Srgrimes int rc, trk, idx, retry; 990578Srgrimes 991578Srgrimes /* Only read TOC if needed */ 992578Srgrimes if (cd->flags & MCDTOC) return 0; 993578Srgrimes 994578Srgrimes printf("mcd%d: reading toc header\n", unit); 995578Srgrimes if (mcd_toc_header(unit, &th) != 0) 996578Srgrimes return ENXIO; 997578Srgrimes 998578Srgrimes printf("mcd%d: stopping play\n", unit); 999578Srgrimes if ((rc=mcd_stop(unit)) != 0) 1000578Srgrimes return rc; 1001578Srgrimes 1002578Srgrimes /* try setting the mode twice */ 1003578Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) 1004578Srgrimes return EIO; 1005578Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) 1006578Srgrimes return EIO; 1007578Srgrimes 1008578Srgrimes printf("mcd%d: get_toc reading qchannel info\n",unit); 1009578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1010578Srgrimes cd->toc[trk].idx_no = 0; 1011578Srgrimes trk = th.ending_track - th.starting_track + 1; 1012578Srgrimes for(retry=0; retry<300 && trk>0; retry++) 1013578Srgrimes { 1014578Srgrimes if (mcd_getqchan(unit, &q) < 0) break; 1015578Srgrimes idx = bcd2bin(q.idx_no); 1016578Srgrimes if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) 1017578Srgrimes if (cd->toc[idx].idx_no == 0) 1018578Srgrimes { 1019578Srgrimes cd->toc[idx] = q; 1020578Srgrimes trk--; 1021578Srgrimes } 1022578Srgrimes } 1023578Srgrimes 1024578Srgrimes if (mcd_setmode(unit, MCD_MD_COOKED) != 0) 1025578Srgrimes return EIO; 1026578Srgrimes 1027578Srgrimes if (trk != 0) return ENXIO; 1028578Srgrimes 1029578Srgrimes /* add a fake last+1 */ 1030578Srgrimes idx = th.ending_track + 1; 1031578Srgrimes cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1032578Srgrimes cd->toc[idx].trk_no = 0; 1033578Srgrimes cd->toc[idx].idx_no = 0xAA; 1034578Srgrimes cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1035578Srgrimes cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1036578Srgrimes cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1037578Srgrimes 1038578Srgrimes cd->flags |= MCDTOC; 1039578Srgrimes 1040578Srgrimes return 0; 1041578Srgrimes} 1042578Srgrimes 1043578Srgrimesstatic int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te) 1044578Srgrimes{ 1045578Srgrimes struct mcd_data *cd = mcd_data + unit; 1046578Srgrimes struct ret_toc 1047578Srgrimes { 1048578Srgrimes struct ioc_toc_header th; 1049578Srgrimes struct cd_toc_entry rt; 1050578Srgrimes } ret_toc; 1051578Srgrimes struct ioc_toc_header th; 1052578Srgrimes int rc, i; 1053578Srgrimes 1054578Srgrimes /* Make sure we have a valid toc */ 1055578Srgrimes if ((rc=mcd_read_toc(unit)) != 0) 1056578Srgrimes return rc; 1057578Srgrimes 1058578Srgrimes /* find the toc to copy*/ 1059578Srgrimes i = te->starting_track; 1060578Srgrimes if (i == MCD_LASTPLUS1) 1061578Srgrimes i = bcd2bin(cd->volinfo.trk_high) + 1; 1062578Srgrimes 1063578Srgrimes /* verify starting track */ 1064578Srgrimes if (i < bcd2bin(cd->volinfo.trk_low) || 1065578Srgrimes i > bcd2bin(cd->volinfo.trk_high)+1) 1066578Srgrimes return EINVAL; 1067578Srgrimes 1068578Srgrimes /* do we have room */ 1069578Srgrimes if (te->data_len < sizeof(struct ioc_toc_header) + 1070578Srgrimes sizeof(struct cd_toc_entry)) return EINVAL; 1071578Srgrimes 1072578Srgrimes /* Copy the toc header */ 1073578Srgrimes if (mcd_toc_header(unit, &th) < 0) return EIO; 1074578Srgrimes ret_toc.th = th; 1075578Srgrimes 1076578Srgrimes /* copy the toc data */ 1077578Srgrimes ret_toc.rt.control = cd->toc[i].ctrl_adr; 1078578Srgrimes ret_toc.rt.addr_type = te->address_format; 1079578Srgrimes ret_toc.rt.track = i; 1080578Srgrimes if (te->address_format == CD_MSF_FORMAT) 1081578Srgrimes { 10821097Srgrimes ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0]; 10831097Srgrimes ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1]; 10841097Srgrimes ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2]; 1085578Srgrimes } 1086578Srgrimes 1087578Srgrimes /* copy the data back */ 1088578Srgrimes copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) 1089578Srgrimes + sizeof(struct ioc_toc_header)); 1090578Srgrimes 1091578Srgrimes return 0; 1092578Srgrimes} 1093578Srgrimes 1094578Srgrimesstatic int mcd_stop(int unit) 1095578Srgrimes{ 1096578Srgrimes struct mcd_data *cd = mcd_data + unit; 1097578Srgrimes 1098578Srgrimes if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1099578Srgrimes return ENXIO; 1100578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 1101578Srgrimes return 0; 1102578Srgrimes} 1103578Srgrimes 1104578Srgrimesstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q) 1105578Srgrimes{ 1106578Srgrimes struct mcd_data *cd = mcd_data + unit; 1107578Srgrimes 1108578Srgrimes if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1109578Srgrimes return -1; 1110578Srgrimes if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1111578Srgrimes return -1; 1112578Srgrimes if (cd->debug) 1113578Srgrimes printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", 1114578Srgrimes unit, 1115578Srgrimes q->ctrl_adr, q->trk_no, q->idx_no, 1116578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], 1117578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); 1118578Srgrimes return 0; 1119578Srgrimes} 1120578Srgrimes 1121578Srgrimesstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc) 1122578Srgrimes{ 1123578Srgrimes struct mcd_data *cd = mcd_data + unit; 1124578Srgrimes struct mcd_qchninfo q; 1125578Srgrimes struct cd_sub_channel_info data; 1126578Srgrimes 1127578Srgrimes printf("mcd%d: subchan af=%d, df=%d\n", unit, 1128578Srgrimes sc->address_format, 1129578Srgrimes sc->data_format); 1130578Srgrimes if (sc->address_format != CD_MSF_FORMAT) return EIO; 1131578Srgrimes if (sc->data_format != CD_CURRENT_POSITION) return EIO; 1132578Srgrimes 1133578Srgrimes if (mcd_getqchan(unit, &q) < 0) return EIO; 1134578Srgrimes 1135578Srgrimes data.header.audio_status = cd->audio_status; 1136578Srgrimes data.what.position.data_format = CD_MSF_FORMAT; 1137578Srgrimes data.what.position.track_number = bcd2bin(q.trk_no); 1138578Srgrimes 1139578Srgrimes if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) 1140578Srgrimes return EFAULT; 1141578Srgrimes return 0; 1142578Srgrimes} 1143578Srgrimes 1144578Srgrimesstatic int mcd_playtracks(int unit, struct ioc_play_track *pt) 1145578Srgrimes{ 1146578Srgrimes struct mcd_data *cd = mcd_data + unit; 1147578Srgrimes struct mcd_read2 pb; 1148578Srgrimes int a = pt->start_track; 1149578Srgrimes int z = pt->end_track; 1150578Srgrimes int rc; 1151578Srgrimes 1152578Srgrimes if ((rc = mcd_read_toc(unit)) != 0) return rc; 1153578Srgrimes 1154578Srgrimes printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 1155578Srgrimes a, pt->start_index, z, pt->end_index); 1156578Srgrimes 1157578Srgrimes if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || 1158578Srgrimes z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) 1159578Srgrimes return EINVAL; 1160578Srgrimes 1161578Srgrimes pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; 1162578Srgrimes pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; 1163578Srgrimes pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; 1164578Srgrimes pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; 1165578Srgrimes pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; 1166578Srgrimes pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; 1167578Srgrimes 1168578Srgrimes return mcd_play(unit, &pb); 1169578Srgrimes} 1170578Srgrimes 1171578Srgrimesstatic int mcd_play(int unit, struct mcd_read2 *pb) 1172578Srgrimes{ 1173578Srgrimes struct mcd_data *cd = mcd_data + unit; 1174578Srgrimes int port = cd->iobase; 1175578Srgrimes int retry, st; 1176578Srgrimes 1177578Srgrimes cd->lastpb = *pb; 1178578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1179578Srgrimes { 1180578Srgrimes outb(port+mcd_command, MCD_CMDREAD2); 1181578Srgrimes outb(port+mcd_command, pb->start_msf[0]); 1182578Srgrimes outb(port+mcd_command, pb->start_msf[1]); 1183578Srgrimes outb(port+mcd_command, pb->start_msf[2]); 1184578Srgrimes outb(port+mcd_command, pb->end_msf[0]); 1185578Srgrimes outb(port+mcd_command, pb->end_msf[1]); 1186578Srgrimes outb(port+mcd_command, pb->end_msf[2]); 1187578Srgrimes if ((st=mcd_getstat(unit, 0)) != -1) break; 1188578Srgrimes } 1189578Srgrimes 1190578Srgrimes if (cd->debug) 1191578Srgrimes printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); 1192578Srgrimes if (st == -1) return ENXIO; 1193578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1194578Srgrimes return 0; 1195578Srgrimes} 1196578Srgrimes 1197578Srgrimesstatic int mcd_pause(int unit) 1198578Srgrimes{ 1199578Srgrimes struct mcd_data *cd = mcd_data + unit; 1200578Srgrimes struct mcd_qchninfo q; 1201578Srgrimes int rc; 1202578Srgrimes 1203578Srgrimes /* Verify current status */ 1204578Srgrimes if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) 1205578Srgrimes { 1206578Srgrimes printf("mcd%d: pause attempted when not playing\n", unit); 1207578Srgrimes return EINVAL; 1208578Srgrimes } 1209578Srgrimes 1210578Srgrimes /* Get the current position */ 1211578Srgrimes if (mcd_getqchan(unit, &q) < 0) return EIO; 1212578Srgrimes 1213578Srgrimes /* Copy it into lastpb */ 1214578Srgrimes cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1215578Srgrimes cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1216578Srgrimes cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1217578Srgrimes 1218578Srgrimes /* Stop playing */ 1219578Srgrimes if ((rc=mcd_stop(unit)) != 0) return rc; 1220578Srgrimes 1221578Srgrimes /* Set the proper status and exit */ 1222578Srgrimes cd->audio_status = CD_AS_PLAY_PAUSED; 1223578Srgrimes return 0; 1224578Srgrimes} 1225578Srgrimes 1226578Srgrimesstatic int mcd_resume(int unit) 1227578Srgrimes{ 1228578Srgrimes struct mcd_data *cd = mcd_data + unit; 1229578Srgrimes 1230578Srgrimes if (cd->audio_status != CD_AS_PLAY_PAUSED) return EINVAL; 1231578Srgrimes return mcd_play(unit, &cd->lastpb); 1232578Srgrimes} 1233578Srgrimes#endif /*!MCDMINI*/ 1234578Srgrimes 1235578Srgrimes#endif /* NMCD > 0 */ 1236