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