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: releng/10.3/sys/dev/mcd/mcd.c 260276 2014-01-04 18:53:31Z dim $"); 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; 2928876Srgrimes 293104445Smdodd sc = (struct mcd_softc *)bp->bio_dev->si_drv1; 294578Srgrimes 295578Srgrimes /* if device invalidated (e.g. media change, door open), error */ 296106490Smdodd if (!(sc->data.flags & MCDVALID)) { 297104545Smdodd device_printf(sc->dev, "media changed\n"); 29859249Sphk bp->bio_error = EIO; 299578Srgrimes goto bad; 300578Srgrimes } 301578Srgrimes 302578Srgrimes /* read only */ 30359249Sphk if (!(bp->bio_cmd == BIO_READ)) { 30459249Sphk bp->bio_error = EROFS; 305578Srgrimes goto bad; 306578Srgrimes } 3078876Srgrimes 308578Srgrimes /* no data to read */ 30959249Sphk if (bp->bio_bcount == 0) 310578Srgrimes goto done; 3118876Srgrimes 312106490Smdodd if (!(sc->data.flags & MCDTOC)) { 313104545Smdodd bp->bio_error = EIO; 314104545Smdodd goto bad; 315578Srgrimes } 3168876Srgrimes 317104545Smdodd bp->bio_resid = 0; 318104545Smdodd 319578Srgrimes /* queue it */ 320112946Sphk bioq_disksort(&sc->data.head, bp); 3218876Srgrimes 322578Srgrimes /* now check whether we can perform processing */ 323104445Smdodd mcd_start(sc); 324578Srgrimes return; 325578Srgrimes 326578Srgrimesbad: 32759249Sphk bp->bio_flags |= BIO_ERROR; 328578Srgrimesdone: 32959249Sphk bp->bio_resid = bp->bio_bcount; 330578Srgrimes biodone(bp); 331578Srgrimes return; 332578Srgrimes} 333578Srgrimes 334104441Smdoddstatic void 335104445Smdoddmcd_start(struct mcd_softc *sc) 336578Srgrimes{ 33759249Sphk struct bio *bp; 3388876Srgrimes 339106490Smdodd if (sc->data.flags & MCDMBXBSY) { 340578Srgrimes return; 3412477Sache } 342578Srgrimes 343137045Sphk bp = bioq_takefirst(&sc->data.head); 34415574Sphk if (bp != 0) { 345578Srgrimes /* block found to process, dequeue */ 346578Srgrimes /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ 347106490Smdodd sc->data.flags |= MCDMBXBSY; 348578Srgrimes } else { 349578Srgrimes /* nothing to do */ 350578Srgrimes return; 351578Srgrimes } 352578Srgrimes 353106490Smdodd sc->data.mbx.retry = MCD_RETRYS; 354106490Smdodd sc->data.mbx.bp = bp; 355578Srgrimes 356106490Smdodd mcd_doread(sc, MCD_S_BEGIN,&(sc->data.mbx)); 357578Srgrimes return; 358578Srgrimes} 359578Srgrimes 360104441Smdoddstatic int 361130585Sphkmcdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 362578Srgrimes{ 363104445Smdodd struct mcd_softc *sc; 364104545Smdodd int retry,r; 3658876Srgrimes 366104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 367578Srgrimes 368104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 369106490Smdodd return (EIO); 37037618SbdeMCD_TRACE("ioctl called 0x%lx\n", cmd); 371578Srgrimes 372578Srgrimes switch (cmd) { 37314285Sache case CDIOCSETPATCH: 37414285Sache case CDIOCGETVOL: 37514285Sache case CDIOCSETVOL: 37614285Sache case CDIOCSETMONO: 37714285Sache case CDIOCSETSTERIO: 37814285Sache case CDIOCSETMUTE: 37914285Sache case CDIOCSETLEFT: 38014285Sache case CDIOCSETRIGHT: 381106490Smdodd return (EINVAL); 38214285Sache case CDIOCEJECT: 383104445Smdodd return mcd_eject(sc); 38414285Sache case CDIOCSETDEBUG: 385106490Smdodd sc->data.debug = 1; 386106490Smdodd return (0); 38714285Sache case CDIOCCLRDEBUG: 388106490Smdodd sc->data.debug = 0; 389106490Smdodd return (0); 39014285Sache case CDIOCRESET: 391104445Smdodd return mcd_hard_reset(sc); 39214285Sache case CDIOCALLOW: 393104445Smdodd return mcd_lock_door(sc, MCD_LK_UNLOCK); 39414285Sache case CDIOCPREVENT: 395104445Smdodd return mcd_lock_door(sc, MCD_LK_LOCK); 39614285Sache case CDIOCCLOSE: 397104445Smdodd return mcd_inject(sc); 39814285Sache } 39914285Sache 400106490Smdodd if (!(sc->data.flags & MCDVALID)) { 401106490Smdodd if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 402106490Smdodd || !(sc->data.status & MCDDSKIN)) 40314285Sache for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { 404106490Smdodd (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC); 405104445Smdodd if ((r = mcd_getstat(sc, 1)) == -1) 406106490Smdodd return (EIO); 40714285Sache if (r != -2) 40814285Sache break; 40914285Sache } 410106490Smdodd if ( (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG)) 411106490Smdodd || !(sc->data.status & MCDDSKIN) 412111731Sphk || mcd_size(dev) < 0 41314285Sache ) 414106490Smdodd return (ENXIO); 415106490Smdodd sc->data.flags |= MCDVALID; 416106490Smdodd sc->data.partflags |= MCDREADRAW; 417104445Smdodd (void) mcd_lock_door(sc, MCD_LK_LOCK); 418106490Smdodd if (!(sc->data.flags & MCDVALID)) 419106490Smdodd return (ENXIO); 42014285Sache } 42114285Sache 42214285Sache switch (cmd) { 423104545Smdodd case DIOCGMEDIASIZE: 424106490Smdodd *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; 425104545Smdodd return (0); 426104545Smdodd case DIOCGSECTORSIZE: 427106490Smdodd *(u_int *)addr = sc->data.blksize; 428104545Smdodd return (0); 429104545Smdodd 430578Srgrimes case CDIOCPLAYTRACKS: 431104445Smdodd return mcd_playtracks(sc, (struct ioc_play_track *) addr); 432578Srgrimes case CDIOCPLAYBLOCKS: 433104445Smdodd return mcd_playblocks(sc, (struct ioc_play_blocks *) addr); 4342477Sache case CDIOCPLAYMSF: 435104445Smdodd return mcd_playmsf(sc, (struct ioc_play_msf *) addr); 436141031Ssobomax case CDIOCREADSUBCHANNEL_SYSSPACE: 437141031Ssobomax return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); 438578Srgrimes case CDIOCREADSUBCHANNEL: 439141031Ssobomax return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); 440578Srgrimes case CDIOREADTOCHEADER: 441104445Smdodd return mcd_toc_header(sc, (struct ioc_toc_header *) addr); 442578Srgrimes case CDIOREADTOCENTRYS: 443104445Smdodd return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr); 444578Srgrimes case CDIOCRESUME: 445104445Smdodd return mcd_resume(sc); 446578Srgrimes case CDIOCPAUSE: 447104445Smdodd return mcd_pause(sc); 448578Srgrimes case CDIOCSTART: 449104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 450106490Smdodd return (EIO); 451106490Smdodd return (0); 452578Srgrimes case CDIOCSTOP: 453104445Smdodd return mcd_stop(sc); 454578Srgrimes default: 455106490Smdodd return (ENOTTY); 456578Srgrimes } 457578Srgrimes /*NOTREACHED*/ 458578Srgrimes} 459578Srgrimes 460104441Smdoddstatic int 461130585Sphkmcd_size(struct cdev *dev) 462578Srgrimes{ 463104445Smdodd struct mcd_softc *sc; 464578Srgrimes int size; 465578Srgrimes 466104445Smdodd sc = (struct mcd_softc *)dev->si_drv1; 467104445Smdodd 468104445Smdodd if (mcd_volinfo(sc) == 0) { 469106490Smdodd sc->data.blksize = MCDBLK; 470106490Smdodd size = msf2hsg(sc->data.volinfo.vol_msf, 0); 471106490Smdodd sc->data.disksize = size * (MCDBLK/DEV_BSIZE); 472106490Smdodd return (0); 473578Srgrimes } 474106490Smdodd return (-1); 475578Srgrimes} 476578Srgrimes 477578Srgrimes/*************************************************************** 478578Srgrimes * lower level of driver starts here 479578Srgrimes **************************************************************/ 480578Srgrimes 481578Srgrimes#ifdef NOTDEF 4821197Srgrimesstatic char 4831197Srgrimesirqs[] = { 484578Srgrimes 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 485578Srgrimes 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 486578Srgrimes}; 487578Srgrimes 4881197Srgrimesstatic char 4891197Srgrimesdrqs[] = { 490578Srgrimes 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, 491578Srgrimes}; 492578Srgrimes#endif 493578Srgrimes 49411872Sphk#ifdef NOT_YET 4951197Srgrimesstatic void 496104445Smdoddmcd_configure(struct mcd_softc *sc) 497578Srgrimes{ 498104445Smdodd MCD_WRITE(sc, MCD_REG_CONFIG, sc->data.config); 499578Srgrimes} 50011872Sphk#endif 501578Srgrimes 5021197Srgrimes/* Wait for non-busy - return 0 on timeout */ 5031197Srgrimesstatic int 504104445Smdoddtwiddle_thumbs(struct mcd_softc *sc, int count, char *whine) 5051197Srgrimes{ 5061197Srgrimes int i; 5071197Srgrimes 5081197Srgrimes for (i = 0; i < count; i++) { 509104445Smdodd if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 510106490Smdodd return (1); 5111197Srgrimes } 51213598Sjoerg if (bootverbose) 513104445Smdodd device_printf(sc->dev, "timeout %s\n", whine); 514106490Smdodd return (0); 5151197Srgrimes} 5161197Srgrimes 517978Sjkh/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */ 518578Srgrimes 519104445Smdoddint 520104445Smdoddmcd_probe(struct mcd_softc *sc) 521578Srgrimes{ 5221197Srgrimes int i, j; 5231197Srgrimes unsigned char stbytes[3]; 524578Srgrimes 525104445Smdodd sc->data.flags = MCDPROBING; 526578Srgrimes 527578Srgrimes#ifdef NOTDEF 528578Srgrimes /* get irq/drq configuration word */ 529104445Smdodd sc->data.config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ 530578Srgrimes#else 531104445Smdodd sc->data.config = 0; 532578Srgrimes#endif 533578Srgrimes 534578Srgrimes /* send a reset */ 535104445Smdodd MCD_WRITE(sc, MCD_FLAGS, M_RESET); 536578Srgrimes 5371197Srgrimes /* 5381197Srgrimes * delay awhile by getting any pending garbage (old data) and 5391197Srgrimes * throwing it away. 5401197Srgrimes */ 5412477Sache for (i = 1000000; i != 0; i--) 542104445Smdodd (void)MCD_READ(sc, MCD_FLAGS); 543578Srgrimes 5441197Srgrimes /* Get status */ 545104445Smdodd MCD_WRITE(sc, MCD_DATA, MCD_CMDGETSTAT); 546104445Smdodd if (!twiddle_thumbs(sc, 1000000, "getting status")) 547104445Smdodd return (ENXIO); /* Timeout */ 5481197Srgrimes /* Get version information */ 549104445Smdodd MCD_WRITE(sc, MCD_DATA, MCD_CMDCONTINFO); 5501197Srgrimes for (j = 0; j < 3; j++) { 551104445Smdodd if (!twiddle_thumbs(sc, 3000, "getting version info")) 552104445Smdodd return (ENXIO); 553104445Smdodd stbytes[j] = (MCD_READ(sc, MCD_DATA) & 0xFF); 5541197Srgrimes } 5555178Sache if (stbytes[1] == stbytes[2]) 556104445Smdodd return (ENXIO); 5575226Sache if (stbytes[2] >= 4 || stbytes[1] != 'M') { 558104445Smdodd MCD_WRITE(sc, MCD_CTRL, M_PICKLE); 559104445Smdodd sc->data.flags |= MCDNEWMODEL; 5601197Srgrimes } 561104445Smdodd sc->data.read_command = MCD_CMDSINGLESPEEDREAD; 5624480Sache switch (stbytes[1]) { 5634480Sache case 'M': 56413874Sache if (stbytes[2] <= 2) { 565104445Smdodd sc->data.type = MCD_TYPE_LU002S; 566104445Smdodd sc->data.name = "Mitsumi LU002S"; 56713874Sache } else if (stbytes[2] <= 5) { 568104445Smdodd sc->data.type = MCD_TYPE_LU005S; 569104445Smdodd sc->data.name = "Mitsumi LU005S"; 5704480Sache } else { 571104445Smdodd sc->data.type = MCD_TYPE_LU006S; 572104445Smdodd sc->data.name = "Mitsumi LU006S"; 5734480Sache } 5744480Sache break; 5754480Sache case 'F': 576104445Smdodd sc->data.type = MCD_TYPE_FX001; 577104445Smdodd sc->data.name = "Mitsumi FX001"; 5784480Sache break; 5794480Sache case 'D': 580104445Smdodd sc->data.type = MCD_TYPE_FX001D; 581104445Smdodd sc->data.name = "Mitsumi FX001D"; 582104445Smdodd sc->data.read_command = MCD_CMDDOUBLESPEEDREAD; 5834480Sache break; 5844480Sache default: 585104445Smdodd sc->data.type = MCD_TYPE_UNKNOWN; 586104445Smdodd sc->data.name = "Mitsumi ???"; 5874480Sache break; 5884480Sache } 5895226Sache 590104445Smdodd if (bootverbose) 591104445Smdodd device_printf(sc->dev, "type %s, version info: %c %x\n", 592104445Smdodd sc->data.name, stbytes[1], stbytes[2]); 593104445Smdodd 594106490Smdodd return (0); 595578Srgrimes} 596578Srgrimes 597978Sjkh 5981197Srgrimesstatic int 599104445Smdoddmcd_waitrdy(struct mcd_softc *sc, int dly) 600578Srgrimes{ 601578Srgrimes int i; 602578Srgrimes 6035226Sache /* wait until flag port senses status ready */ 6042477Sache for (i=0; i<dly; i+=MIN_DELAY) { 605104445Smdodd if (!(MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL)) 606106490Smdodd return (0); 6072477Sache DELAY(MIN_DELAY); 608578Srgrimes } 609106490Smdodd return (-1); 610578Srgrimes} 611578Srgrimes 6121197Srgrimesstatic int 613104445Smdoddmcd_getreply(struct mcd_softc *sc, int dly) 614578Srgrimes{ 615578Srgrimes 616578Srgrimes /* wait data to become ready */ 617104445Smdodd if (mcd_waitrdy(sc, dly)<0) { 618104445Smdodd device_printf(sc->dev, "timeout getreply\n"); 619106490Smdodd return (-1); 620578Srgrimes } 621578Srgrimes 622578Srgrimes /* get the data */ 623106490Smdodd return (MCD_READ(sc, MCD_REG_STATUS) & 0xFF); 624578Srgrimes} 625578Srgrimes 6261197Srgrimesstatic int 627104445Smdoddmcd_getstat(struct mcd_softc *sc, int sflg) 628578Srgrimes{ 629578Srgrimes int i; 630578Srgrimes 631578Srgrimes /* get the status */ 632578Srgrimes if (sflg) 633104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 634104445Smdodd i = mcd_getreply(sc, DELAY_GETREPLY); 6356604Sache if (i<0 || (i & MCD_ST_CMDCHECK)) { 636106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 637106490Smdodd return (-1); 6386604Sache } 639578Srgrimes 640106490Smdodd sc->data.status = i; 641578Srgrimes 642104445Smdodd if (mcd_setflags(sc) < 0) 643106490Smdodd return (-2); 644106490Smdodd return (sc->data.status); 645578Srgrimes} 646578Srgrimes 6472477Sachestatic int 648104445Smdoddmcd_setflags(struct mcd_softc *sc) 649578Srgrimes{ 650104445Smdodd 651578Srgrimes /* check flags */ 652106490Smdodd if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) 653106490Smdodd || !(sc->data.status & MCDDSKIN)) { 6548375Srgrimes MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n"); 655104445Smdodd mcd_soft_reset(sc); 656106490Smdodd return (-1); 657578Srgrimes } 658578Srgrimes 659106490Smdodd if (sc->data.status & MCDAUDIOBSY) 660106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 661106490Smdodd else if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 662106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 663106490Smdodd return (0); 664578Srgrimes} 665578Srgrimes 6661197Srgrimesstatic int 667104445Smdoddmcd_get(struct mcd_softc *sc, char *buf, int nmax) 668578Srgrimes{ 669578Srgrimes int i,k; 6708876Srgrimes 671578Srgrimes for (i=0; i<nmax; i++) { 672578Srgrimes /* wait for data */ 673104445Smdodd if ((k = mcd_getreply(sc, DELAY_GETREPLY)) < 0) { 674104445Smdodd device_printf(sc->dev, "timeout mcd_get\n"); 675106490Smdodd return (-1); 676578Srgrimes } 677578Srgrimes buf[i] = k; 678578Srgrimes } 679106490Smdodd return (i); 680578Srgrimes} 681578Srgrimes 6821197Srgrimesstatic int 683104445Smdoddmcd_send(struct mcd_softc *sc, int cmd,int nretrys) 684578Srgrimes{ 6852477Sache int i,k=0; 6868876Srgrimes 6872477Sache/*MCD_TRACE("mcd_send: command = 0x%02x\n",cmd,0,0,0);*/ 688578Srgrimes for (i=0; i<nretrys; i++) { 689104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, cmd); 690104445Smdodd if ((k=mcd_getstat(sc, 0)) != -1) 691578Srgrimes break; 692578Srgrimes } 6932477Sache if (k == -2) { 694104445Smdodd device_printf(sc->dev, "media changed\n"); 695106490Smdodd return (-1); 6962477Sache } 697578Srgrimes if (i == nretrys) { 698104445Smdodd device_printf(sc->dev, "mcd_send retry cnt exceeded\n"); 699106490Smdodd return (-1); 700578Srgrimes } 7012477Sache/*MCD_TRACE("mcd_send: done\n",0,0,0,0);*/ 702106490Smdodd return (0); 703578Srgrimes} 704578Srgrimes 7051197Srgrimesstatic void 7061197Srgrimeshsg2msf(int hsg, bcd_t *msf) 707578Srgrimes{ 708578Srgrimes hsg += 150; 709578Srgrimes F_msf(msf) = bin2bcd(hsg % 75); 71013770Sache hsg /= 75; 71113770Sache S_msf(msf) = bin2bcd(hsg % 60); 71213770Sache hsg /= 60; 71313770Sache M_msf(msf) = bin2bcd(hsg); 714578Srgrimes} 715578Srgrimes 7161197Srgrimesstatic int 71713770Sachemsf2hsg(bcd_t *msf, int relative) 718578Srgrimes{ 71913770Sache return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 + 72013770Sache bcd2bin(F_msf(msf)) - (!relative) * 150; 721578Srgrimes} 722578Srgrimes 7231197Srgrimesstatic int 724104445Smdoddmcd_volinfo(struct mcd_softc *sc) 725578Srgrimes{ 726578Srgrimes 727578Srgrimes /* Just return if we already have it */ 728106490Smdodd if (sc->data.flags & MCDVOLINFO) return (0); 729578Srgrimes 7302477Sache/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ 7312477Sache 732578Srgrimes /* send volume info command */ 733104445Smdodd if (mcd_send(sc, MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) 734106490Smdodd return (EIO); 735578Srgrimes 736578Srgrimes /* get data */ 737106490Smdodd if (mcd_get(sc, (char*) &sc->data.volinfo,sizeof(struct mcd_volinfo)) < 0) { 738104445Smdodd device_printf(sc->dev, "mcd_volinfo: error read data\n"); 739106490Smdodd return (EIO); 740578Srgrimes } 741578Srgrimes 742106490Smdodd if (sc->data.volinfo.trk_low > 0 && 743106490Smdodd sc->data.volinfo.trk_high >= sc->data.volinfo.trk_low 7446604Sache ) { 745106490Smdodd sc->data.flags |= MCDVOLINFO; /* volinfo is OK */ 746106490Smdodd return (0); 747578Srgrimes } 748578Srgrimes 749106490Smdodd return (EINVAL); 750578Srgrimes} 751578Srgrimes 752578Srgrimes/* state machine to process read requests 753578Srgrimes * initialize with MCD_S_BEGIN: calculate sizes, and read status 754578Srgrimes * MCD_S_WAITSTAT: wait for status reply, set mode 755578Srgrimes * MCD_S_WAITMODE: waits for status reply from set mode, set read command 756578Srgrimes * MCD_S_WAITREAD: wait for read ready, read data 757578Srgrimes */ 7581197Srgrimesstatic void 75925056Sbdemcd_timeout(void *arg) 76025056Sbde{ 761104445Smdodd struct mcd_softc *sc; 762104445Smdodd 763104445Smdodd sc = (struct mcd_softc *)arg; 764104445Smdodd 765104445Smdodd mcd_doread(sc, sc->ch_state, sc->ch_mbxsave); 76625056Sbde} 76725056Sbde 76825056Sbdestatic void 769104445Smdoddmcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin) 770578Srgrimes{ 771104445Smdodd struct mcd_mbx *mbx; 772104445Smdodd struct bio *bp; 773104445Smdodd int rm, i, k; 774578Srgrimes struct mcd_read2 rbuf; 775104445Smdodd int blknum; 776578Srgrimes caddr_t addr; 777578Srgrimes 778104445Smdodd mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; 779104445Smdodd bp = mbx->bp; 780104445Smdodd 781578Srgrimesloop: 782578Srgrimes switch (state) { 783578Srgrimes case MCD_S_BEGIN: 784104445Smdodd mbx = sc->ch_mbxsave = mbxin; 785578Srgrimes 786578Srgrimes case MCD_S_BEGIN1: 7876604Sacheretry_status: 788578Srgrimes /* get status */ 789104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); 790578Srgrimes mbx->count = RDELAY_WAITSTAT; 791104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 792104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 793578Srgrimes return; 794578Srgrimes case MCD_S_WAITSTAT: 795104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 796104445Smdodd untimeout(mcd_timeout,(caddr_t)sc, sc->ch); 797578Srgrimes if (mbx->count-- >= 0) { 798104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 799104445Smdodd sc->ch_state = MCD_S_WAITSTAT; 800104445Smdodd timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 801578Srgrimes return; 802578Srgrimes } 803106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 804106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) 8056028Sache goto retry_status; 806104445Smdodd if (mcd_setflags(sc) < 0) 8072477Sache goto changed; 8081197Srgrimes MCD_TRACE("got WAITSTAT delay=%d\n", 8098375Srgrimes RDELAY_WAITSTAT-mbx->count); 810578Srgrimes /* reject, if audio active */ 811106490Smdodd if (sc->data.status & MCDAUDIOBSY) { 812104445Smdodd device_printf(sc->dev, "audio is active\n"); 813578Srgrimes goto readerr; 814578Srgrimes } 8156604Sache 8166028Sacheretry_mode: 817578Srgrimes /* to check for raw/cooked mode */ 818106490Smdodd if (sc->data.flags & MCDREADRAW) { 8194389Sache rm = MCD_MD_RAW; 820578Srgrimes mbx->sz = MCDRBLK; 821578Srgrimes } else { 8224389Sache rm = MCD_MD_COOKED; 823106490Smdodd mbx->sz = sc->data.blksize; 824578Srgrimes } 825578Srgrimes 826106490Smdodd if (rm == sc->data.curr_mode) 8272477Sache goto modedone; 8282477Sache 829578Srgrimes mbx->count = RDELAY_WAITMODE; 8302477Sache 831106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 8322477Sache mbx->mode = rm; 833104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 834104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rm); 8352477Sache 836104445Smdodd sc->ch_state = MCD_S_WAITMODE; 837104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 838578Srgrimes return; 839578Srgrimes } else { 840104445Smdodd device_printf(sc->dev, "timeout getstatus\n"); 841578Srgrimes goto readerr; 842578Srgrimes } 843578Srgrimes 844578Srgrimes case MCD_S_WAITMODE: 845104445Smdodd sc->ch_state = MCD_S_WAITMODE; 846104445Smdodd untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 847578Srgrimes if (mbx->count-- < 0) { 848104445Smdodd device_printf(sc->dev, "timeout set mode\n"); 849578Srgrimes goto readerr; 850578Srgrimes } 851104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { 852104445Smdodd sc->ch_state = MCD_S_WAITMODE; 853104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); 854578Srgrimes return; 855578Srgrimes } 856106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 857106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) { 858106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 8596028Sache goto retry_mode; 8606028Sache } 861104445Smdodd if (mcd_setflags(sc) < 0) 8622477Sache goto changed; 863106490Smdodd sc->data.curr_mode = mbx->mode; 8641197Srgrimes MCD_TRACE("got WAITMODE delay=%d\n", 8658375Srgrimes RDELAY_WAITMODE-mbx->count); 8662477Sachemodedone: 867578Srgrimes /* for first block */ 86859249Sphk mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; 869578Srgrimes mbx->skip = 0; 870578Srgrimes 871578Srgrimesnextblock: 872121212Sphk blknum = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz; 873578Srgrimes 8748456Srgrimes MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n", 8758375Srgrimes blknum, bp); 876578Srgrimes 877578Srgrimes /* build parameter block */ 878578Srgrimes hsg2msf(blknum,rbuf.start_msf); 8796028Sacheretry_read: 880578Srgrimes /* send the read command */ 881106719Smdodd critical_enter(); 882106490Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command); 883104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]); 884104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]); 885104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]); 886104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 0); 887104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 0); 888104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, 1); 889106719Smdodd critical_exit(); 8902477Sache 8912762Sache /* Spin briefly (<= 2ms) to avoid missing next block */ 8922762Sache for (i = 0; i < 20; i++) { 893104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 8945226Sache if (!(k & MFL_DATA_NOT_AVAIL)) 8952762Sache goto got_it; 8962762Sache DELAY(100); 8972762Sache } 8982762Sache 899578Srgrimes mbx->count = RDELAY_WAITREAD; 900104445Smdodd sc->ch_state = MCD_S_WAITREAD; 901104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 902578Srgrimes return; 903578Srgrimes case MCD_S_WAITREAD: 904104445Smdodd sc->ch_state = MCD_S_WAITREAD; 905104445Smdodd untimeout(mcd_timeout, (caddr_t)sc, sc->ch); 906578Srgrimes if (mbx->count-- > 0) { 907104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 9085226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */ 9091197Srgrimes MCD_TRACE("got data delay=%d\n", 9108375Srgrimes RDELAY_WAITREAD-mbx->count); 9112762Sache got_it: 912578Srgrimes /* data is ready */ 91359249Sphk addr = bp->bio_data + mbx->skip; 9142477Sache 915104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2,0x04); /* XXX */ 916578Srgrimes for (i=0; i<mbx->sz; i++) 917104445Smdodd *addr++ = MCD_READ(sc, MCD_REG_RDATA); 918104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2,0x0c); /* XXX */ 919578Srgrimes 920104445Smdodd k = MCD_READ(sc, MCD_FLAGS); 9212477Sache /* If we still have some junk, read it too */ 9225226Sache if (!(k & MFL_DATA_NOT_AVAIL)) { 923104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2, 0x04); /* XXX */ 924104445Smdodd (void)MCD_READ(sc, MCD_REG_RDATA); 925104445Smdodd (void)MCD_READ(sc, MCD_REG_RDATA); 926104445Smdodd MCD_WRITE(sc, MCD_REG_CTL2, 0x0c); /* XXX */ 9272477Sache } 9282477Sache 929578Srgrimes if (--mbx->nblk > 0) { 930578Srgrimes mbx->skip += mbx->sz; 931578Srgrimes goto nextblock; 932578Srgrimes } 933578Srgrimes 934578Srgrimes /* return buffer */ 93559249Sphk bp->bio_resid = 0; 936578Srgrimes biodone(bp); 937578Srgrimes 938106490Smdodd sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 939104445Smdodd mcd_start(sc); 940578Srgrimes return; 941578Srgrimes } 9425226Sache if (!(k & MFL_STATUS_NOT_AVAIL)) { 943106490Smdodd sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; 944106490Smdodd if (sc->data.status & MCD_ST_CMDCHECK) 9456028Sache goto retry_read; 946104445Smdodd if (mcd_setflags(sc) < 0) 9472477Sache goto changed; 9482477Sache } 949104445Smdodd sc->ch_state = MCD_S_WAITREAD; 950104445Smdodd sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ 951578Srgrimes return; 952578Srgrimes } else { 953104445Smdodd device_printf(sc->dev, "timeout read data\n"); 954578Srgrimes goto readerr; 955578Srgrimes } 956578Srgrimes } 957578Srgrimes 958578Srgrimesreaderr: 959578Srgrimes if (mbx->retry-- > 0) { 960104445Smdodd device_printf(sc->dev, "retrying\n"); 961578Srgrimes state = MCD_S_BEGIN1; 962578Srgrimes goto loop; 963578Srgrimes } 9642477Sacheharderr: 965578Srgrimes /* invalidate the buffer */ 96659249Sphk bp->bio_flags |= BIO_ERROR; 96759249Sphk bp->bio_resid = bp->bio_bcount; 968578Srgrimes biodone(bp); 9692477Sache 970106490Smdodd sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); 971104445Smdodd mcd_start(sc); 972578Srgrimes return; 973578Srgrimes 9742477Sachechanged: 975104445Smdodd device_printf(sc->dev, "media changed\n"); 9762477Sache goto harderr; 9772477Sache 978578Srgrimes#ifdef NOTDEF 979104445Smdodd device_printf(sc->dev, "unit timeout, resetting\n"); 980104445Smdodd MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 981578Srgrimes DELAY(300000); 982104445Smdodd (void)mcd_getstat(sc, 1); 983104445Smdodd (void)mcd_getstat(sc, 1); 984106490Smdodd /*sc->data.status &= ~MCDDSKCHNG; */ 985106490Smdodd sc->data.debug = 1; /* preventive set debug mode */ 986578Srgrimes 987578Srgrimes#endif 988578Srgrimes 989578Srgrimes} 990578Srgrimes 9911197Srgrimesstatic int 992104445Smdoddmcd_lock_door(struct mcd_softc *sc, int lock) 9932477Sache{ 9942477Sache 995104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDLOCKDRV); 996104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, lock); 997104445Smdodd if (mcd_getstat(sc, 0) == -1) 998106490Smdodd return (EIO); 999106490Smdodd return (0); 10006604Sache} 10016604Sache 10026604Sachestatic int 1003104445Smdoddmcd_close_tray(struct mcd_softc *sc) 10046604Sache{ 10056604Sache int retry, r; 10066604Sache 1007104445Smdodd if (mcd_getstat(sc, 1) == -1) 1008106490Smdodd return (EIO); 1009106490Smdodd if (sc->data.status & MCDDOOROPEN) { 1010104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDCLOSETRAY); 10116604Sache for (retry = 0; retry < CLOSE_TRAY_SECS * WAIT_FRAC; retry++) { 1012104445Smdodd if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) 1013106490Smdodd (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdcls", hz/WAIT_FRAC); 10146604Sache else { 1015104445Smdodd if ((r = mcd_getstat(sc, 0)) == -1) 1016106490Smdodd return (EIO); 1017106490Smdodd return (0); 10186604Sache } 10196604Sache } 1020106490Smdodd return (ENXIO); 10216604Sache } 1022106490Smdodd return (0); 10236604Sache} 10246604Sache 10256604Sachestatic int 1026104445Smdoddmcd_eject(struct mcd_softc *sc) 10276604Sache{ 1028104445Smdodd int r; 10296604Sache 1030104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1031106490Smdodd return (EIO); 1032106490Smdodd if (sc->data.status & MCDDOOROPEN) 1033106490Smdodd return (0); 1034104445Smdodd if ((r = mcd_stop(sc)) == EIO) 1035106490Smdodd return (r); 1036104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDEJECTDISK); 1037104445Smdodd if (mcd_getstat(sc, 0) == -1) 1038106490Smdodd return (EIO); 1039106490Smdodd return (0); 10402477Sache} 10412477Sache 10422477Sachestatic int 1043104445Smdoddmcd_inject(struct mcd_softc *sc) 104413866Sache{ 104513866Sache 1046104445Smdodd if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ 1047106490Smdodd return (EIO); 1048106490Smdodd if (sc->data.status & MCDDOOROPEN) 1049104445Smdodd return mcd_close_tray(sc); 1050106490Smdodd return (0); 105113866Sache} 105213866Sache 105313866Sachestatic int 1054104445Smdoddmcd_hard_reset(struct mcd_softc *sc) 10552477Sache{ 10562477Sache 1057104445Smdodd MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); 1058106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1059106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 1060106490Smdodd return (0); 10612477Sache} 10622477Sache 10632477Sachestatic void 1064104445Smdoddmcd_soft_reset(struct mcd_softc *sc) 10652477Sache{ 10662477Sache 1067106490Smdodd sc->data.flags &= (MCDINIT|MCDPROBING|MCDNEWMODEL); 1068106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1069106490Smdodd sc->data.partflags = 0; 1070106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 10712477Sache} 10722477Sache 10732477Sachestatic int 1074104445Smdoddmcd_setmode(struct mcd_softc *sc, int mode) 1075578Srgrimes{ 10762477Sache int retry, st; 1077578Srgrimes 1078106490Smdodd if (sc->data.curr_mode == mode) 1079106490Smdodd return (0); 1080106490Smdodd if (sc->data.debug) 1081104445Smdodd device_printf(sc->dev, "setting mode to %d\n", mode); 1082578Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) 1083578Srgrimes { 1084106490Smdodd sc->data.curr_mode = MCD_MD_UNKNOWN; 1085104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); 1086104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, mode); 1087104445Smdodd if ((st = mcd_getstat(sc, 0)) >= 0) { 1088106490Smdodd sc->data.curr_mode = mode; 1089106490Smdodd return (0); 10902477Sache } 10912477Sache if (st == -2) { 1092104445Smdodd device_printf(sc->dev, "media changed\n"); 10932477Sache break; 10942477Sache } 1095578Srgrimes } 1096578Srgrimes 1097106490Smdodd return (-1); 1098578Srgrimes} 1099578Srgrimes 11001197Srgrimesstatic int 1101104445Smdoddmcd_toc_header(struct mcd_softc *sc, struct ioc_toc_header *th) 1102578Srgrimes{ 11032477Sache int r; 1104578Srgrimes 1105104445Smdodd if ((r = mcd_volinfo(sc)) != 0) 1106106490Smdodd return (r); 1107578Srgrimes 1108106490Smdodd th->starting_track = bcd2bin(sc->data.volinfo.trk_low); 1109106490Smdodd th->ending_track = bcd2bin(sc->data.volinfo.trk_high); 111013874Sache th->len = 2 * sizeof(u_char) /* start & end tracks */ + 111113874Sache (th->ending_track + 1 - th->starting_track + 1) * 111213874Sache sizeof(struct cd_toc_entry); 1113578Srgrimes 1114106490Smdodd return (0); 1115578Srgrimes} 1116578Srgrimes 11171197Srgrimesstatic int 1118104445Smdoddmcd_read_toc(struct mcd_softc *sc) 1119578Srgrimes{ 1120578Srgrimes struct ioc_toc_header th; 1121578Srgrimes struct mcd_qchninfo q; 1122578Srgrimes int rc, trk, idx, retry; 1123578Srgrimes 1124578Srgrimes /* Only read TOC if needed */ 1125106490Smdodd if (sc->data.flags & MCDTOC) 1126106490Smdodd return (0); 1127578Srgrimes 1128106490Smdodd if (sc->data.debug) 1129104445Smdodd device_printf(sc->dev, "reading toc header\n"); 1130578Srgrimes 1131104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1132106490Smdodd return (rc); 1133578Srgrimes 1134104445Smdodd if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1135106490Smdodd return (EIO); 11366665Sache 1137104445Smdodd if (mcd_setmode(sc, MCD_MD_TOC) != 0) 1138106490Smdodd return (EIO); 1139578Srgrimes 1140106490Smdodd if (sc->data.debug) 1141104445Smdodd device_printf(sc->dev, "get_toc reading qchannel info\n"); 11422477Sache 1143578Srgrimes for(trk=th.starting_track; trk<=th.ending_track; trk++) 1144106490Smdodd sc->data.toc[trk].idx_no = 0; 1145578Srgrimes trk = th.ending_track - th.starting_track + 1; 11466612Sache for(retry=0; retry<600 && trk>0; retry++) 1147578Srgrimes { 1148104445Smdodd if (mcd_getqchan(sc, &q) < 0) break; 1149578Srgrimes idx = bcd2bin(q.idx_no); 11502477Sache if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) { 1151106490Smdodd if (sc->data.toc[idx].idx_no == 0) { 1152106490Smdodd sc->data.toc[idx] = q; 1153578Srgrimes trk--; 1154578Srgrimes } 11551197Srgrimes } 1156578Srgrimes } 1157578Srgrimes 1158104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1159106490Smdodd return (EIO); 1160578Srgrimes 11612477Sache if (trk != 0) 1162106490Smdodd return (ENXIO); 1163578Srgrimes 1164578Srgrimes /* add a fake last+1 */ 1165578Srgrimes idx = th.ending_track + 1; 1166106490Smdodd sc->data.toc[idx].control = sc->data.toc[idx-1].control; 1167106490Smdodd sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type; 1168106490Smdodd sc->data.toc[idx].trk_no = 0; 1169106490Smdodd sc->data.toc[idx].idx_no = MCD_LASTPLUS1; 1170106490Smdodd sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0]; 1171106490Smdodd sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1]; 1172106490Smdodd sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2]; 1173578Srgrimes 1174106490Smdodd if (sc->data.debug) 11752477Sache { int i; 11762477Sache for (i = th.starting_track; i <= idx; i++) 1177104445Smdodd device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n", 1178104445Smdodd i, 1179106490Smdodd sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no : 1180106490Smdodd bcd2bin(sc->data.toc[i].idx_no), 1181106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[0]), 1182106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[1]), 1183106490Smdodd bcd2bin(sc->data.toc[i].hd_pos_msf[2])); 11842477Sache } 11852477Sache 1186106490Smdodd sc->data.flags |= MCDTOC; 1187578Srgrimes 1188106490Smdodd return (0); 1189578Srgrimes} 1190578Srgrimes 119131016Sphk#if 0 11921197Srgrimesstatic int 1193104445Smdoddmcd_toc_entry(struct mcd_softc *sc, struct ioc_read_toc_single_entry *te) 119425460Sjoerg{ 119525460Sjoerg struct ioc_toc_header th; 119625460Sjoerg int rc, trk; 119725460Sjoerg 119825460Sjoerg if (te->address_format != CD_MSF_FORMAT 119925460Sjoerg && te->address_format != CD_LBA_FORMAT) 1200106490Smdodd return (EINVAL); 120125460Sjoerg 120225460Sjoerg /* Copy the toc header */ 1203104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1204106490Smdodd return (rc); 120525460Sjoerg 120625460Sjoerg /* verify starting track */ 120725460Sjoerg trk = te->track; 120825460Sjoerg if (trk == 0) 120925460Sjoerg trk = th.starting_track; 121025460Sjoerg else if (trk == MCD_LASTPLUS1) 121125460Sjoerg trk = th.ending_track + 1; 121225460Sjoerg else if (trk < th.starting_track || trk > th.ending_track + 1) 1213106490Smdodd return (EINVAL); 121425460Sjoerg 121525460Sjoerg /* Make sure we have a valid toc */ 1216104445Smdodd if ((rc=mcd_read_toc(sc)) != 0) 1217106490Smdodd return (rc); 121825460Sjoerg 121925460Sjoerg /* Copy the TOC data. */ 1220106490Smdodd if (sc->data.toc[trk].idx_no == 0) 1221106490Smdodd return (EIO); 122225460Sjoerg 1223106490Smdodd te->entry.control = sc->data.toc[trk].control; 1224106490Smdodd te->entry.addr_type = sc->data.toc[trk].addr_type; 122525460Sjoerg te->entry.track = 1226106490Smdodd sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1227106490Smdodd bcd2bin(sc->data.toc[trk].idx_no); 122825460Sjoerg switch (te->address_format) { 122925460Sjoerg case CD_MSF_FORMAT: 123025460Sjoerg te->entry.addr.msf.unused = 0; 1231106490Smdodd te->entry.addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1232106490Smdodd te->entry.addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1233106490Smdodd te->entry.addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 123425460Sjoerg break; 123525460Sjoerg case CD_LBA_FORMAT: 1236106490Smdodd te->entry.addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 123725460Sjoerg break; 123825460Sjoerg } 1239106490Smdodd return (0); 124025460Sjoerg} 124131016Sphk#endif 124225460Sjoerg 124325460Sjoergstatic int 1244104445Smdoddmcd_toc_entrys(struct mcd_softc *sc, struct ioc_read_toc_entry *te) 1245578Srgrimes{ 12462477Sache struct cd_toc_entry entries[MCD_MAXTOCS]; 1247578Srgrimes struct ioc_toc_header th; 124813743Sache int rc, n, trk, len; 1249578Srgrimes 125013743Sache if ( te->data_len < sizeof(entries[0]) 125113743Sache || (te->data_len % sizeof(entries[0])) != 0 125246571Speter || (te->address_format != CD_MSF_FORMAT 125346571Speter && te->address_format != CD_LBA_FORMAT) 12542477Sache ) 1255106490Smdodd return (EINVAL); 1256578Srgrimes 1257578Srgrimes /* Copy the toc header */ 1258104445Smdodd if ((rc = mcd_toc_header(sc, &th)) != 0) 1259106490Smdodd return (rc); 1260578Srgrimes 126113732Sache /* verify starting track */ 126213732Sache trk = te->starting_track; 126313732Sache if (trk == 0) 126413732Sache trk = th.starting_track; 126513732Sache else if (trk == MCD_LASTPLUS1) 126613732Sache trk = th.ending_track + 1; 126713732Sache else if (trk < th.starting_track || trk > th.ending_track + 1) 1268106490Smdodd return (EINVAL); 126913732Sache 127013743Sache len = ((th.ending_track + 1 - trk) + 1) * 127113743Sache sizeof(entries[0]); 127213743Sache if (te->data_len < len) 127313743Sache len = te->data_len; 127413743Sache if (len > sizeof(entries)) 1275106490Smdodd return (EINVAL); 127613743Sache 127713732Sache /* Make sure we have a valid toc */ 1278104445Smdodd if ((rc=mcd_read_toc(sc)) != 0) 1279106490Smdodd return (rc); 128013732Sache 128113732Sache /* Copy the TOC data. */ 128213732Sache for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) { 1283106490Smdodd if (sc->data.toc[trk].idx_no == 0) 128413732Sache continue; 1285106490Smdodd entries[n].control = sc->data.toc[trk].control; 1286106490Smdodd entries[n].addr_type = sc->data.toc[trk].addr_type; 128713732Sache entries[n].track = 1288106490Smdodd sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no : 1289106490Smdodd bcd2bin(sc->data.toc[trk].idx_no); 129013732Sache switch (te->address_format) { 129113732Sache case CD_MSF_FORMAT: 129213732Sache entries[n].addr.msf.unused = 0; 1293106490Smdodd entries[n].addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]); 1294106490Smdodd entries[n].addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]); 1295106490Smdodd entries[n].addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]); 129613732Sache break; 129713732Sache case CD_LBA_FORMAT: 1298106490Smdodd entries[n].addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0)); 129913732Sache break; 13002477Sache } 13012477Sache len -= sizeof(struct cd_toc_entry); 130213732Sache n++; 1303578Srgrimes } 1304578Srgrimes 1305578Srgrimes /* copy the data back */ 130613732Sache return copyout(entries, te->data, n * sizeof(struct cd_toc_entry)); 1307578Srgrimes} 1308578Srgrimes 13091197Srgrimesstatic int 1310104445Smdoddmcd_stop(struct mcd_softc *sc) 1311578Srgrimes{ 1312578Srgrimes 13136604Sache /* Verify current status */ 1314106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1315106490Smdodd sc->data.audio_status != CD_AS_PLAY_PAUSED && 1316106490Smdodd sc->data.audio_status != CD_AS_PLAY_COMPLETED) { 1317106490Smdodd if (sc->data.debug) 1318104445Smdodd device_printf(sc->dev, 1319104445Smdodd "stop attempted when not playing, audio status %d\n", 1320106490Smdodd sc->data.audio_status); 1321106490Smdodd return (EINVAL); 13226604Sache } 1323106490Smdodd if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) 1324104445Smdodd if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) 1325106490Smdodd return (EIO); 1326106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 1327106490Smdodd return (0); 1328578Srgrimes} 1329578Srgrimes 13301197Srgrimesstatic int 1331104445Smdoddmcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q) 1332578Srgrimes{ 1333578Srgrimes 1334104445Smdodd if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRYS) < 0) 1335106490Smdodd return (-1); 1336104445Smdodd if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0) 1337106490Smdodd return (-1); 1338106490Smdodd if (sc->data.debug) { 1339104445Smdodd device_printf(sc->dev, 1340104445Smdodd "getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n", 1341104445Smdodd q->control, q->addr_type, 1342104445Smdodd bcd2bin(q->trk_no), 1343104445Smdodd bcd2bin(q->idx_no), 1344104445Smdodd bcd2bin(q->trk_size_msf[0]), 1345104445Smdodd bcd2bin(q->trk_size_msf[1]), 1346104445Smdodd bcd2bin(q->trk_size_msf[2]), 1347104445Smdodd bcd2bin(q->hd_pos_msf[0]), 1348104445Smdodd bcd2bin(q->hd_pos_msf[1]), 1349104445Smdodd bcd2bin(q->hd_pos_msf[2])); 13501197Srgrimes } 1351106490Smdodd return (0); 1352578Srgrimes} 1353578Srgrimes 13541197Srgrimesstatic int 1355141031Ssobomaxmcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) 1356578Srgrimes{ 1357578Srgrimes struct mcd_qchninfo q; 1358578Srgrimes struct cd_sub_channel_info data; 135913770Sache int lba; 1360578Srgrimes 1361106490Smdodd if (sc->data.debug) 1362104445Smdodd device_printf(sc->dev, "subchan af=%d, df=%d\n", 1363104445Smdodd sch->address_format, 1364104445Smdodd sch->data_format); 13652477Sache 1366104445Smdodd if (sch->address_format != CD_MSF_FORMAT && 1367104445Smdodd sch->address_format != CD_LBA_FORMAT) 1368106490Smdodd return (EINVAL); 13692477Sache 1370104445Smdodd if (sch->data_format != CD_CURRENT_POSITION && 1371104445Smdodd sch->data_format != CD_MEDIA_CATALOG) 1372106490Smdodd return (EINVAL); 13732477Sache 1374104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1375106490Smdodd return (EIO); 13762477Sache 1377104445Smdodd if (mcd_getqchan(sc, &q) < 0) 1378106490Smdodd return (EIO); 1379578Srgrimes 1380106490Smdodd data.header.audio_status = sc->data.audio_status; 1381104445Smdodd data.what.position.data_format = sch->data_format; 138213886Sache 1383104445Smdodd switch (sch->data_format) { 138413886Sache case CD_MEDIA_CATALOG: 138513886Sache data.what.media_catalog.mc_valid = 1; 138613886Sache data.what.media_catalog.mc_number[0] = '\0'; 138713732Sache break; 138813886Sache 138913886Sache case CD_CURRENT_POSITION: 139013886Sache data.what.position.control = q.control; 139113886Sache data.what.position.addr_type = q.addr_type; 139213886Sache data.what.position.track_number = bcd2bin(q.trk_no); 139313886Sache data.what.position.index_number = bcd2bin(q.idx_no); 1394104445Smdodd switch (sch->address_format) { 139513886Sache case CD_MSF_FORMAT: 139613886Sache data.what.position.reladdr.msf.unused = 0; 139713886Sache data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]); 139813886Sache data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]); 139913886Sache data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]); 140013886Sache data.what.position.absaddr.msf.unused = 0; 140113886Sache data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]); 140213886Sache data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]); 140313886Sache data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]); 140413886Sache break; 140513886Sache case CD_LBA_FORMAT: 140613886Sache lba = msf2hsg(q.trk_size_msf, 1); 140713886Sache /* 140813886Sache * Pre-gap has index number of 0, and decreasing MSF 140913886Sache * address. Must be converted to negative LBA, per 141013886Sache * SCSI spec. 141113886Sache */ 141213886Sache if (data.what.position.index_number == 0) 141313886Sache lba = -lba; 141413886Sache data.what.position.reladdr.lba = htonl(lba); 141513886Sache data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0)); 141613886Sache break; 141713886Sache } 141813732Sache break; 14196665Sache } 1420578Srgrimes 1421141031Ssobomax if (nocopyout == 0) 1422141031Ssobomax return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 1423141031Ssobomax bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 1424141061Smaxim return (0); 1425578Srgrimes} 1426578Srgrimes 14271197Srgrimesstatic int 1428104445Smdoddmcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p) 14292477Sache{ 14302477Sache struct mcd_read2 pb; 14312477Sache 1432106490Smdodd if (sc->data.debug) 1433104445Smdodd device_printf(sc->dev, "playmsf: from %d:%d.%d to %d:%d.%d\n", 143413833Sache p->start_m, p->start_s, p->start_f, 143513833Sache p->end_m, p->end_s, p->end_f); 143613833Sache 143713833Sache if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >= 143813833Sache (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) || 143913833Sache (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) > 1440106490Smdodd M_msf(sc->data.volinfo.vol_msf) * 60 * 75 + 1441106490Smdodd S_msf(sc->data.volinfo.vol_msf) * 75 + 1442106490Smdodd F_msf(sc->data.volinfo.vol_msf)) 1443106490Smdodd return (EINVAL); 144413833Sache 144513833Sache pb.start_msf[0] = bin2bcd(p->start_m); 144613833Sache pb.start_msf[1] = bin2bcd(p->start_s); 144713833Sache pb.start_msf[2] = bin2bcd(p->start_f); 144813833Sache pb.end_msf[0] = bin2bcd(p->end_m); 144913833Sache pb.end_msf[1] = bin2bcd(p->end_s); 145013833Sache pb.end_msf[2] = bin2bcd(p->end_f); 145113833Sache 1452104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1453106490Smdodd return (EIO); 14542477Sache 1455104445Smdodd return mcd_play(sc, &pb); 14562477Sache} 14572477Sache 14582477Sachestatic int 1459104445Smdoddmcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *pt) 1460578Srgrimes{ 1461578Srgrimes struct mcd_read2 pb; 1462578Srgrimes int a = pt->start_track; 1463578Srgrimes int z = pt->end_track; 14644390Sache int rc, i; 1465578Srgrimes 1466104445Smdodd if ((rc = mcd_read_toc(sc)) != 0) 1467106490Smdodd return (rc); 1468578Srgrimes 1469106490Smdodd if (sc->data.debug) 1470104445Smdodd device_printf(sc->dev, "playtracks from %d:%d to %d:%d\n", 14712477Sache a, pt->start_index, z, pt->end_index); 14722477Sache 1473106490Smdodd if ( a < bcd2bin(sc->data.volinfo.trk_low) 1474106490Smdodd || a > bcd2bin(sc->data.volinfo.trk_high) 14752477Sache || a > z 1476106490Smdodd || z < bcd2bin(sc->data.volinfo.trk_low) 1477106490Smdodd || z > bcd2bin(sc->data.volinfo.trk_high)) 1478106490Smdodd return (EINVAL); 1479578Srgrimes 14804390Sache for (i = 0; i < 3; i++) { 1481106490Smdodd pb.start_msf[i] = sc->data.toc[a].hd_pos_msf[i]; 1482106490Smdodd pb.end_msf[i] = sc->data.toc[z+1].hd_pos_msf[i]; 14834390Sache } 1484578Srgrimes 1485104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1486106490Smdodd return (EIO); 148713833Sache 1488104445Smdodd return mcd_play(sc, &pb); 1489578Srgrimes} 1490578Srgrimes 14911197Srgrimesstatic int 1492104445Smdoddmcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p) 149313833Sache{ 149413833Sache struct mcd_read2 pb; 149513833Sache 1496106490Smdodd if (sc->data.debug) 1497104445Smdodd device_printf(sc->dev, "playblocks: blkno %d length %d\n", 1498104445Smdodd p->blk, p->len); 149913833Sache 1500106490Smdodd if (p->blk > sc->data.disksize || p->len > sc->data.disksize || 150113833Sache p->blk < 0 || p->len < 0 || 1502106490Smdodd (p->blk + p->len) > sc->data.disksize) 1503106490Smdodd return (EINVAL); 150413833Sache 150513833Sache hsg2msf(p->blk, pb.start_msf); 150613833Sache hsg2msf(p->blk + p->len, pb.end_msf); 150713833Sache 1508104445Smdodd if (mcd_setmode(sc, MCD_MD_COOKED) != 0) 1509106490Smdodd return (EIO); 151013833Sache 1511104445Smdodd return mcd_play(sc, &pb); 151213833Sache} 151313833Sache 151413833Sachestatic int 1515104445Smdoddmcd_play(struct mcd_softc *sc, struct mcd_read2 *pb) 1516578Srgrimes{ 15172477Sache int retry, st = -1, status; 1518578Srgrimes 1519106490Smdodd sc->data.lastpb = *pb; 15201197Srgrimes for(retry=0; retry<MCD_RETRYS; retry++) { 15212477Sache 1522106719Smdodd critical_enter(); 1523104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSINGLESPEEDREAD); 1524104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[0]); 1525104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[1]); 1526104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->start_msf[2]); 1527104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[0]); 1528104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[1]); 1529104445Smdodd MCD_WRITE(sc, MCD_REG_COMMAND, pb->end_msf[2]); 1530106719Smdodd critical_exit(); 15312477Sache 1532104445Smdodd status=mcd_getstat(sc, 0); 15332477Sache if (status == -1) 15342477Sache continue; 15352477Sache else if (status != -2) 15362477Sache st = 0; 15372477Sache break; 1538578Srgrimes } 1539578Srgrimes 15402477Sache if (status == -2) { 1541104445Smdodd device_printf(sc->dev, "media changed\n"); 1542106490Smdodd return (ENXIO); 15431197Srgrimes } 1544106490Smdodd if (sc->data.debug) 1545104445Smdodd device_printf(sc->dev, 1546104445Smdodd "mcd_play retry=%d, status=0x%02x\n", retry, status); 15472477Sache if (st < 0) 1548106490Smdodd return (ENXIO); 1549106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 1550106490Smdodd return (0); 1551578Srgrimes} 1552578Srgrimes 15531197Srgrimesstatic int 1554104445Smdoddmcd_pause(struct mcd_softc *sc) 1555578Srgrimes{ 1556578Srgrimes struct mcd_qchninfo q; 1557578Srgrimes int rc; 1558578Srgrimes 1559578Srgrimes /* Verify current status */ 1560106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && 1561106490Smdodd sc->data.audio_status != CD_AS_PLAY_PAUSED) { 1562106490Smdodd if (sc->data.debug) 1563104445Smdodd device_printf(sc->dev, 1564104445Smdodd "pause attempted when not playing, audio status %d\n", 1565106490Smdodd sc->data.audio_status); 1566106490Smdodd return (EINVAL); 1567578Srgrimes } 1568578Srgrimes 1569578Srgrimes /* Get the current position */ 1570104445Smdodd if (mcd_getqchan(sc, &q) < 0) 1571106490Smdodd return (EIO); 1572578Srgrimes 1573578Srgrimes /* Copy it into lastpb */ 1574106490Smdodd sc->data.lastpb.start_msf[0] = q.hd_pos_msf[0]; 1575106490Smdodd sc->data.lastpb.start_msf[1] = q.hd_pos_msf[1]; 1576106490Smdodd sc->data.lastpb.start_msf[2] = q.hd_pos_msf[2]; 1577578Srgrimes 1578578Srgrimes /* Stop playing */ 1579104445Smdodd if ((rc=mcd_stop(sc)) != 0) 1580106490Smdodd return (rc); 1581578Srgrimes 1582578Srgrimes /* Set the proper status and exit */ 1583106490Smdodd sc->data.audio_status = CD_AS_PLAY_PAUSED; 1584106490Smdodd return (0); 1585578Srgrimes} 1586578Srgrimes 15871197Srgrimesstatic int 1588104445Smdoddmcd_resume(struct mcd_softc *sc) 1589578Srgrimes{ 1590578Srgrimes 1591106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_PAUSED) 1592106490Smdodd return (EINVAL); 1593106490Smdodd return mcd_play(sc, &sc->data.lastpb); 1594578Srgrimes} 1595