1139749Simp/*- 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 * 43578Srgrimes */ 44119418Sobrien 45119418Sobrien#include <sys/cdefs.h> 46119418Sobrien__FBSDID("$FreeBSD$"); 47260276Sdimstatic const char __used COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; 48578Srgrimes 492056Swollman#include <sys/param.h> 502056Swollman#include <sys/systm.h> 5161011Speter#include <sys/kernel.h> 522056Swollman#include <sys/conf.h> 5324131Sbde#include <sys/fcntl.h> 5460041Sphk#include <sys/bio.h> 552056Swollman#include <sys/cdio.h> 56104545Smdodd#include <sys/disk.h> 5761011Speter#include <sys/bus.h> 583816Swollman 59104445Smdodd#include <machine/bus.h> 60104445Smdodd#include <machine/resource.h> 61104445Smdodd#include <sys/rman.h> 627430Sbde 63104445Smdodd#include <isa/isavar.h> 64104445Smdodd 65104445Smdodd#include <dev/mcd/mcdreg.h> 66104445Smdodd#include <dev/mcd/mcdvar.h> 67578Srgrimes 68115477Sphk#define MCD_TRACE(format, args...) \ 698375Srgrimes{ \ 70104445Smdodd if (sc->debug) { \ 71104445Smdodd device_printf(sc->dev, "status=0x%02x: ", \ 72104445Smdodd sc->data.status); \ 738375Srgrimes printf(format, ## args); \ 748375Srgrimes } \ 758375Srgrimes} 76578Srgrimes 772395Sache#define RAW_PART 2 78578Srgrimes 79578Srgrimes/* flags */ 8014654Sache#define MCDVALID 0x0001 /* parameters loaded */ 8114654Sache#define MCDINIT 0x0002 /* device is init'd */ 8214654Sache#define MCDNEWMODEL 0x0004 /* device is new model */ 8314654Sache#define MCDLABEL 0x0008 /* label is read */ 8414654Sache#define MCDPROBING 0x0010 /* probing */ 8514654Sache#define MCDREADRAW 0x0020 /* read raw mode (2352 bytes) */ 8614654Sache#define MCDVOLINFO 0x0040 /* already read volinfo */ 8714654Sache#define MCDTOC 0x0080 /* already read toc */ 8814654Sache#define MCDMBXBSY 0x0100 /* local mbx is busy */ 89578Srgrimes 90578Srgrimes/* status */ 91578Srgrimes#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ 92578Srgrimes#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ 93578Srgrimes#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ 94578Srgrimes#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ 95578Srgrimes 961241Sjkh/* These are apparently the different states a mitsumi can get up to */ 971241Sjkh#define MCDCDABSENT 0x0030 981241Sjkh#define MCDCDPRESENT 0x0020 991241Sjkh#define MCDSCLOSED 0x0080 1001241Sjkh#define MCDSOPEN 0x00a0 1011237Sjkh 1022477Sache#define MCD_MD_UNKNOWN (-1) 1032477Sache 1044480Sache#define MCD_TYPE_UNKNOWN 0 1054480Sache#define MCD_TYPE_LU002S 1 1064480Sache#define MCD_TYPE_LU005S 2 10713874Sache#define MCD_TYPE_LU006S 3 10813874Sache#define MCD_TYPE_FX001 4 10913874Sache#define MCD_TYPE_FX001D 5 1104480Sache 111578Srgrimes/* reader state machine */ 112578Srgrimes#define MCD_S_BEGIN 0 113578Srgrimes#define MCD_S_BEGIN1 1 114578Srgrimes#define MCD_S_WAITSTAT 2 115578Srgrimes#define MCD_S_WAITMODE 3 116578Srgrimes#define MCD_S_WAITREAD 4 117578Srgrimes 118578Srgrimes/* prototypes */ 119104445Smdoddstatic void mcd_start(struct mcd_softc *); 12011872Sphk#ifdef NOTYET 121104445Smdoddstatic void mcd_configure(struct mcd_softc *sc); 12211872Sphk#endif 123104445Smdoddstatic int mcd_get(struct mcd_softc *, char *buf, int nmax); 124104445Smdoddstatic int mcd_setflags(struct mcd_softc *); 125104445Smdoddstatic int mcd_getstat(struct mcd_softc *,int sflg); 126104445Smdoddstatic int mcd_send(struct mcd_softc *, int cmd,int nretrys); 127104445Smdoddstatic void hsg2msf(int hsg, bcd_t *msf); 128104445Smdoddstatic int msf2hsg(bcd_t *msf, int relative); 129104445Smdoddstatic int mcd_volinfo(struct mcd_softc *); 130104445Smdoddstatic int mcd_waitrdy(struct mcd_softc *,int dly); 131104445Smdoddstatic timeout_t mcd_timeout; 132104445Smdoddstatic void mcd_doread(struct mcd_softc *, int state, struct mcd_mbx *mbxin); 133104445Smdoddstatic void mcd_soft_reset(struct mcd_softc *); 134104445Smdoddstatic int mcd_hard_reset(struct mcd_softc *); 135104445Smdoddstatic int mcd_setmode(struct mcd_softc *, int mode); 136104445Smdoddstatic int mcd_getqchan(struct mcd_softc *, struct mcd_qchninfo *q); 137141031Ssobomaxstatic int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc, 138141031Ssobomax int nocopyout); 139104445Smdoddstatic int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *th); 140104445Smdoddstatic int mcd_read_toc(struct mcd_softc *); 141104445Smdoddstatic int mcd_toc_entrys(struct mcd_softc *, struct ioc_read_toc_entry *te); 14231016Sphk#if 0 143104445Smdoddstatic int mcd_toc_entry(struct mcd_softc *, struct ioc_read_toc_single_entry *te); 14431016Sphk#endif 145104445Smdoddstatic int mcd_stop(struct mcd_softc *); 146104445Smdoddstatic int mcd_eject(struct mcd_softc *); 147104445Smdoddstatic int mcd_inject(struct mcd_softc *); 148104445Smdoddstatic int mcd_playtracks(struct mcd_softc *, struct ioc_play_track *pt); 149104445Smdoddstatic int mcd_play(struct mcd_softc *, struct mcd_read2 *pb); 150104445Smdoddstatic int mcd_playmsf(struct mcd_softc *, struct ioc_play_msf *pt); 151104445Smdoddstatic int mcd_playblocks(struct mcd_softc *, struct ioc_play_blocks *); 152104445Smdoddstatic int mcd_pause(struct mcd_softc *); 153104445Smdoddstatic int mcd_resume(struct mcd_softc *); 154104445Smdoddstatic int mcd_lock_door(struct mcd_softc *, int lock); 155104445Smdoddstatic int mcd_close_tray(struct mcd_softc *); 156130585Sphkstatic int mcd_size(struct cdev *dev); 157578Srgrimes 158104445Smdoddstatic d_open_t mcdopen; 159104445Smdoddstatic d_close_t mcdclose; 160104445Smdoddstatic d_ioctl_t mcdioctl; 161104445Smdoddstatic d_strategy_t mcdstrategy; 162578Srgrimes 16337389Sjulianstatic struct cdevsw mcd_cdevsw = { 164126080Sphk .d_version = D_VERSION, 165111815Sphk .d_open = mcdopen, 166111815Sphk .d_close = mcdclose, 167111815Sphk .d_read = physread, 168111815Sphk .d_ioctl = mcdioctl, 169111815Sphk .d_strategy = mcdstrategy, 170111815Sphk .d_name = "mcd", 171126080Sphk .d_flags = D_DISK | D_NEEDGIANT, 17247625Sphk}; 17337389Sjulian 174578Srgrimes#define MCD_RETRYS 5 175578Srgrimes#define MCD_RDRETRYS 8 176578Srgrimes 1776604Sache#define CLOSE_TRAY_SECS 8 1786604Sache#define DISK_SENSE_SECS 3 1796604Sache#define WAIT_FRAC 4 1806604Sache 181578Srgrimes/* several delays */ 1822477Sache#define RDELAY_WAITSTAT 300 1832477Sache#define RDELAY_WAITMODE 300 184578Srgrimes#define RDELAY_WAITREAD 800 185578Srgrimes 1862477Sache#define MIN_DELAY 15 18710069Sjoerg#define DELAY_GETREPLY 5000000 188578Srgrimes 189104445Smdoddint 190104445Smdoddmcd_attach(struct mcd_softc *sc) 191578Srgrimes{ 192104445Smdodd int unit; 1938876Srgrimes 194104445Smdodd unit = device_get_unit(sc->dev); 195104445Smdodd 196106490Smdodd sc->data.flags |= MCDINIT; 197104445Smdodd mcd_soft_reset(sc); 198106490Smdodd bioq_init(&sc->data.head); 199578Srgrimes 200578Srgrimes#ifdef NOTYET 201578Srgrimes /* wire controller for interrupts and dma */ 202104445Smdodd mcd_configure(sc); 203578Srgrimes#endif 2044480Sache /* name filled in probe */ 205104545Smdodd sc->mcd_dev_t = make_dev(&mcd_cdevsw, 8 * unit, 206104445Smdodd UID_ROOT, GID_OPERATOR, 0640, "mcd%d", unit); 207104445Smdodd 208104545Smdodd sc->mcd_dev_t->si_drv1 = (void *)sc; 209104445Smdodd 210106490Smdodd return (0); 211578Srgrimes} 212578Srgrimes 213104441Smdoddstatic int 214130585Sphkmcdopen(struct cdev *dev, int flags, int fmt, struct thread *td) 215578Srgrimes{ 216104445Smdodd struct mcd_softc *sc; 217104545Smdodd int r,retry; 2188876Srgrimes 219104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 2208876Srgrimes 221578Srgrimes /* not initialized*/ 222106490Smdodd if (!(sc->data.flags & MCDINIT)) 223106490Smdodd return (ENXIO); 224578Srgrimes 225578Srgrimes /* invalidated in the meantime? mark all open part's invalid */ 226106490Smdodd if (!(sc->data.flags & MCDVALID) && sc->data.openflags) 227106490Smdodd return (ENXIO); 228578Srgrimes 229104445Smdodd if (mcd_getstat(sc, 1) == -1) 230106490Smdodd return (EIO); 231578Srgrimes 232106490Smdodd if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 233106490Smdodd || !(sc->data.status & MCDDSKIN)) 2346604Sache for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 235106490Smdodd (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn1", hz/WAIT_FRAC); 236104445Smdodd if ((r = mcd_getstat(sc, 1)) == -1) 237106490Smdodd return (EIO); 2386604Sache if (r != -2) 2396604Sache break; 2406604Sache } 2416604Sache 242106490Smdodd if (sc->data.status & MCDDOOROPEN) { 243104445Smdodd device_printf(sc->dev, "door is open\n"); 244106490Smdodd return (ENXIO); 2452477Sache } 246106490Smdodd if (!(sc->data.status & MCDDSKIN)) { 247104445Smdodd device_printf(sc->dev, "no CD inside\n"); 248106490Smdodd return (ENXIO); 2492477Sache } 250106490Smdodd if (sc->data.status & MCDDSKCHNG) { 251104445Smdodd device_printf(sc->dev, "CD not sensed\n"); 252106490Smdodd return (ENXIO); 2536604Sache } 254578Srgrimes 255111731Sphk if (mcd_size(dev) < 0) { 256104445Smdodd device_printf(sc->dev, "failed to get disk size\n"); 257106490Smdodd return (ENXIO); 258104545Smdodd } 259578Srgrimes 260106490Smdodd sc->data.openflags = 1; 261106490Smdodd sc->data.partflags |= MCDREADRAW; 262106490Smdodd sc->data.flags |= MCDVALID; 263578Srgrimes 264104545Smdodd (void) mcd_lock_door(sc, MCD_LK_LOCK); 265106490Smdodd if (!(sc->data.flags & MCDVALID)) 266106490Smdodd return (ENXIO); 26751111Sjulian 268106490Smdodd return mcd_read_toc(sc); 269578Srgrimes} 270578Srgrimes 271104441Smdoddstatic int 272130585Sphkmcdclose(struct cdev *dev, int flags, int fmt, struct thread *td) 273578Srgrimes{ 274104445Smdodd struct mcd_softc *sc; 2758876Srgrimes 276104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 2778876Srgrimes 278106490Smdodd if (!(sc->data.flags & MCDINIT) || !sc->data.openflags) 279106490Smdodd return (ENXIO); 280578Srgrimes 281104445Smdodd (void) mcd_lock_door(sc, MCD_LK_UNLOCK); 282106490Smdodd sc->data.openflags = 0; 283106490Smdodd sc->data.partflags &= ~MCDREADRAW; 284578Srgrimes 285106490Smdodd return (0); 286578Srgrimes} 287578Srgrimes 288104441Smdoddstatic void 28959249Sphkmcdstrategy(struct bio *bp) 290578Srgrimes{ 291104445Smdodd struct mcd_softc *sc; 292578Srgrimes int s; 2938876Srgrimes 294104445Smdodd sc = (struct mcd_softc *)bp->bio_dev->si_drv1; 295578Srgrimes 296578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 297106490Smdodd if (!(sc->data.flags & MCDVALID)) { 298104545Smdodd device_printf(sc->dev, "media changed\n"); 29959249Sphk bp->bio_error = EIO; 300578Srgrimes goto bad; 301578Srgrimes } 302578Srgrimes 303578Srgrimes /* read only */ 30459249Sphk if (!(bp->bio_cmd == BIO_READ)) { 30559249Sphk bp->bio_error = EROFS; 306578Srgrimes goto bad; 307578Srgrimes } 3088876Srgrimes 309578Srgrimes /* no data to read */ 31059249Sphk if (bp->bio_bcount == 0) 311578Srgrimes goto done; 3128876Srgrimes 313106490Smdodd if (!(sc->data.flags & MCDTOC)) { 314104545Smdodd bp->bio_error = EIO; 315104545Smdodd goto bad; 316578Srgrimes } 3178876Srgrimes 318104545Smdodd bp->bio_resid = 0; 319104545Smdodd 320578Srgrimes /* queue it */ 321578Srgrimes s = splbio(); 322112946Sphk bioq_disksort(&sc->data.head, bp); 323578Srgrimes splx(s); 3248876Srgrimes 325578Srgrimes /* now check whether we can perform processing */ 326104445Smdodd mcd_start(sc); 327578Srgrimes return; 328578Srgrimes 329578Srgrimesbad: 33059249Sphk bp->bio_flags |= BIO_ERROR; 331578Srgrimesdone: 33259249Sphk bp->bio_resid = bp->bio_bcount; 333578Srgrimes biodone(bp); 334578Srgrimes return; 335578Srgrimes} 336578Srgrimes 337104441Smdoddstatic void 338104445Smdoddmcd_start(struct mcd_softc *sc) 339578Srgrimes{ 34059249Sphk struct bio *bp; 34146573Speter int s = splbio(); 3428876Srgrimes 343106490Smdodd if (sc->data.flags & MCDMBXBSY) { 3442477Sache splx(s); 345578Srgrimes return; 3462477Sache } 347578Srgrimes 348137045Sphk bp = bioq_takefirst(&sc->data.head); 34915574Sphk if (bp != 0) { 350578Srgrimes /* block found to process, dequeue */ 351578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 352106490Smdodd sc->data.flags |= MCDMBXBSY; 353578Srgrimes splx(s); 354578Srgrimes } else { 355578Srgrimes /* nothing to do */ 356578Srgrimes splx(s); 357578Srgrimes return; 358578Srgrimes } 359578Srgrimes 360106490Smdodd sc->data.mbx.retry = MCD_RETRYS; 361106490Smdodd sc->data.mbx.bp = bp; 362578Srgrimes 363106490Smdodd mcd_doread(sc, MCD_S_BEGIN,&(sc->data.mbx)); 364578Srgrimes return; 365578Srgrimes} 366578Srgrimes 367104441Smdoddstatic int 368130585Sphkmcdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 369578Srgrimes{ 370104445Smdodd struct mcd_softc *sc; 371104545Smdodd int retry,r; 3728876Srgrimes 373104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 374578Srgrimes 375104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 376106490Smdodd return (EIO); 37737618SbdeMCD_TRACE("ioctl called 0x%lx\n", cmd); 378578Srgrimes 379578Srgrimes switch (cmd) { 38014285Sache case CDIOCSETPATCH: 38114285Sache case CDIOCGETVOL: 38214285Sache case CDIOCSETVOL: 38314285Sache case CDIOCSETMONO: 38414285Sache case CDIOCSETSTERIO: 38514285Sache case CDIOCSETMUTE: 38614285Sache case CDIOCSETLEFT: 38714285Sache case CDIOCSETRIGHT: 388106490Smdodd return (EINVAL); 38914285Sache case CDIOCEJECT: 390104445Smdodd return mcd_eject(sc); 39114285Sache case CDIOCSETDEBUG: 392106490Smdodd sc->data.debug = 1; 393106490Smdodd return (0); 39414285Sache case CDIOCCLRDEBUG: 395106490Smdodd sc->data.debug = 0; 396106490Smdodd return (0); 39714285Sache case CDIOCRESET: 398104445Smdodd return mcd_hard_reset(sc); 39914285Sache case CDIOCALLOW: 400104445Smdodd return mcd_lock_door(sc, MCD_LK_UNLOCK); 40114285Sache case CDIOCPREVENT: 402104445Smdodd return mcd_lock_door(sc, MCD_LK_LOCK); 40314285Sache case CDIOCCLOSE: 404104445Smdodd return mcd_inject(sc); 40514285Sache } 40614285Sache 407106490Smdodd if (!(sc->data.flags & MCDVALID)) { 408106490Smdodd if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 409106490Smdodd || !(sc->data.status & MCDDSKIN)) 41014285Sache for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 411106490Smdodd (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC); 412104445Smdodd if ((r = mcd_getstat(sc, 1)) == -1) 413106490Smdodd return (EIO); 41414285Sache if (r != -2) 41514285Sache break; 41614285Sache } 417106490Smdodd if ( (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG)) 418106490Smdodd || !(sc->data.status & MCDDSKIN) 419111731Sphk || mcd_size(dev) < 0 42014285Sache ) 421106490Smdodd return (ENXIO); 422106490Smdodd sc->data.flags |= MCDVALID; 423106490Smdodd sc->data.partflags |= MCDREADRAW; 424104445Smdodd (void) mcd_lock_door(sc, MCD_LK_LOCK); 425106490Smdodd if (!(sc->data.flags & MCDVALID)) 426106490Smdodd return (ENXIO); 42714285Sache } 42814285Sache 42914285Sache switch (cmd) { 430104545Smdodd case DIOCGMEDIASIZE: 431106490Smdodd *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; 432104545Smdodd return (0); 433104545Smdodd case DIOCGSECTORSIZE: 434106490Smdodd *(u_int *)addr = sc->data.blksize; 435104545Smdodd return (0); 436104545Smdodd 437578Srgrimes case CDIOCPLAYTRACKS: 438104445Smdodd return mcd_playtracks(sc, (struct ioc_play_track *) addr); 439578Srgrimes case CDIOCPLAYBLOCKS: 440104445Smdodd return mcd_playblocks(sc, (struct ioc_play_blocks *) addr); 4412477Sache case CDIOCPLAYMSF: 442104445Smdodd return mcd_playmsf(sc, (struct ioc_play_msf *) addr); 443141031Ssobomax case CDIOCREADSUBCHANNEL_SYSSPACE: 444141031Ssobomax return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); 445578Srgrimes case CDIOCREADSUBCHANNEL: 446141031Ssobomax return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); 447578Srgrimes case CDIOREADTOCHEADER: 448104445Smdodd return mcd_toc_header(sc, (struct ioc_toc_header *) addr); 449578Srgrimes case CDIOREADTOCENTRYS: 450104445Smdodd return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr); 451578Srgrimes case CDIOCRESUME: 452104445Smdodd return mcd_resume(sc); 453578Srgrimes case CDIOCPAUSE: 454104445Smdodd return mcd_pause(sc); 455578Srgrimes case CDIOCSTART: 456104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 457106490Smdodd return (EIO); 458106490Smdodd return (0); 459578Srgrimes case CDIOCSTOP: 460104445Smdodd return mcd_stop(sc); 461578Srgrimes default: 462106490Smdodd return (ENOTTY); 463578Srgrimes } 464578Srgrimes /*NOTREACHED*/ 465578Srgrimes} 466578Srgrimes 467104441Smdoddstatic int 468130585Sphkmcd_size(struct cdev *dev) 469578Srgrimes{ 470104445Smdodd struct mcd_softc *sc; 471578Srgrimes int size; 472578Srgrimes 473104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 474104445Smdodd 475104445Smdodd if (mcd_volinfo(sc) == 0) { 476106490Smdodd sc->data.blksize = MCDBLK; 477106490Smdodd size = msf2hsg(sc->data.volinfo.vol_msf, 0); 478106490Smdodd sc->data.disksize = size * (MCDBLK/DEV_BSIZE); 479106490Smdodd return (0); 480578Srgrimes } 481106490Smdodd return (-1); 482578Srgrimes} 483578Srgrimes 484578Srgrimes/*************************************************************** 485578Srgrimes * lower level of driver starts here 486578Srgrimes **************************************************************/ 487578Srgrimes 488578Srgrimes#ifdef NOTDEF 4891197Srgrimesstatic char 4901197Srgrimesirqs[] = { 491578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 492578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 493578Srgrimes}; 494578Srgrimes 4951197Srgrimesstatic char 4961197Srgrimesdrqs[] = { 497578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 498578Srgrimes}; 499578Srgrimes#endif 500578Srgrimes 50111872Sphk#ifdef NOT_YET 5021197Srgrimesstatic void 503104445Smdoddmcd_configure(struct mcd_softc *sc) 504578Srgrimes{ 505104445Smdodd MCD_WRITE(sc, MCD_REG_CONFIG, sc->data.config); 506578Srgrimes} 50711872Sphk#endif 508578Srgrimes 5091197Srgrimes/* Wait for non-busy - return 0 on timeout */ 5101197Srgrimesstatic int 511104445Smdoddtwiddle_thumbs(struct mcd_softc *sc, int count, char *whine) 5121197Srgrimes{ 5131197Srgrimes int i; 5141197Srgrimes 5151197Srgrimes for (i = 0; i < count; i++) { 516104445Smdodd if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 517106490Smdodd return (1); 5181197Srgrimes } 51913598Sjoerg if (bootverbose) 520104445Smdodd device_printf(sc->dev, "timeout %s\n", whine); 521106490Smdodd return (0); 5221197Srgrimes} 5231197Srgrimes 524978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 525578Srgrimes 526104445Smdoddint 527104445Smdoddmcd_probe(struct mcd_softc *sc) 528578Srgrimes{ 5291197Srgrimes int i, j; 5301197Srgrimes unsigned char stbytes[3]; 531578Srgrimes 532104445Smdodd sc->data.flags = MCDPROBING; 533578Srgrimes 534578Srgrimes#ifdef NOTDEF 535578Srgrimes /* get irq/drq configuration word */ 536104445Smdodd sc->data.config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 537578Srgrimes#else 538104445Smdodd sc->data.config = 0; 539578Srgrimes#endif 540578Srgrimes 541578Srgrimes /* send a reset */ 542104445Smdodd MCD_WRITE(sc, MCD_FLAGS, M_RESET); 543578Srgrimes 5441197Srgrimes /* 5451197Srgrimes * delay awhile by getting any pending garbage (old data) and 5461197Srgrimes * throwing it away. 5471197Srgrimes */ 5482477Sache for (i = 1000000; i != 0; i--) 549104445Smdodd (void)MCD_READ(sc, MCD_FLAGS); 550578Srgrimes 5511197Srgrimes /* Get status */ 552104445Smdodd MCD_WRITE(sc, MCD_DATA, MCD_CMDGETSTAT); 553104445Smdodd if (!twiddle_thumbs(sc, 1000000, "getting status")) 554104445Smdodd return (ENXIO); /* Timeout */ 5551197Srgrimes /* Get version information */ 556104445Smdodd MCD_WRITE(sc, MCD_DATA, MCD_CMDCONTINFO); 5571197Srgrimes for (j = 0; j < 3; j++) { 558104445Smdodd if (!twiddle_thumbs(sc, 3000, "getting version info")) 559104445Smdodd return (ENXIO); 560104445Smdodd stbytes[j] = (MCD_READ(sc, MCD_DATA) & 0xFF); 5611197Srgrimes } 5625178Sache if (stbytes[1] == stbytes[2]) 563104445Smdodd return (ENXIO); 5645226Sache if (stbytes[2] >= 4 || stbytes[1] != 'M') { 565104445Smdodd MCD_WRITE(sc, MCD_CTRL, M_PICKLE); 566104445Smdodd sc->data.flags |= MCDNEWMODEL; 5671197Srgrimes } 568104445Smdodd sc->data.read_command = MCD_CMDSINGLESPEEDREAD; 5694480Sache switch (stbytes[1]) { 5704480Sache case 'M': 57113874Sache if (stbytes[2] <= 2) { 572104445Smdodd sc->data.type = MCD_TYPE_LU002S; 573104445Smdodd sc->data.name = "Mitsumi LU002S"; 57413874Sache } else if (stbytes[2] <= 5) { 575104445Smdodd sc->data.type = MCD_TYPE_LU005S; 576104445Smdodd sc->data.name = "Mitsumi LU005S"; 5774480Sache } else { 578104445Smdodd sc->data.type = MCD_TYPE_LU006S; 579104445Smdodd sc->data.name = "Mitsumi LU006S"; 5804480Sache } 5814480Sache break; 5824480Sache case 'F': 583104445Smdodd sc->data.type = MCD_TYPE_FX001; 584104445Smdodd sc->data.name = "Mitsumi FX001"; 5854480Sache break; 5864480Sache case 'D': 587104445Smdodd sc->data.type = MCD_TYPE_FX001D; 588104445Smdodd sc->data.name = "Mitsumi FX001D"; 589104445Smdodd sc->data.read_command = MCD_CMDDOUBLESPEEDREAD; 5904480Sache break; 5914480Sache default: 592104445Smdodd sc->data.type = MCD_TYPE_UNKNOWN; 593104445Smdodd sc->data.name = "Mitsumi ???"; 5944480Sache break; 5954480Sache } 5965226Sache 597104445Smdodd if (bootverbose) 598104445Smdodd device_printf(sc->dev, "type %s, version info: %c %x\n", 599104445Smdodd sc->data.name, stbytes[1], stbytes[2]); 600104445Smdodd 601106490Smdodd return (0); 602578Srgrimes} 603578Srgrimes 604978Sjkh 6051197Srgrimesstatic int 606104445Smdoddmcd_waitrdy(struct mcd_softc *sc, int dly) 607578Srgrimes{ 608578Srgrimes int i; 609578Srgrimes 6105226Sache /* wait until flag port senses status ready */ 6112477Sache for (i=0; i<dly; i+=MIN_DELAY) { 612104445Smdodd if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 613106490Smdodd return (0); 6142477Sache DELAY(MIN_DELAY); 615578Srgrimes } 616106490Smdodd return (-1); 617578Srgrimes} 618578Srgrimes 6191197Srgrimesstatic int 620104445Smdoddmcd_getreply(struct mcd_softc *sc, int dly) 621578Srgrimes{ 622578Srgrimes 623578Srgrimes /* wait data to become ready */ 624104445Smdodd if (mcd_waitrdy(sc, dly)<0) { 625104445Smdodd device_printf(sc->dev, "timeout getreply\n"); 626106490Smdodd return (-1); 627578Srgrimes } 628578Srgrimes 629578Srgrimes /* get the data */ 630106490Smdodd return (MCD_READ(sc, MCD_REG_STATUS) & 0xFF); 631578Srgrimes} 632578Srgrimes 6331197Srgrimesstatic int 634104445Smdoddmcd_getstat(struct mcd_softc *sc, int sflg) 635578Srgrimes{ 636578Srgrimes int i; 637578Srgrimes 638578Srgrimes /* get the status */ 639578Srgrimes if (sflg) 640104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 641104445Smdodd i = mcd_getreply(sc, DELAY_GETREPLY); 6426604Sache if (i<0 || (i & MCD_ST_CMDCHECK)) { 643106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 644106490Smdodd return (-1); 6456604Sache } 646578Srgrimes 647106490Smdodd sc->data.status = i; 648578Srgrimes 649104445Smdodd if (mcd_setflags(sc) < 0) 650106490Smdodd return (-2); 651106490Smdodd return (sc->data.status); 652578Srgrimes} 653578Srgrimes 6542477Sachestatic int 655104445Smdoddmcd_setflags(struct mcd_softc *sc) 656578Srgrimes{ 657104445Smdodd 658578Srgrimes /* check flags */ 659106490Smdodd if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 660106490Smdodd || !(sc->data.status & MCDDSKIN)) { 6618375Srgrimes MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n"); 662104445Smdodd mcd_soft_reset(sc); 663106490Smdodd return (-1); 664578Srgrimes } 665578Srgrimes 666106490Smdodd if (sc->data.status & MCDAUDIOBSY) 667106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 668106490Smdodd else if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 669106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 670106490Smdodd return (0); 671578Srgrimes} 672578Srgrimes 6731197Srgrimesstatic int 674104445Smdoddmcd_get(struct mcd_softc *sc, char *buf, int nmax) 675578Srgrimes{ 676578Srgrimes int i,k; 6778876Srgrimes 678578Srgrimes for (i=0; i<nmax; i++) { 679578Srgrimes /* wait for data */ 680104445Smdodd if ((k = mcd_getreply(sc, DELAY_GETREPLY)) < 0) { 681104445Smdodd device_printf(sc->dev, "timeout mcd_get\n"); 682106490Smdodd return (-1); 683578Srgrimes } 684578Srgrimes buf[i] = k; 685578Srgrimes } 686106490Smdodd return (i); 687578Srgrimes} 688578Srgrimes 6891197Srgrimesstatic int 690104445Smdoddmcd_send(struct mcd_softc *sc, int cmd,int nretrys) 691578Srgrimes{ 6922477Sache int i,k=0; 6938876Srgrimes 6942477Sache/*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/ 695578Srgrimes for (i=0; i<nretrys; i++) { 696104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, cmd); 697104445Smdodd if ((k=mcd_getstat(sc, 0)) != -1) 698578Srgrimes break; 699578Srgrimes } 7002477Sache if (k == -2) { 701104445Smdodd device_printf(sc->dev, "media changed\n"); 702106490Smdodd return (-1); 7032477Sache } 704578Srgrimes if (i == nretrys) { 705104445Smdodd device_printf(sc->dev, "mcd_send retry cnt exceeded\n"); 706106490Smdodd return (-1); 707578Srgrimes } 7082477Sache/*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/ 709106490Smdodd return (0); 710578Srgrimes} 711578Srgrimes 7121197Srgrimesstatic void 7131197Srgrimeshsg2msf(int hsg, bcd_t *msf) 714578Srgrimes{ 715578Srgrimes hsg += 150; 716578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 71713770Sache hsg /= 75; 71813770Sache S_msf(msf) = bin2bcd(hsg % 60); 71913770Sache hsg /= 60; 72013770Sache M_msf(msf) = bin2bcd(hsg); 721578Srgrimes} 722578Srgrimes 7231197Srgrimesstatic int 72413770Sachemsf2hsg(bcd_t *msf, int relative) 725578Srgrimes{ 72613770Sache return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 + 72713770Sache bcd2bin(F_msf(msf)) - (!relative) * 150; 728578Srgrimes} 729578Srgrimes 7301197Srgrimesstatic int 731104445Smdoddmcd_volinfo(struct mcd_softc *sc) 732578Srgrimes{ 733578Srgrimes 734578Srgrimes /* Just return if we already have it */ 735106490Smdodd if (sc->data.flags & MCDVOLINFO) return (0); 736578Srgrimes 7372477Sache/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 7382477Sache 739578Srgrimes /* send volume info command */ 740104445Smdodd if (mcd_send(sc, MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 741106490Smdodd return (EIO); 742578Srgrimes 743578Srgrimes /* get data */ 744106490Smdodd if (mcd_get(sc, (char*) &sc->data.volinfo,sizeof(struct mcd_volinfo)) < 0) { 745104445Smdodd device_printf(sc->dev, "mcd_volinfo: error read data\n"); 746106490Smdodd return (EIO); 747578Srgrimes } 748578Srgrimes 749106490Smdodd if (sc->data.volinfo.trk_low > 0 && 750106490Smdodd sc->data.volinfo.trk_high >= sc->data.volinfo.trk_low 7516604Sache ) { 752106490Smdodd sc->data.flags |= MCDVOLINFO; /* volinfo is OK */ 753106490Smdodd return (0); 754578Srgrimes } 755578Srgrimes 756106490Smdodd return (EINVAL); 757578Srgrimes} 758578Srgrimes 759578Srgrimes/* state machine to process read requests 760578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 761578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 762578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 763578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 764578Srgrimes */ 7651197Srgrimesstatic void 76625056Sbdemcd_timeout(void *arg) 76725056Sbde{ 768104445Smdodd struct mcd_softc *sc; 769104445Smdodd 770104445Smdodd sc = (struct mcd_softc *)arg; 771104445Smdodd 772104445Smdodd mcd_doread(sc, sc->ch_state, sc->ch_mbxsave); 77325056Sbde} 77425056Sbde 77525056Sbdestatic void 776104445Smdoddmcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin) 777578Srgrimes{ 778104445Smdodd struct mcd_mbx *mbx; 779104445Smdodd struct bio *bp; 780104445Smdodd int rm, i, k; 781578Srgrimes struct mcd_read2 rbuf; 782104445Smdodd int blknum; 783578Srgrimes caddr_t addr; 784578Srgrimes 785104445Smdodd mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; 786104445Smdodd bp = mbx->bp; 787104445Smdodd 788578Srgrimesloop: 789578Srgrimes switch (state) { 790578Srgrimes case MCD_S_BEGIN: 791104445Smdodd mbx = sc->ch_mbxsave = mbxin; 792578Srgrimes 793578Srgrimes case MCD_S_BEGIN1: 7946604Sacheretry_status: 795578Srgrimes /* get status */ 796104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 797578Srgrimes mbx->count = RDELAY_WAITSTAT; 798104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 799104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 800578Srgrimes return; 801578Srgrimes case MCD_S_WAITSTAT: 802104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 803104445Smdodd untimeout(mcd_timeout,(caddr_t)sc, sc->ch); 804578Srgrimes if (mbx->count-- >= 0) { 805104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 806104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 807104445Smdodd timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 808578Srgrimes return; 809578Srgrimes } 810106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 811106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) 8126028Sache goto retry_status; 813104445Smdodd if (mcd_setflags(sc) < 0) 8142477Sache goto changed; 8151197Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n", 8168375Srgrimes RDELAY_WAITSTAT-mbx->count); 817578Srgrimes /* reject, if audio active */ 818106490Smdodd if (sc->data.status & MCDAUDIOBSY) { 819104445Smdodd device_printf(sc->dev, "audio is active\n"); 820578Srgrimes goto readerr; 821578Srgrimes } 8226604Sache 8236028Sacheretry_mode: 824578Srgrimes /* to check for raw/cooked mode */ 825106490Smdodd if (sc->data.flags & MCDREADRAW) { 8264389Sache rm = MCD_MD_RAW; 827578Srgrimes mbx->sz = MCDRBLK; 828578Srgrimes } else { 8294389Sache rm = MCD_MD_COOKED; 830106490Smdodd mbx->sz = sc->data.blksize; 831578Srgrimes } 832578Srgrimes 833106490Smdodd if (rm == sc->data.curr_mode) 8342477Sache goto modedone; 8352477Sache 836578Srgrimes mbx->count = RDELAY_WAITMODE; 8372477Sache 838106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 8392477Sache mbx->mode = rm; 840104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 841104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rm); 8422477Sache 843104445Smdodd sc->ch_state = MCD_S_WAITMODE; 844104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 845578Srgrimes return; 846578Srgrimes } else { 847104445Smdodd device_printf(sc->dev, "timeout getstatus\n"); 848578Srgrimes goto readerr; 849578Srgrimes } 850578Srgrimes 851578Srgrimes case MCD_S_WAITMODE: 852104445Smdodd sc->ch_state = MCD_S_WAITMODE; 853104445Smdodd untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 854578Srgrimes if (mbx->count-- < 0) { 855104445Smdodd device_printf(sc->dev, "timeout set mode\n"); 856578Srgrimes goto readerr; 857578Srgrimes } 858104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 859104445Smdodd sc->ch_state = MCD_S_WAITMODE; 860104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); 861578Srgrimes return; 862578Srgrimes } 863106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 864106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) { 865106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 8666028Sache goto retry_mode; 8676028Sache } 868104445Smdodd if (mcd_setflags(sc) < 0) 8692477Sache goto changed; 870106490Smdodd sc->data.curr_mode = mbx->mode; 8711197Srgrimes MCD_TRACE("got WAITMODE delay=%d\n", 8728375Srgrimes RDELAY_WAITMODE-mbx->count); 8732477Sachemodedone: 874578Srgrimes /* for first block */ 87559249Sphk mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; 876578Srgrimes mbx->skip = 0; 877578Srgrimes 878578Srgrimesnextblock: 879121212Sphk blknum = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz; 880578Srgrimes 8818456Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n", 8828375Srgrimes blknum, bp); 883578Srgrimes 884578Srgrimes /* build parameter block */ 885578Srgrimes hsg2msf(blknum,rbuf.start_msf); 8866028Sacheretry_read: 887578Srgrimes /* send the read command */ 888106719Smdodd critical_enter(); 889106490Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command); 890104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]); 891104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]); 892104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]); 893104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 0); 894104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 0); 895104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 1); 896106719Smdodd critical_exit(); 8972477Sache 8982762Sache /* Spin briefly (<= 2ms) to avoid missing next block */ 8992762Sache for (i = 0; i < 20; i++) { 900104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 9015226Sache if (!(k & MFL_DATA_NOT_AVAIL)) 9022762Sache goto got_it; 9032762Sache DELAY(100); 9042762Sache } 9052762Sache 906578Srgrimes mbx->count = RDELAY_WAITREAD; 907104445Smdodd sc->ch_state = MCD_S_WAITREAD; 908104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 909578Srgrimes return; 910578Srgrimes case MCD_S_WAITREAD: 911104445Smdodd sc->ch_state = MCD_S_WAITREAD; 912104445Smdodd untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 913578Srgrimes if (mbx->count-- > 0) { 914104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 9155226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */ 9161197Srgrimes MCD_TRACE("got data delay=%d\n", 9178375Srgrimes RDELAY_WAITREAD-mbx->count); 9182762Sache got_it: 919578Srgrimes /* data is ready */ 92059249Sphk addr = bp->bio_data + mbx->skip; 9212477Sache 922104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2,0x04); /* XXX */ 923578Srgrimes for (i=0; i<mbx->sz; i++) 924104445Smdodd *addr++ = MCD_READ(sc, MCD_REG_RDATA); 925104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2,0x0c); /* XXX */ 926578Srgrimes 927104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 9282477Sache /* If we still have some junk, read it too */ 9295226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { 930104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2, 0x04); /* XXX */ 931104445Smdodd (void)MCD_READ(sc, MCD_REG_RDATA); 932104445Smdodd (void)MCD_READ(sc, MCD_REG_RDATA); 933104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2, 0x0c); /* XXX */ 9342477Sache } 9352477Sache 936578Srgrimes if (--mbx->nblk > 0) { 937578Srgrimes mbx->skip += mbx->sz; 938578Srgrimes goto nextblock; 939578Srgrimes } 940578Srgrimes 941578Srgrimes /* return buffer */ 94259249Sphk bp->bio_resid = 0; 943578Srgrimes biodone(bp); 944578Srgrimes 945106490Smdodd sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 946104445Smdodd mcd_start(sc); 947578Srgrimes return; 948578Srgrimes } 9495226Sache if (!(k & MFL_STATUS_NOT_AVAIL)) { 950106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 951106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) 9526028Sache goto retry_read; 953104445Smdodd if (mcd_setflags(sc) < 0) 9542477Sache goto changed; 9552477Sache } 956104445Smdodd sc->ch_state = MCD_S_WAITREAD; 957104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 958578Srgrimes return; 959578Srgrimes } else { 960104445Smdodd device_printf(sc->dev, "timeout read data\n"); 961578Srgrimes goto readerr; 962578Srgrimes } 963578Srgrimes } 964578Srgrimes 965578Srgrimesreaderr: 966578Srgrimes if (mbx->retry-- > 0) { 967104445Smdodd device_printf(sc->dev, "retrying\n"); 968578Srgrimes state = MCD_S_BEGIN1; 969578Srgrimes goto loop; 970578Srgrimes } 9712477Sacheharderr: 972578Srgrimes /* invalidate the buffer */ 97359249Sphk bp->bio_flags |= BIO_ERROR; 97459249Sphk bp->bio_resid = bp->bio_bcount; 975578Srgrimes biodone(bp); 9762477Sache 977106490Smdodd sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 978104445Smdodd mcd_start(sc); 979578Srgrimes return; 980578Srgrimes 9812477Sachechanged: 982104445Smdodd device_printf(sc->dev, "media changed\n"); 9832477Sache goto harderr; 9842477Sache 985578Srgrimes#ifdef NOTDEF 986104445Smdodd device_printf(sc->dev, "unit timeout, resetting\n"); 987104445Smdodd MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 988578Srgrimes DELAY(300000); 989104445Smdodd (void)mcd_getstat(sc, 1); 990104445Smdodd (void)mcd_getstat(sc, 1); 991106490Smdodd /*sc->data.status &= ~MCDDSKCHNG; */ 992106490Smdodd sc->data.debug = 1; /* preventive set debug mode */ 993578Srgrimes 994578Srgrimes#endif 995578Srgrimes 996578Srgrimes} 997578Srgrimes 9981197Srgrimesstatic int 999104445Smdoddmcd_lock_door(struct mcd_softc *sc, int lock) 10002477Sache{ 10012477Sache 1002104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDLOCKDRV); 1003104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, lock); 1004104445Smdodd if (mcd_getstat(sc, 0) == -1) 1005106490Smdodd return (EIO); 1006106490Smdodd return (0); 10076604Sache} 10086604Sache 10096604Sachestatic int 1010104445Smdoddmcd_close_tray(struct mcd_softc *sc) 10116604Sache{ 10126604Sache int retry, r; 10136604Sache 1014104445Smdodd if (mcd_getstat(sc, 1) == -1) 1015106490Smdodd return (EIO); 1016106490Smdodd if (sc->data.status & MCDDOOROPEN) { 1017104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDCLOSETRAY); 10186604Sache for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) { 1019104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) 1020106490Smdodd (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC); 10216604Sache else { 1022104445Smdodd if ((r = mcd_getstat(sc, 0)) == -1) 1023106490Smdodd return (EIO); 1024106490Smdodd return (0); 10256604Sache } 10266604Sache } 1027106490Smdodd return (ENXIO); 10286604Sache } 1029106490Smdodd return (0); 10306604Sache} 10316604Sache 10326604Sachestatic int 1033104445Smdoddmcd_eject(struct mcd_softc *sc) 10346604Sache{ 1035104445Smdodd int r; 10366604Sache 1037104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1038106490Smdodd return (EIO); 1039106490Smdodd if (sc->data.status & MCDDOOROPEN) 1040106490Smdodd return (0); 1041104445Smdodd if ((r = mcd_stop(sc)) == EIO) 1042106490Smdodd return (r); 1043104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDEJECTDISK); 1044104445Smdodd if (mcd_getstat(sc, 0) == -1) 1045106490Smdodd return (EIO); 1046106490Smdodd return (0); 10472477Sache} 10482477Sache 10492477Sachestatic int 1050104445Smdoddmcd_inject(struct mcd_softc *sc) 105113866Sache{ 105213866Sache 1053104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1054106490Smdodd return (EIO); 1055106490Smdodd if (sc->data.status & MCDDOOROPEN) 1056104445Smdodd return mcd_close_tray(sc); 1057106490Smdodd return (0); 105813866Sache} 105913866Sache 106013866Sachestatic int 1061104445Smdoddmcd_hard_reset(struct mcd_softc *sc) 10622477Sache{ 10632477Sache 1064104445Smdodd MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 1065106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1066106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 1067106490Smdodd return (0); 10682477Sache} 10692477Sache 10702477Sachestatic void 1071104445Smdoddmcd_soft_reset(struct mcd_softc *sc) 10722477Sache{ 10732477Sache 1074106490Smdodd sc->data.flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL); 1075106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1076106490Smdodd sc->data.partflags = 0; 1077106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 10782477Sache} 10792477Sache 10802477Sachestatic int 1081104445Smdoddmcd_setmode(struct mcd_softc *sc, int mode) 1082578Srgrimes{ 10832477Sache int retry, st; 1084578Srgrimes 1085106490Smdodd if (sc->data.curr_mode == mode) 1086106490Smdodd return (0); 1087106490Smdodd if (sc->data.debug) 1088104445Smdodd device_printf(sc->dev, "setting mode to %d\n", mode); 1089578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1090578Srgrimes { 1091106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1092104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 1093104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, mode); 1094104445Smdodd if ((st = mcd_getstat(sc, 0)) >= 0) { 1095106490Smdodd sc->data.curr_mode = mode; 1096106490Smdodd return (0); 10972477Sache } 10982477Sache if (st == -2) { 1099104445Smdodd device_printf(sc->dev, "media changed\n"); 11002477Sache break; 11012477Sache } 1102578Srgrimes } 1103578Srgrimes 1104106490Smdodd return (-1); 1105578Srgrimes} 1106578Srgrimes 11071197Srgrimesstatic int 1108104445Smdoddmcd_toc_header(struct mcd_softc *sc, struct ioc_toc_header *th) 1109578Srgrimes{ 11102477Sache int r; 1111578Srgrimes 1112104445Smdodd if ((r = mcd_volinfo(sc)) != 0) 1113106490Smdodd return (r); 1114578Srgrimes 1115106490Smdodd th->starting_track = bcd2bin(sc->data.volinfo.trk_low); 1116106490Smdodd th->ending_track = bcd2bin(sc->data.volinfo.trk_high); 111713874Sache th->len = 2 * sizeof(u_char) /* start & end tracks */ + 111813874Sache (th->ending_track + 1 - th->starting_track + 1) * 111913874Sache sizeof(struct cd_toc_entry); 1120578Srgrimes 1121106490Smdodd return (0); 1122578Srgrimes} 1123578Srgrimes 11241197Srgrimesstatic int 1125104445Smdoddmcd_read_toc(struct mcd_softc *sc) 1126578Srgrimes{ 1127578Srgrimes struct ioc_toc_header th; 1128578Srgrimes struct mcd_qchninfo q; 1129578Srgrimes int rc, trk, idx, retry; 1130578Srgrimes 1131578Srgrimes /* Only read TOC if needed */ 1132106490Smdodd if (sc->data.flags & MCDTOC) 1133106490Smdodd return (0); 1134578Srgrimes 1135106490Smdodd if (sc->data.debug) 1136104445Smdodd device_printf(sc->dev, "reading toc header\n"); 1137578Srgrimes 1138104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1139106490Smdodd return (rc); 1140578Srgrimes 1141104445Smdodd if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1142106490Smdodd return (EIO); 11436665Sache 1144104445Smdodd if (mcd_setmode(sc, MCD_MD_TOC) != 0) 1145106490Smdodd return (EIO); 1146578Srgrimes 1147106490Smdodd if (sc->data.debug) 1148104445Smdodd device_printf(sc->dev, "get_toc reading qchannel info\n"); 11492477Sache 1150578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1151106490Smdodd sc->data.toc[trk].idx_no = 0; 1152578Srgrimes trk = th.ending_track - th.starting_track + 1; 11536612Sache for(retry=0; retry<600 && trk>0; retry++) 1154578Srgrimes { 1155104445Smdodd if (mcd_getqchan(sc, &q) < 0) break; 1156578Srgrimes idx = bcd2bin(q.idx_no); 11572477Sache if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) { 1158106490Smdodd if (sc->data.toc[idx].idx_no == 0) { 1159106490Smdodd sc->data.toc[idx] = q; 1160578Srgrimes trk--; 1161578Srgrimes } 11621197Srgrimes } 1163578Srgrimes } 1164578Srgrimes 1165104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1166106490Smdodd return (EIO); 1167578Srgrimes 11682477Sache if (trk != 0) 1169106490Smdodd return (ENXIO); 1170578Srgrimes 1171578Srgrimes /* add a fake last+1 */ 1172578Srgrimes idx = th.ending_track + 1; 1173106490Smdodd sc->data.toc[idx].control = sc->data.toc[idx-1].control; 1174106490Smdodd sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type; 1175106490Smdodd sc->data.toc[idx].trk_no = 0; 1176106490Smdodd sc->data.toc[idx].idx_no = MCD_LASTPLUS1; 1177106490Smdodd sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0]; 1178106490Smdodd sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1]; 1179106490Smdodd sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2]; 1180578Srgrimes 1181106490Smdodd if (sc->data.debug) 11822477Sache { int i; 11832477Sache for (i = th.starting_track; i <= idx; i++) 1184104445Smdodd device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n", 1185104445Smdodd i, 1186106490Smdodd sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no : 1187106490Smdodd bcd2bin(sc->data.toc[i].idx_no), 1188106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[0]), 1189106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[1]), 1190106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[2])); 11912477Sache } 11922477Sache 1193106490Smdodd sc->data.flags |= MCDTOC; 1194578Srgrimes 1195106490Smdodd return (0); 1196578Srgrimes} 1197578Srgrimes 119831016Sphk#if 0 11991197Srgrimesstatic int 1200104445Smdoddmcd_toc_entry(struct mcd_softc *sc, struct ioc_read_toc_single_entry *te) 120125460Sjoerg{ 120225460Sjoerg struct ioc_toc_header th; 120325460Sjoerg int rc, trk; 120425460Sjoerg 120525460Sjoerg if (te->address_format != CD_MSF_FORMAT 120625460Sjoerg && te->address_format != CD_LBA_FORMAT) 1207106490Smdodd return (EINVAL); 120825460Sjoerg 120925460Sjoerg /* Copy the toc header */ 1210104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1211106490Smdodd return (rc); 121225460Sjoerg 121325460Sjoerg /* verify starting track */ 121425460Sjoerg trk = te->track; 121525460Sjoerg if (trk == 0) 121625460Sjoerg trk = th.starting_track; 121725460Sjoerg else if (trk == MCD_LASTPLUS1) 121825460Sjoerg trk = th.ending_track + 1; 121925460Sjoerg else if (trk < th.starting_track || trk > th.ending_track + 1) 1220106490Smdodd return (EINVAL); 122125460Sjoerg 122225460Sjoerg /* Make sure we have a valid toc */ 1223104445Smdodd if ((rc=mcd_read_toc(sc)) != 0) 1224106490Smdodd return (rc); 122525460Sjoerg 122625460Sjoerg /* Copy the TOC data. */ 1227106490Smdodd if (sc->data.toc[trk].idx_no == 0) 1228106490Smdodd return (EIO); 122925460Sjoerg 1230106490Smdodd te->entry.control = sc->data.toc[trk].control; 1231106490Smdodd te->entry.addr_type = sc->data.toc[trk].addr_type; 123225460Sjoerg te->entry.track = 1233106490Smdodd sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1234106490Smdodd bcd2bin(sc->data.toc[trk].idx_no); 123525460Sjoerg switch (te->address_format) { 123625460Sjoerg case CD_MSF_FORMAT: 123725460Sjoerg te->entry.addr.msf.unused = 0; 1238106490Smdodd te->entry.addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1239106490Smdodd te->entry.addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1240106490Smdodd te->entry.addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 124125460Sjoerg break; 124225460Sjoerg case CD_LBA_FORMAT: 1243106490Smdodd te->entry.addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 124425460Sjoerg break; 124525460Sjoerg } 1246106490Smdodd return (0); 124725460Sjoerg} 124831016Sphk#endif 124925460Sjoerg 125025460Sjoergstatic int 1251104445Smdoddmcd_toc_entrys(struct mcd_softc *sc, struct ioc_read_toc_entry *te) 1252578Srgrimes{ 12532477Sache struct cd_toc_entry entries[MCD_MAXTOCS]; 1254578Srgrimes struct ioc_toc_header th; 125513743Sache int rc, n, trk, len; 1256578Srgrimes 125713743Sache if ( te->data_len < sizeof(entries[0]) 125813743Sache || (te->data_len % sizeof(entries[0])) != 0 125946571Speter || (te->address_format != CD_MSF_FORMAT 126046571Speter && te->address_format != CD_LBA_FORMAT) 12612477Sache ) 1262106490Smdodd return (EINVAL); 1263578Srgrimes 1264578Srgrimes /* Copy the toc header */ 1265104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1266106490Smdodd return (rc); 1267578Srgrimes 126813732Sache /* verify starting track */ 126913732Sache trk = te->starting_track; 127013732Sache if (trk == 0) 127113732Sache trk = th.starting_track; 127213732Sache else if (trk == MCD_LASTPLUS1) 127313732Sache trk = th.ending_track + 1; 127413732Sache else if (trk < th.starting_track || trk > th.ending_track + 1) 1275106490Smdodd return (EINVAL); 127613732Sache 127713743Sache len = ((th.ending_track + 1 - trk) + 1) * 127813743Sache sizeof(entries[0]); 127913743Sache if (te->data_len < len) 128013743Sache len = te->data_len; 128113743Sache if (len > sizeof(entries)) 1282106490Smdodd return (EINVAL); 128313743Sache 128413732Sache /* Make sure we have a valid toc */ 1285104445Smdodd if ((rc=mcd_read_toc(sc)) != 0) 1286106490Smdodd return (rc); 128713732Sache 128813732Sache /* Copy the TOC data. */ 128913732Sache for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) { 1290106490Smdodd if (sc->data.toc[trk].idx_no == 0) 129113732Sache continue; 1292106490Smdodd entries[n].control = sc->data.toc[trk].control; 1293106490Smdodd entries[n].addr_type = sc->data.toc[trk].addr_type; 129413732Sache entries[n].track = 1295106490Smdodd sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1296106490Smdodd bcd2bin(sc->data.toc[trk].idx_no); 129713732Sache switch (te->address_format) { 129813732Sache case CD_MSF_FORMAT: 129913732Sache entries[n].addr.msf.unused = 0; 1300106490Smdodd entries[n].addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1301106490Smdodd entries[n].addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1302106490Smdodd entries[n].addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 130313732Sache break; 130413732Sache case CD_LBA_FORMAT: 1305106490Smdodd entries[n].addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 130613732Sache break; 13072477Sache } 13082477Sache len -= sizeof(struct cd_toc_entry); 130913732Sache n++; 1310578Srgrimes } 1311578Srgrimes 1312578Srgrimes /* copy the data back */ 131313732Sache return copyout(entries, te->data, n * sizeof(struct cd_toc_entry)); 1314578Srgrimes} 1315578Srgrimes 13161197Srgrimesstatic int 1317104445Smdoddmcd_stop(struct mcd_softc *sc) 1318578Srgrimes{ 1319578Srgrimes 13206604Sache /* Verify current status */ 1321106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1322106490Smdodd sc->data.audio_status != CD_AS_PLAY_PAUSED && 1323106490Smdodd sc->data.audio_status != CD_AS_PLAY_COMPLETED) { 1324106490Smdodd if (sc->data.debug) 1325104445Smdodd device_printf(sc->dev, 1326104445Smdodd "stop attempted when not playing, audio status %d\n", 1327106490Smdodd sc->data.audio_status); 1328106490Smdodd return (EINVAL); 13296604Sache } 1330106490Smdodd if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 1331104445Smdodd if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1332106490Smdodd return (EIO); 1333106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 1334106490Smdodd return (0); 1335578Srgrimes} 1336578Srgrimes 13371197Srgrimesstatic int 1338104445Smdoddmcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q) 1339578Srgrimes{ 1340578Srgrimes 1341104445Smdodd if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1342106490Smdodd return (-1); 1343104445Smdodd if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1344106490Smdodd return (-1); 1345106490Smdodd if (sc->data.debug) { 1346104445Smdodd device_printf(sc->dev, 1347104445Smdodd "getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n", 1348104445Smdodd q->control, q->addr_type, 1349104445Smdodd bcd2bin(q->trk_no), 1350104445Smdodd bcd2bin(q->idx_no), 1351104445Smdodd bcd2bin(q->trk_size_msf[0]), 1352104445Smdodd bcd2bin(q->trk_size_msf[1]), 1353104445Smdodd bcd2bin(q->trk_size_msf[2]), 1354104445Smdodd bcd2bin(q->hd_pos_msf[0]), 1355104445Smdodd bcd2bin(q->hd_pos_msf[1]), 1356104445Smdodd bcd2bin(q->hd_pos_msf[2])); 13571197Srgrimes } 1358106490Smdodd return (0); 1359578Srgrimes} 1360578Srgrimes 13611197Srgrimesstatic int 1362141031Ssobomaxmcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) 1363578Srgrimes{ 1364578Srgrimes struct mcd_qchninfo q; 1365578Srgrimes struct cd_sub_channel_info data; 136613770Sache int lba; 1367578Srgrimes 1368106490Smdodd if (sc->data.debug) 1369104445Smdodd device_printf(sc->dev, "subchan af=%d, df=%d\n", 1370104445Smdodd sch->address_format, 1371104445Smdodd sch->data_format); 13722477Sache 1373104445Smdodd if (sch->address_format != CD_MSF_FORMAT && 1374104445Smdodd sch->address_format != CD_LBA_FORMAT) 1375106490Smdodd return (EINVAL); 13762477Sache 1377104445Smdodd if (sch->data_format != CD_CURRENT_POSITION && 1378104445Smdodd sch->data_format != CD_MEDIA_CATALOG) 1379106490Smdodd return (EINVAL); 13802477Sache 1381104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1382106490Smdodd return (EIO); 13832477Sache 1384104445Smdodd if (mcd_getqchan(sc, &q) < 0) 1385106490Smdodd return (EIO); 1386578Srgrimes 1387106490Smdodd data.header.audio_status = sc->data.audio_status; 1388104445Smdodd data.what.position.data_format = sch->data_format; 138913886Sache 1390104445Smdodd switch (sch->data_format) { 139113886Sache case CD_MEDIA_CATALOG: 139213886Sache data.what.media_catalog.mc_valid = 1; 139313886Sache data.what.media_catalog.mc_number[0] = '\0'; 139413732Sache break; 139513886Sache 139613886Sache case CD_CURRENT_POSITION: 139713886Sache data.what.position.control = q.control; 139813886Sache data.what.position.addr_type = q.addr_type; 139913886Sache data.what.position.track_number = bcd2bin(q.trk_no); 140013886Sache data.what.position.index_number = bcd2bin(q.idx_no); 1401104445Smdodd switch (sch->address_format) { 140213886Sache case CD_MSF_FORMAT: 140313886Sache data.what.position.reladdr.msf.unused = 0; 140413886Sache data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]); 140513886Sache data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]); 140613886Sache data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]); 140713886Sache data.what.position.absaddr.msf.unused = 0; 140813886Sache data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]); 140913886Sache data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]); 141013886Sache data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]); 141113886Sache break; 141213886Sache case CD_LBA_FORMAT: 141313886Sache lba = msf2hsg(q.trk_size_msf, 1); 141413886Sache /* 141513886Sache * Pre-gap has index number of 0, and decreasing MSF 141613886Sache * address. Must be converted to negative LBA, per 141713886Sache * SCSI spec. 141813886Sache */ 141913886Sache if (data.what.position.index_number == 0) 142013886Sache lba = -lba; 142113886Sache data.what.position.reladdr.lba = htonl(lba); 142213886Sache data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0)); 142313886Sache break; 142413886Sache } 142513732Sache break; 14266665Sache } 1427578Srgrimes 1428141031Ssobomax if (nocopyout == 0) 1429141031Ssobomax return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 1430141031Ssobomax bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 1431141061Smaxim return (0); 1432578Srgrimes} 1433578Srgrimes 14341197Srgrimesstatic int 1435104445Smdoddmcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p) 14362477Sache{ 14372477Sache struct mcd_read2 pb; 14382477Sache 1439106490Smdodd if (sc->data.debug) 1440104445Smdodd device_printf(sc->dev, "playmsf: from %d:%d.%d to %d:%d.%d\n", 144113833Sache p->start_m, p->start_s, p->start_f, 144213833Sache p->end_m, p->end_s, p->end_f); 144313833Sache 144413833Sache if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >= 144513833Sache (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) || 144613833Sache (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) > 1447106490Smdodd M_msf(sc->data.volinfo.vol_msf) * 60 * 75 + 1448106490Smdodd S_msf(sc->data.volinfo.vol_msf) * 75 + 1449106490Smdodd F_msf(sc->data.volinfo.vol_msf)) 1450106490Smdodd return (EINVAL); 145113833Sache 145213833Sache pb.start_msf[0] = bin2bcd(p->start_m); 145313833Sache pb.start_msf[1] = bin2bcd(p->start_s); 145413833Sache pb.start_msf[2] = bin2bcd(p->start_f); 145513833Sache pb.end_msf[0] = bin2bcd(p->end_m); 145613833Sache pb.end_msf[1] = bin2bcd(p->end_s); 145713833Sache pb.end_msf[2] = bin2bcd(p->end_f); 145813833Sache 1459104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1460106490Smdodd return (EIO); 14612477Sache 1462104445Smdodd return mcd_play(sc, &pb); 14632477Sache} 14642477Sache 14652477Sachestatic int 1466104445Smdoddmcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *pt) 1467578Srgrimes{ 1468578Srgrimes struct mcd_read2 pb; 1469578Srgrimes int a = pt->start_track; 1470578Srgrimes int z = pt->end_track; 14714390Sache int rc, i; 1472578Srgrimes 1473104445Smdodd if ((rc = mcd_read_toc(sc)) != 0) 1474106490Smdodd return (rc); 1475578Srgrimes 1476106490Smdodd if (sc->data.debug) 1477104445Smdodd device_printf(sc->dev, "playtracks from %d:%d to %d:%d\n", 14782477Sache a, pt->start_index, z, pt->end_index); 14792477Sache 1480106490Smdodd if ( a < bcd2bin(sc->data.volinfo.trk_low) 1481106490Smdodd || a > bcd2bin(sc->data.volinfo.trk_high) 14822477Sache || a > z 1483106490Smdodd || z < bcd2bin(sc->data.volinfo.trk_low) 1484106490Smdodd || z > bcd2bin(sc->data.volinfo.trk_high)) 1485106490Smdodd return (EINVAL); 1486578Srgrimes 14874390Sache for (i = 0; i < 3; i++) { 1488106490Smdodd pb.start_msf[i] = sc->data.toc[a].hd_pos_msf[i]; 1489106490Smdodd pb.end_msf[i] = sc->data.toc[z+1].hd_pos_msf[i]; 14904390Sache } 1491578Srgrimes 1492104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1493106490Smdodd return (EIO); 149413833Sache 1495104445Smdodd return mcd_play(sc, &pb); 1496578Srgrimes} 1497578Srgrimes 14981197Srgrimesstatic int 1499104445Smdoddmcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p) 150013833Sache{ 150113833Sache struct mcd_read2 pb; 150213833Sache 1503106490Smdodd if (sc->data.debug) 1504104445Smdodd device_printf(sc->dev, "playblocks: blkno %d length %d\n", 1505104445Smdodd p->blk, p->len); 150613833Sache 1507106490Smdodd if (p->blk > sc->data.disksize || p->len > sc->data.disksize || 150813833Sache p->blk < 0 || p->len < 0 || 1509106490Smdodd (p->blk + p->len) > sc->data.disksize) 1510106490Smdodd return (EINVAL); 151113833Sache 151213833Sache hsg2msf(p->blk, pb.start_msf); 151313833Sache hsg2msf(p->blk + p->len, pb.end_msf); 151413833Sache 1515104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1516106490Smdodd return (EIO); 151713833Sache 1518104445Smdodd return mcd_play(sc, &pb); 151913833Sache} 152013833Sache 152113833Sachestatic int 1522104445Smdoddmcd_play(struct mcd_softc *sc, struct mcd_read2 *pb) 1523578Srgrimes{ 15242477Sache int retry, st = -1, status; 1525578Srgrimes 1526106490Smdodd sc->data.lastpb = *pb; 15271197Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) { 15282477Sache 1529106719Smdodd critical_enter(); 1530104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSINGLESPEEDREAD); 1531104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[0]); 1532104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[1]); 1533104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[2]); 1534104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[0]); 1535104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[1]); 1536104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[2]); 1537106719Smdodd critical_exit(); 15382477Sache 1539104445Smdodd status=mcd_getstat(sc, 0); 15402477Sache if (status == -1) 15412477Sache continue; 15422477Sache else if (status != -2) 15432477Sache st = 0; 15442477Sache break; 1545578Srgrimes } 1546578Srgrimes 15472477Sache if (status == -2) { 1548104445Smdodd device_printf(sc->dev, "media changed\n"); 1549106490Smdodd return (ENXIO); 15501197Srgrimes } 1551106490Smdodd if (sc->data.debug) 1552104445Smdodd device_printf(sc->dev, 1553104445Smdodd "mcd_play retry=%d, status=0x%02x\n", retry, status); 15542477Sache if (st < 0) 1555106490Smdodd return (ENXIO); 1556106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 1557106490Smdodd return (0); 1558578Srgrimes} 1559578Srgrimes 15601197Srgrimesstatic int 1561104445Smdoddmcd_pause(struct mcd_softc *sc) 1562578Srgrimes{ 1563578Srgrimes struct mcd_qchninfo q; 1564578Srgrimes int rc; 1565578Srgrimes 1566578Srgrimes /* Verify current status */ 1567106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1568106490Smdodd sc->data.audio_status != CD_AS_PLAY_PAUSED) { 1569106490Smdodd if (sc->data.debug) 1570104445Smdodd device_printf(sc->dev, 1571104445Smdodd "pause attempted when not playing, audio status %d\n", 1572106490Smdodd sc->data.audio_status); 1573106490Smdodd return (EINVAL); 1574578Srgrimes } 1575578Srgrimes 1576578Srgrimes /* Get the current position */ 1577104445Smdodd if (mcd_getqchan(sc, &q) < 0) 1578106490Smdodd return (EIO); 1579578Srgrimes 1580578Srgrimes /* Copy it into lastpb */ 1581106490Smdodd sc->data.lastpb.start_msf[0] = q.hd_pos_msf[0]; 1582106490Smdodd sc->data.lastpb.start_msf[1] = q.hd_pos_msf[1]; 1583106490Smdodd sc->data.lastpb.start_msf[2] = q.hd_pos_msf[2]; 1584578Srgrimes 1585578Srgrimes /* Stop playing */ 1586104445Smdodd if ((rc=mcd_stop(sc)) != 0) 1587106490Smdodd return (rc); 1588578Srgrimes 1589578Srgrimes /* Set the proper status and exit */ 1590106490Smdodd sc->data.audio_status = CD_AS_PLAY_PAUSED; 1591106490Smdodd return (0); 1592578Srgrimes} 1593578Srgrimes 15941197Srgrimesstatic int 1595104445Smdoddmcd_resume(struct mcd_softc *sc) 1596578Srgrimes{ 1597578Srgrimes 1598106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_PAUSED) 1599106490Smdodd return (EINVAL); 1600106490Smdodd return mcd_play(sc, &sc->data.lastpb); 1601578Srgrimes} 1602