1 /* $NetBSD: awacs.c,v 1.24 2005/12/11 12:18:03 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: awacs.c,v 1.24 2005/12/11 12:18:03 christos Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/audioio.h> 34 #include <sys/device.h> 35 #include <sys/malloc.h> 36 #include <sys/systm.h> 37 38 #include <dev/auconv.h> 39 #include <dev/audio_if.h> 40 #include <dev/mulaw.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/pio.h> 46 47 #include <dev/ofw/openfirm.h> 48 #include <macppc/dev/dbdma.h> 49 50 #ifdef AWACS_DEBUG 51 # define DPRINTF printf 52 #else 53 # define DPRINTF while (0) printf 54 #endif 55 56 /* sc_flags values */ 57 #define AWACS_CAP_BSWAP 0x0001 58 59 struct awacs_softc { 60 struct device sc_dev; 61 int sc_flags; 62 63 void (*sc_ointr)(void *); /* DMA completion intr handler */ 64 void *sc_oarg; /* arg for sc_ointr() */ 65 int sc_opages; /* # of output pages */ 66 67 void (*sc_iintr)(void *); /* DMA completion intr handler */ 68 void *sc_iarg; /* arg for sc_iintr() */ 69 70 u_int sc_record_source; /* recording source mask */ 71 u_int sc_output_mask; /* output source mask */ 72 73 char *sc_reg; 74 u_int sc_codecctl0; 75 u_int sc_codecctl1; 76 u_int sc_codecctl2; 77 u_int sc_codecctl4; 78 u_int sc_soundctl; 79 80 struct dbdma_regmap *sc_odma; 81 struct dbdma_regmap *sc_idma; 82 struct dbdma_command *sc_odmacmd; 83 struct dbdma_command *sc_idmacmd; 84 85 #define AWACS_NFORMATS 2 86 struct audio_format sc_formats[AWACS_NFORMATS]; 87 }; 88 89 int awacs_match(struct device *, struct cfdata *, void *); 90 void awacs_attach(struct device *, struct device *, void *); 91 int awacs_intr(void *); 92 93 void awacs_close(void *); 94 int awacs_query_encoding(void *, struct audio_encoding *); 95 int awacs_set_params(void *, int, int, audio_params_t *, audio_params_t *, 96 stream_filter_list_t *, stream_filter_list_t *); 97 int awacs_round_blocksize(void *, int, int, const audio_params_t *); 98 int awacs_trigger_output(void *, void *, void *, int, void (*)(void *), 99 void *, const audio_params_t *); 100 int awacs_trigger_input(void *, void *, void *, int, void (*)(void *), 101 void *, const audio_params_t *); 102 int awacs_halt_output(void *); 103 int awacs_halt_input(void *); 104 int awacs_getdev(void *, struct audio_device *); 105 int awacs_set_port(void *, mixer_ctrl_t *); 106 int awacs_get_port(void *, mixer_ctrl_t *); 107 int awacs_query_devinfo(void *, mixer_devinfo_t *); 108 size_t awacs_round_buffersize(void *, int, size_t); 109 paddr_t awacs_mappage(void *, void *, off_t, int); 110 int awacs_get_props(void *); 111 112 static inline u_int awacs_read_reg(struct awacs_softc *, int); 113 static inline void awacs_write_reg(struct awacs_softc *, int, int); 114 void awacs_write_codec(struct awacs_softc *, int); 115 void awacs_set_speaker_volume(struct awacs_softc *, int, int); 116 void awacs_set_ext_volume(struct awacs_softc *, int, int); 117 int awacs_set_rate(struct awacs_softc *, const audio_params_t *); 118 119 CFATTACH_DECL(awacs, sizeof(struct awacs_softc), 120 awacs_match, awacs_attach, NULL, NULL); 121 122 const struct audio_hw_if awacs_hw_if = { 123 NULL, /* open */ 124 awacs_close, 125 NULL, 126 awacs_query_encoding, 127 awacs_set_params, 128 awacs_round_blocksize, 129 NULL, 130 NULL, 131 NULL, 132 NULL, 133 NULL, 134 awacs_halt_output, 135 awacs_halt_input, 136 NULL, 137 awacs_getdev, 138 NULL, 139 awacs_set_port, 140 awacs_get_port, 141 awacs_query_devinfo, 142 NULL, 143 NULL, 144 awacs_round_buffersize, 145 awacs_mappage, 146 awacs_get_props, 147 awacs_trigger_output, 148 awacs_trigger_input, 149 NULL, 150 }; 151 152 struct audio_device awacs_device = { 153 "AWACS", 154 "", 155 "awacs" 156 }; 157 158 #define AWACS_NFORMATS 2 159 #define AWACS_FORMATS_LE 0 160 static const struct audio_format awacs_formats[AWACS_NFORMATS] = { 161 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 162 2, AUFMT_STEREO, 8, {7350, 8820, 11025, 14700, 17640, 22050, 29400, 44100}}, 163 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_BE, 16, 16, 164 2, AUFMT_STEREO, 8, {7350, 8820, 11025, 14700, 17640, 22050, 29400, 44100}}, 165 }; 166 167 /* register offset */ 168 #define AWACS_SOUND_CTRL 0x00 169 #define AWACS_CODEC_CTRL 0x10 170 #define AWACS_CODEC_STATUS 0x20 171 #define AWACS_CLIP_COUNT 0x30 172 #define AWACS_BYTE_SWAP 0x40 173 174 /* sound control */ 175 #define AWACS_INPUT_SUBFRAME0 0x00000001 176 #define AWACS_INPUT_SUBFRAME1 0x00000002 177 #define AWACS_INPUT_SUBFRAME2 0x00000004 178 #define AWACS_INPUT_SUBFRAME3 0x00000008 179 180 #define AWACS_OUTPUT_SUBFRAME0 0x00000010 181 #define AWACS_OUTPUT_SUBFRAME1 0x00000020 182 #define AWACS_OUTPUT_SUBFRAME2 0x00000040 183 #define AWACS_OUTPUT_SUBFRAME3 0x00000080 184 185 #define AWACS_RATE_44100 0x00000000 186 #define AWACS_RATE_29400 0x00000100 187 #define AWACS_RATE_22050 0x00000200 188 #define AWACS_RATE_17640 0x00000300 189 #define AWACS_RATE_14700 0x00000400 190 #define AWACS_RATE_11025 0x00000500 191 #define AWACS_RATE_8820 0x00000600 192 #define AWACS_RATE_7350 0x00000700 193 #define AWACS_RATE_MASK 0x00000700 194 195 /* codec control */ 196 #define AWACS_CODEC_ADDR0 0x00000000 197 #define AWACS_CODEC_ADDR1 0x00001000 198 #define AWACS_CODEC_ADDR2 0x00002000 199 #define AWACS_CODEC_ADDR4 0x00004000 200 #define AWACS_CODEC_EMSEL0 0x00000000 201 #define AWACS_CODEC_EMSEL1 0x00400000 202 #define AWACS_CODEC_EMSEL2 0x00800000 203 #define AWACS_CODEC_EMSEL4 0x00c00000 204 #define AWACS_CODEC_BUSY 0x01000000 205 206 /* cc0 */ 207 #define AWACS_DEFAULT_CD_GAIN 0x000000bb 208 #define AWACS_INPUT_CD 0x00000200 209 #define AWACS_INPUT_LINE 0x00000400 210 #define AWACS_INPUT_MICROPHONE 0x00000800 211 #define AWACS_INPUT_MASK 0x00000e00 212 213 /* cc1 */ 214 #define AWACS_MUTE_SPEAKER 0x00000080 215 #define AWACS_MUTE_HEADPHONE 0x00000200 216 217 int 218 awacs_match(struct device *parent, struct cfdata *match, void *aux) 219 { 220 struct confargs *ca; 221 222 ca = aux; 223 if (strcmp(ca->ca_name, "i2s") == 0) 224 return 1; 225 226 if (strcmp(ca->ca_name, "awacs") != 0 && 227 strcmp(ca->ca_name, "davbus") != 0) 228 return 0; 229 230 if (ca->ca_nreg < 24 || ca->ca_nintr < 12) 231 return 0; 232 233 return 1; 234 } 235 236 void 237 awacs_attach(struct device *parent, struct device *self, void *aux) 238 { 239 struct awacs_softc *sc; 240 struct confargs *ca; 241 int cirq, oirq, iirq, cirq_type, oirq_type, iirq_type; 242 243 sc = (struct awacs_softc *)self; 244 ca = aux; 245 ca->ca_reg[0] += ca->ca_baseaddr; 246 ca->ca_reg[2] += ca->ca_baseaddr; 247 ca->ca_reg[4] += ca->ca_baseaddr; 248 249 sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]); 250 251 sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */ 252 sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */ 253 sc->sc_odmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command)); 254 sc->sc_idmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command)); 255 256 if (strcmp(ca->ca_name, "i2s") == 0) { 257 int node, intr[6]; 258 259 node = OF_child(ca->ca_node); 260 if (node == 0) { 261 printf("no i2s-a child\n"); 262 return; 263 } 264 if (OF_getprop(node, "interrupts", intr, sizeof(intr)) == -1) { 265 printf("no interrupt property\n"); 266 return; 267 } 268 269 cirq = intr[0]; 270 oirq = intr[2]; 271 iirq = intr[4]; 272 cirq_type = intr[1] ? IST_LEVEL : IST_EDGE; 273 oirq_type = intr[3] ? IST_LEVEL : IST_EDGE; 274 iirq_type = intr[5] ? IST_LEVEL : IST_EDGE; 275 } else if (ca->ca_nintr == 24) { 276 cirq = ca->ca_intr[0]; 277 oirq = ca->ca_intr[2]; 278 iirq = ca->ca_intr[4]; 279 cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE; 280 oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE; 281 iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE; 282 } else { 283 cirq = ca->ca_intr[0]; 284 oirq = ca->ca_intr[1]; 285 iirq = ca->ca_intr[2]; 286 cirq_type = oirq_type = iirq_type = IST_LEVEL; 287 } 288 289 intr_establish(cirq, cirq_type, IPL_AUDIO, awacs_intr, sc); 290 intr_establish(oirq, oirq_type, IPL_AUDIO, awacs_intr, sc); 291 /* intr_establish(iirq, iirq_type, IPL_AUDIO, awacs_intr, sc); */ 292 293 printf(": irq %d,%d,%d\n", cirq, oirq, iirq); 294 295 memcpy(&sc->sc_formats, awacs_formats, sizeof(awacs_formats)); 296 /* XXX Uni-North based models don't have byteswap capability. */ 297 if (OF_finddevice("/uni-n") == -1) { 298 sc->sc_flags |= AWACS_CAP_BSWAP; 299 } else { 300 AUFMT_INVALIDATE(&sc->sc_formats[AWACS_FORMATS_LE]); 301 } 302 303 sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 | 304 AWACS_RATE_44100; 305 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 306 307 sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0; 308 sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0; 309 sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0; 310 sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0; 311 312 sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN; 313 awacs_write_codec(sc, sc->sc_codecctl0); 314 315 /* Set initial volume[s] */ 316 awacs_set_speaker_volume(sc, 80, 80); 317 318 /* Set loopback (for CD?) */ 319 /* sc->sc_codecctl1 |= 0x440; */ 320 sc->sc_codecctl1 |= 0x40; 321 awacs_write_codec(sc, sc->sc_codecctl1); 322 323 /* default output to speakers */ 324 sc->sc_output_mask = 1 << 0; 325 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 326 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 327 awacs_write_codec(sc, sc->sc_codecctl1); 328 329 /* default input from CD */ 330 sc->sc_record_source = 1 << 0; 331 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 332 sc->sc_codecctl0 |= AWACS_INPUT_CD; 333 awacs_write_codec(sc, sc->sc_codecctl0); 334 335 /* Enable interrupts and looping mode. */ 336 /* XXX ... */ 337 338 audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev); 339 } 340 341 static inline u_int 342 awacs_read_reg(struct awacs_softc *sc, int reg) 343 { 344 char *addr; 345 346 addr = sc->sc_reg; 347 return in32rb(addr + reg); 348 } 349 350 static inline void 351 awacs_write_reg(struct awacs_softc *sc, int reg, int val) 352 { 353 char *addr; 354 355 addr = sc->sc_reg; 356 out32rb(addr + reg, val); 357 } 358 359 void 360 awacs_write_codec(struct awacs_softc *sc, int value) 361 { 362 363 awacs_write_reg(sc, AWACS_CODEC_CTRL, value); 364 while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY) 365 continue; 366 } 367 368 int 369 awacs_intr(void *v) 370 { 371 struct awacs_softc *sc; 372 struct dbdma_command *cmd; 373 int count; 374 int status; 375 376 sc = v; 377 cmd = sc->sc_odmacmd; 378 count = sc->sc_opages; 379 /* Fill used buffer(s). */ 380 while (count-- > 0) { 381 /* if DBDMA_INT_ALWAYS */ 382 if (in16rb(&cmd->d_command) & 0x30) { /* XXX */ 383 status = in16rb(&cmd->d_status); 384 cmd->d_status = 0; 385 if (status) /* status == 0x8400 */ 386 if (sc->sc_ointr) 387 (*sc->sc_ointr)(sc->sc_oarg); 388 } 389 cmd++; 390 } 391 392 return 1; 393 } 394 395 /* 396 * Close function is called at splaudio(). 397 */ 398 void 399 awacs_close(void *h) 400 { 401 struct awacs_softc *sc; 402 403 sc = h; 404 awacs_halt_output(sc); 405 awacs_halt_input(sc); 406 407 sc->sc_ointr = 0; 408 sc->sc_iintr = 0; 409 } 410 411 int 412 awacs_query_encoding(void *h, struct audio_encoding *ae) 413 { 414 struct awacs_softc *sc; 415 416 sc = h; 417 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 418 419 switch (ae->index) { 420 case 0: 421 strcpy(ae->name, AudioEslinear); 422 ae->encoding = AUDIO_ENCODING_SLINEAR; 423 ae->precision = 16; 424 ae->flags = 0; 425 return 0; 426 case 1: 427 strcpy(ae->name, AudioEslinear_be); 428 ae->encoding = AUDIO_ENCODING_SLINEAR_BE; 429 ae->precision = 16; 430 ae->flags = 0; 431 return 0; 432 case 2: 433 strcpy(ae->name, AudioEslinear_le); 434 ae->encoding = AUDIO_ENCODING_SLINEAR_LE; 435 ae->precision = 16; 436 if (sc->sc_flags & AWACS_CAP_BSWAP) 437 ae->flags = 0; 438 return 0; 439 case 3: 440 strcpy(ae->name, AudioEulinear_be); 441 ae->encoding = AUDIO_ENCODING_ULINEAR_BE; 442 ae->precision = 16; 443 return 0; 444 case 4: 445 strcpy(ae->name, AudioEulinear_le); 446 ae->encoding = AUDIO_ENCODING_ULINEAR_LE; 447 ae->precision = 16; 448 return 0; 449 case 5: 450 strcpy(ae->name, AudioEmulaw); 451 ae->encoding = AUDIO_ENCODING_ULAW; 452 ae->precision = 8; 453 return 0; 454 case 6: 455 strcpy(ae->name, AudioEalaw); 456 ae->encoding = AUDIO_ENCODING_ALAW; 457 ae->precision = 8; 458 return 0; 459 default: 460 return EINVAL; 461 } 462 } 463 464 int 465 awacs_set_params(void *h, int setmode, int usemode, 466 audio_params_t *play, audio_params_t *rec, 467 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 468 { 469 struct awacs_softc *sc; 470 audio_params_t *p; 471 stream_filter_list_t *fil; 472 int mode, i; 473 474 sc = h; 475 p = NULL; 476 /* 477 * This device only has one clock, so make the sample rates match. 478 */ 479 if (play->sample_rate != rec->sample_rate && 480 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 481 if (setmode == AUMODE_PLAY) { 482 rec->sample_rate = play->sample_rate; 483 setmode |= AUMODE_RECORD; 484 } else if (setmode == AUMODE_RECORD) { 485 play->sample_rate = rec->sample_rate; 486 setmode |= AUMODE_PLAY; 487 } else 488 return EINVAL; 489 } 490 491 for (mode = AUMODE_RECORD; mode != -1; 492 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 493 if ((setmode & mode) == 0) 494 continue; 495 496 p = mode == AUMODE_PLAY ? play : rec; 497 fil = mode == AUMODE_PLAY ? pfil : rfil; 498 switch (p->sample_rate) { 499 case 48000: /* aurateconv */ 500 case 44100: 501 case 29400: 502 case 22050: 503 case 17640: 504 case 14700: 505 case 11025: 506 case 8820: 507 case 8000: /* aurateconv */ 508 case 7350: 509 break; 510 default: 511 return EINVAL; 512 } 513 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0); 514 i = auconv_set_converter(sc->sc_formats, AWACS_NFORMATS, 515 mode, p, TRUE, fil); 516 if (i < 0) 517 return EINVAL; 518 if (i == AWACS_FORMATS_LE) 519 awacs_write_reg(sc, AWACS_BYTE_SWAP, 1); 520 if (fil->req_size > 0) 521 p = &fil->filters[0].param; 522 if (awacs_set_rate(sc, p)) 523 return EINVAL; 524 } 525 return 0; 526 } 527 528 int 529 awacs_round_blocksize(void *h, int size, int mode, const audio_params_t *param) 530 { 531 532 if (size < PAGE_SIZE) 533 size = PAGE_SIZE; 534 return size & ~PGOFSET; 535 } 536 537 int 538 awacs_halt_output(void *h) 539 { 540 struct awacs_softc *sc; 541 542 sc = h; 543 dbdma_stop(sc->sc_odma); 544 dbdma_reset(sc->sc_odma); 545 return 0; 546 } 547 548 int 549 awacs_halt_input(void *h) 550 { 551 struct awacs_softc *sc; 552 553 sc = h; 554 dbdma_stop(sc->sc_idma); 555 dbdma_reset(sc->sc_idma); 556 return 0; 557 } 558 559 int 560 awacs_getdev(void *h, struct audio_device *retp) 561 { 562 563 *retp = awacs_device; 564 return 0; 565 } 566 567 enum { 568 AWACS_MONITOR_CLASS, 569 AWACS_OUTPUT_CLASS, 570 AWACS_RECORD_CLASS, 571 AWACS_OUTPUT_SELECT, 572 AWACS_VOL_SPEAKER, 573 AWACS_VOL_HEADPHONE, 574 AWACS_INPUT_SELECT, 575 AWACS_VOL_INPUT, 576 AWACS_ENUM_LAST 577 }; 578 579 int 580 awacs_set_port(void *h, mixer_ctrl_t *mc) 581 { 582 struct awacs_softc *sc; 583 int l, r; 584 585 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type); 586 sc = h; 587 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 588 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 589 590 switch (mc->dev) { 591 case AWACS_OUTPUT_SELECT: 592 /* No change necessary? */ 593 if (mc->un.mask == sc->sc_output_mask) 594 return 0; 595 596 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE; 597 if (mc->un.mask & 1 << 0) 598 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 599 if (mc->un.mask & 1 << 1) 600 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 601 602 awacs_write_codec(sc, sc->sc_codecctl1); 603 sc->sc_output_mask = mc->un.mask; 604 return 0; 605 606 case AWACS_VOL_SPEAKER: 607 awacs_set_speaker_volume(sc, l, r); 608 return 0; 609 610 case AWACS_VOL_HEADPHONE: 611 awacs_set_ext_volume(sc, l, r); 612 return 0; 613 614 case AWACS_INPUT_SELECT: 615 /* no change necessary? */ 616 if (mc->un.mask == sc->sc_record_source) 617 return 0; 618 switch (mc->un.mask) { 619 case 1 << 0: /* CD */ 620 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 621 sc->sc_codecctl0 |= AWACS_INPUT_CD; 622 awacs_write_codec(sc, sc->sc_codecctl0); 623 break; 624 case 1 << 1: /* microphone */ 625 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 626 sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE; 627 awacs_write_codec(sc, sc->sc_codecctl0); 628 break; 629 case 1 << 2: /* line in */ 630 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 631 sc->sc_codecctl0 |= AWACS_INPUT_LINE; 632 awacs_write_codec(sc, sc->sc_codecctl0); 633 break; 634 default: /* invalid argument */ 635 return EINVAL; 636 } 637 sc->sc_record_source = mc->un.mask; 638 return 0; 639 640 case AWACS_VOL_INPUT: 641 sc->sc_codecctl0 &= ~0xff; 642 sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4); 643 awacs_write_codec(sc, sc->sc_codecctl0); 644 return 0; 645 } 646 647 return ENXIO; 648 } 649 650 int 651 awacs_get_port(void *h, mixer_ctrl_t *mc) 652 { 653 struct awacs_softc *sc; 654 int vol, l, r; 655 656 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type); 657 sc = h; 658 switch (mc->dev) { 659 case AWACS_OUTPUT_SELECT: 660 mc->un.mask = sc->sc_output_mask; 661 return 0; 662 663 case AWACS_VOL_SPEAKER: 664 vol = sc->sc_codecctl4; 665 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 666 r = (15 - (vol & 0x0f)) * 16; 667 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 668 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 669 return 0; 670 671 case AWACS_VOL_HEADPHONE: 672 vol = sc->sc_codecctl2; 673 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 674 r = (15 - (vol & 0x0f)) * 16; 675 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 676 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 677 return 0; 678 679 case AWACS_INPUT_SELECT: 680 mc->un.mask = sc->sc_record_source; 681 return 0; 682 683 case AWACS_VOL_INPUT: 684 vol = sc->sc_codecctl0 & 0xff; 685 l = (vol & 0xf0); 686 r = (vol & 0x0f) << 4; 687 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 688 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 689 return 0; 690 691 default: 692 return ENXIO; 693 } 694 695 return 0; 696 } 697 698 int 699 awacs_query_devinfo(void *h, mixer_devinfo_t *dip) 700 { 701 702 DPRINTF("query_devinfo %d\n", dip->index); 703 704 switch (dip->index) { 705 706 case AWACS_OUTPUT_SELECT: 707 dip->mixer_class = AWACS_MONITOR_CLASS; 708 strcpy(dip->label.name, AudioNoutput); 709 dip->type = AUDIO_MIXER_SET; 710 dip->prev = dip->next = AUDIO_MIXER_LAST; 711 dip->un.s.num_mem = 2; 712 strcpy(dip->un.s.member[0].label.name, AudioNspeaker); 713 dip->un.s.member[0].mask = 1 << 0; 714 strcpy(dip->un.s.member[1].label.name, AudioNheadphone); 715 dip->un.s.member[1].mask = 1 << 1; 716 return 0; 717 718 case AWACS_VOL_SPEAKER: 719 dip->mixer_class = AWACS_OUTPUT_CLASS; 720 strcpy(dip->label.name, AudioNspeaker); 721 dip->type = AUDIO_MIXER_VALUE; 722 dip->prev = dip->next = AUDIO_MIXER_LAST; 723 dip->un.v.num_channels = 2; 724 strcpy(dip->un.v.units.name, AudioNvolume); 725 return 0; 726 727 case AWACS_VOL_HEADPHONE: 728 dip->mixer_class = AWACS_OUTPUT_CLASS; 729 strcpy(dip->label.name, AudioNheadphone); 730 dip->type = AUDIO_MIXER_VALUE; 731 dip->prev = dip->next = AUDIO_MIXER_LAST; 732 dip->un.v.num_channels = 2; 733 strcpy(dip->un.v.units.name, AudioNvolume); 734 return 0; 735 736 case AWACS_INPUT_SELECT: 737 dip->mixer_class = AWACS_RECORD_CLASS; 738 strcpy(dip->label.name, AudioNsource); 739 dip->type = AUDIO_MIXER_SET; 740 dip->prev = dip->next = AUDIO_MIXER_LAST; 741 dip->un.s.num_mem = 3; 742 strcpy(dip->un.s.member[0].label.name, AudioNcd); 743 dip->un.s.member[0].mask = 1 << 0; 744 strcpy(dip->un.s.member[1].label.name, AudioNmicrophone); 745 dip->un.s.member[1].mask = 1 << 1; 746 strcpy(dip->un.s.member[2].label.name, AudioNline); 747 dip->un.s.member[2].mask = 1 << 2; 748 return 0; 749 750 case AWACS_VOL_INPUT: 751 dip->mixer_class = AWACS_RECORD_CLASS; 752 strcpy(dip->label.name, AudioNrecord); 753 dip->type = AUDIO_MIXER_VALUE; 754 dip->prev = dip->next = AUDIO_MIXER_LAST; 755 dip->un.v.num_channels = 2; 756 strcpy(dip->un.v.units.name, AudioNvolume); 757 return 0; 758 759 case AWACS_MONITOR_CLASS: 760 dip->mixer_class = AWACS_MONITOR_CLASS; 761 strcpy(dip->label.name, AudioCmonitor); 762 dip->type = AUDIO_MIXER_CLASS; 763 dip->next = dip->prev = AUDIO_MIXER_LAST; 764 return 0; 765 766 case AWACS_OUTPUT_CLASS: 767 dip->mixer_class = AWACS_OUTPUT_CLASS; 768 strcpy(dip->label.name, AudioCoutputs); 769 dip->type = AUDIO_MIXER_CLASS; 770 dip->next = dip->prev = AUDIO_MIXER_LAST; 771 return 0; 772 773 case AWACS_RECORD_CLASS: 774 dip->mixer_class = AWACS_RECORD_CLASS; 775 strcpy(dip->label.name, AudioCrecord); 776 dip->type = AUDIO_MIXER_CLASS; 777 dip->next = dip->prev = AUDIO_MIXER_LAST; 778 return 0; 779 } 780 781 return ENXIO; 782 } 783 784 size_t 785 awacs_round_buffersize(void *h, int dir, size_t size) 786 { 787 788 if (size > 65536) 789 size = 65536; 790 return size; 791 } 792 793 paddr_t 794 awacs_mappage(void *h, void *mem, off_t off, int prot) 795 { 796 797 if (off < 0) 798 return -1; 799 return -1; /* XXX */ 800 } 801 802 int 803 awacs_get_props(void *h) 804 { 805 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */; 806 } 807 808 int 809 awacs_trigger_output(void *h, void *start, void *end, int bsize, 810 void (*intr)(void *), void *arg, 811 const audio_params_t *param) 812 { 813 struct awacs_softc *sc; 814 struct dbdma_command *cmd; 815 vaddr_t va; 816 int i, len, intmode; 817 818 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); 819 sc = h; 820 cmd = sc->sc_odmacmd; 821 sc->sc_ointr = intr; 822 sc->sc_oarg = arg; 823 sc->sc_opages = ((char *)end - (char *)start) / PAGE_SIZE; 824 825 #ifdef DIAGNOSTIC 826 if (sc->sc_opages > 16) 827 panic("awacs_trigger_output"); 828 #endif 829 830 va = (vaddr_t)start; 831 len = 0; 832 for (i = sc->sc_opages; i > 0; i--) { 833 len += PAGE_SIZE; 834 if (len < bsize) 835 intmode = DBDMA_INT_NEVER; 836 else { 837 len = 0; 838 intmode = DBDMA_INT_ALWAYS; 839 } 840 841 DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, PAGE_SIZE, vtophys(va), 842 intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 843 va += PAGE_SIZE; 844 cmd++; 845 } 846 847 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 848 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 849 dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd)); 850 851 dbdma_start(sc->sc_odma, sc->sc_odmacmd); 852 853 return 0; 854 } 855 856 int 857 awacs_trigger_input(void *h, void *start, void *end, int bsize, 858 void (*intr)(void *), void *arg, 859 const audio_params_t *param) 860 { 861 862 printf("awacs_trigger_input called\n"); 863 return 1; 864 } 865 866 void 867 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right) 868 { 869 int lval; 870 int rval; 871 872 lval = 15 - (left & 0xff) / 16; 873 rval = 15 - (right & 0xff) / 16; 874 DPRINTF("speaker_volume %d %d\n", lval, rval); 875 876 sc->sc_codecctl4 &= ~0x3cf; 877 sc->sc_codecctl4 |= (lval << 6) | rval; 878 awacs_write_codec(sc, sc->sc_codecctl4); 879 } 880 881 void 882 awacs_set_ext_volume(struct awacs_softc *sc, int left, int right) 883 { 884 int lval; 885 int rval; 886 887 lval = 15 - (left & 0xff) / 16; 888 rval = 15 - (right & 0xff) / 16; 889 DPRINTF("ext_volume %d %d\n", lval, rval); 890 891 sc->sc_codecctl2 &= ~0x3cf; 892 sc->sc_codecctl2 |= (lval << 6) | rval; 893 awacs_write_codec(sc, sc->sc_codecctl2); 894 } 895 896 int 897 awacs_set_rate(struct awacs_softc *sc, const audio_params_t *p) 898 { 899 int c; 900 901 switch (p->sample_rate) { 902 case 44100: 903 c = AWACS_RATE_44100; 904 break; 905 case 29400: 906 c = AWACS_RATE_29400; 907 break; 908 case 22050: 909 c = AWACS_RATE_22050; 910 break; 911 case 17640: 912 c = AWACS_RATE_17640; 913 break; 914 case 14700: 915 c = AWACS_RATE_14700; 916 break; 917 case 11025: 918 c = AWACS_RATE_11025; 919 break; 920 case 8820: 921 c = AWACS_RATE_8820; 922 break; 923 case 7350: 924 c = AWACS_RATE_7350; 925 break; 926 default: 927 return -1; 928 } 929 930 sc->sc_soundctl &= ~AWACS_RATE_MASK; 931 sc->sc_soundctl |= c; 932 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 933 934 return 0; 935 } 936