harmony.c revision 1.7
1/* $OpenBSD: harmony.c,v 1.7 2003/01/27 19:16:41 jason 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jason L. Wright 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * Harmony (CS4215/AD1849 LASI) audio interface. 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/errno.h> 41#include <sys/ioctl.h> 42#include <sys/device.h> 43#include <sys/proc.h> 44#include <sys/malloc.h> 45 46#include <sys/audioio.h> 47#include <dev/audio_if.h> 48#include <dev/auconv.h> 49 50#include <machine/cpu.h> 51#include <machine/intr.h> 52#include <machine/iomod.h> 53#include <machine/autoconf.h> 54#include <machine/bus.h> 55 56#include <hppa/dev/cpudevs.h> 57#include <hppa/gsc/gscbusvar.h> 58#include <hppa/gsc/harmonyreg.h> 59 60#define HARMONY_PORT_INPUT_LVL 0 61#define HARMONY_PORT_OUTPUT_LVL 1 62#define HARMONY_PORT_MONITOR_LVL 2 63#define HARMONY_PORT_RECORD_SOURCE 3 64#define HARMONY_PORT_INPUT_CLASS 4 65#define HARMONY_PORT_OUTPUT_CLASS 5 66#define HARMONY_PORT_MONITOR_CLASS 6 67#define HARMONY_PORT_RECORD_CLASS 7 68 69#define HARMONY_IN_MIC 0 70#define HARMONY_IN_LINE 1 71 72#define PLAYBACK_EMPTYS 3 /* playback empty buffers */ 73#define CAPTURE_EMPTYS 3 /* capture empty buffers */ 74#define HARMONY_BUFSIZE 4096 75 76struct harmony_volume { 77 u_char left, right; 78}; 79 80struct harmony_empty { 81 u_int8_t playback[PLAYBACK_EMPTYS][HARMONY_BUFSIZE]; 82 u_int8_t capture[CAPTURE_EMPTYS][HARMONY_BUFSIZE]; 83}; 84 85struct harmony_dma { 86 struct harmony_dma *d_next; 87 bus_dmamap_t d_map; 88 bus_dma_segment_t d_seg; 89 caddr_t d_kva; 90 size_t d_size; 91}; 92 93struct harmony_channel { 94 struct harmony_dma *c_current; 95 bus_size_t c_segsz; 96 bus_size_t c_cnt; 97 bus_size_t c_blksz; 98 bus_addr_t c_lastaddr; 99 void (*c_intr)(void *); 100 void *c_intrarg; 101}; 102 103struct harmony_softc { 104 struct device sc_dv; 105 bus_dma_tag_t sc_dmat; 106 bus_space_tag_t sc_bt; 107 bus_space_handle_t sc_bh; 108 int sc_open; 109 u_int32_t sc_cntlbits; 110 int sc_need_commit; 111 int sc_playback_empty; 112 bus_addr_t sc_playback_paddrs[PLAYBACK_EMPTYS]; 113 int sc_capture_empty; 114 bus_addr_t sc_capture_paddrs[CAPTURE_EMPTYS]; 115 bus_dmamap_t sc_empty_map; 116 bus_dma_segment_t sc_empty_seg; 117 int sc_empty_rseg; 118 struct harmony_empty *sc_empty_kva; 119 struct harmony_dma *sc_dmas; 120 int sc_playing, sc_capturing; 121 struct harmony_channel sc_playback, sc_capture; 122 struct harmony_volume sc_monitor_lvl, sc_input_lvl, sc_output_lvl; 123 int sc_in_port; 124}; 125 126#define READ_REG(sc, reg) \ 127 bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, (reg)) 128#define WRITE_REG(sc, reg, val) \ 129 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg), (val)) 130#define SYNC_REG(sc, reg, flags) \ 131 bus_space_barrier((sc)->sc_bt, (sc)->sc_bh, (reg), sizeof(u_int32_t), \ 132 (flags)) 133 134int harmony_open(void *, int); 135void harmony_close(void *); 136int harmony_query_encoding(void *, struct audio_encoding *); 137int harmony_set_params(void *, int, int, struct audio_params *, 138 struct audio_params *); 139int harmony_round_blocksize(void *, int); 140int harmony_commit_settings(void *); 141int harmony_halt_output(void *); 142int harmony_halt_input(void *); 143int harmony_getdev(void *, struct audio_device *); 144int harmony_set_port(void *, mixer_ctrl_t *); 145int harmony_get_port(void *, mixer_ctrl_t *); 146int harmony_query_devinfo(void *addr, mixer_devinfo_t *); 147void * harmony_allocm(void *, int, size_t, int, int); 148void harmony_freem(void *, void *, int); 149size_t harmony_round_buffersize(void *, int, size_t); 150int harmony_get_props(void *); 151int harmony_trigger_output(void *, void *, void *, int, 152 void (*intr)(void *), void *arg, struct audio_params *); 153int harmony_trigger_input(void *, void *, void *, int, 154 void (*intr)(void *), void *arg, struct audio_params *); 155 156struct audio_hw_if harmony_sa_hw_if = { 157 harmony_open, 158 harmony_close, 159 NULL, 160 harmony_query_encoding, 161 harmony_set_params, 162 harmony_round_blocksize, 163 harmony_commit_settings, 164 NULL, 165 NULL, 166 NULL, 167 NULL, 168 harmony_halt_output, 169 harmony_halt_input, 170 NULL, 171 harmony_getdev, 172 NULL, 173 harmony_set_port, 174 harmony_get_port, 175 harmony_query_devinfo, 176 harmony_allocm, 177 harmony_freem, 178 harmony_round_buffersize, 179 NULL, 180 harmony_get_props, 181 harmony_trigger_output, 182 harmony_trigger_input, 183}; 184 185const struct audio_device harmony_device = { 186 "harmony", 187 "gsc", 188 "lasi", 189}; 190 191int harmony_match(struct device *, void *, void *); 192void harmony_attach(struct device *, struct device *, void *); 193int harmony_intr(void *); 194void harmony_intr_enable(struct harmony_softc *); 195void harmony_intr_disable(struct harmony_softc *); 196u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *); 197void harmony_set_gainctl(struct harmony_softc *); 198void harmony_reset_codec(struct harmony_softc *); 199 200int 201harmony_match(parent, match, aux) 202 struct device *parent; 203 void *match, *aux; 204{ 205 struct gsc_attach_args *ga = aux; 206 207 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) { 208 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 || 209 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB || 210 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB || 211 ga->ga_type.iodc_sv_model == HPPA_FIO_A2) 212 return (1); 213 } 214 return (0); 215} 216 217void 218harmony_attach(parent, self, aux) 219 struct device *parent, *self; 220 void *aux; 221{ 222 struct harmony_softc *sc = (struct harmony_softc *)self; 223 struct gsc_attach_args *ga = aux; 224 int i; 225 226 sc->sc_bt = ga->ga_iot; 227 sc->sc_dmat = ga->ga_dmatag; 228 229 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0, 230 &sc->sc_bh) != 0) { 231 printf(": couldn't map registers\n"); 232 return; 233 } 234 235 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty), 236 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg, 237 BUS_DMA_NOWAIT) != 0) { 238 printf(": couldn't alloc empty memory\n"); 239 return; 240 } 241 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1, 242 sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva, 243 BUS_DMA_NOWAIT) != 0) { 244 printf(": couldn't map empty memory\n"); 245 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 246 sc->sc_empty_rseg); 247 return; 248 } 249 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1, 250 sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT, 251 &sc->sc_empty_map) != 0) { 252 printf(": can't create empty dmamap\n"); 253 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 254 sizeof(struct harmony_empty)); 255 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 256 sc->sc_empty_rseg); 257 return; 258 } 259 if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva, 260 sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) { 261 printf(": can't load empty dmamap\n"); 262 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map); 263 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 264 sizeof(struct harmony_empty)); 265 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 266 sc->sc_empty_rseg); 267 return; 268 } 269 270 sc->sc_playback_empty = 0; 271 for (i = 0; i < PLAYBACK_EMPTYS; i++) 272 sc->sc_playback_paddrs[i] = 273 sc->sc_empty_map->dm_segs[0].ds_addr + 274 offsetof(struct harmony_empty, playback[i][0]); 275 276 sc->sc_capture_empty = 0; 277 for (i = 0; i < CAPTURE_EMPTYS; i++) 278 sc->sc_capture_paddrs[i] = 279 sc->sc_empty_map->dm_segs[0].ds_addr + 280 offsetof(struct harmony_empty, playback[i][0]); 281 282 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 283 offsetof(struct harmony_empty, playback[0][0]), 284 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 285 286 (void)gsc_intr_establish((struct gsc_softc *)parent, 287 IPL_AUDIO, ga->ga_irq, harmony_intr, sc, &sc->sc_dv); 288 289 /* set defaults */ 290 sc->sc_in_port = HARMONY_IN_LINE; 291 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240; 292 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244; 293 sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208; 294 295 /* reset chip, and push default gain controls */ 296 harmony_reset_codec(sc); 297 298 printf("\n"); 299 300 audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv); 301} 302 303void 304harmony_reset_codec(struct harmony_softc *sc) 305{ 306 /* silence */ 307 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M | 308 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M); 309 310 /* start reset */ 311 WRITE_REG(sc, HARMONY_RESET, RESET_RST); 312 313 DELAY(100000); /* wait at least 0.05 sec */ 314 315 harmony_set_gainctl(sc); 316 WRITE_REG(sc, HARMONY_RESET, 0); 317} 318 319/* 320 * interrupt handler 321 */ 322int 323harmony_intr(vsc) 324 void *vsc; 325{ 326 struct harmony_softc *sc = vsc; 327 u_int32_t dstatus; 328 int r = 0; 329 330 harmony_intr_disable(sc); 331 332 dstatus = READ_REG(sc, HARMONY_DSTATUS); 333 334 if (dstatus & DSTATUS_PN) { 335 r = 1; 336 if (sc->sc_playing == 0) { 337 WRITE_REG(sc, HARMONY_PNXTADD, 338 sc->sc_playback_paddrs[sc->sc_playback_empty]); 339 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); 340 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS) 341 sc->sc_playback_empty = 0; 342 } else { 343 struct harmony_channel *c = &sc->sc_playback; 344 struct harmony_dma *d; 345 bus_addr_t nextaddr; 346 bus_size_t togo; 347 348 d = c->c_current; 349 togo = c->c_segsz - c->c_cnt; 350 if (togo == 0) { 351 nextaddr = d->d_map->dm_segs[0].ds_addr; 352 c->c_cnt = togo = c->c_blksz; 353 } else { 354 nextaddr = c->c_lastaddr; 355 if (togo > c->c_blksz) 356 togo = c->c_blksz; 357 c->c_cnt += togo; 358 } 359 360 bus_dmamap_sync(sc->sc_dmat, d->d_map, 361 nextaddr - d->d_map->dm_segs[0].ds_addr, 362 c->c_blksz, BUS_DMASYNC_PREWRITE); 363 364 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); 365 bus_space_barrier(sc->sc_bt, sc->sc_bh, 366 HARMONY_PNXTADD, sizeof(u_int32_t), 367 BUS_SPACE_BARRIER_WRITE); 368 c->c_lastaddr = nextaddr + togo; 369 370 if (c->c_intr != NULL) 371 (*c->c_intr)(c->c_intrarg); 372 } 373 } 374 375 if (dstatus & DSTATUS_RN) { 376 r = 1; 377 if (sc->sc_capturing == 0) { 378 WRITE_REG(sc, HARMONY_RNXTADD, 379 sc->sc_capture_paddrs[sc->sc_capture_empty]); 380 if (++sc->sc_capture_empty == CAPTURE_EMPTYS) 381 sc->sc_capture_empty = 0; 382 } else { 383 struct harmony_channel *c = &sc->sc_capture; 384 struct harmony_dma *d; 385 bus_addr_t nextaddr; 386 bus_size_t togo; 387 388 d = c->c_current; 389 togo = c->c_segsz - c->c_cnt; 390 if (togo == 0) { 391 nextaddr = d->d_map->dm_segs[0].ds_addr; 392 c->c_cnt = togo = c->c_blksz; 393 } else { 394 nextaddr = c->c_lastaddr; 395 if (togo > c->c_blksz) 396 togo = c->c_blksz; 397 c->c_cnt += togo; 398 } 399 400 bus_dmamap_sync(sc->sc_dmat, d->d_map, 401 nextaddr - d->d_map->dm_segs[0].ds_addr, 402 c->c_blksz, BUS_DMASYNC_PREWRITE); 403 404 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr); 405 bus_space_barrier(sc->sc_bt, sc->sc_bh, 406 HARMONY_RNXTADD, sizeof(u_int32_t), 407 BUS_SPACE_BARRIER_WRITE); 408 c->c_lastaddr = nextaddr + togo; 409 410 if (c->c_intr != NULL) 411 (*c->c_intr)(c->c_intrarg); 412 } 413 } 414 415 harmony_intr_enable(sc); 416 417 return (r); 418} 419 420void 421harmony_intr_enable(struct harmony_softc *sc) 422{ 423 WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE); 424 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 425} 426 427void 428harmony_intr_disable(struct harmony_softc *sc) 429{ 430 WRITE_REG(sc, HARMONY_DSTATUS, 0); 431 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 432} 433 434int 435harmony_open(void *vsc, int flags) 436{ 437 struct harmony_softc *sc = vsc; 438 439 if (sc->sc_open) 440 return (EBUSY); 441 sc->sc_open = 1; 442 return (0); 443} 444 445void 446harmony_close(void *vsc) 447{ 448 struct harmony_softc *sc = vsc; 449 450 harmony_halt_input(sc); 451 harmony_halt_output(sc); 452 harmony_intr_disable(sc); 453 sc->sc_open = 0; 454} 455 456int 457harmony_query_encoding(void *vsc, struct audio_encoding *fp) 458{ 459 int err = 0; 460 461 switch (fp->index) { 462 case 0: 463 strcpy(fp->name, AudioEmulaw); 464 fp->encoding = AUDIO_ENCODING_ULAW; 465 fp->precision = 8; 466 fp->flags = 0; 467 break; 468 case 1: 469 strcpy(fp->name, AudioEalaw); 470 fp->encoding = AUDIO_ENCODING_ALAW; 471 fp->precision = 8; 472 fp->flags = 0; 473 break; 474 case 2: 475 strcpy(fp->name, AudioEslinear_be); 476 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 477 fp->precision = 16; 478 fp->flags = 0; 479 break; 480 case 3: 481 strcpy(fp->name, AudioEslinear_le); 482 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 483 fp->precision = 16; 484 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 485 break; 486 case 4: 487 strcpy(fp->name, AudioEulinear_be); 488 fp->encoding = AUDIO_ENCODING_ULINEAR_BE; 489 fp->precision = 16; 490 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 491 break; 492 default: 493 err = EINVAL; 494 } 495 return (err); 496} 497 498int 499harmony_set_params(void *vsc, int setmode, int usemode, 500 struct audio_params *p, struct audio_params *r) 501{ 502 struct harmony_softc *sc = vsc; 503 u_int32_t bits; 504 void (*pswcode)(void *, u_char *, int cnt) = NULL; 505 void (*rswcode)(void *, u_char *, int cnt) = NULL; 506 507 switch (p->encoding) { 508 case AUDIO_ENCODING_ULAW: 509 if (p->precision != 8) 510 return (EINVAL); 511 bits = CNTL_FORMAT_ULAW; 512 break; 513 case AUDIO_ENCODING_ALAW: 514 if (p->precision != 8) 515 return (EINVAL); 516 bits = CNTL_FORMAT_ALAW; 517 break; 518 case AUDIO_ENCODING_SLINEAR_BE: 519 if (p->precision != 16) 520 return (EINVAL); 521 bits = CNTL_FORMAT_SLINEAR16BE; 522 break; 523 524 /* emulated formats */ 525 case AUDIO_ENCODING_SLINEAR_LE: 526 if (p->precision != 16) 527 return (EINVAL); 528 bits = CNTL_FORMAT_SLINEAR16BE; 529 rswcode = pswcode = swap_bytes; 530 break; 531 case AUDIO_ENCODING_ULINEAR_BE: 532 if (p->precision != 16) 533 return (EINVAL); 534 bits = CNTL_FORMAT_SLINEAR16BE; 535 rswcode = pswcode = change_sign16_be; 536 break; 537 default: 538 return (EINVAL); 539 } 540 541 if (p->channels == 1) 542 bits |= CNTL_CHANS_MONO; 543 else if (p->channels == 2) 544 bits |= CNTL_CHANS_STEREO; 545 else 546 return (EINVAL); 547 548 bits |= harmony_speed_bits(sc, &p->sample_rate); 549 p->sw_code = pswcode; 550 r->sw_code = rswcode; 551 sc->sc_cntlbits = bits; 552 sc->sc_need_commit = 1; 553 554 return (0); 555} 556 557int 558harmony_round_blocksize(void *vsc, int blk) 559{ 560 return (HARMONY_BUFSIZE); 561} 562 563int 564harmony_commit_settings(void *vsc) 565{ 566 struct harmony_softc *sc = vsc; 567 u_int32_t reg; 568 u_int8_t quietchar; 569 int i; 570 571 if (sc->sc_need_commit == 0) 572 return (0); 573 574 harmony_intr_disable(sc); 575 576 for (;;) { 577 reg = READ_REG(sc, HARMONY_DSTATUS); 578 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0) 579 break; 580 } 581 582 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M | 583 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M); 584 585 /* set the silence character based on the encoding type */ 586 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 587 offsetof(struct harmony_empty, playback[0][0]), 588 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE); 589 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) { 590 case CNTL_FORMAT_ULAW: 591 quietchar = 0x7f; 592 break; 593 case CNTL_FORMAT_ALAW: 594 quietchar = 0x55; 595 break; 596 case CNTL_FORMAT_SLINEAR16BE: 597 default: 598 quietchar = 0; 599 break; 600 } 601 for (i = 0; i < PLAYBACK_EMPTYS; i++) 602 memset(&sc->sc_empty_kva->playback[i][0], 603 quietchar, HARMONY_BUFSIZE); 604 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 605 offsetof(struct harmony_empty, playback[0][0]), 606 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 607 608 for (;;) { 609 /* Wait for it to come out of control mode */ 610 reg = READ_REG(sc, HARMONY_CNTL); 611 if ((reg & CNTL_C) == 0) 612 break; 613 } 614 615 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL, 616 sc->sc_cntlbits | CNTL_C); 617 618 for (;;) { 619 /* Wait for it to come out of control mode */ 620 reg = READ_REG(sc, HARMONY_CNTL); 621 if ((reg & CNTL_C) == 0) 622 break; 623 } 624 625 harmony_set_gainctl(sc); 626 sc->sc_need_commit = 0; 627 628 if (sc->sc_playing || sc->sc_capturing) 629 harmony_intr_enable(sc); 630 631 return (0); 632} 633 634int 635harmony_halt_output(void *vsc) 636{ 637 struct harmony_softc *sc = vsc; 638 639 sc->sc_playing = 0; 640 return (0); 641} 642 643int 644harmony_halt_input(void *vsc) 645{ 646 struct harmony_softc *sc = vsc; 647 648 sc->sc_capturing = 0; 649 return (0); 650} 651 652int 653harmony_getdev(void *vsc, struct audio_device *retp) 654{ 655 *retp = harmony_device; 656 return (0); 657} 658 659int 660harmony_set_port(void *vsc, mixer_ctrl_t *cp) 661{ 662 struct harmony_softc *sc = vsc; 663 int err = EINVAL; 664 665 switch (cp->dev) { 666 case HARMONY_PORT_INPUT_LVL: 667 if (cp->type != AUDIO_MIXER_VALUE) 668 break; 669 if (cp->un.value.num_channels == 1) 670 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 671 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 672 else if (cp->un.value.num_channels == 2) { 673 sc->sc_input_lvl.left = 674 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 675 sc->sc_input_lvl.right = 676 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 677 } else 678 break; 679 sc->sc_need_commit = 1; 680 err = 0; 681 break; 682 case HARMONY_PORT_OUTPUT_LVL: 683 if (cp->type != AUDIO_MIXER_VALUE) 684 break; 685 if (cp->un.value.num_channels == 1) 686 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 687 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 688 else if (cp->un.value.num_channels == 2) { 689 sc->sc_output_lvl.left = 690 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 691 sc->sc_output_lvl.right = 692 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 693 } else 694 break; 695 sc->sc_need_commit = 1; 696 err = 0; 697 break; 698 case HARMONY_PORT_MONITOR_LVL: 699 if (cp->type != AUDIO_MIXER_VALUE) 700 break; 701 if (cp->un.value.num_channels != 1) 702 break; 703 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right = 704 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 705 sc->sc_need_commit = 1; 706 err = 0; 707 break; 708 case HARMONY_PORT_RECORD_SOURCE: 709 if (cp->type != AUDIO_MIXER_ENUM) 710 break; 711 if (cp->un.ord != HARMONY_IN_LINE && 712 cp->un.ord != HARMONY_IN_MIC) 713 break; 714 sc->sc_in_port = cp->un.ord; 715 err = 0; 716 sc->sc_need_commit = 1; 717 break; 718 } 719 720 return (err); 721} 722 723int 724harmony_get_port(void *vsc, mixer_ctrl_t *cp) 725{ 726 struct harmony_softc *sc = vsc; 727 int err = EINVAL; 728 729 switch (cp->dev) { 730 case HARMONY_PORT_INPUT_LVL: 731 if (cp->type != AUDIO_MIXER_VALUE) 732 break; 733 if (cp->un.value.num_channels == 1) { 734 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 735 sc->sc_input_lvl.left; 736 } else if (cp->un.value.num_channels == 2) { 737 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 738 sc->sc_input_lvl.left; 739 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 740 sc->sc_input_lvl.right; 741 } else 742 break; 743 err = 0; 744 break; 745 case HARMONY_PORT_OUTPUT_LVL: 746 if (cp->type != AUDIO_MIXER_VALUE) 747 break; 748 if (cp->un.value.num_channels == 1) { 749 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 750 sc->sc_output_lvl.left; 751 } else if (cp->un.value.num_channels == 2) { 752 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 753 sc->sc_output_lvl.left; 754 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 755 sc->sc_output_lvl.right; 756 } else 757 break; 758 err = 0; 759 break; 760 case HARMONY_PORT_MONITOR_LVL: 761 if (cp->type != AUDIO_MIXER_VALUE) 762 break; 763 if (cp->un.value.num_channels != 1) 764 break; 765 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 766 sc->sc_monitor_lvl.left; 767 err = 0; 768 break; 769 case HARMONY_PORT_RECORD_SOURCE: 770 if (cp->type != AUDIO_MIXER_ENUM) 771 break; 772 cp->un.ord = sc->sc_in_port; 773 err = 0; 774 break; 775 } 776 return (0); 777} 778 779int 780harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip) 781{ 782 int err = 0; 783 784 switch (dip->index) { 785 case HARMONY_PORT_INPUT_LVL: 786 dip->type = AUDIO_MIXER_VALUE; 787 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 788 dip->prev = dip->next = AUDIO_MIXER_LAST; 789 strcpy(dip->label.name, AudioNinput); 790 dip->un.v.num_channels = 2; 791 strcpy(dip->un.v.units.name, AudioNvolume); 792 break; 793 case HARMONY_PORT_OUTPUT_LVL: 794 dip->type = AUDIO_MIXER_VALUE; 795 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 796 dip->prev = dip->next = AUDIO_MIXER_LAST; 797 strcpy(dip->label.name, AudioNoutput); 798 dip->un.v.num_channels = 2; 799 strcpy(dip->un.v.units.name, AudioNvolume); 800 break; 801 case HARMONY_PORT_MONITOR_LVL: 802 dip->type = AUDIO_MIXER_VALUE; 803 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 804 dip->prev = dip->next = AUDIO_MIXER_LAST; 805 strcpy(dip->label.name, AudioNoutput); 806 dip->un.v.num_channels = 1; 807 strcpy(dip->un.v.units.name, AudioNvolume); 808 break; 809 case HARMONY_PORT_RECORD_SOURCE: 810 dip->type = AUDIO_MIXER_ENUM; 811 dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 812 dip->prev = dip->next = AUDIO_MIXER_LAST; 813 strcpy(dip->label.name, AudioNsource); 814 dip->un.e.num_mem = 2; 815 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 816 dip->un.e.member[0].ord = HARMONY_IN_MIC; 817 strcpy(dip->un.e.member[1].label.name, AudioNline); 818 dip->un.e.member[1].ord = HARMONY_IN_LINE; 819 break; 820 case HARMONY_PORT_INPUT_CLASS: 821 dip->type = AUDIO_MIXER_CLASS; 822 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 823 dip->prev = dip->next = AUDIO_MIXER_LAST; 824 strcpy(dip->label.name, AudioCinputs); 825 break; 826 case HARMONY_PORT_OUTPUT_CLASS: 827 dip->type = AUDIO_MIXER_CLASS; 828 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 829 dip->prev = dip->next = AUDIO_MIXER_LAST; 830 strcpy(dip->label.name, AudioCoutputs); 831 break; 832 case HARMONY_PORT_MONITOR_CLASS: 833 dip->type = AUDIO_MIXER_CLASS; 834 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 835 dip->prev = dip->next = AUDIO_MIXER_LAST; 836 strcpy(dip->label.name, AudioCmonitor); 837 break; 838 case HARMONY_PORT_RECORD_CLASS: 839 dip->type = AUDIO_MIXER_CLASS; 840 dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 841 dip->prev = dip->next = AUDIO_MIXER_LAST; 842 strcpy(dip->label.name, AudioCrecord); 843 break; 844 default: 845 err = ENXIO; 846 break; 847 } 848 849 return (err); 850} 851 852void * 853harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags) 854{ 855 struct harmony_softc *sc = vsc; 856 struct harmony_dma *d; 857 int rseg; 858 859 d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags); 860 if (d == NULL) 861 goto fail; 862 863 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, 864 &d->d_map) != 0) 865 goto fail1; 866 867 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1, 868 &rseg, BUS_DMA_NOWAIT) != 0) 869 goto fail2; 870 871 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva, 872 BUS_DMA_NOWAIT) != 0) 873 goto fail3; 874 875 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL, 876 BUS_DMA_NOWAIT) != 0) 877 goto fail4; 878 879 d->d_next = sc->sc_dmas; 880 sc->sc_dmas = d; 881 d->d_size = size; 882 return (d->d_kva); 883 884fail4: 885 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size); 886fail3: 887 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 888fail2: 889 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 890fail1: 891 free(d, pool); 892fail: 893 return (NULL); 894} 895 896void 897harmony_freem(void *vsc, void *ptr, int pool) 898{ 899 struct harmony_softc *sc = vsc; 900 struct harmony_dma *d, **dd; 901 902 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) { 903 if (d->d_kva != ptr) 904 continue; 905 bus_dmamap_unload(sc->sc_dmat, d->d_map); 906 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size); 907 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 908 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 909 free(d, pool); 910 return; 911 } 912 printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname); 913} 914 915size_t 916harmony_round_buffersize(void *vsc, int direction, size_t size) 917{ 918 return (size & (size_t)(-HARMONY_BUFSIZE)); 919} 920 921int 922harmony_get_props(void *vsc) 923{ 924 return (AUDIO_PROP_FULLDUPLEX); 925} 926 927int 928harmony_trigger_output(void *vsc, void *start, void *end, int blksize, 929 void (*intr)(void *), void *intrarg, struct audio_params *param) 930{ 931 struct harmony_softc *sc = vsc; 932 struct harmony_channel *c = &sc->sc_playback; 933 struct harmony_dma *d; 934 935 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 936 /*EMPTY*/; 937 if (d == NULL) { 938 printf("%s: trigger_output: bad addr: %p\n", 939 sc->sc_dv.dv_xname, start); 940 return (EINVAL); 941 } 942 943 c->c_intr = intr; 944 c->c_intrarg = intrarg; 945 c->c_blksz = blksize; 946 c->c_current = d; 947 c->c_segsz = (caddr_t)end - (caddr_t)start; 948 c->c_cnt = 0; 949 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 950 951 sc->sc_playing = 1; 952 harmony_intr_enable(sc); 953 954 return (0); 955} 956 957int 958harmony_trigger_input(void *vsc, void *start, void *end, int blksize, 959 void (*intr)(void *), void *intrarg, struct audio_params *param) 960{ 961 struct harmony_softc *sc = vsc; 962 struct harmony_channel *c = &sc->sc_capture; 963 struct harmony_dma *d; 964 965 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 966 /*EMPTY*/; 967 if (d == NULL) { 968 printf("%s: trigger_input: bad addr: %p\n", 969 sc->sc_dv.dv_xname, start); 970 return (EINVAL); 971 } 972 973 c->c_intr = intr; 974 c->c_intrarg = intrarg; 975 c->c_blksz = blksize; 976 c->c_current = d; 977 c->c_segsz = (caddr_t)end - (caddr_t)start; 978 c->c_cnt = 0; 979 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 980 981 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_RNXTADD, 982 d->d_map->dm_segs[0].ds_addr); 983 bus_space_barrier(sc->sc_bt, sc->sc_bh, HARMONY_RNXTADD, 984 sizeof(u_int32_t), BUS_SPACE_BARRIER_WRITE); 985 986 sc->sc_capturing = 1; 987 harmony_intr_enable(sc); 988 return (0); 989} 990 991static const struct speed_struct { 992 u_int32_t speed; 993 u_int32_t bits; 994} harmony_speeds[] = { 995 { 5125, CNTL_RATE_5125 }, 996 { 6615, CNTL_RATE_6615 }, 997 { 8000, CNTL_RATE_8000 }, 998 { 9600, CNTL_RATE_9600 }, 999 { 11025, CNTL_RATE_11025 }, 1000 { 16000, CNTL_RATE_16000 }, 1001 { 18900, CNTL_RATE_18900 }, 1002 { 22050, CNTL_RATE_22050 }, 1003 { 27428, CNTL_RATE_27428 }, 1004 { 32000, CNTL_RATE_32000 }, 1005 { 33075, CNTL_RATE_33075 }, 1006 { 37800, CNTL_RATE_37800 }, 1007 { 44100, CNTL_RATE_44100 }, 1008 { 48000, CNTL_RATE_48000 }, 1009}; 1010 1011u_int32_t 1012harmony_speed_bits(struct harmony_softc *sc, u_long *speedp) 1013{ 1014 int i, n, selected = -1; 1015 1016 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]); 1017 1018 if ((*speedp) <= harmony_speeds[0].speed) 1019 selected = 0; 1020 else if ((*speedp) >= harmony_speeds[n - 1].speed) 1021 selected = n - 1; 1022 else { 1023 for (i = 1; selected == -1 && i < n; i++) { 1024 if ((*speedp) == harmony_speeds[i].speed) 1025 selected = i; 1026 else if ((*speedp) < harmony_speeds[i].speed) { 1027 int diff1, diff2; 1028 1029 diff1 = (*speedp) - harmony_speeds[i - 1].speed; 1030 diff2 = harmony_speeds[i].speed - (*speedp); 1031 if (diff1 < diff2) 1032 selected = i - 1; 1033 else 1034 selected = i; 1035 } 1036 } 1037 } 1038 1039 if (selected == -1) 1040 selected = 2; 1041 1042 *speedp = harmony_speeds[selected].speed; 1043 return (harmony_speeds[selected].bits); 1044} 1045 1046void 1047harmony_set_gainctl(struct harmony_softc *sc) 1048{ 1049 /* master (monitor) and playback are inverted */ 1050 u_int32_t bits, mask, val; 1051 1052 /* XXX leave these bits alone or the chip will not come out of CNTL */ 1053 bits = GAINCTL_HE | GAINCTL_LE | GAINCTL_SE | GAINCTL_IS_MASK; 1054 1055 /* input level */ 1056 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) << 1057 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M; 1058 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) << 1059 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 1060 1061 /* output level (inverted) */ 1062 mask = (1 << GAINCTL_OUTPUT_BITS) - 1; 1063 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS)); 1064 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M; 1065 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS)); 1066 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 1067 1068 /* monitor level (inverted) */ 1069 mask = (1 << GAINCTL_MONITOR_BITS) - 1; 1070 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS)); 1071 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M; 1072 1073 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits); 1074} 1075 1076struct cfdriver harmony_cd = { 1077 NULL, "harmony", DV_DULL 1078}; 1079 1080struct cfattach harmony_ca = { 1081 sizeof(struct harmony_softc), harmony_match, harmony_attach 1082}; 1083