mcd.c revision 6665
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 56604Sache * Changes Copyright (C) 1994-1995 by Andrey A. Chernov, Moscow, Russia 61197Srgrimes * 71197Srgrimes * Rewrote probe routine to work on newer Mitsumi drives. 81197Srgrimes * Additional changes (C) 1994 by Jordan K. Hubbard 91197Srgrimes * 10578Srgrimes * All rights reserved. 11578Srgrimes * 12578Srgrimes * Redistribution and use in source and binary forms, with or without 13578Srgrimes * modification, are permitted provided that the following conditions 14578Srgrimes * are met: 15578Srgrimes * 1. Redistributions of source code must retain the above copyright 16578Srgrimes * notice, this list of conditions and the following disclaimer. 17578Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 18578Srgrimes * notice, this list of conditions and the following disclaimer in the 19578Srgrimes * documentation and/or other materials provided with the distribution. 20578Srgrimes * 3. All advertising materials mentioning features or use of this software 21578Srgrimes * must display the following acknowledgement: 22578Srgrimes * This software was developed by Holger Veit and Brian Moore 231197Srgrimes * for use with "386BSD" and similar operating systems. 24578Srgrimes * "Similar operating systems" includes mainly non-profit oriented 25578Srgrimes * systems for research and education, including but not restricted to 26578Srgrimes * "NetBSD", "FreeBSD", "Mach" (by CMU). 27578Srgrimes * 4. Neither the name of the developer(s) nor the name "386BSD" 28578Srgrimes * may be used to endorse or promote products derived from this 29578Srgrimes * software without specific prior written permission. 30578Srgrimes * 31578Srgrimes * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY 32578Srgrimes * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33578Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34578Srgrimes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE 35578Srgrimes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 36578Srgrimes * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 37578Srgrimes * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 38578Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39578Srgrimes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40578Srgrimes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41578Srgrimes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42578Srgrimes * 436665Sache * $Id: mcd.c,v 1.38 1995/02/22 02:12:10 ache Exp $ 44578Srgrimes */ 45578Srgrimesstatic char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 46578Srgrimes 47578Srgrimes#include "mcd.h" 48578Srgrimes#if NMCD > 0 492056Swollman#include <sys/types.h> 502056Swollman#include <sys/param.h> 512056Swollman#include <sys/systm.h> 522056Swollman#include <sys/conf.h> 532056Swollman#include <sys/file.h> 542056Swollman#include <sys/buf.h> 552056Swollman#include <sys/stat.h> 562056Swollman#include <sys/uio.h> 572056Swollman#include <sys/ioctl.h> 582056Swollman#include <sys/cdio.h> 592056Swollman#include <sys/errno.h> 602056Swollman#include <sys/dkbad.h> 612056Swollman#include <sys/disklabel.h> 623816Swollman#include <sys/devconf.h> 633816Swollman 642056Swollman#include <i386/isa/isa.h> 652056Swollman#include <i386/isa/isa_device.h> 662056Swollman#include <i386/isa/mcdreg.h> 67578Srgrimes 682477Sache#define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d: status=0x%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}} 69578Srgrimes 70578Srgrimes#define mcd_part(dev) ((minor(dev)) & 7) 71578Srgrimes#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) 72578Srgrimes#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) 732395Sache#define RAW_PART 2 74578Srgrimes 75578Srgrimes/* flags */ 76578Srgrimes#define MCDOPEN 0x0001 /* device opened */ 77578Srgrimes#define MCDVALID 0x0002 /* parameters loaded */ 78578Srgrimes#define MCDINIT 0x0004 /* device is init'd */ 792477Sache#define MCDNEWMODEL 0x0008 /* device is new model */ 80578Srgrimes#define MCDLABEL 0x0010 /* label is read */ 81578Srgrimes#define MCDPROBING 0x0020 /* probing */ 82578Srgrimes#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ 83578Srgrimes#define MCDVOLINFO 0x0080 /* already read volinfo */ 84578Srgrimes#define MCDTOC 0x0100 /* already read toc */ 85578Srgrimes#define MCDMBXBSY 0x0200 /* local mbx is busy */ 86578Srgrimes 87578Srgrimes/* status */ 88578Srgrimes#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 89578Srgrimes#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 90578Srgrimes#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 91578Srgrimes#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 92578Srgrimes 931241Sjkh/* These are apparently the different states a mitsumi can get up to */ 941241Sjkh#define MCDCDABSENT 0x0030 951241Sjkh#define MCDCDPRESENT 0x0020 961241Sjkh#define MCDSCLOSED 0x0080 971241Sjkh#define MCDSOPEN 0x00a0 981237Sjkh 992477Sache#define MCD_MD_UNKNOWN (-1) 1002477Sache 101578Srgrimes/* toc */ 102578Srgrimes#define MCD_MAXTOCS 104 /* from the Linux driver */ 103578Srgrimes#define MCD_LASTPLUS1 170 /* special toc entry */ 104578Srgrimes 1054480Sache#define MCD_TYPE_UNKNOWN 0 1064480Sache#define MCD_TYPE_LU002S 1 1074480Sache#define MCD_TYPE_LU005S 2 1084480Sache#define MCD_TYPE_FX001 3 1094480Sache#define MCD_TYPE_FX001D 4 1104480Sache 111578Srgrimesstruct mcd_mbx { 112578Srgrimes short unit; 113578Srgrimes short port; 114578Srgrimes short retry; 115578Srgrimes short nblk; 116578Srgrimes int sz; 117578Srgrimes u_long skip; 118578Srgrimes struct buf *bp; 119578Srgrimes int p_offset; 120578Srgrimes short count; 1212477Sache short mode; 122578Srgrimes}; 123578Srgrimes 124578Srgrimesstruct mcd_data { 1254480Sache short type; 1264480Sache char *name; 127578Srgrimes short config; 128578Srgrimes short flags; 1296028Sache u_char read_command; 130578Srgrimes short status; 131578Srgrimes int blksize; 132578Srgrimes u_long disksize; 133578Srgrimes int iobase; 134578Srgrimes struct disklabel dlabel; 135578Srgrimes int partflags[MAXPARTITIONS]; 136578Srgrimes int openflags; 137578Srgrimes struct mcd_volinfo volinfo; 138578Srgrimes struct mcd_qchninfo toc[MCD_MAXTOCS]; 139578Srgrimes short audio_status; 1402477Sache short curr_mode; 141578Srgrimes struct mcd_read2 lastpb; 142578Srgrimes short debug; 143578Srgrimes struct buf head; /* head of buf queue */ 144578Srgrimes struct mcd_mbx mbx; 145578Srgrimes} mcd_data[NMCD]; 146578Srgrimes 147578Srgrimes/* reader state machine */ 148578Srgrimes#define MCD_S_BEGIN 0 149578Srgrimes#define MCD_S_BEGIN1 1 150578Srgrimes#define MCD_S_WAITSTAT 2 151578Srgrimes#define MCD_S_WAITMODE 3 152578Srgrimes#define MCD_S_WAITREAD 4 153578Srgrimes 154578Srgrimes/* prototypes */ 155578Srgrimesint mcdopen(dev_t dev); 156578Srgrimesint mcdclose(dev_t dev); 157798Swollmanvoid mcdstrategy(struct buf *bp); 158578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); 159578Srgrimesint mcdsize(dev_t dev); 160578Srgrimesstatic void mcd_done(struct mcd_mbx *mbx); 161578Srgrimesstatic void mcd_start(int unit); 162578Srgrimesstatic int mcd_getdisklabel(int unit); 163578Srgrimesstatic void mcd_configure(struct mcd_data *cd); 164578Srgrimesstatic int mcd_get(int unit, char *buf, int nmax); 1652477Sachestatic int mcd_setflags(int unit,struct mcd_data *cd); 166578Srgrimesstatic int mcd_getstat(int unit,int sflg); 167578Srgrimesstatic int mcd_send(int unit, int cmd,int nretrys); 168578Srgrimesstatic int bcd2bin(bcd_t b); 169578Srgrimesstatic bcd_t bin2bcd(int b); 170578Srgrimesstatic void hsg2msf(int hsg, bcd_t *msf); 171578Srgrimesstatic int msf2hsg(bcd_t *msf); 172578Srgrimesstatic int mcd_volinfo(int unit); 173578Srgrimesstatic int mcd_waitrdy(int port,int dly); 174978Sjkhstatic void mcd_doread(int state, struct mcd_mbx *mbxin); 1752477Sachestatic void mcd_soft_reset(int unit); 1762477Sachestatic int mcd_hard_reset(int unit); 177578Srgrimesstatic int mcd_setmode(int unit, int mode); 178578Srgrimesstatic int mcd_getqchan(int unit, struct mcd_qchninfo *q); 179578Srgrimesstatic int mcd_subchan(int unit, struct ioc_read_subchannel *sc); 180578Srgrimesstatic int mcd_toc_header(int unit, struct ioc_toc_header *th); 181578Srgrimesstatic int mcd_read_toc(int unit); 1822477Sachestatic int mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te); 183578Srgrimesstatic int mcd_stop(int unit); 1842477Sachestatic int mcd_eject(int unit); 185578Srgrimesstatic int mcd_playtracks(int unit, struct ioc_play_track *pt); 186578Srgrimesstatic int mcd_play(int unit, struct mcd_read2 *pb); 1872477Sachestatic int mcd_playmsf(int unit, struct ioc_play_msf *pt); 188578Srgrimesstatic int mcd_pause(int unit); 189578Srgrimesstatic int mcd_resume(int unit); 1906604Sachestatic int mcd_lock_door(int unit, int lock); 1916604Sachestatic int mcd_close_tray(int unit); 192578Srgrimes 193578Srgrimesextern int hz; 194578Srgrimesextern int mcd_probe(struct isa_device *dev); 195578Srgrimesextern int mcd_attach(struct isa_device *dev); 196578Srgrimesstruct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; 197578Srgrimes 198578Srgrimes#define mcd_put(port,byte) outb(port,byte) 199578Srgrimes 200578Srgrimes#define MCD_RETRYS 5 201578Srgrimes#define MCD_RDRETRYS 8 202578Srgrimes 2036604Sache#define CLOSE_TRAY_SECS 8 2046604Sache#define DISK_SENSE_SECS 3 2056604Sache#define WAIT_FRAC 4 2066604Sache 207578Srgrimes/* several delays */ 2082477Sache#define RDELAY_WAITSTAT 300 2092477Sache#define RDELAY_WAITMODE 300 210578Srgrimes#define RDELAY_WAITREAD 800 211578Srgrimes 2122477Sache#define MIN_DELAY 15 2136665Sache#define DELAY_GETREPLY 1500000 214578Srgrimes 2153816Swollmanstatic struct kern_devconf kdc_mcd[NMCD] = { { 2163816Swollman 0, 0, 0, /* filled in by dev_attach */ 2173816Swollman "mcd", 0, { MDDT_ISA, 0, "bio" }, 2183816Swollman isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 2193816Swollman &kdc_isa0, /* parent */ 2203816Swollman 0, /* parentdata */ 2213816Swollman DC_IDLE, /* status */ 2224480Sache "Mitsumi CD-ROM controller" /* properly filled later */ 2233816Swollman} }; 2243816Swollman 2253816Swollmanstatic inline void 2263816Swollmanmcd_registerdev(struct isa_device *id) 2273816Swollman{ 2283816Swollman if(id->id_unit) 2293816Swollman kdc_mcd[id->id_unit] = kdc_mcd[0]; 2303816Swollman kdc_mcd[id->id_unit].kdc_unit = id->id_unit; 2313816Swollman kdc_mcd[id->id_unit].kdc_isa = id; 2323816Swollman dev_attach(&kdc_mcd[id->id_unit]); 2333816Swollman} 2343816Swollman 235578Srgrimesint mcd_attach(struct isa_device *dev) 236578Srgrimes{ 237578Srgrimes struct mcd_data *cd = mcd_data + dev->id_unit; 238578Srgrimes int i; 239578Srgrimes 240578Srgrimes cd->iobase = dev->id_iobase; 241578Srgrimes cd->flags |= MCDINIT; 2422477Sache mcd_soft_reset(dev->id_unit); 243578Srgrimes 244578Srgrimes#ifdef NOTYET 245578Srgrimes /* wire controller for interrupts and dma */ 246578Srgrimes mcd_configure(cd); 247578Srgrimes#endif 2483816Swollman mcd_registerdev(dev); 2494480Sache /* name filled in probe */ 2504480Sache kdc_mcd[dev->id_unit].kdc_description = mcd_data[dev->id_unit].name; 251578Srgrimes 252578Srgrimes return 1; 253578Srgrimes} 254578Srgrimes 255578Srgrimesint mcdopen(dev_t dev) 256578Srgrimes{ 2576604Sache int unit,part,phys,r,retry; 258578Srgrimes struct mcd_data *cd; 259578Srgrimes 260578Srgrimes unit = mcd_unit(dev); 261578Srgrimes if (unit >= NMCD) 262578Srgrimes return ENXIO; 263578Srgrimes 264578Srgrimes cd = mcd_data + unit; 265578Srgrimes part = mcd_part(dev); 266578Srgrimes phys = mcd_phys(dev); 267578Srgrimes 268578Srgrimes /* not initialized*/ 269578Srgrimes if (!(cd->flags & MCDINIT)) 270578Srgrimes return ENXIO; 271578Srgrimes 272578Srgrimes /* invalidated in the meantime? mark all open part's invalid */ 273578Srgrimes if (!(cd->flags & MCDVALID) && cd->openflags) 274578Srgrimes return ENXIO; 275578Srgrimes 2766604Sache if (mcd_close_tray(unit) == EIO) /* detect disk change too */ 2776604Sache return EIO; 278578Srgrimes 2796604Sache if ( (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) 2806604Sache || !(cd->status & MCDDSKIN)) 2816604Sache for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 2826604Sache (void) tsleep((caddr_t)cd, PSOCK | PCATCH, "mcdsns", hz/WAIT_FRAC); 2836604Sache if ((r = mcd_getstat(unit,1)) == -1) 2846604Sache return EIO; 2856604Sache if (r != -2) 2866604Sache break; 2876604Sache } 2886604Sache 2892477Sache if (cd->status & MCDDOOROPEN) { 2902477Sache printf("mcd%d: door is open\n"); 2912477Sache return ENXIO; 2922477Sache } 2932477Sache if (!(cd->status & MCDDSKIN)) { 2942477Sache printf("mcd%d: no CD inside\n"); 2952477Sache return ENXIO; 2962477Sache } 2976604Sache if (cd->status & MCDDSKCHNG) { 2986604Sache printf("mcd%d: CD not sensed\n"); 2996604Sache return ENXIO; 3006604Sache } 301578Srgrimes 302578Srgrimes if (mcdsize(dev) < 0) { 303578Srgrimes printf("mcd%d: failed to get disk size\n",unit); 304578Srgrimes return ENXIO; 305578Srgrimes } else 306578Srgrimes cd->flags |= MCDVALID; 307578Srgrimes 3082477Sache /* XXX get a default disklabel */ 3092477Sache mcd_getdisklabel(unit); 3102477Sache 311578SrgrimesMCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", 312578Srgrimes part,cd->disksize,cd->blksize,0); 313578Srgrimes 314578Srgrimes if (part == RAW_PART || 315578Srgrimes (part < cd->dlabel.d_npartitions && 316578Srgrimes cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { 317578Srgrimes cd->partflags[part] |= MCDOPEN; 318578Srgrimes cd->openflags |= (1<<part); 319578Srgrimes if (part == RAW_PART && phys != 0) 320578Srgrimes cd->partflags[part] |= MCDREADRAW; 3213816Swollman kdc_mcd[unit].kdc_state = DC_BUSY; 3226604Sache (void) mcd_lock_door(unit, MCD_LK_LOCK); 3236604Sache if (!(cd->flags & MCDVALID)) 3246604Sache return ENXIO; 325578Srgrimes return 0; 326578Srgrimes } 327578Srgrimes 328578Srgrimes return ENXIO; 329578Srgrimes} 330578Srgrimes 331578Srgrimesint mcdclose(dev_t dev) 332578Srgrimes{ 333578Srgrimes int unit,part,phys; 334578Srgrimes struct mcd_data *cd; 335578Srgrimes 336578Srgrimes unit = mcd_unit(dev); 337578Srgrimes if (unit >= NMCD) 338578Srgrimes return ENXIO; 339578Srgrimes 340578Srgrimes cd = mcd_data + unit; 341578Srgrimes part = mcd_part(dev); 342578Srgrimes phys = mcd_phys(dev); 343578Srgrimes 344578Srgrimes if (!(cd->flags & MCDINIT)) 345578Srgrimes return ENXIO; 346578Srgrimes 3473816Swollman kdc_mcd[unit].kdc_state = DC_IDLE; 3486604Sache (void) mcd_lock_door(unit, MCD_LK_UNLOCK); 3496604Sache 3506604Sache if (!(cd->flags & MCDVALID)) 3512477Sache return 0; 352578Srgrimes 353578Srgrimes /* close channel */ 354578Srgrimes cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); 355578Srgrimes cd->openflags &= ~(1<<part); 356578Srgrimes MCD_TRACE("close: partition=%d\n",part,0,0,0); 357578Srgrimes 358578Srgrimes return 0; 359578Srgrimes} 360578Srgrimes 361798Swollmanvoid 362798Swollmanmcdstrategy(struct buf *bp) 363578Srgrimes{ 364578Srgrimes struct mcd_data *cd; 365578Srgrimes struct buf *qp; 366578Srgrimes int s; 367578Srgrimes 368578Srgrimes int unit = mcd_unit(bp->b_dev); 369578Srgrimes 370578Srgrimes cd = mcd_data + unit; 371578Srgrimes 372578Srgrimes /* test validity */ 373578Srgrimes/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", 374578Srgrimes bp,unit,bp->b_blkno,bp->b_bcount);*/ 375578Srgrimes if (unit >= NMCD || bp->b_blkno < 0) { 376578Srgrimes printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", 377578Srgrimes unit, bp->b_blkno, bp->b_bcount); 378578Srgrimes pg("mcd: mcdstratregy failure"); 379578Srgrimes bp->b_error = EINVAL; 380578Srgrimes bp->b_flags |= B_ERROR; 381578Srgrimes goto bad; 382578Srgrimes } 383578Srgrimes 384578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 385578Srgrimes if (!(cd->flags & MCDVALID)) { 386578SrgrimesMCD_TRACE("strategy: drive not valid\n",0,0,0,0); 387578Srgrimes bp->b_error = EIO; 388578Srgrimes goto bad; 389578Srgrimes } 390578Srgrimes 391578Srgrimes /* read only */ 392578Srgrimes if (!(bp->b_flags & B_READ)) { 393578Srgrimes bp->b_error = EROFS; 394578Srgrimes goto bad; 395578Srgrimes } 396578Srgrimes 397578Srgrimes /* no data to read */ 398578Srgrimes if (bp->b_bcount == 0) 399578Srgrimes goto done; 400578Srgrimes 401578Srgrimes /* for non raw access, check partition limits */ 402578Srgrimes if (mcd_part(bp->b_dev) != RAW_PART) { 403578Srgrimes if (!(cd->flags & MCDLABEL)) { 404578Srgrimes bp->b_error = EIO; 405578Srgrimes goto bad; 406578Srgrimes } 407578Srgrimes /* adjust transfer if necessary */ 408578Srgrimes if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { 409578Srgrimes goto done; 410578Srgrimes } 4111379Sdg } else { 4121379Sdg bp->b_pblkno = bp->b_blkno; 4131437Sgclarkii bp->b_resid = 0; 414578Srgrimes } 415578Srgrimes 416578Srgrimes /* queue it */ 417578Srgrimes qp = &cd->head; 418578Srgrimes s = splbio(); 419578Srgrimes disksort(qp,bp); 420578Srgrimes splx(s); 421578Srgrimes 422578Srgrimes /* now check whether we can perform processing */ 423578Srgrimes mcd_start(unit); 424578Srgrimes return; 425578Srgrimes 426578Srgrimesbad: 427578Srgrimes bp->b_flags |= B_ERROR; 428578Srgrimesdone: 429578Srgrimes bp->b_resid = bp->b_bcount; 430578Srgrimes biodone(bp); 431578Srgrimes return; 432578Srgrimes} 433578Srgrimes 434578Srgrimesstatic void mcd_start(int unit) 435578Srgrimes{ 436578Srgrimes struct mcd_data *cd = mcd_data + unit; 437578Srgrimes struct buf *bp, *qp = &cd->head; 438578Srgrimes struct partition *p; 439578Srgrimes int part; 440578Srgrimes register s = splbio(); 441578Srgrimes 4422477Sache if (cd->flags & MCDMBXBSY) { 4432477Sache splx(s); 444578Srgrimes return; 4452477Sache } 446578Srgrimes 447578Srgrimes if ((bp = qp->b_actf) != 0) { 448578Srgrimes /* block found to process, dequeue */ 449578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 4502526Sse qp->b_actf = bp->b_actf; /* changed from: bp->av_forw <se> */ 451578Srgrimes splx(s); 452578Srgrimes } else { 453578Srgrimes /* nothing to do */ 454578Srgrimes splx(s); 455578Srgrimes return; 456578Srgrimes } 457578Srgrimes 458578Srgrimes /* changed media? */ 459578Srgrimes if (!(cd->flags & MCDVALID)) { 460578Srgrimes MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); 461578Srgrimes return; 462578Srgrimes } 463578Srgrimes 464578Srgrimes p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); 465578Srgrimes 466578Srgrimes cd->flags |= MCDMBXBSY; 4672477Sache if (cd->partflags[mcd_part(bp->b_dev)] & MCDREADRAW) 4682477Sache cd->flags |= MCDREADRAW; 469578Srgrimes cd->mbx.unit = unit; 470578Srgrimes cd->mbx.port = cd->iobase; 471578Srgrimes cd->mbx.retry = MCD_RETRYS; 472578Srgrimes cd->mbx.bp = bp; 473578Srgrimes cd->mbx.p_offset = p->p_offset; 474578Srgrimes 475578Srgrimes /* calling the read routine */ 476978Sjkh mcd_doread(MCD_S_BEGIN,&(cd->mbx)); 477578Srgrimes /* triggers mcd_start, when successful finished */ 478578Srgrimes return; 479578Srgrimes} 480578Srgrimes 481578Srgrimesint mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) 482578Srgrimes{ 483578Srgrimes struct mcd_data *cd; 484578Srgrimes int unit,part; 485578Srgrimes 486578Srgrimes unit = mcd_unit(dev); 487578Srgrimes part = mcd_part(dev); 488578Srgrimes cd = mcd_data + unit; 489578Srgrimes 4906604Sache if (mcd_getstat(unit, 1) == -1) /* detect disk change too */ 4912477Sache return EIO; 492578SrgrimesMCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); 493578Srgrimes 494578Srgrimes switch (cmd) { 495578Srgrimes case DIOCSBAD: 4966604Sache if (!(cd->flags & MCDVALID)) 4976604Sache return ENXIO; 498578Srgrimes return EINVAL; 499578Srgrimes case DIOCGDINFO: 5006604Sache if (!(cd->flags & MCDVALID)) 5016604Sache return ENXIO; 5022477Sache *(struct disklabel *) addr = cd->dlabel; 5032477Sache return 0; 504578Srgrimes case DIOCGPART: 5056604Sache if (!(cd->flags & MCDVALID)) 5066604Sache return ENXIO; 5072477Sache ((struct partinfo *) addr)->disklab = &cd->dlabel; 5082477Sache ((struct partinfo *) addr)->part = 5092477Sache &cd->dlabel.d_partitions[mcd_part(dev)]; 5102477Sache return 0; 5112477Sache 5122477Sache /* 5132477Sache * a bit silly, but someone might want to test something on a 5142477Sache * section of cdrom. 5152477Sache */ 516578Srgrimes case DIOCWDINFO: 517578Srgrimes case DIOCSDINFO: 5186604Sache if (!(cd->flags & MCDVALID)) 5196604Sache return ENXIO; 5202477Sache if ((flags & FWRITE) == 0) 5212477Sache return EBADF; 5222477Sache else { 5232477Sache return setdisklabel(&cd->dlabel, 5242477Sache (struct disklabel *) addr, 5252477Sache 0); 5262477Sache } 527578Srgrimes case DIOCWLABEL: 5286604Sache if (!(cd->flags & MCDVALID)) 5296604Sache return ENXIO; 5302477Sache return EBADF; 531578Srgrimes case CDIOCPLAYTRACKS: 5326604Sache if (!(cd->flags & MCDVALID)) 5336604Sache return ENXIO; 534578Srgrimes return mcd_playtracks(unit, (struct ioc_play_track *) addr); 535578Srgrimes case CDIOCPLAYBLOCKS: 5366604Sache if (!(cd->flags & MCDVALID)) 5376604Sache return ENXIO; 5382477Sache return EINVAL; 5392477Sache case CDIOCPLAYMSF: 5406604Sache if (!(cd->flags & MCDVALID)) 5416604Sache return ENXIO; 5422477Sache return mcd_playmsf(unit, (struct ioc_play_msf *) addr); 543578Srgrimes case CDIOCREADSUBCHANNEL: 5446604Sache if (!(cd->flags & MCDVALID)) 5456604Sache return ENXIO; 546578Srgrimes return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); 547578Srgrimes case CDIOREADTOCHEADER: 5486604Sache if (!(cd->flags & MCDVALID)) 5496604Sache return ENXIO; 550578Srgrimes return mcd_toc_header(unit, (struct ioc_toc_header *) addr); 551578Srgrimes case CDIOREADTOCENTRYS: 5526604Sache if (!(cd->flags & MCDVALID)) 5536604Sache return ENXIO; 5542477Sache return mcd_toc_entrys(unit, (struct ioc_read_toc_entry *) addr); 555578Srgrimes case CDIOCSETPATCH: 556578Srgrimes case CDIOCGETVOL: 557578Srgrimes case CDIOCSETVOL: 558578Srgrimes case CDIOCSETMONO: 559578Srgrimes case CDIOCSETSTERIO: 560578Srgrimes case CDIOCSETMUTE: 561578Srgrimes case CDIOCSETLEFT: 562578Srgrimes case CDIOCSETRIGHT: 563578Srgrimes return EINVAL; 564578Srgrimes case CDIOCRESUME: 5656604Sache if (!(cd->flags & MCDVALID)) 5666604Sache return ENXIO; 567578Srgrimes return mcd_resume(unit); 568578Srgrimes case CDIOCPAUSE: 5696604Sache if (!(cd->flags & MCDVALID)) 5706604Sache return ENXIO; 571578Srgrimes return mcd_pause(unit); 572578Srgrimes case CDIOCSTART: 5736604Sache if (!(cd->flags & MCDVALID)) 5746604Sache return ENXIO; 575578Srgrimes return EINVAL; 576578Srgrimes case CDIOCSTOP: 5776604Sache if (!(cd->flags & MCDVALID)) 5786604Sache return ENXIO; 579578Srgrimes return mcd_stop(unit); 580578Srgrimes case CDIOCEJECT: 5812477Sache return mcd_eject(unit); 582578Srgrimes case CDIOCSETDEBUG: 583578Srgrimes cd->debug = 1; 584578Srgrimes return 0; 585578Srgrimes case CDIOCCLRDEBUG: 586578Srgrimes cd->debug = 0; 587578Srgrimes return 0; 588578Srgrimes case CDIOCRESET: 5892477Sache return mcd_hard_reset(unit); 5904398Sache case CDIOCALLOW: 5916604Sache return mcd_lock_door(unit, MCD_LK_UNLOCK); 592578Srgrimes default: 593578Srgrimes return ENOTTY; 594578Srgrimes } 595578Srgrimes /*NOTREACHED*/ 596578Srgrimes} 597578Srgrimes 598578Srgrimes/* this could have been taken from scsi/cd.c, but it is not clear 599578Srgrimes * whether the scsi cd driver is linked in 600578Srgrimes */ 601578Srgrimesstatic int mcd_getdisklabel(int unit) 602578Srgrimes{ 603578Srgrimes struct mcd_data *cd = mcd_data + unit; 604578Srgrimes 605578Srgrimes if (cd->flags & MCDLABEL) 606578Srgrimes return -1; 607578Srgrimes 608578Srgrimes bzero(&cd->dlabel,sizeof(struct disklabel)); 6094480Sache /* filled with spaces first */ 6104480Sache strncpy(cd->dlabel.d_typename," ", 6114480Sache sizeof(cd->dlabel.d_typename)); 6124480Sache strncpy(cd->dlabel.d_typename, cd->name, 6134480Sache min(strlen(cd->name), sizeof(cd->dlabel.d_typename) - 1)); 6144480Sache strncpy(cd->dlabel.d_packname,"unknown ", 6154480Sache sizeof(cd->dlabel.d_packname)); 616578Srgrimes cd->dlabel.d_secsize = cd->blksize; 617578Srgrimes cd->dlabel.d_nsectors = 100; 618578Srgrimes cd->dlabel.d_ntracks = 1; 619578Srgrimes cd->dlabel.d_ncylinders = (cd->disksize/100)+1; 620578Srgrimes cd->dlabel.d_secpercyl = 100; 621578Srgrimes cd->dlabel.d_secperunit = cd->disksize; 622578Srgrimes cd->dlabel.d_rpm = 300; 623578Srgrimes cd->dlabel.d_interleave = 1; 624578Srgrimes cd->dlabel.d_flags = D_REMOVABLE; 625578Srgrimes cd->dlabel.d_npartitions= 1; 626578Srgrimes cd->dlabel.d_partitions[0].p_offset = 0; 627578Srgrimes cd->dlabel.d_partitions[0].p_size = cd->disksize; 628578Srgrimes cd->dlabel.d_partitions[0].p_fstype = 9; 629578Srgrimes cd->dlabel.d_magic = DISKMAGIC; 630578Srgrimes cd->dlabel.d_magic2 = DISKMAGIC; 631578Srgrimes cd->dlabel.d_checksum = dkcksum(&cd->dlabel); 632578Srgrimes 633578Srgrimes cd->flags |= MCDLABEL; 634578Srgrimes return 0; 635578Srgrimes} 636578Srgrimes 637578Srgrimesint mcdsize(dev_t dev) 638578Srgrimes{ 639578Srgrimes int size; 640578Srgrimes int unit = mcd_unit(dev); 641578Srgrimes struct mcd_data *cd = mcd_data + unit; 642578Srgrimes 6432477Sache if (mcd_volinfo(unit) == 0) { 644578Srgrimes cd->blksize = MCDBLK; 645578Srgrimes size = msf2hsg(cd->volinfo.vol_msf); 646578Srgrimes cd->disksize = size * (MCDBLK/DEV_BSIZE); 647578Srgrimes return 0; 648578Srgrimes } 649578Srgrimes return -1; 650578Srgrimes} 651578Srgrimes 652578Srgrimes/*************************************************************** 653578Srgrimes * lower level of driver starts here 654578Srgrimes **************************************************************/ 655578Srgrimes 656578Srgrimes#ifdef NOTDEF 6571197Srgrimesstatic char 6581197Srgrimesirqs[] = { 659578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 660578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 661578Srgrimes}; 662578Srgrimes 6631197Srgrimesstatic char 6641197Srgrimesdrqs[] = { 665578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 666578Srgrimes}; 667578Srgrimes#endif 668578Srgrimes 6691197Srgrimesstatic void 6701197Srgrimesmcd_configure(struct mcd_data *cd) 671578Srgrimes{ 672578Srgrimes outb(cd->iobase+mcd_config,cd->config); 673578Srgrimes} 674578Srgrimes 6751197Srgrimes/* Wait for non-busy - return 0 on timeout */ 6761197Srgrimesstatic int 6771197Srgrimestwiddle_thumbs(int port, int unit, int count, char *whine) 6781197Srgrimes{ 6791197Srgrimes int i; 6801197Srgrimes 6811197Srgrimes for (i = 0; i < count; i++) { 6825226Sache if (!(inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 6831197Srgrimes return 1; 6841197Srgrimes } 6851197Srgrimes printf("mcd%d: timeout %s\n", unit, whine); 6861197Srgrimes return 0; 6871197Srgrimes} 6881197Srgrimes 689978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 690578Srgrimes 6911197Srgrimesint 6921197Srgrimesmcd_probe(struct isa_device *dev) 693578Srgrimes{ 694578Srgrimes int port = dev->id_iobase; 695578Srgrimes int unit = dev->id_unit; 6961197Srgrimes int i, j; 6971197Srgrimes int status; 6981197Srgrimes unsigned char stbytes[3]; 699578Srgrimes 700578Srgrimes mcd_data[unit].flags = MCDPROBING; 701578Srgrimes 702578Srgrimes#ifdef NOTDEF 703578Srgrimes /* get irq/drq configuration word */ 704578Srgrimes mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 705578Srgrimes#else 706578Srgrimes mcd_data[unit].config = 0; 707578Srgrimes#endif 708578Srgrimes 709578Srgrimes /* send a reset */ 7101197Srgrimes outb(port+MCD_FLAGS, M_RESET); 711578Srgrimes 7121197Srgrimes /* 7131197Srgrimes * delay awhile by getting any pending garbage (old data) and 7141197Srgrimes * throwing it away. 7151197Srgrimes */ 7162477Sache for (i = 1000000; i != 0; i--) 7171197Srgrimes inb(port+MCD_FLAGS); 718578Srgrimes 7191197Srgrimes /* Get status */ 7201197Srgrimes outb(port+MCD_DATA, MCD_CMDGETSTAT); 7212477Sache if (!twiddle_thumbs(port, unit, 1000000, "getting status")) 7221197Srgrimes return 0; /* Timeout */ 7231197Srgrimes /* Get version information */ 7241197Srgrimes outb(port+MCD_DATA, MCD_CMDCONTINFO); 7251197Srgrimes for (j = 0; j < 3; j++) { 7262477Sache if (!twiddle_thumbs(port, unit, 3000, "getting version info")) 7271197Srgrimes return 0; 7281197Srgrimes stbytes[j] = (inb(port+MCD_DATA) & 0xFF); 7291197Srgrimes } 7305178Sache if (stbytes[1] == stbytes[2]) 7315178Sache return 0; 7325226Sache if (stbytes[2] >= 4 || stbytes[1] != 'M') { 7331197Srgrimes outb(port+MCD_CTRL, M_PICKLE); 7342477Sache mcd_data[unit].flags |= MCDNEWMODEL; 7351197Srgrimes } 7366028Sache mcd_data[unit].read_command = MCD_CMDSINGLESPEEDREAD; 7374480Sache switch (stbytes[1]) { 7384480Sache case 'M': 7394480Sache if (mcd_data[unit].flags & MCDNEWMODEL) { 7404480Sache mcd_data[unit].type = MCD_TYPE_LU005S; 7414480Sache mcd_data[unit].name = "Mitsumi LU005S"; 7424480Sache } else { 7434480Sache mcd_data[unit].type = MCD_TYPE_LU002S; 7444480Sache mcd_data[unit].name = "Mitsumi LU002S"; 7454480Sache } 7464480Sache break; 7474480Sache case 'F': 7484480Sache mcd_data[unit].type = MCD_TYPE_FX001; 7494480Sache mcd_data[unit].name = "Mitsumi FX001"; 7504480Sache break; 7514480Sache case 'D': 7524480Sache mcd_data[unit].type = MCD_TYPE_FX001D; 7534480Sache mcd_data[unit].name = "Mitsumi FX001D"; 7546028Sache mcd_data[unit].read_command = MCD_CMDDOUBLESPEEDREAD; 7554480Sache break; 7564480Sache default: 7574480Sache mcd_data[unit].type = MCD_TYPE_UNKNOWN; 7584480Sache mcd_data[unit].name = "Mitsumi ???"; 7594480Sache break; 7604480Sache } 7615226Sache printf("mcd%d: type %s, version info: %c %x\n", unit, mcd_data[unit].name, 7625226Sache stbytes[1], stbytes[2]); 7635226Sache 7641197Srgrimes return 4; 765578Srgrimes} 766578Srgrimes 767978Sjkh 7681197Srgrimesstatic int 7691197Srgrimesmcd_waitrdy(int port,int dly) 770578Srgrimes{ 771578Srgrimes int i; 772578Srgrimes 7735226Sache /* wait until flag port senses status ready */ 7742477Sache for (i=0; i<dly; i+=MIN_DELAY) { 7755226Sache if (!(inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 776578Srgrimes return 0; 7772477Sache DELAY(MIN_DELAY); 778578Srgrimes } 779578Srgrimes return -1; 780578Srgrimes} 781578Srgrimes 7821197Srgrimesstatic int 7831197Srgrimesmcd_getreply(int unit,int dly) 784578Srgrimes{ 785578Srgrimes int i; 786578Srgrimes struct mcd_data *cd = mcd_data + unit; 787578Srgrimes int port = cd->iobase; 788578Srgrimes 789578Srgrimes /* wait data to become ready */ 790578Srgrimes if (mcd_waitrdy(port,dly)<0) { 791578Srgrimes printf("mcd%d: timeout getreply\n",unit); 792578Srgrimes return -1; 793578Srgrimes } 794578Srgrimes 795578Srgrimes /* get the data */ 796578Srgrimes return inb(port+mcd_status) & 0xFF; 797578Srgrimes} 798578Srgrimes 7991197Srgrimesstatic int 8001197Srgrimesmcd_getstat(int unit,int sflg) 801578Srgrimes{ 802578Srgrimes int i; 803578Srgrimes struct mcd_data *cd = mcd_data + unit; 804578Srgrimes int port = cd->iobase; 805578Srgrimes 806578Srgrimes /* get the status */ 807578Srgrimes if (sflg) 808578Srgrimes outb(port+mcd_command, MCD_CMDGETSTAT); 809578Srgrimes i = mcd_getreply(unit,DELAY_GETREPLY); 8106604Sache if (i<0 || (i & MCD_ST_CMDCHECK)) { 8116604Sache cd->curr_mode = MCD_MD_UNKNOWN; 8126604Sache return -1; 8136604Sache } 814578Srgrimes 815578Srgrimes cd->status = i; 816578Srgrimes 8172477Sache if (mcd_setflags(unit,cd) < 0) 8182477Sache return -2; 819578Srgrimes return cd->status; 820578Srgrimes} 821578Srgrimes 8222477Sachestatic int 8231197Srgrimesmcd_setflags(int unit, struct mcd_data *cd) 824578Srgrimes{ 825578Srgrimes /* check flags */ 8262477Sache if ( (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) 8272477Sache || !(cd->status & MCDDSKIN)) { 8282477Sache MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n",0,0,0,0); 8292477Sache mcd_soft_reset(unit); 8302477Sache return -1; 831578Srgrimes } 832578Srgrimes 833578Srgrimes if (cd->status & MCDAUDIOBSY) 834578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 835578Srgrimes else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 836578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 8372477Sache return 0; 838578Srgrimes} 839578Srgrimes 8401197Srgrimesstatic int 8411197Srgrimesmcd_get(int unit, char *buf, int nmax) 842578Srgrimes{ 843578Srgrimes int port = mcd_data[unit].iobase; 844578Srgrimes int i,k; 845578Srgrimes 846578Srgrimes for (i=0; i<nmax; i++) { 847578Srgrimes /* wait for data */ 848578Srgrimes if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) { 849578Srgrimes printf("mcd%d: timeout mcd_get\n",unit); 850578Srgrimes return -1; 851578Srgrimes } 852578Srgrimes buf[i] = k; 853578Srgrimes } 854578Srgrimes return i; 855578Srgrimes} 856578Srgrimes 8571197Srgrimesstatic int 8581197Srgrimesmcd_send(int unit, int cmd,int nretrys) 859578Srgrimes{ 8602477Sache int i,k=0; 861578Srgrimes int port = mcd_data[unit].iobase; 862578Srgrimes 8632477Sache/*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/ 864578Srgrimes for (i=0; i<nretrys; i++) { 865578Srgrimes outb(port+mcd_command, cmd); 8662477Sache if ((k=mcd_getstat(unit,0)) != -1) 867578Srgrimes break; 868578Srgrimes } 8692477Sache if (k == -2) { 8702477Sache printf("mcd%d: media changed\n",unit); 8712477Sache return -1; 8722477Sache } 873578Srgrimes if (i == nretrys) { 874578Srgrimes printf("mcd%d: mcd_send retry cnt exceeded\n",unit); 875578Srgrimes return -1; 876578Srgrimes } 8772477Sache/*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/ 878578Srgrimes return 0; 879578Srgrimes} 880578Srgrimes 8811197Srgrimesstatic int 8821197Srgrimesbcd2bin(bcd_t b) 883578Srgrimes{ 884578Srgrimes return (b >> 4) * 10 + (b & 15); 885578Srgrimes} 886578Srgrimes 8871197Srgrimesstatic bcd_t 8881197Srgrimesbin2bcd(int b) 889578Srgrimes{ 890578Srgrimes return ((b / 10) << 4) | (b % 10); 891578Srgrimes} 892578Srgrimes 8931197Srgrimesstatic void 8941197Srgrimeshsg2msf(int hsg, bcd_t *msf) 895578Srgrimes{ 896578Srgrimes hsg += 150; 897578Srgrimes M_msf(msf) = bin2bcd(hsg / 4500); 898578Srgrimes hsg %= 4500; 899578Srgrimes S_msf(msf) = bin2bcd(hsg / 75); 900578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 901578Srgrimes} 902578Srgrimes 9031197Srgrimesstatic int 9041197Srgrimesmsf2hsg(bcd_t *msf) 905578Srgrimes{ 906578Srgrimes return (bcd2bin(M_msf(msf)) * 60 + 907578Srgrimes bcd2bin(S_msf(msf))) * 75 + 908578Srgrimes bcd2bin(F_msf(msf)) - 150; 909578Srgrimes} 910578Srgrimes 9111197Srgrimesstatic int 9121197Srgrimesmcd_volinfo(int unit) 913578Srgrimes{ 914578Srgrimes struct mcd_data *cd = mcd_data + unit; 915578Srgrimes int i; 916578Srgrimes 917578Srgrimes /* Just return if we already have it */ 918578Srgrimes if (cd->flags & MCDVOLINFO) return 0; 919578Srgrimes 9202477Sache/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 9212477Sache 922578Srgrimes /* send volume info command */ 923578Srgrimes if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 9242477Sache return EIO; 925578Srgrimes 926578Srgrimes /* get data */ 927578Srgrimes if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { 928578Srgrimes printf("mcd%d: mcd_volinfo: error read data\n",unit); 9292477Sache return EIO; 930578Srgrimes } 931578Srgrimes 9326604Sache if (cd->volinfo.trk_low > 0 && 9336604Sache cd->volinfo.trk_high >= cd->volinfo.trk_low 9346604Sache ) { 935578Srgrimes cd->flags |= MCDVOLINFO; /* volinfo is OK */ 936578Srgrimes return 0; 937578Srgrimes } 938578Srgrimes 9392477Sache return EINVAL; 940578Srgrimes} 941578Srgrimes 942798Swollmanvoid 943798Swollmanmcdintr(unit) 944798Swollman int unit; 945578Srgrimes{ 9462477Sache MCD_TRACE("stray interrupt\n",0,0,0,0); 947578Srgrimes} 948578Srgrimes 949578Srgrimes/* state machine to process read requests 950578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 951578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 952578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 953578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 954578Srgrimes */ 955578Srgrimesstatic struct mcd_mbx *mbxsave; 956578Srgrimes 9571197Srgrimesstatic void 9581197Srgrimesmcd_doread(int state, struct mcd_mbx *mbxin) 959578Srgrimes{ 960578Srgrimes struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; 961578Srgrimes int unit = mbx->unit; 962578Srgrimes int port = mbx->port; 9632477Sache int com_port = mbx->port + mcd_command; 9642477Sache int data_port = mbx->port + mcd_rdata; 965578Srgrimes struct buf *bp = mbx->bp; 966578Srgrimes struct mcd_data *cd = mcd_data + unit; 967578Srgrimes 968578Srgrimes int rm,i,k; 969578Srgrimes struct mcd_read2 rbuf; 970578Srgrimes int blknum; 971578Srgrimes caddr_t addr; 972578Srgrimes 973578Srgrimesloop: 974578Srgrimes switch (state) { 975578Srgrimes case MCD_S_BEGIN: 976578Srgrimes mbx = mbxsave = mbxin; 977578Srgrimes 978578Srgrimes case MCD_S_BEGIN1: 9796604Sacheretry_status: 980578Srgrimes /* get status */ 9812477Sache outb(com_port, MCD_CMDGETSTAT); 982578Srgrimes mbx->count = RDELAY_WAITSTAT; 9831197Srgrimes timeout((timeout_func_t)mcd_doread, 9841197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 985578Srgrimes return; 986578Srgrimes case MCD_S_WAITSTAT: 9871000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT); 988578Srgrimes if (mbx->count-- >= 0) { 9895226Sache if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 9901197Srgrimes timeout((timeout_func_t)mcd_doread, 9911197Srgrimes (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */ 992578Srgrimes return; 993578Srgrimes } 9942477Sache cd->status = inb(port+mcd_status) & 0xFF; 9956028Sache if (cd->status & MCD_ST_CMDCHECK) 9966028Sache goto retry_status; 9972477Sache if (mcd_setflags(unit,cd) < 0) 9982477Sache goto changed; 9991197Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n", 10001197Srgrimes RDELAY_WAITSTAT-mbx->count,0,0,0); 1001578Srgrimes /* reject, if audio active */ 1002578Srgrimes if (cd->status & MCDAUDIOBSY) { 1003578Srgrimes printf("mcd%d: audio is active\n",unit); 1004578Srgrimes goto readerr; 1005578Srgrimes } 10066604Sache 10076028Sacheretry_mode: 1008578Srgrimes /* to check for raw/cooked mode */ 1009578Srgrimes if (cd->flags & MCDREADRAW) { 10104389Sache rm = MCD_MD_RAW; 1011578Srgrimes mbx->sz = MCDRBLK; 1012578Srgrimes } else { 10134389Sache rm = MCD_MD_COOKED; 1014578Srgrimes mbx->sz = cd->blksize; 1015578Srgrimes } 1016578Srgrimes 10172477Sache if (rm == cd->curr_mode) 10182477Sache goto modedone; 10192477Sache 1020578Srgrimes mbx->count = RDELAY_WAITMODE; 10212477Sache 10222477Sache cd->curr_mode = MCD_MD_UNKNOWN; 10232477Sache mbx->mode = rm; 10242477Sache mcd_put(com_port, MCD_CMDSETMODE); 10252477Sache mcd_put(com_port, rm); 10262477Sache 10271197Srgrimes timeout((timeout_func_t)mcd_doread, 10281197Srgrimes (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */ 1029578Srgrimes return; 1030578Srgrimes } else { 1031578Srgrimes printf("mcd%d: timeout getstatus\n",unit); 1032578Srgrimes goto readerr; 1033578Srgrimes } 1034578Srgrimes 1035578Srgrimes case MCD_S_WAITMODE: 10361000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE); 1037578Srgrimes if (mbx->count-- < 0) { 1038578Srgrimes printf("mcd%d: timeout set mode\n",unit); 1039578Srgrimes goto readerr; 1040578Srgrimes } 10415226Sache if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 1042798Swollman timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100); 1043578Srgrimes return; 1044578Srgrimes } 10452477Sache cd->status = inb(port+mcd_status) & 0xFF; 10466028Sache if (cd->status & MCD_ST_CMDCHECK) { 10476604Sache cd->curr_mode = MCD_MD_UNKNOWN; 10486028Sache goto retry_mode; 10496028Sache } 10502477Sache if (mcd_setflags(unit,cd) < 0) 10512477Sache goto changed; 10522477Sache cd->curr_mode = mbx->mode; 10531197Srgrimes MCD_TRACE("got WAITMODE delay=%d\n", 10541197Srgrimes RDELAY_WAITMODE-mbx->count,0,0,0); 10552477Sachemodedone: 1056578Srgrimes /* for first block */ 1057578Srgrimes mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; 1058578Srgrimes mbx->skip = 0; 1059578Srgrimes 1060578Srgrimesnextblock: 1061578Srgrimes blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) 1062578Srgrimes + mbx->p_offset + mbx->skip/mbx->sz; 1063578Srgrimes 10641197Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n", 10651197Srgrimes blknum,bp,0,0); 1066578Srgrimes 1067578Srgrimes /* build parameter block */ 1068578Srgrimes hsg2msf(blknum,rbuf.start_msf); 10696028Sacheretry_read: 1070578Srgrimes /* send the read command */ 10712477Sache disable_intr(); 10726028Sache mcd_put(com_port,cd->read_command); 10732477Sache mcd_put(com_port,rbuf.start_msf[0]); 10742477Sache mcd_put(com_port,rbuf.start_msf[1]); 10752477Sache mcd_put(com_port,rbuf.start_msf[2]); 10762477Sache mcd_put(com_port,0); 10772477Sache mcd_put(com_port,0); 10782477Sache mcd_put(com_port,1); 10792477Sache enable_intr(); 10802477Sache 10812762Sache /* Spin briefly (<= 2ms) to avoid missing next block */ 10822762Sache for (i = 0; i < 20; i++) { 10835226Sache k = inb(port+MCD_FLAGS); 10845226Sache if (!(k & MFL_DATA_NOT_AVAIL)) 10852762Sache goto got_it; 10862762Sache DELAY(100); 10872762Sache } 10882762Sache 1089578Srgrimes mbx->count = RDELAY_WAITREAD; 10901197Srgrimes timeout((timeout_func_t)mcd_doread, 10911197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 1092578Srgrimes return; 1093578Srgrimes case MCD_S_WAITREAD: 10941000Sats untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD); 1095578Srgrimes if (mbx->count-- > 0) { 10965226Sache k = inb(port+MCD_FLAGS); 10975226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */ 10981197Srgrimes MCD_TRACE("got data delay=%d\n", 10991197Srgrimes RDELAY_WAITREAD-mbx->count,0,0,0); 11002762Sache got_it: 1101578Srgrimes /* data is ready */ 1102578Srgrimes addr = bp->b_un.b_addr + mbx->skip; 11032477Sache 1104578Srgrimes outb(port+mcd_ctl2,0x04); /* XXX */ 1105578Srgrimes for (i=0; i<mbx->sz; i++) 11062477Sache *addr++ = inb(data_port); 1107578Srgrimes outb(port+mcd_ctl2,0x0c); /* XXX */ 1108578Srgrimes 11095226Sache k = inb(port+MCD_FLAGS); 11102477Sache /* If we still have some junk, read it too */ 11115226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { 11122477Sache outb(port+mcd_ctl2,0x04); /* XXX */ 11132477Sache (void)inb(data_port); 11142477Sache (void)inb(data_port); 11152477Sache outb(port+mcd_ctl2,0x0c); /* XXX */ 11162477Sache } 11172477Sache 1118578Srgrimes if (--mbx->nblk > 0) { 1119578Srgrimes mbx->skip += mbx->sz; 1120578Srgrimes goto nextblock; 1121578Srgrimes } 1122578Srgrimes 1123578Srgrimes /* return buffer */ 1124578Srgrimes bp->b_resid = 0; 1125578Srgrimes biodone(bp); 1126578Srgrimes 11272477Sache cd->flags &= ~(MCDMBXBSY|MCDREADRAW); 1128578Srgrimes mcd_start(mbx->unit); 1129578Srgrimes return; 1130578Srgrimes } 11315226Sache if (!(k & MFL_STATUS_NOT_AVAIL)) { 11322477Sache cd->status = inb(port+mcd_status) & 0xFF; 11336028Sache if (cd->status & MCD_ST_CMDCHECK) 11346028Sache goto retry_read; 11352477Sache if (mcd_setflags(unit,cd) < 0) 11362477Sache goto changed; 11372477Sache } 11381197Srgrimes timeout((timeout_func_t)mcd_doread, 11391197Srgrimes (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */ 1140578Srgrimes return; 1141578Srgrimes } else { 1142578Srgrimes printf("mcd%d: timeout read data\n",unit); 1143578Srgrimes goto readerr; 1144578Srgrimes } 1145578Srgrimes } 1146578Srgrimes 1147578Srgrimesreaderr: 1148578Srgrimes if (mbx->retry-- > 0) { 1149578Srgrimes printf("mcd%d: retrying\n",unit); 1150578Srgrimes state = MCD_S_BEGIN1; 1151578Srgrimes goto loop; 1152578Srgrimes } 11532477Sacheharderr: 1154578Srgrimes /* invalidate the buffer */ 1155578Srgrimes bp->b_flags |= B_ERROR; 1156578Srgrimes bp->b_resid = bp->b_bcount; 1157578Srgrimes biodone(bp); 11582477Sache 11592477Sache cd->flags &= ~(MCDMBXBSY|MCDREADRAW); 1160578Srgrimes mcd_start(mbx->unit); 1161578Srgrimes return; 1162578Srgrimes 11632477Sachechanged: 11642477Sache printf("mcd%d: media changed\n", unit); 11652477Sache goto harderr; 11662477Sache 1167578Srgrimes#ifdef NOTDEF 1168578Srgrimes printf("mcd%d: unit timeout, resetting\n",mbx->unit); 1169578Srgrimes outb(mbx->port+mcd_reset,MCD_CMDRESET); 1170578Srgrimes DELAY(300000); 1171578Srgrimes (void)mcd_getstat(mbx->unit,1); 1172578Srgrimes (void)mcd_getstat(mbx->unit,1); 1173578Srgrimes /*cd->status &= ~MCDDSKCHNG; */ 1174578Srgrimes cd->debug = 1; /* preventive set debug mode */ 1175578Srgrimes 1176578Srgrimes#endif 1177578Srgrimes 1178578Srgrimes} 1179578Srgrimes 11801197Srgrimesstatic int 11816604Sachemcd_lock_door(int unit, int lock) 11822477Sache{ 11832477Sache struct mcd_data *cd = mcd_data + unit; 11842477Sache int port = cd->iobase; 11852477Sache 11866604Sache outb(port+mcd_command, MCD_CMDLOCKDRV); 11876604Sache outb(port+mcd_command, lock); 11886604Sache if (mcd_getstat(unit,0) == -1) 11896604Sache return EIO; 11906604Sache return 0; 11916604Sache} 11926604Sache 11936604Sachestatic int 11946604Sachemcd_close_tray(int unit) 11956604Sache{ 11966604Sache struct mcd_data *cd = mcd_data + unit; 11976604Sache int port = cd->iobase; 11986604Sache int retry, r; 11996604Sache 12006604Sache if (mcd_getstat(unit,1) == -1) 12016604Sache return EIO; 12026604Sache if (cd->status & MCDDOOROPEN) { 12036604Sache outb(port+mcd_command, MCD_CMDCLOSETRAY); 12046604Sache for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) { 12056604Sache if (inb(port+MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) 12066604Sache (void) tsleep((caddr_t)cd, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC); 12076604Sache else { 12086604Sache if ((r = mcd_getstat(unit,0)) == -1) 12096604Sache return EIO; 12106604Sache return 0; 12116604Sache } 12126604Sache } 12136604Sache return ENXIO; 12146604Sache } 12156604Sache return 0; 12166604Sache} 12176604Sache 12186604Sachestatic int 12196604Sachemcd_eject(int unit) 12206604Sache{ 12216604Sache struct mcd_data *cd = mcd_data + unit; 12226604Sache int port = cd->iobase, r; 12236604Sache 12246604Sache if (mcd_getstat(unit,1) == -1) /* detect disk change too */ 12256604Sache return EIO; 12266604Sache if (cd->status & MCDDOOROPEN) 12276604Sache return mcd_close_tray(unit); 12286604Sache if ((r = mcd_stop(unit)) == EIO) 12296604Sache return r; 12302477Sache outb(port+mcd_command, MCD_CMDEJECTDISK); 12316604Sache if (mcd_getstat(unit,0) == -1) 12326604Sache return EIO; 12332477Sache return 0; 12342477Sache} 12352477Sache 12362477Sachestatic int 12372477Sachemcd_hard_reset(int unit) 12382477Sache{ 12392477Sache struct mcd_data *cd = mcd_data + unit; 12402477Sache int port = cd->iobase; 12412477Sache 12422477Sache outb(port+mcd_reset,MCD_CMDRESET); 12432477Sache cd->curr_mode = MCD_MD_UNKNOWN; 12442477Sache cd->audio_status = CD_AS_AUDIO_INVALID; 12452477Sache return 0; 12462477Sache} 12472477Sache 12482477Sachestatic void 12492477Sachemcd_soft_reset(int unit) 12502477Sache{ 12512477Sache struct mcd_data *cd = mcd_data + unit; 12522477Sache int i; 12532477Sache 12542477Sache cd->openflags = 0; 12552477Sache cd->flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL); 12562477Sache cd->curr_mode = MCD_MD_UNKNOWN; 12572477Sache for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0; 12582477Sache cd->audio_status = CD_AS_AUDIO_INVALID; 12592477Sache} 12602477Sache 12612477Sachestatic int 12621197Srgrimesmcd_setmode(int unit, int mode) 1263578Srgrimes{ 1264578Srgrimes struct mcd_data *cd = mcd_data + unit; 1265578Srgrimes int port = cd->iobase; 12662477Sache int retry, st; 1267578Srgrimes 12682477Sache if (cd->curr_mode == mode) 12692477Sache return 0; 12702477Sache if (cd->debug) 12712477Sache printf("mcd%d: setting mode to %d\n", unit, mode); 1272578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1273578Srgrimes { 12742477Sache cd->curr_mode = MCD_MD_UNKNOWN; 1275578Srgrimes outb(port+mcd_command, MCD_CMDSETMODE); 1276578Srgrimes outb(port+mcd_command, mode); 12772477Sache if ((st = mcd_getstat(unit, 0)) >= 0) { 12782477Sache cd->curr_mode = mode; 12792477Sache return 0; 12802477Sache } 12812477Sache if (st == -2) { 12822477Sache printf("mcd%d: media changed\n", unit); 12832477Sache break; 12842477Sache } 1285578Srgrimes } 1286578Srgrimes 1287578Srgrimes return -1; 1288578Srgrimes} 1289578Srgrimes 12901197Srgrimesstatic int 12911197Srgrimesmcd_toc_header(int unit, struct ioc_toc_header *th) 1292578Srgrimes{ 1293578Srgrimes struct mcd_data *cd = mcd_data + unit; 12942477Sache int r; 1295578Srgrimes 12962477Sache if ((r = mcd_volinfo(unit)) != 0) 12972477Sache return r; 1298578Srgrimes 1299578Srgrimes th->len = msf2hsg(cd->volinfo.vol_msf); 1300578Srgrimes th->starting_track = bcd2bin(cd->volinfo.trk_low); 1301578Srgrimes th->ending_track = bcd2bin(cd->volinfo.trk_high); 1302578Srgrimes 1303578Srgrimes return 0; 1304578Srgrimes} 1305578Srgrimes 13061197Srgrimesstatic int 13071197Srgrimesmcd_read_toc(int unit) 1308578Srgrimes{ 1309578Srgrimes struct mcd_data *cd = mcd_data + unit; 1310578Srgrimes struct ioc_toc_header th; 1311578Srgrimes struct mcd_qchninfo q; 1312578Srgrimes int rc, trk, idx, retry; 1313578Srgrimes 1314578Srgrimes /* Only read TOC if needed */ 13152477Sache if (cd->flags & MCDTOC) 13161197Srgrimes return 0; 1317578Srgrimes 13182477Sache if (cd->debug) 13192477Sache printf("mcd%d: reading toc header\n", unit); 1320578Srgrimes 13212477Sache if ((rc = mcd_toc_header(unit, &th)) != 0) 1322578Srgrimes return rc; 1323578Srgrimes 13246665Sache if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 13256665Sache return EIO; 13266665Sache 13272477Sache if (mcd_setmode(unit, MCD_MD_TOC) != 0) 1328578Srgrimes return EIO; 1329578Srgrimes 13302477Sache if (cd->debug) 13312477Sache printf("mcd%d: get_toc reading qchannel info\n",unit); 13322477Sache 1333578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1334578Srgrimes cd->toc[trk].idx_no = 0; 1335578Srgrimes trk = th.ending_track - th.starting_track + 1; 13366612Sache for(retry=0; retry<600 && trk>0; retry++) 1337578Srgrimes { 1338578Srgrimes if (mcd_getqchan(unit, &q) < 0) break; 1339578Srgrimes idx = bcd2bin(q.idx_no); 13402477Sache if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) { 13411197Srgrimes if (cd->toc[idx].idx_no == 0) { 1342578Srgrimes cd->toc[idx] = q; 1343578Srgrimes trk--; 1344578Srgrimes } 13451197Srgrimes } 1346578Srgrimes } 1347578Srgrimes 13482477Sache if (mcd_setmode(unit, MCD_MD_COOKED) != 0) 1349578Srgrimes return EIO; 1350578Srgrimes 13512477Sache if (trk != 0) 13521197Srgrimes return ENXIO; 1353578Srgrimes 1354578Srgrimes /* add a fake last+1 */ 1355578Srgrimes idx = th.ending_track + 1; 1356578Srgrimes cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; 1357578Srgrimes cd->toc[idx].trk_no = 0; 1358578Srgrimes cd->toc[idx].idx_no = 0xAA; 1359578Srgrimes cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; 1360578Srgrimes cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; 1361578Srgrimes cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; 1362578Srgrimes 13632477Sache if (cd->debug) 13642477Sache { int i; 13652477Sache for (i = th.starting_track; i <= idx; i++) 13662477Sache printf("mcd%d: trk %d idx %d pos %d %d %d\n", 13672477Sache unit, i, 13682477Sache cd->toc[i].idx_no, 13692477Sache bcd2bin(cd->toc[i].hd_pos_msf[0]), 13702477Sache bcd2bin(cd->toc[i].hd_pos_msf[1]), 13712477Sache bcd2bin(cd->toc[i].hd_pos_msf[2])); 13722477Sache } 13732477Sache 1374578Srgrimes cd->flags |= MCDTOC; 1375578Srgrimes 1376578Srgrimes return 0; 1377578Srgrimes} 1378578Srgrimes 13791197Srgrimesstatic int 13802477Sachemcd_toc_entrys(int unit, struct ioc_read_toc_entry *te) 1381578Srgrimes{ 1382578Srgrimes struct mcd_data *cd = mcd_data + unit; 13832477Sache struct cd_toc_entry entries[MCD_MAXTOCS]; 1384578Srgrimes struct ioc_toc_header th; 13852477Sache int rc, i, len = te->data_len; 1386578Srgrimes 1387578Srgrimes /* Make sure we have a valid toc */ 13882477Sache if ((rc=mcd_read_toc(unit)) != 0) 1389578Srgrimes return rc; 1390578Srgrimes 1391578Srgrimes /* find the toc to copy*/ 1392578Srgrimes i = te->starting_track; 13932477Sache if (i == MCD_LASTPLUS1) 1394578Srgrimes i = bcd2bin(cd->volinfo.trk_high) + 1; 1395578Srgrimes 1396578Srgrimes /* verify starting track */ 1397578Srgrimes if (i < bcd2bin(cd->volinfo.trk_low) || 13981197Srgrimes i > bcd2bin(cd->volinfo.trk_high)+1) { 1399578Srgrimes return EINVAL; 14001197Srgrimes } 1401578Srgrimes 1402578Srgrimes /* do we have room */ 14032477Sache if ( len > sizeof(entries) 14042477Sache || len < sizeof(struct cd_toc_entry) 14052477Sache || (len % sizeof(struct cd_toc_entry)) != 0 14062477Sache ) 14071197Srgrimes return EINVAL; 1408578Srgrimes 1409578Srgrimes /* Copy the toc header */ 14102477Sache if ((rc = mcd_toc_header(unit, &th)) != 0) 14112477Sache return rc; 1412578Srgrimes 14132477Sache do { 14142477Sache /* copy the toc data */ 14152477Sache entries[i-1].control = cd->toc[i].ctrl_adr; 14162477Sache entries[i-1].addr_type = te->address_format; 14172477Sache entries[i-1].track = i; 14182477Sache if (te->address_format == CD_MSF_FORMAT) { 14192477Sache entries[i-1].addr.msf.unused = 0; 14202477Sache entries[i-1].addr.msf.minute = bcd2bin(cd->toc[i].hd_pos_msf[0]); 14212477Sache entries[i-1].addr.msf.second = bcd2bin(cd->toc[i].hd_pos_msf[1]); 14222477Sache entries[i-1].addr.msf.frame = bcd2bin(cd->toc[i].hd_pos_msf[2]); 14232477Sache } 14242477Sache len -= sizeof(struct cd_toc_entry); 14252477Sache i++; 1426578Srgrimes } 14272477Sache while (len > 0 && i <= th.ending_track + 2); 1428578Srgrimes 1429578Srgrimes /* copy the data back */ 14302477Sache if (copyout(entries, te->data, (i - 1) * sizeof(struct cd_toc_entry)) != 0) 14312477Sache return EFAULT; 1432578Srgrimes 1433578Srgrimes return 0; 1434578Srgrimes} 1435578Srgrimes 14361197Srgrimesstatic int 14371197Srgrimesmcd_stop(int unit) 1438578Srgrimes{ 1439578Srgrimes struct mcd_data *cd = mcd_data + unit; 1440578Srgrimes 14416604Sache /* Verify current status */ 14426604Sache if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS && 14436604Sache cd->audio_status != CD_AS_PLAY_PAUSED) { 14446604Sache if (cd->debug) 14456604Sache printf("mcd%d: stop attempted when not playing\n", unit); 14466604Sache return EINVAL; 14476604Sache } 14486604Sache if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) 14496604Sache if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 14506604Sache return EIO; 1451578Srgrimes cd->audio_status = CD_AS_PLAY_COMPLETED; 1452578Srgrimes return 0; 1453578Srgrimes} 1454578Srgrimes 14551197Srgrimesstatic int 14561197Srgrimesmcd_getqchan(int unit, struct mcd_qchninfo *q) 1457578Srgrimes{ 1458578Srgrimes struct mcd_data *cd = mcd_data + unit; 1459578Srgrimes 14602477Sache if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1461578Srgrimes return -1; 14622477Sache if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1463578Srgrimes return -1; 14641197Srgrimes if (cd->debug) { 14656665Sache printf("mcd%d: getqchan ctrl_adr=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n", 1466578Srgrimes unit, 14672477Sache q->ctrl_adr, bcd2bin(q->trk_no), bcd2bin(q->idx_no), 14684390Sache bcd2bin(q->trk_size_msf[0]), bcd2bin(q->trk_size_msf[1]), 14694390Sache bcd2bin(q->trk_size_msf[2]), 14702477Sache bcd2bin(q->hd_pos_msf[0]), bcd2bin(q->hd_pos_msf[1]), 14712477Sache bcd2bin(q->hd_pos_msf[2])); 14721197Srgrimes } 1473578Srgrimes return 0; 1474578Srgrimes} 1475578Srgrimes 14761197Srgrimesstatic int 14771197Srgrimesmcd_subchan(int unit, struct ioc_read_subchannel *sc) 1478578Srgrimes{ 1479578Srgrimes struct mcd_data *cd = mcd_data + unit; 1480578Srgrimes struct mcd_qchninfo q; 1481578Srgrimes struct cd_sub_channel_info data; 1482578Srgrimes 14832477Sache if (cd->debug) 14842477Sache printf("mcd%d: subchan af=%d, df=%d\n", unit, 14852477Sache sc->address_format, 14862477Sache sc->data_format); 14872477Sache 14886665Sache if (sc->address_format != CD_MSF_FORMAT && 14896665Sache sc->address_format != CD_LBA_FORMAT) 14902477Sache return EINVAL; 14912477Sache 14922477Sache if (sc->data_format != CD_CURRENT_POSITION) 14932477Sache return EINVAL; 14942477Sache 14952477Sache if (mcd_setmode(unit, MCD_MD_COOKED) != 0) 14961197Srgrimes return EIO; 14972477Sache 14982477Sache if (mcd_getqchan(unit, &q) < 0) 14991197Srgrimes return EIO; 1500578Srgrimes 1501578Srgrimes data.header.audio_status = cd->audio_status; 15026665Sache data.what.position.data_format = CD_CURRENT_POSITION; 15036665Sache data.what.position.addr_type = q.ctrl_adr; 15046665Sache data.what.position.control = q.ctrl_adr >> 4; 1505578Srgrimes data.what.position.track_number = bcd2bin(q.trk_no); 15066665Sache data.what.position.index_number = bcd2bin(q.idx_no); 15076665Sache if (sc->address_format == CD_MSF_FORMAT) { 15086665Sache data.what.position.reladdr.msf.unused = 0; 15096665Sache data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]); 15106665Sache data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]); 15116665Sache data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]); 15126665Sache data.what.position.absaddr.msf.unused = 0; 15136665Sache data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]); 15146665Sache data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]); 15156665Sache data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]); 15166665Sache } else if (sc->address_format == CD_LBA_FORMAT) { 15176665Sache data.what.position.reladdr.lba = msf2hsg(q.trk_size_msf); 15186665Sache data.what.position.absaddr.lba = msf2hsg(q.hd_pos_msf); 15196665Sache } 1520578Srgrimes 15214390Sache if (copyout(&data, sc->data, min(sizeof(struct cd_sub_channel_info), sc->data_len))!=0) 1522578Srgrimes return EFAULT; 1523578Srgrimes return 0; 1524578Srgrimes} 1525578Srgrimes 15261197Srgrimesstatic int 15272477Sachemcd_playmsf(int unit, struct ioc_play_msf *pt) 15282477Sache{ 15292477Sache struct mcd_read2 pb; 15302477Sache 15312477Sache if (mcd_setmode(unit, MCD_MD_COOKED) != 0) 15322477Sache return EIO; 15332477Sache 15342477Sache pb.start_msf[0] = bin2bcd(pt->start_m); 15352477Sache pb.start_msf[1] = bin2bcd(pt->start_s); 15362477Sache pb.start_msf[2] = bin2bcd(pt->start_f); 15372477Sache pb.end_msf[0] = bin2bcd(pt->end_m); 15382477Sache pb.end_msf[1] = bin2bcd(pt->end_s); 15392477Sache pb.end_msf[2] = bin2bcd(pt->end_f); 15402477Sache 15412477Sache return mcd_play(unit, &pb); 15422477Sache} 15432477Sache 15442477Sachestatic int 15451197Srgrimesmcd_playtracks(int unit, struct ioc_play_track *pt) 1546578Srgrimes{ 1547578Srgrimes struct mcd_data *cd = mcd_data + unit; 1548578Srgrimes struct mcd_read2 pb; 1549578Srgrimes int a = pt->start_track; 1550578Srgrimes int z = pt->end_track; 15514390Sache int rc, i; 1552578Srgrimes 15532477Sache if ((rc = mcd_read_toc(unit)) != 0) 15541197Srgrimes return rc; 1555578Srgrimes 15562477Sache if (cd->debug) 15572477Sache printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, 15582477Sache a, pt->start_index, z, pt->end_index); 15592477Sache 15602477Sache if ( a < bcd2bin(cd->volinfo.trk_low) 15612477Sache || a > bcd2bin(cd->volinfo.trk_high) 15622477Sache || a > z 15632477Sache || z < bcd2bin(cd->volinfo.trk_low) 15642477Sache || z > bcd2bin(cd->volinfo.trk_high)) 1565578Srgrimes return EINVAL; 1566578Srgrimes 15674390Sache for (i = 0; i < 3; i++) { 15684390Sache pb.start_msf[i] = cd->toc[a].hd_pos_msf[i]; 15694390Sache pb.end_msf[i] = cd->toc[z+1].hd_pos_msf[i]; 15704390Sache } 1571578Srgrimes 1572578Srgrimes return mcd_play(unit, &pb); 1573578Srgrimes} 1574578Srgrimes 15751197Srgrimesstatic int 15761197Srgrimesmcd_play(int unit, struct mcd_read2 *pb) 1577578Srgrimes{ 1578578Srgrimes struct mcd_data *cd = mcd_data + unit; 15792477Sache int com_port = cd->iobase + mcd_command; 15802477Sache int retry, st = -1, status; 1581578Srgrimes 1582578Srgrimes cd->lastpb = *pb; 15831197Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) { 15842477Sache 15852477Sache disable_intr(); 15866028Sache outb(com_port, MCD_CMDSINGLESPEEDREAD); 15872477Sache outb(com_port, pb->start_msf[0]); 15882477Sache outb(com_port, pb->start_msf[1]); 15892477Sache outb(com_port, pb->start_msf[2]); 15902477Sache outb(com_port, pb->end_msf[0]); 15912477Sache outb(com_port, pb->end_msf[1]); 15922477Sache outb(com_port, pb->end_msf[2]); 15932477Sache enable_intr(); 15942477Sache 15952477Sache status=mcd_getstat(unit, 0); 15962477Sache if (status == -1) 15972477Sache continue; 15982477Sache else if (status != -2) 15992477Sache st = 0; 16002477Sache break; 1601578Srgrimes } 1602578Srgrimes 16032477Sache if (status == -2) { 16042477Sache printf("mcd%d: media changed\n", unit); 16052477Sache return ENXIO; 16061197Srgrimes } 16072477Sache if (cd->debug) 16082477Sache printf("mcd%d: mcd_play retry=%d, status=0x%02x\n", unit, retry, status); 16092477Sache if (st < 0) 16101197Srgrimes return ENXIO; 1611578Srgrimes cd->audio_status = CD_AS_PLAY_IN_PROGRESS; 1612578Srgrimes return 0; 1613578Srgrimes} 1614578Srgrimes 16151197Srgrimesstatic int 16161197Srgrimesmcd_pause(int unit) 1617578Srgrimes{ 1618578Srgrimes struct mcd_data *cd = mcd_data + unit; 1619578Srgrimes struct mcd_qchninfo q; 1620578Srgrimes int rc; 1621578Srgrimes 1622578Srgrimes /* Verify current status */ 16231197Srgrimes if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { 16242477Sache if (cd->debug) 16252477Sache printf("mcd%d: pause attempted when not playing\n", unit); 1626578Srgrimes return EINVAL; 1627578Srgrimes } 1628578Srgrimes 1629578Srgrimes /* Get the current position */ 16302477Sache if (mcd_getqchan(unit, &q) < 0) 16311197Srgrimes return EIO; 1632578Srgrimes 1633578Srgrimes /* Copy it into lastpb */ 1634578Srgrimes cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; 1635578Srgrimes cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; 1636578Srgrimes cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; 1637578Srgrimes 1638578Srgrimes /* Stop playing */ 16392477Sache if ((rc=mcd_stop(unit)) != 0) 16401197Srgrimes return rc; 1641578Srgrimes 1642578Srgrimes /* Set the proper status and exit */ 1643578Srgrimes cd->audio_status = CD_AS_PLAY_PAUSED; 1644578Srgrimes return 0; 1645578Srgrimes} 1646578Srgrimes 16471197Srgrimesstatic int 16481197Srgrimesmcd_resume(int unit) 1649578Srgrimes{ 1650578Srgrimes struct mcd_data *cd = mcd_data + unit; 1651578Srgrimes 16522477Sache if (cd->audio_status != CD_AS_PLAY_PAUSED) 16531197Srgrimes return EINVAL; 1654578Srgrimes return mcd_play(unit, &cd->lastpb); 1655578Srgrimes} 1656578Srgrimes#endif /* NMCD > 0 */ 1657