| File: | modules/scd/../../dev/scd/scd.c |
| Warning: | line 596, column 7 Copies out a struct with a union element with different sizes |
| 1 | /*- | |||
| 2 | * Copyright (c) 1995 Mikael Hybsch | |||
| 3 | * All rights reserved. | |||
| 4 | * | |||
| 5 | * Portions of this file are copied from mcd.c | |||
| 6 | * which has the following copyrights: | |||
| 7 | * | |||
| 8 | * Copyright 1993 by Holger Veit (data part) | |||
| 9 | * Copyright 1993 by Brian Moore (audio part) | |||
| 10 | * Changes Copyright 1993 by Gary Clark II | |||
| 11 | * Changes Copyright (C) 1994 by Andrew A. Chernov | |||
| 12 | * | |||
| 13 | * Rewrote probe routine to work on newer Mitsumi drives. | |||
| 14 | * Additional changes (C) 1994 by Jordan K. Hubbard | |||
| 15 | * | |||
| 16 | * All rights reserved. | |||
| 17 | * | |||
| 18 | * Redistribution and use in source and binary forms, with or without | |||
| 19 | * modification, are permitted provided that the following conditions | |||
| 20 | * are met: | |||
| 21 | * 1. Redistributions of source code must retain the above copyright | |||
| 22 | * notice, this list of conditions and the following disclaimer | |||
| 23 | * in this position and unchanged. | |||
| 24 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 25 | * notice, this list of conditions and the following disclaimer in the | |||
| 26 | * documentation and/or other materials provided with the distribution. | |||
| 27 | * 3. The name of the author may not be used to endorse or promote products | |||
| 28 | * derived from this software without specific prior written permission | |||
| 29 | * | |||
| 30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 31 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 32 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 33 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 35 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 39 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 40 | * | |||
| 41 | */ | |||
| 42 | ||||
| 43 | #include <sys/cdefs.h> | |||
| 44 | __FBSDID("$FreeBSD: releng/11.0/sys/dev/scd/scd.c 298646 2016-04-26 15:03:15Z pfg $")__asm__(".ident\t\"" "$FreeBSD: releng/11.0/sys/dev/scd/scd.c 298646 2016-04-26 15:03:15Z pfg $" "\""); | |||
| 45 | ||||
| 46 | ||||
| 47 | #undef SCD_DEBUG | |||
| 48 | ||||
| 49 | #include <sys/param.h> | |||
| 50 | #include <sys/systm.h> | |||
| 51 | #include <sys/kernel.h> | |||
| 52 | #include <sys/conf.h> | |||
| 53 | #include <sys/fcntl.h> | |||
| 54 | #include <sys/bio.h> | |||
| 55 | #include <sys/cdio.h> | |||
| 56 | #include <sys/disk.h> | |||
| 57 | #include <sys/bus.h> | |||
| 58 | ||||
| 59 | #include <machine/stdarg.h> | |||
| 60 | ||||
| 61 | #include <machine/bus.h> | |||
| 62 | #include <machine/resource.h> | |||
| 63 | #include <sys/rman.h> | |||
| 64 | ||||
| 65 | #include <isa/isavar.h> | |||
| 66 | ||||
| 67 | #include <dev/scd/scdreg.h> | |||
| 68 | #include <dev/scd/scdvar.h> | |||
| 69 | ||||
| 70 | /* flags */ | |||
| 71 | #define SCDOPEN0x0001 0x0001 /* device opened */ | |||
| 72 | #define SCDVALID0x0002 0x0002 /* parameters loaded */ | |||
| 73 | #define SCDINIT0x0004 0x0004 /* device is init'd */ | |||
| 74 | #define SCDPROBING0x0020 0x0020 /* probing */ | |||
| 75 | #define SCDTOC0x0100 0x0100 /* already read toc */ | |||
| 76 | #define SCDMBXBSY0x0200 0x0200 /* local mbx is busy */ | |||
| 77 | #define SCDSPINNING0x0400 0x0400 /* drive is spun up */ | |||
| 78 | ||||
| 79 | #define SCD_S_BEGIN0 0 | |||
| 80 | #define SCD_S_BEGIN11 1 | |||
| 81 | #define SCD_S_WAITSTAT2 2 | |||
| 82 | #define SCD_S_WAITFIFO3 3 | |||
| 83 | #define SCD_S_WAITSPIN4 4 | |||
| 84 | #define SCD_S_WAITREAD5 5 | |||
| 85 | #define SCD_S_WAITPARAM6 6 | |||
| 86 | ||||
| 87 | #define RDELAY_WAIT300 300 | |||
| 88 | #define RDELAY_WAITREAD300 300 | |||
| 89 | ||||
| 90 | #define SCDBLKSIZE2048 2048 | |||
| 91 | ||||
| 92 | #ifdef SCD_DEBUG | |||
| 93 | static int scd_debuglevel = SCD_DEBUG; | |||
| 94 | # define XDEBUG(sc, level, fmt, args...) \ | |||
| 95 | do { \ | |||
| 96 | if (scd_debuglevel >= level) \ | |||
| 97 | device_printf(sc->dev, fmt, ## args); \ | |||
| 98 | } while (0) | |||
| 99 | #else | |||
| 100 | # define XDEBUG(sc, level, fmt, args...) | |||
| 101 | #endif | |||
| 102 | ||||
| 103 | #define IS_ATTENTION(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x01) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_ATTENTION0x01) != 0) | |||
| 104 | #define IS_BUSY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x80) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_BUSY0x80) != 0) | |||
| 105 | #define IS_DATA_RDY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x04) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_DATA_READY0x04) != 0) | |||
| 106 | #define STATUS_BIT(sc, bit)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (bit)) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (bit)) != 0) | |||
| 107 | #define FSTATUS_BIT(sc, bit)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (bit)) != 0) ((SCD_READ(sc, IREG_FSTATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (bit)) != 0) | |||
| 108 | ||||
| 109 | /* prototypes */ | |||
| 110 | static void hsg2msf(int hsg, bcd_t *msf); | |||
| 111 | static int msf2hsg(bcd_t *msf); | |||
| 112 | ||||
| 113 | static void process_attention(struct scd_softc *); | |||
| 114 | static int waitfor_status_bits(struct scd_softc *, int bits_set, int bits_clear); | |||
| 115 | static int send_cmd(struct scd_softc *, u_char cmd, u_int nargs, ...); | |||
| 116 | static void init_drive(struct scd_softc *); | |||
| 117 | static int spin_up(struct scd_softc *); | |||
| 118 | static int read_toc(struct scd_softc *); | |||
| 119 | static int get_result(struct scd_softc *, int result_len, u_char *result); | |||
| 120 | static void print_error(struct scd_softc *, int errcode); | |||
| 121 | ||||
| 122 | static void scd_start(struct scd_softc *); | |||
| 123 | static void scd_timeout(void *); | |||
| 124 | static void scd_doread(struct scd_softc *, int state, struct scd_mbx *mbxin); | |||
| 125 | ||||
| 126 | static int scd_eject(struct scd_softc *); | |||
| 127 | static int scd_stop(struct scd_softc *); | |||
| 128 | static int scd_pause(struct scd_softc *); | |||
| 129 | static int scd_resume(struct scd_softc *); | |||
| 130 | static int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt); | |||
| 131 | static int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf); | |||
| 132 | static int scd_play(struct scd_softc *, struct ioc_play_msf *msf); | |||
| 133 | static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch, int nocopyout); | |||
| 134 | static int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch); | |||
| 135 | ||||
| 136 | /* for xcdplayer */ | |||
| 137 | static int scd_toc_header(struct scd_softc *, struct ioc_toc_header *th); | |||
| 138 | static int scd_toc_entrys(struct scd_softc *, struct ioc_read_toc_entry *te); | |||
| 139 | static int scd_toc_entry(struct scd_softc *, struct ioc_read_toc_single_entry *te); | |||
| 140 | #define SCD_LASTPLUS1170 170 /* don't ask, xcdplayer passes this in */ | |||
| 141 | ||||
| 142 | static d_open_t scdopen; | |||
| 143 | static d_close_t scdclose; | |||
| 144 | static d_ioctl_t scdioctl; | |||
| 145 | static d_strategy_t scdstrategy; | |||
| 146 | ||||
| 147 | ||||
| 148 | static struct cdevsw scd_cdevsw = { | |||
| 149 | .d_version = D_VERSION0x17122009, | |||
| 150 | .d_open = scdopen, | |||
| 151 | .d_close = scdclose, | |||
| 152 | .d_read = physreadphysio, | |||
| 153 | .d_ioctl = scdioctl, | |||
| 154 | .d_strategy = scdstrategy, | |||
| 155 | .d_name = "scd", | |||
| 156 | .d_flags = D_DISK0x0002, | |||
| 157 | }; | |||
| 158 | ||||
| 159 | int | |||
| 160 | scd_attach(struct scd_softc *sc) | |||
| 161 | { | |||
| 162 | int unit; | |||
| 163 | ||||
| 164 | unit = device_get_unit(sc->dev); | |||
| 165 | ||||
| 166 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (166) ); | |||
| 167 | init_drive(sc); | |||
| 168 | ||||
| 169 | sc->data.flags = SCDINIT0x0004; | |||
| 170 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
| 171 | bioq_init(&sc->data.head); | |||
| 172 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (172 )); | |||
| 173 | ||||
| 174 | sc->scd_dev_t = make_dev(&scd_cdevsw, 8 * unit, | |||
| 175 | UID_ROOT0, GID_OPERATOR5, 0640, "scd%d", unit); | |||
| 176 | sc->scd_dev_t->si_drv1 = (void *)sc; | |||
| 177 | ||||
| 178 | return (0); | |||
| 179 | } | |||
| 180 | ||||
| 181 | static int | |||
| 182 | scdopen(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
| 183 | { | |||
| 184 | struct scd_softc *sc; | |||
| 185 | int rc; | |||
| 186 | ||||
| 187 | sc = (struct scd_softc *)dev->si_drv1; | |||
| 188 | ||||
| 189 | /* mark all open part's invalid */ | |||
| 190 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (190) ); | |||
| 191 | if (sc->data.openflag) { | |||
| 192 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (192 )); | |||
| 193 | return (ENXIO6); | |||
| 194 | } | |||
| 195 | ||||
| 196 | XDEBUG(sc, 1, "DEBUG: status = 0x%x\n", SCD_READ(sc, IREG_STATUS)); | |||
| 197 | ||||
| 198 | if ((rc = spin_up(sc)) != 0) { | |||
| 199 | print_error(sc, rc); | |||
| 200 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (200 )); | |||
| 201 | return (EIO5); | |||
| 202 | } | |||
| 203 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
| 204 | int loop_count = 3; | |||
| 205 | ||||
| 206 | while (loop_count-- > 0 && (rc = read_toc(sc)) != 0) { | |||
| 207 | if (rc == ERR_NOT_SPINNING0x22) { | |||
| 208 | rc = spin_up(sc); | |||
| 209 | if (rc) { | |||
| 210 | print_error(sc, rc); | |||
| 211 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (211 )); | |||
| 212 | return (EIO5); | |||
| 213 | } | |||
| 214 | continue; | |||
| 215 | } | |||
| 216 | device_printf(sc->dev, "TOC read error 0x%x\n", rc); | |||
| 217 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (217 )); | |||
| 218 | return (EIO5); | |||
| 219 | } | |||
| 220 | } | |||
| 221 | ||||
| 222 | sc->data.openflag = 1; | |||
| 223 | sc->data.flags |= SCDVALID0x0002; | |||
| 224 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (224 )); | |||
| 225 | ||||
| 226 | return (0); | |||
| 227 | } | |||
| 228 | ||||
| 229 | static int | |||
| 230 | scdclose(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
| 231 | { | |||
| 232 | struct scd_softc *sc; | |||
| 233 | ||||
| 234 | sc = (struct scd_softc *)dev->si_drv1; | |||
| 235 | ||||
| 236 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (236) ); | |||
| 237 | KASSERT(sc->data.openflag, ("device not open"))do { } while (0); | |||
| 238 | ||||
| 239 | if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS0x11) { | |||
| 240 | (void)send_cmd(sc, CMD_SPIN_DOWN0x52, 0); | |||
| 241 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
| 242 | } | |||
| 243 | ||||
| 244 | /* close channel */ | |||
| 245 | sc->data.openflag = 0; | |||
| 246 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (246 )); | |||
| 247 | ||||
| 248 | return (0); | |||
| 249 | } | |||
| 250 | ||||
| 251 | static void | |||
| 252 | scdstrategy(struct bio *bp) | |||
| 253 | { | |||
| 254 | struct scd_softc *sc; | |||
| 255 | ||||
| 256 | sc = (struct scd_softc *)bp->bio_dev->si_drv1; | |||
| 257 | ||||
| 258 | /* if device invalidated (e.g. media change, door open), error */ | |||
| 259 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (259) ); | |||
| 260 | if (!(sc->data.flags & SCDVALID0x0002)) { | |||
| 261 | device_printf(sc->dev, "media changed\n"); | |||
| 262 | bp->bio_error = EIO5; | |||
| 263 | goto bad; | |||
| 264 | } | |||
| 265 | ||||
| 266 | /* read only */ | |||
| 267 | if (!(bp->bio_cmd == BIO_READ0x01)) { | |||
| 268 | bp->bio_error = EROFS30; | |||
| 269 | goto bad; | |||
| 270 | } | |||
| 271 | ||||
| 272 | /* no data to read */ | |||
| 273 | if (bp->bio_bcount == 0) | |||
| 274 | goto done; | |||
| 275 | ||||
| 276 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
| 277 | bp->bio_error = EIO5; | |||
| 278 | goto bad; | |||
| 279 | } | |||
| 280 | ||||
| 281 | bp->bio_resid = 0; | |||
| 282 | ||||
| 283 | /* queue it */ | |||
| 284 | bioq_disksort(&sc->data.head, bp); | |||
| 285 | ||||
| 286 | /* now check whether we can perform processing */ | |||
| 287 | scd_start(sc); | |||
| 288 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (288 )); | |||
| 289 | return; | |||
| 290 | ||||
| 291 | bad: | |||
| 292 | bp->bio_flags |= BIO_ERROR0x01; | |||
| 293 | done: | |||
| 294 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (294 )); | |||
| 295 | bp->bio_resid = bp->bio_bcount; | |||
| 296 | biodone(bp); | |||
| 297 | return; | |||
| 298 | } | |||
| 299 | ||||
| 300 | static void | |||
| 301 | scd_start(struct scd_softc *sc) | |||
| 302 | { | |||
| 303 | struct bio *bp; | |||
| 304 | ||||
| 305 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
| 306 | if (sc->data.flags & SCDMBXBSY0x0200) | |||
| 307 | return; | |||
| 308 | ||||
| 309 | bp = bioq_takefirst(&sc->data.head); | |||
| 310 | if (bp != 0) { | |||
| 311 | /* block found to process, dequeue */ | |||
| 312 | sc->data.flags |= SCDMBXBSY0x0200; | |||
| 313 | } else { | |||
| 314 | /* nothing to do */ | |||
| 315 | return; | |||
| 316 | } | |||
| 317 | ||||
| 318 | sc->data.mbx.retry = 3; | |||
| 319 | sc->data.mbx.bp = bp; | |||
| 320 | ||||
| 321 | scd_doread(sc, SCD_S_BEGIN0, &(sc->data.mbx)); | |||
| 322 | return; | |||
| 323 | } | |||
| 324 | ||||
| 325 | static int | |||
| 326 | scdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) | |||
| 327 | { | |||
| 328 | struct scd_softc *sc; | |||
| 329 | int error; | |||
| 330 | ||||
| 331 | sc = (struct scd_softc *)dev->si_drv1; | |||
| 332 | ||||
| 333 | XDEBUG(sc, 1, "ioctl: cmd=0x%lx\n", cmd); | |||
| 334 | ||||
| 335 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (335) ); | |||
| 336 | if (!(sc->data.flags & SCDVALID0x0002)) { | |||
| ||||
| 337 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (337 )); | |||
| 338 | return (EIO5); | |||
| 339 | } | |||
| 340 | ||||
| 341 | error = 0; | |||
| 342 | switch (cmd) { | |||
| 343 | case DIOCGMEDIASIZE((unsigned long) ((0x40000000) | (((sizeof(off_t)) & ((1 << 13) - 1)) << 16) | ((('d')) << 8) | ((129)))): | |||
| 344 | *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; | |||
| 345 | break; | |||
| 346 | case DIOCGSECTORSIZE((unsigned long) ((0x40000000) | (((sizeof(u_int)) & ((1 << 13) - 1)) << 16) | ((('d')) << 8) | ((128)))): | |||
| 347 | *(u_int *)addr = sc->data.blksize; | |||
| 348 | break; | |||
| 349 | case CDIOCPLAYTRACKS((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_track )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((1)))): | |||
| 350 | error = scd_playtracks(sc, (struct ioc_play_track *) addr); | |||
| 351 | break; | |||
| 352 | case CDIOCPLAYBLOCKS((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_blocks )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((2)))): | |||
| 353 | error = EINVAL22; | |||
| 354 | break; | |||
| 355 | case CDIOCPLAYMSF((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_msf )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((25)))): | |||
| 356 | error = scd_playmsf(sc, (struct ioc_play_msf *) addr); | |||
| 357 | break; | |||
| 358 | case CDIOCREADSUBCHANNEL_SYSSPACE((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_subchannel)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((31)))): | |||
| 359 | return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); | |||
| 360 | case CDIOCREADSUBCHANNEL((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_subchannel)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((3)))): | |||
| 361 | return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); | |||
| 362 | case CDIOREADTOCHEADER((unsigned long) ((0x40000000) | (((sizeof(struct ioc_toc_header )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((4)))): | |||
| 363 | error = scd_toc_header (sc, (struct ioc_toc_header *) addr); | |||
| 364 | break; | |||
| 365 | case CDIOREADTOCENTRYS((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_toc_entry)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((5)))): | |||
| 366 | return scd_toc_entrys (sc, (struct ioc_read_toc_entry*) addr); | |||
| 367 | case CDIOREADTOCENTRY((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_toc_single_entry)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((6)))): | |||
| 368 | error = scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr); | |||
| 369 | break; | |||
| 370 | case CDIOCSETPATCH((unsigned long) ((0x80000000) | (((sizeof(struct ioc_patch)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((9)))): | |||
| 371 | case CDIOCGETVOL((unsigned long) ((0x40000000) | (((sizeof(struct ioc_vol)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((10)))): | |||
| 372 | case CDIOCSETVOL((unsigned long) ((0x80000000) | (((sizeof(struct ioc_vol)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((11)))): | |||
| 373 | case CDIOCSETMONO((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((12)))): | |||
| 374 | case CDIOCSETSTERIO((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((13)))): | |||
| 375 | case CDIOCSETMUTE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((14)))): | |||
| 376 | case CDIOCSETLEFT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((15)))): | |||
| 377 | case CDIOCSETRIGHT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((16)))): | |||
| 378 | error = EINVAL22; | |||
| 379 | break; | |||
| 380 | case CDIOCRESUME((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((20)))): | |||
| 381 | error = scd_resume(sc); | |||
| 382 | break; | |||
| 383 | case CDIOCPAUSE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((19)))): | |||
| 384 | error = scd_pause(sc); | |||
| 385 | break; | |||
| 386 | case CDIOCSTART((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((22)))): | |||
| 387 | error = EINVAL22; | |||
| 388 | break; | |||
| 389 | case CDIOCSTOP((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((23)))): | |||
| 390 | error = scd_stop(sc); | |||
| 391 | break; | |||
| 392 | case CDIOCEJECT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((24)))): | |||
| 393 | error = scd_eject(sc); | |||
| 394 | break; | |||
| 395 | case CDIOCALLOW((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((26)))): | |||
| 396 | break; | |||
| 397 | case CDIOCSETDEBUG((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((17)))): | |||
| 398 | #ifdef SCD_DEBUG | |||
| 399 | scd_debuglevel++; | |||
| 400 | #endif | |||
| 401 | break; | |||
| 402 | case CDIOCCLRDEBUG((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((18)))): | |||
| 403 | #ifdef SCD_DEBUG | |||
| 404 | scd_debuglevel = 0; | |||
| 405 | ||||
| 406 | #endif | |||
| 407 | break; | |||
| 408 | default: | |||
| 409 | device_printf(sc->dev, "unsupported ioctl (cmd=0x%lx)\n", cmd); | |||
| 410 | error = ENOTTY25; | |||
| 411 | break; | |||
| 412 | } | |||
| 413 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (413 )); | |||
| 414 | return (error); | |||
| 415 | } | |||
| 416 | ||||
| 417 | /*************************************************************** | |||
| 418 | * lower level of driver starts here | |||
| 419 | **************************************************************/ | |||
| 420 | ||||
| 421 | static int | |||
| 422 | scd_playtracks(struct scd_softc *sc, struct ioc_play_track *pt) | |||
| 423 | { | |||
| 424 | struct ioc_play_msf msf; | |||
| 425 | int a = pt->start_track; | |||
| 426 | int z = pt->end_track; | |||
| 427 | int rc; | |||
| 428 | ||||
| 429 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
| 430 | if (rc == -ERR_NOT_SPINNING0x22) { | |||
| 431 | if (spin_up(sc) != 0) | |||
| 432 | return (EIO5); | |||
| 433 | rc = read_toc(sc); | |||
| 434 | } | |||
| 435 | if (rc != 0) { | |||
| 436 | print_error(sc, rc); | |||
| 437 | return (EIO5); | |||
| 438 | } | |||
| 439 | } | |||
| 440 | ||||
| 441 | XDEBUG(sc, 1, "playtracks from %d:%d to %d:%d\n", | |||
| 442 | a, pt->start_index, z, pt->end_index); | |||
| 443 | ||||
| 444 | if ( a < sc->data.first_track | |||
| 445 | || a > sc->data.last_track | |||
| 446 | || a > z | |||
| 447 | || z > sc->data.last_track) | |||
| 448 | return (EINVAL22); | |||
| 449 | ||||
| 450 | bcopy(sc->data.toc[a].start_msf, &msf.start_m, 3); | |||
| 451 | hsg2msf(msf2hsg(sc->data.toc[z+1].start_msf)-1, &msf.end_m); | |||
| 452 | ||||
| 453 | return scd_play(sc, &msf); | |||
| 454 | } | |||
| 455 | ||||
| 456 | /* The start/end msf is expected to be in bin format */ | |||
| 457 | static int | |||
| 458 | scd_playmsf(struct scd_softc *sc, struct ioc_play_msf *msfin) | |||
| 459 | { | |||
| 460 | struct ioc_play_msf msf; | |||
| 461 | ||||
| 462 | msf.start_m = bin2bcd(msfin->start_m)(bin2bcd_data[msfin->start_m]); | |||
| 463 | msf.start_s = bin2bcd(msfin->start_s)(bin2bcd_data[msfin->start_s]); | |||
| 464 | msf.start_f = bin2bcd(msfin->start_f)(bin2bcd_data[msfin->start_f]); | |||
| 465 | msf.end_m = bin2bcd(msfin->end_m)(bin2bcd_data[msfin->end_m]); | |||
| 466 | msf.end_s = bin2bcd(msfin->end_s)(bin2bcd_data[msfin->end_s]); | |||
| 467 | msf.end_f = bin2bcd(msfin->end_f)(bin2bcd_data[msfin->end_f]); | |||
| 468 | ||||
| 469 | return scd_play(sc, &msf); | |||
| 470 | } | |||
| 471 | ||||
| 472 | /* The start/end msf is expected to be in bcd format */ | |||
| 473 | static int | |||
| 474 | scd_play(struct scd_softc *sc, struct ioc_play_msf *msf) | |||
| 475 | { | |||
| 476 | int i, rc; | |||
| 477 | ||||
| 478 | XDEBUG(sc, 1, "playing: %02x:%02x:%02x -> %02x:%02x:%02x\n", | |||
| 479 | msf->start_m, msf->start_s, msf->start_f, | |||
| 480 | msf->end_m, msf->end_s, msf->end_f); | |||
| 481 | ||||
| 482 | for (i = 0; i < 2; i++) { | |||
| 483 | rc = send_cmd(sc, CMD_PLAY_AUDIO0x40, 7, | |||
| 484 | 0x03, | |||
| 485 | msf->start_m, msf->start_s, msf->start_f, | |||
| 486 | msf->end_m, msf->end_s, msf->end_f); | |||
| 487 | if (rc == -ERR_NOT_SPINNING0x22) { | |||
| 488 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
| 489 | if (spin_up(sc) != 0) | |||
| 490 | return (EIO5); | |||
| 491 | } else if (rc < 0) { | |||
| 492 | print_error(sc, rc); | |||
| 493 | return (EIO5); | |||
| 494 | } else { | |||
| 495 | break; | |||
| 496 | } | |||
| 497 | } | |||
| 498 | sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS0x11; | |||
| 499 | bcopy((char *)msf, (char *)&sc->data.last_play, sizeof(struct ioc_play_msf)); | |||
| 500 | return (0); | |||
| 501 | } | |||
| 502 | ||||
| 503 | static int | |||
| 504 | scd_stop(struct scd_softc *sc) | |||
| 505 | { | |||
| 506 | ||||
| 507 | (void)send_cmd(sc, CMD_STOP_AUDIO0x41, 0); | |||
| 508 | sc->data.audio_status = CD_AS_PLAY_COMPLETED0x13; | |||
| 509 | return (0); | |||
| 510 | } | |||
| 511 | ||||
| 512 | static int | |||
| 513 | scd_pause(struct scd_softc *sc) | |||
| 514 | { | |||
| 515 | struct sony_subchannel_position_data subpos; | |||
| 516 | ||||
| 517 | if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS0x11) | |||
| 518 | return (EINVAL22); | |||
| 519 | ||||
| 520 | if (read_subcode(sc, &subpos) != 0) | |||
| 521 | return (EIO5); | |||
| 522 | ||||
| 523 | if (send_cmd(sc, CMD_STOP_AUDIO0x41, 0) != 0) | |||
| 524 | return (EIO5); | |||
| 525 | ||||
| 526 | sc->data.last_play.start_m = subpos.abs_msf[0]; | |||
| 527 | sc->data.last_play.start_s = subpos.abs_msf[1]; | |||
| 528 | sc->data.last_play.start_f = subpos.abs_msf[2]; | |||
| 529 | sc->data.audio_status = CD_AS_PLAY_PAUSED0x12; | |||
| 530 | ||||
| 531 | XDEBUG(sc, 1, "pause @ %02x:%02x:%02x\n", | |||
| 532 | sc->data.last_play.start_m, | |||
| 533 | sc->data.last_play.start_s, | |||
| 534 | sc->data.last_play.start_f); | |||
| 535 | ||||
| 536 | return (0); | |||
| 537 | } | |||
| 538 | ||||
| 539 | static int | |||
| 540 | scd_resume(struct scd_softc *sc) | |||
| 541 | { | |||
| 542 | ||||
| 543 | if (sc->data.audio_status != CD_AS_PLAY_PAUSED0x12) | |||
| 544 | return (EINVAL22); | |||
| 545 | return scd_play(sc, &sc->data.last_play); | |||
| 546 | } | |||
| 547 | ||||
| 548 | static int | |||
| 549 | scd_eject(struct scd_softc *sc) | |||
| 550 | { | |||
| 551 | ||||
| 552 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
| 553 | sc->data.flags &= ~(SCDSPINNING0x0400|SCDTOC0x0100); | |||
| 554 | ||||
| 555 | if (send_cmd(sc, CMD_STOP_AUDIO0x41, 0) != 0 || | |||
| 556 | send_cmd(sc, CMD_SPIN_DOWN0x52, 0) != 0 || | |||
| 557 | send_cmd(sc, CMD_EJECT0x50, 0) != 0) | |||
| 558 | { | |||
| 559 | return (EIO5); | |||
| 560 | } | |||
| 561 | return (0); | |||
| 562 | } | |||
| 563 | ||||
| 564 | static int | |||
| 565 | scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) | |||
| 566 | { | |||
| 567 | struct sony_subchannel_position_data q; | |||
| 568 | struct cd_sub_channel_info data; | |||
| 569 | ||||
| 570 | XDEBUG(sc, 1, "subchan af=%d, df=%d\n", | |||
| 571 | sch->address_format, sch->data_format); | |||
| 572 | ||||
| 573 | if (sch->address_format != CD_MSF_FORMAT2) | |||
| 574 | return (EINVAL22); | |||
| 575 | ||||
| 576 | if (sch->data_format != CD_CURRENT_POSITION1) | |||
| 577 | return (EINVAL22); | |||
| 578 | ||||
| 579 | if (read_subcode(sc, &q) != 0) | |||
| 580 | return (EIO5); | |||
| 581 | ||||
| 582 | data.header.audio_status = sc->data.audio_status; | |||
| 583 | data.what.position.data_format = CD_MSF_FORMAT2; | |||
| 584 | data.what.position.track_number = bcd2bin(q.track_number)(bcd2bin_data[q.track_number]); | |||
| 585 | data.what.position.reladdr.msf.unused = 0; | |||
| 586 | data.what.position.reladdr.msf.minute = bcd2bin(q.rel_msf[0])(bcd2bin_data[q.rel_msf[0]]); | |||
| 587 | data.what.position.reladdr.msf.second = bcd2bin(q.rel_msf[1])(bcd2bin_data[q.rel_msf[1]]); | |||
| 588 | data.what.position.reladdr.msf.frame = bcd2bin(q.rel_msf[2])(bcd2bin_data[q.rel_msf[2]]); | |||
| 589 | data.what.position.absaddr.msf.unused = 0; | |||
| 590 | data.what.position.absaddr.msf.minute = bcd2bin(q.abs_msf[0])(bcd2bin_data[q.abs_msf[0]]); | |||
| 591 | data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1])(bcd2bin_data[q.abs_msf[1]]); | |||
| 592 | data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2])(bcd2bin_data[q.abs_msf[2]]); | |||
| 593 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (593 )); | |||
| 594 | ||||
| 595 | if (nocopyout == 0) { | |||
| 596 | if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) | |||
| ||||
| 597 | return (EFAULT14); | |||
| 598 | } else { | |||
| 599 | bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); | |||
| 600 | } | |||
| 601 | return (0); | |||
| 602 | } | |||
| 603 | ||||
| 604 | int | |||
| 605 | scd_probe(struct scd_softc *sc) | |||
| 606 | { | |||
| 607 | struct sony_drive_configuration drive_config; | |||
| 608 | int rc; | |||
| 609 | static char namebuf[8+16+8+3]; | |||
| 610 | char *s = namebuf; | |||
| 611 | int loop_count = 0; | |||
| 612 | ||||
| 613 | sc->data.flags = SCDPROBING0x0020; | |||
| 614 | ||||
| 615 | bzero(&drive_config, sizeof(drive_config)); | |||
| 616 | ||||
| 617 | again: | |||
| 618 | /* Reset drive */ | |||
| 619 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESET_DRIVE)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x80)); | |||
| 620 | ||||
| 621 | /* Calm down */ | |||
| 622 | DELAY(300000); | |||
| 623 | ||||
| 624 | /* Only the ATTENTION bit may be set */ | |||
| 625 | if ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & ~1) != 0) { | |||
| 626 | XDEBUG(sc, 1, "too many bits set. probe failed.\n"); | |||
| 627 | return (ENXIO6); | |||
| 628 | } | |||
| 629 | rc = send_cmd(sc, CMD_GET_DRIVE_CONFIG0x00, 0); | |||
| 630 | if (rc != sizeof(drive_config)) { | |||
| 631 | /* Sometimes if the drive is playing audio I get */ | |||
| 632 | /* the bad result 82. Fix by repeating the reset */ | |||
| 633 | if (rc > 0 && loop_count++ == 0) | |||
| 634 | goto again; | |||
| 635 | return (ENXIO6); | |||
| 636 | } | |||
| 637 | if (get_result(sc, rc, (u_char *)&drive_config) != 0) | |||
| 638 | return (ENXIO6); | |||
| 639 | ||||
| 640 | bcopy(drive_config.vendor, namebuf, 8); | |||
| 641 | s = namebuf+8; | |||
| 642 | while (*(s-1) == ' ') /* Strip trailing spaces */ | |||
| 643 | s--; | |||
| 644 | *s++ = ' '; | |||
| 645 | bcopy(drive_config.product, s, 16); | |||
| 646 | s += 16; | |||
| 647 | while (*(s-1) == ' ') | |||
| 648 | s--; | |||
| 649 | *s++ = ' '; | |||
| 650 | bcopy(drive_config.revision, s, 8); | |||
| 651 | s += 8; | |||
| 652 | while (*(s-1) == ' ') | |||
| 653 | s--; | |||
| 654 | *s = 0; | |||
| 655 | ||||
| 656 | sc->data.name = namebuf; | |||
| 657 | ||||
| 658 | if (drive_config.config & 0x10) | |||
| 659 | sc->data.double_speed = 1; | |||
| 660 | else | |||
| 661 | sc->data.double_speed = 0; | |||
| 662 | ||||
| 663 | return (0); | |||
| 664 | } | |||
| 665 | ||||
| 666 | static int | |||
| 667 | read_subcode(struct scd_softc *sc, struct sony_subchannel_position_data *scp) | |||
| 668 | { | |||
| 669 | int rc; | |||
| 670 | ||||
| 671 | rc = send_cmd(sc, CMD_GET_SUBCHANNEL_DATA0x21, 0); | |||
| 672 | if (rc < 0 || rc < sizeof(*scp)) | |||
| 673 | return (EIO5); | |||
| 674 | if (get_result(sc, rc, (u_char *)scp) != 0) | |||
| 675 | return (EIO5); | |||
| 676 | return (0); | |||
| 677 | } | |||
| 678 | ||||
| 679 | /* State machine copied from mcd.c */ | |||
| 680 | ||||
| 681 | /* This (and the code in mcd.c) will not work with more than one drive */ | |||
| 682 | /* because there is only one sc->ch_mbxsave below. Should fix that some day. */ | |||
| 683 | /* (sc->ch_mbxsave & state should probably be included in the scd_data struct and */ | |||
| 684 | /* the unit number used as first argument to scd_doread().) /Micke */ | |||
| 685 | ||||
| 686 | /* state machine to process read requests | |||
| 687 | * initialize with SCD_S_BEGIN: reset state machine | |||
| 688 | * SCD_S_WAITSTAT: wait for ready (!busy) | |||
| 689 | * SCD_S_WAITSPIN: wait for drive to spin up (if not spinning) | |||
| 690 | * SCD_S_WAITFIFO: wait for param fifo to get ready, them exec. command. | |||
| 691 | * SCD_S_WAITREAD: wait for data ready, read data | |||
| 692 | * SCD_S_WAITPARAM: wait for command result params, read them, error if bad data read. | |||
| 693 | */ | |||
| 694 | ||||
| 695 | static void | |||
| 696 | scd_timeout(void *arg) | |||
| 697 | { | |||
| 698 | struct scd_softc *sc; | |||
| 699 | sc = (struct scd_softc *)arg; | |||
| 700 | ||||
| 701 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
| 702 | scd_doread(sc, sc->ch_state, sc->ch_mbxsave); | |||
| 703 | } | |||
| 704 | ||||
| 705 | static void | |||
| 706 | scd_doread(struct scd_softc *sc, int state, struct scd_mbx *mbxin) | |||
| 707 | { | |||
| 708 | struct scd_mbx *mbx = (state!=SCD_S_BEGIN0) ? sc->ch_mbxsave : mbxin; | |||
| 709 | struct bio *bp = mbx->bp; | |||
| 710 | int i; | |||
| 711 | int blknum; | |||
| 712 | caddr_t addr; | |||
| 713 | static char sdata[3]; /* Must be preserved between calls to this function */ | |||
| 714 | ||||
| 715 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
| 716 | loop: | |||
| 717 | switch (state) { | |||
| 718 | case SCD_S_BEGIN0: | |||
| 719 | mbx = sc->ch_mbxsave = mbxin; | |||
| 720 | ||||
| 721 | case SCD_S_BEGIN11: | |||
| 722 | /* get status */ | |||
| 723 | mbx->count = RDELAY_WAIT300; | |||
| 724 | ||||
| 725 | process_attention(sc); | |||
| 726 | goto trystat; | |||
| 727 | ||||
| 728 | case SCD_S_WAITSTAT2: | |||
| 729 | sc->ch_state = SCD_S_WAITSTAT2; | |||
| 730 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
| 731 | if (mbx->count-- <= 0) { | |||
| 732 | device_printf(sc->dev, "timeout. drive busy.\n"); | |||
| 733 | goto harderr; | |||
| 734 | } | |||
| 735 | ||||
| 736 | trystat: | |||
| 737 | if (IS_BUSY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x80) != 0)) { | |||
| 738 | sc->ch_state = SCD_S_WAITSTAT2; | |||
| 739 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 740 | return; | |||
| 741 | } | |||
| 742 | ||||
| 743 | process_attention(sc); | |||
| 744 | ||||
| 745 | /* reject, if audio active */ | |||
| 746 | if (sc->data.audio_status & CD_AS_PLAY_IN_PROGRESS0x11) { | |||
| 747 | device_printf(sc->dev, "audio is active\n"); | |||
| 748 | goto harderr; | |||
| 749 | } | |||
| 750 | ||||
| 751 | mbx->sz = sc->data.blksize; | |||
| 752 | ||||
| 753 | /* for first block */ | |||
| 754 | mbx->nblk = howmany(bp->bio_bcount, mbx->sz)(((bp->bio_bcount)+((mbx->sz)-1))/(mbx->sz)); | |||
| 755 | mbx->skip = 0; | |||
| 756 | ||||
| 757 | nextblock: | |||
| 758 | if (!(sc->data.flags & SCDVALID0x0002)) | |||
| 759 | goto changed; | |||
| 760 | ||||
| 761 | blknum = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz; | |||
| 762 | ||||
| 763 | XDEBUG(sc, 2, "scd_doread: read blknum=%d\n", blknum); | |||
| 764 | ||||
| 765 | /* build parameter block */ | |||
| 766 | hsg2msf(blknum, sdata); | |||
| 767 | ||||
| 768 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 769 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x40)); | |||
| 770 | SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x04)); | |||
| 771 | ||||
| 772 | if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) | |||
| 773 | goto writeparam; | |||
| 774 | ||||
| 775 | mbx->count = 100; | |||
| 776 | sc->ch_state = SCD_S_WAITFIFO3; | |||
| 777 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 778 | return; | |||
| 779 | ||||
| 780 | case SCD_S_WAITSPIN4: | |||
| 781 | sc->ch_state = SCD_S_WAITSPIN4; | |||
| 782 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
| 783 | if (mbx->count-- <= 0) { | |||
| 784 | device_printf(sc->dev, "timeout waiting for drive to spin up.\n"); | |||
| 785 | goto harderr; | |||
| 786 | } | |||
| 787 | if (!STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) { | |||
| 788 | sc->ch_state = SCD_S_WAITSPIN4; | |||
| 789 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 790 | return; | |||
| 791 | } | |||
| 792 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 793 | switch ((i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
| 794 | case 0x20: | |||
| 795 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 796 | print_error(sc, i); | |||
| 797 | goto harderr; | |||
| 798 | case 0x00: | |||
| 799 | (void)SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 800 | sc->data.flags |= SCDSPINNING0x0400; | |||
| 801 | break; | |||
| 802 | } | |||
| 803 | XDEBUG(sc, 1, "DEBUG: spin up complete\n"); | |||
| 804 | ||||
| 805 | state = SCD_S_BEGIN11; | |||
| 806 | goto loop; | |||
| 807 | ||||
| 808 | case SCD_S_WAITFIFO3: | |||
| 809 | sc->ch_state = SCD_S_WAITFIFO3; | |||
| 810 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
| 811 | if (mbx->count-- <= 0) { | |||
| 812 | device_printf(sc->dev, "timeout. write param not ready.\n"); | |||
| 813 | goto harderr; | |||
| 814 | } | |||
| 815 | if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) { | |||
| 816 | sc->ch_state = SCD_S_WAITFIFO3; | |||
| 817 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 818 | return; | |||
| 819 | } | |||
| 820 | XDEBUG(sc, 1, "mbx->count (writeparamwait) = %d(%d)\n", mbx->count, 100); | |||
| 821 | ||||
| 822 | writeparam: | |||
| 823 | /* The reason this test isn't done 'till now is to make sure */ | |||
| 824 | /* that it is ok to send the SPIN_UP cmd below. */ | |||
| 825 | if (!(sc->data.flags & SCDSPINNING0x0400)) { | |||
| 826 | XDEBUG(sc, 1, "spinning up drive ...\n"); | |||
| 827 | SCD_WRITE(sc, OREG_COMMAND, CMD_SPIN_UP)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (0x51)); | |||
| 828 | mbx->count = 300; | |||
| 829 | sc->ch_state = SCD_S_WAITSPIN4; | |||
| 830 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 831 | return; | |||
| 832 | } | |||
| 833 | ||||
| 834 | /* send the read command */ | |||
| 835 | SCD_WRITE(sc, OREG_WPARAMS, sdata[0])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[0])); | |||
| 836 | SCD_WRITE(sc, OREG_WPARAMS, sdata[1])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[1])); | |||
| 837 | SCD_WRITE(sc, OREG_WPARAMS, sdata[2])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[2])); | |||
| 838 | SCD_WRITE(sc, OREG_WPARAMS, 0)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (0)); | |||
| 839 | SCD_WRITE(sc, OREG_WPARAMS, 0)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (0)); | |||
| 840 | SCD_WRITE(sc, OREG_WPARAMS, 1)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (1)); | |||
| 841 | SCD_WRITE(sc, OREG_COMMAND, CMD_READ)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (0x34)); | |||
| 842 | ||||
| 843 | mbx->count = RDELAY_WAITREAD300; | |||
| 844 | for (i = 0; i < 50; i++) { | |||
| 845 | if (STATUS_BIT(sc, SBIT_DATA_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x04)) != 0)) | |||
| 846 | goto got_data; | |||
| 847 | DELAY(100); | |||
| 848 | } | |||
| 849 | ||||
| 850 | sc->ch_state = SCD_S_WAITREAD5; | |||
| 851 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 852 | return; | |||
| 853 | ||||
| 854 | case SCD_S_WAITREAD5: | |||
| 855 | sc->ch_state = SCD_S_WAITREAD5; | |||
| 856 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
| 857 | if (mbx->count-- <= 0) { | |||
| 858 | if (STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) | |||
| 859 | goto got_param; | |||
| 860 | device_printf(sc->dev, "timeout while reading data\n"); | |||
| 861 | goto readerr; | |||
| 862 | } | |||
| 863 | if (!STATUS_BIT(sc, SBIT_DATA_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x04)) != 0)) { | |||
| 864 | process_attention(sc); | |||
| 865 | if (!(sc->data.flags & SCDVALID0x0002)) | |||
| 866 | goto changed; | |||
| 867 | sc->ch_state = SCD_S_WAITREAD5; | |||
| 868 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 869 | return; | |||
| 870 | } | |||
| 871 | XDEBUG(sc, 2, "mbx->count (after RDY_BIT) = %d(%d)\n", mbx->count, RDELAY_WAITREAD); | |||
| 872 | ||||
| 873 | got_data: | |||
| 874 | /* data is ready */ | |||
| 875 | addr = bp->bio_data + mbx->skip; | |||
| 876 | SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x04)); | |||
| 877 | SCD_READ_MULTI(sc, IREG_DATA, addr, mbx->sz)bus_space_read_multi_1((sc->port)->r_bustag, (sc->port )->r_bushandle, (2), (addr), (mbx->sz)); | |||
| 878 | ||||
| 879 | mbx->count = 100; | |||
| 880 | for (i = 0; i < 20; i++) { | |||
| 881 | if (STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) | |||
| 882 | goto waitfor_param; | |||
| 883 | DELAY(100); | |||
| 884 | } | |||
| 885 | goto waitfor_param; | |||
| 886 | ||||
| 887 | case SCD_S_WAITPARAM6: | |||
| 888 | sc->ch_state = SCD_S_WAITPARAM6; | |||
| 889 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
| 890 | if (mbx->count-- <= 0) { | |||
| 891 | device_printf(sc->dev, "timeout waiting for params\n"); | |||
| 892 | goto readerr; | |||
| 893 | } | |||
| 894 | ||||
| 895 | waitfor_param: | |||
| 896 | if (!STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) { | |||
| 897 | sc->ch_state = SCD_S_WAITPARAM6; | |||
| 898 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
| 899 | return; | |||
| 900 | } | |||
| 901 | #ifdef SCD_DEBUG | |||
| 902 | if (mbx->count < 100 && scd_debuglevel > 0) | |||
| 903 | device_printf(sc->dev, "mbx->count (paramwait) = %d(%d)\n", mbx->count, 100); | |||
| 904 | #endif | |||
| 905 | ||||
| 906 | got_param: | |||
| 907 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 908 | switch ((i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
| 909 | case 0x50: | |||
| 910 | switch (i) { | |||
| 911 | case ERR_FATAL_READ_ERROR10x53: | |||
| 912 | case ERR_FATAL_READ_ERROR20x57: | |||
| 913 | device_printf(sc->dev, "unrecoverable read error 0x%x\n", i); | |||
| 914 | goto harderr; | |||
| 915 | } | |||
| 916 | break; | |||
| 917 | case 0x20: | |||
| 918 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 919 | switch (i) { | |||
| 920 | case ERR_NOT_SPINNING0x22: | |||
| 921 | XDEBUG(sc, 1, "read error: drive not spinning\n"); | |||
| 922 | if (mbx->retry-- > 0) { | |||
| 923 | state = SCD_S_BEGIN11; | |||
| 924 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
| 925 | goto loop; | |||
| 926 | } | |||
| 927 | goto harderr; | |||
| 928 | default: | |||
| 929 | print_error(sc, i); | |||
| 930 | goto readerr; | |||
| 931 | } | |||
| 932 | case 0x00: | |||
| 933 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 934 | break; | |||
| 935 | } | |||
| 936 | ||||
| 937 | if (--mbx->nblk > 0) { | |||
| 938 | mbx->skip += mbx->sz; | |||
| 939 | goto nextblock; | |||
| 940 | } | |||
| 941 | ||||
| 942 | /* return buffer */ | |||
| 943 | bp->bio_resid = 0; | |||
| 944 | biodone(bp); | |||
| 945 | ||||
| 946 | sc->data.flags &= ~SCDMBXBSY0x0200; | |||
| 947 | scd_start(sc); | |||
| 948 | return; | |||
| 949 | } | |||
| 950 | ||||
| 951 | readerr: | |||
| 952 | if (mbx->retry-- > 0) { | |||
| 953 | device_printf(sc->dev, "retrying ...\n"); | |||
| 954 | state = SCD_S_BEGIN11; | |||
| 955 | goto loop; | |||
| 956 | } | |||
| 957 | harderr: | |||
| 958 | /* invalidate the buffer */ | |||
| 959 | bp->bio_error = EIO5; | |||
| 960 | bp->bio_flags |= BIO_ERROR0x01; | |||
| 961 | bp->bio_resid = bp->bio_bcount; | |||
| 962 | biodone(bp); | |||
| 963 | ||||
| 964 | sc->data.flags &= ~SCDMBXBSY0x0200; | |||
| 965 | scd_start(sc); | |||
| 966 | return; | |||
| 967 | ||||
| 968 | changed: | |||
| 969 | device_printf(sc->dev, "media changed\n"); | |||
| 970 | goto harderr; | |||
| 971 | } | |||
| 972 | ||||
| 973 | static void | |||
| 974 | hsg2msf(int hsg, bcd_t *msf) | |||
| 975 | { | |||
| 976 | ||||
| 977 | hsg += 150; | |||
| 978 | M_msf(msf)msf[0] = bin2bcd(hsg / 4500)(bin2bcd_data[hsg / 4500]); | |||
| 979 | hsg %= 4500; | |||
| 980 | S_msf(msf)msf[1] = bin2bcd(hsg / 75)(bin2bcd_data[hsg / 75]); | |||
| 981 | F_msf(msf)msf[2] = bin2bcd(hsg % 75)(bin2bcd_data[hsg % 75]); | |||
| 982 | } | |||
| 983 | ||||
| 984 | static int | |||
| 985 | msf2hsg(bcd_t *msf) | |||
| 986 | { | |||
| 987 | ||||
| 988 | return (bcd2bin(M_msf(msf))(bcd2bin_data[msf[0]]) * 60 + | |||
| 989 | bcd2bin(S_msf(msf))(bcd2bin_data[msf[1]])) * 75 + | |||
| 990 | bcd2bin(F_msf(msf))(bcd2bin_data[msf[2]]) - 150; | |||
| 991 | } | |||
| 992 | ||||
| 993 | static void | |||
| 994 | process_attention(struct scd_softc *sc) | |||
| 995 | { | |||
| 996 | unsigned char code; | |||
| 997 | int count = 0; | |||
| 998 | ||||
| 999 | while (IS_ATTENTION(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x01) != 0) && count++ < 30) { | |||
| 1000 | SCD_WRITE(sc, OREG_CONTROL, CBIT_ATTENTION_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x01)); | |||
| 1001 | code = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 1002 | ||||
| 1003 | #ifdef SCD_DEBUG | |||
| 1004 | if (scd_debuglevel > 0) { | |||
| 1005 | if (count == 1) | |||
| 1006 | device_printf(sc->dev, "DEBUG: ATTENTIONS = 0x%x", code); | |||
| 1007 | else | |||
| 1008 | printf(",0x%x", code); | |||
| 1009 | } | |||
| 1010 | #endif | |||
| 1011 | ||||
| 1012 | switch (code) { | |||
| 1013 | case ATTEN_SPIN_DOWN0x27: | |||
| 1014 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
| 1015 | break; | |||
| 1016 | ||||
| 1017 | case ATTEN_SPIN_UP_DONE0x24: | |||
| 1018 | sc->data.flags |= SCDSPINNING0x0400; | |||
| 1019 | break; | |||
| 1020 | ||||
| 1021 | case ATTEN_AUDIO_DONE0x90: | |||
| 1022 | sc->data.audio_status = CD_AS_PLAY_COMPLETED0x13; | |||
| 1023 | break; | |||
| 1024 | ||||
| 1025 | case ATTEN_DRIVE_LOADED0x80: | |||
| 1026 | sc->data.flags &= ~(SCDTOC0x0100|SCDSPINNING0x0400|SCDVALID0x0002); | |||
| 1027 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
| 1028 | break; | |||
| 1029 | ||||
| 1030 | case ATTEN_EJECT_PUSHED0x81: | |||
| 1031 | sc->data.flags &= ~SCDVALID0x0002; | |||
| 1032 | break; | |||
| 1033 | } | |||
| 1034 | DELAY(100); | |||
| 1035 | } | |||
| 1036 | #ifdef SCD_DEBUG | |||
| 1037 | if (scd_debuglevel > 0 && count > 0) | |||
| 1038 | printf("\n"); | |||
| 1039 | #endif | |||
| 1040 | } | |||
| 1041 | ||||
| 1042 | /* Returns 0 OR sony error code */ | |||
| 1043 | static int | |||
| 1044 | spin_up(struct scd_softc *sc) | |||
| 1045 | { | |||
| 1046 | unsigned char res_reg[12]; | |||
| 1047 | unsigned int res_size; | |||
| 1048 | int rc; | |||
| 1049 | int loop_count = 0; | |||
| 1050 | ||||
| 1051 | again: | |||
| 1052 | rc = send_cmd(sc, CMD_SPIN_UP0x51, 0, 0, res_reg, &res_size); | |||
| 1053 | if (rc != 0) { | |||
| 1054 | XDEBUG(sc, 2, "CMD_SPIN_UP error 0x%x\n", rc); | |||
| 1055 | return (rc); | |||
| 1056 | } | |||
| 1057 | ||||
| 1058 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
| 1059 | rc = send_cmd(sc, CMD_READ_TOC0x30, 0); | |||
| 1060 | if (rc == ERR_NOT_SPINNING0x22) { | |||
| 1061 | if (loop_count++ < 3) | |||
| 1062 | goto again; | |||
| 1063 | return (rc); | |||
| 1064 | } | |||
| 1065 | if (rc != 0) | |||
| 1066 | return (rc); | |||
| 1067 | } | |||
| 1068 | ||||
| 1069 | sc->data.flags |= SCDSPINNING0x0400; | |||
| 1070 | ||||
| 1071 | return (0); | |||
| 1072 | } | |||
| 1073 | ||||
| 1074 | static struct sony_tracklist * | |||
| 1075 | get_tl(struct sony_toc *toc, int size) | |||
| 1076 | { | |||
| 1077 | struct sony_tracklist *tl = &toc->tracks[0]; | |||
| 1078 | ||||
| 1079 | if (tl->track != 0xb0) | |||
| 1080 | return (tl); | |||
| 1081 | if (tl->track != 0xb1) | |||
| 1082 | return (tl); | |||
| 1083 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
| 1084 | if (tl->track != 0xb2) | |||
| 1085 | return (tl); | |||
| 1086 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
| 1087 | if (tl->track != 0xb3) | |||
| 1088 | return (tl); | |||
| 1089 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
| 1090 | if (tl->track != 0xb4) | |||
| 1091 | return (tl); | |||
| 1092 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
| 1093 | if (tl->track != 0xc0) | |||
| 1094 | return (tl); | |||
| 1095 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
| 1096 | return (tl); | |||
| 1097 | } | |||
| 1098 | ||||
| 1099 | static int | |||
| 1100 | read_toc(struct scd_softc *sc) | |||
| 1101 | { | |||
| 1102 | struct sony_toc toc; | |||
| 1103 | struct sony_tracklist *tl; | |||
| 1104 | int rc, i, j; | |||
| 1105 | u_long first, last; | |||
| 1106 | ||||
| 1107 | rc = send_cmd(sc, CMD_GET_TOC0x24, 1, 1); | |||
| 1108 | if (rc < 0) | |||
| 1109 | return (rc); | |||
| 1110 | if (rc > sizeof(toc)) { | |||
| 1111 | device_printf(sc->dev, "program error: toc too large (%d)\n", rc); | |||
| 1112 | return (EIO5); | |||
| 1113 | } | |||
| 1114 | if (get_result(sc, rc, (u_char *)&toc) != 0) | |||
| 1115 | return (EIO5); | |||
| 1116 | ||||
| 1117 | XDEBUG(sc, 1, "toc read. len = %d, sizeof(toc) = %d\n", rc, sizeof(toc)); | |||
| 1118 | ||||
| 1119 | tl = get_tl(&toc, rc); | |||
| 1120 | first = msf2hsg(tl->start_msf); | |||
| 1121 | last = msf2hsg(toc.lead_out_start_msf); | |||
| 1122 | sc->data.blksize = SCDBLKSIZE2048; | |||
| 1123 | sc->data.disksize = last*sc->data.blksize/DEV_BSIZE(1<<9); | |||
| 1124 | ||||
| 1125 | XDEBUG(sc, 1, "firstsector = %ld, lastsector = %ld", first, last); | |||
| 1126 | ||||
| 1127 | sc->data.first_track = bcd2bin(toc.first_track)(bcd2bin_data[toc.first_track]); | |||
| 1128 | sc->data.last_track = bcd2bin(toc.last_track)(bcd2bin_data[toc.last_track]); | |||
| 1129 | if (sc->data.last_track > (MAX_TRACKS100-2)) | |||
| 1130 | sc->data.last_track = MAX_TRACKS100-2; | |||
| 1131 | for (j = 0, i = sc->data.first_track; i <= sc->data.last_track; i++, j++) { | |||
| 1132 | sc->data.toc[i].adr = tl[j].adr; | |||
| 1133 | sc->data.toc[i].ctl = tl[j].ctl; /* for xcdplayer */ | |||
| 1134 | bcopy(tl[j].start_msf, sc->data.toc[i].start_msf, 3); | |||
| 1135 | #ifdef SCD_DEBUG | |||
| 1136 | if (scd_debuglevel > 0) { | |||
| 1137 | if ((j % 3) == 0) { | |||
| 1138 | printf("\n"); | |||
| 1139 | device_printf(sc->dev, "tracks "); | |||
| 1140 | } | |||
| 1141 | printf("[%03d: %2d %2d %2d] ", i, | |||
| 1142 | bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]), | |||
| 1143 | bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]), | |||
| 1144 | bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]])); | |||
| 1145 | } | |||
| 1146 | #endif | |||
| 1147 | } | |||
| 1148 | bcopy(toc.lead_out_start_msf, sc->data.toc[sc->data.last_track+1].start_msf, 3); | |||
| 1149 | #ifdef SCD_DEBUG | |||
| 1150 | if (scd_debuglevel > 0) { | |||
| 1151 | i = sc->data.last_track+1; | |||
| 1152 | printf("[END: %2d %2d %2d]\n", | |||
| 1153 | bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]), | |||
| 1154 | bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]), | |||
| 1155 | bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]])); | |||
| 1156 | } | |||
| 1157 | #endif | |||
| 1158 | ||||
| 1159 | sc->data.flags |= SCDTOC0x0100; | |||
| 1160 | ||||
| 1161 | return (0); | |||
| 1162 | } | |||
| 1163 | ||||
| 1164 | static void | |||
| 1165 | init_drive(struct scd_softc *sc) | |||
| 1166 | { | |||
| 1167 | int rc; | |||
| 1168 | ||||
| 1169 | rc = send_cmd(sc, CMD_SET_DRIVE_PARAM0x10, 2, | |||
| 1170 | 0x05, 0x03 | ((sc->data.double_speed) ? 0x04: 0)); | |||
| 1171 | if (rc != 0) | |||
| 1172 | device_printf(sc->dev, "Unable to set parameters. Errcode = 0x%x\n", rc); | |||
| 1173 | } | |||
| 1174 | ||||
| 1175 | /* Returns 0 or errno */ | |||
| 1176 | static int | |||
| 1177 | get_result(struct scd_softc *sc, int result_len, u_char *result) | |||
| 1178 | { | |||
| 1179 | int loop_index = 2; /* send_cmd() reads two bytes ... */ | |||
| 1180 | ||||
| 1181 | XDEBUG(sc, 1, "DEBUG: get_result: bytes=%d\n", result_len); | |||
| 1182 | ||||
| 1183 | while (result_len-- > 0) { | |||
| 1184 | if (loop_index++ >= 10) { | |||
| 1185 | loop_index = 1; | |||
| 1186 | if (waitfor_status_bits(sc, SBIT_RESULT_READY0x02, 0)) | |||
| 1187 | return (EIO5); | |||
| 1188 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 1189 | } | |||
| 1190 | if (result) | |||
| 1191 | *result++ = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 1192 | else | |||
| 1193 | (void)SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 1194 | } | |||
| 1195 | return (0); | |||
| 1196 | } | |||
| 1197 | ||||
| 1198 | /* Returns -0x100 for timeout, -(drive error code) OR number of result bytes */ | |||
| 1199 | static int | |||
| 1200 | send_cmd(struct scd_softc *sc, u_char cmd, u_int nargs, ...) | |||
| 1201 | { | |||
| 1202 | va_list ap; | |||
| 1203 | u_char c; | |||
| 1204 | int rc; | |||
| 1205 | int i; | |||
| 1206 | ||||
| 1207 | if (waitfor_status_bits(sc, 0, SBIT_BUSY0x80)) { | |||
| 1208 | device_printf(sc->dev, "drive busy\n"); | |||
| 1209 | return (-0x100); | |||
| 1210 | } | |||
| 1211 | ||||
| 1212 | XDEBUG(sc, 1, "DEBUG: send_cmd: cmd=0x%x nargs=%d", cmd, nargs); | |||
| 1213 | ||||
| 1214 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 1215 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x40)); | |||
| 1216 | ||||
| 1217 | for (i = 0; i < 100; i++) | |||
| 1218 | if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) | |||
| 1219 | break; | |||
| 1220 | if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) { | |||
| 1221 | XDEBUG(sc, 1, "\nwparam timeout\n"); | |||
| 1222 | return (-EIO5); | |||
| 1223 | } | |||
| 1224 | ||||
| 1225 | va_start(ap, nargs)__builtin_va_start((ap), (nargs)); | |||
| 1226 | for (i = 0; i < nargs; i++) { | |||
| 1227 | c = (u_char)va_arg(ap, int)__builtin_va_arg((ap), int); | |||
| 1228 | SCD_WRITE(sc, OREG_WPARAMS, c)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (c)); | |||
| 1229 | XDEBUG(sc, 1, ",{0x%x}", c); | |||
| 1230 | } | |||
| 1231 | va_end(ap)__builtin_va_end(ap); | |||
| 1232 | XDEBUG(sc, 1, "\n"); | |||
| 1233 | ||||
| 1234 | SCD_WRITE(sc, OREG_COMMAND, cmd)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (cmd)); | |||
| 1235 | ||||
| 1236 | rc = waitfor_status_bits(sc, SBIT_RESULT_READY0x02, SBIT_BUSY0x80); | |||
| 1237 | if (rc) | |||
| 1238 | return (-0x100); | |||
| 1239 | ||||
| 1240 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
| 1241 | switch ((rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
| 1242 | case 0x20: | |||
| 1243 | rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 1244 | /* FALLTHROUGH */ | |||
| 1245 | case 0x50: | |||
| 1246 | XDEBUG(sc, 1, "DEBUG: send_cmd: drive_error=0x%x\n", rc); | |||
| 1247 | return (-rc); | |||
| 1248 | case 0x00: | |||
| 1249 | default: | |||
| 1250 | rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
| 1251 | XDEBUG(sc, 1, "DEBUG: send_cmd: result_len=%d\n", rc); | |||
| 1252 | return (rc); | |||
| 1253 | } | |||
| 1254 | } | |||
| 1255 | ||||
| 1256 | static void | |||
| 1257 | print_error(struct scd_softc *sc, int errcode) | |||
| 1258 | { | |||
| 1259 | ||||
| 1260 | switch (errcode) { | |||
| 1261 | case -ERR_CD_NOT_LOADED0x20: | |||
| 1262 | device_printf(sc->dev, "door is open\n"); | |||
| 1263 | break; | |||
| 1264 | case -ERR_NO_CD_INSIDE0x21: | |||
| 1265 | device_printf(sc->dev, "no cd inside\n"); | |||
| 1266 | break; | |||
| 1267 | default: | |||
| 1268 | if (errcode == -0x100 || errcode > 0) | |||
| 1269 | device_printf(sc->dev, "device timeout\n"); | |||
| 1270 | else | |||
| 1271 | device_printf(sc->dev, "unexpected error 0x%x\n", -errcode); | |||
| 1272 | break; | |||
| 1273 | } | |||
| 1274 | } | |||
| 1275 | ||||
| 1276 | /* Returns 0 or errno value */ | |||
| 1277 | static int | |||
| 1278 | waitfor_status_bits(struct scd_softc *sc, int bits_set, int bits_clear) | |||
| 1279 | { | |||
| 1280 | u_int flags = sc->data.flags; | |||
| 1281 | u_int max_loop; | |||
| 1282 | u_char c = 0; | |||
| 1283 | ||||
| 1284 | if (flags & SCDPROBING0x0020) { | |||
| 1285 | max_loop = 0; | |||
| 1286 | while (max_loop++ < 1000) { | |||
| 1287 | c = SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)); | |||
| 1288 | if (c == 0xff) | |||
| 1289 | return (EIO5); | |||
| 1290 | if (c & SBIT_ATTENTION0x01) { | |||
| 1291 | process_attention(sc); | |||
| 1292 | continue; | |||
| 1293 | } | |||
| 1294 | if ((c & bits_set) == bits_set && | |||
| 1295 | (c & bits_clear) == 0) | |||
| 1296 | { | |||
| 1297 | break; | |||
| 1298 | } | |||
| 1299 | DELAY(10000); | |||
| 1300 | } | |||
| 1301 | } else { | |||
| 1302 | max_loop = 100; | |||
| 1303 | while (max_loop-- > 0) { | |||
| 1304 | c = SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)); | |||
| 1305 | if (c & SBIT_ATTENTION0x01) { | |||
| 1306 | process_attention(sc); | |||
| 1307 | continue; | |||
| 1308 | } | |||
| 1309 | if ((c & bits_set) == bits_set && | |||
| 1310 | (c & bits_clear) == 0) | |||
| 1311 | { | |||
| 1312 | break; | |||
| 1313 | } | |||
| 1314 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1314 )); | |||
| 1315 | pause("waitfor", hz/10)pause_sbt(("waitfor"), tick_sbt * (hz/10), 0, 0x0100); | |||
| 1316 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1316 )); | |||
| 1317 | } | |||
| 1318 | } | |||
| 1319 | if ((c & bits_set) == bits_set && | |||
| 1320 | (c & bits_clear) == 0) | |||
| 1321 | { | |||
| 1322 | return (0); | |||
| 1323 | } | |||
| 1324 | #ifdef SCD_DEBUG | |||
| 1325 | if (scd_debuglevel > 0) | |||
| 1326 | device_printf(sc->dev, "DEBUG: waitfor: TIMEOUT (0x%x,(0x%x,0x%x))\n", c, bits_set, bits_clear); | |||
| 1327 | else | |||
| 1328 | #endif | |||
| 1329 | device_printf(sc->dev, "timeout.\n"); | |||
| 1330 | return (EIO5); | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | /* these two routines for xcdplayer - "borrowed" from mcd.c */ | |||
| 1334 | static int | |||
| 1335 | scd_toc_header (struct scd_softc *sc, struct ioc_toc_header* th) | |||
| 1336 | { | |||
| 1337 | int rc; | |||
| 1338 | ||||
| 1339 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
| 1340 | print_error(sc, rc); | |||
| 1341 | return (EIO5); | |||
| 1342 | } | |||
| 1343 | ||||
| 1344 | th->starting_track = sc->data.first_track; | |||
| 1345 | th->ending_track = sc->data.last_track; | |||
| 1346 | th->len = 0; /* not used */ | |||
| 1347 | ||||
| 1348 | return (0); | |||
| 1349 | } | |||
| 1350 | ||||
| 1351 | static int | |||
| 1352 | scd_toc_entrys (struct scd_softc *sc, struct ioc_read_toc_entry *te) | |||
| 1353 | { | |||
| 1354 | struct cd_toc_entry toc_entry; | |||
| 1355 | int rc, i, len = te->data_len; | |||
| 1356 | ||||
| 1357 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
| 1358 | print_error(sc, rc); | |||
| 1359 | return (EIO5); | |||
| 1360 | } | |||
| 1361 | ||||
| 1362 | /* find the toc to copy*/ | |||
| 1363 | i = te->starting_track; | |||
| 1364 | if (i == SCD_LASTPLUS1170) | |||
| 1365 | i = sc->data.last_track + 1; | |||
| 1366 | ||||
| 1367 | /* verify starting track */ | |||
| 1368 | if (i < sc->data.first_track || i > sc->data.last_track+1) | |||
| 1369 | return (EINVAL22); | |||
| 1370 | ||||
| 1371 | /* valid length ? */ | |||
| 1372 | if (len < sizeof(struct cd_toc_entry) | |||
| 1373 | || (len % sizeof(struct cd_toc_entry)) != 0) | |||
| 1374 | return (EINVAL22); | |||
| 1375 | ||||
| 1376 | /* copy the toc data */ | |||
| 1377 | toc_entry.control = sc->data.toc[i].ctl; | |||
| 1378 | toc_entry.addr_type = te->address_format; | |||
| 1379 | toc_entry.track = i; | |||
| 1380 | if (te->address_format == CD_MSF_FORMAT2) { | |||
| 1381 | toc_entry.addr.msf.unused = 0; | |||
| 1382 | toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]); | |||
| 1383 | toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]); | |||
| 1384 | toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]]); | |||
| 1385 | } | |||
| 1386 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1386 )); | |||
| 1387 | ||||
| 1388 | /* copy the data back */ | |||
| 1389 | if (copyout(&toc_entry, te->data, sizeof(struct cd_toc_entry)) != 0) | |||
| 1390 | return (EFAULT14); | |||
| 1391 | ||||
| 1392 | return (0); | |||
| 1393 | } | |||
| 1394 | ||||
| 1395 | ||||
| 1396 | static int | |||
| 1397 | scd_toc_entry (struct scd_softc *sc, struct ioc_read_toc_single_entry *te) | |||
| 1398 | { | |||
| 1399 | struct cd_toc_entry toc_entry; | |||
| 1400 | int rc, i; | |||
| 1401 | ||||
| 1402 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
| 1403 | print_error(sc, rc); | |||
| 1404 | return (EIO5); | |||
| 1405 | } | |||
| 1406 | ||||
| 1407 | /* find the toc to copy*/ | |||
| 1408 | i = te->track; | |||
| 1409 | if (i == SCD_LASTPLUS1170) | |||
| 1410 | i = sc->data.last_track + 1; | |||
| 1411 | ||||
| 1412 | /* verify starting track */ | |||
| 1413 | if (i < sc->data.first_track || i > sc->data.last_track+1) | |||
| 1414 | return (EINVAL22); | |||
| 1415 | ||||
| 1416 | /* copy the toc data */ | |||
| 1417 | toc_entry.control = sc->data.toc[i].ctl; | |||
| 1418 | toc_entry.addr_type = te->address_format; | |||
| 1419 | toc_entry.track = i; | |||
| 1420 | if (te->address_format == CD_MSF_FORMAT2) { | |||
| 1421 | toc_entry.addr.msf.unused = 0; | |||
| 1422 | toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]); | |||
| 1423 | toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]); | |||
| 1424 | toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]]); | |||
| 1425 | } | |||
| 1426 | ||||
| 1427 | /* copy the data back */ | |||
| 1428 | bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry)); | |||
| 1429 | ||||
| 1430 | return (0); | |||
| 1431 | } |