1 /* $NetBSD: repulse.c,v 1.20 2014/01/22 00:25:16 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Ignatios Souvatzis. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: repulse.c,v 1.20 2014/01/22 00:25:16 christos Exp $"); 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/fcntl.h> /* FREAD */ 41 #include <sys/bus.h> 42 43 #include <sys/audioio.h> 44 #include <dev/audio_if.h> 45 #include <dev/mulaw.h> 46 47 #include <dev/ic/ac97reg.h> 48 #include <dev/ic/ac97var.h> 49 50 #include <amiga/dev/zbusvar.h> 51 #include <amiga/amiga/isr.h> 52 53 #include <amiga/dev/repulse_firmware.h> 54 55 #ifndef vu_int8_t 56 #define vu_int8_t volatile uint8_t 57 #endif 58 #ifndef vu_int16_t 59 #define vu_int16_t volatile uint16_t 60 #endif 61 #ifndef vu_int32_t 62 #define vu_int32_t volatile uint32_t 63 #endif 64 65 /* ac97 attachment functions */ 66 67 int repac_attach(void *, struct ac97_codec_if *); 68 int repac_read(void *, uint8_t, uint16_t *); 69 int repac_write(void *, uint8_t, uint16_t); 70 int repac_reset(void *); 71 enum ac97_host_flag repac_flags(void *); 72 73 /* audio attachment functions */ 74 75 void rep_close(void *); 76 int rep_getdev(void *, struct audio_device *); 77 int rep_get_props(void *); 78 int rep_halt_output(void *); 79 int rep_halt_input(void *); 80 int rep_query_encoding(void *, struct audio_encoding *); 81 int rep_set_params(void *, int, int, audio_params_t *, 82 audio_params_t *, stream_filter_list_t *, stream_filter_list_t *); 83 int rep_round_blocksize(void *, int, int, const audio_params_t *); 84 int rep_set_port(void *, mixer_ctrl_t *); 85 int rep_get_port(void *, mixer_ctrl_t *); 86 int rep_query_devinfo(void *, mixer_devinfo_t *); 87 size_t rep_round_buffersize(void *, int, size_t); 88 void rep_get_locks(void *, kmutex_t **, kmutex_t **); 89 90 int rep_start_input(void *, void *, int, void (*)(void *), void *); 91 int rep_start_output(void *, void *, int, void (*)(void *), void *); 92 93 int rep_intr(void *); 94 95 96 /* audio attachment */ 97 98 const struct audio_hw_if rep_hw_if = { 99 /* open */ 0, 100 rep_close, 101 /* drain */ 0, 102 rep_query_encoding, 103 rep_set_params, 104 rep_round_blocksize, 105 /* commit_setting */ 0, 106 /* init_output */ 0, 107 /* init_input */ 0, 108 rep_start_output, 109 rep_start_input, 110 rep_halt_output, 111 rep_halt_input, 112 /* speaker_ctl */ 0, 113 rep_getdev, 114 /* getfd */ 0, 115 rep_set_port, 116 rep_get_port, 117 rep_query_devinfo, 118 /* allocm */ 0, 119 /* freem */ 0, 120 rep_round_buffersize, 121 /* mappage */ 0, 122 rep_get_props, 123 /* trigger_output */ 0, 124 /* trigger_input */ 0, 125 /* dev_ioctl */ 0, 126 rep_get_locks, 127 }; 128 129 /* hardware registers */ 130 131 struct repulse_hw { 132 vu_int16_t rhw_status; 133 vu_int16_t rhw_fifostatus; /* 0xrrrrpppp0000flag */ 134 vu_int16_t rhw_reg_address; 135 vu_int16_t rhw_reg_data; 136 /* 0x08 */ 137 vu_int16_t rhw_fifo_lh; 138 vu_int16_t rhw_fifo_ll; 139 vu_int16_t rhw_fifo_rh; 140 vu_int16_t rhw_fifo_rl; 141 /* 0x10 */ 142 vu_int16_t rhw_fifo_pack; 143 vu_int16_t rhw_play_fifosz; 144 vu_int32_t rhw_spdifin_stat; 145 #define rhw_spdifout_stat rhw_spdifin_stat; 146 147 /* 0x18 */ 148 vu_int16_t rhw_capt_fifosz; 149 vu_int16_t rhw_version; 150 vu_int16_t rhw_dummy1; 151 vu_int8_t rhw_firmwareload; 152 /* 0x1F */ 153 vu_int8_t rhw_dummy2[66 - 31]; 154 /* 0x42 */ 155 vu_int16_t rhw_reset; 156 } /* __attribute__((packed)) */; 157 158 #define REPSTATUS_PLAY 0x0001 159 #define REPSTATUS_RECORD 0x0002 160 #define REPSTATUS_PLAYFIFORST 0x0004 161 #define REPSTATUS_RECFIFORST 0x0008 162 163 #define REPSTATUS_REGSENDBUSY 0x0010 164 #define REPSTATUS_LOOPBACK 0x0020 165 #define REPSTATUS_ENSPDIFIN 0x0040 166 #define REPSTATUS_ENSPDIFOUT 0x0080 167 168 #define REPSTATUS_CODECRESET 0x0200 169 #define REPSTATUS_SPDIFOUT24 0x0400 170 #define REPSTATUS_SPDIFIN24 0x0800 171 172 #define REPSTATUS_RECIRQENABLE 0x1000 173 #define REPSTATUS_RECIRQACK 0x2000 174 #define REPSTATUS_PLAYIRQENABLE 0x4000 175 #define REPSTATUS_PLAYIRQACK 0x8000 176 177 #define REPFIFO_PLAYFIFOFULL 0x0001 178 #define REPFIFO_PLAYFIFOEMPTY 0x0002 179 #define REPFIFO_RECFIFOFULL 0x0004 180 #define REPFIFO_RECFIFOEMPTY 0x0008 181 #define REPFIFO_PLAYFIFOGAUGE(x) ((x << 4) & 0xf000) 182 #define REPFIFO_RECFIFOGAUGE(x) (x & 0xf000) 183 184 /* ac97 data stream transfer functions */ 185 void rep_read_16_stereo(struct repulse_hw *, uint8_t *, int, unsigned); 186 void rep_read_16_mono(struct repulse_hw *, uint8_t *, int, unsigned); 187 void rep_write_16_stereo(struct repulse_hw *, uint8_t *, int, unsigned); 188 void rep_write_16_mono(struct repulse_hw *, uint8_t *, int, unsigned); 189 void rep_read_8_stereo(struct repulse_hw *, uint8_t *, int, unsigned); 190 void rep_read_8_mono(struct repulse_hw *, uint8_t *, int, unsigned); 191 void rep_write_8_stereo(struct repulse_hw *, uint8_t *, int, unsigned); 192 void rep_write_8_mono(struct repulse_hw *, uint8_t *, int, unsigned); 193 194 /* AmigaDOS Delay() ticks */ 195 196 #define USECPERTICK (1000000/50) 197 198 /* NetBSD device attachment */ 199 200 struct repulse_softc { 201 device_t sc_dev; 202 struct isr sc_isr; 203 struct ac97_host_if sc_achost; 204 struct ac97_codec_if *sc_codec_if; 205 206 struct repulse_hw *sc_boardp; 207 208 void (*sc_captmore)(void *); 209 void *sc_captarg; 210 211 void (*sc_captfun)(struct repulse_hw *, uint8_t *, int, unsigned); 212 void *sc_captbuf; 213 int sc_captscale; 214 int sc_captbufsz; 215 unsigned sc_captflags; 216 217 218 void (*sc_playmore)(void *); 219 void *sc_playarg; 220 void (*sc_playfun)(struct repulse_hw *, uint8_t *, int, unsigned); 221 int sc_playscale; 222 unsigned sc_playflags; 223 224 kmutex_t sc_lock; 225 kmutex_t sc_intr_lock; 226 }; 227 228 int repulse_match (device_t, cfdata_t, void *); 229 void repulse_attach (device_t, device_t, void *); 230 231 CFATTACH_DECL_NEW(repulse, sizeof(struct repulse_softc), 232 repulse_match, repulse_attach, NULL, NULL); 233 234 int 235 repulse_match(device_t parent, cfdata_t cf, void *aux) 236 { 237 struct zbus_args *zap; 238 239 zap = aux; 240 241 if (zap->manid != 0x4144) 242 return (0); 243 244 if (zap->prodid != 0) 245 return (0); 246 247 return (1); 248 } 249 250 void 251 repulse_attach(device_t parent, device_t self, void *aux) 252 { 253 struct repulse_softc *sc; 254 struct zbus_args *zap; 255 struct repulse_hw *bp; 256 const uint8_t *fwp; 257 int needs_firmware; 258 uint16_t a; 259 260 sc = device_private(self); 261 sc->sc_dev = self; 262 zap = aux; 263 bp = (struct repulse_hw *)zap->va; 264 sc->sc_boardp = bp; 265 266 needs_firmware = 0; 267 if (bp->rhw_fifostatus & 0x00f0) 268 needs_firmware = 1; 269 else { 270 bp->rhw_status = 0x000c; 271 if (bp->rhw_status != 0 || bp->rhw_fifostatus != 0x0f0a) 272 needs_firmware = 1; 273 } 274 275 printf(": "); 276 if (needs_firmware) { 277 printf("loading "); 278 bp->rhw_reset = 0; 279 280 delay(1 * USECPERTICK); 281 282 for (fwp = (const uint8_t *)repulse_firmware; 283 fwp < (repulse_firmware_size + 284 (const uint8_t *)repulse_firmware); fwp++) 285 bp->rhw_firmwareload = *fwp; 286 287 delay(1 * USECPERTICK); 288 289 if (bp->rhw_fifostatus & 0x00f0) 290 goto Initerr; 291 292 a = /* bp->rhw_status; 293 a |= */ REPSTATUS_CODECRESET; 294 bp->rhw_status = a; 295 296 a = bp->rhw_status; 297 if ((a & REPSTATUS_CODECRESET) == 0) 298 goto Initerr; 299 300 (void)bp->rhw_status; 301 (void)bp->rhw_status; 302 (void)bp->rhw_status; 303 a = bp->rhw_status; 304 a &= ~REPSTATUS_CODECRESET; 305 bp->rhw_status = a; 306 } 307 308 printf("firmware version 0x%x\n", bp->rhw_version); 309 310 sc->sc_achost.arg = sc; 311 312 sc->sc_achost.reset = repac_reset; 313 sc->sc_achost.read = repac_read; 314 sc->sc_achost.write = repac_write; 315 sc->sc_achost.attach = repac_attach; 316 sc->sc_achost.flags = 0; 317 318 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 319 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 320 321 if (ac97_attach(&sc->sc_achost, self, &sc->sc_lock)) { 322 printf("%s: error attaching codec\n", device_xname(self)); 323 return; 324 } 325 326 #ifdef DIAGNOSTIC 327 /* 328 * Print a warning if the codec doesn't support hardware variable 329 * rate audio. As the initial incarnations of the Repulse board 330 * are AC'97 2.1, it is epxected that we'll always have VRA. 331 */ 332 /* 333 * XXX this should be a panic(). OTOH, audio codec speed is not 334 * important enough to do this. 335 */ 336 a = sc->sc_codec_if->vtbl->get_extcaps(sc->sc_codec_if); 337 if (!(a & AC97_EXT_AUDIO_VRA)) { 338 printf("%s: warning: codec doesn't support " 339 "hardware AC'97 2.0 Variable Rate Audio\n", 340 device_xname(self)); 341 } 342 #endif 343 344 sc->sc_isr.isr_ipl = 2; 345 sc->sc_isr.isr_arg = sc; 346 sc->sc_isr.isr_intr = rep_intr; 347 add_isr(&sc->sc_isr); 348 349 audio_attach_mi(&rep_hw_if, sc, self); 350 351 return; 352 353 Initerr: 354 printf("\n%s: firmware not successfully loaded\n", device_xname(self)); 355 return; 356 357 } 358 359 int 360 repac_reset(void *arg) 361 { 362 struct repulse_softc *sc; 363 struct repulse_hw *bp; 364 uint16_t a; 365 366 sc = arg; 367 bp = sc->sc_boardp; 368 a = bp->rhw_status; 369 a |= REPSTATUS_CODECRESET; 370 bp->rhw_status = a; 371 372 a = bp->rhw_status; 373 #ifdef DIAGNOSTIC 374 if ((a & REPSTATUS_CODECRESET) == 0) 375 panic("%s: cannot set reset bit", device_xname(sc->sc_dev)); 376 #endif 377 378 a = bp->rhw_status; 379 a = bp->rhw_status; 380 a = bp->rhw_status; 381 a = bp->rhw_status; 382 a &= ~REPSTATUS_CODECRESET; 383 bp->rhw_status = a; 384 return 0; 385 } 386 387 int 388 repac_read(void *arg, u_int8_t reg, u_int16_t *valuep) 389 { 390 struct repulse_softc *sc; 391 struct repulse_hw *bp; 392 393 sc = arg; 394 bp = sc->sc_boardp; 395 while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 396 continue; 397 bp->rhw_reg_address = (reg & 0x7F) | 0x80; 398 399 while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 400 continue; 401 402 *valuep = bp->rhw_reg_data; 403 404 return 0; 405 } 406 407 int 408 repac_write(void *arg, uint8_t reg, uint16_t value) 409 { 410 struct repulse_softc *sc; 411 struct repulse_hw *bp; 412 413 sc = arg; 414 bp = sc->sc_boardp; 415 bp->rhw_reg_data = value; 416 bp->rhw_reg_address = reg & 0x7F; 417 418 while (bp->rhw_status & REPSTATUS_REGSENDBUSY) 419 continue; 420 421 return 0; 422 } 423 424 int 425 repac_attach(void *arg, struct ac97_codec_if *acip) 426 { 427 struct repulse_softc *sc; 428 429 sc = arg; 430 sc->sc_codec_if = acip; 431 432 return 0; 433 } 434 435 /* audio(9) support stuff which is not ac97-constant */ 436 437 void 438 rep_close(void *arg) 439 { 440 struct repulse_softc *sc; 441 442 sc = arg; 443 rep_halt_output(sc); 444 rep_halt_input(sc); 445 } 446 447 int 448 rep_getdev(void *arg, struct audio_device *retp) 449 { 450 struct repulse_softc *sc; 451 struct repulse_hw *bp; 452 453 if (retp != NULL) { 454 sc = arg; 455 bp = sc->sc_boardp; 456 strncpy(retp->name, "Repulse", sizeof(retp->name)); 457 snprintf(retp->version, sizeof(retp->version), "0x%x", 458 bp->rhw_version); 459 strncpy(retp->config, "", sizeof(retp->config)); 460 } 461 462 return 0; 463 } 464 465 int 466 rep_get_props(void *v) 467 { 468 return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 469 } 470 471 int 472 rep_halt_output(void *arg) 473 { 474 struct repulse_softc *sc; 475 struct repulse_hw *bp; 476 477 sc = arg; 478 bp = sc->sc_boardp; 479 bp->rhw_status &= ~(REPSTATUS_PLAYIRQENABLE|REPSTATUS_PLAY); 480 481 482 return 0; 483 } 484 485 int 486 rep_halt_input(void *arg) 487 { 488 struct repulse_softc *sc; 489 struct repulse_hw *bp; 490 491 sc = arg; 492 bp = sc->sc_boardp; 493 bp->rhw_status &= ~(REPSTATUS_RECIRQENABLE|REPSTATUS_RECORD); 494 495 return 0; 496 } 497 498 /* 499 * Encoding support. 500 * 501 * TODO: add 24bit and 32bit modes here and in setparams. 502 */ 503 504 const struct repulse_encoding_query { 505 const char *name; 506 int encoding, precision, flags; 507 } rep_encoding_queries[] = { 508 { AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0}, 509 { AudioEmulaw, AUDIO_ENCODING_ULAW, 8, AUDIO_ENCODINGFLAG_EMULATED}, 510 { AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED}, 511 { AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0}, 512 { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0}, 513 { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0}, 514 { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0}, 515 { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0}, 516 }; 517 518 int 519 rep_query_encoding(void *arg, struct audio_encoding *fp) 520 { 521 int i; 522 const struct repulse_encoding_query *p; 523 524 i = fp->index; 525 526 if (i >= sizeof(rep_encoding_queries) / 527 sizeof(struct repulse_encoding_query)) 528 return EINVAL; 529 530 p = &rep_encoding_queries[i]; 531 532 strncpy (fp->name, p->name, sizeof(fp->name)); 533 fp->encoding = p->encoding; 534 fp->precision = p->precision; 535 fp->flags = p->flags; 536 537 return 0; 538 } 539 540 /* 541 * XXX the following three functions need to be enhanced for the FPGA s/pdif 542 * mode. Generic ac97 versions for now. 543 */ 544 545 int 546 rep_get_port(void *arg, mixer_ctrl_t *cp) 547 { 548 struct repulse_softc *sc; 549 550 sc = arg; 551 return sc->sc_codec_if->vtbl->mixer_get_port(sc->sc_codec_if, cp); 552 } 553 554 int 555 rep_set_port(void *arg, mixer_ctrl_t *cp) 556 { 557 struct repulse_softc *sc; 558 559 sc = arg; 560 return sc->sc_codec_if->vtbl->mixer_set_port(sc->sc_codec_if, cp); 561 } 562 563 int 564 rep_query_devinfo(void *arg, mixer_devinfo_t *dip) 565 { 566 struct repulse_softc *sc; 567 568 sc = arg; 569 return sc->sc_codec_if->vtbl->query_devinfo(sc->sc_codec_if, dip); 570 } 571 572 int 573 rep_round_blocksize(void *arg, int blk, int mode, const audio_params_t *param) 574 { 575 int b1; 576 577 b1 = (blk & -32); 578 579 if (b1 > 65536 / 2 / 2 /* channels */ / 4 /* bytes per channel */) 580 b1 = 65536 / 2 / 2 / 4; 581 return b1; 582 } 583 584 size_t 585 rep_round_buffersize(void *arg, int direction, size_t size) 586 { 587 return size; 588 } 589 590 void 591 rep_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 592 { 593 struct repulse_softc *sc = opaque; 594 595 *intr = &sc->sc_intr_lock; 596 *thread = &sc->sc_lock; 597 } 598 599 600 int 601 rep_set_params(void *addr, int setmode, int usemode, 602 audio_params_t *play, audio_params_t *rec, 603 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 604 { 605 audio_params_t hw; 606 struct repulse_softc *sc; 607 audio_params_t *p; 608 int mode, reg; 609 unsigned flags; 610 u_int16_t a; 611 612 sc = addr; 613 /* for mode in (RECORD, PLAY) */ 614 for (mode = AUMODE_RECORD; mode != -1; 615 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 616 617 if ((setmode & mode) == 0) 618 continue; 619 620 p = mode == AUMODE_PLAY ? play : rec; 621 622 /* TODO XXX we can do upto 32bit, 96000 */ 623 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 624 (p->precision != 8 && p->precision != 16) || 625 (p->channels != 1 && p->channels != 2)) 626 return EINVAL; 627 628 reg = mode == AUMODE_PLAY ? 629 AC97_REG_PCM_FRONT_DAC_RATE : AC97_REG_PCM_LR_ADC_RATE; 630 631 repac_write(sc, reg, (uint16_t) p->sample_rate); 632 repac_read(sc, reg, &a); 633 p->sample_rate = a; 634 635 if (mode == AUMODE_PLAY) 636 sc->sc_playscale = p->channels * p->precision / 8; 637 else 638 sc->sc_captscale = p->channels * p->precision / 8; 639 640 hw = *p; 641 642 /* everything else is software, alas... */ 643 /* XXX TBD signed/unsigned, *law, etc */ 644 645 flags = 0; 646 if (p->encoding == AUDIO_ENCODING_ULINEAR_LE || 647 p->encoding == AUDIO_ENCODING_ULINEAR_BE || 648 p->encoding == AUDIO_ENCODING_ULINEAR) 649 flags |= 1; 650 651 if (p->encoding == AUDIO_ENCODING_SLINEAR_LE || 652 p->encoding == AUDIO_ENCODING_ULINEAR_LE) 653 flags |= 2; 654 655 if (mode == AUMODE_PLAY) { 656 sc->sc_playflags = flags; 657 if (p->encoding == AUDIO_ENCODING_ULAW) { 658 sc->sc_playfun = p->channels == 1 ? 659 rep_write_16_mono : 660 rep_write_16_stereo; 661 sc->sc_playflags = 0; 662 sc->sc_playscale = p->channels * 2; 663 hw.encoding = AUDIO_ENCODING_SLINEAR_BE; 664 hw.precision = hw.validbits = 16; 665 pfil->append(pfil, mulaw_to_linear16, &hw); 666 } else 667 if (p->encoding == AUDIO_ENCODING_ALAW) { 668 sc->sc_playfun = p->channels == 1 ? 669 rep_write_16_mono : 670 rep_write_16_stereo; 671 sc->sc_playflags = 0; 672 sc->sc_playscale = p->channels * 2; 673 hw.encoding = AUDIO_ENCODING_SLINEAR_BE; 674 hw.precision = hw.validbits = 16; 675 pfil->append(pfil, alaw_to_linear16, &hw); 676 } else 677 if (p->precision == 8 && p->channels == 1) 678 sc->sc_playfun = rep_write_8_mono; 679 else if (p->precision == 8 && p->channels == 2) 680 sc->sc_playfun = rep_write_8_stereo; 681 else if (p->precision == 16 && p->channels == 1) 682 sc->sc_playfun = rep_write_16_mono; 683 else if (p->precision == 16 && p->channels == 2) 684 sc->sc_playfun = rep_write_16_stereo; 685 } else { 686 sc->sc_captflags = flags; 687 if (p->encoding == AUDIO_ENCODING_ULAW) { 688 sc->sc_captfun = p->channels == 1 ? 689 rep_read_8_mono : 690 rep_read_8_stereo; 691 sc->sc_captflags = 0; 692 hw.encoding = AUDIO_ENCODING_SLINEAR_LE; 693 rfil->append(rfil, linear8_to_mulaw, &hw); 694 } else 695 if (p->encoding == AUDIO_ENCODING_ALAW) { 696 sc->sc_captfun = p->channels == 1 ? 697 rep_read_8_mono : 698 rep_read_8_stereo; 699 sc->sc_captflags = 0; 700 rfil->append(rfil, linear8_to_alaw, &hw); 701 } else 702 if (p->precision == 8 && p->channels == 1) 703 sc->sc_captfun = rep_read_8_mono; 704 else if (p->precision == 8 && p->channels == 2) 705 sc->sc_captfun = rep_read_8_stereo; 706 else if (p->precision == 16 && p->channels == 1) 707 sc->sc_captfun = rep_read_16_mono; 708 else if (p->precision == 16 && p->channels == 2) 709 sc->sc_captfun = rep_read_16_stereo; 710 } 711 /* TBD: mu-law, A-law */ 712 } 713 return 0; 714 } 715 716 void 717 rep_write_8_mono(struct repulse_hw *bp, uint8_t *p, int length, unsigned flags) 718 { 719 uint16_t sample; 720 uint16_t xor; 721 722 xor = flags & 1 ? 0x8000 : 0; 723 724 bp->rhw_fifo_pack = 0; 725 726 while (length-- > 0) { 727 sample = ((*p++) << 8) ^ xor; 728 bp->rhw_fifo_lh = sample; 729 bp->rhw_fifo_rh = sample; 730 } 731 } 732 733 void 734 rep_write_8_stereo(struct repulse_hw *bp, uint8_t *p, int length, 735 unsigned flags) 736 { 737 uint16_t xor; 738 739 xor = flags & 1 ? 0x8000 : 0; 740 741 bp->rhw_fifo_pack = 0; 742 743 while (length-- > 0) { 744 bp->rhw_fifo_lh = ((*p++) << 8) ^ xor; 745 bp->rhw_fifo_rh = ((*p++) << 8) ^ xor; 746 } 747 } 748 749 void 750 rep_write_16_mono(struct repulse_hw *bp, uint8_t *p, int length, 751 unsigned flags) 752 { 753 uint16_t *q; 754 uint16_t sample; 755 uint16_t xor; 756 757 q = (uint16_t *)p; 758 xor = flags & 1 ? 0x8000 : 0; 759 760 bp->rhw_fifo_pack = 0; 761 762 if (flags & 2) { 763 while (length > 0) { 764 sample = bswap16(*q++) ^ xor; 765 bp->rhw_fifo_lh = sample; 766 bp->rhw_fifo_rh = sample; 767 length -= 2; 768 } 769 return; 770 } 771 772 while (length > 0) { 773 sample = (*q++) ^ xor; 774 bp->rhw_fifo_lh = sample; 775 bp->rhw_fifo_rh = sample; 776 length -= 2; 777 } 778 } 779 780 void 781 rep_write_16_stereo(struct repulse_hw *bp, uint8_t *p, int length, 782 unsigned flags) 783 { 784 uint16_t *q; 785 uint16_t xor; 786 787 q = (uint16_t *)p; 788 xor = flags & 1 ? 0x8000 : 0; 789 790 bp->rhw_fifo_pack = 0; 791 792 if (flags & 2) { 793 while (length > 0) { 794 bp->rhw_fifo_lh = bswap16(*q++) ^ xor; 795 bp->rhw_fifo_rh = bswap16(*q++) ^ xor; 796 length -= 4; 797 } 798 return; 799 } 800 while (length > 0) { 801 bp->rhw_fifo_lh = (*q++) ^ xor; 802 bp->rhw_fifo_rh = (*q++) ^ xor; 803 length -= 4; 804 } 805 } 806 807 void 808 rep_read_8_mono(struct repulse_hw *bp, uint8_t *p, int length, unsigned flags) 809 { 810 uint16_t v, xor; 811 812 xor = flags & 1 ? 0x8000 : 0; 813 814 while (length > 0) { 815 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8; 816 v = bp->rhw_fifo_rh; 817 __USE(v); 818 length--; 819 } 820 } 821 822 void 823 rep_read_16_mono(struct repulse_hw *bp, uint8_t *p, int length, unsigned flags) 824 { 825 uint16_t *q; 826 uint16_t v; 827 uint16_t xor; 828 829 q = (uint16_t *)p; 830 xor = flags & 1 ? 0x8000 : 0; 831 832 if (flags & 2) { 833 while (length > 0) { 834 *q++ = bswap16(bp->rhw_fifo_lh ^ xor); 835 v = bp->rhw_fifo_rh; 836 __USE(v); 837 length -= 2; 838 } 839 return; 840 } 841 842 while (length > 0) { 843 *q++ = bp->rhw_fifo_lh ^ xor; 844 v = bp->rhw_fifo_rh; 845 length -= 2; 846 } 847 } 848 849 void 850 rep_read_8_stereo(struct repulse_hw *bp, uint8_t *p, int length, 851 unsigned flags) 852 { 853 uint16_t xor; 854 855 xor = flags & 1 ? 0x8000 : 0; 856 while (length > 0) { 857 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8; 858 *p++ = (bp->rhw_fifo_rh ^ xor) >> 8; 859 length -= 2; 860 } 861 } 862 863 void 864 rep_read_16_stereo(struct repulse_hw *bp, uint8_t *p, int length, 865 unsigned flags) 866 { 867 uint16_t *q; 868 uint16_t xor; 869 870 q = (uint16_t *)p; 871 xor = flags & 1 ? 0x8000 : 0; 872 873 if (flags & 2) { 874 while (length > 0) { 875 *q++ = bswap16(bp->rhw_fifo_lh ^ xor); 876 *q++ = bswap16(bp->rhw_fifo_rh ^ xor); 877 length -= 4; 878 } 879 return; 880 } 881 while (length > 0) { 882 *q++ = bp->rhw_fifo_lh ^ xor; 883 *q++ = bp->rhw_fifo_rh ^ xor; 884 length -= 4; 885 } 886 } 887 888 /* 889 * At this point the transfer function is set. 890 */ 891 892 int 893 rep_start_output(void *addr, void *block, int blksize, 894 void (*intr)(void*), void *intrarg) 895 { 896 struct repulse_softc *sc; 897 uint8_t *buf; 898 struct repulse_hw *bp; 899 uint16_t status; 900 901 902 sc = addr; 903 bp = sc->sc_boardp; 904 buf = block; 905 906 /* TODO: prepare hw if necessary */ 907 status = bp->rhw_status; 908 if (!(status & REPSTATUS_PLAY)) 909 bp->rhw_status = status | 910 REPSTATUS_PLAY | REPSTATUS_PLAYFIFORST; 911 912 /* copy data */ 913 (*sc->sc_playfun)(bp, buf, blksize, sc->sc_playflags); 914 915 /* TODO: set hw if necessary */ 916 if (intr) { 917 bp->rhw_status |= REPSTATUS_PLAYIRQENABLE; 918 bp->rhw_play_fifosz = blksize / sc->sc_playscale / 2; 919 /* /2: give us time to return on the first call */ 920 } 921 922 /* save callback function */ 923 sc->sc_playarg = intrarg; 924 sc->sc_playmore = intr; 925 926 return 0; 927 } 928 929 int 930 rep_start_input(void *addr, void *block, int blksize, 931 void (*intr)(void*), void *intrarg) 932 { 933 struct repulse_softc *sc; 934 struct repulse_hw *bp; 935 uint16_t status; 936 937 sc = addr; 938 bp = sc->sc_boardp; 939 940 sc->sc_captbuf = block; 941 sc->sc_captbufsz = blksize; 942 sc->sc_captarg = intrarg; 943 sc->sc_captmore = intr; 944 945 status = bp->rhw_status; 946 if (!(status & REPSTATUS_RECORD)) 947 bp->rhw_status = status | REPSTATUS_RECORD 948 | REPSTATUS_RECFIFORST; 949 950 bp->rhw_status |= REPSTATUS_RECIRQENABLE; 951 bp->rhw_capt_fifosz = blksize / sc->sc_captscale; 952 953 return 0; 954 } 955 956 /* irq handler */ 957 958 int 959 rep_intr(void *tag) 960 { 961 struct repulse_softc *sc; 962 struct repulse_hw *bp; 963 int foundone; 964 uint16_t status; 965 966 foundone = 0; 967 968 sc = tag; 969 970 mutex_spin_enter(&sc->sc_intr_lock); 971 972 bp = sc->sc_boardp; 973 status = bp->rhw_status; 974 975 if (status & REPSTATUS_PLAYIRQACK) { 976 foundone = 1; 977 status &= ~REPSTATUS_PLAYIRQENABLE; 978 bp->rhw_status = status; 979 (*sc->sc_playmore)(sc->sc_playarg); 980 } 981 982 if (status & REPSTATUS_RECIRQACK) { 983 foundone = 1; 984 status &= ~REPSTATUS_RECIRQENABLE; 985 bp->rhw_status = status; 986 (*sc->sc_captfun)(bp, sc->sc_captbuf, sc->sc_captbufsz, 987 sc->sc_captflags); 988 (*sc->sc_captmore)(sc->sc_captarg); 989 } 990 991 mutex_spin_exit(&sc->sc_intr_lock); 992 993 return foundone; 994 } 995