mcd.c revision 1437
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 * 421437Sgclarkii * $Id: mcd.c,v 1.15 1994/04/20 07:06:41 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) 821294Sats#define RAW_PART 0 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 1021241Sjkh/* These are apparently the different states a mitsumi can get up to */ 1031241Sjkh#define MCDCDABSENT 0x0030 1041241Sjkh#define MCDCDPRESENT 0x0020 1051241Sjkh#define MCDSCLOSED 0x0080 1061241Sjkh#define MCDSOPEN 0x00a0 1071237Sjkh 108578Srgrimes/* toc */ 109578Srgrimes#define MCD_MAXTOCS 104 /* from the Linux driver */ 110578Srgrimes#define MCD_LASTPLUS1 170 /* special toc entry */ 111578Srgrimes 112578Srgrimesstruct mcd_mbx { 113578Srgrimes short unit; 114578Srgrimes short port; 115578Srgrimes short retry; 116578Srgrimes short nblk; 117578Srgrimes int sz; 118578Srgrimes u_long skip; 119578Srgrimes struct buf *bp; 120578Srgrimes int p_offset; 121578Srgrimes short count; 122578Srgrimes}; 123578Srgrimes 124578Srgrimesstruct mcd_data { 125578Srgrimes short config; 126578Srgrimes short flags; 127578Srgrimes short status; 128578Srgrimes int blksize; 129578Srgrimes u_long disksize; 130578Srgrimes int iobase; 131578Srgrimes struct disklabel dlabel; 132578Srgrimes int partflags[MAXPARTITIONS]; 133578Srgrimes int openflags; 134578Srgrimes struct mcd_volinfo volinfo; 135578Srgrimes#ifndef MCDMINI 136578Srgrimes struct mcd_qchninfo toc[MCD_MAXTOCS]; 137578Srgrimes short audio_status; 138578Srgrimes struct mcd_read2 lastpb; 139578Srgrimes#endif 140578Srgrimes short debug; 141578Srgrimes struct buf head; /* head of buf queue */ 142578Srgrimes struct mcd_mbx mbx; 143578Srgrimes} mcd_data[NMCD]; 144578Srgrimes 145578Srgrimes/* reader state machine */ 146578Srgrimes#define MCD_S_BEGIN 0 147578Srgrimes#define MCD_S_BEGIN1 1 148578Srgrimes#define MCD_S_WAITSTAT 2 149578Srgrimes#define MCD_S_WAITMODE 3 150578Srgrimes#define MCD_S_WAITREAD 4 151578Srgrimes 152578Srgrimes/* prototypes */ 153578Srgrimesint mcdopen(dev_t dev); 154578Srgrimesint mcdclose(dev_t dev); 155798Swollmanvoid mcdstrategy(struct buf *bp); 156578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 157578Srgrimesint mcdsize(dev_t dev); 158578Srgrimesstatic void mcd_done(struct mcd_mbx *mbx); 159578Srgrimesstatic void mcd_start(int unit); 160578Srgrimesstatic int mcd_getdisklabel(int unit); 161578Srgrimesstatic void mcd_configure(struct mcd_data *cd); 162578Srgrimesstatic int mcd_get(int unit, char *buf, int nmax); 163578Srgrimesstatic void mcd_setflags(int unit,struct mcd_data *cd); 164578Srgrimesstatic int mcd_getstat(int unit,int sflg); 165578Srgrimesstatic int mcd_send(int unit, int cmd,int nretrys); 166578Srgrimesstatic int bcd2bin(bcd_t b); 167578Srgrimesstatic bcd_t bin2bcd(int b); 168578Srgrimesstatic void hsg2msf(int hsg, bcd_t *msf); 169578Srgrimesstatic int msf2hsg(bcd_t *msf); 170578Srgrimesstatic int mcd_volinfo(int unit); 171578Srgrimesstatic int mcd_waitrdy(int port,int dly); 172978Sjkhstatic void mcd_doread(int state, struct mcd_mbx *mbxin); 173578Srgrimes#ifndef MCDMINI 174578Srgrimesstatic int mcd_setmode(int unit, int mode); 175578Srgrimesstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q); 176578Srgrimesstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 177578Srgrimesstatic int mcd_toc_header(int unit, struct ioc_toc_header *th); 178578Srgrimesstatic int mcd_read_toc(int unit); 179578Srgrimesstatic int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); 180578Srgrimesstatic int mcd_stop(int unit); 181578Srgrimesstatic int mcd_playtracks(int unit, struct ioc_play_track *pt); 182578Srgrimesstatic int mcd_play(int unit, struct mcd_read2 *pb); 183578Srgrimesstatic int mcd_pause(int unit); 184578Srgrimesstatic int mcd_resume(int unit); 185578Srgrimes#endif 186578Srgrimes 187578Srgrimesextern int hz; 188578Srgrimesextern int mcd_probe(struct isa_device *dev); 189578Srgrimesextern int mcd_attach(struct isa_device *dev); 190578Srgrimesstruct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 191578Srgrimes 192578Srgrimes#define mcd_put(port,byte) outb(port,byte) 193578Srgrimes 194578Srgrimes#define MCD_RETRYS 5 195578Srgrimes#define MCD_RDRETRYS 8 196578Srgrimes 197578Srgrimes#define MCDBLK 2048 /* for cooked mode */ 198578Srgrimes#define MCDRBLK 2352 /* for raw mode */ 199578Srgrimes 200578Srgrimes/* several delays */ 201578Srgrimes#define RDELAY_WAITSTAT 300 202578Srgrimes#define RDELAY_WAITMODE 300 203578Srgrimes#define RDELAY_WAITREAD 800 204578Srgrimes 205578Srgrimes#define DELAY_STATUS 10000l /* 10000 * 1us */ 206578Srgrimes#define DELAY_GETREPLY 200000l /* 200000 * 2us */ 207578Srgrimes#define DELAY_SEEKREAD 20000l /* 20000 * 1us */ 208578Srgrimes#define mcd_delay DELAY 209578Srgrimes 210578Srgrimesint mcd_attach(struct isa_device *dev) 211578Srgrimes{ 212578Srgrimes struct mcd_data *cd = mcd_data + dev->id_unit; 213578Srgrimes int i; 214578Srgrimes 215578Srgrimes cd->iobase = dev->id_iobase; 216578Srgrimes cd->flags |= MCDINIT; 217578Srgrimes cd->openflags = 0; 218578Srgrimes for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 219578Srgrimes 220578Srgrimes#ifdef NOTYET 221578Srgrimes /* wire controller for interrupts and dma */ 222578Srgrimes mcd_configure(cd); 223578Srgrimes#endif 224578Srgrimes 225578Srgrimes return 1; 226578Srgrimes} 227578Srgrimes 228578Srgrimesint mcdopen(dev_t dev) 229578Srgrimes{ 230578Srgrimes int unit,part,phys; 231578Srgrimes struct mcd_data *cd; 232578Srgrimes 233578Srgrimes unit = mcd_unit(dev); 234578Srgrimes if (unit >= NMCD) 235578Srgrimes return ENXIO; 236578Srgrimes 237578Srgrimes cd = mcd_data + unit; 238578Srgrimes part = mcd_part(dev); 239578Srgrimes phys = mcd_phys(dev); 240578Srgrimes 241578Srgrimes /* not initialized*/ 242578Srgrimes if (!(cd->flags & MCDINIT)) 243578Srgrimes return ENXIO; 244578Srgrimes 245578Srgrimes /* invalidated in the meantime? mark all open part's invalid */ 246578Srgrimes if (!(cd->flags & MCDVALID) && cd->openflags) 247578Srgrimes return ENXIO; 248578Srgrimes 249578Srgrimes if (mcd_getstat(unit,1) < 0) 250578Srgrimes return ENXIO; 251578Srgrimes 252578Srgrimes /* XXX get a default disklabel */ 253578Srgrimes mcd_getdisklabel(unit); 254578Srgrimes 255578Srgrimes if (mcdsize(dev) < 0) { 256578Srgrimes printf("mcd%d: failed to get disk size\n",unit); 257578Srgrimes return ENXIO; 258578Srgrimes } else 259578Srgrimes cd->flags |= MCDVALID; 260578Srgrimes 261578SrgrimesMCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 262578Srgrimes part,cd->disksize,cd->blksize,0); 263578Srgrimes 264578Srgrimes if (part == RAW_PART || 265578Srgrimes (part < cd->dlabel.d_npartitions && 266578Srgrimes cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 267578Srgrimes cd->partflags[part] |= MCDOPEN; 268578Srgrimes cd->openflags |= (1<<part); 269578Srgrimes if (part == RAW_PART && phys != 0) 270578Srgrimes cd->partflags[part] |= MCDREADRAW; 271578Srgrimes return 0; 272578Srgrimes } 273578Srgrimes 274578Srgrimes return ENXIO; 275578Srgrimes} 276578Srgrimes 277578Srgrimesint mcdclose(dev_t dev) 278578Srgrimes{ 279578Srgrimes int unit,part,phys; 280578Srgrimes struct mcd_data *cd; 281578Srgrimes 282578Srgrimes unit = mcd_unit(dev); 283578Srgrimes if (unit >= NMCD) 284578Srgrimes return ENXIO; 285578Srgrimes 286578Srgrimes cd = mcd_data + unit; 287578Srgrimes part = mcd_part(dev); 288578Srgrimes phys = mcd_phys(dev); 289578Srgrimes 290578Srgrimes if (!(cd->flags & MCDINIT)) 291578Srgrimes return ENXIO; 292578Srgrimes 293578Srgrimes mcd_getstat(unit,1); /* get status */ 294578Srgrimes 295578Srgrimes /* close channel */ 296578Srgrimes cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 297578Srgrimes cd->openflags &= ~(1<<part); 298578Srgrimes MCD_TRACE("close: partition=%d\n",part,0,0,0); 299578Srgrimes 300578Srgrimes return 0; 301578Srgrimes} 302578Srgrimes 303798Swollmanvoid 304798Swollmanmcdstrategy(struct buf *bp) 305578Srgrimes{ 306578Srgrimes struct mcd_data *cd; 307578Srgrimes struct buf *qp; 308578Srgrimes int s; 309578Srgrimes 310578Srgrimes int unit = mcd_unit(bp->b_dev); 311578Srgrimes 312578Srgrimes cd = mcd_data + unit; 313578Srgrimes 314578Srgrimes /* test validity */ 315578Srgrimes/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 316578Srgrimes bp,unit,bp->b_blkno,bp->b_bcount);*/ 317578Srgrimes if (unit >= NMCD || bp->b_blkno < 0) { 318578Srgrimes printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 319578Srgrimes unit, bp->b_blkno, bp->b_bcount); 320578Srgrimes pg("mcd: mcdstratregy failure"); 321578Srgrimes bp->b_error = EINVAL; 322578Srgrimes bp->b_flags |= B_ERROR; 323578Srgrimes goto bad; 324578Srgrimes } 325578Srgrimes 326578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 327578Srgrimes if (!(cd->flags & MCDVALID)) { 328578SrgrimesMCD_TRACE("strategy: drive not valid\n",0,0,0,0); 329578Srgrimes bp->b_error = EIO; 330578Srgrimes goto bad; 331578Srgrimes } 332578Srgrimes 333578Srgrimes /* read only */ 334578Srgrimes if (!(bp->b_flags & B_READ)) { 335578Srgrimes bp->b_error = EROFS; 336578Srgrimes goto bad; 337578Srgrimes } 338578Srgrimes 339578Srgrimes /* no data to read */ 340578Srgrimes if (bp->b_bcount == 0) 341578Srgrimes goto done; 342578Srgrimes 343578Srgrimes /* for non raw access, check partition limits */ 344578Srgrimes if (mcd_part(bp->b_dev) != RAW_PART) { 345578Srgrimes if (!(cd->flags & MCDLABEL)) { 346578Srgrimes bp->b_error = EIO; 347578Srgrimes goto bad; 348578Srgrimes } 349578Srgrimes /* adjust transfer if necessary */ 350578Srgrimes if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 351578Srgrimes goto done; 352578Srgrimes } 3531379Sdg } else { 3541379Sdg bp->b_pblkno = bp->b_blkno; 3551437Sgclarkii bp->b_resid = 0; 356578Srgrimes } 357578Srgrimes 358578Srgrimes /* queue it */ 359578Srgrimes qp = &cd->head; 360578Srgrimes s = splbio(); 361578Srgrimes disksort(qp,bp); 362578Srgrimes splx(s); 363578Srgrimes 364578Srgrimes /* now check whether we can perform processing */ 365578Srgrimes mcd_start(unit); 366578Srgrimes return; 367578Srgrimes 368578Srgrimesbad: 369578Srgrimes bp->b_flags |= B_ERROR; 370578Srgrimesdone: 371578Srgrimes bp->b_resid = bp->b_bcount; 372578Srgrimes biodone(bp); 373578Srgrimes return; 374578Srgrimes} 375578Srgrimes 376578Srgrimesstatic void mcd_start(int unit) 377578Srgrimes{ 378578Srgrimes struct mcd_data *cd = mcd_data + unit; 379578Srgrimes struct buf *bp, *qp = &cd->head; 380578Srgrimes struct partition *p; 381578Srgrimes int part; 382578Srgrimes register s = splbio(); 383578Srgrimes 384578Srgrimes if (cd->flags & MCDMBXBSY) 385578Srgrimes return; 386578Srgrimes 387578Srgrimes if ((bp = qp->b_actf) != 0) { 388578Srgrimes /* block found to process, dequeue */ 389578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 390578Srgrimes qp->b_actf = bp->av_forw; 391578Srgrimes splx(s); 392578Srgrimes } else { 393578Srgrimes /* nothing to do */ 394578Srgrimes splx(s); 395578Srgrimes return; 396578Srgrimes } 397578Srgrimes 398578Srgrimes /* changed media? */ 399578Srgrimes if (!(cd->flags & MCDVALID)) { 400578Srgrimes MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 401578Srgrimes return; 402578Srgrimes } 403578Srgrimes 404578Srgrimes p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 405578Srgrimes 406578Srgrimes cd->flags |= MCDMBXBSY; 407578Srgrimes cd->mbx.unit = unit; 408578Srgrimes cd->mbx.port = cd->iobase; 409578Srgrimes cd->mbx.retry = MCD_RETRYS; 410578Srgrimes cd->mbx.bp = bp; 411578Srgrimes cd->mbx.p_offset = p->p_offset; 412578Srgrimes 413578Srgrimes /* calling the read routine */ 414978Sjkh mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 415578Srgrimes /* triggers mcd_start, when successful finished */ 416578Srgrimes return; 417578Srgrimes} 418578Srgrimes 419578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 420578Srgrimes{ 421578Srgrimes struct mcd_data *cd; 422578Srgrimes int unit,part; 423578Srgrimes 424578Srgrimes unit = mcd_unit(dev); 425578Srgrimes part = mcd_part(dev); 426578Srgrimes cd = mcd_data + unit; 427578Srgrimes 428578Srgrimes#ifdef MCDMINI 429578Srgrimes return ENOTTY; 430578Srgrimes#else 431578Srgrimes if (!(cd->flags & MCDVALID)) 432578Srgrimes return EIO; 433578SrgrimesMCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 434578Srgrimes 435578Srgrimes switch (cmd) { 436578Srgrimes case DIOCSBAD: 437578Srgrimes return EINVAL; 438578Srgrimes case DIOCGDINFO: 439578Srgrimes case DIOCGPART: 440578Srgrimes case DIOCWDINFO: 441578Srgrimes case DIOCSDINFO: 442578Srgrimes case DIOCWLABEL: 443578Srgrimes return ENOTTY; 444578Srgrimes case CDIOCPLAYTRACKS: 445578Srgrimes return mcd_playtracks(unit, (struct ioc_play_track *) addr); 446578Srgrimes case CDIOCPLAYBLOCKS: 447578Srgrimes return mcd_play(unit, (struct mcd_read2 *) addr); 448578Srgrimes case CDIOCREADSUBCHANNEL: 449578Srgrimes return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 450578Srgrimes case CDIOREADTOCHEADER: 451578Srgrimes return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 452578Srgrimes case CDIOREADTOCENTRYS: 453578Srgrimes return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); 454578Srgrimes case CDIOCSETPATCH: 455578Srgrimes case CDIOCGETVOL: 456578Srgrimes case CDIOCSETVOL: 457578Srgrimes case CDIOCSETMONO: 458578Srgrimes case CDIOCSETSTERIO: 459578Srgrimes case CDIOCSETMUTE: 460578Srgrimes case CDIOCSETLEFT: 461578Srgrimes case CDIOCSETRIGHT: 462578Srgrimes return EINVAL; 463578Srgrimes case CDIOCRESUME: 464578Srgrimes return mcd_resume(unit); 465578Srgrimes case CDIOCPAUSE: 466578Srgrimes return mcd_pause(unit); 467578Srgrimes case CDIOCSTART: 468578Srgrimes return EINVAL; 469578Srgrimes case CDIOCSTOP: 470578Srgrimes return mcd_stop(unit); 471578Srgrimes case CDIOCEJECT: 472578Srgrimes return EINVAL; 473578Srgrimes case CDIOCSETDEBUG: 474578Srgrimes cd->debug = 1; 475578Srgrimes return 0; 476578Srgrimes case CDIOCCLRDEBUG: 477578Srgrimes cd->debug = 0; 478578Srgrimes return 0; 479578Srgrimes case CDIOCRESET: 480578Srgrimes return EINVAL; 481578Srgrimes default: 482578Srgrimes return ENOTTY; 483578Srgrimes } 484578Srgrimes /*NOTREACHED*/ 485578Srgrimes#endif /*!MCDMINI*/ 486578Srgrimes} 487578Srgrimes 488578Srgrimes/* this could have been taken from scsi/cd.c, but it is not clear 489578Srgrimes * whether the scsi cd driver is linked in 490578Srgrimes */ 491578Srgrimesstatic int mcd_getdisklabel(int unit) 492578Srgrimes{ 493578Srgrimes struct mcd_data *cd = mcd_data + unit; 494578Srgrimes 495578Srgrimes if (cd->flags & MCDLABEL) 496578Srgrimes return -1; 497578Srgrimes 498578Srgrimes bzero(&cd->dlabel,sizeof(struct disklabel)); 499578Srgrimes strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); 500578Srgrimes strncpy(cd->dlabel.d_packname,"unknown ",16); 501578Srgrimes cd->dlabel.d_secsize = cd->blksize; 502578Srgrimes cd->dlabel.d_nsectors = 100; 503578Srgrimes cd->dlabel.d_ntracks = 1; 504578Srgrimes cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 505578Srgrimes cd->dlabel.d_secpercyl = 100; 506578Srgrimes cd->dlabel.d_secperunit = cd->disksize; 507578Srgrimes cd->dlabel.d_rpm = 300; 508578Srgrimes cd->dlabel.d_interleave = 1; 509578Srgrimes cd->dlabel.d_flags = D_REMOVABLE; 510578Srgrimes cd->dlabel.d_npartitions= 1; 511578Srgrimes cd->dlabel.d_partitions[0].p_offset = 0; 512578Srgrimes cd->dlabel.d_partitions[0].p_size = cd->disksize; 513578Srgrimes cd->dlabel.d_partitions[0].p_fstype = 9; 514578Srgrimes cd->dlabel.d_magic = DISKMAGIC; 515578Srgrimes cd->dlabel.d_magic2 = DISKMAGIC; 516578Srgrimes cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 517578Srgrimes 518578Srgrimes cd->flags |= MCDLABEL; 519578Srgrimes return 0; 520578Srgrimes} 521578Srgrimes 522578Srgrimesint mcdsize(dev_t dev) 523578Srgrimes{ 524578Srgrimes int size; 525578Srgrimes int unit = mcd_unit(dev); 526578Srgrimes struct mcd_data *cd = mcd_data + unit; 527578Srgrimes 528578Srgrimes if (mcd_volinfo(unit) >= 0) { 529578Srgrimes cd->blksize = MCDBLK; 530578Srgrimes size = msf2hsg(cd->volinfo.vol_msf); 531578Srgrimes cd->disksize = size * (MCDBLK/DEV_BSIZE); 532578Srgrimes return 0; 533578Srgrimes } 534578Srgrimes return -1; 535578Srgrimes} 536578Srgrimes 537578Srgrimes/*************************************************************** 538578Srgrimes * lower level of driver starts here 539578Srgrimes **************************************************************/ 540578Srgrimes 541578Srgrimes#ifdef NOTDEF 5421197Srgrimesstatic char 5431197Srgrimesirqs[] = { 544578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 545578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 546578Srgrimes}; 547578Srgrimes 5481197Srgrimesstatic char 5491197Srgrimesdrqs[] = { 550578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 551578Srgrimes}; 552578Srgrimes#endif 553578Srgrimes 5541197Srgrimesstatic void 5551197Srgrimesmcd_configure(struct mcd_data *cd) 556578Srgrimes{ 557578Srgrimes outb(cd->iobase+mcd_config,cd->config); 558578Srgrimes} 559578Srgrimes 5601197Srgrimes/* Wait for non-busy - return 0 on timeout */ 5611197Srgrimesstatic int 5621197Srgrimestwiddle_thumbs(int port, int unit, int count, char *whine) 5631197Srgrimes{ 5641197Srgrimes int i; 5651197Srgrimes 5661197Srgrimes for (i = 0; i < count; i++) { 5671197Srgrimes if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) { 5681197Srgrimes return 1; 5691197Srgrimes } 5701197Srgrimes } 5711197Srgrimes#ifdef MCD_TO_WARNING_ON 5721197Srgrimes printf("mcd%d: timeout %s\n", unit, whine); 5731197Srgrimes#endif 5741197Srgrimes return 0; 5751197Srgrimes} 5761197Srgrimes 577978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 578578Srgrimes 5791197Srgrimesint 5801197Srgrimesmcd_probe(struct isa_device *dev) 581578Srgrimes{ 582578Srgrimes int port = dev->id_iobase; 583578Srgrimes int unit = dev->id_unit; 5841197Srgrimes int i, j; 5851197Srgrimes int status; 5861197Srgrimes unsigned char stbytes[3]; 587578Srgrimes 588578Srgrimes mcd_data[unit].flags = MCDPROBING; 589578Srgrimes 590578Srgrimes#ifdef NOTDEF 591578Srgrimes /* get irq/drq configuration word */ 592578Srgrimes mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 593578Srgrimes#else 594578Srgrimes mcd_data[unit].config = 0; 595578Srgrimes#endif 596578Srgrimes 597578Srgrimes /* send a reset */ 5981197Srgrimes outb(port+MCD_FLAGS, M_RESET); 599578Srgrimes 6001197Srgrimes /* 6011197Srgrimes * delay awhile by getting any pending garbage (old data) and 6021197Srgrimes * throwing it away. 6031197Srgrimes */ 6041197Srgrimes for (i = 1000000; i != 0; i--) { 6051197Srgrimes inb(port+MCD_FLAGS); 6061197Srgrimes } 607578Srgrimes 6081197Srgrimes /* Get status */ 6091197Srgrimes outb(port+MCD_DATA, MCD_CMDGETSTAT); 6101197Srgrimes if (!twiddle_thumbs(port, unit, 1000000, "getting status")) { 6111197Srgrimes return 0; /* Timeout */ 6121197Srgrimes } 6131197Srgrimes status = inb(port+MCD_DATA); 6141241Sjkh if (status != MCDCDABSENT && status != MCDCDPRESENT && 6151241Sjkh status != MCDSOPEN && status != MCDSCLOSED) 6161237Sjkh return 0; /* Not actually a Mitsumi drive here */ 6171197Srgrimes /* Get version information */ 6181197Srgrimes outb(port+MCD_DATA, MCD_CMDCONTINFO); 6191197Srgrimes for (j = 0; j < 3; j++) { 6201197Srgrimes if (!twiddle_thumbs(port, unit, 3000, "getting version info")) { 6211197Srgrimes return 0; 6221197Srgrimes } 6231197Srgrimes stbytes[j] = (inb(port+MCD_DATA) & 0xFF); 6241197Srgrimes } 6251197Srgrimes printf("mcd%d: version information is %x %c %x\n", unit, 6261197Srgrimes stbytes[0], stbytes[1], stbytes[2]); 6271197Srgrimes if (stbytes[1] >= 4) { 6281197Srgrimes outb(port+MCD_CTRL, M_PICKLE); 6291197Srgrimes printf("mcd%d: Adjusted for newer drive model\n", unit); 6301197Srgrimes } 6311197Srgrimes return 4; 632578Srgrimes} 633578Srgrimes 634978Sjkh 6351197Srgrimesstatic int 6361197Srgrimesmcd_waitrdy(int port,int dly) 637578Srgrimes{ 638578Srgrimes int i; 639578Srgrimes 640578Srgrimes /* wait until xfer port senses data ready */ 641578Srgrimes for (i=0; i<dly; i++) { 642578Srgrimes if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0) 643578Srgrimes return 0; 644578Srgrimes mcd_delay(1); 645578Srgrimes } 646578Srgrimes return -1; 647578Srgrimes} 648578Srgrimes 6491197Srgrimesstatic int 6501197Srgrimesmcd_getreply(int unit,int dly) 651578Srgrimes{ 652578Srgrimes int i; 653578Srgrimes struct mcd_data *cd = mcd_data + unit; 654578Srgrimes int port = cd->iobase; 655578Srgrimes 656578Srgrimes /* wait data to become ready */ 657578Srgrimes if (mcd_waitrdy(port,dly)<0) { 658578Srgrimes#ifdef MCD_TO_WARNING_ON 659578Srgrimes printf("mcd%d: timeout getreply\n",unit); 660578Srgrimes#endif 661578Srgrimes return -1; 662578Srgrimes } 663578Srgrimes 664578Srgrimes /* get the data */ 665578Srgrimes return inb(port+mcd_status) & 0xFF; 666578Srgrimes} 667578Srgrimes 6681197Srgrimesstatic int 6691197Srgrimesmcd_getstat(int unit,int sflg) 670578Srgrimes{ 671578Srgrimes int i; 672578Srgrimes struct mcd_data *cd = mcd_data + unit; 673578Srgrimes int port = cd->iobase; 674578Srgrimes 675578Srgrimes /* get the status */ 676578Srgrimes if (sflg) 677578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 678578Srgrimes i = mcd_getreply(unit,DELAY_GETREPLY); 679578Srgrimes if (i<0) return -1; 680578Srgrimes 681578Srgrimes cd->status = i; 682578Srgrimes 683578Srgrimes mcd_setflags(unit,cd); 684578Srgrimes return cd->status; 685578Srgrimes} 686578Srgrimes 6871197Srgrimesstatic void 6881197Srgrimesmcd_setflags(int unit, struct mcd_data *cd) 689578Srgrimes{ 690578Srgrimes /* check flags */ 691578Srgrimes if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { 692578Srgrimes MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); 693578Srgrimes cd->flags &= ~MCDVALID; 694578Srgrimes } 695578Srgrimes 696578Srgrimes#ifndef MCDMINI 697578Srgrimes if (cd->status & MCDAUDIOBSY) 698578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 699578Srgrimes else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 700578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 701578Srgrimes#endif 702578Srgrimes} 703578Srgrimes 7041197Srgrimesstatic int 7051197Srgrimesmcd_get(int unit, char *buf, int nmax) 706578Srgrimes{ 707578Srgrimes int port = mcd_data[unit].iobase; 708578Srgrimes int i,k; 709578Srgrimes 710578Srgrimes for (i=0; i<nmax; i++) { 711578Srgrimes /* wait for data */ 712578Srgrimes if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 713578Srgrimes#ifdef MCD_TO_WARNING_ON 714578Srgrimes printf("mcd%d: timeout mcd_get\n",unit); 715578Srgrimes#endif 716578Srgrimes return -1; 717578Srgrimes } 718578Srgrimes buf[i] = k; 719578Srgrimes } 720578Srgrimes return i; 721578Srgrimes} 722578Srgrimes 7231197Srgrimesstatic int 7241197Srgrimesmcd_send(int unit, int cmd,int nretrys) 725578Srgrimes{ 726578Srgrimes int i,k; 727578Srgrimes int port = mcd_data[unit].iobase; 728578Srgrimes 729578Srgrimes/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/ 730578Srgrimes for (i=0; i<nretrys; i++) { 731578Srgrimes outb(port+mcd_command, cmd); 7321197Srgrimes if ((k=mcd_getstat(unit,0)) != -1) { 733578Srgrimes break; 7341197Srgrimes } 735578Srgrimes } 736578Srgrimes if (i == nretrys) { 737578Srgrimes printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 738578Srgrimes return -1; 739578Srgrimes } 740578Srgrimes/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/ 741578Srgrimes return 0; 742578Srgrimes} 743578Srgrimes 7441197Srgrimesstatic int 7451197Srgrimesbcd2bin(bcd_t b) 746578Srgrimes{ 747578Srgrimes return (b >> 4) * 10 + (b & 15); 748578Srgrimes} 749578Srgrimes 7501197Srgrimesstatic bcd_t 7511197Srgrimesbin2bcd(int b) 752578Srgrimes{ 753578Srgrimes return ((b / 10) << 4) | (b % 10); 754578Srgrimes} 755578Srgrimes 7561197Srgrimesstatic void 7571197Srgrimeshsg2msf(int hsg, bcd_t *msf) 758578Srgrimes{ 759578Srgrimes hsg += 150; 760578Srgrimes M_msf(msf) = bin2bcd(hsg / 4500); 761578Srgrimes hsg %= 4500; 762578Srgrimes S_msf(msf) = bin2bcd(hsg / 75); 763578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 764578Srgrimes} 765578Srgrimes 7661197Srgrimesstatic int 7671197Srgrimesmsf2hsg(bcd_t *msf) 768578Srgrimes{ 769578Srgrimes return (bcd2bin(M_msf(msf)) * 60 + 770578Srgrimes bcd2bin(S_msf(msf))) * 75 + 771578Srgrimes bcd2bin(F_msf(msf)) - 150; 772578Srgrimes} 773578Srgrimes 7741197Srgrimesstatic int 7751197Srgrimesmcd_volinfo(int unit) 776578Srgrimes{ 777578Srgrimes struct mcd_data *cd = mcd_data + unit; 778578Srgrimes int i; 779578Srgrimes 780578Srgrimes/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 781578Srgrimes 782578Srgrimes /* Get the status, in case the disc has been changed */ 783578Srgrimes if (mcd_getstat(unit, 1) < 0) return EIO; 784578Srgrimes 785578Srgrimes /* Just return if we already have it */ 786578Srgrimes if (cd->flags & MCDVOLINFO) return 0; 787578Srgrimes 788578Srgrimes /* send volume info command */ 789578Srgrimes if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 790578Srgrimes return -1; 791578Srgrimes 792578Srgrimes /* get data */ 793578Srgrimes if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 794578Srgrimes printf("mcd%d: mcd_volinfo: error read data\n",unit); 795578Srgrimes return -1; 796578Srgrimes } 797578Srgrimes 798578Srgrimes if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { 799578Srgrimes cd->flags |= MCDVOLINFO; /* volinfo is OK */ 800578Srgrimes return 0; 801578Srgrimes } 802578Srgrimes 803578Srgrimes return -1; 804578Srgrimes} 805578Srgrimes 806798Swollmanvoid 807798Swollmanmcdintr(unit) 808798Swollman int unit; 809578Srgrimes{ 810578Srgrimes int port = mcd_data[unit].iobase; 811578Srgrimes u_int i; 812578Srgrimes 813578Srgrimes MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); 814578Srgrimes 815578Srgrimes /* just read out status and ignore the rest */ 816578Srgrimes if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { 817578Srgrimes i = inb(port+mcd_status); 818578Srgrimes } 819578Srgrimes} 820578Srgrimes 821578Srgrimes/* state machine to process read requests 822578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 823578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 824578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 825578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 826578Srgrimes */ 827578Srgrimesstatic struct mcd_mbx *mbxsave; 828578Srgrimes 8291197Srgrimesstatic void 8301197Srgrimesmcd_doread(int state, struct mcd_mbx *mbxin) 831578Srgrimes{ 832578Srgrimes struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 833578Srgrimes int unit = mbx->unit; 834578Srgrimes int port = mbx->port; 835578Srgrimes struct buf *bp = mbx->bp; 836578Srgrimes struct mcd_data *cd = mcd_data + unit; 837578Srgrimes 838578Srgrimes int rm,i,k; 839578Srgrimes struct mcd_read2 rbuf; 840578Srgrimes int blknum; 841578Srgrimes caddr_t addr; 842578Srgrimes 843578Srgrimesloop: 844578Srgrimes switch (state) { 845578Srgrimes case MCD_S_BEGIN: 846578Srgrimes mbx = mbxsave = mbxin; 847578Srgrimes 848578Srgrimes case MCD_S_BEGIN1: 849578Srgrimes /* get status */ 850578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 851578Srgrimes mbx->count = RDELAY_WAITSTAT; 8521197Srgrimes timeout((timeout_func_t)mcd_doread, 8531197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 854578Srgrimes return; 855578Srgrimes case MCD_S_WAITSTAT: 8561000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT); 857578Srgrimes if (mbx->count-- >= 0) { 858578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 8591197Srgrimes timeout((timeout_func_t)mcd_doread, 8601197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 861578Srgrimes return; 862578Srgrimes } 863578Srgrimes mcd_setflags(unit,cd); 8641197Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n", 8651197Srgrimes RDELAY_WAITSTAT-mbx->count,0,0,0); 866578Srgrimes /* reject, if audio active */ 867578Srgrimes if (cd->status & MCDAUDIOBSY) { 868578Srgrimes printf("mcd%d: audio is active\n",unit); 869578Srgrimes goto readerr; 870578Srgrimes } 871578Srgrimes 872578Srgrimes /* to check for raw/cooked mode */ 873578Srgrimes if (cd->flags & MCDREADRAW) { 874578Srgrimes rm = MCD_MD_RAW; 875578Srgrimes mbx->sz = MCDRBLK; 876578Srgrimes } else { 877578Srgrimes rm = MCD_MD_COOKED; 878578Srgrimes mbx->sz = cd->blksize; 879578Srgrimes } 880578Srgrimes 881578Srgrimes mbx->count = RDELAY_WAITMODE; 882578Srgrimes 883578Srgrimes mcd_put(port+mcd_command, MCD_CMDSETMODE); 884578Srgrimes mcd_put(port+mcd_command, rm); 8851197Srgrimes timeout((timeout_func_t)mcd_doread, 8861197Srgrimes (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */ 887578Srgrimes return; 888578Srgrimes } else { 889578Srgrimes#ifdef MCD_TO_WARNING_ON 890578Srgrimes printf("mcd%d: timeout getstatus\n",unit); 891578Srgrimes#endif 892578Srgrimes goto readerr; 893578Srgrimes } 894578Srgrimes 895578Srgrimes case MCD_S_WAITMODE: 8961000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE); 897578Srgrimes if (mbx->count-- < 0) { 898578Srgrimes#ifdef MCD_TO_WARNING_ON 899578Srgrimes printf("mcd%d: timeout set mode\n",unit); 900578Srgrimes#endif 901578Srgrimes goto readerr; 902578Srgrimes } 903578Srgrimes if (inb(port+mcd_xfer) & MCD_ST_BUSY) { 904798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); 905578Srgrimes return; 906578Srgrimes } 907578Srgrimes mcd_setflags(unit,cd); 9081197Srgrimes MCD_TRACE("got WAITMODE delay=%d\n", 9091197Srgrimes RDELAY_WAITMODE-mbx->count,0,0,0); 910578Srgrimes /* for first block */ 911578Srgrimes mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 912578Srgrimes mbx->skip = 0; 913578Srgrimes 914578Srgrimesnextblock: 915578Srgrimes blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 916578Srgrimes + mbx->p_offset + mbx->skip/mbx->sz; 917578Srgrimes 9181197Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n", 9191197Srgrimes blknum,bp,0,0); 920578Srgrimes 921578Srgrimes /* build parameter block */ 922578Srgrimes hsg2msf(blknum,rbuf.start_msf); 923578Srgrimes 924578Srgrimes /* send the read command */ 925578Srgrimes mcd_put(port+mcd_command,MCD_CMDREAD2); 926578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[0]); 927578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[1]); 928578Srgrimes mcd_put(port+mcd_command,rbuf.start_msf[2]); 929578Srgrimes mcd_put(port+mcd_command,0); 930578Srgrimes mcd_put(port+mcd_command,0); 931578Srgrimes mcd_put(port+mcd_command,1); 932578Srgrimes mbx->count = RDELAY_WAITREAD; 9331197Srgrimes timeout((timeout_func_t)mcd_doread, 9341197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 935578Srgrimes return; 936578Srgrimes case MCD_S_WAITREAD: 9371000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD); 938578Srgrimes if (mbx->count-- > 0) { 939578Srgrimes k = inb(port+mcd_xfer); 940578Srgrimes if ((k & 2)==0) { 9411197Srgrimes MCD_TRACE("got data delay=%d\n", 9421197Srgrimes RDELAY_WAITREAD-mbx->count,0,0,0); 943578Srgrimes /* data is ready */ 944578Srgrimes addr = bp->b_un.b_addr + mbx->skip; 945578Srgrimes outb(port+mcd_ctl2,0x04); /* XXX */ 946578Srgrimes for (i=0; i<mbx->sz; i++) 947578Srgrimes *addr++ = inb(port+mcd_rdata); 948578Srgrimes outb(port+mcd_ctl2,0x0c); /* XXX */ 949578Srgrimes 950578Srgrimes if (--mbx->nblk > 0) { 951578Srgrimes mbx->skip += mbx->sz; 952578Srgrimes goto nextblock; 953578Srgrimes } 954578Srgrimes 955578Srgrimes /* return buffer */ 956578Srgrimes bp->b_resid = 0; 957578Srgrimes biodone(bp); 958578Srgrimes 959578Srgrimes cd->flags &= ~MCDMBXBSY; 960578Srgrimes mcd_start(mbx->unit); 961578Srgrimes return; 962578Srgrimes } 963578Srgrimes if ((k & 4)==0) 964578Srgrimes mcd_getstat(unit,0); 9651197Srgrimes timeout((timeout_func_t)mcd_doread, 9661197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 967578Srgrimes return; 968578Srgrimes } else { 969578Srgrimes#ifdef MCD_TO_WARNING_ON 970578Srgrimes printf("mcd%d: timeout read data\n",unit); 971578Srgrimes#endif 972578Srgrimes goto readerr; 973578Srgrimes } 974578Srgrimes } 975578Srgrimes 976578Srgrimesreaderr: 977578Srgrimes if (mbx->retry-- > 0) { 978578Srgrimes#ifdef MCD_TO_WARNING_ON 979578Srgrimes printf("mcd%d: retrying\n",unit); 980578Srgrimes#endif 981578Srgrimes state = MCD_S_BEGIN1; 982578Srgrimes goto loop; 983578Srgrimes } 984578Srgrimes 985578Srgrimes /* invalidate the buffer */ 986578Srgrimes bp->b_flags |= B_ERROR; 987578Srgrimes bp->b_resid = bp->b_bcount; 988578Srgrimes biodone(bp); 989578Srgrimes mcd_start(mbx->unit); 990578Srgrimes return; 991578Srgrimes 992578Srgrimes#ifdef NOTDEF 993578Srgrimes printf("mcd%d: unit timeout, resetting\n",mbx->unit); 994578Srgrimes outb(mbx->port+mcd_reset,MCD_CMDRESET); 995578Srgrimes DELAY(300000); 996578Srgrimes (void)mcd_getstat(mbx->unit,1); 997578Srgrimes (void)mcd_getstat(mbx->unit,1); 998578Srgrimes /*cd->status &= ~MCDDSKCHNG; */ 999578Srgrimes cd->debug = 1; /* preventive set debug mode */ 1000578Srgrimes 1001578Srgrimes#endif 1002578Srgrimes 1003578Srgrimes} 1004578Srgrimes 1005578Srgrimes#ifndef MCDMINI 10061197Srgrimesstatic int 10071197Srgrimesmcd_setmode(int unit, int mode) 1008578Srgrimes{ 1009578Srgrimes struct mcd_data *cd = mcd_data + unit; 1010578Srgrimes int port = cd->iobase; 1011578Srgrimes int retry; 1012578Srgrimes 1013578Srgrimes printf("mcd%d: setting mode to %d\n", unit, mode); 1014578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1015578Srgrimes { 1016578Srgrimes outb(port+mcd_command, MCD_CMDSETMODE); 1017578Srgrimes outb(port+mcd_command, mode); 1018578Srgrimes if (mcd_getstat(unit, 0) != -1) return 0; 1019578Srgrimes } 1020578Srgrimes 1021578Srgrimes return -1; 1022578Srgrimes} 1023578Srgrimes 10241197Srgrimesstatic int 10251197Srgrimesmcd_toc_header(int unit, struct ioc_toc_header *th) 1026578Srgrimes{ 1027578Srgrimes struct mcd_data *cd = mcd_data + unit; 1028578Srgrimes 10291197Srgrimes if (mcd_volinfo(unit) < 0) { 1030578Srgrimes return ENXIO; 10311197Srgrimes } 1032578Srgrimes 1033578Srgrimes th->len = msf2hsg(cd->volinfo.vol_msf); 1034578Srgrimes th->starting_track = bcd2bin(cd->volinfo.trk_low); 1035578Srgrimes th->ending_track = bcd2bin(cd->volinfo.trk_high); 1036578Srgrimes 1037578Srgrimes return 0; 1038578Srgrimes} 1039578Srgrimes 10401197Srgrimesstatic int 10411197Srgrimesmcd_read_toc(int unit) 1042578Srgrimes{ 1043578Srgrimes struct mcd_data *cd = mcd_data + unit; 1044578Srgrimes struct ioc_toc_header th; 1045578Srgrimes struct mcd_qchninfo q; 1046578Srgrimes int rc, trk, idx, retry; 1047578Srgrimes 1048578Srgrimes /* Only read TOC if needed */ 10491197Srgrimes if (cd->flags & MCDTOC) { 10501197Srgrimes return 0; 10511197Srgrimes } 1052578Srgrimes 1053578Srgrimes printf("mcd%d: reading toc header\n", unit); 10541197Srgrimes if (mcd_toc_header(unit, &th) != 0) { 1055578Srgrimes return ENXIO; 10561197Srgrimes } 1057578Srgrimes 1058578Srgrimes printf("mcd%d: stopping play\n", unit); 10591197Srgrimes if ((rc=mcd_stop(unit)) != 0) { 1060578Srgrimes return rc; 10611197Srgrimes } 1062578Srgrimes 1063578Srgrimes /* try setting the mode twice */ 10641197Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1065578Srgrimes return EIO; 10661197Srgrimes } 10671197Srgrimes if (mcd_setmode(unit, MCD_MD_TOC) != 0) { 1068578Srgrimes return EIO; 10691197Srgrimes } 1070578Srgrimes 1071578Srgrimes printf("mcd%d: get_toc reading qchannel info\n",unit); 1072578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1073578Srgrimes cd->toc[trk].idx_no = 0; 1074578Srgrimes trk = th.ending_track - th.starting_track + 1; 1075578Srgrimes for(retry=0; retry<300 && trk>0; retry++) 1076578Srgrimes { 1077578Srgrimes if (mcd_getqchan(unit, &q) < 0) break; 1078578Srgrimes idx = bcd2bin(q.idx_no); 10791197Srgrimes if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) { 10801197Srgrimes if (cd->toc[idx].idx_no == 0) { 1081578Srgrimes cd->toc[idx] = q; 1082578Srgrimes trk--; 1083578Srgrimes } 10841197Srgrimes } 1085578Srgrimes } 1086578Srgrimes 10871197Srgrimes if (mcd_setmode(unit, MCD_MD_COOKED) != 0) { 1088578Srgrimes return EIO; 10891197Srgrimes } 1090578Srgrimes 10911197Srgrimes if (trk != 0) { 10921197Srgrimes return ENXIO; 10931197Srgrimes } 1094578Srgrimes 1095578Srgrimes /* add a fake last+1 */ 1096578Srgrimes idx = th.ending_track + 1; 1097578Srgrimes cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1098578Srgrimes cd->toc[idx].trk_no = 0; 1099578Srgrimes cd->toc[idx].idx_no = 0xAA; 1100578Srgrimes cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1101578Srgrimes cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1102578Srgrimes cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1103578Srgrimes 1104578Srgrimes cd->flags |= MCDTOC; 1105578Srgrimes 1106578Srgrimes return 0; 1107578Srgrimes} 1108578Srgrimes 11091197Srgrimesstatic int 11101197Srgrimesmcd_toc_entry(int unit, struct ioc_read_toc_entry *te) 1111578Srgrimes{ 1112578Srgrimes struct mcd_data *cd = mcd_data + unit; 11131197Srgrimes struct ret_toc { 1114578Srgrimes struct ioc_toc_header th; 1115578Srgrimes struct cd_toc_entry rt; 1116578Srgrimes } ret_toc; 1117578Srgrimes struct ioc_toc_header th; 1118578Srgrimes int rc, i; 1119578Srgrimes 1120578Srgrimes /* Make sure we have a valid toc */ 11211197Srgrimes if ((rc=mcd_read_toc(unit)) != 0) { 1122578Srgrimes return rc; 11231197Srgrimes } 1124578Srgrimes 1125578Srgrimes /* find the toc to copy*/ 1126578Srgrimes i = te->starting_track; 11271197Srgrimes if (i == MCD_LASTPLUS1) { 1128578Srgrimes i = bcd2bin(cd->volinfo.trk_high) + 1; 11291197Srgrimes } 1130578Srgrimes 1131578Srgrimes /* verify starting track */ 1132578Srgrimes if (i < bcd2bin(cd->volinfo.trk_low) || 11331197Srgrimes i > bcd2bin(cd->volinfo.trk_high)+1) { 1134578Srgrimes return EINVAL; 11351197Srgrimes } 1136578Srgrimes 1137578Srgrimes /* do we have room */ 1138578Srgrimes if (te->data_len < sizeof(struct ioc_toc_header) + 11391197Srgrimes sizeof(struct cd_toc_entry)) { 11401197Srgrimes return EINVAL; 11411197Srgrimes } 1142578Srgrimes 1143578Srgrimes /* Copy the toc header */ 11441197Srgrimes if (mcd_toc_header(unit, &th) < 0) { 11451197Srgrimes return EIO; 11461197Srgrimes } 1147578Srgrimes ret_toc.th = th; 1148578Srgrimes 1149578Srgrimes /* copy the toc data */ 1150578Srgrimes ret_toc.rt.control = cd->toc[i].ctrl_adr; 1151578Srgrimes ret_toc.rt.addr_type = te->address_format; 1152578Srgrimes ret_toc.rt.track = i; 11531197Srgrimes if (te->address_format == CD_MSF_FORMAT) { 11541097Srgrimes ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0]; 11551097Srgrimes ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1]; 11561097Srgrimes ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2]; 1157578Srgrimes } 1158578Srgrimes 1159578Srgrimes /* copy the data back */ 1160578Srgrimes copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) 1161578Srgrimes + sizeof(struct ioc_toc_header)); 1162578Srgrimes 1163578Srgrimes return 0; 1164578Srgrimes} 1165578Srgrimes 11661197Srgrimesstatic int 11671197Srgrimesmcd_stop(int unit) 1168578Srgrimes{ 1169578Srgrimes struct mcd_data *cd = mcd_data + unit; 1170578Srgrimes 11711197Srgrimes if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) { 1172578Srgrimes return ENXIO; 11731197Srgrimes } 1174578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 1175578Srgrimes return 0; 1176578Srgrimes} 1177578Srgrimes 11781197Srgrimesstatic int 11791197Srgrimesmcd_getqchan(int unit, struct mcd_qchninfo *q) 1180578Srgrimes{ 1181578Srgrimes struct mcd_data *cd = mcd_data + unit; 1182578Srgrimes 11831197Srgrimes if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) { 1184578Srgrimes return -1; 11851197Srgrimes } 11861197Srgrimes if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) { 1187578Srgrimes return -1; 11881197Srgrimes } 11891197Srgrimes if (cd->debug) { 11901197Srgrimes printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", 1191578Srgrimes unit, 1192578Srgrimes q->ctrl_adr, q->trk_no, q->idx_no, 1193578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], 1194578Srgrimes q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); 11951197Srgrimes } 1196578Srgrimes return 0; 1197578Srgrimes} 1198578Srgrimes 11991197Srgrimesstatic int 12001197Srgrimesmcd_subchan(int unit, struct ioc_read_subchannel *sc) 1201578Srgrimes{ 1202578Srgrimes struct mcd_data *cd = mcd_data + unit; 1203578Srgrimes struct mcd_qchninfo q; 1204578Srgrimes struct cd_sub_channel_info data; 1205578Srgrimes 1206578Srgrimes printf("mcd%d: subchan af=%d, df=%d\n", unit, 1207578Srgrimes sc->address_format, 1208578Srgrimes sc->data_format); 12091197Srgrimes if (sc->address_format != CD_MSF_FORMAT) { 12101197Srgrimes return EIO; 12111197Srgrimes } 12121197Srgrimes if (sc->data_format != CD_CURRENT_POSITION) { 12131197Srgrimes return EIO; 12141197Srgrimes } 12151197Srgrimes if (mcd_getqchan(unit, &q) < 0) { 12161197Srgrimes return EIO; 12171197Srgrimes } 1218578Srgrimes 1219578Srgrimes data.header.audio_status = cd->audio_status; 1220578Srgrimes data.what.position.data_format = CD_MSF_FORMAT; 1221578Srgrimes data.what.position.track_number = bcd2bin(q.trk_no); 1222578Srgrimes 12231197Srgrimes if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) { 1224578Srgrimes return EFAULT; 12251197Srgrimes } 1226578Srgrimes return 0; 1227578Srgrimes} 1228578Srgrimes 12291197Srgrimesstatic int 12301197Srgrimesmcd_playtracks(int unit, struct ioc_play_track *pt) 1231578Srgrimes{ 1232578Srgrimes struct mcd_data *cd = mcd_data + unit; 1233578Srgrimes struct mcd_read2 pb; 1234578Srgrimes int a = pt->start_track; 1235578Srgrimes int z = pt->end_track; 1236578Srgrimes int rc; 1237578Srgrimes 12381197Srgrimes if ((rc = mcd_read_toc(unit)) != 0) { 12391197Srgrimes return rc; 12401197Srgrimes } 1241578Srgrimes printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 1242578Srgrimes a, pt->start_index, z, pt->end_index); 1243578Srgrimes 1244578Srgrimes if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || 12451197Srgrimes z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) { 1246578Srgrimes return EINVAL; 12471197Srgrimes } 1248578Srgrimes 1249578Srgrimes pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; 1250578Srgrimes pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; 1251578Srgrimes pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; 1252578Srgrimes pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; 1253578Srgrimes pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; 1254578Srgrimes pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; 1255578Srgrimes 1256578Srgrimes return mcd_play(unit, &pb); 1257578Srgrimes} 1258578Srgrimes 12591197Srgrimesstatic int 12601197Srgrimesmcd_play(int unit, struct mcd_read2 *pb) 1261578Srgrimes{ 1262578Srgrimes struct mcd_data *cd = mcd_data + unit; 1263578Srgrimes int port = cd->iobase; 1264578Srgrimes int retry, st; 1265578Srgrimes 1266578Srgrimes cd->lastpb = *pb; 12671197Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) { 1268578Srgrimes outb(port+mcd_command, MCD_CMDREAD2); 1269578Srgrimes outb(port+mcd_command, pb->start_msf[0]); 1270578Srgrimes outb(port+mcd_command, pb->start_msf[1]); 1271578Srgrimes outb(port+mcd_command, pb->start_msf[2]); 1272578Srgrimes outb(port+mcd_command, pb->end_msf[0]); 1273578Srgrimes outb(port+mcd_command, pb->end_msf[1]); 1274578Srgrimes outb(port+mcd_command, pb->end_msf[2]); 12751197Srgrimes if ((st=mcd_getstat(unit, 0)) != -1) { 12761197Srgrimes break; 12771197Srgrimes } 1278578Srgrimes } 1279578Srgrimes 12801197Srgrimes if (cd->debug) { 12811197Srgrimes printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); 12821197Srgrimes } 12831197Srgrimes if (st == -1) { 12841197Srgrimes return ENXIO; 12851197Srgrimes } 1286578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1287578Srgrimes return 0; 1288578Srgrimes} 1289578Srgrimes 12901197Srgrimesstatic int 12911197Srgrimesmcd_pause(int unit) 1292578Srgrimes{ 1293578Srgrimes struct mcd_data *cd = mcd_data + unit; 1294578Srgrimes struct mcd_qchninfo q; 1295578Srgrimes int rc; 1296578Srgrimes 1297578Srgrimes /* Verify current status */ 12981197Srgrimes if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { 1299578Srgrimes printf("mcd%d: pause attempted when not playing\n", unit); 1300578Srgrimes return EINVAL; 1301578Srgrimes } 1302578Srgrimes 1303578Srgrimes /* Get the current position */ 13041197Srgrimes if (mcd_getqchan(unit, &q) < 0) { 13051197Srgrimes return EIO; 13061197Srgrimes } 1307578Srgrimes 1308578Srgrimes /* Copy it into lastpb */ 1309578Srgrimes cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1310578Srgrimes cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1311578Srgrimes cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1312578Srgrimes 1313578Srgrimes /* Stop playing */ 13141197Srgrimes if ((rc=mcd_stop(unit)) != 0) { 13151197Srgrimes return rc; 13161197Srgrimes } 1317578Srgrimes 1318578Srgrimes /* Set the proper status and exit */ 1319578Srgrimes cd->audio_status = CD_AS_PLAY_PAUSED; 1320578Srgrimes return 0; 1321578Srgrimes} 1322578Srgrimes 13231197Srgrimesstatic int 13241197Srgrimesmcd_resume(int unit) 1325578Srgrimes{ 1326578Srgrimes struct mcd_data *cd = mcd_data + unit; 1327578Srgrimes 13281197Srgrimes if (cd->audio_status != CD_AS_PLAY_PAUSED) { 13291197Srgrimes return EINVAL; 13301197Srgrimes } 1331578Srgrimes return mcd_play(unit, &cd->lastpb); 1332578Srgrimes} 1333578Srgrimes#endif /*!MCDMINI*/ 1334578Srgrimes 1335578Srgrimes#endif /* NMCD > 0 */ 1336