harmony.c revision 1.29
1/* $OpenBSD: harmony.c,v 1.29 2014/07/12 18:44:41 tedu Exp $ */ 2 3/* 4 * Copyright (c) 2003 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Harmony (CS4215/AD1849 LASI) audio interface. 31 */ 32 33#include <sys/param.h> 34#include <sys/kernel.h> 35#include <sys/systm.h> 36#include <sys/errno.h> 37#include <sys/ioctl.h> 38#include <sys/device.h> 39#include <sys/proc.h> 40#include <sys/malloc.h> 41 42#include <sys/audioio.h> 43#include <dev/audio_if.h> 44#include <dev/auconv.h> 45#include <dev/rndvar.h> 46 47#include <machine/cpu.h> 48#include <machine/intr.h> 49#include <machine/iomod.h> 50#include <machine/autoconf.h> 51#include <machine/bus.h> 52 53#include <hppa/dev/cpudevs.h> 54#include <hppa/gsc/gscbusvar.h> 55#include <hppa/gsc/harmonyreg.h> 56#include <hppa/gsc/harmonyvar.h> 57 58int harmony_open(void *, int); 59void harmony_close(void *); 60int harmony_query_encoding(void *, struct audio_encoding *); 61int harmony_set_params(void *, int, int, struct audio_params *, 62 struct audio_params *); 63int harmony_round_blocksize(void *, int); 64int harmony_commit_settings(void *); 65int harmony_halt_output(void *); 66int harmony_halt_input(void *); 67int harmony_getdev(void *, struct audio_device *); 68int harmony_set_port(void *, mixer_ctrl_t *); 69int harmony_get_port(void *, mixer_ctrl_t *); 70int harmony_query_devinfo(void *addr, mixer_devinfo_t *); 71void * harmony_allocm(void *, int, size_t, int, int); 72void harmony_freem(void *, void *, int); 73size_t harmony_round_buffersize(void *, int, size_t); 74int harmony_get_props(void *); 75int harmony_trigger_output(void *, void *, void *, int, 76 void (*intr)(void *), void *, struct audio_params *); 77int harmony_trigger_input(void *, void *, void *, int, 78 void (*intr)(void *), void *, struct audio_params *); 79 80struct audio_hw_if harmony_sa_hw_if = { 81 harmony_open, 82 harmony_close, 83 NULL, 84 harmony_query_encoding, 85 harmony_set_params, 86 harmony_round_blocksize, 87 harmony_commit_settings, 88 NULL, 89 NULL, 90 NULL, 91 NULL, 92 harmony_halt_output, 93 harmony_halt_input, 94 NULL, 95 harmony_getdev, 96 NULL, 97 harmony_set_port, 98 harmony_get_port, 99 harmony_query_devinfo, 100 harmony_allocm, 101 harmony_freem, 102 harmony_round_buffersize, 103 NULL, 104 harmony_get_props, 105 harmony_trigger_output, 106 harmony_trigger_input, 107 NULL 108}; 109 110int harmony_match(struct device *, void *, void *); 111void harmony_attach(struct device *, struct device *, void *); 112int harmony_intr(void *); 113void harmony_intr_enable(struct harmony_softc *); 114void harmony_intr_disable(struct harmony_softc *); 115u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *); 116int harmony_set_gainctl(struct harmony_softc *); 117void harmony_reset_codec(struct harmony_softc *); 118void harmony_start_cp(struct harmony_softc *); 119void harmony_tick_pb(void *); 120void harmony_tick_cp(void *); 121void harmony_try_more(struct harmony_softc *); 122 123void harmony_acc_tmo(void *); 124#define ADD_CLKALLICA(sc) do { \ 125 (sc)->sc_acc <<= 1; \ 126 (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \ 127 if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \ 128 add_true_randomness((sc)->sc_acc_num ^= (sc)->sc_acc); \ 129} while(0) 130 131int 132harmony_match(parent, match, aux) 133 struct device *parent; 134 void *match, *aux; 135{ 136 struct gsc_attach_args *ga = aux; 137 bus_space_handle_t bh; 138 u_int32_t cntl; 139 140 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) { 141 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 || 142 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB || 143 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB || 144 ga->ga_type.iodc_sv_model == HPPA_FIO_A2) { 145 if (bus_space_map(ga->ga_iot, ga->ga_hpa, 146 HARMONY_NREGS, 0, &bh) != 0) 147 return (0); 148 cntl = bus_space_read_4(ga->ga_iot, bh, HARMONY_ID) & 149 ID_REV_MASK; 150 bus_space_unmap(ga->ga_iot, bh, HARMONY_NREGS); 151 if (cntl == ID_REV_TS || cntl == ID_REV_NOTS) 152 return (1); 153 } 154 } 155 return (0); 156} 157 158void 159harmony_attach(parent, self, aux) 160 struct device *parent, *self; 161 void *aux; 162{ 163 struct harmony_softc *sc = (struct harmony_softc *)self; 164 struct gsc_attach_args *ga = aux; 165 u_int8_t rev; 166 u_int32_t cntl; 167 int i; 168 169 sc->sc_bt = ga->ga_iot; 170 sc->sc_dmat = ga->ga_dmatag; 171 172 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0, 173 &sc->sc_bh) != 0) { 174 printf(": couldn't map registers\n"); 175 return; 176 } 177 178 cntl = READ_REG(sc, HARMONY_ID); 179 sc->sc_teleshare = (cntl & ID_REV_MASK) == ID_REV_TS; 180 181 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty), 182 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg, 183 BUS_DMA_NOWAIT) != 0) { 184 printf(": couldn't alloc DMA memory\n"); 185 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 186 return; 187 } 188 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1, 189 sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva, 190 BUS_DMA_NOWAIT) != 0) { 191 printf(": couldn't map DMA memory\n"); 192 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 193 sc->sc_empty_rseg); 194 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 195 return; 196 } 197 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1, 198 sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT, 199 &sc->sc_empty_map) != 0) { 200 printf(": can't create DMA map\n"); 201 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 202 sizeof(struct harmony_empty)); 203 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 204 sc->sc_empty_rseg); 205 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 206 return; 207 } 208 if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva, 209 sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) { 210 printf(": can't load DMA map\n"); 211 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map); 212 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 213 sizeof(struct harmony_empty)); 214 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 215 sc->sc_empty_rseg); 216 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 217 return; 218 } 219 220 sc->sc_playback_empty = 0; 221 for (i = 0; i < PLAYBACK_EMPTYS; i++) 222 sc->sc_playback_paddrs[i] = 223 sc->sc_empty_map->dm_segs[0].ds_addr + 224 offsetof(struct harmony_empty, playback[i][0]); 225 226 sc->sc_capture_empty = 0; 227 for (i = 0; i < CAPTURE_EMPTYS; i++) 228 sc->sc_capture_paddrs[i] = 229 sc->sc_empty_map->dm_segs[0].ds_addr + 230 offsetof(struct harmony_empty, playback[i][0]); 231 232 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 233 offsetof(struct harmony_empty, playback[0][0]), 234 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 235 236 (void)gsc_intr_establish((struct gsc_softc *)parent, ga->ga_irq, 237 IPL_AUDIO, harmony_intr, sc, sc->sc_dv.dv_xname); 238 239 /* set defaults */ 240 sc->sc_in_port = HARMONY_IN_LINE; 241 sc->sc_out_port = HARMONY_OUT_SPEAKER; 242 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240; 243 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244; 244 sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208; 245 sc->sc_outputgain = 0; 246 247 /* reset chip, and push default gain controls */ 248 harmony_reset_codec(sc); 249 250 cntl = READ_REG(sc, HARMONY_CNTL); 251 rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT; 252 printf(": rev %u", rev); 253 254 if (sc->sc_teleshare) 255 printf(", teleshare"); 256 printf("\n"); 257 258 if ((rev & CS4215_REV_VER) >= CS4215_REV_VER_E) 259 sc->sc_hasulinear8 = 1; 260 261 strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name)); 262 snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, 263 "%u.%u;%u", ga->ga_type.iodc_sv_rev, 264 ga->ga_type.iodc_model, ga->ga_type.iodc_revision); 265 strlcpy(sc->sc_audev.config, sc->sc_dv.dv_xname, 266 sizeof(sc->sc_audev.config)); 267 268 audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv); 269 270 timeout_set(&sc->sc_acc_tmo, harmony_acc_tmo, sc); 271 sc->sc_acc_num = 0xa5a5a5a5; 272} 273 274void 275harmony_reset_codec(struct harmony_softc *sc) 276{ 277 /* silence */ 278 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M | 279 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M); 280 281 /* start reset */ 282 WRITE_REG(sc, HARMONY_RESET, RESET_RST); 283 284 DELAY(100000); /* wait at least 0.05 sec */ 285 286 harmony_set_gainctl(sc); 287 WRITE_REG(sc, HARMONY_RESET, 0); 288} 289 290void 291harmony_acc_tmo(void *v) 292{ 293 struct harmony_softc *sc = v; 294 295 ADD_CLKALLICA(sc); 296 timeout_add(&sc->sc_acc_tmo, 1); 297} 298 299/* 300 * interrupt handler 301 */ 302int 303harmony_intr(vsc) 304 void *vsc; 305{ 306 struct harmony_softc *sc = vsc; 307 struct harmony_channel *c; 308 u_int32_t dstatus; 309 int r = 0; 310 311 mtx_enter(&audio_lock); 312 ADD_CLKALLICA(sc); 313 314 harmony_intr_disable(sc); 315 316 dstatus = READ_REG(sc, HARMONY_DSTATUS); 317 318 if (dstatus & DSTATUS_PN) { 319 struct harmony_dma *d; 320 bus_addr_t nextaddr; 321 bus_size_t togo; 322 323 r = 1; 324 c = &sc->sc_playback; 325 d = c->c_current; 326 togo = c->c_segsz - c->c_cnt; 327 if (togo == 0) { 328 nextaddr = d->d_map->dm_segs[0].ds_addr; 329 c->c_cnt = togo = c->c_blksz; 330 } else { 331 nextaddr = c->c_lastaddr; 332 if (togo > c->c_blksz) 333 togo = c->c_blksz; 334 c->c_cnt += togo; 335 } 336 337 bus_dmamap_sync(sc->sc_dmat, d->d_map, 338 nextaddr - d->d_map->dm_segs[0].ds_addr, 339 c->c_blksz, BUS_DMASYNC_PREWRITE); 340 341 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); 342 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); 343 c->c_lastaddr = nextaddr + togo; 344 harmony_try_more(sc); 345 } 346 347 dstatus = READ_REG(sc, HARMONY_DSTATUS); 348 349 if (dstatus & DSTATUS_RN) { 350 c = &sc->sc_capture; 351 r = 1; 352 harmony_start_cp(sc); 353 if (sc->sc_capturing && c->c_intr != NULL) 354 (*c->c_intr)(c->c_intrarg); 355 } 356 357 if (READ_REG(sc, HARMONY_OV) & OV_OV) { 358 sc->sc_ov = 1; 359 WRITE_REG(sc, HARMONY_OV, 0); 360 } else 361 sc->sc_ov = 0; 362 363 harmony_intr_enable(sc); 364 mtx_leave(&audio_lock); 365 return (r); 366} 367 368void 369harmony_intr_enable(struct harmony_softc *sc) 370{ 371 WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE); 372 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 373} 374 375void 376harmony_intr_disable(struct harmony_softc *sc) 377{ 378 WRITE_REG(sc, HARMONY_DSTATUS, 0); 379 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 380} 381 382int 383harmony_open(void *vsc, int flags) 384{ 385 struct harmony_softc *sc = vsc; 386 387 if (sc->sc_open) 388 return (EBUSY); 389 sc->sc_open = 1; 390 return (0); 391} 392 393void 394harmony_close(void *vsc) 395{ 396 struct harmony_softc *sc = vsc; 397 398 /* XXX: not useful, halt_*() already called */ 399 harmony_halt_input(sc); 400 harmony_halt_output(sc); 401 harmony_intr_disable(sc); 402 sc->sc_open = 0; 403} 404 405int 406harmony_query_encoding(void *vsc, struct audio_encoding *fp) 407{ 408 struct harmony_softc *sc = vsc; 409 int err = 0; 410 411 switch (fp->index) { 412 case 0: 413 strlcpy(fp->name, AudioEmulaw, sizeof fp->name); 414 fp->encoding = AUDIO_ENCODING_ULAW; 415 fp->precision = 8; 416 fp->flags = 0; 417 break; 418 case 1: 419 strlcpy(fp->name, AudioEalaw, sizeof fp->name); 420 fp->encoding = AUDIO_ENCODING_ALAW; 421 fp->precision = 8; 422 fp->flags = 0; 423 break; 424 case 2: 425 strlcpy(fp->name, AudioEslinear_be, sizeof fp->name); 426 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 427 fp->precision = 16; 428 fp->flags = 0; 429 break; 430 case 3: 431 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name); 432 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 433 fp->precision = 16; 434 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 435 break; 436 case 4: 437 strlcpy(fp->name, AudioEulinear_be, sizeof fp->name); 438 fp->encoding = AUDIO_ENCODING_ULINEAR_BE; 439 fp->precision = 16; 440 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 441 break; 442 case 5: 443 strlcpy(fp->name, AudioEulinear_le, sizeof fp->name); 444 fp->encoding = AUDIO_ENCODING_ULINEAR_LE; 445 fp->precision = 16; 446 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 447 break; 448 case 6: 449 if (sc->sc_hasulinear8) { 450 strlcpy(fp->name, AudioEulinear, sizeof fp->name); 451 fp->encoding = AUDIO_ENCODING_ULINEAR; 452 fp->precision = 8; 453 fp->flags = 0; 454 break; 455 } 456 /*FALLTHROUGH*/ 457 case 7: 458 if (sc->sc_hasulinear8) { 459 strlcpy(fp->name, AudioEslinear, sizeof fp->name); 460 fp->encoding = AUDIO_ENCODING_SLINEAR; 461 fp->precision = 8; 462 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 463 break; 464 } 465 /*FALLTHROUGH*/ 466 default: 467 err = EINVAL; 468 } 469 fp->bps = AUDIO_BPS(fp->precision); 470 fp->msb = 1; 471 return (err); 472} 473 474int 475harmony_set_params(void *vsc, int setmode, int usemode, 476 struct audio_params *p, struct audio_params *r) 477{ 478 struct harmony_softc *sc = vsc; 479 u_int32_t bits; 480 void (*pswcode)(void *, u_char *, int cnt) = NULL; 481 void (*rswcode)(void *, u_char *, int cnt) = NULL; 482 483 switch (p->encoding) { 484 case AUDIO_ENCODING_ULAW: 485 if (p->precision != 8) 486 return (EINVAL); 487 bits = CNTL_FORMAT_ULAW; 488 break; 489 case AUDIO_ENCODING_ALAW: 490 if (p->precision != 8) 491 return (EINVAL); 492 bits = CNTL_FORMAT_ALAW; 493 break; 494 case AUDIO_ENCODING_SLINEAR_BE: 495 if (p->precision == 8) { 496 bits = CNTL_FORMAT_ULINEAR8; 497 rswcode = pswcode = change_sign8; 498 break; 499 } 500 if (p->precision == 16) { 501 bits = CNTL_FORMAT_SLINEAR16BE; 502 break; 503 } 504 return (EINVAL); 505 case AUDIO_ENCODING_ULINEAR: 506 if (p->precision != 8) 507 return (EINVAL); 508 bits = CNTL_FORMAT_ULINEAR8; 509 break; 510 case AUDIO_ENCODING_SLINEAR: 511 if (p->precision != 8) 512 return (EINVAL); 513 bits = CNTL_FORMAT_ULINEAR8; 514 rswcode = pswcode = change_sign8; 515 break; 516 case AUDIO_ENCODING_SLINEAR_LE: 517 if (p->precision == 8) { 518 bits = CNTL_FORMAT_ULINEAR8; 519 rswcode = pswcode = change_sign8; 520 break; 521 } 522 if (p->precision == 16) { 523 bits = CNTL_FORMAT_SLINEAR16BE; 524 rswcode = pswcode = swap_bytes; 525 break; 526 } 527 return (EINVAL); 528 case AUDIO_ENCODING_ULINEAR_BE: 529 if (p->precision == 8) { 530 bits = CNTL_FORMAT_ULINEAR8; 531 break; 532 } 533 if (p->precision == 16) { 534 bits = CNTL_FORMAT_SLINEAR16BE; 535 rswcode = pswcode = change_sign16_be; 536 break; 537 } 538 return (EINVAL); 539 case AUDIO_ENCODING_ULINEAR_LE: 540 if (p->precision == 8) { 541 bits = CNTL_FORMAT_ULINEAR8; 542 break; 543 } 544 if (p->precision == 16) { 545 bits = CNTL_FORMAT_SLINEAR16BE; 546 pswcode = change_sign16_swap_bytes_le; 547 rswcode = swap_bytes_change_sign16_le; 548 break; 549 } 550 return (EINVAL); 551 default: 552 return (EINVAL); 553 } 554 555 if (sc->sc_outputgain) 556 bits |= CNTL_OLB; 557 558 if (p->channels == 1) 559 bits |= CNTL_CHANS_MONO; 560 else if (p->channels == 2) 561 bits |= CNTL_CHANS_STEREO; 562 else 563 return (EINVAL); 564 565 p->sw_code = pswcode; 566 r->sw_code = rswcode; 567 p->bps = AUDIO_BPS(p->precision); 568 r->bps = AUDIO_BPS(r->precision); 569 p->msb = r->msb = 1; 570 571 bits |= harmony_speed_bits(sc, &p->sample_rate); 572 sc->sc_cntlbits = bits; 573 sc->sc_need_commit = 1; 574 575 return (0); 576} 577 578int 579harmony_round_blocksize(void *vsc, int blk) 580{ 581 return (HARMONY_BUFSIZE); 582} 583 584int 585harmony_commit_settings(void *vsc) 586{ 587 struct harmony_softc *sc = vsc; 588 u_int32_t reg; 589 u_int8_t quietchar; 590 int i; 591 592 if (sc->sc_need_commit == 0) 593 return (0); 594 595 harmony_intr_disable(sc); 596 597 for (;;) { 598 reg = READ_REG(sc, HARMONY_DSTATUS); 599 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0) 600 break; 601 } 602 603 /* Setting some bits in gainctl requires a reset */ 604 harmony_reset_codec(sc); 605 606 /* set the silence character based on the encoding type */ 607 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 608 offsetof(struct harmony_empty, playback[0][0]), 609 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE); 610 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) { 611 case CNTL_FORMAT_ULAW: 612 quietchar = 0x7f; 613 break; 614 case CNTL_FORMAT_ALAW: 615 quietchar = 0x55; 616 break; 617 case CNTL_FORMAT_SLINEAR16BE: 618 case CNTL_FORMAT_ULINEAR8: 619 default: 620 quietchar = 0; 621 break; 622 } 623 for (i = 0; i < PLAYBACK_EMPTYS; i++) 624 memset(&sc->sc_empty_kva->playback[i][0], 625 quietchar, HARMONY_BUFSIZE); 626 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 627 offsetof(struct harmony_empty, playback[0][0]), 628 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 629 630 for (;;) { 631 /* Wait for it to come out of control mode */ 632 reg = READ_REG(sc, HARMONY_CNTL); 633 if ((reg & CNTL_C) == 0) 634 break; 635 } 636 637 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL, 638 sc->sc_cntlbits | CNTL_C); 639 640 for (;;) { 641 /* Wait for it to come out of control mode */ 642 reg = READ_REG(sc, HARMONY_CNTL); 643 if ((reg & CNTL_C) == 0) 644 break; 645 } 646 647 sc->sc_need_commit = 0; 648 649 if (sc->sc_playing || sc->sc_capturing) 650 harmony_intr_enable(sc); 651 652 return (0); 653} 654 655int 656harmony_halt_output(void *vsc) 657{ 658 struct harmony_softc *sc = vsc; 659 660 /* XXX: disable interrupts */ 661 sc->sc_playing = 0; 662 return (0); 663} 664 665int 666harmony_halt_input(void *vsc) 667{ 668 struct harmony_softc *sc = vsc; 669 670 /* XXX: disable interrupts */ 671 sc->sc_capturing = 0; 672 return (0); 673} 674 675int 676harmony_getdev(void *vsc, struct audio_device *retp) 677{ 678 struct harmony_softc *sc = vsc; 679 680 *retp = sc->sc_audev; 681 682 return (0); 683} 684 685int 686harmony_set_port(void *vsc, mixer_ctrl_t *cp) 687{ 688 struct harmony_softc *sc = vsc; 689 int err = EINVAL; 690 691 switch (cp->dev) { 692 case HARMONY_PORT_INPUT_LVL: 693 if (cp->type != AUDIO_MIXER_VALUE) 694 break; 695 if (cp->un.value.num_channels == 1) 696 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 697 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 698 else if (cp->un.value.num_channels == 2) { 699 sc->sc_input_lvl.left = 700 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 701 sc->sc_input_lvl.right = 702 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 703 } else 704 break; 705 sc->sc_need_commit = 1; 706 err = 0; 707 break; 708 case HARMONY_PORT_OUTPUT_LVL: 709 if (cp->type != AUDIO_MIXER_VALUE) 710 break; 711 if (cp->un.value.num_channels == 1) 712 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 713 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 714 else if (cp->un.value.num_channels == 2) { 715 sc->sc_output_lvl.left = 716 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 717 sc->sc_output_lvl.right = 718 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 719 } else 720 break; 721 sc->sc_need_commit = 1; 722 err = 0; 723 break; 724 case HARMONY_PORT_OUTPUT_GAIN: 725 if (cp->type != AUDIO_MIXER_ENUM) 726 break; 727 sc->sc_outputgain = cp->un.ord ? 1 : 0; 728 err = 0; 729 break; 730 case HARMONY_PORT_MONITOR_LVL: 731 if (cp->type != AUDIO_MIXER_VALUE) 732 break; 733 if (cp->un.value.num_channels != 1) 734 break; 735 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right = 736 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 737 sc->sc_need_commit = 1; 738 err = 0; 739 break; 740 case HARMONY_PORT_RECORD_SOURCE: 741 if (cp->type != AUDIO_MIXER_ENUM) 742 break; 743 if (cp->un.ord != HARMONY_IN_LINE && 744 cp->un.ord != HARMONY_IN_MIC) 745 break; 746 sc->sc_in_port = cp->un.ord; 747 err = 0; 748 sc->sc_need_commit = 1; 749 break; 750 case HARMONY_PORT_OUTPUT_SOURCE: 751 if (cp->type != AUDIO_MIXER_ENUM) 752 break; 753 if (cp->un.ord != HARMONY_OUT_LINE && 754 cp->un.ord != HARMONY_OUT_SPEAKER && 755 cp->un.ord != HARMONY_OUT_HEADPHONE) 756 break; 757 sc->sc_out_port = cp->un.ord; 758 err = 0; 759 sc->sc_need_commit = 1; 760 break; 761 } 762 763 return (err); 764} 765 766int 767harmony_get_port(void *vsc, mixer_ctrl_t *cp) 768{ 769 struct harmony_softc *sc = vsc; 770 int err = EINVAL; 771 772 switch (cp->dev) { 773 case HARMONY_PORT_INPUT_LVL: 774 if (cp->type != AUDIO_MIXER_VALUE) 775 break; 776 if (cp->un.value.num_channels == 1) { 777 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 778 sc->sc_input_lvl.left; 779 } else if (cp->un.value.num_channels == 2) { 780 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 781 sc->sc_input_lvl.left; 782 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 783 sc->sc_input_lvl.right; 784 } else 785 break; 786 err = 0; 787 break; 788 case HARMONY_PORT_INPUT_OV: 789 if (cp->type != AUDIO_MIXER_ENUM) 790 break; 791 cp->un.ord = sc->sc_ov ? 1 : 0; 792 err = 0; 793 break; 794 case HARMONY_PORT_OUTPUT_LVL: 795 if (cp->type != AUDIO_MIXER_VALUE) 796 break; 797 if (cp->un.value.num_channels == 1) { 798 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 799 sc->sc_output_lvl.left; 800 } else if (cp->un.value.num_channels == 2) { 801 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 802 sc->sc_output_lvl.left; 803 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 804 sc->sc_output_lvl.right; 805 } else 806 break; 807 err = 0; 808 break; 809 case HARMONY_PORT_OUTPUT_GAIN: 810 if (cp->type != AUDIO_MIXER_ENUM) 811 break; 812 cp->un.ord = sc->sc_outputgain ? 1 : 0; 813 err = 0; 814 break; 815 case HARMONY_PORT_MONITOR_LVL: 816 if (cp->type != AUDIO_MIXER_VALUE) 817 break; 818 if (cp->un.value.num_channels != 1) 819 break; 820 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 821 sc->sc_monitor_lvl.left; 822 err = 0; 823 break; 824 case HARMONY_PORT_RECORD_SOURCE: 825 if (cp->type != AUDIO_MIXER_ENUM) 826 break; 827 cp->un.ord = sc->sc_in_port; 828 err = 0; 829 break; 830 case HARMONY_PORT_OUTPUT_SOURCE: 831 if (cp->type != AUDIO_MIXER_ENUM) 832 break; 833 cp->un.ord = sc->sc_out_port; 834 err = 0; 835 break; 836 } 837 return (0); 838} 839 840int 841harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip) 842{ 843 int err = 0; 844 845 switch (dip->index) { 846 case HARMONY_PORT_INPUT_LVL: 847 dip->type = AUDIO_MIXER_VALUE; 848 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 849 dip->prev = dip->next = AUDIO_MIXER_LAST; 850 strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name); 851 dip->un.v.num_channels = 2; 852 strlcpy(dip->un.v.units.name, AudioNvolume, 853 sizeof dip->un.v.units.name); 854 break; 855 case HARMONY_PORT_INPUT_OV: 856 dip->type = AUDIO_MIXER_ENUM; 857 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 858 dip->prev = dip->next = AUDIO_MIXER_LAST; 859 strlcpy(dip->label.name, "overrange", sizeof dip->label.name); 860 dip->un.e.num_mem = 2; 861 strlcpy(dip->un.e.member[0].label.name, AudioNoff, 862 sizeof dip->un.e.member[0].label.name); 863 dip->un.e.member[0].ord = 0; 864 strlcpy(dip->un.e.member[1].label.name, AudioNon, 865 sizeof dip->un.e.member[1].label.name); 866 dip->un.e.member[1].ord = 1; 867 break; 868 case HARMONY_PORT_OUTPUT_LVL: 869 dip->type = AUDIO_MIXER_VALUE; 870 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 871 dip->prev = dip->next = AUDIO_MIXER_LAST; 872 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); 873 dip->un.v.num_channels = 2; 874 strlcpy(dip->un.v.units.name, AudioNvolume, 875 sizeof dip->un.v.units.name); 876 break; 877 case HARMONY_PORT_OUTPUT_GAIN: 878 dip->type = AUDIO_MIXER_ENUM; 879 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 880 dip->prev = dip->next = AUDIO_MIXER_LAST; 881 strlcpy(dip->label.name, "gain", sizeof dip->label.name); 882 dip->un.e.num_mem = 2; 883 strlcpy(dip->un.e.member[0].label.name, AudioNoff, 884 sizeof dip->un.e.member[0].label.name); 885 dip->un.e.member[0].ord = 0; 886 strlcpy(dip->un.e.member[1].label.name, AudioNon, 887 sizeof dip->un.e.member[1].label.name); 888 dip->un.e.member[1].ord = 1; 889 break; 890 case HARMONY_PORT_MONITOR_LVL: 891 dip->type = AUDIO_MIXER_VALUE; 892 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 893 dip->prev = dip->next = AUDIO_MIXER_LAST; 894 strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name); 895 dip->un.v.num_channels = 1; 896 strlcpy(dip->un.v.units.name, AudioNvolume, 897 sizeof dip->un.v.units.name); 898 break; 899 case HARMONY_PORT_RECORD_SOURCE: 900 dip->type = AUDIO_MIXER_ENUM; 901 dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 902 dip->prev = dip->next = AUDIO_MIXER_LAST; 903 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 904 dip->un.e.num_mem = 2; 905 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone, 906 sizeof dip->un.e.member[0].label.name); 907 dip->un.e.member[0].ord = HARMONY_IN_MIC; 908 strlcpy(dip->un.e.member[1].label.name, AudioNline, 909 sizeof dip->un.e.member[1].label.name); 910 dip->un.e.member[1].ord = HARMONY_IN_LINE; 911 break; 912 case HARMONY_PORT_OUTPUT_SOURCE: 913 dip->type = AUDIO_MIXER_ENUM; 914 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 915 dip->prev = dip->next = AUDIO_MIXER_LAST; 916 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); 917 dip->un.e.num_mem = 3; 918 strlcpy(dip->un.e.member[0].label.name, AudioNline, 919 sizeof dip->un.e.member[0].label.name); 920 dip->un.e.member[0].ord = HARMONY_OUT_LINE; 921 strlcpy(dip->un.e.member[1].label.name, AudioNspeaker, 922 sizeof dip->un.e.member[1].label.name); 923 dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER; 924 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone, 925 sizeof dip->un.e.member[2].label.name); 926 dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE; 927 break; 928 case HARMONY_PORT_INPUT_CLASS: 929 dip->type = AUDIO_MIXER_CLASS; 930 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 931 dip->prev = dip->next = AUDIO_MIXER_LAST; 932 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name); 933 break; 934 case HARMONY_PORT_OUTPUT_CLASS: 935 dip->type = AUDIO_MIXER_CLASS; 936 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 937 dip->prev = dip->next = AUDIO_MIXER_LAST; 938 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 939 break; 940 case HARMONY_PORT_MONITOR_CLASS: 941 dip->type = AUDIO_MIXER_CLASS; 942 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 943 dip->prev = dip->next = AUDIO_MIXER_LAST; 944 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 945 break; 946 case HARMONY_PORT_RECORD_CLASS: 947 dip->type = AUDIO_MIXER_CLASS; 948 dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 949 dip->prev = dip->next = AUDIO_MIXER_LAST; 950 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 951 break; 952 default: 953 err = ENXIO; 954 break; 955 } 956 957 return (err); 958} 959 960void * 961harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags) 962{ 963 struct harmony_softc *sc = vsc; 964 struct harmony_dma *d; 965 int rseg; 966 967 d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags); 968 if (d == NULL) 969 goto fail; 970 971 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, 972 &d->d_map) != 0) 973 goto fail1; 974 975 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1, 976 &rseg, BUS_DMA_NOWAIT) != 0) 977 goto fail2; 978 979 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva, 980 BUS_DMA_NOWAIT) != 0) 981 goto fail3; 982 983 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL, 984 BUS_DMA_NOWAIT) != 0) 985 goto fail4; 986 987 d->d_next = sc->sc_dmas; 988 sc->sc_dmas = d; 989 d->d_size = size; 990 return (d->d_kva); 991 992fail4: 993 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size); 994fail3: 995 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 996fail2: 997 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 998fail1: 999 free(d, pool, 0); 1000fail: 1001 return (NULL); 1002} 1003 1004void 1005harmony_freem(void *vsc, void *ptr, int pool) 1006{ 1007 struct harmony_softc *sc = vsc; 1008 struct harmony_dma *d, **dd; 1009 1010 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) { 1011 if (d->d_kva != ptr) 1012 continue; 1013 bus_dmamap_unload(sc->sc_dmat, d->d_map); 1014 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size); 1015 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 1016 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 1017 free(d, pool, 0); 1018 return; 1019 } 1020 printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname); 1021} 1022 1023size_t 1024harmony_round_buffersize(void *vsc, int direction, size_t size) 1025{ 1026 return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE)); 1027} 1028 1029int 1030harmony_get_props(void *vsc) 1031{ 1032 return (AUDIO_PROP_FULLDUPLEX); 1033} 1034 1035int 1036harmony_trigger_output(void *vsc, void *start, void *end, int blksize, 1037 void (*intr)(void *), void *intrarg, struct audio_params *param) 1038{ 1039 struct harmony_softc *sc = vsc; 1040 struct harmony_channel *c = &sc->sc_playback; 1041 struct harmony_dma *d; 1042 bus_addr_t nextaddr; 1043 bus_size_t togo; 1044 1045 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 1046 /*EMPTY*/; 1047 if (d == NULL) { 1048 printf("%s: trigger_output: bad addr: %p\n", 1049 sc->sc_dv.dv_xname, start); 1050 return (EINVAL); 1051 } 1052 1053 c->c_intr = intr; 1054 c->c_intrarg = intrarg; 1055 c->c_blksz = blksize; 1056 c->c_current = d; 1057 c->c_segsz = (caddr_t)end - (caddr_t)start; 1058 c->c_cnt = 0; 1059 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 1060 1061 sc->sc_playing = 1; 1062 1063 togo = c->c_segsz - c->c_cnt; 1064 if (togo == 0) { 1065 nextaddr = d->d_map->dm_segs[0].ds_addr; 1066 c->c_cnt = togo = c->c_blksz; 1067 } else { 1068 nextaddr = c->c_lastaddr; 1069 if (togo > c->c_blksz) 1070 togo = c->c_blksz; 1071 c->c_cnt += togo; 1072 } 1073 1074 bus_dmamap_sync(sc->sc_dmat, d->d_map, 1075 nextaddr - d->d_map->dm_segs[0].ds_addr, 1076 c->c_blksz, BUS_DMASYNC_PREWRITE); 1077 1078 mtx_enter(&audio_lock); 1079 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); 1080 c->c_theaddr = nextaddr; 1081 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); 1082 c->c_lastaddr = nextaddr + togo; 1083 1084 harmony_start_cp(sc); 1085 harmony_intr_enable(sc); 1086 mtx_leave(&audio_lock); 1087 return (0); 1088} 1089 1090void 1091harmony_start_cp(struct harmony_softc *sc) 1092{ 1093 struct harmony_channel *c = &sc->sc_capture; 1094 struct harmony_dma *d; 1095 bus_addr_t nextaddr; 1096 bus_size_t togo; 1097 1098 if (sc->sc_capturing == 0) { 1099 WRITE_REG(sc, HARMONY_RNXTADD, 1100 sc->sc_capture_paddrs[sc->sc_capture_empty]); 1101 if (++sc->sc_capture_empty == CAPTURE_EMPTYS) 1102 sc->sc_capture_empty = 0; 1103 } else { 1104 d = c->c_current; 1105 togo = c->c_segsz - c->c_cnt; 1106 if (togo == 0) { 1107 nextaddr = d->d_map->dm_segs[0].ds_addr; 1108 c->c_cnt = togo = c->c_blksz; 1109 } else { 1110 nextaddr = c->c_lastaddr; 1111 if (togo > c->c_blksz) 1112 togo = c->c_blksz; 1113 c->c_cnt += togo; 1114 } 1115 1116 bus_dmamap_sync(sc->sc_dmat, d->d_map, 1117 nextaddr - d->d_map->dm_segs[0].ds_addr, 1118 c->c_blksz, BUS_DMASYNC_PREWRITE); 1119 1120 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr); 1121 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE); 1122 c->c_lastaddr = nextaddr + togo; 1123 } 1124 1125 timeout_add(&sc->sc_acc_tmo, 1); 1126} 1127 1128int 1129harmony_trigger_input(void *vsc, void *start, void *end, int blksize, 1130 void (*intr)(void *), void *intrarg, struct audio_params *param) 1131{ 1132 struct harmony_softc *sc = vsc; 1133 struct harmony_channel *c = &sc->sc_capture; 1134 struct harmony_dma *d; 1135 1136 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 1137 /*EMPTY*/; 1138 if (d == NULL) { 1139 printf("%s: trigger_input: bad addr: %p\n", 1140 sc->sc_dv.dv_xname, start); 1141 return (EINVAL); 1142 } 1143 1144 c->c_intr = intr; 1145 c->c_intrarg = intrarg; 1146 c->c_blksz = blksize; 1147 c->c_current = d; 1148 c->c_segsz = (caddr_t)end - (caddr_t)start; 1149 c->c_cnt = 0; 1150 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 1151 mtx_enter(&audio_lock); 1152 sc->sc_capturing = 1; 1153 harmony_start_cp(sc); 1154 harmony_intr_enable(sc); 1155 mtx_leave(&audio_lock); 1156 return (0); 1157} 1158 1159static const struct speed_struct { 1160 u_int32_t speed; 1161 u_int32_t bits; 1162} harmony_speeds[] = { 1163 { 5125, CNTL_RATE_5125 }, 1164 { 6615, CNTL_RATE_6615 }, 1165 { 8000, CNTL_RATE_8000 }, 1166 { 9600, CNTL_RATE_9600 }, 1167 { 11025, CNTL_RATE_11025 }, 1168 { 16000, CNTL_RATE_16000 }, 1169 { 18900, CNTL_RATE_18900 }, 1170 { 22050, CNTL_RATE_22050 }, 1171 { 27428, CNTL_RATE_27428 }, 1172 { 32000, CNTL_RATE_32000 }, 1173 { 33075, CNTL_RATE_33075 }, 1174 { 37800, CNTL_RATE_37800 }, 1175 { 44100, CNTL_RATE_44100 }, 1176 { 48000, CNTL_RATE_48000 }, 1177}; 1178 1179u_int32_t 1180harmony_speed_bits(struct harmony_softc *sc, u_long *speedp) 1181{ 1182 int i, n, selected = -1; 1183 1184 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]); 1185 1186 if ((*speedp) <= harmony_speeds[0].speed) 1187 selected = 0; 1188 else if ((*speedp) >= harmony_speeds[n - 1].speed) 1189 selected = n - 1; 1190 else { 1191 for (i = 1; selected == -1 && i < n; i++) { 1192 if ((*speedp) == harmony_speeds[i].speed) 1193 selected = i; 1194 else if ((*speedp) < harmony_speeds[i].speed) { 1195 int diff1, diff2; 1196 1197 diff1 = (*speedp) - harmony_speeds[i - 1].speed; 1198 diff2 = harmony_speeds[i].speed - (*speedp); 1199 if (diff1 < diff2) 1200 selected = i - 1; 1201 else 1202 selected = i; 1203 } 1204 } 1205 } 1206 1207 if (selected == -1) 1208 selected = 2; 1209 1210 *speedp = harmony_speeds[selected].speed; 1211 return (harmony_speeds[selected].bits); 1212} 1213 1214int 1215harmony_set_gainctl(struct harmony_softc *sc) 1216{ 1217 u_int32_t bits, mask, val, old; 1218 1219 /* XXX leave these bits alone or the chip will not come out of CNTL */ 1220 bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; 1221 1222 /* input level */ 1223 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) << 1224 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M; 1225 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) << 1226 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 1227 1228 /* output level (inverted) */ 1229 mask = (1 << GAINCTL_OUTPUT_BITS) - 1; 1230 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS)); 1231 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M; 1232 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS)); 1233 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 1234 1235 /* monitor level (inverted) */ 1236 mask = (1 << GAINCTL_MONITOR_BITS) - 1; 1237 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS)); 1238 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M; 1239 1240 /* XXX messing with these causes CNTL_C to get stuck... grr. */ 1241 bits &= ~GAINCTL_IS_MASK; 1242 if (sc->sc_in_port == HARMONY_IN_MIC) 1243 bits |= GAINCTL_IS_LINE; 1244 else 1245 bits |= GAINCTL_IS_MICROPHONE; 1246 1247 /* XXX messing with these causes CNTL_C to get stuck... grr. */ 1248 bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE); 1249 if (sc->sc_out_port == HARMONY_OUT_LINE) 1250 bits |= GAINCTL_LE; 1251 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER) 1252 bits |= GAINCTL_SE; 1253 else 1254 bits |= GAINCTL_HE; 1255 1256 mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; 1257 old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL); 1258 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits); 1259 if ((old & mask) != (bits & mask)) 1260 return (1); 1261 return (0); 1262} 1263 1264void 1265harmony_try_more(struct harmony_softc *sc) 1266{ 1267 struct harmony_channel *c = &sc->sc_playback; 1268 struct harmony_dma *d = c->c_current; 1269 u_int32_t cur; 1270 int i, nsegs; 1271 1272 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_PCURADD); 1273 cur &= PCURADD_BUFMASK; 1274 nsegs = 0; 1275 1276#ifdef DIAGNOSTIC 1277 if (cur < d->d_map->dm_segs[0].ds_addr || 1278 cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz)) 1279 panic("%s: bad current %x < %lx || %x > %lx", 1280 sc->sc_dv.dv_xname, cur, d->d_map->dm_segs[0].ds_addr, cur, 1281 d->d_map->dm_segs[0].ds_addr + c->c_segsz); 1282#endif /* DIAGNOSTIC */ 1283 1284 if (cur > c->c_theaddr) { 1285 nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE; 1286 } else if (cur < c->c_theaddr) { 1287 nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz - 1288 c->c_theaddr) / HARMONY_BUFSIZE; 1289 nsegs += (cur - d->d_map->dm_segs[0].ds_addr) / 1290 HARMONY_BUFSIZE; 1291 } 1292 1293 if (nsegs != 0 && c->c_intr != NULL) { 1294 for (i = 0; i < nsegs; i++) 1295 (*c->c_intr)(c->c_intrarg); 1296 c->c_theaddr = cur; 1297 } 1298} 1299 1300struct cfdriver harmony_cd = { 1301 NULL, "harmony", DV_DULL 1302}; 1303 1304struct cfattach harmony_ca = { 1305 sizeof(struct harmony_softc), harmony_match, harmony_attach 1306}; 1307