scd.c revision 274679
17332Sjkh/*- 27332Sjkh * Copyright (c) 1995 Mikael Hybsch 37332Sjkh * All rights reserved. 47332Sjkh * 57332Sjkh * Portions of this file are copied from mcd.c 67332Sjkh * which has the following copyrights: 77332Sjkh * 87332Sjkh * Copyright 1993 by Holger Veit (data part) 97332Sjkh * Copyright 1993 by Brian Moore (audio part) 107332Sjkh * Changes Copyright 1993 by Gary Clark II 117332Sjkh * Changes Copyright (C) 1994 by Andrew A. Chernov 127332Sjkh * 137332Sjkh * Rewrote probe routine to work on newer Mitsumi drives. 147332Sjkh * Additional changes (C) 1994 by Jordan K. Hubbard 157332Sjkh * 167332Sjkh * All rights reserved. 177332Sjkh * 187332Sjkh * Redistribution and use in source and binary forms, with or without 197332Sjkh * modification, are permitted provided that the following conditions 207332Sjkh * are met: 217332Sjkh * 1. Redistributions of source code must retain the above copyright 227332Sjkh * notice, this list of conditions and the following disclaimer 237332Sjkh * in this position and unchanged. 247332Sjkh * 2. Redistributions in binary form must reproduce the above copyright 257332Sjkh * notice, this list of conditions and the following disclaimer in the 267332Sjkh * documentation and/or other materials provided with the distribution. 277332Sjkh * 3. The name of the author may not be used to endorse or promote products 2897748Sschweikh * derived from this software without specific prior written permission 297332Sjkh * 307332Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 317332Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 327332Sjkh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 337332Sjkh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 347332Sjkh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 357332Sjkh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 367332Sjkh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 377332Sjkh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 387332Sjkh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 397332Sjkh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 407332Sjkh * 417332Sjkh */ 427332Sjkh 43119419Sobrien#include <sys/cdefs.h> 44119419Sobrien__FBSDID("$FreeBSD: head/sys/dev/scd/scd.c 274679 2014-11-18 22:02:37Z jhb $"); 457332Sjkh 46119419Sobrien 47106451Smdodd#undef SCD_DEBUG 487332Sjkh 497332Sjkh#include <sys/param.h> 507332Sjkh#include <sys/systm.h> 5161011Speter#include <sys/kernel.h> 527332Sjkh#include <sys/conf.h> 53106450Smdodd#include <sys/fcntl.h> 5460041Sphk#include <sys/bio.h> 557332Sjkh#include <sys/cdio.h> 56106450Smdodd#include <sys/disk.h> 5761011Speter#include <sys/bus.h> 587369Sbde 597332Sjkh#include <machine/stdarg.h> 607332Sjkh 61106449Smdodd#include <machine/bus.h> 62106449Smdodd#include <machine/resource.h> 63106449Smdodd#include <sys/rman.h> 647332Sjkh 65106449Smdodd#include <isa/isavar.h> 6612502Sjulian 67106449Smdodd#include <dev/scd/scdreg.h> 68106449Smdodd#include <dev/scd/scdvar.h> 69106449Smdodd 707332Sjkh/* flags */ 717332Sjkh#define SCDOPEN 0x0001 /* device opened */ 727332Sjkh#define SCDVALID 0x0002 /* parameters loaded */ 737332Sjkh#define SCDINIT 0x0004 /* device is init'd */ 747332Sjkh#define SCDPROBING 0x0020 /* probing */ 757332Sjkh#define SCDTOC 0x0100 /* already read toc */ 767332Sjkh#define SCDMBXBSY 0x0200 /* local mbx is busy */ 777332Sjkh#define SCDSPINNING 0x0400 /* drive is spun up */ 787332Sjkh 797332Sjkh#define SCD_S_BEGIN 0 807332Sjkh#define SCD_S_BEGIN1 1 817332Sjkh#define SCD_S_WAITSTAT 2 827332Sjkh#define SCD_S_WAITFIFO 3 837332Sjkh#define SCD_S_WAITSPIN 4 847332Sjkh#define SCD_S_WAITREAD 5 857332Sjkh#define SCD_S_WAITPARAM 6 867332Sjkh 877332Sjkh#define RDELAY_WAIT 300 887332Sjkh#define RDELAY_WAITREAD 300 897332Sjkh 907332Sjkh#define SCDBLKSIZE 2048 917332Sjkh 927332Sjkh#ifdef SCD_DEBUG 9311872Sphk static int scd_debuglevel = SCD_DEBUG; 94106449Smdodd# define XDEBUG(sc, level, fmt, args...) \ 95106449Smdodd do { \ 96106449Smdodd if (scd_debuglevel >= level) \ 97106449Smdodd device_printf(sc->dev, fmt, ## args); \ 98106449Smdodd } while (0) 997332Sjkh#else 100106449Smdodd# define XDEBUG(sc, level, fmt, args...) 1017332Sjkh#endif 1027332Sjkh 103106449Smdodd#define IS_ATTENTION(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_ATTENTION) != 0) 104106449Smdodd#define IS_BUSY(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_BUSY) != 0) 105106449Smdodd#define IS_DATA_RDY(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_DATA_READY) != 0) 106106449Smdodd#define STATUS_BIT(sc, bit) ((SCD_READ(sc, IREG_STATUS) & (bit)) != 0) 107106449Smdodd#define FSTATUS_BIT(sc, bit) ((SCD_READ(sc, IREG_FSTATUS) & (bit)) != 0) 1087332Sjkh 1097332Sjkh/* prototypes */ 1107332Sjkhstatic void hsg2msf(int hsg, bcd_t *msf); 1117332Sjkhstatic int msf2hsg(bcd_t *msf); 1127332Sjkh 113106449Smdoddstatic void process_attention(struct scd_softc *); 114106449Smdoddstatic int waitfor_status_bits(struct scd_softc *, int bits_set, int bits_clear); 115106449Smdoddstatic int send_cmd(struct scd_softc *, u_char cmd, u_int nargs, ...); 116106449Smdoddstatic void init_drive(struct scd_softc *); 117106449Smdoddstatic int spin_up(struct scd_softc *); 118106449Smdoddstatic int read_toc(struct scd_softc *); 119106449Smdoddstatic int get_result(struct scd_softc *, int result_len, u_char *result); 120106449Smdoddstatic void print_error(struct scd_softc *, int errcode); 1217332Sjkh 122106449Smdoddstatic void scd_start(struct scd_softc *); 123274679Sjhbstatic void scd_timeout(void *); 124106449Smdoddstatic void scd_doread(struct scd_softc *, int state, struct scd_mbx *mbxin); 1257332Sjkh 126106449Smdoddstatic int scd_eject(struct scd_softc *); 127106449Smdoddstatic int scd_stop(struct scd_softc *); 128106449Smdoddstatic int scd_pause(struct scd_softc *); 129106449Smdoddstatic int scd_resume(struct scd_softc *); 130106449Smdoddstatic int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt); 131106449Smdoddstatic int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf); 132106449Smdoddstatic int scd_play(struct scd_softc *, struct ioc_play_msf *msf); 133141031Ssobomaxstatic int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch, int nocopyout); 134106449Smdoddstatic int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch); 1357332Sjkh 1367332Sjkh/* for xcdplayer */ 137106449Smdoddstatic int scd_toc_header(struct scd_softc *, struct ioc_toc_header *th); 138106449Smdoddstatic int scd_toc_entrys(struct scd_softc *, struct ioc_read_toc_entry *te); 139106449Smdoddstatic int scd_toc_entry(struct scd_softc *, struct ioc_read_toc_single_entry *te); 1407332Sjkh#define SCD_LASTPLUS1 170 /* don't ask, xcdplayer passes this in */ 1417332Sjkh 14212675Sjulianstatic d_open_t scdopen; 14312675Sjulianstatic d_close_t scdclose; 14412675Sjulianstatic d_ioctl_t scdioctl; 14512675Sjulianstatic d_strategy_t scdstrategy; 14612675Sjulian 14774810Sphk 14837389Sjulianstatic struct cdevsw scd_cdevsw = { 149126080Sphk .d_version = D_VERSION, 150111815Sphk .d_open = scdopen, 151111815Sphk .d_close = scdclose, 152111815Sphk .d_read = physread, 153111815Sphk .d_ioctl = scdioctl, 154111815Sphk .d_strategy = scdstrategy, 155111815Sphk .d_name = "scd", 156274679Sjhb .d_flags = D_DISK, 15747625Sphk}; 15812675Sjulian 159106449Smdoddint 160106449Smdoddscd_attach(struct scd_softc *sc) 1617332Sjkh{ 162106449Smdodd int unit; 1638876Srgrimes 164106449Smdodd unit = device_get_unit(sc->dev); 1657332Sjkh 166274679Sjhb SCD_LOCK(sc); 167106449Smdodd init_drive(sc); 1687332Sjkh 169106490Smdodd sc->data.flags = SCDINIT; 170106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 171106490Smdodd bioq_init(&sc->data.head); 172274679Sjhb SCD_UNLOCK(sc); 1737332Sjkh 174106449Smdodd sc->scd_dev_t = make_dev(&scd_cdevsw, 8 * unit, 175106449Smdodd UID_ROOT, GID_OPERATOR, 0640, "scd%d", unit); 176106449Smdodd sc->scd_dev_t->si_drv1 = (void *)sc; 177106449Smdodd 178106451Smdodd return (0); 1797332Sjkh} 1807332Sjkh 18112675Sjulianstatic int 182130585Sphkscdopen(struct cdev *dev, int flags, int fmt, struct thread *td) 1837332Sjkh{ 184106449Smdodd struct scd_softc *sc; 1857332Sjkh int rc; 1868876Srgrimes 187106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 1887332Sjkh 189274679Sjhb /* mark all open part's invalid */ 190274679Sjhb SCD_LOCK(sc); 191274679Sjhb if (sc->data.openflag) { 192274679Sjhb SCD_UNLOCK(sc); 193106451Smdodd return (ENXIO); 194274679Sjhb } 1957332Sjkh 196106449Smdodd XDEBUG(sc, 1, "DEBUG: status = 0x%x\n", SCD_READ(sc, IREG_STATUS)); 1977332Sjkh 198106449Smdodd if ((rc = spin_up(sc)) != 0) { 199106449Smdodd print_error(sc, rc); 200274679Sjhb SCD_UNLOCK(sc); 201106451Smdodd return (EIO); 2027332Sjkh } 203106490Smdodd if (!(sc->data.flags & SCDTOC)) { 2047332Sjkh int loop_count = 3; 2057332Sjkh 206106449Smdodd while (loop_count-- > 0 && (rc = read_toc(sc)) != 0) { 2077332Sjkh if (rc == ERR_NOT_SPINNING) { 208106449Smdodd rc = spin_up(sc); 2097332Sjkh if (rc) { 210274679Sjhb print_error(sc, rc); 211274679Sjhb SCD_UNLOCK(sc); 212106451Smdodd return (EIO); 2137332Sjkh } 2147332Sjkh continue; 2157332Sjkh } 216106449Smdodd device_printf(sc->dev, "TOC read error 0x%x\n", rc); 217274679Sjhb SCD_UNLOCK(sc); 218106451Smdodd return (EIO); 2197332Sjkh } 2207332Sjkh } 2217332Sjkh 222106490Smdodd sc->data.openflag = 1; 223106490Smdodd sc->data.flags |= SCDVALID; 224274679Sjhb SCD_UNLOCK(sc); 2257332Sjkh 226106451Smdodd return (0); 2277332Sjkh} 2287332Sjkh 22912675Sjulianstatic int 230130585Sphkscdclose(struct cdev *dev, int flags, int fmt, struct thread *td) 2317332Sjkh{ 232106449Smdodd struct scd_softc *sc; 2338876Srgrimes 234106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 2357332Sjkh 236274679Sjhb SCD_LOCK(sc); 237274679Sjhb KASSERT(sc->data.openflag, ("device not open")); 2387332Sjkh 239106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS) { 240106449Smdodd (void)send_cmd(sc, CMD_SPIN_DOWN, 0); 241106490Smdodd sc->data.flags &= ~SCDSPINNING; 2427332Sjkh } 2437332Sjkh 2447332Sjkh /* close channel */ 245106490Smdodd sc->data.openflag = 0; 246274679Sjhb SCD_UNLOCK(sc); 2477332Sjkh 248106451Smdodd return (0); 2497332Sjkh} 2507332Sjkh 25112675Sjulianstatic void 25259249Sphkscdstrategy(struct bio *bp) 2537332Sjkh{ 254106449Smdodd struct scd_softc *sc; 2557332Sjkh 256106449Smdodd sc = (struct scd_softc *)bp->bio_dev->si_drv1; 2577332Sjkh 2587332Sjkh /* if device invalidated (e.g. media change, door open), error */ 259274679Sjhb SCD_LOCK(sc); 260106490Smdodd if (!(sc->data.flags & SCDVALID)) { 261106449Smdodd device_printf(sc->dev, "media changed\n"); 26259249Sphk bp->bio_error = EIO; 2637332Sjkh goto bad; 2647332Sjkh } 2657332Sjkh 2667332Sjkh /* read only */ 26759249Sphk if (!(bp->bio_cmd == BIO_READ)) { 26859249Sphk bp->bio_error = EROFS; 2697332Sjkh goto bad; 2707332Sjkh } 2718876Srgrimes 2727332Sjkh /* no data to read */ 27359249Sphk if (bp->bio_bcount == 0) 2747332Sjkh goto done; 2758876Srgrimes 276106490Smdodd if (!(sc->data.flags & SCDTOC)) { 27759249Sphk bp->bio_error = EIO; 2787332Sjkh goto bad; 2797332Sjkh } 2807332Sjkh 28159249Sphk bp->bio_resid = 0; 2828876Srgrimes 2837332Sjkh /* queue it */ 284112946Sphk bioq_disksort(&sc->data.head, bp); 2858876Srgrimes 2867332Sjkh /* now check whether we can perform processing */ 287106449Smdodd scd_start(sc); 288274679Sjhb SCD_UNLOCK(sc); 2897332Sjkh return; 2907332Sjkh 2917332Sjkhbad: 29259249Sphk bp->bio_flags |= BIO_ERROR; 2937332Sjkhdone: 294274679Sjhb SCD_UNLOCK(sc); 29559249Sphk bp->bio_resid = bp->bio_bcount; 2967332Sjkh biodone(bp); 2977332Sjkh return; 2987332Sjkh} 2997332Sjkh 3007332Sjkhstatic void 301106449Smdoddscd_start(struct scd_softc *sc) 3027332Sjkh{ 30359249Sphk struct bio *bp; 3048876Srgrimes 305274679Sjhb SCD_ASSERT_LOCKED(sc); 306274679Sjhb if (sc->data.flags & SCDMBXBSY) 3077332Sjkh return; 3087332Sjkh 309137046Sphk bp = bioq_takefirst(&sc->data.head); 31015574Sphk if (bp != 0) { 3117332Sjkh /* block found to process, dequeue */ 312106490Smdodd sc->data.flags |= SCDMBXBSY; 3137332Sjkh } else { 3147332Sjkh /* nothing to do */ 3157332Sjkh return; 3167332Sjkh } 3177332Sjkh 318106490Smdodd sc->data.mbx.retry = 3; 319106490Smdodd sc->data.mbx.bp = bp; 3207332Sjkh 321106490Smdodd scd_doread(sc, SCD_S_BEGIN, &(sc->data.mbx)); 3227332Sjkh return; 3237332Sjkh} 3247332Sjkh 32512675Sjulianstatic int 326130585Sphkscdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 3277332Sjkh{ 328106449Smdodd struct scd_softc *sc; 329274679Sjhb int error; 3308876Srgrimes 331106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 3327332Sjkh 333106449Smdodd XDEBUG(sc, 1, "ioctl: cmd=0x%lx\n", cmd); 3347332Sjkh 335274679Sjhb SCD_LOCK(sc); 336274679Sjhb if (!(sc->data.flags & SCDVALID)) { 337274679Sjhb SCD_UNLOCK(sc); 338106451Smdodd return (EIO); 339274679Sjhb } 3407332Sjkh 341274679Sjhb error = 0; 3427332Sjkh switch (cmd) { 343106450Smdodd case DIOCGMEDIASIZE: 344106490Smdodd *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; 345106450Smdodd break; 346106450Smdodd case DIOCGSECTORSIZE: 347106490Smdodd *(u_int *)addr = sc->data.blksize; 348106450Smdodd break; 3497332Sjkh case CDIOCPLAYTRACKS: 350274679Sjhb error = scd_playtracks(sc, (struct ioc_play_track *) addr); 351274679Sjhb break; 3527332Sjkh case CDIOCPLAYBLOCKS: 353274679Sjhb error = EINVAL; 354274679Sjhb break; 3557332Sjkh case CDIOCPLAYMSF: 356274679Sjhb error = scd_playmsf(sc, (struct ioc_play_msf *) addr); 357274679Sjhb break; 358141031Ssobomax case CDIOCREADSUBCHANNEL_SYSSPACE: 359141031Ssobomax return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); 3607332Sjkh case CDIOCREADSUBCHANNEL: 361141031Ssobomax return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); 3627332Sjkh case CDIOREADTOCHEADER: 363274679Sjhb error = scd_toc_header (sc, (struct ioc_toc_header *) addr); 364274679Sjhb break; 3657332Sjkh case CDIOREADTOCENTRYS: 366106449Smdodd return scd_toc_entrys (sc, (struct ioc_read_toc_entry*) addr); 36725460Sjoerg case CDIOREADTOCENTRY: 368274679Sjhb error = scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr); 369274679Sjhb break; 3707332Sjkh case CDIOCSETPATCH: 3717332Sjkh case CDIOCGETVOL: 3727332Sjkh case CDIOCSETVOL: 3737332Sjkh case CDIOCSETMONO: 3747332Sjkh case CDIOCSETSTERIO: 3757332Sjkh case CDIOCSETMUTE: 3767332Sjkh case CDIOCSETLEFT: 3777332Sjkh case CDIOCSETRIGHT: 378274679Sjhb error = EINVAL; 379274679Sjhb break; 3807332Sjkh case CDIOCRESUME: 381274679Sjhb error = scd_resume(sc); 382274679Sjhb break; 3837332Sjkh case CDIOCPAUSE: 384274679Sjhb error = scd_pause(sc); 385274679Sjhb break; 3867332Sjkh case CDIOCSTART: 387274679Sjhb error = EINVAL; 388274679Sjhb break; 3897332Sjkh case CDIOCSTOP: 390274679Sjhb error = scd_stop(sc); 391274679Sjhb break; 3927332Sjkh case CDIOCEJECT: 393274679Sjhb error = scd_eject(sc); 394274679Sjhb break; 3957332Sjkh case CDIOCALLOW: 396274679Sjhb break; 3977332Sjkh case CDIOCSETDEBUG: 3987332Sjkh#ifdef SCD_DEBUG 3997332Sjkh scd_debuglevel++; 4007332Sjkh#endif 401274679Sjhb break; 4027332Sjkh case CDIOCCLRDEBUG: 4037332Sjkh#ifdef SCD_DEBUG 4047332Sjkh scd_debuglevel = 0; 4057332Sjkh 4067332Sjkh#endif 407274679Sjhb break; 4087332Sjkh default: 409106449Smdodd device_printf(sc->dev, "unsupported ioctl (cmd=0x%lx)\n", cmd); 410274679Sjhb error = ENOTTY; 411274679Sjhb break; 4127332Sjkh } 413274679Sjhb SCD_UNLOCK(sc); 414274679Sjhb return (error); 4157332Sjkh} 4167332Sjkh 4177332Sjkh/*************************************************************** 4187332Sjkh * lower level of driver starts here 4197332Sjkh **************************************************************/ 4207332Sjkh 4217332Sjkhstatic int 422106449Smdoddscd_playtracks(struct scd_softc *sc, struct ioc_play_track *pt) 4237332Sjkh{ 4247332Sjkh struct ioc_play_msf msf; 4257332Sjkh int a = pt->start_track; 4267332Sjkh int z = pt->end_track; 42711872Sphk int rc; 4287332Sjkh 429106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 4307332Sjkh if (rc == -ERR_NOT_SPINNING) { 431106449Smdodd if (spin_up(sc) != 0) 432106451Smdodd return (EIO); 433106449Smdodd rc = read_toc(sc); 4347332Sjkh } 4357332Sjkh if (rc != 0) { 436106449Smdodd print_error(sc, rc); 437106451Smdodd return (EIO); 4387332Sjkh } 4397332Sjkh } 4407332Sjkh 441106449Smdodd XDEBUG(sc, 1, "playtracks from %d:%d to %d:%d\n", 442106449Smdodd a, pt->start_index, z, pt->end_index); 4437332Sjkh 444106490Smdodd if ( a < sc->data.first_track 445106490Smdodd || a > sc->data.last_track 4467332Sjkh || a > z 447106490Smdodd || z > sc->data.last_track) 448106451Smdodd return (EINVAL); 4497332Sjkh 450106490Smdodd bcopy(sc->data.toc[a].start_msf, &msf.start_m, 3); 451106490Smdodd hsg2msf(msf2hsg(sc->data.toc[z+1].start_msf)-1, &msf.end_m); 4527332Sjkh 453106449Smdodd return scd_play(sc, &msf); 4547332Sjkh} 4557332Sjkh 4567332Sjkh/* The start/end msf is expected to be in bin format */ 4577332Sjkhstatic int 458106449Smdoddscd_playmsf(struct scd_softc *sc, struct ioc_play_msf *msfin) 4597332Sjkh{ 4607332Sjkh struct ioc_play_msf msf; 4617332Sjkh 4627332Sjkh msf.start_m = bin2bcd(msfin->start_m); 4637332Sjkh msf.start_s = bin2bcd(msfin->start_s); 4647332Sjkh msf.start_f = bin2bcd(msfin->start_f); 4657332Sjkh msf.end_m = bin2bcd(msfin->end_m); 4667332Sjkh msf.end_s = bin2bcd(msfin->end_s); 4677332Sjkh msf.end_f = bin2bcd(msfin->end_f); 4687332Sjkh 469106449Smdodd return scd_play(sc, &msf); 4707332Sjkh} 4717332Sjkh 4727332Sjkh/* The start/end msf is expected to be in bcd format */ 4737332Sjkhstatic int 474106449Smdoddscd_play(struct scd_softc *sc, struct ioc_play_msf *msf) 4757332Sjkh{ 4767332Sjkh int i, rc; 4777332Sjkh 478106449Smdodd XDEBUG(sc, 1, "playing: %02x:%02x:%02x -> %02x:%02x:%02x\n", 4797332Sjkh msf->start_m, msf->start_s, msf->start_f, 480106449Smdodd msf->end_m, msf->end_s, msf->end_f); 4817332Sjkh 4827332Sjkh for (i = 0; i < 2; i++) { 483106449Smdodd rc = send_cmd(sc, CMD_PLAY_AUDIO, 7, 4847332Sjkh 0x03, 4857332Sjkh msf->start_m, msf->start_s, msf->start_f, 4867332Sjkh msf->end_m, msf->end_s, msf->end_f); 4877332Sjkh if (rc == -ERR_NOT_SPINNING) { 488106490Smdodd sc->data.flags &= ~SCDSPINNING; 489106449Smdodd if (spin_up(sc) != 0) 490106451Smdodd return (EIO); 4917332Sjkh } else if (rc < 0) { 492106449Smdodd print_error(sc, rc); 493106451Smdodd return (EIO); 4947332Sjkh } else { 4957332Sjkh break; 4967332Sjkh } 4977332Sjkh } 498106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 499106490Smdodd bcopy((char *)msf, (char *)&sc->data.last_play, sizeof(struct ioc_play_msf)); 500106451Smdodd return (0); 5017332Sjkh} 5027332Sjkh 5037332Sjkhstatic int 504106449Smdoddscd_stop(struct scd_softc *sc) 5057332Sjkh{ 5067332Sjkh 507106449Smdodd (void)send_cmd(sc, CMD_STOP_AUDIO, 0); 508106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 509106451Smdodd return (0); 5107332Sjkh} 5117332Sjkh 5127332Sjkhstatic int 513106449Smdoddscd_pause(struct scd_softc *sc) 5147332Sjkh{ 5157332Sjkh struct sony_subchannel_position_data subpos; 5167332Sjkh 517106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS) 518106451Smdodd return (EINVAL); 5197332Sjkh 520106449Smdodd if (read_subcode(sc, &subpos) != 0) 521106451Smdodd return (EIO); 5227332Sjkh 523106449Smdodd if (send_cmd(sc, CMD_STOP_AUDIO, 0) != 0) 524106451Smdodd return (EIO); 5258876Srgrimes 526106490Smdodd sc->data.last_play.start_m = subpos.abs_msf[0]; 527106490Smdodd sc->data.last_play.start_s = subpos.abs_msf[1]; 528106490Smdodd sc->data.last_play.start_f = subpos.abs_msf[2]; 529106490Smdodd sc->data.audio_status = CD_AS_PLAY_PAUSED; 5307332Sjkh 531106449Smdodd XDEBUG(sc, 1, "pause @ %02x:%02x:%02x\n", 532106490Smdodd sc->data.last_play.start_m, 533106490Smdodd sc->data.last_play.start_s, 534106490Smdodd sc->data.last_play.start_f); 5357332Sjkh 536106451Smdodd return (0); 5377332Sjkh} 5387332Sjkh 5397332Sjkhstatic int 540106449Smdoddscd_resume(struct scd_softc *sc) 5417332Sjkh{ 542106449Smdodd 543106449Smdodd if (sc->data.audio_status != CD_AS_PLAY_PAUSED) 544106451Smdodd return (EINVAL); 545106449Smdodd return scd_play(sc, &sc->data.last_play); 5467332Sjkh} 5477332Sjkh 5487332Sjkhstatic int 549106449Smdoddscd_eject(struct scd_softc *sc) 5507332Sjkh{ 5517332Sjkh 552106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 553106490Smdodd sc->data.flags &= ~(SCDSPINNING|SCDTOC); 5547332Sjkh 555106449Smdodd if (send_cmd(sc, CMD_STOP_AUDIO, 0) != 0 || 556106449Smdodd send_cmd(sc, CMD_SPIN_DOWN, 0) != 0 || 557106449Smdodd send_cmd(sc, CMD_EJECT, 0) != 0) 5587332Sjkh { 559106451Smdodd return (EIO); 5607332Sjkh } 561106451Smdodd return (0); 5627332Sjkh} 5637332Sjkh 5647332Sjkhstatic int 565141031Ssobomaxscd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) 5667332Sjkh{ 5677332Sjkh struct sony_subchannel_position_data q; 5687332Sjkh struct cd_sub_channel_info data; 5697332Sjkh 570106449Smdodd XDEBUG(sc, 1, "subchan af=%d, df=%d\n", 571106449Smdodd sch->address_format, sch->data_format); 5727332Sjkh 573106449Smdodd if (sch->address_format != CD_MSF_FORMAT) 574106451Smdodd return (EINVAL); 5757332Sjkh 576106449Smdodd if (sch->data_format != CD_CURRENT_POSITION) 577106451Smdodd return (EINVAL); 5787332Sjkh 579106449Smdodd if (read_subcode(sc, &q) != 0) 580106451Smdodd return (EIO); 5817332Sjkh 582106490Smdodd data.header.audio_status = sc->data.audio_status; 5837332Sjkh data.what.position.data_format = CD_MSF_FORMAT; 5847332Sjkh data.what.position.track_number = bcd2bin(q.track_number); 5857332Sjkh data.what.position.reladdr.msf.unused = 0; 5867332Sjkh data.what.position.reladdr.msf.minute = bcd2bin(q.rel_msf[0]); 5877332Sjkh data.what.position.reladdr.msf.second = bcd2bin(q.rel_msf[1]); 5887332Sjkh data.what.position.reladdr.msf.frame = bcd2bin(q.rel_msf[2]); 5897332Sjkh data.what.position.absaddr.msf.unused = 0; 5907332Sjkh data.what.position.absaddr.msf.minute = bcd2bin(q.abs_msf[0]); 5917332Sjkh data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1]); 5927332Sjkh data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2]); 593274679Sjhb SCD_UNLOCK(sc); 5947332Sjkh 595141031Ssobomax if (nocopyout == 0) { 596141031Ssobomax if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) 597141031Ssobomax return (EFAULT); 598141031Ssobomax } else { 599141031Ssobomax bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); 600141031Ssobomax } 601106451Smdodd return (0); 6027332Sjkh} 6037332Sjkh 604106449Smdoddint 605106449Smdoddscd_probe(struct scd_softc *sc) 60642552Seivind{ 6077332Sjkh struct sony_drive_configuration drive_config; 6087332Sjkh int rc; 6097332Sjkh static char namebuf[8+16+8+3]; 6107332Sjkh char *s = namebuf; 6117332Sjkh int loop_count = 0; 6127332Sjkh 613106490Smdodd sc->data.flags = SCDPROBING; 6147332Sjkh 6157332Sjkh bzero(&drive_config, sizeof(drive_config)); 6167332Sjkh 6177332Sjkhagain: 6187332Sjkh /* Reset drive */ 619106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESET_DRIVE); 6207332Sjkh 6217332Sjkh /* Calm down */ 6227332Sjkh DELAY(300000); 6237332Sjkh 6247332Sjkh /* Only the ATTENTION bit may be set */ 625106449Smdodd if ((SCD_READ(sc, IREG_STATUS) & ~1) != 0) { 626106449Smdodd XDEBUG(sc, 1, "too many bits set. probe failed.\n"); 627106449Smdodd return (ENXIO); 6287332Sjkh } 629106449Smdodd rc = send_cmd(sc, CMD_GET_DRIVE_CONFIG, 0); 6307332Sjkh if (rc != sizeof(drive_config)) { 6317332Sjkh /* Sometimes if the drive is playing audio I get */ 6327332Sjkh /* the bad result 82. Fix by repeating the reset */ 6337332Sjkh if (rc > 0 && loop_count++ == 0) 6347332Sjkh goto again; 635106449Smdodd return (ENXIO); 6367332Sjkh } 637106449Smdodd if (get_result(sc, rc, (u_char *)&drive_config) != 0) 638106449Smdodd return (ENXIO); 6397332Sjkh 6407332Sjkh bcopy(drive_config.vendor, namebuf, 8); 6417332Sjkh s = namebuf+8; 6427332Sjkh while (*(s-1) == ' ') /* Strip trailing spaces */ 6437332Sjkh s--; 6447332Sjkh *s++ = ' '; 6457332Sjkh bcopy(drive_config.product, s, 16); 6467332Sjkh s += 16; 6477332Sjkh while (*(s-1) == ' ') 6487332Sjkh s--; 6497332Sjkh *s++ = ' '; 6507332Sjkh bcopy(drive_config.revision, s, 8); 6517332Sjkh s += 8; 6527332Sjkh while (*(s-1) == ' ') 6537332Sjkh s--; 6547332Sjkh *s = 0; 6557332Sjkh 656106490Smdodd sc->data.name = namebuf; 6577332Sjkh 6587332Sjkh if (drive_config.config & 0x10) 659106490Smdodd sc->data.double_speed = 1; 6607332Sjkh else 661106490Smdodd sc->data.double_speed = 0; 6627332Sjkh 663106449Smdodd return (0); 6647332Sjkh} 6657332Sjkh 6667332Sjkhstatic int 667106449Smdoddread_subcode(struct scd_softc *sc, struct sony_subchannel_position_data *scp) 6687332Sjkh{ 6697332Sjkh int rc; 6707332Sjkh 671106449Smdodd rc = send_cmd(sc, CMD_GET_SUBCHANNEL_DATA, 0); 672106449Smdodd if (rc < 0 || rc < sizeof(*scp)) 673106451Smdodd return (EIO); 674106449Smdodd if (get_result(sc, rc, (u_char *)scp) != 0) 675106451Smdodd return (EIO); 676106451Smdodd return (0); 6777332Sjkh} 6787332Sjkh 6797332Sjkh/* State machine copied from mcd.c */ 6807332Sjkh 6817332Sjkh/* This (and the code in mcd.c) will not work with more than one drive */ 682106449Smdodd/* because there is only one sc->ch_mbxsave below. Should fix that some day. */ 683106449Smdodd/* (sc->ch_mbxsave & state should probably be included in the scd_data struct and */ 6847332Sjkh/* the unit number used as first argument to scd_doread().) /Micke */ 6857332Sjkh 6867332Sjkh/* state machine to process read requests 6877332Sjkh * initialize with SCD_S_BEGIN: reset state machine 6887332Sjkh * SCD_S_WAITSTAT: wait for ready (!busy) 6897332Sjkh * SCD_S_WAITSPIN: wait for drive to spin up (if not spinning) 6907332Sjkh * SCD_S_WAITFIFO: wait for param fifo to get ready, them exec. command. 6917332Sjkh * SCD_S_WAITREAD: wait for data ready, read data 6927332Sjkh * SCD_S_WAITPARAM: wait for command result params, read them, error if bad data read. 6937332Sjkh */ 6947332Sjkh 6957332Sjkhstatic void 69625056Sbdescd_timeout(void *arg) 69725056Sbde{ 698106449Smdodd struct scd_softc *sc; 699106449Smdodd sc = (struct scd_softc *)arg; 700106449Smdodd 701274679Sjhb SCD_ASSERT_LOCKED(sc); 702106449Smdodd scd_doread(sc, sc->ch_state, sc->ch_mbxsave); 70325056Sbde} 70425056Sbde 70525056Sbdestatic void 706106449Smdoddscd_doread(struct scd_softc *sc, int state, struct scd_mbx *mbxin) 7077332Sjkh{ 708106449Smdodd struct scd_mbx *mbx = (state!=SCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; 70959249Sphk struct bio *bp = mbx->bp; 710106449Smdodd int i; 7117332Sjkh int blknum; 7127332Sjkh caddr_t addr; 7137332Sjkh static char sdata[3]; /* Must be preserved between calls to this function */ 7147332Sjkh 715274679Sjhb SCD_ASSERT_LOCKED(sc); 7167332Sjkhloop: 7177332Sjkh switch (state) { 7187332Sjkh case SCD_S_BEGIN: 719106449Smdodd mbx = sc->ch_mbxsave = mbxin; 7207332Sjkh 7217332Sjkh case SCD_S_BEGIN1: 7227332Sjkh /* get status */ 7237332Sjkh mbx->count = RDELAY_WAIT; 7247332Sjkh 725106449Smdodd process_attention(sc); 7267332Sjkh goto trystat; 7277332Sjkh 7287332Sjkh case SCD_S_WAITSTAT: 729106449Smdodd sc->ch_state = SCD_S_WAITSTAT; 730274679Sjhb callout_stop(&sc->timer); 7317332Sjkh if (mbx->count-- <= 0) { 732106449Smdodd device_printf(sc->dev, "timeout. drive busy.\n"); 7337332Sjkh goto harderr; 7347332Sjkh } 7357332Sjkh 7367332Sjkhtrystat: 737106449Smdodd if (IS_BUSY(sc)) { 738106449Smdodd sc->ch_state = SCD_S_WAITSTAT; 739274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 7407332Sjkh return; 7417332Sjkh } 7428876Srgrimes 743106449Smdodd process_attention(sc); 7447332Sjkh 7457332Sjkh /* reject, if audio active */ 746106490Smdodd if (sc->data.audio_status & CD_AS_PLAY_IN_PROGRESS) { 747106449Smdodd device_printf(sc->dev, "audio is active\n"); 7487332Sjkh goto harderr; 7497332Sjkh } 7507332Sjkh 751106490Smdodd mbx->sz = sc->data.blksize; 7527332Sjkh 7537332Sjkh /* for first block */ 75459249Sphk mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; 7557332Sjkh mbx->skip = 0; 7567332Sjkh 7577332Sjkhnextblock: 758106490Smdodd if (!(sc->data.flags & SCDVALID)) 7597332Sjkh goto changed; 7607332Sjkh 761121212Sphk blknum = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz; 7627332Sjkh 763106449Smdodd XDEBUG(sc, 2, "scd_doread: read blknum=%d\n", blknum); 7647332Sjkh 7657332Sjkh /* build parameter block */ 7667332Sjkh hsg2msf(blknum, sdata); 7677332Sjkh 768106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 769106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR); 770106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR); 7717332Sjkh 772106449Smdodd if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)) 7737332Sjkh goto writeparam; 7747332Sjkh 7757332Sjkh mbx->count = 100; 776106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 777274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 7787332Sjkh return; 7797332Sjkh 7807332Sjkh case SCD_S_WAITSPIN: 781106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 782274679Sjhb callout_stop(&sc->timer); 7837332Sjkh if (mbx->count-- <= 0) { 784106449Smdodd device_printf(sc->dev, "timeout waiting for drive to spin up.\n"); 7857332Sjkh goto harderr; 7867332Sjkh } 787106449Smdodd if (!STATUS_BIT(sc, SBIT_RESULT_READY)) { 788106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 789274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 7907332Sjkh return; 7917332Sjkh } 792106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 793106449Smdodd switch ((i = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 7947332Sjkh case 0x20: 795106449Smdodd i = SCD_READ(sc, IREG_RESULT); 796106449Smdodd print_error(sc, i); 7977332Sjkh goto harderr; 7987332Sjkh case 0x00: 799106449Smdodd (void)SCD_READ(sc, IREG_RESULT); 800106490Smdodd sc->data.flags |= SCDSPINNING; 8017332Sjkh break; 8027332Sjkh } 803106449Smdodd XDEBUG(sc, 1, "DEBUG: spin up complete\n"); 8047332Sjkh 8057332Sjkh state = SCD_S_BEGIN1; 8067332Sjkh goto loop; 8077332Sjkh 8087332Sjkh case SCD_S_WAITFIFO: 809106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 810274679Sjhb callout_stop(&sc->timer); 8117332Sjkh if (mbx->count-- <= 0) { 812106449Smdodd device_printf(sc->dev, "timeout. write param not ready.\n"); 8137332Sjkh goto harderr; 8147332Sjkh } 815106449Smdodd if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)) { 816106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 817274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 8187332Sjkh return; 8197332Sjkh } 820106449Smdodd XDEBUG(sc, 1, "mbx->count (writeparamwait) = %d(%d)\n", mbx->count, 100); 8217332Sjkh 8227332Sjkhwriteparam: 8237332Sjkh /* The reason this test isn't done 'till now is to make sure */ 8247332Sjkh /* that it is ok to send the SPIN_UP cmd below. */ 825106490Smdodd if (!(sc->data.flags & SCDSPINNING)) { 826106449Smdodd XDEBUG(sc, 1, "spinning up drive ...\n"); 827106449Smdodd SCD_WRITE(sc, OREG_COMMAND, CMD_SPIN_UP); 8287332Sjkh mbx->count = 300; 829106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 830274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 8317332Sjkh return; 8327332Sjkh } 8337332Sjkh 8347332Sjkh /* send the read command */ 835106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[0]); 836106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[1]); 837106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[2]); 838106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 0); 839106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 0); 840106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 1); 841106449Smdodd SCD_WRITE(sc, OREG_COMMAND, CMD_READ); 8427332Sjkh 8437332Sjkh mbx->count = RDELAY_WAITREAD; 8447332Sjkh for (i = 0; i < 50; i++) { 845106449Smdodd if (STATUS_BIT(sc, SBIT_DATA_READY)) 8467332Sjkh goto got_data; 8477332Sjkh DELAY(100); 8487332Sjkh } 8497332Sjkh 850106449Smdodd sc->ch_state = SCD_S_WAITREAD; 851274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 8527332Sjkh return; 8537332Sjkh 8547332Sjkh case SCD_S_WAITREAD: 855106449Smdodd sc->ch_state = SCD_S_WAITREAD; 856274679Sjhb callout_stop(&sc->timer); 8577332Sjkh if (mbx->count-- <= 0) { 858106449Smdodd if (STATUS_BIT(sc, SBIT_RESULT_READY)) 8597332Sjkh goto got_param; 860106449Smdodd device_printf(sc->dev, "timeout while reading data\n"); 8617332Sjkh goto readerr; 8627332Sjkh } 863106449Smdodd if (!STATUS_BIT(sc, SBIT_DATA_READY)) { 864106449Smdodd process_attention(sc); 865106490Smdodd if (!(sc->data.flags & SCDVALID)) 8667332Sjkh goto changed; 867106449Smdodd sc->ch_state = SCD_S_WAITREAD; 868274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 8697332Sjkh return; 8707332Sjkh } 871106449Smdodd XDEBUG(sc, 2, "mbx->count (after RDY_BIT) = %d(%d)\n", mbx->count, RDELAY_WAITREAD); 8727332Sjkh 8737332Sjkhgot_data: 8747332Sjkh /* data is ready */ 87559249Sphk addr = bp->bio_data + mbx->skip; 876106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR); 877106449Smdodd SCD_READ_MULTI(sc, IREG_DATA, addr, mbx->sz); 8787332Sjkh 8797332Sjkh mbx->count = 100; 8807332Sjkh for (i = 0; i < 20; i++) { 881106449Smdodd if (STATUS_BIT(sc, SBIT_RESULT_READY)) 8827332Sjkh goto waitfor_param; 8837332Sjkh DELAY(100); 8847332Sjkh } 8857332Sjkh goto waitfor_param; 8867332Sjkh 8877332Sjkh case SCD_S_WAITPARAM: 888106449Smdodd sc->ch_state = SCD_S_WAITPARAM; 889274679Sjhb callout_stop(&sc->timer); 8907332Sjkh if (mbx->count-- <= 0) { 891106449Smdodd device_printf(sc->dev, "timeout waiting for params\n"); 8927332Sjkh goto readerr; 8937332Sjkh } 8947332Sjkh 8957332Sjkhwaitfor_param: 896106449Smdodd if (!STATUS_BIT(sc, SBIT_RESULT_READY)) { 897106449Smdodd sc->ch_state = SCD_S_WAITPARAM; 898274679Sjhb callout_reset(&sc->timer, hz / 100, scd_timeout, sc); /* XXX */ 8997332Sjkh return; 9007332Sjkh } 901106451Smdodd#ifdef SCD_DEBUG 9027332Sjkh if (mbx->count < 100 && scd_debuglevel > 0) 903106449Smdodd device_printf(sc->dev, "mbx->count (paramwait) = %d(%d)\n", mbx->count, 100); 9047332Sjkh#endif 9057332Sjkh 9067332Sjkhgot_param: 907106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 908106449Smdodd switch ((i = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 9097332Sjkh case 0x50: 9107332Sjkh switch (i) { 9117332Sjkh case ERR_FATAL_READ_ERROR1: 9127332Sjkh case ERR_FATAL_READ_ERROR2: 913106449Smdodd device_printf(sc->dev, "unrecoverable read error 0x%x\n", i); 9147332Sjkh goto harderr; 9157332Sjkh } 9167332Sjkh break; 9177332Sjkh case 0x20: 918106449Smdodd i = SCD_READ(sc, IREG_RESULT); 9197332Sjkh switch (i) { 9207332Sjkh case ERR_NOT_SPINNING: 921106449Smdodd XDEBUG(sc, 1, "read error: drive not spinning\n"); 9227332Sjkh if (mbx->retry-- > 0) { 9237332Sjkh state = SCD_S_BEGIN1; 924106490Smdodd sc->data.flags &= ~SCDSPINNING; 9257332Sjkh goto loop; 9267332Sjkh } 9277332Sjkh goto harderr; 9287332Sjkh default: 929106449Smdodd print_error(sc, i); 9307332Sjkh goto readerr; 9317332Sjkh } 9327332Sjkh case 0x00: 933106449Smdodd i = SCD_READ(sc, IREG_RESULT); 9347332Sjkh break; 9357332Sjkh } 9367332Sjkh 9377332Sjkh if (--mbx->nblk > 0) { 9387332Sjkh mbx->skip += mbx->sz; 9397332Sjkh goto nextblock; 9407332Sjkh } 9417332Sjkh 9427332Sjkh /* return buffer */ 94359249Sphk bp->bio_resid = 0; 9447332Sjkh biodone(bp); 9457332Sjkh 946106490Smdodd sc->data.flags &= ~SCDMBXBSY; 947106449Smdodd scd_start(sc); 9487332Sjkh return; 9497332Sjkh } 9507332Sjkh 9517332Sjkhreaderr: 9527332Sjkh if (mbx->retry-- > 0) { 953106449Smdodd device_printf(sc->dev, "retrying ...\n"); 9547332Sjkh state = SCD_S_BEGIN1; 9557332Sjkh goto loop; 9567332Sjkh } 9577332Sjkhharderr: 9587332Sjkh /* invalidate the buffer */ 95959249Sphk bp->bio_error = EIO; 96059249Sphk bp->bio_flags |= BIO_ERROR; 96159249Sphk bp->bio_resid = bp->bio_bcount; 9627332Sjkh biodone(bp); 9637332Sjkh 964106490Smdodd sc->data.flags &= ~SCDMBXBSY; 965106449Smdodd scd_start(sc); 9667332Sjkh return; 9677332Sjkh 9687332Sjkhchanged: 969106449Smdodd device_printf(sc->dev, "media changed\n"); 9707332Sjkh goto harderr; 9717332Sjkh} 9727332Sjkh 9737332Sjkhstatic void 9747332Sjkhhsg2msf(int hsg, bcd_t *msf) 9757332Sjkh{ 976106490Smdodd 9777332Sjkh hsg += 150; 9787332Sjkh M_msf(msf) = bin2bcd(hsg / 4500); 9797332Sjkh hsg %= 4500; 9807332Sjkh S_msf(msf) = bin2bcd(hsg / 75); 9817332Sjkh F_msf(msf) = bin2bcd(hsg % 75); 9827332Sjkh} 9837332Sjkh 9847332Sjkhstatic int 9857332Sjkhmsf2hsg(bcd_t *msf) 9867332Sjkh{ 987106490Smdodd 9887332Sjkh return (bcd2bin(M_msf(msf)) * 60 + 9897332Sjkh bcd2bin(S_msf(msf))) * 75 + 9907332Sjkh bcd2bin(F_msf(msf)) - 150; 9917332Sjkh} 9927332Sjkh 9937332Sjkhstatic void 994106449Smdoddprocess_attention(struct scd_softc *sc) 9957332Sjkh{ 9967332Sjkh unsigned char code; 9977332Sjkh int count = 0; 9987332Sjkh 999106449Smdodd while (IS_ATTENTION(sc) && count++ < 30) { 1000106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_ATTENTION_CLEAR); 1001106449Smdodd code = SCD_READ(sc, IREG_RESULT); 10027332Sjkh 1003106451Smdodd#ifdef SCD_DEBUG 10047332Sjkh if (scd_debuglevel > 0) { 10057332Sjkh if (count == 1) 1006106449Smdodd device_printf(sc->dev, "DEBUG: ATTENTIONS = 0x%x", code); 10077332Sjkh else 10087332Sjkh printf(",0x%x", code); 10097332Sjkh } 10107332Sjkh#endif 10117332Sjkh 10127332Sjkh switch (code) { 10137332Sjkh case ATTEN_SPIN_DOWN: 1014106449Smdodd sc->data.flags &= ~SCDSPINNING; 10157332Sjkh break; 10167332Sjkh 10177332Sjkh case ATTEN_SPIN_UP_DONE: 1018106449Smdodd sc->data.flags |= SCDSPINNING; 10197332Sjkh break; 10207332Sjkh 10217332Sjkh case ATTEN_AUDIO_DONE: 1022106449Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 10237332Sjkh break; 10247332Sjkh 10257332Sjkh case ATTEN_DRIVE_LOADED: 1026106449Smdodd sc->data.flags &= ~(SCDTOC|SCDSPINNING|SCDVALID); 1027106449Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 10287332Sjkh break; 10297332Sjkh 10307332Sjkh case ATTEN_EJECT_PUSHED: 1031106449Smdodd sc->data.flags &= ~SCDVALID; 10327332Sjkh break; 10337332Sjkh } 10347332Sjkh DELAY(100); 10357332Sjkh } 1036106451Smdodd#ifdef SCD_DEBUG 10377332Sjkh if (scd_debuglevel > 0 && count > 0) 10387332Sjkh printf("\n"); 10397332Sjkh#endif 10407332Sjkh} 10417332Sjkh 10427332Sjkh/* Returns 0 OR sony error code */ 10437332Sjkhstatic int 1044106449Smdoddspin_up(struct scd_softc *sc) 10457332Sjkh{ 10467332Sjkh unsigned char res_reg[12]; 10477332Sjkh unsigned int res_size; 10487332Sjkh int rc; 10497332Sjkh int loop_count = 0; 10507332Sjkh 10517332Sjkhagain: 1052106449Smdodd rc = send_cmd(sc, CMD_SPIN_UP, 0, 0, res_reg, &res_size); 10537332Sjkh if (rc != 0) { 1054106449Smdodd XDEBUG(sc, 2, "CMD_SPIN_UP error 0x%x\n", rc); 1055106451Smdodd return (rc); 10567332Sjkh } 10577332Sjkh 1058106449Smdodd if (!(sc->data.flags & SCDTOC)) { 1059106449Smdodd rc = send_cmd(sc, CMD_READ_TOC, 0); 10607332Sjkh if (rc == ERR_NOT_SPINNING) { 10617332Sjkh if (loop_count++ < 3) 10627332Sjkh goto again; 1063106451Smdodd return (rc); 10647332Sjkh } 10657332Sjkh if (rc != 0) 1066106451Smdodd return (rc); 10677332Sjkh } 10687332Sjkh 1069106449Smdodd sc->data.flags |= SCDSPINNING; 10707332Sjkh 1071106451Smdodd return (0); 10727332Sjkh} 10737332Sjkh 10747332Sjkhstatic struct sony_tracklist * 10757332Sjkhget_tl(struct sony_toc *toc, int size) 10767332Sjkh{ 10777332Sjkh struct sony_tracklist *tl = &toc->tracks[0]; 10787332Sjkh 10797332Sjkh if (tl->track != 0xb0) 1080106451Smdodd return (tl); 10818876Srgrimes if (tl->track != 0xb1) 1082106451Smdodd return (tl); 1083132771Skan tl = (struct sony_tracklist *)((char *)tl + 9); 10848876Srgrimes if (tl->track != 0xb2) 1085106451Smdodd return (tl); 1086132771Skan tl = (struct sony_tracklist *)((char *)tl + 9); 10878876Srgrimes if (tl->track != 0xb3) 1088106451Smdodd return (tl); 1089132771Skan tl = (struct sony_tracklist *)((char *)tl + 9); 10908876Srgrimes if (tl->track != 0xb4) 1091106451Smdodd return (tl); 1092132771Skan tl = (struct sony_tracklist *)((char *)tl + 9); 10938876Srgrimes if (tl->track != 0xc0) 1094106451Smdodd return (tl); 1095132771Skan tl = (struct sony_tracklist *)((char *)tl + 9); 1096106451Smdodd return (tl); 10977332Sjkh} 10987332Sjkh 10997332Sjkhstatic int 1100106449Smdoddread_toc(struct scd_softc *sc) 11017332Sjkh{ 11027332Sjkh struct sony_toc toc; 11037332Sjkh struct sony_tracklist *tl; 11047332Sjkh int rc, i, j; 11057332Sjkh u_long first, last; 11067332Sjkh 1107106453Smdodd rc = send_cmd(sc, CMD_GET_TOC, 1, 1); 11087332Sjkh if (rc < 0) 1109106451Smdodd return (rc); 11107332Sjkh if (rc > sizeof(toc)) { 1111106449Smdodd device_printf(sc->dev, "program error: toc too large (%d)\n", rc); 1112106451Smdodd return (EIO); 11137332Sjkh } 1114106449Smdodd if (get_result(sc, rc, (u_char *)&toc) != 0) 1115106451Smdodd return (EIO); 11167332Sjkh 1117106449Smdodd XDEBUG(sc, 1, "toc read. len = %d, sizeof(toc) = %d\n", rc, sizeof(toc)); 11187332Sjkh 11197332Sjkh tl = get_tl(&toc, rc); 11207332Sjkh first = msf2hsg(tl->start_msf); 11217332Sjkh last = msf2hsg(toc.lead_out_start_msf); 1122106490Smdodd sc->data.blksize = SCDBLKSIZE; 1123106490Smdodd sc->data.disksize = last*sc->data.blksize/DEV_BSIZE; 11247332Sjkh 1125106449Smdodd XDEBUG(sc, 1, "firstsector = %ld, lastsector = %ld", first, last); 11267332Sjkh 1127106490Smdodd sc->data.first_track = bcd2bin(toc.first_track); 1128106490Smdodd sc->data.last_track = bcd2bin(toc.last_track); 1129106490Smdodd if (sc->data.last_track > (MAX_TRACKS-2)) 1130106490Smdodd sc->data.last_track = MAX_TRACKS-2; 1131106490Smdodd for (j = 0, i = sc->data.first_track; i <= sc->data.last_track; i++, j++) { 1132106490Smdodd sc->data.toc[i].adr = tl[j].adr; 1133106490Smdodd sc->data.toc[i].ctl = tl[j].ctl; /* for xcdplayer */ 1134106490Smdodd bcopy(tl[j].start_msf, sc->data.toc[i].start_msf, 3); 11357332Sjkh#ifdef SCD_DEBUG 11367332Sjkh if (scd_debuglevel > 0) { 1137106449Smdodd if ((j % 3) == 0) { 1138106449Smdodd printf("\n"); 1139106449Smdodd device_printf(sc->dev, "tracks "); 1140106449Smdodd } 11417332Sjkh printf("[%03d: %2d %2d %2d] ", i, 1142106490Smdodd bcd2bin(sc->data.toc[i].start_msf[0]), 1143106490Smdodd bcd2bin(sc->data.toc[i].start_msf[1]), 1144106490Smdodd bcd2bin(sc->data.toc[i].start_msf[2])); 11457332Sjkh } 11467332Sjkh#endif 11477332Sjkh } 1148106490Smdodd bcopy(toc.lead_out_start_msf, sc->data.toc[sc->data.last_track+1].start_msf, 3); 11497332Sjkh#ifdef SCD_DEBUG 11507332Sjkh if (scd_debuglevel > 0) { 1151106490Smdodd i = sc->data.last_track+1; 11527332Sjkh printf("[END: %2d %2d %2d]\n", 1153106490Smdodd bcd2bin(sc->data.toc[i].start_msf[0]), 1154106490Smdodd bcd2bin(sc->data.toc[i].start_msf[1]), 1155106490Smdodd bcd2bin(sc->data.toc[i].start_msf[2])); 11567332Sjkh } 11577332Sjkh#endif 11587332Sjkh 1159106490Smdodd sc->data.flags |= SCDTOC; 11607332Sjkh 1161106451Smdodd return (0); 11627332Sjkh} 11637332Sjkh 11647332Sjkhstatic void 1165106449Smdoddinit_drive(struct scd_softc *sc) 11667332Sjkh{ 11677332Sjkh int rc; 11687332Sjkh 1169106449Smdodd rc = send_cmd(sc, CMD_SET_DRIVE_PARAM, 2, 1170106449Smdodd 0x05, 0x03 | ((sc->data.double_speed) ? 0x04: 0)); 11717332Sjkh if (rc != 0) 1172106449Smdodd device_printf(sc->dev, "Unable to set parameters. Errcode = 0x%x\n", rc); 11737332Sjkh} 11747332Sjkh 11757332Sjkh/* Returns 0 or errno */ 11767332Sjkhstatic int 1177106449Smdoddget_result(struct scd_softc *sc, int result_len, u_char *result) 11787332Sjkh{ 11797332Sjkh int loop_index = 2; /* send_cmd() reads two bytes ... */ 11807332Sjkh 1181106449Smdodd XDEBUG(sc, 1, "DEBUG: get_result: bytes=%d\n", result_len); 11827332Sjkh 11837332Sjkh while (result_len-- > 0) { 11847332Sjkh if (loop_index++ >= 10) { 11857332Sjkh loop_index = 1; 1186106449Smdodd if (waitfor_status_bits(sc, SBIT_RESULT_READY, 0)) 1187106451Smdodd return (EIO); 1188106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 11897332Sjkh } 11907332Sjkh if (result) 1191106449Smdodd *result++ = SCD_READ(sc, IREG_RESULT); 11927332Sjkh else 1193106449Smdodd (void)SCD_READ(sc, IREG_RESULT); 11947332Sjkh } 1195106451Smdodd return (0); 11967332Sjkh} 11977332Sjkh 11987332Sjkh/* Returns -0x100 for timeout, -(drive error code) OR number of result bytes */ 11997332Sjkhstatic int 1200106449Smdoddsend_cmd(struct scd_softc *sc, u_char cmd, u_int nargs, ...) 12017332Sjkh{ 12027332Sjkh va_list ap; 12037332Sjkh u_char c; 12047332Sjkh int rc; 12057332Sjkh int i; 12067332Sjkh 1207106449Smdodd if (waitfor_status_bits(sc, 0, SBIT_BUSY)) { 1208106449Smdodd device_printf(sc->dev, "drive busy\n"); 1209106451Smdodd return (-0x100); 12107332Sjkh } 12117332Sjkh 1212106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: cmd=0x%x nargs=%d", cmd, nargs); 12137332Sjkh 1214106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 1215106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR); 12167332Sjkh 12177332Sjkh for (i = 0; i < 100; i++) 1218106449Smdodd if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)) 12197332Sjkh break; 1220106449Smdodd if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)) { 1221106449Smdodd XDEBUG(sc, 1, "\nwparam timeout\n"); 1222106451Smdodd return (-EIO); 12237332Sjkh } 12248876Srgrimes 12257332Sjkh va_start(ap, nargs); 12267332Sjkh for (i = 0; i < nargs; i++) { 12277332Sjkh c = (u_char)va_arg(ap, int); 1228106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, c); 1229106449Smdodd XDEBUG(sc, 1, ",{0x%x}", c); 12307332Sjkh } 12317332Sjkh va_end(ap); 1232106449Smdodd XDEBUG(sc, 1, "\n"); 12337332Sjkh 1234106449Smdodd SCD_WRITE(sc, OREG_COMMAND, cmd); 12357332Sjkh 1236106449Smdodd rc = waitfor_status_bits(sc, SBIT_RESULT_READY, SBIT_BUSY); 123711872Sphk if (rc) 1238106451Smdodd return (-0x100); 12397332Sjkh 1240106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 1241106449Smdodd switch ((rc = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 12427332Sjkh case 0x20: 1243106449Smdodd rc = SCD_READ(sc, IREG_RESULT); 1244102412Scharnier /* FALLTHROUGH */ 12457332Sjkh case 0x50: 1246106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: drive_error=0x%x\n", rc); 1247106451Smdodd return (-rc); 12487332Sjkh case 0x00: 12497332Sjkh default: 1250106449Smdodd rc = SCD_READ(sc, IREG_RESULT); 1251106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: result_len=%d\n", rc); 1252106451Smdodd return (rc); 12537332Sjkh } 12547332Sjkh} 12557332Sjkh 12567332Sjkhstatic void 1257106449Smdoddprint_error(struct scd_softc *sc, int errcode) 12587332Sjkh{ 1259106490Smdodd 12607332Sjkh switch (errcode) { 12617332Sjkh case -ERR_CD_NOT_LOADED: 1262106449Smdodd device_printf(sc->dev, "door is open\n"); 12637332Sjkh break; 12647332Sjkh case -ERR_NO_CD_INSIDE: 1265106449Smdodd device_printf(sc->dev, "no cd inside\n"); 12667332Sjkh break; 12677332Sjkh default: 12687332Sjkh if (errcode == -0x100 || errcode > 0) 1269106449Smdodd device_printf(sc->dev, "device timeout\n"); 12707332Sjkh else 1271106449Smdodd device_printf(sc->dev, "unexpected error 0x%x\n", -errcode); 12727332Sjkh break; 12737332Sjkh } 12747332Sjkh} 12757332Sjkh 12767332Sjkh/* Returns 0 or errno value */ 12777332Sjkhstatic int 1278106449Smdoddwaitfor_status_bits(struct scd_softc *sc, int bits_set, int bits_clear) 12797332Sjkh{ 1280106449Smdodd u_int flags = sc->data.flags; 12817332Sjkh u_int max_loop; 12827332Sjkh u_char c = 0; 12837332Sjkh 12847332Sjkh if (flags & SCDPROBING) { 12857332Sjkh max_loop = 0; 12867332Sjkh while (max_loop++ < 1000) { 1287106449Smdodd c = SCD_READ(sc, IREG_STATUS); 12887332Sjkh if (c == 0xff) 1289106451Smdodd return (EIO); 12907332Sjkh if (c & SBIT_ATTENTION) { 1291106449Smdodd process_attention(sc); 12927332Sjkh continue; 12937332Sjkh } 12947332Sjkh if ((c & bits_set) == bits_set && 12957332Sjkh (c & bits_clear) == 0) 12967332Sjkh { 12977332Sjkh break; 12987332Sjkh } 12997332Sjkh DELAY(10000); 13007332Sjkh } 13017332Sjkh } else { 13027332Sjkh max_loop = 100; 13037332Sjkh while (max_loop-- > 0) { 1304106449Smdodd c = SCD_READ(sc, IREG_STATUS); 13057332Sjkh if (c & SBIT_ATTENTION) { 1306106449Smdodd process_attention(sc); 13077332Sjkh continue; 13087332Sjkh } 13097332Sjkh if ((c & bits_set) == bits_set && 13107332Sjkh (c & bits_clear) == 0) 13117332Sjkh { 13127332Sjkh break; 13137332Sjkh } 1314274679Sjhb SCD_UNLOCK(sc); 1315167086Sjhb pause("waitfor", hz/10); 1316274679Sjhb SCD_LOCK(sc); 13177332Sjkh } 13187332Sjkh } 13197332Sjkh if ((c & bits_set) == bits_set && 13207332Sjkh (c & bits_clear) == 0) 13217332Sjkh { 1322106451Smdodd return (0); 13237332Sjkh } 13247332Sjkh#ifdef SCD_DEBUG 13257332Sjkh if (scd_debuglevel > 0) 1326106449Smdodd device_printf(sc->dev, "DEBUG: waitfor: TIMEOUT (0x%x,(0x%x,0x%x))\n", c, bits_set, bits_clear); 13277332Sjkh else 13287332Sjkh#endif 1329106449Smdodd device_printf(sc->dev, "timeout.\n"); 1330106451Smdodd return (EIO); 13317332Sjkh} 13327332Sjkh 13337332Sjkh/* these two routines for xcdplayer - "borrowed" from mcd.c */ 13347332Sjkhstatic int 1335106449Smdoddscd_toc_header (struct scd_softc *sc, struct ioc_toc_header* th) 13367332Sjkh{ 13377332Sjkh int rc; 13387332Sjkh 1339106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1340106449Smdodd print_error(sc, rc); 1341106451Smdodd return (EIO); 13427332Sjkh } 13437332Sjkh 1344106490Smdodd th->starting_track = sc->data.first_track; 1345106490Smdodd th->ending_track = sc->data.last_track; 13467332Sjkh th->len = 0; /* not used */ 13477332Sjkh 1348106451Smdodd return (0); 13497332Sjkh} 13507332Sjkh 13517332Sjkhstatic int 1352106449Smdoddscd_toc_entrys (struct scd_softc *sc, struct ioc_read_toc_entry *te) 13537332Sjkh{ 13547332Sjkh struct cd_toc_entry toc_entry; 13557332Sjkh int rc, i, len = te->data_len; 13567332Sjkh 1357106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1358106449Smdodd print_error(sc, rc); 1359106451Smdodd return (EIO); 13607332Sjkh } 13617332Sjkh 13627332Sjkh /* find the toc to copy*/ 13637332Sjkh i = te->starting_track; 13647332Sjkh if (i == SCD_LASTPLUS1) 1365106490Smdodd i = sc->data.last_track + 1; 13668876Srgrimes 13677332Sjkh /* verify starting track */ 1368106490Smdodd if (i < sc->data.first_track || i > sc->data.last_track+1) 1369106451Smdodd return (EINVAL); 13707332Sjkh 13717332Sjkh /* valid length ? */ 13727332Sjkh if (len < sizeof(struct cd_toc_entry) 13737332Sjkh || (len % sizeof(struct cd_toc_entry)) != 0) 1374106451Smdodd return (EINVAL); 13757332Sjkh 13767332Sjkh /* copy the toc data */ 1377106490Smdodd toc_entry.control = sc->data.toc[i].ctl; 13787332Sjkh toc_entry.addr_type = te->address_format; 13797332Sjkh toc_entry.track = i; 13807332Sjkh if (te->address_format == CD_MSF_FORMAT) { 13817332Sjkh toc_entry.addr.msf.unused = 0; 1382106490Smdodd toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0]); 1383106490Smdodd toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1]); 1384106490Smdodd toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2]); 13857332Sjkh } 1386274679Sjhb SCD_UNLOCK(sc); 13877332Sjkh 13887332Sjkh /* copy the data back */ 13897332Sjkh if (copyout(&toc_entry, te->data, sizeof(struct cd_toc_entry)) != 0) 1390106451Smdodd return (EFAULT); 13917332Sjkh 1392106451Smdodd return (0); 13937332Sjkh} 13947332Sjkh 139512517Sjulian 139625460Sjoergstatic int 1397106449Smdoddscd_toc_entry (struct scd_softc *sc, struct ioc_read_toc_single_entry *te) 139825460Sjoerg{ 139925460Sjoerg struct cd_toc_entry toc_entry; 140025460Sjoerg int rc, i; 140125460Sjoerg 1402106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1403106449Smdodd print_error(sc, rc); 1404106451Smdodd return (EIO); 140525460Sjoerg } 140625460Sjoerg 140725460Sjoerg /* find the toc to copy*/ 140825460Sjoerg i = te->track; 140925460Sjoerg if (i == SCD_LASTPLUS1) 1410106490Smdodd i = sc->data.last_track + 1; 141125460Sjoerg 141225460Sjoerg /* verify starting track */ 1413106490Smdodd if (i < sc->data.first_track || i > sc->data.last_track+1) 1414106451Smdodd return (EINVAL); 141525460Sjoerg 141625460Sjoerg /* copy the toc data */ 1417106490Smdodd toc_entry.control = sc->data.toc[i].ctl; 141825460Sjoerg toc_entry.addr_type = te->address_format; 141925460Sjoerg toc_entry.track = i; 142025460Sjoerg if (te->address_format == CD_MSF_FORMAT) { 142125460Sjoerg toc_entry.addr.msf.unused = 0; 1422106490Smdodd toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0]); 1423106490Smdodd toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1]); 1424106490Smdodd toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2]); 142525460Sjoerg } 142625460Sjoerg 142725460Sjoerg /* copy the data back */ 142825460Sjoerg bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry)); 142925460Sjoerg 1430106451Smdodd return (0); 143125460Sjoerg} 1432