scd.c revision 106490
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 4350477Speter/* $FreeBSD: head/sys/dev/scd/scd.c 106490 2002-11-06 08:08:55Z mdodd $ */ 447332Sjkh 45106451Smdodd#undef SCD_DEBUG 467332Sjkh 477332Sjkh#include <sys/param.h> 487332Sjkh#include <sys/systm.h> 4961011Speter#include <sys/kernel.h> 507332Sjkh#include <sys/conf.h> 51106450Smdodd#include <sys/fcntl.h> 5260041Sphk#include <sys/bio.h> 537332Sjkh#include <sys/cdio.h> 54106450Smdodd#include <sys/disk.h> 5561011Speter#include <sys/bus.h> 567369Sbde 577332Sjkh#include <machine/stdarg.h> 587332Sjkh 59106449Smdodd#include <machine/bus_pio.h> 60106449Smdodd#include <machine/bus.h> 61106449Smdodd#include <machine/resource.h> 62106449Smdodd#include <sys/rman.h> 637332Sjkh 64106449Smdodd#include <isa/isavar.h> 6512502Sjulian 66106449Smdodd#include <dev/scd/scdreg.h> 67106449Smdodd#include <dev/scd/scdvar.h> 68106449Smdodd 697332Sjkh/* flags */ 707332Sjkh#define SCDOPEN 0x0001 /* device opened */ 717332Sjkh#define SCDVALID 0x0002 /* parameters loaded */ 727332Sjkh#define SCDINIT 0x0004 /* device is init'd */ 737332Sjkh#define SCDPROBING 0x0020 /* probing */ 747332Sjkh#define SCDTOC 0x0100 /* already read toc */ 757332Sjkh#define SCDMBXBSY 0x0200 /* local mbx is busy */ 767332Sjkh#define SCDSPINNING 0x0400 /* drive is spun up */ 777332Sjkh 787332Sjkh#define SCD_S_BEGIN 0 797332Sjkh#define SCD_S_BEGIN1 1 807332Sjkh#define SCD_S_WAITSTAT 2 817332Sjkh#define SCD_S_WAITFIFO 3 827332Sjkh#define SCD_S_WAITSPIN 4 837332Sjkh#define SCD_S_WAITREAD 5 847332Sjkh#define SCD_S_WAITPARAM 6 857332Sjkh 867332Sjkh#define RDELAY_WAIT 300 877332Sjkh#define RDELAY_WAITREAD 300 887332Sjkh 897332Sjkh#define SCDBLKSIZE 2048 907332Sjkh 917332Sjkh#ifdef SCD_DEBUG 9211872Sphk static int scd_debuglevel = SCD_DEBUG; 93106449Smdodd# define XDEBUG(sc, level, fmt, args...) \ 94106449Smdodd do { \ 95106449Smdodd if (scd_debuglevel >= level) \ 96106449Smdodd device_printf(sc->dev, fmt, ## args); \ 97106449Smdodd } while (0) 987332Sjkh#else 99106449Smdodd# define XDEBUG(sc, level, fmt, args...) 1007332Sjkh#endif 1017332Sjkh 102106449Smdodd#define IS_ATTENTION(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_ATTENTION) != 0) 103106449Smdodd#define IS_BUSY(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_BUSY) != 0) 104106449Smdodd#define IS_DATA_RDY(sc) ((SCD_READ(sc, IREG_STATUS) & SBIT_DATA_READY) != 0) 105106449Smdodd#define STATUS_BIT(sc, bit) ((SCD_READ(sc, IREG_STATUS) & (bit)) != 0) 106106449Smdodd#define FSTATUS_BIT(sc, bit) ((SCD_READ(sc, IREG_FSTATUS) & (bit)) != 0) 1077332Sjkh 1087332Sjkh/* prototypes */ 1097332Sjkhstatic void hsg2msf(int hsg, bcd_t *msf); 1107332Sjkhstatic int msf2hsg(bcd_t *msf); 1117332Sjkh 112106449Smdoddstatic void process_attention(struct scd_softc *); 113106449Smdoddstatic int waitfor_status_bits(struct scd_softc *, int bits_set, int bits_clear); 114106449Smdoddstatic int send_cmd(struct scd_softc *, u_char cmd, u_int nargs, ...); 115106449Smdoddstatic void init_drive(struct scd_softc *); 116106449Smdoddstatic int spin_up(struct scd_softc *); 117106449Smdoddstatic int read_toc(struct scd_softc *); 118106449Smdoddstatic int get_result(struct scd_softc *, int result_len, u_char *result); 119106449Smdoddstatic void print_error(struct scd_softc *, int errcode); 1207332Sjkh 121106449Smdoddstatic void scd_start(struct scd_softc *); 12225056Sbdestatic timeout_t scd_timeout; 123106449Smdoddstatic void scd_doread(struct scd_softc *, int state, struct scd_mbx *mbxin); 1247332Sjkh 125106449Smdoddstatic int scd_eject(struct scd_softc *); 126106449Smdoddstatic int scd_stop(struct scd_softc *); 127106449Smdoddstatic int scd_pause(struct scd_softc *); 128106449Smdoddstatic int scd_resume(struct scd_softc *); 129106449Smdoddstatic int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt); 130106449Smdoddstatic int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf); 131106449Smdoddstatic int scd_play(struct scd_softc *, struct ioc_play_msf *msf); 132106449Smdoddstatic int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch); 133106449Smdoddstatic int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch); 1347332Sjkh 1357332Sjkh/* for xcdplayer */ 136106449Smdoddstatic int scd_toc_header(struct scd_softc *, struct ioc_toc_header *th); 137106449Smdoddstatic int scd_toc_entrys(struct scd_softc *, struct ioc_read_toc_entry *te); 138106449Smdoddstatic int scd_toc_entry(struct scd_softc *, struct ioc_read_toc_single_entry *te); 1397332Sjkh#define SCD_LASTPLUS1 170 /* don't ask, xcdplayer passes this in */ 1407332Sjkh 14112675Sjulianstatic d_open_t scdopen; 14212675Sjulianstatic d_close_t scdclose; 14312675Sjulianstatic d_ioctl_t scdioctl; 14412675Sjulianstatic d_strategy_t scdstrategy; 14512675Sjulian 14612675Sjulian#define CDEV_MAJOR 45 14774810Sphk 14837389Sjulianstatic struct cdevsw scd_cdevsw = { 14947625Sphk /* open */ scdopen, 15047625Sphk /* close */ scdclose, 15147625Sphk /* read */ physread, 15247625Sphk /* write */ nowrite, 15347625Sphk /* ioctl */ scdioctl, 15447625Sphk /* poll */ nopoll, 15547625Sphk /* mmap */ nommap, 15647625Sphk /* strategy */ scdstrategy, 15747625Sphk /* name */ "scd", 15847625Sphk /* maj */ CDEV_MAJOR, 15947625Sphk /* dump */ nodump, 16047625Sphk /* psize */ nopsize, 16147625Sphk /* flags */ D_DISK, 16247625Sphk}; 16312675Sjulian 164106449Smdoddint 165106449Smdoddscd_attach(struct scd_softc *sc) 1667332Sjkh{ 167106449Smdodd int unit; 1688876Srgrimes 169106449Smdodd unit = device_get_unit(sc->dev); 1707332Sjkh 171106449Smdodd init_drive(sc); 1727332Sjkh 173106490Smdodd sc->data.flags = SCDINIT; 174106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 175106490Smdodd bioq_init(&sc->data.head); 1767332Sjkh 177106449Smdodd sc->scd_dev_t = make_dev(&scd_cdevsw, 8 * unit, 178106449Smdodd UID_ROOT, GID_OPERATOR, 0640, "scd%d", unit); 179106449Smdodd sc->scd_dev_t->si_drv1 = (void *)sc; 180106449Smdodd 181106451Smdodd return (0); 1827332Sjkh} 1837332Sjkh 18412675Sjulianstatic int 18583366Sjulianscdopen(dev_t dev, int flags, int fmt, struct thread *td) 1867332Sjkh{ 187106449Smdodd struct scd_softc *sc; 1887332Sjkh int rc; 1898876Srgrimes 190106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 1917332Sjkh 1927332Sjkh /* not initialized*/ 193106490Smdodd if (!(sc->data.flags & SCDINIT)) 194106451Smdodd return (ENXIO); 1957332Sjkh 1967332Sjkh /* invalidated in the meantime? mark all open part's invalid */ 197106490Smdodd if (sc->data.openflag) 198106451Smdodd return (ENXIO); 1997332Sjkh 200106449Smdodd XDEBUG(sc, 1, "DEBUG: status = 0x%x\n", SCD_READ(sc, IREG_STATUS)); 2017332Sjkh 202106449Smdodd if ((rc = spin_up(sc)) != 0) { 203106449Smdodd print_error(sc, rc); 204106451Smdodd return (EIO); 2057332Sjkh } 206106490Smdodd if (!(sc->data.flags & SCDTOC)) { 2077332Sjkh int loop_count = 3; 2087332Sjkh 209106449Smdodd while (loop_count-- > 0 && (rc = read_toc(sc)) != 0) { 2107332Sjkh if (rc == ERR_NOT_SPINNING) { 211106449Smdodd rc = spin_up(sc); 2127332Sjkh if (rc) { 213106449Smdodd print_error(sc, rc);\ 214106451Smdodd return (EIO); 2157332Sjkh } 2167332Sjkh continue; 2177332Sjkh } 218106449Smdodd device_printf(sc->dev, "TOC read error 0x%x\n", rc); 219106451Smdodd return (EIO); 2207332Sjkh } 2217332Sjkh } 2227332Sjkh 223106490Smdodd dev->si_bsize_phys = sc->data.blksize; 22451111Sjulian 225106490Smdodd sc->data.openflag = 1; 226106490Smdodd sc->data.flags |= SCDVALID; 2277332Sjkh 228106451Smdodd return (0); 2297332Sjkh} 2307332Sjkh 23112675Sjulianstatic int 23283366Sjulianscdclose(dev_t dev, int flags, int fmt, struct thread *td) 2337332Sjkh{ 234106449Smdodd struct scd_softc *sc; 2358876Srgrimes 236106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 2377332Sjkh 238106490Smdodd if (!(sc->data.flags & SCDINIT) || !sc->data.openflag) 239106451Smdodd return (ENXIO); 2407332Sjkh 241106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS) { 242106449Smdodd (void)send_cmd(sc, CMD_SPIN_DOWN, 0); 243106490Smdodd sc->data.flags &= ~SCDSPINNING; 2447332Sjkh } 2457332Sjkh 2467332Sjkh 2477332Sjkh /* close channel */ 248106490Smdodd sc->data.openflag = 0; 2497332Sjkh 250106451Smdodd return (0); 2517332Sjkh} 2527332Sjkh 25312675Sjulianstatic void 25459249Sphkscdstrategy(struct bio *bp) 2557332Sjkh{ 2567332Sjkh int s; 257106449Smdodd struct scd_softc *sc; 2587332Sjkh 259106449Smdodd sc = (struct scd_softc *)bp->bio_dev->si_drv1; 2607332Sjkh 261106449Smdodd XDEBUG(sc, 2, "DEBUG: strategy: block=%ld, bcount=%ld\n", 262106449Smdodd (long)bp->bio_blkno, bp->bio_bcount); 2637332Sjkh 264106449Smdodd if (bp->bio_blkno < 0 || (bp->bio_bcount % SCDBLKSIZE)) { 265106449Smdodd device_printf(sc->dev, "strategy failure: blkno = %ld, bcount = %ld\n", 266106449Smdodd (long)bp->bio_blkno, bp->bio_bcount); 26759249Sphk bp->bio_error = EINVAL; 26859249Sphk bp->bio_flags |= BIO_ERROR; 2697332Sjkh goto bad; 2707332Sjkh } 2717332Sjkh 2727332Sjkh /* if device invalidated (e.g. media change, door open), error */ 273106490Smdodd if (!(sc->data.flags & SCDVALID)) { 274106449Smdodd device_printf(sc->dev, "media changed\n"); 27559249Sphk bp->bio_error = EIO; 2767332Sjkh goto bad; 2777332Sjkh } 2787332Sjkh 2797332Sjkh /* read only */ 28059249Sphk if (!(bp->bio_cmd == BIO_READ)) { 28159249Sphk bp->bio_error = EROFS; 2827332Sjkh goto bad; 2837332Sjkh } 2848876Srgrimes 2857332Sjkh /* no data to read */ 28659249Sphk if (bp->bio_bcount == 0) 2877332Sjkh goto done; 2888876Srgrimes 289106490Smdodd if (!(sc->data.flags & SCDTOC)) { 29059249Sphk bp->bio_error = EIO; 2917332Sjkh goto bad; 2927332Sjkh } 2937332Sjkh 29459249Sphk bp->bio_pblkno = bp->bio_blkno; 29559249Sphk bp->bio_resid = 0; 2968876Srgrimes 2977332Sjkh /* queue it */ 2987332Sjkh s = splbio(); 299106490Smdodd bioqdisksort(&sc->data.head, bp); 3007332Sjkh splx(s); 3018876Srgrimes 3027332Sjkh /* now check whether we can perform processing */ 303106449Smdodd scd_start(sc); 3047332Sjkh return; 3057332Sjkh 3067332Sjkhbad: 30759249Sphk bp->bio_flags |= BIO_ERROR; 3087332Sjkhdone: 30959249Sphk bp->bio_resid = bp->bio_bcount; 3107332Sjkh biodone(bp); 3117332Sjkh return; 3127332Sjkh} 3137332Sjkh 3147332Sjkhstatic void 315106449Smdoddscd_start(struct scd_softc *sc) 3167332Sjkh{ 31759249Sphk struct bio *bp; 31846573Speter int s = splbio(); 3198876Srgrimes 320106490Smdodd if (sc->data.flags & SCDMBXBSY) { 3217332Sjkh splx(s); 3227332Sjkh return; 3237332Sjkh } 3247332Sjkh 325106490Smdodd bp = bioq_first(&sc->data.head); 32615574Sphk if (bp != 0) { 3277332Sjkh /* block found to process, dequeue */ 328106490Smdodd bioq_remove(&sc->data.head, bp); 329106490Smdodd sc->data.flags |= SCDMBXBSY; 3307332Sjkh splx(s); 3317332Sjkh } else { 3327332Sjkh /* nothing to do */ 3337332Sjkh splx(s); 3347332Sjkh return; 3357332Sjkh } 3367332Sjkh 337106490Smdodd sc->data.mbx.retry = 3; 338106490Smdodd sc->data.mbx.bp = bp; 3397332Sjkh splx(s); 3407332Sjkh 341106490Smdodd scd_doread(sc, SCD_S_BEGIN, &(sc->data.mbx)); 3427332Sjkh return; 3437332Sjkh} 3447332Sjkh 34512675Sjulianstatic int 34683366Sjulianscdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 3477332Sjkh{ 348106449Smdodd struct scd_softc *sc; 3498876Srgrimes 350106449Smdodd sc = (struct scd_softc *)dev->si_drv1; 3517332Sjkh 352106449Smdodd XDEBUG(sc, 1, "ioctl: cmd=0x%lx\n", cmd); 3537332Sjkh 354106490Smdodd if (!(sc->data.flags & SCDVALID)) 355106451Smdodd return (EIO); 3567332Sjkh 3577332Sjkh switch (cmd) { 358106450Smdodd case DIOCGMEDIASIZE: 359106490Smdodd *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; 360106450Smdodd return (0); 361106450Smdodd break; 362106450Smdodd case DIOCGSECTORSIZE: 363106490Smdodd *(u_int *)addr = sc->data.blksize; 364106450Smdodd return (0); 365106450Smdodd break; 3667332Sjkh case CDIOCPLAYTRACKS: 367106449Smdodd return scd_playtracks(sc, (struct ioc_play_track *) addr); 3687332Sjkh case CDIOCPLAYBLOCKS: 369106451Smdodd return (EINVAL); 3707332Sjkh case CDIOCPLAYMSF: 371106449Smdodd return scd_playmsf(sc, (struct ioc_play_msf *) addr); 3727332Sjkh case CDIOCREADSUBCHANNEL: 373106449Smdodd return scd_subchan(sc, (struct ioc_read_subchannel *) addr); 3747332Sjkh case CDIOREADTOCHEADER: 375106449Smdodd return scd_toc_header (sc, (struct ioc_toc_header *) addr); 3767332Sjkh case CDIOREADTOCENTRYS: 377106449Smdodd return scd_toc_entrys (sc, (struct ioc_read_toc_entry*) addr); 37825460Sjoerg case CDIOREADTOCENTRY: 379106449Smdodd return scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr); 3807332Sjkh case CDIOCSETPATCH: 3817332Sjkh case CDIOCGETVOL: 3827332Sjkh case CDIOCSETVOL: 3837332Sjkh case CDIOCSETMONO: 3847332Sjkh case CDIOCSETSTERIO: 3857332Sjkh case CDIOCSETMUTE: 3867332Sjkh case CDIOCSETLEFT: 3877332Sjkh case CDIOCSETRIGHT: 388106451Smdodd return (EINVAL); 3897332Sjkh case CDIOCRESUME: 390106449Smdodd return scd_resume(sc); 3917332Sjkh case CDIOCPAUSE: 392106449Smdodd return scd_pause(sc); 3937332Sjkh case CDIOCSTART: 394106451Smdodd return (EINVAL); 3957332Sjkh case CDIOCSTOP: 396106449Smdodd return scd_stop(sc); 3977332Sjkh case CDIOCEJECT: 398106449Smdodd return scd_eject(sc); 3997332Sjkh case CDIOCALLOW: 400106451Smdodd return (0); 4017332Sjkh case CDIOCSETDEBUG: 4027332Sjkh#ifdef SCD_DEBUG 4037332Sjkh scd_debuglevel++; 4047332Sjkh#endif 405106451Smdodd return (0); 4067332Sjkh case CDIOCCLRDEBUG: 4077332Sjkh#ifdef SCD_DEBUG 4087332Sjkh scd_debuglevel = 0; 4097332Sjkh 4107332Sjkh#endif 411106451Smdodd return (0); 4127332Sjkh default: 413106449Smdodd device_printf(sc->dev, "unsupported ioctl (cmd=0x%lx)\n", cmd); 414106451Smdodd return (ENOTTY); 4157332Sjkh } 4167332Sjkh} 4177332Sjkh 4187332Sjkh/*************************************************************** 4197332Sjkh * lower level of driver starts here 4207332Sjkh **************************************************************/ 4217332Sjkh 4227332Sjkhstatic int 423106449Smdoddscd_playtracks(struct scd_softc *sc, struct ioc_play_track *pt) 4247332Sjkh{ 4257332Sjkh struct ioc_play_msf msf; 4267332Sjkh int a = pt->start_track; 4277332Sjkh int z = pt->end_track; 42811872Sphk int rc; 4297332Sjkh 430106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 4317332Sjkh if (rc == -ERR_NOT_SPINNING) { 432106449Smdodd if (spin_up(sc) != 0) 433106451Smdodd return (EIO); 434106449Smdodd rc = read_toc(sc); 4357332Sjkh } 4367332Sjkh if (rc != 0) { 437106449Smdodd print_error(sc, rc); 438106451Smdodd return (EIO); 4397332Sjkh } 4407332Sjkh } 4417332Sjkh 442106449Smdodd XDEBUG(sc, 1, "playtracks from %d:%d to %d:%d\n", 443106449Smdodd a, pt->start_index, z, pt->end_index); 4447332Sjkh 445106490Smdodd if ( a < sc->data.first_track 446106490Smdodd || a > sc->data.last_track 4477332Sjkh || a > z 448106490Smdodd || z > sc->data.last_track) 449106451Smdodd return (EINVAL); 4507332Sjkh 451106490Smdodd bcopy(sc->data.toc[a].start_msf, &msf.start_m, 3); 452106490Smdodd hsg2msf(msf2hsg(sc->data.toc[z+1].start_msf)-1, &msf.end_m); 4537332Sjkh 454106449Smdodd return scd_play(sc, &msf); 4557332Sjkh} 4567332Sjkh 4577332Sjkh/* The start/end msf is expected to be in bin format */ 4587332Sjkhstatic int 459106449Smdoddscd_playmsf(struct scd_softc *sc, struct ioc_play_msf *msfin) 4607332Sjkh{ 4617332Sjkh struct ioc_play_msf msf; 4627332Sjkh 4637332Sjkh msf.start_m = bin2bcd(msfin->start_m); 4647332Sjkh msf.start_s = bin2bcd(msfin->start_s); 4657332Sjkh msf.start_f = bin2bcd(msfin->start_f); 4667332Sjkh msf.end_m = bin2bcd(msfin->end_m); 4677332Sjkh msf.end_s = bin2bcd(msfin->end_s); 4687332Sjkh msf.end_f = bin2bcd(msfin->end_f); 4697332Sjkh 470106449Smdodd return scd_play(sc, &msf); 4717332Sjkh} 4727332Sjkh 4737332Sjkh/* The start/end msf is expected to be in bcd format */ 4747332Sjkhstatic int 475106449Smdoddscd_play(struct scd_softc *sc, struct ioc_play_msf *msf) 4767332Sjkh{ 4777332Sjkh int i, rc; 4787332Sjkh 479106449Smdodd XDEBUG(sc, 1, "playing: %02x:%02x:%02x -> %02x:%02x:%02x\n", 4807332Sjkh msf->start_m, msf->start_s, msf->start_f, 481106449Smdodd msf->end_m, msf->end_s, msf->end_f); 4827332Sjkh 4837332Sjkh for (i = 0; i < 2; i++) { 484106449Smdodd rc = send_cmd(sc, CMD_PLAY_AUDIO, 7, 4857332Sjkh 0x03, 4867332Sjkh msf->start_m, msf->start_s, msf->start_f, 4877332Sjkh msf->end_m, msf->end_s, msf->end_f); 4887332Sjkh if (rc == -ERR_NOT_SPINNING) { 489106490Smdodd sc->data.flags &= ~SCDSPINNING; 490106449Smdodd if (spin_up(sc) != 0) 491106451Smdodd return (EIO); 4927332Sjkh } else if (rc < 0) { 493106449Smdodd print_error(sc, rc); 494106451Smdodd return (EIO); 4957332Sjkh } else { 4967332Sjkh break; 4977332Sjkh } 4987332Sjkh } 499106490Smdodd sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; 500106490Smdodd bcopy((char *)msf, (char *)&sc->data.last_play, sizeof(struct ioc_play_msf)); 501106451Smdodd return (0); 5027332Sjkh} 5037332Sjkh 5047332Sjkhstatic int 505106449Smdoddscd_stop(struct scd_softc *sc) 5067332Sjkh{ 5077332Sjkh 508106449Smdodd (void)send_cmd(sc, CMD_STOP_AUDIO, 0); 509106490Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 510106451Smdodd return (0); 5117332Sjkh} 5127332Sjkh 5137332Sjkhstatic int 514106449Smdoddscd_pause(struct scd_softc *sc) 5157332Sjkh{ 5167332Sjkh struct sony_subchannel_position_data subpos; 5177332Sjkh 518106490Smdodd if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS) 519106451Smdodd return (EINVAL); 5207332Sjkh 521106449Smdodd if (read_subcode(sc, &subpos) != 0) 522106451Smdodd return (EIO); 5237332Sjkh 524106449Smdodd if (send_cmd(sc, CMD_STOP_AUDIO, 0) != 0) 525106451Smdodd return (EIO); 5268876Srgrimes 527106490Smdodd sc->data.last_play.start_m = subpos.abs_msf[0]; 528106490Smdodd sc->data.last_play.start_s = subpos.abs_msf[1]; 529106490Smdodd sc->data.last_play.start_f = subpos.abs_msf[2]; 530106490Smdodd sc->data.audio_status = CD_AS_PLAY_PAUSED; 5317332Sjkh 532106449Smdodd XDEBUG(sc, 1, "pause @ %02x:%02x:%02x\n", 533106490Smdodd sc->data.last_play.start_m, 534106490Smdodd sc->data.last_play.start_s, 535106490Smdodd sc->data.last_play.start_f); 5367332Sjkh 537106451Smdodd return (0); 5387332Sjkh} 5397332Sjkh 5407332Sjkhstatic int 541106449Smdoddscd_resume(struct scd_softc *sc) 5427332Sjkh{ 543106449Smdodd 544106449Smdodd if (sc->data.audio_status != CD_AS_PLAY_PAUSED) 545106451Smdodd return (EINVAL); 546106449Smdodd return scd_play(sc, &sc->data.last_play); 5477332Sjkh} 5487332Sjkh 5497332Sjkhstatic int 550106449Smdoddscd_eject(struct scd_softc *sc) 5517332Sjkh{ 5527332Sjkh 553106490Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 554106490Smdodd sc->data.flags &= ~(SCDSPINNING|SCDTOC); 5557332Sjkh 556106449Smdodd if (send_cmd(sc, CMD_STOP_AUDIO, 0) != 0 || 557106449Smdodd send_cmd(sc, CMD_SPIN_DOWN, 0) != 0 || 558106449Smdodd send_cmd(sc, CMD_EJECT, 0) != 0) 5597332Sjkh { 560106451Smdodd return (EIO); 5617332Sjkh } 562106451Smdodd return (0); 5637332Sjkh} 5647332Sjkh 5657332Sjkhstatic int 566106449Smdoddscd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch) 5677332Sjkh{ 5687332Sjkh struct sony_subchannel_position_data q; 5697332Sjkh struct cd_sub_channel_info data; 5707332Sjkh 571106449Smdodd XDEBUG(sc, 1, "subchan af=%d, df=%d\n", 572106449Smdodd sch->address_format, sch->data_format); 5737332Sjkh 574106449Smdodd if (sch->address_format != CD_MSF_FORMAT) 575106451Smdodd return (EINVAL); 5767332Sjkh 577106449Smdodd if (sch->data_format != CD_CURRENT_POSITION) 578106451Smdodd return (EINVAL); 5797332Sjkh 580106449Smdodd if (read_subcode(sc, &q) != 0) 581106451Smdodd return (EIO); 5827332Sjkh 583106490Smdodd data.header.audio_status = sc->data.audio_status; 5847332Sjkh data.what.position.data_format = CD_MSF_FORMAT; 5857332Sjkh data.what.position.track_number = bcd2bin(q.track_number); 5867332Sjkh data.what.position.reladdr.msf.unused = 0; 5877332Sjkh data.what.position.reladdr.msf.minute = bcd2bin(q.rel_msf[0]); 5887332Sjkh data.what.position.reladdr.msf.second = bcd2bin(q.rel_msf[1]); 5897332Sjkh data.what.position.reladdr.msf.frame = bcd2bin(q.rel_msf[2]); 5907332Sjkh data.what.position.absaddr.msf.unused = 0; 5917332Sjkh data.what.position.absaddr.msf.minute = bcd2bin(q.abs_msf[0]); 5927332Sjkh data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1]); 5937332Sjkh data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2]); 5947332Sjkh 595106449Smdodd if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) 596106451Smdodd return (EFAULT); 597106451Smdodd return (0); 5987332Sjkh} 5997332Sjkh 600106449Smdoddint 601106449Smdoddscd_probe(struct scd_softc *sc) 60242552Seivind{ 6037332Sjkh struct sony_drive_configuration drive_config; 6047332Sjkh int rc; 6057332Sjkh static char namebuf[8+16+8+3]; 6067332Sjkh char *s = namebuf; 6077332Sjkh int loop_count = 0; 6087332Sjkh 609106490Smdodd sc->data.flags = SCDPROBING; 6107332Sjkh 6117332Sjkh bzero(&drive_config, sizeof(drive_config)); 6127332Sjkh 6137332Sjkhagain: 6147332Sjkh /* Reset drive */ 615106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESET_DRIVE); 6167332Sjkh 6177332Sjkh /* Calm down */ 6187332Sjkh DELAY(300000); 6197332Sjkh 6207332Sjkh /* Only the ATTENTION bit may be set */ 621106449Smdodd if ((SCD_READ(sc, IREG_STATUS) & ~1) != 0) { 622106449Smdodd XDEBUG(sc, 1, "too many bits set. probe failed.\n"); 623106449Smdodd return (ENXIO); 6247332Sjkh } 625106449Smdodd rc = send_cmd(sc, CMD_GET_DRIVE_CONFIG, 0); 6267332Sjkh if (rc != sizeof(drive_config)) { 6277332Sjkh /* Sometimes if the drive is playing audio I get */ 6287332Sjkh /* the bad result 82. Fix by repeating the reset */ 6297332Sjkh if (rc > 0 && loop_count++ == 0) 6307332Sjkh goto again; 631106449Smdodd return (ENXIO); 6327332Sjkh } 633106449Smdodd if (get_result(sc, rc, (u_char *)&drive_config) != 0) 634106449Smdodd return (ENXIO); 6357332Sjkh 6367332Sjkh bcopy(drive_config.vendor, namebuf, 8); 6377332Sjkh s = namebuf+8; 6387332Sjkh while (*(s-1) == ' ') /* Strip trailing spaces */ 6397332Sjkh s--; 6407332Sjkh *s++ = ' '; 6417332Sjkh bcopy(drive_config.product, s, 16); 6427332Sjkh s += 16; 6437332Sjkh while (*(s-1) == ' ') 6447332Sjkh s--; 6457332Sjkh *s++ = ' '; 6467332Sjkh bcopy(drive_config.revision, s, 8); 6477332Sjkh s += 8; 6487332Sjkh while (*(s-1) == ' ') 6497332Sjkh s--; 6507332Sjkh *s = 0; 6517332Sjkh 652106490Smdodd sc->data.name = namebuf; 6537332Sjkh 6547332Sjkh if (drive_config.config & 0x10) 655106490Smdodd sc->data.double_speed = 1; 6567332Sjkh else 657106490Smdodd sc->data.double_speed = 0; 6587332Sjkh 659106449Smdodd return (0); 6607332Sjkh} 6617332Sjkh 6627332Sjkhstatic int 663106449Smdoddread_subcode(struct scd_softc *sc, struct sony_subchannel_position_data *scp) 6647332Sjkh{ 6657332Sjkh int rc; 6667332Sjkh 667106449Smdodd rc = send_cmd(sc, CMD_GET_SUBCHANNEL_DATA, 0); 668106449Smdodd if (rc < 0 || rc < sizeof(*scp)) 669106451Smdodd return (EIO); 670106449Smdodd if (get_result(sc, rc, (u_char *)scp) != 0) 671106451Smdodd return (EIO); 672106451Smdodd return (0); 6737332Sjkh} 6747332Sjkh 6757332Sjkh/* State machine copied from mcd.c */ 6767332Sjkh 6777332Sjkh/* This (and the code in mcd.c) will not work with more than one drive */ 678106449Smdodd/* because there is only one sc->ch_mbxsave below. Should fix that some day. */ 679106449Smdodd/* (sc->ch_mbxsave & state should probably be included in the scd_data struct and */ 6807332Sjkh/* the unit number used as first argument to scd_doread().) /Micke */ 6817332Sjkh 6827332Sjkh/* state machine to process read requests 6837332Sjkh * initialize with SCD_S_BEGIN: reset state machine 6847332Sjkh * SCD_S_WAITSTAT: wait for ready (!busy) 6857332Sjkh * SCD_S_WAITSPIN: wait for drive to spin up (if not spinning) 6867332Sjkh * SCD_S_WAITFIFO: wait for param fifo to get ready, them exec. command. 6877332Sjkh * SCD_S_WAITREAD: wait for data ready, read data 6887332Sjkh * SCD_S_WAITPARAM: wait for command result params, read them, error if bad data read. 6897332Sjkh */ 6907332Sjkh 6917332Sjkhstatic void 69225056Sbdescd_timeout(void *arg) 69325056Sbde{ 694106449Smdodd struct scd_softc *sc; 695106449Smdodd sc = (struct scd_softc *)arg; 696106449Smdodd 697106449Smdodd scd_doread(sc, sc->ch_state, sc->ch_mbxsave); 69825056Sbde} 69925056Sbde 70025056Sbdestatic void 701106449Smdoddscd_doread(struct scd_softc *sc, int state, struct scd_mbx *mbxin) 7027332Sjkh{ 703106449Smdodd struct scd_mbx *mbx = (state!=SCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; 70459249Sphk struct bio *bp = mbx->bp; 705106449Smdodd int i; 7067332Sjkh int blknum; 7077332Sjkh caddr_t addr; 7087332Sjkh static char sdata[3]; /* Must be preserved between calls to this function */ 7097332Sjkh 7107332Sjkhloop: 7117332Sjkh switch (state) { 7127332Sjkh case SCD_S_BEGIN: 713106449Smdodd mbx = sc->ch_mbxsave = mbxin; 7147332Sjkh 7157332Sjkh case SCD_S_BEGIN1: 7167332Sjkh /* get status */ 7177332Sjkh mbx->count = RDELAY_WAIT; 7187332Sjkh 719106449Smdodd process_attention(sc); 7207332Sjkh goto trystat; 7217332Sjkh 7227332Sjkh case SCD_S_WAITSTAT: 723106449Smdodd sc->ch_state = SCD_S_WAITSTAT; 724106449Smdodd untimeout(scd_timeout, (caddr_t)sc, sc->ch); 7257332Sjkh if (mbx->count-- <= 0) { 726106449Smdodd device_printf(sc->dev, "timeout. drive busy.\n"); 7277332Sjkh goto harderr; 7287332Sjkh } 7297332Sjkh 7307332Sjkhtrystat: 731106449Smdodd if (IS_BUSY(sc)) { 732106449Smdodd sc->ch_state = SCD_S_WAITSTAT; 733106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 7347332Sjkh return; 7357332Sjkh } 7368876Srgrimes 737106449Smdodd process_attention(sc); 7387332Sjkh 7397332Sjkh /* reject, if audio active */ 740106490Smdodd if (sc->data.audio_status & CD_AS_PLAY_IN_PROGRESS) { 741106449Smdodd device_printf(sc->dev, "audio is active\n"); 7427332Sjkh goto harderr; 7437332Sjkh } 7447332Sjkh 745106490Smdodd mbx->sz = sc->data.blksize; 7467332Sjkh 7477332Sjkh /* for first block */ 74859249Sphk mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; 7497332Sjkh mbx->skip = 0; 7507332Sjkh 7517332Sjkhnextblock: 752106490Smdodd if (!(sc->data.flags & SCDVALID)) 7537332Sjkh goto changed; 7547332Sjkh 75559249Sphk blknum = (bp->bio_blkno / (mbx->sz/DEV_BSIZE)) 756106450Smdodd + mbx->skip/mbx->sz; 7577332Sjkh 758106449Smdodd XDEBUG(sc, 2, "scd_doread: read blknum=%d\n", blknum); 7597332Sjkh 7607332Sjkh /* build parameter block */ 7617332Sjkh hsg2msf(blknum, sdata); 7627332Sjkh 763106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 764106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR); 765106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR); 7667332Sjkh 767106449Smdodd if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)) 7687332Sjkh goto writeparam; 7697332Sjkh 7707332Sjkh mbx->count = 100; 771106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 772106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 7737332Sjkh return; 7747332Sjkh 7757332Sjkh case SCD_S_WAITSPIN: 776106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 777106449Smdodd untimeout(scd_timeout,(caddr_t)sc, sc->ch); 7787332Sjkh if (mbx->count-- <= 0) { 779106449Smdodd device_printf(sc->dev, "timeout waiting for drive to spin up.\n"); 7807332Sjkh goto harderr; 7817332Sjkh } 782106449Smdodd if (!STATUS_BIT(sc, SBIT_RESULT_READY)) { 783106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 784106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 7857332Sjkh return; 7867332Sjkh } 787106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 788106449Smdodd switch ((i = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 7897332Sjkh case 0x20: 790106449Smdodd i = SCD_READ(sc, IREG_RESULT); 791106449Smdodd print_error(sc, i); 7927332Sjkh goto harderr; 7937332Sjkh case 0x00: 794106449Smdodd (void)SCD_READ(sc, IREG_RESULT); 795106490Smdodd sc->data.flags |= SCDSPINNING; 7967332Sjkh break; 7977332Sjkh } 798106449Smdodd XDEBUG(sc, 1, "DEBUG: spin up complete\n"); 7997332Sjkh 8007332Sjkh state = SCD_S_BEGIN1; 8017332Sjkh goto loop; 8027332Sjkh 8037332Sjkh case SCD_S_WAITFIFO: 804106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 805106449Smdodd untimeout(scd_timeout,(caddr_t)sc, sc->ch); 8067332Sjkh if (mbx->count-- <= 0) { 807106449Smdodd device_printf(sc->dev, "timeout. write param not ready.\n"); 8087332Sjkh goto harderr; 8097332Sjkh } 810106449Smdodd if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)) { 811106449Smdodd sc->ch_state = SCD_S_WAITFIFO; 812106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc,hz/100); /* XXX */ 8137332Sjkh return; 8147332Sjkh } 815106449Smdodd XDEBUG(sc, 1, "mbx->count (writeparamwait) = %d(%d)\n", mbx->count, 100); 8167332Sjkh 8177332Sjkhwriteparam: 8187332Sjkh /* The reason this test isn't done 'till now is to make sure */ 8197332Sjkh /* that it is ok to send the SPIN_UP cmd below. */ 820106490Smdodd if (!(sc->data.flags & SCDSPINNING)) { 821106449Smdodd XDEBUG(sc, 1, "spinning up drive ...\n"); 822106449Smdodd SCD_WRITE(sc, OREG_COMMAND, CMD_SPIN_UP); 8237332Sjkh mbx->count = 300; 824106449Smdodd sc->ch_state = SCD_S_WAITSPIN; 825106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 8267332Sjkh return; 8277332Sjkh } 8287332Sjkh 8297332Sjkh /* send the read command */ 8307332Sjkh disable_intr(); 831106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[0]); 832106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[1]); 833106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, sdata[2]); 834106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 0); 835106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 0); 836106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, 1); 837106449Smdodd SCD_WRITE(sc, OREG_COMMAND, CMD_READ); 8387332Sjkh enable_intr(); 8397332Sjkh 8407332Sjkh mbx->count = RDELAY_WAITREAD; 8417332Sjkh for (i = 0; i < 50; i++) { 842106449Smdodd if (STATUS_BIT(sc, SBIT_DATA_READY)) 8437332Sjkh goto got_data; 8447332Sjkh DELAY(100); 8457332Sjkh } 8467332Sjkh 847106449Smdodd sc->ch_state = SCD_S_WAITREAD; 848106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 8497332Sjkh return; 8507332Sjkh 8517332Sjkh case SCD_S_WAITREAD: 852106449Smdodd sc->ch_state = SCD_S_WAITREAD; 853106449Smdodd untimeout(scd_timeout,(caddr_t)sc, sc->ch); 8547332Sjkh if (mbx->count-- <= 0) { 855106449Smdodd if (STATUS_BIT(sc, SBIT_RESULT_READY)) 8567332Sjkh goto got_param; 857106449Smdodd device_printf(sc->dev, "timeout while reading data\n"); 8587332Sjkh goto readerr; 8597332Sjkh } 860106449Smdodd if (!STATUS_BIT(sc, SBIT_DATA_READY)) { 861106449Smdodd process_attention(sc); 862106490Smdodd if (!(sc->data.flags & SCDVALID)) 8637332Sjkh goto changed; 864106449Smdodd sc->ch_state = SCD_S_WAITREAD; 865106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 8667332Sjkh return; 8677332Sjkh } 868106449Smdodd XDEBUG(sc, 2, "mbx->count (after RDY_BIT) = %d(%d)\n", mbx->count, RDELAY_WAITREAD); 8697332Sjkh 8707332Sjkhgot_data: 8717332Sjkh /* data is ready */ 87259249Sphk addr = bp->bio_data + mbx->skip; 873106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR); 874106449Smdodd SCD_READ_MULTI(sc, IREG_DATA, addr, mbx->sz); 8757332Sjkh 8767332Sjkh mbx->count = 100; 8777332Sjkh for (i = 0; i < 20; i++) { 878106449Smdodd if (STATUS_BIT(sc, SBIT_RESULT_READY)) 8797332Sjkh goto waitfor_param; 8807332Sjkh DELAY(100); 8817332Sjkh } 8827332Sjkh goto waitfor_param; 8837332Sjkh 8847332Sjkh case SCD_S_WAITPARAM: 885106449Smdodd sc->ch_state = SCD_S_WAITPARAM; 886106449Smdodd untimeout(scd_timeout,(caddr_t)sc, sc->ch); 8877332Sjkh if (mbx->count-- <= 0) { 888106449Smdodd device_printf(sc->dev, "timeout waiting for params\n"); 8897332Sjkh goto readerr; 8907332Sjkh } 8917332Sjkh 8927332Sjkhwaitfor_param: 893106449Smdodd if (!STATUS_BIT(sc, SBIT_RESULT_READY)) { 894106449Smdodd sc->ch_state = SCD_S_WAITPARAM; 895106449Smdodd sc->ch = timeout(scd_timeout, (caddr_t)sc, hz/100); /* XXX */ 8967332Sjkh return; 8977332Sjkh } 898106451Smdodd#ifdef SCD_DEBUG 8997332Sjkh if (mbx->count < 100 && scd_debuglevel > 0) 900106449Smdodd device_printf(sc->dev, "mbx->count (paramwait) = %d(%d)\n", mbx->count, 100); 9017332Sjkh#endif 9027332Sjkh 9037332Sjkhgot_param: 904106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 905106449Smdodd switch ((i = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 9067332Sjkh case 0x50: 9077332Sjkh switch (i) { 9087332Sjkh case ERR_FATAL_READ_ERROR1: 9097332Sjkh case ERR_FATAL_READ_ERROR2: 910106449Smdodd device_printf(sc->dev, "unrecoverable read error 0x%x\n", i); 9117332Sjkh goto harderr; 9127332Sjkh } 9137332Sjkh break; 9147332Sjkh case 0x20: 915106449Smdodd i = SCD_READ(sc, IREG_RESULT); 9167332Sjkh switch (i) { 9177332Sjkh case ERR_NOT_SPINNING: 918106449Smdodd XDEBUG(sc, 1, "read error: drive not spinning\n"); 9197332Sjkh if (mbx->retry-- > 0) { 9207332Sjkh state = SCD_S_BEGIN1; 921106490Smdodd sc->data.flags &= ~SCDSPINNING; 9227332Sjkh goto loop; 9237332Sjkh } 9247332Sjkh goto harderr; 9257332Sjkh default: 926106449Smdodd print_error(sc, i); 9277332Sjkh goto readerr; 9287332Sjkh } 9297332Sjkh case 0x00: 930106449Smdodd i = SCD_READ(sc, IREG_RESULT); 9317332Sjkh break; 9327332Sjkh } 9337332Sjkh 9347332Sjkh if (--mbx->nblk > 0) { 9357332Sjkh mbx->skip += mbx->sz; 9367332Sjkh goto nextblock; 9377332Sjkh } 9387332Sjkh 9397332Sjkh /* return buffer */ 94059249Sphk bp->bio_resid = 0; 9417332Sjkh biodone(bp); 9427332Sjkh 943106490Smdodd sc->data.flags &= ~SCDMBXBSY; 944106449Smdodd scd_start(sc); 9457332Sjkh return; 9467332Sjkh } 9477332Sjkh 9487332Sjkhreaderr: 9497332Sjkh if (mbx->retry-- > 0) { 950106449Smdodd device_printf(sc->dev, "retrying ...\n"); 9517332Sjkh state = SCD_S_BEGIN1; 9527332Sjkh goto loop; 9537332Sjkh } 9547332Sjkhharderr: 9557332Sjkh /* invalidate the buffer */ 95659249Sphk bp->bio_error = EIO; 95759249Sphk bp->bio_flags |= BIO_ERROR; 95859249Sphk bp->bio_resid = bp->bio_bcount; 9597332Sjkh biodone(bp); 9607332Sjkh 961106490Smdodd sc->data.flags &= ~SCDMBXBSY; 962106449Smdodd scd_start(sc); 9637332Sjkh return; 9647332Sjkh 9657332Sjkhchanged: 966106449Smdodd device_printf(sc->dev, "media changed\n"); 9677332Sjkh goto harderr; 9687332Sjkh} 9697332Sjkh 9707332Sjkhstatic void 9717332Sjkhhsg2msf(int hsg, bcd_t *msf) 9727332Sjkh{ 973106490Smdodd 9747332Sjkh hsg += 150; 9757332Sjkh M_msf(msf) = bin2bcd(hsg / 4500); 9767332Sjkh hsg %= 4500; 9777332Sjkh S_msf(msf) = bin2bcd(hsg / 75); 9787332Sjkh F_msf(msf) = bin2bcd(hsg % 75); 9797332Sjkh} 9807332Sjkh 9817332Sjkhstatic int 9827332Sjkhmsf2hsg(bcd_t *msf) 9837332Sjkh{ 984106490Smdodd 9857332Sjkh return (bcd2bin(M_msf(msf)) * 60 + 9867332Sjkh bcd2bin(S_msf(msf))) * 75 + 9877332Sjkh bcd2bin(F_msf(msf)) - 150; 9887332Sjkh} 9897332Sjkh 9907332Sjkhstatic void 991106449Smdoddprocess_attention(struct scd_softc *sc) 9927332Sjkh{ 9937332Sjkh unsigned char code; 9947332Sjkh int count = 0; 9957332Sjkh 996106449Smdodd while (IS_ATTENTION(sc) && count++ < 30) { 997106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_ATTENTION_CLEAR); 998106449Smdodd code = SCD_READ(sc, IREG_RESULT); 9997332Sjkh 1000106451Smdodd#ifdef SCD_DEBUG 10017332Sjkh if (scd_debuglevel > 0) { 10027332Sjkh if (count == 1) 1003106449Smdodd device_printf(sc->dev, "DEBUG: ATTENTIONS = 0x%x", code); 10047332Sjkh else 10057332Sjkh printf(",0x%x", code); 10067332Sjkh } 10077332Sjkh#endif 10087332Sjkh 10097332Sjkh switch (code) { 10107332Sjkh case ATTEN_SPIN_DOWN: 1011106449Smdodd sc->data.flags &= ~SCDSPINNING; 10127332Sjkh break; 10137332Sjkh 10147332Sjkh case ATTEN_SPIN_UP_DONE: 1015106449Smdodd sc->data.flags |= SCDSPINNING; 10167332Sjkh break; 10177332Sjkh 10187332Sjkh case ATTEN_AUDIO_DONE: 1019106449Smdodd sc->data.audio_status = CD_AS_PLAY_COMPLETED; 10207332Sjkh break; 10217332Sjkh 10227332Sjkh case ATTEN_DRIVE_LOADED: 1023106449Smdodd sc->data.flags &= ~(SCDTOC|SCDSPINNING|SCDVALID); 1024106449Smdodd sc->data.audio_status = CD_AS_AUDIO_INVALID; 10257332Sjkh break; 10267332Sjkh 10277332Sjkh case ATTEN_EJECT_PUSHED: 1028106449Smdodd sc->data.flags &= ~SCDVALID; 10297332Sjkh break; 10307332Sjkh } 10317332Sjkh DELAY(100); 10327332Sjkh } 1033106451Smdodd#ifdef SCD_DEBUG 10347332Sjkh if (scd_debuglevel > 0 && count > 0) 10357332Sjkh printf("\n"); 10367332Sjkh#endif 10377332Sjkh} 10387332Sjkh 10397332Sjkh/* Returns 0 OR sony error code */ 10407332Sjkhstatic int 1041106449Smdoddspin_up(struct scd_softc *sc) 10427332Sjkh{ 10437332Sjkh unsigned char res_reg[12]; 10447332Sjkh unsigned int res_size; 10457332Sjkh int rc; 10467332Sjkh int loop_count = 0; 10477332Sjkh 10487332Sjkhagain: 1049106449Smdodd rc = send_cmd(sc, CMD_SPIN_UP, 0, 0, res_reg, &res_size); 10507332Sjkh if (rc != 0) { 1051106449Smdodd XDEBUG(sc, 2, "CMD_SPIN_UP error 0x%x\n", rc); 1052106451Smdodd return (rc); 10537332Sjkh } 10547332Sjkh 1055106449Smdodd if (!(sc->data.flags & SCDTOC)) { 1056106449Smdodd rc = send_cmd(sc, CMD_READ_TOC, 0); 10577332Sjkh if (rc == ERR_NOT_SPINNING) { 10587332Sjkh if (loop_count++ < 3) 10597332Sjkh goto again; 1060106451Smdodd return (rc); 10617332Sjkh } 10627332Sjkh if (rc != 0) 1063106451Smdodd return (rc); 10647332Sjkh } 10657332Sjkh 1066106449Smdodd sc->data.flags |= SCDSPINNING; 10677332Sjkh 1068106451Smdodd return (0); 10697332Sjkh} 10707332Sjkh 10717332Sjkhstatic struct sony_tracklist * 10727332Sjkhget_tl(struct sony_toc *toc, int size) 10737332Sjkh{ 10747332Sjkh struct sony_tracklist *tl = &toc->tracks[0]; 10757332Sjkh 10767332Sjkh if (tl->track != 0xb0) 1077106451Smdodd return (tl); 10787332Sjkh (char *)tl += 9; 10798876Srgrimes if (tl->track != 0xb1) 1080106451Smdodd return (tl); 10817332Sjkh (char *)tl += 9; 10828876Srgrimes if (tl->track != 0xb2) 1083106451Smdodd return (tl); 10847332Sjkh (char *)tl += 9; 10858876Srgrimes if (tl->track != 0xb3) 1086106451Smdodd return (tl); 10877332Sjkh (char *)tl += 9; 10888876Srgrimes if (tl->track != 0xb4) 1089106451Smdodd return (tl); 10907332Sjkh (char *)tl += 9; 10918876Srgrimes if (tl->track != 0xc0) 1092106451Smdodd return (tl); 10937332Sjkh (char *)tl += 9; 1094106451Smdodd return (tl); 10957332Sjkh} 10967332Sjkh 10977332Sjkhstatic int 1098106449Smdoddread_toc(struct scd_softc *sc) 10997332Sjkh{ 11007332Sjkh struct sony_toc toc; 11017332Sjkh struct sony_tracklist *tl; 11027332Sjkh int rc, i, j; 11037332Sjkh u_long first, last; 11047332Sjkh 1105106453Smdodd rc = send_cmd(sc, CMD_GET_TOC, 1, 1); 11067332Sjkh if (rc < 0) 1107106451Smdodd return (rc); 11087332Sjkh if (rc > sizeof(toc)) { 1109106449Smdodd device_printf(sc->dev, "program error: toc too large (%d)\n", rc); 1110106451Smdodd return (EIO); 11117332Sjkh } 1112106449Smdodd if (get_result(sc, rc, (u_char *)&toc) != 0) 1113106451Smdodd return (EIO); 11147332Sjkh 1115106449Smdodd XDEBUG(sc, 1, "toc read. len = %d, sizeof(toc) = %d\n", rc, sizeof(toc)); 11167332Sjkh 11177332Sjkh tl = get_tl(&toc, rc); 11187332Sjkh first = msf2hsg(tl->start_msf); 11197332Sjkh last = msf2hsg(toc.lead_out_start_msf); 1120106490Smdodd sc->data.blksize = SCDBLKSIZE; 1121106490Smdodd sc->data.disksize = last*sc->data.blksize/DEV_BSIZE; 11227332Sjkh 1123106449Smdodd XDEBUG(sc, 1, "firstsector = %ld, lastsector = %ld", first, last); 11247332Sjkh 1125106490Smdodd sc->data.first_track = bcd2bin(toc.first_track); 1126106490Smdodd sc->data.last_track = bcd2bin(toc.last_track); 1127106490Smdodd if (sc->data.last_track > (MAX_TRACKS-2)) 1128106490Smdodd sc->data.last_track = MAX_TRACKS-2; 1129106490Smdodd for (j = 0, i = sc->data.first_track; i <= sc->data.last_track; i++, j++) { 1130106490Smdodd sc->data.toc[i].adr = tl[j].adr; 1131106490Smdodd sc->data.toc[i].ctl = tl[j].ctl; /* for xcdplayer */ 1132106490Smdodd bcopy(tl[j].start_msf, sc->data.toc[i].start_msf, 3); 11337332Sjkh#ifdef SCD_DEBUG 11347332Sjkh if (scd_debuglevel > 0) { 1135106449Smdodd if ((j % 3) == 0) { 1136106449Smdodd printf("\n"); 1137106449Smdodd device_printf(sc->dev, "tracks "); 1138106449Smdodd } 11397332Sjkh printf("[%03d: %2d %2d %2d] ", i, 1140106490Smdodd bcd2bin(sc->data.toc[i].start_msf[0]), 1141106490Smdodd bcd2bin(sc->data.toc[i].start_msf[1]), 1142106490Smdodd bcd2bin(sc->data.toc[i].start_msf[2])); 11437332Sjkh } 11447332Sjkh#endif 11457332Sjkh } 1146106490Smdodd bcopy(toc.lead_out_start_msf, sc->data.toc[sc->data.last_track+1].start_msf, 3); 11477332Sjkh#ifdef SCD_DEBUG 11487332Sjkh if (scd_debuglevel > 0) { 1149106490Smdodd i = sc->data.last_track+1; 11507332Sjkh printf("[END: %2d %2d %2d]\n", 1151106490Smdodd bcd2bin(sc->data.toc[i].start_msf[0]), 1152106490Smdodd bcd2bin(sc->data.toc[i].start_msf[1]), 1153106490Smdodd bcd2bin(sc->data.toc[i].start_msf[2])); 11547332Sjkh } 11557332Sjkh#endif 11567332Sjkh 1157106490Smdodd sc->data.flags |= SCDTOC; 11587332Sjkh 1159106451Smdodd return (0); 11607332Sjkh} 11617332Sjkh 11627332Sjkhstatic void 1163106449Smdoddinit_drive(struct scd_softc *sc) 11647332Sjkh{ 11657332Sjkh int rc; 11667332Sjkh 1167106449Smdodd rc = send_cmd(sc, CMD_SET_DRIVE_PARAM, 2, 1168106449Smdodd 0x05, 0x03 | ((sc->data.double_speed) ? 0x04: 0)); 11697332Sjkh if (rc != 0) 1170106449Smdodd device_printf(sc->dev, "Unable to set parameters. Errcode = 0x%x\n", rc); 11717332Sjkh} 11727332Sjkh 11737332Sjkh/* Returns 0 or errno */ 11747332Sjkhstatic int 1175106449Smdoddget_result(struct scd_softc *sc, int result_len, u_char *result) 11767332Sjkh{ 11777332Sjkh int loop_index = 2; /* send_cmd() reads two bytes ... */ 11787332Sjkh 1179106449Smdodd XDEBUG(sc, 1, "DEBUG: get_result: bytes=%d\n", result_len); 11807332Sjkh 11817332Sjkh while (result_len-- > 0) { 11827332Sjkh if (loop_index++ >= 10) { 11837332Sjkh loop_index = 1; 1184106449Smdodd if (waitfor_status_bits(sc, SBIT_RESULT_READY, 0)) 1185106451Smdodd return (EIO); 1186106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 11877332Sjkh } 11887332Sjkh if (result) 1189106449Smdodd *result++ = SCD_READ(sc, IREG_RESULT); 11907332Sjkh else 1191106449Smdodd (void)SCD_READ(sc, IREG_RESULT); 11927332Sjkh } 1193106451Smdodd return (0); 11947332Sjkh} 11957332Sjkh 11967332Sjkh/* Returns -0x100 for timeout, -(drive error code) OR number of result bytes */ 11977332Sjkhstatic int 1198106449Smdoddsend_cmd(struct scd_softc *sc, u_char cmd, u_int nargs, ...) 11997332Sjkh{ 12007332Sjkh va_list ap; 12017332Sjkh u_char c; 12027332Sjkh int rc; 12037332Sjkh int i; 12047332Sjkh 1205106449Smdodd if (waitfor_status_bits(sc, 0, SBIT_BUSY)) { 1206106449Smdodd device_printf(sc->dev, "drive busy\n"); 1207106451Smdodd return (-0x100); 12087332Sjkh } 12097332Sjkh 1210106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: cmd=0x%x nargs=%d", cmd, nargs); 12117332Sjkh 1212106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 1213106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR); 12147332Sjkh 12157332Sjkh for (i = 0; i < 100; i++) 1216106449Smdodd if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)) 12177332Sjkh break; 1218106449Smdodd if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)) { 1219106449Smdodd XDEBUG(sc, 1, "\nwparam timeout\n"); 1220106451Smdodd return (-EIO); 12217332Sjkh } 12228876Srgrimes 12237332Sjkh va_start(ap, nargs); 12247332Sjkh for (i = 0; i < nargs; i++) { 12257332Sjkh c = (u_char)va_arg(ap, int); 1226106449Smdodd SCD_WRITE(sc, OREG_WPARAMS, c); 1227106449Smdodd XDEBUG(sc, 1, ",{0x%x}", c); 12287332Sjkh } 12297332Sjkh va_end(ap); 1230106449Smdodd XDEBUG(sc, 1, "\n"); 12317332Sjkh 1232106449Smdodd SCD_WRITE(sc, OREG_COMMAND, cmd); 12337332Sjkh 1234106449Smdodd rc = waitfor_status_bits(sc, SBIT_RESULT_READY, SBIT_BUSY); 123511872Sphk if (rc) 1236106451Smdodd return (-0x100); 12377332Sjkh 1238106449Smdodd SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR); 1239106449Smdodd switch ((rc = SCD_READ(sc, IREG_RESULT)) & 0xf0) { 12407332Sjkh case 0x20: 1241106449Smdodd rc = SCD_READ(sc, IREG_RESULT); 1242102412Scharnier /* FALLTHROUGH */ 12437332Sjkh case 0x50: 1244106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: drive_error=0x%x\n", rc); 1245106451Smdodd return (-rc); 12467332Sjkh case 0x00: 12477332Sjkh default: 1248106449Smdodd rc = SCD_READ(sc, IREG_RESULT); 1249106449Smdodd XDEBUG(sc, 1, "DEBUG: send_cmd: result_len=%d\n", rc); 1250106451Smdodd return (rc); 12517332Sjkh } 12527332Sjkh} 12537332Sjkh 12547332Sjkhstatic void 1255106449Smdoddprint_error(struct scd_softc *sc, int errcode) 12567332Sjkh{ 1257106490Smdodd 12587332Sjkh switch (errcode) { 12597332Sjkh case -ERR_CD_NOT_LOADED: 1260106449Smdodd device_printf(sc->dev, "door is open\n"); 12617332Sjkh break; 12627332Sjkh case -ERR_NO_CD_INSIDE: 1263106449Smdodd device_printf(sc->dev, "no cd inside\n"); 12647332Sjkh break; 12657332Sjkh default: 12667332Sjkh if (errcode == -0x100 || errcode > 0) 1267106449Smdodd device_printf(sc->dev, "device timeout\n"); 12687332Sjkh else 1269106449Smdodd device_printf(sc->dev, "unexpected error 0x%x\n", -errcode); 12707332Sjkh break; 12717332Sjkh } 12727332Sjkh} 12737332Sjkh 12747332Sjkh/* Returns 0 or errno value */ 12757332Sjkhstatic int 1276106449Smdoddwaitfor_status_bits(struct scd_softc *sc, int bits_set, int bits_clear) 12777332Sjkh{ 1278106449Smdodd u_int flags = sc->data.flags; 12797332Sjkh u_int max_loop; 12807332Sjkh u_char c = 0; 12817332Sjkh 12827332Sjkh if (flags & SCDPROBING) { 12837332Sjkh max_loop = 0; 12847332Sjkh while (max_loop++ < 1000) { 1285106449Smdodd c = SCD_READ(sc, IREG_STATUS); 12867332Sjkh if (c == 0xff) 1287106451Smdodd return (EIO); 12887332Sjkh if (c & SBIT_ATTENTION) { 1289106449Smdodd process_attention(sc); 12907332Sjkh continue; 12917332Sjkh } 12927332Sjkh if ((c & bits_set) == bits_set && 12937332Sjkh (c & bits_clear) == 0) 12947332Sjkh { 12957332Sjkh break; 12967332Sjkh } 12977332Sjkh DELAY(10000); 12987332Sjkh } 12997332Sjkh } else { 13007332Sjkh max_loop = 100; 13017332Sjkh while (max_loop-- > 0) { 1302106449Smdodd c = SCD_READ(sc, IREG_STATUS); 13037332Sjkh if (c & SBIT_ATTENTION) { 1304106449Smdodd process_attention(sc); 13057332Sjkh continue; 13067332Sjkh } 13077332Sjkh if ((c & bits_set) == bits_set && 13087332Sjkh (c & bits_clear) == 0) 13097332Sjkh { 13107332Sjkh break; 13117332Sjkh } 13127332Sjkh tsleep(waitfor_status_bits, PZERO - 1, "waitfor", hz/10); 13137332Sjkh } 13147332Sjkh } 13157332Sjkh if ((c & bits_set) == bits_set && 13167332Sjkh (c & bits_clear) == 0) 13177332Sjkh { 1318106451Smdodd return (0); 13197332Sjkh } 13207332Sjkh#ifdef SCD_DEBUG 13217332Sjkh if (scd_debuglevel > 0) 1322106449Smdodd device_printf(sc->dev, "DEBUG: waitfor: TIMEOUT (0x%x,(0x%x,0x%x))\n", c, bits_set, bits_clear); 13237332Sjkh else 13247332Sjkh#endif 1325106449Smdodd device_printf(sc->dev, "timeout.\n"); 1326106451Smdodd return (EIO); 13277332Sjkh} 13287332Sjkh 13297332Sjkh/* these two routines for xcdplayer - "borrowed" from mcd.c */ 13307332Sjkhstatic int 1331106449Smdoddscd_toc_header (struct scd_softc *sc, struct ioc_toc_header* th) 13327332Sjkh{ 13337332Sjkh int rc; 13347332Sjkh 1335106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1336106449Smdodd print_error(sc, rc); 1337106451Smdodd return (EIO); 13387332Sjkh } 13397332Sjkh 1340106490Smdodd th->starting_track = sc->data.first_track; 1341106490Smdodd th->ending_track = sc->data.last_track; 13427332Sjkh th->len = 0; /* not used */ 13437332Sjkh 1344106451Smdodd return (0); 13457332Sjkh} 13467332Sjkh 13477332Sjkhstatic int 1348106449Smdoddscd_toc_entrys (struct scd_softc *sc, struct ioc_read_toc_entry *te) 13497332Sjkh{ 13507332Sjkh struct cd_toc_entry toc_entry; 13517332Sjkh int rc, i, len = te->data_len; 13527332Sjkh 1353106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1354106449Smdodd print_error(sc, rc); 1355106451Smdodd return (EIO); 13567332Sjkh } 13577332Sjkh 13587332Sjkh /* find the toc to copy*/ 13597332Sjkh i = te->starting_track; 13607332Sjkh if (i == SCD_LASTPLUS1) 1361106490Smdodd i = sc->data.last_track + 1; 13628876Srgrimes 13637332Sjkh /* verify starting track */ 1364106490Smdodd if (i < sc->data.first_track || i > sc->data.last_track+1) 1365106451Smdodd return (EINVAL); 13667332Sjkh 13677332Sjkh /* valid length ? */ 13687332Sjkh if (len < sizeof(struct cd_toc_entry) 13697332Sjkh || (len % sizeof(struct cd_toc_entry)) != 0) 1370106451Smdodd return (EINVAL); 13717332Sjkh 13727332Sjkh /* copy the toc data */ 1373106490Smdodd toc_entry.control = sc->data.toc[i].ctl; 13747332Sjkh toc_entry.addr_type = te->address_format; 13757332Sjkh toc_entry.track = i; 13767332Sjkh if (te->address_format == CD_MSF_FORMAT) { 13777332Sjkh toc_entry.addr.msf.unused = 0; 1378106490Smdodd toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0]); 1379106490Smdodd toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1]); 1380106490Smdodd toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2]); 13817332Sjkh } 13827332Sjkh 13837332Sjkh /* copy the data back */ 13847332Sjkh if (copyout(&toc_entry, te->data, sizeof(struct cd_toc_entry)) != 0) 1385106451Smdodd return (EFAULT); 13867332Sjkh 1387106451Smdodd return (0); 13887332Sjkh} 13897332Sjkh 139012517Sjulian 139125460Sjoergstatic int 1392106449Smdoddscd_toc_entry (struct scd_softc *sc, struct ioc_read_toc_single_entry *te) 139325460Sjoerg{ 139425460Sjoerg struct cd_toc_entry toc_entry; 139525460Sjoerg int rc, i; 139625460Sjoerg 1397106490Smdodd if (!(sc->data.flags & SCDTOC) && (rc = read_toc(sc)) != 0) { 1398106449Smdodd print_error(sc, rc); 1399106451Smdodd return (EIO); 140025460Sjoerg } 140125460Sjoerg 140225460Sjoerg /* find the toc to copy*/ 140325460Sjoerg i = te->track; 140425460Sjoerg if (i == SCD_LASTPLUS1) 1405106490Smdodd i = sc->data.last_track + 1; 140625460Sjoerg 140725460Sjoerg /* verify starting track */ 1408106490Smdodd if (i < sc->data.first_track || i > sc->data.last_track+1) 1409106451Smdodd return (EINVAL); 141025460Sjoerg 141125460Sjoerg /* copy the toc data */ 1412106490Smdodd toc_entry.control = sc->data.toc[i].ctl; 141325460Sjoerg toc_entry.addr_type = te->address_format; 141425460Sjoerg toc_entry.track = i; 141525460Sjoerg if (te->address_format == CD_MSF_FORMAT) { 141625460Sjoerg toc_entry.addr.msf.unused = 0; 1417106490Smdodd toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0]); 1418106490Smdodd toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1]); 1419106490Smdodd toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2]); 142025460Sjoerg } 142125460Sjoerg 142225460Sjoerg /* copy the data back */ 142325460Sjoerg bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry)); 142425460Sjoerg 1425106451Smdodd return (0); 142625460Sjoerg} 1427