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