harmony.c revision 1.3
1/* $OpenBSD: harmony.c,v 1.3 2003/01/26 21:25:39 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#include <sys/param.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 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 55#define HARMONY_NREGS 0x40 56 57#define HARMONY_ID 0x00 58#define HARMONY_RESET 0x04 59#define HARMONY_CNTL 0x08 60#define HARMONY_GAINCTL 0x0c /* gain control */ 61#define HARMONY_PLAYNXT 0x10 /* play next address */ 62#define HARMONY_PLAYCUR 0x14 /* play current address */ 63#define HARMONY_CAPTNXT 0x18 /* capture next address */ 64#define HARMONY_CAPTCUR 0x1c /* capture current address */ 65#define HARMONY_DSTATUS 0x20 /* device status */ 66#define HARMONY_OV 0x24 67#define HARMONY_PIO 0x28 68#define HARMONY_DIAG 0x3c 69 70#define CNTL_INCNTL 0x80000000 71#define CNTL_FORMAT_MASK 0x000000c0 72#define CNTL_FORMAT_SLINEAR16BE 0x00000000 73#define CNTL_FORMAT_ULAW 0x00000040 74#define CNTL_FORMAT_ALAW 0x00000080 75#define CNTL_CHANS_MASK 0x00000020 76#define CNTL_CHANS_MONO 0x00000000 77#define CNTL_CHANS_STEREO 0x00000020 78#define CNTL_RATE_MASK 0x0000001f 79#define CNTL_RATE_5125 0x00000010 80#define CNTL_RATE_6615 0x00000017 81#define CNTL_RATE_8000 0x00000008 82#define CNTL_RATE_9600 0x0000000f 83#define CNTL_RATE_11025 0x00000011 84#define CNTL_RATE_16000 0x00000009 85#define CNTL_RATE_18900 0x00000012 86#define CNTL_RATE_22050 0x00000013 87#define CNTL_RATE_27428 0x0000000a 88#define CNTL_RATE_32000 0x0000000b 89#define CNTL_RATE_33075 0x00000016 90#define CNTL_RATE_37800 0x00000014 91#define CNTL_RATE_44100 0x00000015 92#define CNTL_RATE_48000 0x0000000e 93 94#define GAINCTL_INPUT_LEFT_M 0x0000f000 95#define GAINCTL_INPUT_LEFT_S 12 96#define GAINCTL_INPUT_RIGHT_M 0x000f0000 97#define GAINCTL_INPUT_RIGHT_S 16 98#define GAINCTL_MONITOR_M 0x00f00000 99#define GAINCTL_MONITOR_S 20 100#define GAINCTL_OUTPUT_LEFT_M 0x00000fc0 101#define GAINCTL_OUTPUT_LEFT_S 6 102#define GAINCTL_OUTPUT_RIGHT_M 0x0000003f 103#define GAINCTL_OUTPUT_RIGHT_S 0 104 105#define DSTATUS_INTRENA 0x80000000 106#define DSTATUS_PLAYNXT 0x00000200 107#define DSTATUS_CAPTNXT 0x00000002 108 109#define HARMONY_PORT_INPUT_LVL 0 110#define HARMONY_PORT_OUTPUT_LVL 1 111#define HARMONY_PORT_MONITOR_LVL 2 112#define HARMONY_PORT_INPUT_CLASS 3 113#define HARMONY_PORT_OUTPUT_CLASS 4 114#define HARMONY_PORT_MONITOR_CLASS 5 115 116#define PLAYBACK_EMPTYS 3 /* playback empty buffers */ 117#define CAPTURE_EMPTYS 3 /* capture empty buffers */ 118#define HARMONY_BUFSIZE 4096 119 120struct harmony_empty { 121 u_int8_t playback[PLAYBACK_EMPTYS][HARMONY_BUFSIZE]; 122 u_int8_t capture[CAPTURE_EMPTYS][HARMONY_BUFSIZE]; 123}; 124 125struct harmony_dma { 126 struct harmony_dma *d_next; 127 bus_dmamap_t d_map; 128 bus_dma_segment_t d_seg; 129 caddr_t d_kva; 130 size_t d_size; 131}; 132 133struct harmony_channel { 134 struct harmony_dma *c_current; 135 bus_size_t c_segsz; 136 bus_size_t c_cnt; 137 bus_size_t c_blksz; 138 bus_addr_t c_lastaddr; 139 void (*c_intr)(void *); 140 void *c_intrarg; 141}; 142 143struct harmony_softc { 144 struct device sc_dv; 145 bus_dma_tag_t sc_dmat; 146 bus_space_tag_t sc_bt; 147 bus_space_handle_t sc_bh; 148 int sc_open; 149 u_int32_t sc_gainctl; 150 u_int32_t sc_cntlbits; 151 int sc_need_commit; 152 int sc_playback_empty; 153 bus_addr_t sc_playback_paddrs[PLAYBACK_EMPTYS]; 154 int sc_capture_empty; 155 bus_addr_t sc_capture_paddrs[CAPTURE_EMPTYS]; 156 bus_dmamap_t sc_empty_map; 157 bus_dma_segment_t sc_empty_seg; 158 int sc_empty_rseg; 159 struct harmony_empty *sc_empty_kva; 160 struct harmony_dma *sc_dmas; 161 int sc_playing, sc_capturing, sc_intr_enable; 162 struct harmony_channel sc_playback; 163}; 164 165int harmony_open(void *, int); 166void harmony_close(void *); 167int harmony_query_encoding(void *, struct audio_encoding *); 168int harmony_set_params(void *, int, int, struct audio_params *, 169 struct audio_params *); 170int harmony_round_blocksize(void *, int); 171int harmony_commit_settings(void *); 172int harmony_halt_output(void *); 173int harmony_halt_input(void *); 174int harmony_getdev(void *, struct audio_device *); 175int harmony_set_port(void *, mixer_ctrl_t *); 176int harmony_get_port(void *, mixer_ctrl_t *); 177int harmony_query_devinfo(void *addr, mixer_devinfo_t *); 178void * harmony_allocm(void *, int, size_t, int, int); 179void harmony_freem(void *, void *, int); 180size_t harmony_round_buffersize(void *, int, size_t); 181int harmony_get_props(void *); 182int harmony_trigger_output(void *, void *, void *, int, 183 void (*intr)(void *), void *arg, struct audio_params *); 184int harmony_trigger_input(void *, void *, void *, int, 185 void (*intr)(void *), void *arg, struct audio_params *); 186 187struct audio_hw_if harmony_sa_hw_if = { 188 harmony_open, 189 harmony_close, 190 NULL, 191 harmony_query_encoding, 192 harmony_set_params, 193 harmony_round_blocksize, 194 harmony_commit_settings, 195 NULL, 196 NULL, 197 NULL, 198 NULL, 199 harmony_halt_output, 200 harmony_halt_input, 201 NULL, 202 harmony_getdev, 203 NULL, 204 harmony_set_port, 205 harmony_get_port, 206 harmony_query_devinfo, 207 harmony_allocm, 208 harmony_freem, 209 harmony_round_buffersize, 210 NULL, 211 harmony_get_props, 212 harmony_trigger_output, 213 harmony_trigger_input, 214}; 215 216struct audio_device harmony_device = { 217 "harmony", 218 "gsc", 219 "lasi", 220}; 221 222int harmony_match(struct device *, void *, void *); 223void harmony_attach(struct device *, struct device *, void *); 224int harmony_intr(void *); 225void harmony_intr_enable(struct harmony_softc *); 226void harmony_intr_disable(struct harmony_softc *); 227void harmony_wait(struct harmony_softc *); 228void harmony_set_gainctl(struct harmony_softc *, u_int32_t); 229u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *); 230 231int 232harmony_match(parent, match, aux) 233 struct device *parent; 234 void *match, *aux; 235{ 236 struct gsc_attach_args *ga = aux; 237 238 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) { 239 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 || 240 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB || 241 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB || 242 ga->ga_type.iodc_sv_model == HPPA_FIO_A2) 243 return (1); 244 } 245 return (0); 246} 247 248void 249harmony_attach(parent, self, aux) 250 struct device *parent, *self; 251 void *aux; 252{ 253 struct harmony_softc *sc = (struct harmony_softc *)self; 254 struct gsc_attach_args *ga = aux; 255 int i; 256 257 sc->sc_bt = ga->ga_iot; 258 sc->sc_dmat = ga->ga_dmatag; 259 260 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0, 261 &sc->sc_bh) != 0) { 262 printf(": couldn't map registers\n"); 263 return; 264 } 265 266 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty), 267 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg, 268 BUS_DMA_NOWAIT) != 0) { 269 printf(": couldn't alloc empty memory\n"); 270 return; 271 } 272 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1, 273 sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva, 274 BUS_DMA_NOWAIT) != 0) { 275 printf(": couldn't map empty memory\n"); 276 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 277 sc->sc_empty_rseg); 278 return; 279 } 280 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1, 281 sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT, 282 &sc->sc_empty_map) != 0) { 283 printf(": can't create empty dmamap\n"); 284 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 285 sizeof(struct harmony_empty)); 286 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 287 sc->sc_empty_rseg); 288 return; 289 } 290 if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva, 291 sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) { 292 printf(": can't load empty dmamap\n"); 293 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map); 294 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva, 295 sizeof(struct harmony_empty)); 296 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 297 sc->sc_empty_rseg); 298 return; 299 } 300 301 sc->sc_playback_empty = 0; 302 for (i = 0; i < PLAYBACK_EMPTYS; i++) 303 sc->sc_playback_paddrs[i] = 304 sc->sc_empty_map->dm_segs[0].ds_addr + 305 offsetof(struct harmony_empty, playback[i][0]); 306 307 sc->sc_capture_empty = 0; 308 for (i = 0; i < CAPTURE_EMPTYS; i++) 309 sc->sc_capture_paddrs[i] = 310 sc->sc_empty_map->dm_segs[0].ds_addr + 311 offsetof(struct harmony_empty, playback[i][0]); 312 313 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 314 offsetof(struct harmony_empty, playback[0][0]), 315 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 316 317 (void)gsc_intr_establish((struct gsc_softc *)parent, 318 IPL_AUDIO, ga->ga_irq, harmony_intr, sc, &sc->sc_dv); 319 320 /* set default gains */ 321 sc->sc_gainctl = 322 ((0x2 << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M) | 323 ((0x2 << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M) | 324 ((0xf << GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M) | 325 ((0xf << GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M) | 326 ((0x2 << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M) | 327 0x0f000000; 328 329 printf("\n"); 330 331 audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv); 332} 333 334/* 335 * interrupt handler 336 */ 337int 338harmony_intr(vsc) 339 void *vsc; 340{ 341 struct harmony_softc *sc = vsc; 342 u_int32_t dstatus; 343 int r = 0; 344 345 if (sc->sc_intr_enable == 0) 346 return (0); 347 348 harmony_intr_disable(sc); 349 harmony_wait(sc); 350 351 dstatus = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_DSTATUS) & 352 (DSTATUS_PLAYNXT | DSTATUS_CAPTNXT); 353 354 if (dstatus & DSTATUS_PLAYNXT) { 355 r = 1; 356 if (sc->sc_playing == 0) { 357 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_PLAYNXT, 358 sc->sc_playback_paddrs[sc->sc_playback_empty]); 359 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS) 360 sc->sc_playback_empty = 0; 361 } else { 362 struct harmony_channel *c = &sc->sc_playback; 363 struct harmony_dma *d; 364 bus_addr_t nextaddr; 365 bus_size_t togo; 366 367 d = c->c_current; 368 togo = c->c_segsz - c->c_cnt; 369 if (togo == 0) { 370 nextaddr = d->d_map->dm_segs[0].ds_addr; 371 c->c_cnt = togo = c->c_blksz; 372 } else { 373 nextaddr = c->c_lastaddr; 374 if (togo > c->c_blksz) 375 togo = c->c_blksz; 376 c->c_cnt += togo; 377 } 378 379 bus_dmamap_sync(sc->sc_dmat, d->d_map, 380 nextaddr - d->d_map->dm_segs[0].ds_addr, 381 c->c_blksz, BUS_DMASYNC_PREWRITE); 382 383 bus_space_write_4(sc->sc_bt, sc->sc_bh, 384 HARMONY_PLAYNXT, nextaddr); 385 c->c_lastaddr = nextaddr + togo; 386 387 if (c->c_intr != NULL) 388 (*c->c_intr)(c->c_intrarg); 389 } 390 } 391 392 if (dstatus & DSTATUS_CAPTNXT) { 393 r = 1; 394 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CAPTNXT, 395 sc->sc_capture_paddrs[sc->sc_capture_empty]); 396 if (++sc->sc_capture_empty == CAPTURE_EMPTYS) 397 sc->sc_capture_empty = 0; 398 } 399 400 harmony_intr_enable(sc); 401 402 return (r); 403} 404 405void 406harmony_intr_enable(struct harmony_softc *sc) 407{ 408 harmony_wait(sc); 409 sc->sc_intr_enable = 1; 410 bus_space_write_4(sc->sc_bt, sc->sc_bh, 411 HARMONY_DSTATUS, DSTATUS_INTRENA); 412} 413 414void 415harmony_intr_disable(struct harmony_softc *sc) 416{ 417 harmony_wait(sc); 418 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_DSTATUS, 0); 419 sc->sc_intr_enable = 0; 420} 421 422void 423harmony_wait(struct harmony_softc *sc) 424{ 425 int i = 5000; 426 427 for (i = 5000; i > 0; i++) 428 if (((bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL) 429 & CNTL_INCNTL)) == 0) 430 return; 431 printf("%s: wait timeout\n", sc->sc_dv.dv_xname); 432} 433 434void 435harmony_set_gainctl(struct harmony_softc *sc, u_int32_t gain) 436{ 437 harmony_wait(sc); 438 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, gain); 439} 440 441int 442harmony_open(void *vsc, int flags) 443{ 444 struct harmony_softc *sc = vsc; 445 446 if (sc->sc_open) 447 return (EBUSY); 448 sc->sc_open = 1; 449 450 /* silence */ 451 harmony_set_gainctl(sc, GAINCTL_OUTPUT_LEFT_M | 452 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M); 453 454 /* reset codec */ 455 harmony_wait(sc); 456 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_RESET, 1); 457 DELAY(50000); 458 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_RESET, 0); 459 460 harmony_set_gainctl(sc, sc->sc_gainctl); 461 462 return (0); 463} 464 465void 466harmony_close(void *vsc) 467{ 468 struct harmony_softc *sc = vsc; 469 470 harmony_halt_input(sc); 471 harmony_halt_output(sc); 472 sc->sc_open = 0; 473} 474 475int 476harmony_query_encoding(void *vsc, struct audio_encoding *fp) 477{ 478 int err = 0; 479 480 switch (fp->index) { 481 case 0: 482 strcpy(fp->name, AudioEmulaw); 483 fp->encoding = AUDIO_ENCODING_ULAW; 484 fp->precision = 8; 485 fp->flags = 0; 486 break; 487 case 1: 488 strcpy(fp->name, AudioEalaw); 489 fp->encoding = AUDIO_ENCODING_ALAW; 490 fp->precision = 8; 491 fp->flags = 0; 492 break; 493 case 2: 494 strcpy(fp->name, AudioEslinear_be); 495 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 496 fp->precision = 16; 497 fp->flags = 0; 498 break; 499 case 3: 500 strcpy(fp->name, AudioEslinear_le); 501 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 502 fp->precision = 16; 503 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 504 break; 505 case 4: 506 strcpy(fp->name, AudioEulinear_be); 507 fp->encoding = AUDIO_ENCODING_ULINEAR_BE; 508 fp->precision = 16; 509 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 510 break; 511 default: 512 err = EINVAL; 513 } 514 return (err); 515} 516 517int 518harmony_set_params(void *vsc, int setmode, int usemode, 519 struct audio_params *p, struct audio_params *r) 520{ 521 struct harmony_softc *sc = vsc; 522 u_int32_t bits; 523 void (*pswcode)(void *, u_char *, int cnt) = NULL; 524 void (*rswcode)(void *, u_char *, int cnt) = NULL; 525 526 switch (p->encoding) { 527 case AUDIO_ENCODING_ULAW: 528 if (p->precision != 8) 529 return (EINVAL); 530 bits = CNTL_FORMAT_ULAW; 531 break; 532 case AUDIO_ENCODING_ALAW: 533 if (p->precision != 8) 534 return (EINVAL); 535 bits = CNTL_FORMAT_ALAW; 536 break; 537 case AUDIO_ENCODING_SLINEAR_BE: 538 if (p->precision != 16) 539 return (EINVAL); 540 bits = CNTL_FORMAT_SLINEAR16BE; 541 break; 542 543 /* emulated formats */ 544 case AUDIO_ENCODING_SLINEAR_LE: 545 if (p->precision != 16) 546 return (EINVAL); 547 bits = CNTL_FORMAT_SLINEAR16BE; 548 rswcode = pswcode = swap_bytes; 549 break; 550 case AUDIO_ENCODING_ULINEAR_BE: 551 if (p->precision != 16) 552 return (EINVAL); 553 bits = CNTL_FORMAT_SLINEAR16BE; 554 rswcode = pswcode = change_sign16_be; 555 break; 556 default: 557 return (EINVAL); 558 } 559 560 if (p->channels == 1) 561 bits |= CNTL_CHANS_MONO; 562 else if (p->channels == 2) 563 bits |= CNTL_CHANS_STEREO; 564 else 565 return (EINVAL); 566 567 bits |= harmony_speed_bits(sc, &p->sample_rate); 568 p->sw_code = pswcode; 569 r->sw_code = rswcode; 570 sc->sc_cntlbits = bits; 571 sc->sc_need_commit = 1; 572 573 return (0); 574} 575 576int 577harmony_round_blocksize(void *vsc, int blk) 578{ 579 return (HARMONY_BUFSIZE); 580} 581 582int 583harmony_commit_settings(void *vsc) 584{ 585 struct harmony_softc *sc = vsc; 586 u_int8_t quietchar; 587 int i; 588 589 if (sc->sc_need_commit == 0) 590 return (0); 591 592 harmony_wait(sc); 593 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL, sc->sc_cntlbits); 594 595 /* set the silence character based on the encoding type */ 596 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 597 offsetof(struct harmony_empty, playback[0][0]), 598 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE); 599 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) { 600 case CNTL_FORMAT_ULAW: 601 quietchar = 0x7f; 602 break; 603 case CNTL_FORMAT_ALAW: 604 quietchar = 0x55; 605 break; 606 case CNTL_FORMAT_SLINEAR16BE: 607 default: 608 quietchar = 0; 609 break; 610 } 611 for (i = 0; i < PLAYBACK_EMPTYS; i++) 612 memset(&sc->sc_empty_kva->playback[i][0], 613 quietchar, HARMONY_BUFSIZE); 614 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 615 offsetof(struct harmony_empty, playback[0][0]), 616 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 617 sc->sc_need_commit = 0; 618 619 return (0); 620} 621 622int 623harmony_halt_output(void *vsc) 624{ 625 struct harmony_softc *sc = vsc; 626 627 harmony_intr_disable(sc); 628 sc->sc_playing = 0; 629 return (0); 630} 631 632int 633harmony_halt_input(void *vsc) 634{ 635 struct harmony_softc *sc = vsc; 636 637 harmony_intr_disable(sc); 638 sc->sc_capturing = 0; 639 return (0); 640} 641 642int 643harmony_getdev(void *vsc, struct audio_device *retp) 644{ 645 *retp = harmony_device; 646 return (0); 647} 648 649int 650harmony_set_port(void *vsc, mixer_ctrl_t *cp) 651{ 652 struct harmony_softc *sc = vsc; 653 int err = EINVAL; 654 655 switch (cp->dev) { 656 case HARMONY_PORT_INPUT_LVL: 657 if (cp->type != AUDIO_MIXER_VALUE) 658 break; 659 if (cp->un.value.num_channels == 1) { 660 sc->sc_gainctl &= 661 ~(GAINCTL_INPUT_LEFT_M | GAINCTL_INPUT_RIGHT_M); 662 sc->sc_gainctl |= 663 (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 664 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M; 665 sc->sc_gainctl |= 666 (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 667 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 668 } else if (cp->un.value.num_channels == 2) { 669 sc->sc_gainctl &= 670 ~(GAINCTL_INPUT_LEFT_M | GAINCTL_INPUT_RIGHT_M); 671 sc->sc_gainctl |= 672 (cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] << 673 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 674 sc->sc_gainctl |= 675 (cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] << 676 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 677 } else 678 break; 679 harmony_set_gainctl(sc, sc->sc_gainctl); 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_gainctl &= 687 ~(GAINCTL_OUTPUT_LEFT_M | GAINCTL_OUTPUT_RIGHT_M); 688 sc->sc_gainctl |= 689 (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 690 GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M; 691 sc->sc_gainctl |= 692 (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 693 GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 694 } else if (cp->un.value.num_channels == 2) { 695 sc->sc_gainctl &= 696 ~(GAINCTL_OUTPUT_LEFT_M | GAINCTL_OUTPUT_RIGHT_M); 697 sc->sc_gainctl |= 698 (cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] << 699 GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 700 sc->sc_gainctl |= 701 (cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] << 702 GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 703 } else 704 break; 705 harmony_set_gainctl(sc, sc->sc_gainctl); 706 err = 0; 707 break; 708 case HARMONY_PORT_MONITOR_LVL: 709 if (cp->type != AUDIO_MIXER_VALUE) 710 break; 711 if (cp->un.value.num_channels != 1) 712 break; 713 sc->sc_gainctl &= ~GAINCTL_MONITOR_M; 714 sc->sc_gainctl |= 715 (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 716 GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M; 717 harmony_set_gainctl(sc, sc->sc_gainctl); 718 err = 0; 719 break; 720 } 721 722 return (err); 723} 724 725int 726harmony_get_port(void *vsc, mixer_ctrl_t *cp) 727{ 728 struct harmony_softc *sc = vsc; 729 int err = EINVAL; 730 731 switch (cp->dev) { 732 case HARMONY_PORT_INPUT_LVL: 733 if (cp->type != AUDIO_MIXER_VALUE) 734 break; 735 if (cp->un.value.num_channels == 1) { 736 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 737 (sc->sc_gainctl & GAINCTL_INPUT_LEFT_M) >> 738 GAINCTL_INPUT_LEFT_S; 739 } else if (cp->un.value.num_channels == 2) { 740 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 741 (sc->sc_gainctl & GAINCTL_INPUT_LEFT_M) >> 742 GAINCTL_INPUT_LEFT_S; 743 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 744 (sc->sc_gainctl & GAINCTL_INPUT_RIGHT_M) >> 745 GAINCTL_INPUT_RIGHT_S; 746 } else 747 break; 748 err = 0; 749 break; 750 case HARMONY_PORT_OUTPUT_LVL: 751 if (cp->type != AUDIO_MIXER_VALUE) 752 break; 753 if (cp->un.value.num_channels == 1) { 754 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 755 (sc->sc_gainctl & GAINCTL_OUTPUT_LEFT_M) >> 756 GAINCTL_OUTPUT_LEFT_S; 757 } else if (cp->un.value.num_channels == 2) { 758 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 759 (sc->sc_gainctl & GAINCTL_OUTPUT_LEFT_M) >> 760 GAINCTL_OUTPUT_LEFT_S; 761 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 762 (sc->sc_gainctl & GAINCTL_OUTPUT_RIGHT_M) >> 763 GAINCTL_OUTPUT_RIGHT_S; 764 } else 765 break; 766 err = 0; 767 break; 768 case HARMONY_PORT_MONITOR_LVL: 769 if (cp->type != AUDIO_MIXER_VALUE) 770 break; 771 if (cp->un.value.num_channels != 1) 772 break; 773 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 774 (sc->sc_gainctl & GAINCTL_MONITOR_M) >> 775 GAINCTL_MONITOR_S; 776 err = 0; 777 break; 778 } 779 return (0); 780} 781 782int 783harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip) 784{ 785 int err = 0; 786 787 switch (dip->index) { 788 case HARMONY_PORT_INPUT_LVL: 789 dip->type = AUDIO_MIXER_VALUE; 790 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 791 dip->prev = dip->next = AUDIO_MIXER_LAST; 792 strcpy(dip->label.name, AudioNinput); 793 dip->un.v.num_channels = 2; 794 strcpy(dip->un.v.units.name, AudioNvolume); 795 break; 796 case HARMONY_PORT_OUTPUT_LVL: 797 dip->type = AUDIO_MIXER_VALUE; 798 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 799 dip->prev = dip->next = AUDIO_MIXER_LAST; 800 strcpy(dip->label.name, AudioNoutput); 801 dip->un.v.num_channels = 2; 802 strcpy(dip->un.v.units.name, AudioNvolume); 803 break; 804 case HARMONY_PORT_MONITOR_LVL: 805 dip->type = AUDIO_MIXER_VALUE; 806 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 807 dip->prev = dip->next = AUDIO_MIXER_LAST; 808 strcpy(dip->label.name, AudioNoutput); 809 dip->un.v.num_channels = 1; 810 strcpy(dip->un.v.units.name, AudioNvolume); 811 break; 812 case HARMONY_PORT_INPUT_CLASS: 813 dip->type = AUDIO_MIXER_CLASS; 814 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 815 dip->prev = dip->next = AUDIO_MIXER_LAST; 816 strcpy(dip->label.name, AudioCinputs); 817 break; 818 case HARMONY_PORT_OUTPUT_CLASS: 819 dip->type = AUDIO_MIXER_CLASS; 820 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 821 dip->prev = dip->next = AUDIO_MIXER_LAST; 822 strcpy(dip->label.name, AudioCoutputs); 823 break; 824 case HARMONY_PORT_MONITOR_CLASS: 825 dip->type = AUDIO_MIXER_CLASS; 826 dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 827 dip->prev = dip->next = AUDIO_MIXER_LAST; 828 strcpy(dip->label.name, AudioCmonitor); 829 break; 830 default: 831 err = ENXIO; 832 break; 833 } 834 835 return (err); 836} 837 838void * 839harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags) 840{ 841 struct harmony_softc *sc = vsc; 842 struct harmony_dma *d; 843 int rseg; 844 845 d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags); 846 if (d == NULL) 847 goto fail; 848 849 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, 850 &d->d_map) != 0) 851 goto fail1; 852 853 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1, 854 &rseg, BUS_DMA_NOWAIT) != 0) 855 goto fail2; 856 857 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva, 858 BUS_DMA_NOWAIT) != 0) 859 goto fail3; 860 861 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL, 862 BUS_DMA_NOWAIT) != 0) 863 goto fail4; 864 865 d->d_next = sc->sc_dmas; 866 sc->sc_dmas = d; 867 d->d_size = size; 868 return (d->d_kva); 869 870fail4: 871 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size); 872fail3: 873 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 874fail2: 875 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 876fail1: 877 free(d, pool); 878fail: 879 return (NULL); 880} 881 882void 883harmony_freem(void *vsc, void *ptr, int pool) 884{ 885 struct harmony_softc *sc = vsc; 886 struct harmony_dma *d, **dd; 887 888 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) { 889 if (d->d_kva != ptr) 890 continue; 891 bus_dmamap_unload(sc->sc_dmat, d->d_map); 892 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size); 893 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 894 bus_dmamap_destroy(sc->sc_dmat, d->d_map); 895 free(d, pool); 896 return; 897 } 898 printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname); 899} 900 901size_t 902harmony_round_buffersize(void *vsc, int direction, size_t size) 903{ 904 return (size & (size_t)(-HARMONY_BUFSIZE)); 905} 906 907int 908harmony_get_props(void *vsc) 909{ 910 return (AUDIO_PROP_FULLDUPLEX); 911} 912 913int 914harmony_trigger_output(void *vsc, void *start, void *end, int blksize, 915 void (*intr)(void *), void *intrarg, struct audio_params *param) 916{ 917 struct harmony_softc *sc = vsc; 918 struct harmony_channel *c = &sc->sc_playback; 919 struct harmony_dma *d; 920 bus_size_t n; 921 922 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 923 /*EMPTY*/; 924 if (d == NULL) { 925 printf("%s: trigger_output: bad addr: %p\n", 926 sc->sc_dv.dv_xname, start); 927 return (EINVAL); 928 } 929 930 c->c_intr = intr; 931 c->c_intrarg = intrarg; 932 933 n = (caddr_t)end - (caddr_t)start; 934 935 c->c_blksz = blksize; 936 c->c_current = d; 937 c->c_segsz = n; 938 939 if (n > c->c_blksz) 940 n = c->c_blksz; 941 c->c_cnt = n; 942 943 bus_dmamap_sync(sc->sc_dmat, d->d_map, 0, c->c_blksz, 944 BUS_DMASYNC_PREWRITE); 945 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_PLAYNXT, 946 d->d_map->dm_segs[0].ds_addr); 947 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr + n; 948 949 sc->sc_playing = 1; 950 harmony_intr_enable(sc); 951 return (0); 952} 953 954int 955harmony_trigger_input(void *vsc, void *start, void *end, int blksize, 956 void (*intr)(void *), void *arg, struct audio_params *param) 957{ 958 struct harmony_softc *sc = vsc; 959 960 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CAPTNXT, 961 sc->sc_capture_paddrs[sc->sc_capture_empty]); 962 if (++sc->sc_capture_empty == CAPTURE_EMPTYS) 963 sc->sc_capture_empty = 0; 964 sc->sc_capturing = 1; 965 harmony_intr_enable(sc); 966 return (0); 967} 968 969static const struct speed_struct { 970 u_int32_t speed; 971 u_int32_t bits; 972} harmony_speeds[] = { 973 { 5125, CNTL_RATE_5125 }, 974 { 6615, CNTL_RATE_6615 }, 975 { 8000, CNTL_RATE_8000 }, 976 { 9600, CNTL_RATE_9600 }, 977 { 11025, CNTL_RATE_11025 }, 978 { 16000, CNTL_RATE_16000 }, 979 { 18900, CNTL_RATE_18900 }, 980 { 22050, CNTL_RATE_22050 }, 981 { 27428, CNTL_RATE_27428 }, 982 { 32000, CNTL_RATE_32000 }, 983 { 33075, CNTL_RATE_33075 }, 984 { 37800, CNTL_RATE_37800 }, 985 { 44100, CNTL_RATE_44100 }, 986 { 48000, CNTL_RATE_48000 }, 987}; 988 989u_int32_t 990harmony_speed_bits(struct harmony_softc *sc, u_long *speedp) 991{ 992 int i, n, selected = -1; 993 994 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]); 995 996 if ((*speedp) <= harmony_speeds[0].speed) 997 selected = 0; 998 else if ((*speedp) >= harmony_speeds[n - 1].speed) 999 selected = n - 1; 1000 else { 1001 for (i = 1; selected == -1 && i < n; i++) { 1002 if ((*speedp) == harmony_speeds[i].speed) 1003 selected = i; 1004 else if ((*speedp) < harmony_speeds[i].speed) { 1005 int diff1, diff2; 1006 1007 diff1 = (*speedp) - harmony_speeds[i - 1].speed; 1008 diff2 = harmony_speeds[i].speed - (*speedp); 1009 if (diff1 < diff2) 1010 selected = i - 1; 1011 else 1012 selected = i; 1013 } 1014 } 1015 } 1016 1017 if (selected == -1) 1018 selected = 2; 1019 1020 *speedp = harmony_speeds[selected].speed; 1021 return (harmony_speeds[selected].bits); 1022} 1023 1024struct cfdriver harmony_cd = { 1025 NULL, "harmony", DV_DULL 1026}; 1027 1028struct cfattach harmony_ca = { 1029 sizeof(struct harmony_softc), harmony_match, harmony_attach 1030}; 1031