1 1.24 andvar /* $NetBSD: repulse.c,v 1.24 2022/02/12 23:30:30 andvar Exp $ */ 2 1.1 is 3 1.1 is /*- 4 1.1 is * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 is * All rights reserved. 6 1.1 is * 7 1.1 is * This code is derived from software contributed to The NetBSD Foundation 8 1.1 is * by Ignatios Souvatzis. 9 1.1 is * 10 1.1 is * Redistribution and use in source and binary forms, with or without 11 1.1 is * modification, are permitted provided that the following conditions 12 1.1 is * are met: 13 1.1 is * 1. Redistributions of source code must retain the above copyright 14 1.1 is * notice, this list of conditions and the following disclaimer. 15 1.1 is * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 is * notice, this list of conditions and the following disclaimer in the 17 1.1 is * documentation and/or other materials provided with the distribution. 18 1.1 is * 19 1.1 is * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 is * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 is * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 is * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 is * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 is * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 is * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 is * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 is * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 is * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 is * POSSIBILITY OF SUCH DAMAGE. 30 1.1 is */ 31 1.1 is 32 1.4 aymeric #include <sys/cdefs.h> 33 1.24 andvar __KERNEL_RCSID(0, "$NetBSD: repulse.c,v 1.24 2022/02/12 23:30:30 andvar Exp $"); 34 1.1 is 35 1.1 is #include <sys/types.h> 36 1.1 is #include <sys/param.h> 37 1.1 is #include <sys/systm.h> 38 1.1 is #include <sys/kernel.h> 39 1.3 aymeric #include <sys/device.h> 40 1.1 is #include <sys/fcntl.h> /* FREAD */ 41 1.17 dyoung #include <sys/bus.h> 42 1.1 is 43 1.1 is #include <sys/audioio.h> 44 1.22 isaki #include <dev/audio/audio_if.h> 45 1.3 aymeric 46 1.1 is #include <dev/ic/ac97reg.h> 47 1.1 is #include <dev/ic/ac97var.h> 48 1.1 is 49 1.1 is #include <amiga/dev/zbusvar.h> 50 1.1 is #include <amiga/amiga/isr.h> 51 1.1 is 52 1.1 is #include <amiga/dev/repulse_firmware.h> 53 1.1 is 54 1.1 is #ifndef vu_int8_t 55 1.13 kent #define vu_int8_t volatile uint8_t 56 1.1 is #endif 57 1.1 is #ifndef vu_int16_t 58 1.13 kent #define vu_int16_t volatile uint16_t 59 1.1 is #endif 60 1.1 is #ifndef vu_int32_t 61 1.13 kent #define vu_int32_t volatile uint32_t 62 1.1 is #endif 63 1.1 is 64 1.1 is /* ac97 attachment functions */ 65 1.1 is 66 1.1 is int repac_attach(void *, struct ac97_codec_if *); 67 1.13 kent int repac_read(void *, uint8_t, uint16_t *); 68 1.13 kent int repac_write(void *, uint8_t, uint16_t); 69 1.9 kent int repac_reset(void *); 70 1.1 is enum ac97_host_flag repac_flags(void *); 71 1.1 is 72 1.1 is /* audio attachment functions */ 73 1.1 is 74 1.1 is int rep_getdev(void *, struct audio_device *); 75 1.1 is int rep_get_props(void *); 76 1.1 is int rep_halt_output(void *); 77 1.1 is int rep_halt_input(void *); 78 1.22 isaki int rep_query_format(void *, audio_format_query_t *); 79 1.22 isaki int rep_set_format(void *, int, const audio_params_t *, const audio_params_t *, 80 1.22 isaki audio_filter_reg_t *, audio_filter_reg_t *); 81 1.12 kent int rep_round_blocksize(void *, int, int, const audio_params_t *); 82 1.1 is int rep_set_port(void *, mixer_ctrl_t *); 83 1.1 is int rep_get_port(void *, mixer_ctrl_t *); 84 1.1 is int rep_query_devinfo(void *, mixer_devinfo_t *); 85 1.18 jmcneill void rep_get_locks(void *, kmutex_t **, kmutex_t **); 86 1.1 is 87 1.1 is int rep_start_input(void *, void *, int, void (*)(void *), void *); 88 1.1 is int rep_start_output(void *, void *, int, void (*)(void *), void *); 89 1.1 is 90 1.13 kent int rep_intr(void *); 91 1.1 is 92 1.1 is 93 1.1 is /* audio attachment */ 94 1.1 is 95 1.10 yamt const struct audio_hw_if rep_hw_if = { 96 1.22 isaki .query_format = rep_query_format, 97 1.22 isaki .set_format = rep_set_format, 98 1.21 isaki .round_blocksize = rep_round_blocksize, 99 1.21 isaki .start_output = rep_start_output, 100 1.21 isaki .start_input = rep_start_input, 101 1.21 isaki .halt_output = rep_halt_output, 102 1.21 isaki .halt_input = rep_halt_input, 103 1.21 isaki .getdev = rep_getdev, 104 1.21 isaki .set_port = rep_set_port, 105 1.21 isaki .get_port = rep_get_port, 106 1.21 isaki .query_devinfo = rep_query_devinfo, 107 1.21 isaki .get_props = rep_get_props, 108 1.21 isaki .get_locks = rep_get_locks, 109 1.1 is }; 110 1.1 is 111 1.1 is /* hardware registers */ 112 1.1 is 113 1.1 is struct repulse_hw { 114 1.1 is vu_int16_t rhw_status; 115 1.1 is vu_int16_t rhw_fifostatus; /* 0xrrrrpppp0000flag */ 116 1.1 is vu_int16_t rhw_reg_address; 117 1.1 is vu_int16_t rhw_reg_data; 118 1.1 is /* 0x08 */ 119 1.1 is vu_int16_t rhw_fifo_lh; 120 1.1 is vu_int16_t rhw_fifo_ll; 121 1.1 is vu_int16_t rhw_fifo_rh; 122 1.1 is vu_int16_t rhw_fifo_rl; 123 1.1 is /* 0x10 */ 124 1.1 is vu_int16_t rhw_fifo_pack; 125 1.1 is vu_int16_t rhw_play_fifosz; 126 1.1 is vu_int32_t rhw_spdifin_stat; 127 1.1 is #define rhw_spdifout_stat rhw_spdifin_stat; 128 1.1 is 129 1.1 is /* 0x18 */ 130 1.1 is vu_int16_t rhw_capt_fifosz; 131 1.1 is vu_int16_t rhw_version; 132 1.1 is vu_int16_t rhw_dummy1; 133 1.1 is vu_int8_t rhw_firmwareload; 134 1.1 is /* 0x1F */ 135 1.1 is vu_int8_t rhw_dummy2[66 - 31]; 136 1.1 is /* 0x42 */ 137 1.1 is vu_int16_t rhw_reset; 138 1.1 is } /* __attribute__((packed)) */; 139 1.1 is 140 1.1 is #define REPSTATUS_PLAY 0x0001 141 1.1 is #define REPSTATUS_RECORD 0x0002 142 1.1 is #define REPSTATUS_PLAYFIFORST 0x0004 143 1.1 is #define REPSTATUS_RECFIFORST 0x0008 144 1.1 is 145 1.1 is #define REPSTATUS_REGSENDBUSY 0x0010 146 1.1 is #define REPSTATUS_LOOPBACK 0x0020 147 1.1 is #define REPSTATUS_ENSPDIFIN 0x0040 148 1.1 is #define REPSTATUS_ENSPDIFOUT 0x0080 149 1.1 is 150 1.1 is #define REPSTATUS_CODECRESET 0x0200 151 1.1 is #define REPSTATUS_SPDIFOUT24 0x0400 152 1.1 is #define REPSTATUS_SPDIFIN24 0x0800 153 1.1 is 154 1.1 is #define REPSTATUS_RECIRQENABLE 0x1000 155 1.1 is #define REPSTATUS_RECIRQACK 0x2000 156 1.1 is #define REPSTATUS_PLAYIRQENABLE 0x4000 157 1.1 is #define REPSTATUS_PLAYIRQACK 0x8000 158 1.1 is 159 1.1 is #define REPFIFO_PLAYFIFOFULL 0x0001 160 1.1 is #define REPFIFO_PLAYFIFOEMPTY 0x0002 161 1.1 is #define REPFIFO_RECFIFOFULL 0x0004 162 1.1 is #define REPFIFO_RECFIFOEMPTY 0x0008 163 1.1 is #define REPFIFO_PLAYFIFOGAUGE(x) ((x << 4) & 0xf000) 164 1.1 is #define REPFIFO_RECFIFOGAUGE(x) (x & 0xf000) 165 1.1 is 166 1.1 is /* AmigaDOS Delay() ticks */ 167 1.1 is 168 1.1 is #define USECPERTICK (1000000/50) 169 1.1 is 170 1.1 is /* NetBSD device attachment */ 171 1.1 is 172 1.1 is struct repulse_softc { 173 1.19 chs device_t sc_dev; 174 1.1 is struct isr sc_isr; 175 1.1 is struct ac97_host_if sc_achost; 176 1.1 is struct ac97_codec_if *sc_codec_if; 177 1.1 is 178 1.1 is struct repulse_hw *sc_boardp; 179 1.1 is 180 1.1 is void (*sc_captmore)(void *); 181 1.1 is void *sc_captarg; 182 1.1 is 183 1.1 is void *sc_captbuf; 184 1.1 is int sc_captscale; 185 1.1 is int sc_captbufsz; 186 1.1 is unsigned sc_captflags; 187 1.1 is 188 1.1 is 189 1.1 is void (*sc_playmore)(void *); 190 1.1 is void *sc_playarg; 191 1.1 is int sc_playscale; 192 1.1 is unsigned sc_playflags; 193 1.1 is 194 1.18 jmcneill kmutex_t sc_lock; 195 1.18 jmcneill kmutex_t sc_intr_lock; 196 1.1 is }; 197 1.1 is 198 1.22 isaki const struct audio_format repulse_format = { 199 1.22 isaki .mode = AUMODE_PLAY | AUMODE_RECORD, 200 1.22 isaki .encoding = AUDIO_ENCODING_SLINEAR_BE, 201 1.22 isaki .validbits = 16, 202 1.22 isaki .precision = 16, 203 1.22 isaki .channels = 2, 204 1.22 isaki .channel_mask = AUFMT_STEREO, 205 1.22 isaki .frequency_type = 6, 206 1.22 isaki .frequency = { 8000, 16000, 22050, 32000, 44100, 48000 }, 207 1.22 isaki }; 208 1.22 isaki 209 1.19 chs int repulse_match (device_t, cfdata_t, void *); 210 1.19 chs void repulse_attach (device_t, device_t, void *); 211 1.1 is 212 1.19 chs CFATTACH_DECL_NEW(repulse, sizeof(struct repulse_softc), 213 1.6 thorpej repulse_match, repulse_attach, NULL, NULL); 214 1.1 is 215 1.1 is int 216 1.19 chs repulse_match(device_t parent, cfdata_t cf, void *aux) 217 1.13 kent { 218 1.1 is struct zbus_args *zap; 219 1.1 is 220 1.1 is zap = aux; 221 1.1 is 222 1.1 is if (zap->manid != 0x4144) 223 1.1 is return (0); 224 1.1 is 225 1.1 is if (zap->prodid != 0) 226 1.1 is return (0); 227 1.1 is 228 1.1 is return (1); 229 1.1 is } 230 1.1 is 231 1.1 is void 232 1.19 chs repulse_attach(device_t parent, device_t self, void *aux) 233 1.13 kent { 234 1.1 is struct repulse_softc *sc; 235 1.1 is struct zbus_args *zap; 236 1.1 is struct repulse_hw *bp; 237 1.14 jmc const uint8_t *fwp; 238 1.1 is int needs_firmware; 239 1.13 kent uint16_t a; 240 1.1 is 241 1.19 chs sc = device_private(self); 242 1.19 chs sc->sc_dev = self; 243 1.1 is zap = aux; 244 1.1 is bp = (struct repulse_hw *)zap->va; 245 1.1 is sc->sc_boardp = bp; 246 1.22 isaki sc->sc_playscale = 4; 247 1.22 isaki sc->sc_captscale = 4; 248 1.1 is 249 1.1 is needs_firmware = 0; 250 1.1 is if (bp->rhw_fifostatus & 0x00f0) 251 1.1 is needs_firmware = 1; 252 1.1 is else { 253 1.1 is bp->rhw_status = 0x000c; 254 1.1 is if (bp->rhw_status != 0 || bp->rhw_fifostatus != 0x0f0a) 255 1.1 is needs_firmware = 1; 256 1.1 is } 257 1.1 is 258 1.1 is printf(": "); 259 1.1 is if (needs_firmware) { 260 1.1 is printf("loading "); 261 1.1 is bp->rhw_reset = 0; 262 1.1 is 263 1.1 is delay(1 * USECPERTICK); 264 1.3 aymeric 265 1.14 jmc for (fwp = (const uint8_t *)repulse_firmware; 266 1.1 is fwp < (repulse_firmware_size + 267 1.14 jmc (const uint8_t *)repulse_firmware); fwp++) 268 1.1 is bp->rhw_firmwareload = *fwp; 269 1.1 is 270 1.1 is delay(1 * USECPERTICK); 271 1.1 is 272 1.1 is if (bp->rhw_fifostatus & 0x00f0) 273 1.1 is goto Initerr; 274 1.1 is 275 1.1 is a = /* bp->rhw_status; 276 1.1 is a |= */ REPSTATUS_CODECRESET; 277 1.1 is bp->rhw_status = a; 278 1.1 is 279 1.1 is a = bp->rhw_status; 280 1.1 is if ((a & REPSTATUS_CODECRESET) == 0) 281 1.1 is goto Initerr; 282 1.1 is 283 1.1 is (void)bp->rhw_status; 284 1.1 is (void)bp->rhw_status; 285 1.1 is (void)bp->rhw_status; 286 1.1 is a = bp->rhw_status; 287 1.1 is a &= ~REPSTATUS_CODECRESET; 288 1.1 is bp->rhw_status = a; 289 1.1 is } 290 1.1 is 291 1.1 is printf("firmware version 0x%x\n", bp->rhw_version); 292 1.1 is 293 1.1 is sc->sc_achost.arg = sc; 294 1.1 is 295 1.1 is sc->sc_achost.reset = repac_reset; 296 1.1 is sc->sc_achost.read = repac_read; 297 1.1 is sc->sc_achost.write = repac_write; 298 1.1 is sc->sc_achost.attach = repac_attach; 299 1.1 is sc->sc_achost.flags = 0; 300 1.1 is 301 1.18 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 302 1.18 jmcneill mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 303 1.18 jmcneill 304 1.18 jmcneill if (ac97_attach(&sc->sc_achost, self, &sc->sc_lock)) { 305 1.19 chs printf("%s: error attaching codec\n", device_xname(self)); 306 1.1 is return; 307 1.1 is } 308 1.1 is 309 1.1 is #ifdef DIAGNOSTIC 310 1.3 aymeric /* 311 1.1 is * Print a warning if the codec doesn't support hardware variable 312 1.1 is * rate audio. As the initial incarnations of the Repulse board 313 1.24 andvar * are AC'97 2.1, it is expected that we'll always have VRA. 314 1.1 is */ 315 1.1 is /* 316 1.1 is * XXX this should be a panic(). OTOH, audio codec speed is not 317 1.1 is * important enough to do this. 318 1.1 is */ 319 1.7 kent a = sc->sc_codec_if->vtbl->get_extcaps(sc->sc_codec_if); 320 1.7 kent if (!(a & AC97_EXT_AUDIO_VRA)) { 321 1.1 is printf("%s: warning: codec doesn't support " 322 1.1 is "hardware AC'97 2.0 Variable Rate Audio\n", 323 1.19 chs device_xname(self)); 324 1.1 is } 325 1.1 is #endif 326 1.1 is 327 1.1 is sc->sc_isr.isr_ipl = 2; 328 1.1 is sc->sc_isr.isr_arg = sc; 329 1.1 is sc->sc_isr.isr_intr = rep_intr; 330 1.1 is add_isr(&sc->sc_isr); 331 1.1 is 332 1.19 chs audio_attach_mi(&rep_hw_if, sc, self); 333 1.1 is 334 1.1 is return; 335 1.1 is 336 1.1 is Initerr: 337 1.19 chs printf("\n%s: firmware not successfully loaded\n", device_xname(self)); 338 1.1 is return; 339 1.3 aymeric 340 1.1 is } 341 1.1 is 342 1.13 kent int 343 1.13 kent repac_reset(void *arg) 344 1.13 kent { 345 1.13 kent struct repulse_softc *sc; 346 1.13 kent struct repulse_hw *bp; 347 1.13 kent uint16_t a; 348 1.3 aymeric 349 1.13 kent sc = arg; 350 1.13 kent bp = sc->sc_boardp; 351 1.1 is a = bp->rhw_status; 352 1.1 is a |= REPSTATUS_CODECRESET; 353 1.1 is bp->rhw_status = a; 354 1.1 is 355 1.1 is a = bp->rhw_status; 356 1.1 is #ifdef DIAGNOSTIC 357 1.1 is if ((a & REPSTATUS_CODECRESET) == 0) 358 1.19 chs panic("%s: cannot set reset bit", device_xname(sc->sc_dev)); 359 1.1 is #endif 360 1.1 is 361 1.1 is a = bp->rhw_status; 362 1.1 is a = bp->rhw_status; 363 1.1 is a = bp->rhw_status; 364 1.1 is a = bp->rhw_status; 365 1.1 is a &= ~REPSTATUS_CODECRESET; 366 1.1 is bp->rhw_status = a; 367 1.9 kent return 0; 368 1.1 is } 369 1.1 is 370 1.13 kent int 371 1.13 kent repac_read(void *arg, u_int8_t reg, u_int16_t *valuep) 372 1.13 kent { 373 1.13 kent struct repulse_softc *sc; 374 1.13 kent struct repulse_hw *bp; 375 1.1 is 376 1.13 kent sc = arg; 377 1.13 kent bp = sc->sc_boardp; 378 1.13 kent while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 379 1.13 kent continue; 380 1.1 is bp->rhw_reg_address = (reg & 0x7F) | 0x80; 381 1.1 is 382 1.13 kent while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 383 1.13 kent continue; 384 1.1 is 385 1.1 is *valuep = bp->rhw_reg_data; 386 1.1 is 387 1.1 is return 0; 388 1.1 is } 389 1.1 is 390 1.13 kent int 391 1.13 kent repac_write(void *arg, uint8_t reg, uint16_t value) 392 1.13 kent { 393 1.13 kent struct repulse_softc *sc; 394 1.13 kent struct repulse_hw *bp; 395 1.1 is 396 1.13 kent sc = arg; 397 1.13 kent bp = sc->sc_boardp; 398 1.1 is bp->rhw_reg_data = value; 399 1.1 is bp->rhw_reg_address = reg & 0x7F; 400 1.1 is 401 1.13 kent while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 402 1.13 kent continue; 403 1.1 is 404 1.1 is return 0; 405 1.1 is } 406 1.1 is 407 1.13 kent int 408 1.13 kent repac_attach(void *arg, struct ac97_codec_if *acip) 409 1.13 kent { 410 1.1 is struct repulse_softc *sc; 411 1.1 is 412 1.1 is sc = arg; 413 1.1 is sc->sc_codec_if = acip; 414 1.1 is 415 1.1 is return 0; 416 1.1 is } 417 1.1 is 418 1.1 is /* audio(9) support stuff which is not ac97-constant */ 419 1.1 is 420 1.1 is int 421 1.1 is rep_getdev(void *arg, struct audio_device *retp) 422 1.1 is { 423 1.13 kent struct repulse_softc *sc; 424 1.13 kent struct repulse_hw *bp; 425 1.1 is 426 1.13 kent if (retp != NULL) { 427 1.13 kent sc = arg; 428 1.13 kent bp = sc->sc_boardp; 429 1.1 is strncpy(retp->name, "Repulse", sizeof(retp->name)); 430 1.1 is snprintf(retp->version, sizeof(retp->version), "0x%x", 431 1.1 is bp->rhw_version); 432 1.1 is strncpy(retp->config, "", sizeof(retp->config)); 433 1.1 is } 434 1.1 is 435 1.1 is return 0; 436 1.1 is } 437 1.1 is 438 1.3 aymeric int 439 1.1 is rep_get_props(void *v) 440 1.1 is { 441 1.23 isaki 442 1.23 isaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 443 1.23 isaki AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 444 1.3 aymeric } 445 1.1 is 446 1.1 is int 447 1.1 is rep_halt_output(void *arg) 448 1.1 is { 449 1.13 kent struct repulse_softc *sc; 450 1.13 kent struct repulse_hw *bp; 451 1.1 is 452 1.13 kent sc = arg; 453 1.13 kent bp = sc->sc_boardp; 454 1.1 is bp->rhw_status &= ~(REPSTATUS_PLAYIRQENABLE|REPSTATUS_PLAY); 455 1.1 is 456 1.1 is 457 1.1 is return 0; 458 1.1 is } 459 1.1 is 460 1.1 is int 461 1.1 is rep_halt_input(void *arg) 462 1.1 is { 463 1.13 kent struct repulse_softc *sc; 464 1.13 kent struct repulse_hw *bp; 465 1.1 is 466 1.13 kent sc = arg; 467 1.13 kent bp = sc->sc_boardp; 468 1.1 is bp->rhw_status &= ~(REPSTATUS_RECIRQENABLE|REPSTATUS_RECORD); 469 1.1 is 470 1.1 is return 0; 471 1.1 is } 472 1.1 is 473 1.1 is int 474 1.22 isaki rep_query_format(void *arg, audio_format_query_t *afp) 475 1.1 is { 476 1.1 is 477 1.22 isaki return audio_query_format(&repulse_format, 1, afp); 478 1.1 is } 479 1.1 is 480 1.1 is /* 481 1.1 is * XXX the following three functions need to be enhanced for the FPGA s/pdif 482 1.1 is * mode. Generic ac97 versions for now. 483 1.1 is */ 484 1.1 is 485 1.3 aymeric int 486 1.1 is rep_get_port(void *arg, mixer_ctrl_t *cp) 487 1.1 is { 488 1.13 kent struct repulse_softc *sc; 489 1.1 is 490 1.13 kent sc = arg; 491 1.13 kent return sc->sc_codec_if->vtbl->mixer_get_port(sc->sc_codec_if, cp); 492 1.1 is } 493 1.1 is 494 1.3 aymeric int 495 1.1 is rep_set_port(void *arg, mixer_ctrl_t *cp) 496 1.1 is { 497 1.13 kent struct repulse_softc *sc; 498 1.1 is 499 1.13 kent sc = arg; 500 1.13 kent return sc->sc_codec_if->vtbl->mixer_set_port(sc->sc_codec_if, cp); 501 1.1 is } 502 1.1 is 503 1.1 is int 504 1.13 kent rep_query_devinfo(void *arg, mixer_devinfo_t *dip) 505 1.1 is { 506 1.13 kent struct repulse_softc *sc; 507 1.1 is 508 1.13 kent sc = arg; 509 1.13 kent return sc->sc_codec_if->vtbl->query_devinfo(sc->sc_codec_if, dip); 510 1.1 is } 511 1.1 is 512 1.1 is int 513 1.12 kent rep_round_blocksize(void *arg, int blk, int mode, const audio_params_t *param) 514 1.1 is { 515 1.1 is int b1; 516 1.1 is 517 1.1 is b1 = (blk & -32); 518 1.1 is 519 1.1 is if (b1 > 65536 / 2 / 2 /* channels */ / 4 /* bytes per channel */) 520 1.1 is b1 = 65536 / 2 / 2 / 4; 521 1.13 kent return b1; 522 1.1 is } 523 1.1 is 524 1.18 jmcneill void 525 1.18 jmcneill rep_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 526 1.18 jmcneill { 527 1.18 jmcneill struct repulse_softc *sc = opaque; 528 1.18 jmcneill 529 1.18 jmcneill *intr = &sc->sc_intr_lock; 530 1.18 jmcneill *thread = &sc->sc_lock; 531 1.18 jmcneill } 532 1.18 jmcneill 533 1.1 is 534 1.1 is int 535 1.22 isaki rep_set_format(void *addr, int setmode, 536 1.22 isaki const audio_params_t *play, const audio_params_t *rec, 537 1.22 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 538 1.22 isaki { 539 1.22 isaki struct repulse_softc *sc; 540 1.1 is 541 1.13 kent sc = addr; 542 1.22 isaki /* XXX 96kHz */ 543 1.22 isaki if ((setmode & AUMODE_PLAY)) { 544 1.22 isaki repac_write(sc, AC97_REG_PCM_FRONT_DAC_RATE, play->sample_rate); 545 1.1 is } 546 1.22 isaki if ((setmode & AUMODE_RECORD)) { 547 1.22 isaki repac_write(sc, AC97_REG_PCM_LR_ADC_RATE, rec->sample_rate); 548 1.1 is } 549 1.1 is 550 1.22 isaki return 0; 551 1.1 is } 552 1.1 is 553 1.1 is 554 1.1 is int 555 1.1 is rep_start_output(void *addr, void *block, int blksize, 556 1.13 kent void (*intr)(void*), void *intrarg) 557 1.13 kent { 558 1.1 is struct repulse_softc *sc; 559 1.1 is struct repulse_hw *bp; 560 1.13 kent uint16_t status; 561 1.1 is 562 1.1 is 563 1.1 is sc = addr; 564 1.1 is bp = sc->sc_boardp; 565 1.1 is 566 1.1 is /* TODO: prepare hw if necessary */ 567 1.1 is status = bp->rhw_status; 568 1.1 is if (!(status & REPSTATUS_PLAY)) 569 1.1 is bp->rhw_status = status | 570 1.1 is REPSTATUS_PLAY | REPSTATUS_PLAYFIFORST; 571 1.1 is 572 1.1 is /* copy data */ 573 1.22 isaki uint16_t *q = block; 574 1.22 isaki int length = blksize; 575 1.22 isaki while (length > 0) { 576 1.22 isaki bp->rhw_fifo_lh = *q++; 577 1.22 isaki bp->rhw_fifo_rh = *q++; 578 1.22 isaki length -= 4; 579 1.22 isaki } 580 1.1 is 581 1.1 is /* TODO: set hw if necessary */ 582 1.1 is if (intr) { 583 1.1 is bp->rhw_status |= REPSTATUS_PLAYIRQENABLE; 584 1.1 is bp->rhw_play_fifosz = blksize / sc->sc_playscale / 2; 585 1.1 is /* /2: give us time to return on the first call */ 586 1.1 is } 587 1.1 is 588 1.1 is /* save callback function */ 589 1.1 is sc->sc_playarg = intrarg; 590 1.1 is sc->sc_playmore = intr; 591 1.1 is 592 1.1 is return 0; 593 1.1 is } 594 1.1 is 595 1.1 is int 596 1.1 is rep_start_input(void *addr, void *block, int blksize, 597 1.13 kent void (*intr)(void*), void *intrarg) 598 1.13 kent { 599 1.1 is struct repulse_softc *sc; 600 1.1 is struct repulse_hw *bp; 601 1.13 kent uint16_t status; 602 1.1 is 603 1.1 is sc = addr; 604 1.1 is bp = sc->sc_boardp; 605 1.1 is 606 1.1 is sc->sc_captbuf = block; 607 1.1 is sc->sc_captbufsz = blksize; 608 1.1 is sc->sc_captarg = intrarg; 609 1.1 is sc->sc_captmore = intr; 610 1.1 is 611 1.1 is status = bp->rhw_status; 612 1.1 is if (!(status & REPSTATUS_RECORD)) 613 1.1 is bp->rhw_status = status | REPSTATUS_RECORD 614 1.1 is | REPSTATUS_RECFIFORST; 615 1.1 is 616 1.1 is bp->rhw_status |= REPSTATUS_RECIRQENABLE; 617 1.1 is bp->rhw_capt_fifosz = blksize / sc->sc_captscale; 618 1.1 is 619 1.1 is return 0; 620 1.1 is } 621 1.1 is 622 1.1 is /* irq handler */ 623 1.1 is 624 1.1 is int 625 1.13 kent rep_intr(void *tag) 626 1.13 kent { 627 1.1 is struct repulse_softc *sc; 628 1.1 is struct repulse_hw *bp; 629 1.1 is int foundone; 630 1.13 kent uint16_t status; 631 1.1 is 632 1.1 is foundone = 0; 633 1.1 is 634 1.1 is sc = tag; 635 1.18 jmcneill 636 1.18 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 637 1.18 jmcneill 638 1.1 is bp = sc->sc_boardp; 639 1.1 is status = bp->rhw_status; 640 1.1 is 641 1.1 is if (status & REPSTATUS_PLAYIRQACK) { 642 1.1 is foundone = 1; 643 1.1 is status &= ~REPSTATUS_PLAYIRQENABLE; 644 1.1 is bp->rhw_status = status; 645 1.1 is (*sc->sc_playmore)(sc->sc_playarg); 646 1.1 is } 647 1.1 is 648 1.1 is if (status & REPSTATUS_RECIRQACK) { 649 1.1 is foundone = 1; 650 1.1 is status &= ~REPSTATUS_RECIRQENABLE; 651 1.1 is bp->rhw_status = status; 652 1.22 isaki uint16_t *q = sc->sc_captbuf; 653 1.22 isaki int length = sc->sc_captbufsz; 654 1.22 isaki while (length > 0) { 655 1.22 isaki *q++ = bp->rhw_fifo_lh; 656 1.22 isaki *q++ = bp->rhw_fifo_rh; 657 1.22 isaki length -= 4; 658 1.22 isaki } 659 1.1 is (*sc->sc_captmore)(sc->sc_captarg); 660 1.1 is } 661 1.1 is 662 1.18 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 663 1.18 jmcneill 664 1.1 is return foundone; 665 1.1 is } 666