1 /* $NetBSD: repulse.c,v 1.4 2002/01/28 09:57:02 aymeric 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.4 2002/01/28 09:57:02 aymeric 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 struct cfattach repulse_ca = { 237 sizeof(struct repulse_softc), repulse_match, repulse_attach 238 }; 239 240 int 241 repulse_match(struct device *parent, struct cfdata *cfp, void *aux) { 242 struct zbus_args *zap; 243 244 zap = aux; 245 246 if (zap->manid != 0x4144) 247 return (0); 248 249 if (zap->prodid != 0) 250 return (0); 251 252 return (1); 253 } 254 255 void 256 repulse_attach(struct device *parent, struct device *self, void *aux) { 257 struct repulse_softc *sc; 258 struct zbus_args *zap; 259 struct repulse_hw *bp; 260 struct mixer_ctrl ctl; 261 u_int8_t *fwp; 262 int needs_firmware; 263 int i; 264 265 u_int16_t a; 266 267 sc = (struct repulse_softc *)self; 268 zap = aux; 269 bp = (struct repulse_hw *)zap->va; 270 sc->sc_boardp = bp; 271 272 needs_firmware = 0; 273 if (bp->rhw_fifostatus & 0x00f0) 274 needs_firmware = 1; 275 else { 276 bp->rhw_status = 0x000c; 277 if (bp->rhw_status != 0 || bp->rhw_fifostatus != 0x0f0a) 278 needs_firmware = 1; 279 } 280 281 printf(": "); 282 if (needs_firmware) { 283 printf("loading "); 284 bp->rhw_reset = 0; 285 286 delay(1 * USECPERTICK); 287 288 for (fwp = (u_int8_t *)repulse_firmware; 289 fwp < (repulse_firmware_size + 290 (u_int8_t *)repulse_firmware); fwp++) 291 bp->rhw_firmwareload = *fwp; 292 293 delay(1 * USECPERTICK); 294 295 if (bp->rhw_fifostatus & 0x00f0) 296 goto Initerr; 297 298 a = /* bp->rhw_status; 299 a |= */ REPSTATUS_CODECRESET; 300 bp->rhw_status = a; 301 302 a = bp->rhw_status; 303 if ((a & REPSTATUS_CODECRESET) == 0) 304 goto Initerr; 305 306 (void)bp->rhw_status; 307 (void)bp->rhw_status; 308 (void)bp->rhw_status; 309 a = bp->rhw_status; 310 a &= ~REPSTATUS_CODECRESET; 311 bp->rhw_status = a; 312 } 313 314 printf("firmware version 0x%x\n", bp->rhw_version); 315 316 sc->sc_achost.arg = sc; 317 318 sc->sc_achost.reset = repac_reset; 319 sc->sc_achost.read = repac_read; 320 sc->sc_achost.write = repac_write; 321 sc->sc_achost.attach = repac_attach; 322 sc->sc_achost.flags = 0; 323 324 if (ac97_attach(&sc->sc_achost)) { 325 printf("%s: error attaching codec\n", self->dv_xname); 326 return; 327 } 328 329 #ifdef DIAGNOSTIC 330 /* 331 * Print a warning if the codec doesn't support hardware variable 332 * rate audio. As the initial incarnations of the Repulse board 333 * are AC'97 2.1, it is epxected that we'll always have VRA. 334 */ 335 /* 336 * XXX this should be a panic(). OTOH, audio codec speed is not 337 * important enough to do this. 338 */ 339 if (repac_read(sc, AC97_REG_EXTENDED_ID, &a) 340 || !(a & AC97_CODEC_DOES_VRA)) { 341 printf("%s: warning: codec doesn't support " 342 "hardware AC'97 2.0 Variable Rate Audio\n", 343 sc->sc_dev.dv_xname); 344 } 345 #endif 346 /* enable VRA */ 347 repac_write(sc, AC97_REG_EXTENDED_STATUS, 348 AC97_ENAB_VRA | AC97_ENAB_MICVRA); 349 350 /* 351 * from auvia.c: disable mutes ... 352 * XXX maybe this should happen in MI code? 353 */ 354 355 for (i = 0; i < 5; i++) { 356 static struct { 357 char *class, *device; 358 } d[] = { 359 { AudioCoutputs, AudioNmaster}, 360 { AudioCinputs, AudioNdac}, 361 { AudioCinputs, AudioNcd}, 362 { AudioCinputs, AudioNline}, 363 { AudioCrecord, AudioNvolume}, 364 }; 365 366 ctl.type = AUDIO_MIXER_ENUM; 367 ctl.un.ord = 0; 368 ctl.dev = sc->sc_codec_if->vtbl->get_portnum_by_name( 369 sc->sc_codec_if, d[i].class, d[i].device, AudioNmute); 370 rep_set_port(sc, &ctl); 371 } 372 373 sc->sc_isr.isr_ipl = 2; 374 sc->sc_isr.isr_arg = sc; 375 sc->sc_isr.isr_intr = rep_intr; 376 add_isr(&sc->sc_isr); 377 378 audio_attach_mi(&rep_hw_if, sc, &sc->sc_dev); 379 380 return; 381 382 Initerr: 383 printf("\n%s: firmware not successfully loaded\n", self->dv_xname); 384 return; 385 386 } 387 388 void repac_reset(void *arg) { 389 struct repulse_softc *sc = arg; 390 struct repulse_hw *bp = sc->sc_boardp; 391 392 u_int16_t a; 393 394 a = bp->rhw_status; 395 a |= REPSTATUS_CODECRESET; 396 bp->rhw_status = a; 397 398 a = bp->rhw_status; 399 #ifdef DIAGNOSTIC 400 if ((a & REPSTATUS_CODECRESET) == 0) 401 panic("%s: cannot set reset bit", sc->sc_dev.dv_xname); 402 #endif 403 404 a = bp->rhw_status; 405 a = bp->rhw_status; 406 a = bp->rhw_status; 407 a = bp->rhw_status; 408 a &= ~REPSTATUS_CODECRESET; 409 bp->rhw_status = a; 410 } 411 412 int repac_read(void *arg, u_int8_t reg, u_int16_t *valuep) { 413 struct repulse_softc *sc = arg; 414 struct repulse_hw *bp = sc->sc_boardp; 415 416 while (bp->rhw_status & REPSTATUS_REGSENDBUSY); 417 bp->rhw_reg_address = (reg & 0x7F) | 0x80; 418 419 while (bp->rhw_status & REPSTATUS_REGSENDBUSY); 420 421 *valuep = bp->rhw_reg_data; 422 423 return 0; 424 } 425 426 int repac_write(void *arg, u_int8_t reg, u_int16_t value) { 427 struct repulse_softc *sc = arg; 428 struct repulse_hw *bp = sc->sc_boardp; 429 430 bp->rhw_reg_data = value; 431 bp->rhw_reg_address = reg & 0x7F; 432 433 while (bp->rhw_status & REPSTATUS_REGSENDBUSY); 434 435 return 0; 436 } 437 438 int repac_attach(void *arg, struct ac97_codec_if *acip){ 439 440 struct repulse_softc *sc; 441 442 sc = arg; 443 sc->sc_codec_if = acip; 444 445 return 0; 446 } 447 448 /* audio(9) support stuff which is not ac97-constant */ 449 450 int 451 rep_open(void *arg, int flags) 452 { 453 return 0; 454 } 455 456 void 457 rep_close(void *arg) 458 { 459 struct repulse_softc *sc = arg; 460 461 rep_halt_output(sc); 462 rep_halt_input(sc); 463 } 464 465 int 466 rep_getdev(void *arg, struct audio_device *retp) 467 { 468 struct repulse_softc *sc = arg; 469 struct repulse_hw *bp = sc->sc_boardp; 470 471 if (retp) { 472 strncpy(retp->name, "Repulse", sizeof(retp->name)); 473 snprintf(retp->version, sizeof(retp->version), "0x%x", 474 bp->rhw_version); 475 strncpy(retp->config, "", sizeof(retp->config)); 476 } 477 478 return 0; 479 } 480 481 int 482 rep_get_props(void *v) 483 { 484 return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX); 485 } 486 487 int 488 rep_halt_output(void *arg) 489 { 490 struct repulse_softc *sc = arg; 491 struct repulse_hw *bp = sc->sc_boardp; 492 493 bp->rhw_status &= ~(REPSTATUS_PLAYIRQENABLE|REPSTATUS_PLAY); 494 495 496 return 0; 497 } 498 499 int 500 rep_halt_input(void *arg) 501 { 502 struct repulse_softc *sc = arg; 503 struct repulse_hw *bp = sc->sc_boardp; 504 505 bp->rhw_status &= ~(REPSTATUS_RECIRQENABLE|REPSTATUS_RECORD); 506 507 return 0; 508 } 509 510 /* 511 * Encoding support. 512 * 513 * TODO: add 24bit and 32bit modes here and in setparams. 514 */ 515 516 const struct repulse_encoding_query { 517 const char *name; 518 int encoding, precision, flags; 519 } rep_encoding_queries[] = { 520 { AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0}, 521 { AudioEmulaw, AUDIO_ENCODING_ULAW, 8, AUDIO_ENCODINGFLAG_EMULATED}, 522 { AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED}, 523 { AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0}, 524 { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0}, 525 { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0}, 526 { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0}, 527 { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0}, 528 }; 529 530 int 531 rep_query_encoding(void *arg, struct audio_encoding *fp) 532 { 533 int i; 534 const struct repulse_encoding_query *p; 535 536 i = fp->index; 537 538 if (i >= sizeof(rep_encoding_queries) / 539 sizeof(struct repulse_encoding_query)) 540 return (EINVAL); 541 542 p = &rep_encoding_queries[i]; 543 544 strncpy (fp->name, p->name, sizeof(fp->name)); 545 fp->encoding = p->encoding; 546 fp->precision = p->precision; 547 fp->flags = p->flags; 548 549 return (0); 550 } 551 552 /* 553 * XXX the following three functions need to be enhanced for the FPGA s/pdif 554 * mode. Generic ac97 versions for now. 555 */ 556 557 int 558 rep_get_port(void *arg, mixer_ctrl_t *cp) 559 { 560 struct repulse_softc *sc = arg; 561 562 return (sc->sc_codec_if->vtbl->mixer_get_port(sc->sc_codec_if, cp)); 563 } 564 565 int 566 rep_set_port(void *arg, mixer_ctrl_t *cp) 567 { 568 struct repulse_softc *sc = arg; 569 570 return (sc->sc_codec_if->vtbl->mixer_set_port(sc->sc_codec_if, cp)); 571 } 572 573 int 574 rep_query_devinfo (void *arg, mixer_devinfo_t *dip) 575 { 576 struct repulse_softc *sc = arg; 577 578 return (sc->sc_codec_if->vtbl->query_devinfo(sc->sc_codec_if, dip)); 579 } 580 581 int 582 rep_round_blocksize(void *arg, int blk) 583 { 584 int b1; 585 586 b1 = (blk & -32); 587 588 if (b1 > 65536 / 2 / 2 /* channels */ / 4 /* bytes per channel */) 589 b1 = 65536 / 2 / 2 / 4; 590 return (b1); 591 } 592 593 size_t 594 rep_round_buffersize(void *arg, int direction, size_t size) 595 { 596 return size; 597 } 598 599 600 int 601 rep_set_params(void *addr, int setmode, int usemode, 602 struct audio_params *play, struct audio_params *rec) 603 { 604 struct repulse_softc *sc = addr; 605 struct audio_params *p; 606 int mode, reg; 607 unsigned flags; 608 u_int16_t a; 609 610 /* for mode in (RECORD, PLAY) */ 611 for (mode = AUMODE_RECORD; mode != -1; 612 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 613 614 if ((setmode & mode) == 0) 615 continue; 616 617 p = mode == AUMODE_PLAY ? play : rec; 618 619 /* TODO XXX we can do upto 32bit, 96000 */ 620 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 621 (p->precision != 8 && p->precision != 16) || 622 (p->channels != 1 && p->channels != 2)) 623 return (EINVAL); 624 625 reg = mode == AUMODE_PLAY ? 626 AC97_REG_PCM_FRONT_DAC_RATE : AC97_REG_PCM_LR_ADC_RATE; 627 628 repac_write(sc, reg, (u_int16_t) p->sample_rate); 629 repac_read(sc, reg, &a); 630 p->sample_rate = a; 631 632 if (mode == AUMODE_PLAY) 633 sc->sc_playscale = p->channels * p->precision / 8; 634 else 635 sc->sc_captscale = p->channels * p->precision / 8; 636 637 p->factor = 1; 638 p->sw_code = 0; 639 640 /* everything else is software, alas... */ 641 /* XXX TBD signed/unsigned, *law, etc */ 642 643 flags = 0; 644 if (p->encoding == AUDIO_ENCODING_ULINEAR_LE || 645 p->encoding == AUDIO_ENCODING_ULINEAR_BE || 646 p->encoding == AUDIO_ENCODING_ULINEAR) 647 flags |= 1; 648 649 if (p->encoding == AUDIO_ENCODING_SLINEAR_LE || 650 p->encoding == AUDIO_ENCODING_ULINEAR_LE) 651 flags |= 2; 652 653 if (mode == AUMODE_PLAY) { 654 sc->sc_playflags = flags; 655 if (p->encoding == AUDIO_ENCODING_ULAW) { 656 sc->sc_playfun = p->channels == 1 ? 657 rep_write_16_mono : 658 rep_write_16_stereo; 659 sc->sc_playflags = 0; 660 sc->sc_playscale = p->channels * 2; 661 p->sw_code = mulaw_to_slinear16_be; 662 p->factor = 2; 663 } else 664 if (p->encoding == AUDIO_ENCODING_ALAW) { 665 sc->sc_playfun = p->channels == 1 ? 666 rep_write_16_mono : 667 rep_write_16_stereo; 668 sc->sc_playflags = 0; 669 sc->sc_playscale = p->channels * 2; 670 p->sw_code = alaw_to_slinear16_be; 671 p->factor = 2; 672 } else 673 if (p->precision == 8 && p->channels == 1) 674 sc->sc_playfun = rep_write_8_mono; 675 else if (p->precision == 8 && p->channels == 2) 676 sc->sc_playfun = rep_write_8_stereo; 677 else if (p->precision == 16 && p->channels == 1) 678 sc->sc_playfun = rep_write_16_mono; 679 else if (p->precision == 16 && p->channels == 2) 680 sc->sc_playfun = rep_write_16_stereo; 681 } else { 682 sc->sc_captflags = flags; 683 if (p->encoding == AUDIO_ENCODING_ULAW) { 684 sc->sc_captfun = p->channels == 1 ? 685 rep_read_8_mono : 686 rep_read_8_stereo; 687 sc->sc_captflags = 0; 688 p->sw_code = slinear8_to_mulaw; 689 p->factor = 1; 690 } else 691 if (p->encoding == AUDIO_ENCODING_ALAW) { 692 sc->sc_captfun = p->channels == 1 ? 693 rep_read_8_mono : 694 rep_read_8_stereo; 695 sc->sc_captflags = 0; 696 p->sw_code = slinear8_to_alaw; 697 p->factor = 1; 698 } else 699 if (p->precision == 8 && p->channels == 1) 700 sc->sc_captfun = rep_read_8_mono; 701 else if (p->precision == 8 && p->channels == 2) 702 sc->sc_captfun = rep_read_8_stereo; 703 else if (p->precision == 16 && p->channels == 1) 704 sc->sc_captfun = rep_read_16_mono; 705 else if (p->precision == 16 && p->channels == 2) 706 sc->sc_captfun = rep_read_16_stereo; 707 } 708 /* TBD: ulaw, alaw */ 709 } 710 return 0; 711 } 712 713 void 714 rep_write_8_mono(struct repulse_hw *bp, u_int8_t *p, int length, 715 unsigned flags) 716 { 717 u_int16_t sample; 718 u_int16_t xor; 719 720 xor = flags & 1 ? 0x8000 : 0; 721 722 bp->rhw_fifo_pack = 0; 723 724 while (length-- > 0) { 725 sample = ((*p++) << 8) ^ xor; 726 bp->rhw_fifo_lh = sample; 727 bp->rhw_fifo_rh = sample; 728 } 729 } 730 731 void 732 rep_write_8_stereo(struct repulse_hw *bp, u_int8_t *p, int length, 733 unsigned flags) 734 { 735 u_int16_t xor; 736 737 xor = flags & 1 ? 0x8000 : 0; 738 739 bp->rhw_fifo_pack = 0; 740 741 while (length-- > 0) { 742 bp->rhw_fifo_lh = ((*p++) << 8) ^ xor; 743 bp->rhw_fifo_rh = ((*p++) << 8) ^ xor; 744 } 745 } 746 747 void 748 rep_write_16_mono(struct repulse_hw *bp, u_int8_t *p, int length, 749 unsigned flags) 750 { 751 u_int16_t *q = (u_int16_t *)p; 752 u_int16_t sample; 753 u_int16_t xor; 754 755 xor = flags & 1 ? 0x8000 : 0; 756 757 bp->rhw_fifo_pack = 0; 758 759 if (flags & 2) { 760 while (length > 0) { 761 sample = bswap16(*q++) ^ xor; 762 bp->rhw_fifo_lh = sample; 763 bp->rhw_fifo_rh = sample; 764 length -= 2; 765 } 766 return; 767 } 768 769 while (length > 0) { 770 sample = (*q++) ^ xor; 771 bp->rhw_fifo_lh = sample; 772 bp->rhw_fifo_rh = sample; 773 length -= 2; 774 } 775 } 776 777 void 778 rep_write_16_stereo(struct repulse_hw *bp, u_int8_t *p, int length, 779 unsigned flags) 780 { 781 u_int16_t *q = (u_int16_t *)p; 782 u_int16_t xor; 783 784 xor = flags & 1 ? 0x8000 : 0; 785 786 bp->rhw_fifo_pack = 0; 787 788 if (flags & 2) { 789 while (length > 0) { 790 bp->rhw_fifo_lh = bswap16(*q++) ^ xor; 791 bp->rhw_fifo_rh = bswap16(*q++) ^ xor; 792 length -= 4; 793 } 794 return; 795 } 796 while (length > 0) { 797 bp->rhw_fifo_lh = (*q++) ^ xor; 798 bp->rhw_fifo_rh = (*q++) ^ xor; 799 length -= 4; 800 } 801 } 802 803 void 804 rep_read_8_mono(struct repulse_hw *bp, u_int8_t *p, int length, 805 unsigned flags) 806 { 807 u_int16_t v; 808 u_int16_t xor; 809 810 xor = flags & 1 ? 0x8000 : 0; 811 812 while (length > 0) { 813 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8; 814 v = bp->rhw_fifo_rh; 815 length--; 816 } 817 } 818 819 void 820 rep_read_16_mono(struct repulse_hw *bp, u_int8_t *p, int length, 821 unsigned flags) 822 { 823 u_int16_t *q = (u_int16_t *)p; 824 u_int16_t v; 825 u_int16_t xor; 826 827 xor = flags & 1 ? 0x8000 : 0; 828 829 if (flags & 2) { 830 while (length > 0) { 831 *q++ = bswap16(bp->rhw_fifo_lh ^ xor); 832 v = bp->rhw_fifo_rh; 833 length -= 2; 834 } 835 return; 836 } 837 838 while (length > 0) { 839 *q++ = bp->rhw_fifo_lh ^ xor; 840 v = bp->rhw_fifo_rh; 841 length -= 2; 842 } 843 } 844 845 void 846 rep_read_8_stereo(struct repulse_hw *bp, u_int8_t *p, int length, 847 unsigned flags) 848 { 849 u_int16_t xor; 850 851 xor = flags & 1 ? 0x8000 : 0; 852 while (length > 0) { 853 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8; 854 *p++ = (bp->rhw_fifo_rh ^ xor) >> 8; 855 length -= 2; 856 } 857 } 858 859 void 860 rep_read_16_stereo(struct repulse_hw *bp, u_int8_t *p, int length, 861 unsigned flags) 862 { 863 u_int16_t *q = (u_int16_t *)p; 864 u_int16_t xor; 865 866 xor = flags & 1 ? 0x8000 : 0; 867 868 if (flags & 2) { 869 while (length > 0) { 870 *q++ = bswap16(bp->rhw_fifo_lh ^ xor); 871 *q++ = bswap16(bp->rhw_fifo_rh ^ xor); 872 length -= 4; 873 } 874 return; 875 } 876 while (length > 0) { 877 *q++ = bp->rhw_fifo_lh ^ xor; 878 *q++ = bp->rhw_fifo_rh ^ xor; 879 length -= 4; 880 } 881 } 882 883 /* 884 * At this point the transfer function is set. 885 */ 886 887 int 888 rep_start_output(void *addr, void *block, int blksize, 889 void (*intr)(void*), void *intrarg) { 890 891 struct repulse_softc *sc; 892 u_int8_t *buf; 893 struct repulse_hw *bp; 894 u_int16_t status; 895 896 897 sc = addr; 898 bp = sc->sc_boardp; 899 buf = block; 900 901 /* TODO: prepare hw if necessary */ 902 status = bp->rhw_status; 903 if (!(status & REPSTATUS_PLAY)) 904 bp->rhw_status = status | 905 REPSTATUS_PLAY | REPSTATUS_PLAYFIFORST; 906 907 /* copy data */ 908 (*sc->sc_playfun)(bp, buf, blksize, sc->sc_playflags); 909 910 /* TODO: set hw if necessary */ 911 if (intr) { 912 bp->rhw_status |= REPSTATUS_PLAYIRQENABLE; 913 bp->rhw_play_fifosz = blksize / sc->sc_playscale / 2; 914 /* /2: give us time to return on the first call */ 915 } 916 917 /* save callback function */ 918 sc->sc_playarg = intrarg; 919 sc->sc_playmore = intr; 920 921 return 0; 922 } 923 924 int 925 rep_start_input(void *addr, void *block, int blksize, 926 void (*intr)(void*), void *intrarg) { 927 928 struct repulse_softc *sc; 929 struct repulse_hw *bp; 930 u_int16_t status; 931 932 sc = addr; 933 bp = sc->sc_boardp; 934 935 sc->sc_captbuf = block; 936 sc->sc_captbufsz = blksize; 937 sc->sc_captarg = intrarg; 938 sc->sc_captmore = intr; 939 940 status = bp->rhw_status; 941 if (!(status & REPSTATUS_RECORD)) 942 bp->rhw_status = status | REPSTATUS_RECORD 943 | REPSTATUS_RECFIFORST; 944 945 bp->rhw_status |= REPSTATUS_RECIRQENABLE; 946 bp->rhw_capt_fifosz = blksize / sc->sc_captscale; 947 948 return 0; 949 } 950 951 /* irq handler */ 952 953 int 954 rep_intr(void *tag) { 955 struct repulse_softc *sc; 956 struct repulse_hw *bp; 957 int foundone; 958 u_int16_t status; 959 960 foundone = 0; 961 962 sc = tag; 963 bp = sc->sc_boardp; 964 status = bp->rhw_status; 965 966 if (status & REPSTATUS_PLAYIRQACK) { 967 foundone = 1; 968 status &= ~REPSTATUS_PLAYIRQENABLE; 969 bp->rhw_status = status; 970 (*sc->sc_playmore)(sc->sc_playarg); 971 } 972 973 if (status & REPSTATUS_RECIRQACK) { 974 foundone = 1; 975 status &= ~REPSTATUS_RECIRQENABLE; 976 bp->rhw_status = status; 977 (*sc->sc_captfun)(bp, sc->sc_captbuf, sc->sc_captbufsz, 978 sc->sc_captflags); 979 (*sc->sc_captmore)(sc->sc_captarg); 980 } 981 982 return foundone; 983 } 984