1 /* $OpenBSD: awacs.c,v 1.40 2022/10/26 20:19:07 kn Exp $ */ 2 /* $NetBSD: awacs.c,v 1.4 2001/02/26 21:07:51 wiz Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 Tsubai Masanari. 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/audioio.h> 32 #include <sys/device.h> 33 #include <sys/malloc.h> 34 #include <sys/systm.h> 35 36 #include <dev/audio_if.h> 37 38 #include <machine/bus.h> 39 #include <machine/autoconf.h> 40 #include <macppc/dev/dbdma.h> 41 42 #ifdef AWACS_DEBUG 43 # define DPRINTF printf 44 #else 45 # define DPRINTF while (0) printf 46 #endif 47 48 #define AWACS_DMALIST_MAX 32 49 #define AWACS_DMASEG_MAX NBPG 50 51 struct awacs_dma { 52 bus_dmamap_t map; 53 caddr_t addr; 54 bus_dma_segment_t segs[AWACS_DMALIST_MAX]; 55 int nsegs; 56 size_t size; 57 struct awacs_dma *next; 58 }; 59 60 61 struct awacs_softc { 62 struct device sc_dev; 63 64 void (*sc_ointr)(void *); /* dma completion intr handler */ 65 void *sc_oarg; /* arg for sc_ointr() */ 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 bus_dma_tag_t sc_dmat; 81 struct dbdma_regmap *sc_odma; 82 struct dbdma_regmap *sc_idma; 83 struct dbdma_command *sc_odmacmd, *sc_odmap; 84 struct dbdma_command *sc_idmacmd, *sc_idmap; 85 dbdma_t sc_odbdma, sc_idbdma; 86 87 struct awacs_dma *sc_dmas; 88 }; 89 90 int awacs_match(struct device *, void *, void *); 91 void awacs_attach(struct device *, struct device *, void *); 92 int awacs_intr(void *); 93 int awacs_tx_intr(void *); 94 int awacs_rx_intr(void *); 95 96 int awacs_open(void *, int); 97 void awacs_close(void *); 98 int awacs_set_params(void *, int, int, struct audio_params *, 99 struct audio_params *); 100 int awacs_round_blocksize(void *, int); 101 int awacs_trigger_output(void *, void *, void *, int, void (*)(void *), 102 void *, struct audio_params *); 103 int awacs_trigger_input(void *, void *, void *, int, void (*)(void *), 104 void *, struct audio_params *); 105 int awacs_halt_output(void *); 106 int awacs_halt_input(void *); 107 int awacs_set_port(void *, mixer_ctrl_t *); 108 int awacs_get_port(void *, mixer_ctrl_t *); 109 int awacs_query_devinfo(void *, mixer_devinfo_t *); 110 size_t awacs_round_buffersize(void *, int, size_t); 111 void *awacs_allocm(void *, int, size_t, int, int); 112 113 static inline u_int awacs_read_reg(struct awacs_softc *, int); 114 static inline void awacs_write_reg(struct awacs_softc *, int, int); 115 void awacs_write_codec(struct awacs_softc *, int); 116 void awacs_set_speaker_volume(struct awacs_softc *, int, int); 117 void awacs_set_ext_volume(struct awacs_softc *, int, int); 118 void awacs_set_rate(struct awacs_softc *, struct audio_params *); 119 120 const struct cfattach awacs_ca = { 121 sizeof(struct awacs_softc), awacs_match, awacs_attach 122 }; 123 124 struct cfdriver awacs_cd = { 125 NULL, "awacs", DV_DULL 126 }; 127 128 const struct audio_hw_if awacs_hw_if = { 129 .open = awacs_open, 130 .close = awacs_close, 131 .set_params = awacs_set_params, 132 .round_blocksize = awacs_round_blocksize, 133 .halt_output = awacs_halt_output, 134 .halt_input = awacs_halt_input, 135 .set_port = awacs_set_port, 136 .get_port = awacs_get_port, 137 .query_devinfo = awacs_query_devinfo, 138 .allocm = awacs_allocm, 139 .round_buffersize = awacs_round_buffersize, 140 .trigger_output = awacs_trigger_output, 141 .trigger_input = awacs_trigger_input, 142 }; 143 144 /* register offset */ 145 #define AWACS_SOUND_CTRL 0x00 146 #define AWACS_CODEC_CTRL 0x10 147 #define AWACS_CODEC_STATUS 0x20 148 #define AWACS_CLIP_COUNT 0x30 149 #define AWACS_BYTE_SWAP 0x40 150 151 /* sound control */ 152 #define AWACS_INPUT_SUBFRAME0 0x00000001 153 #define AWACS_INPUT_SUBFRAME1 0x00000002 154 #define AWACS_INPUT_SUBFRAME2 0x00000004 155 #define AWACS_INPUT_SUBFRAME3 0x00000008 156 157 #define AWACS_OUTPUT_SUBFRAME0 0x00000010 158 #define AWACS_OUTPUT_SUBFRAME1 0x00000020 159 #define AWACS_OUTPUT_SUBFRAME2 0x00000040 160 #define AWACS_OUTPUT_SUBFRAME3 0x00000080 161 162 #define AWACS_RATE_44100 0x00000000 163 #define AWACS_RATE_29400 0x00000100 164 #define AWACS_RATE_22050 0x00000200 165 #define AWACS_RATE_17640 0x00000300 166 #define AWACS_RATE_14700 0x00000400 167 #define AWACS_RATE_11025 0x00000500 168 #define AWACS_RATE_8820 0x00000600 169 #define AWACS_RATE_7350 0x00000700 170 #define AWACS_RATE_MASK 0x00000700 171 172 #define AWACS_CTL_CNTRLERR (1 << 11) 173 #define AWACS_CTL_PORTCHG (1 << 12) 174 #define AWACS_INT_CNTRLERR (1 << 13) 175 #define AWACS_INT_PORTCHG (1 << 14) 176 177 /* codec control */ 178 #define AWACS_CODEC_ADDR0 0x00000000 179 #define AWACS_CODEC_ADDR1 0x00001000 180 #define AWACS_CODEC_ADDR2 0x00002000 181 #define AWACS_CODEC_ADDR4 0x00004000 182 #define AWACS_CODEC_EMSEL0 0x00000000 183 #define AWACS_CODEC_EMSEL1 0x00400000 184 #define AWACS_CODEC_EMSEL2 0x00800000 185 #define AWACS_CODEC_EMSEL4 0x00c00000 186 #define AWACS_CODEC_BUSY 0x01000000 187 188 /* cc0 */ 189 #define AWACS_DEFAULT_CD_GAIN 0x000000bb 190 #define AWACS_INPUT_CD 0x00000200 191 #define AWACS_INPUT_LINE 0x00000400 192 #define AWACS_INPUT_MICROPHONE 0x00000800 193 #define AWACS_INPUT_MASK 0x00000e00 194 195 /* cc1 */ 196 #define AWACS_MUTE_SPEAKER 0x00000080 197 #define AWACS_MUTE_HEADPHONE 0x00000200 198 199 const struct awacs_speed_tab { 200 int rate; 201 u_int32_t bits; 202 } awacs_speeds[] = { 203 { 7350, AWACS_RATE_7350 }, 204 { 8820, AWACS_RATE_8820 }, 205 { 11025, AWACS_RATE_11025 }, 206 { 14700, AWACS_RATE_14700 }, 207 { 17640, AWACS_RATE_17640 }, 208 { 22050, AWACS_RATE_22050 }, 209 { 29400, AWACS_RATE_29400 }, 210 { 44100, AWACS_RATE_44100 }, 211 }; 212 213 int 214 awacs_match(struct device *parent, void *match, void *aux) 215 { 216 struct confargs *ca = aux; 217 218 if (strcmp(ca->ca_name, "awacs") != 0 && 219 strcmp(ca->ca_name, "davbus") != 0) 220 return 0; 221 222 #ifdef DEBUG 223 printf("awacs: matched %s nreg %d nintr %d\n", 224 ca->ca_name, ca->ca_nreg, ca->ca_nintr); 225 #endif 226 227 if (ca->ca_nreg < 24 || ca->ca_nintr < 12) 228 return 0; 229 230 /* XXX for now 231 if (ca->ca_nintr > 12) 232 return 0; 233 */ 234 235 return 1; 236 } 237 238 void 239 awacs_attach(struct device *parent, struct device *self, void *aux) 240 { 241 struct awacs_softc *sc = (struct awacs_softc *)self; 242 struct confargs *ca = aux; 243 int cirq, oirq, iirq; 244 int cirq_type, oirq_type, iirq_type; 245 246 ca->ca_reg[0] += ca->ca_baseaddr; 247 ca->ca_reg[2] += ca->ca_baseaddr; 248 ca->ca_reg[4] += ca->ca_baseaddr; 249 250 sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]); 251 252 sc->sc_dmat = ca->ca_dmat; 253 sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */ 254 sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */ 255 sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); 256 sc->sc_odmacmd = sc->sc_odbdma->d_addr; 257 sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); 258 sc->sc_idmacmd = sc->sc_idbdma->d_addr; 259 260 if (ca->ca_nintr == 24) { 261 cirq = ca->ca_intr[0]; 262 oirq = ca->ca_intr[2]; 263 iirq = ca->ca_intr[4]; 264 cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE; 265 oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE; 266 iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE; 267 } else { 268 cirq = ca->ca_intr[0]; 269 oirq = ca->ca_intr[1]; 270 iirq = ca->ca_intr[2]; 271 cirq_type = oirq_type = iirq_type = IST_LEVEL; 272 } 273 mac_intr_establish(parent, cirq, cirq_type, IPL_AUDIO | IPL_MPSAFE, 274 awacs_intr, sc, sc->sc_dev.dv_xname); 275 mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO | IPL_MPSAFE, 276 awacs_tx_intr, sc, sc->sc_dev.dv_xname); 277 mac_intr_establish(parent, iirq, iirq_type, IPL_AUDIO | IPL_MPSAFE, 278 awacs_rx_intr, sc, sc->sc_dev.dv_xname); 279 280 printf(": irq %d,%d,%d", 281 cirq, oirq, iirq); 282 283 sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 | 284 AWACS_RATE_44100 | AWACS_INT_PORTCHG; 285 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 286 287 sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0; 288 sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0; 289 sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0; 290 sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0; 291 292 sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN; 293 awacs_write_codec(sc, sc->sc_codecctl0); 294 295 /* Set initial volume[s] */ 296 awacs_set_speaker_volume(sc, 80, 80); 297 awacs_set_ext_volume(sc, 80, 80); 298 299 /* Set loopback (for CD?) */ 300 /* sc->sc_codecctl1 |= 0x440; */ 301 sc->sc_codecctl1 |= 0x40; 302 awacs_write_codec(sc, sc->sc_codecctl1); 303 304 /* check for headphone present */ 305 if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) { 306 /* default output to speakers */ 307 printf(" headphones"); 308 sc->sc_output_mask = 1 << 1; 309 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 310 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER; 311 awacs_write_codec(sc, sc->sc_codecctl1); 312 } else { 313 /* default output to speakers */ 314 printf(" speaker"); 315 sc->sc_output_mask = 1 << 0; 316 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 317 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 318 awacs_write_codec(sc, sc->sc_codecctl1); 319 } 320 321 /* default input from CD */ 322 sc->sc_record_source = 1 << 0; 323 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 324 sc->sc_codecctl0 |= AWACS_INPUT_CD; 325 awacs_write_codec(sc, sc->sc_codecctl0); 326 327 /* Enable interrupts and looping mode. */ 328 /* XXX ... */ 329 awacs_halt_output(sc); 330 awacs_halt_input(sc); 331 printf("\n"); 332 333 audio_attach_mi(&awacs_hw_if, sc, NULL, &sc->sc_dev); 334 } 335 336 u_int 337 awacs_read_reg(struct awacs_softc *sc, int reg) 338 { 339 char *addr = sc->sc_reg; 340 341 return in32rb(addr + reg); 342 } 343 344 void 345 awacs_write_reg(struct awacs_softc *sc, int reg, int val) 346 { 347 char *addr = sc->sc_reg; 348 349 out32rb(addr + reg, val); 350 } 351 352 void 353 awacs_write_codec(struct awacs_softc *sc, int value) 354 { 355 awacs_write_reg(sc, AWACS_CODEC_CTRL, value); 356 while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY); 357 } 358 359 int 360 awacs_intr(void *v) 361 { 362 int reason; 363 struct awacs_softc *sc = v; 364 365 mtx_enter(&audio_lock); 366 reason = awacs_read_reg(sc, AWACS_SOUND_CTRL); 367 if (reason & AWACS_CTL_CNTRLERR) { 368 /* change outputs ?? */ 369 } 370 if (reason & AWACS_CTL_PORTCHG) { 371 #ifdef DEBUG 372 printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS)); 373 #endif 374 375 if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) { 376 /* default output to speakers */ 377 sc->sc_output_mask = 1 << 1; 378 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 379 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER; 380 awacs_write_codec(sc, sc->sc_codecctl1); 381 } else { 382 /* default output to speakers */ 383 sc->sc_output_mask = 1 << 0; 384 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 385 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 386 awacs_write_codec(sc, sc->sc_codecctl1); 387 } 388 } 389 390 awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */ 391 mtx_leave(&audio_lock); 392 return 1; 393 } 394 395 int 396 awacs_tx_intr(void *v) 397 { 398 struct awacs_softc *sc = v; 399 struct dbdma_command *cmd = sc->sc_odmap; 400 u_int16_t c, status; 401 402 /* if not set we are not running */ 403 if (!cmd) 404 return (0); 405 mtx_enter(&audio_lock); 406 c = in16rb(&cmd->d_command); 407 status = in16rb(&cmd->d_status); 408 409 if (c >> 12 == DBDMA_CMD_OUT_LAST) 410 sc->sc_odmap = sc->sc_odmacmd; 411 else 412 sc->sc_odmap++; 413 414 if (c & (DBDMA_INT_ALWAYS << 4)) { 415 cmd->d_status = 0; 416 if (status) /* status == 0x8400 */ 417 if (sc->sc_ointr) 418 (*sc->sc_ointr)(sc->sc_oarg); 419 } 420 mtx_leave(&audio_lock); 421 return (1); 422 } 423 int 424 awacs_rx_intr(void *v) 425 { 426 struct awacs_softc *sc = v; 427 struct dbdma_command *cmd = sc->sc_idmap; 428 u_int16_t c, status; 429 430 /* if not set we are not running */ 431 if (!cmd) 432 return (0); 433 434 mtx_enter(&audio_lock); 435 c = in16rb(&cmd->d_command); 436 status = in16rb(&cmd->d_status); 437 438 if (c >> 12 == DBDMA_CMD_IN_LAST) 439 sc->sc_idmap = sc->sc_idmacmd; 440 else 441 sc->sc_idmap++; 442 443 if (c & (DBDMA_INT_ALWAYS << 4)) { 444 cmd->d_status = 0; 445 if (status) /* status == 0x8400 */ 446 if (sc->sc_iintr) 447 (*sc->sc_iintr)(sc->sc_iarg); 448 } 449 mtx_leave(&audio_lock); 450 return (1); 451 } 452 453 int 454 awacs_open(void *h, int flags) 455 { 456 return 0; 457 } 458 459 /* 460 * Close function is called at splaudio(). 461 */ 462 void 463 awacs_close(void *h) 464 { 465 struct awacs_softc *sc = h; 466 467 /* XXX: halt_xxx() already called by upper layer */ 468 awacs_halt_output(sc); 469 awacs_halt_input(sc); 470 471 sc->sc_ointr = 0; 472 sc->sc_iintr = 0; 473 } 474 475 int 476 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play, 477 struct audio_params *rec) 478 { 479 struct awacs_softc *sc = h; 480 struct audio_params *p; 481 int mode; 482 483 /* 484 * This device only has one clock, so make the sample rates match. 485 */ 486 if (play->sample_rate != rec->sample_rate && 487 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 488 if (setmode == AUMODE_PLAY) { 489 rec->sample_rate = play->sample_rate; 490 setmode |= AUMODE_RECORD; 491 } else if (setmode == AUMODE_RECORD) { 492 play->sample_rate = rec->sample_rate; 493 setmode |= AUMODE_PLAY; 494 } else 495 return EINVAL; 496 } 497 498 for (mode = AUMODE_RECORD; mode != -1; 499 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 500 if ((setmode & mode) == 0) 501 continue; 502 503 p = mode == AUMODE_PLAY ? play : rec; 504 505 if (p->sample_rate < 4000) 506 p->sample_rate = 4000; 507 if (p->sample_rate > 50000) 508 p->sample_rate = 50000; 509 510 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0); 511 512 p->encoding = AUDIO_ENCODING_SLINEAR_BE; 513 p->precision = 16; 514 p->channels = 2; 515 p->bps = AUDIO_BPS(p->precision); 516 p->msb = 1; 517 } 518 519 /* Set the speed */ 520 awacs_set_rate(sc, p); 521 522 return (0); 523 } 524 525 int 526 awacs_round_blocksize(void *h, int size) 527 { 528 if (size < PAGE_SIZE) 529 size = PAGE_SIZE; 530 return (size + PAGE_SIZE / 2) & ~(PGOFSET); 531 } 532 533 int 534 awacs_halt_output(void *h) 535 { 536 struct awacs_softc *sc = h; 537 538 mtx_enter(&audio_lock); 539 dbdma_stop(sc->sc_odma); 540 dbdma_reset(sc->sc_odma); 541 dbdma_stop(sc->sc_odma); 542 sc->sc_odmap = NULL; 543 mtx_leave(&audio_lock); 544 return 0; 545 } 546 547 int 548 awacs_halt_input(void *h) 549 { 550 struct awacs_softc *sc = h; 551 552 mtx_enter(&audio_lock); 553 dbdma_stop(sc->sc_idma); 554 dbdma_reset(sc->sc_idma); 555 mtx_leave(&audio_lock); 556 return 0; 557 } 558 559 enum { 560 AWACS_OUTPUT_SELECT, 561 AWACS_VOL_SPEAKER, 562 AWACS_VOL_HEADPHONE, 563 AWACS_OUTPUT_CLASS, 564 AWACS_MONITOR_CLASS, 565 AWACS_INPUT_SELECT, 566 AWACS_VOL_INPUT, 567 AWACS_INPUT_CLASS, 568 AWACS_RECORD_CLASS, 569 AWACS_ENUM_LAST 570 }; 571 572 int 573 awacs_set_port(void *h, mixer_ctrl_t *mc) 574 { 575 struct awacs_softc *sc = h; 576 int l, r; 577 578 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type); 579 580 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 581 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 582 583 switch (mc->dev) { 584 case AWACS_OUTPUT_SELECT: 585 /* no change necessary? */ 586 if (mc->un.mask == sc->sc_output_mask) 587 return 0; 588 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE; 589 if (mc->un.mask & 1 << 0) 590 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 591 if (mc->un.mask & 1 << 1) 592 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 593 594 awacs_write_codec(sc, sc->sc_codecctl1); 595 sc->sc_output_mask = mc->un.mask; 596 return 0; 597 598 case AWACS_VOL_SPEAKER: 599 awacs_set_speaker_volume(sc, l, r); 600 return 0; 601 602 case AWACS_VOL_HEADPHONE: 603 awacs_set_ext_volume(sc, l, r); 604 return 0; 605 606 case AWACS_VOL_INPUT: 607 sc->sc_codecctl0 &= ~0xff; 608 sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4); 609 awacs_write_codec(sc, sc->sc_codecctl0); 610 return 0; 611 612 case AWACS_INPUT_SELECT: 613 /* no change necessary? */ 614 if (mc->un.mask == sc->sc_record_source) 615 return 0; 616 switch(mc->un.mask) { 617 case 1<<0: /* CD */ 618 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 619 sc->sc_codecctl0 |= AWACS_INPUT_CD; 620 awacs_write_codec(sc, sc->sc_codecctl0); 621 break; 622 case 1<<1: /* microphone */ 623 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 624 sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE; 625 awacs_write_codec(sc, sc->sc_codecctl0); 626 break; 627 case 1<<2: /* line in */ 628 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 629 sc->sc_codecctl0 |= AWACS_INPUT_LINE; 630 awacs_write_codec(sc, sc->sc_codecctl0); 631 break; 632 default: /* invalid argument */ 633 return -1; 634 } 635 sc->sc_record_source = mc->un.mask; 636 return 0; 637 } 638 639 return ENXIO; 640 } 641 642 int 643 awacs_get_port(void *h, mixer_ctrl_t *mc) 644 { 645 struct awacs_softc *sc = h; 646 int vol, l, r; 647 648 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type); 649 650 switch (mc->dev) { 651 case AWACS_OUTPUT_SELECT: 652 mc->un.mask = sc->sc_output_mask; 653 return 0; 654 655 case AWACS_VOL_SPEAKER: 656 vol = sc->sc_codecctl4; 657 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 658 r = (15 - (vol & 0x0f)) * 16; 659 mc->un.mask = 1 << 0; 660 mc->un.value.num_channels = 2; 661 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 662 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 663 return 0; 664 665 case AWACS_VOL_HEADPHONE: 666 vol = sc->sc_codecctl2; 667 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 668 r = (15 - (vol & 0x0f)) * 16; 669 mc->un.mask = 1 << 1; 670 mc->un.value.num_channels = 2; 671 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 672 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 673 return 0; 674 675 case AWACS_INPUT_SELECT: 676 mc->un.mask = sc->sc_record_source; 677 return 0; 678 679 case AWACS_VOL_INPUT: 680 vol = sc->sc_codecctl0 & 0xff; 681 l = (vol & 0xf0); 682 r = (vol & 0x0f) << 4; 683 mc->un.mask = sc->sc_record_source; 684 mc->un.value.num_channels = 2; 685 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 686 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 687 return 0; 688 689 default: 690 return ENXIO; 691 } 692 693 return 0; 694 } 695 696 int 697 awacs_query_devinfo(void *h, mixer_devinfo_t *dip) 698 { 699 DPRINTF("query_devinfo %d\n", dip->index); 700 701 switch (dip->index) { 702 703 case AWACS_OUTPUT_SELECT: 704 dip->mixer_class = AWACS_OUTPUT_CLASS; 705 strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name); 706 dip->type = AUDIO_MIXER_SET; 707 dip->prev = dip->next = AUDIO_MIXER_LAST; 708 dip->un.s.num_mem = 2; 709 strlcpy(dip->un.s.member[0].label.name, AudioNspeaker, 710 sizeof dip->un.s.member[0].label.name); 711 dip->un.s.member[0].mask = 1 << 0; 712 strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, 713 sizeof dip->un.s.member[0].label.name); 714 dip->un.s.member[1].mask = 1 << 1; 715 return 0; 716 717 case AWACS_VOL_SPEAKER: 718 dip->mixer_class = AWACS_OUTPUT_CLASS; 719 strlcpy(dip->label.name, AudioNspeaker, 720 sizeof dip->label.name); 721 dip->type = AUDIO_MIXER_VALUE; 722 dip->prev = dip->next = AUDIO_MIXER_LAST; 723 dip->un.v.num_channels = 2; 724 strlcpy(dip->un.v.units.name, AudioNvolume, 725 sizeof dip->un.v.units.name); 726 return 0; 727 728 case AWACS_VOL_HEADPHONE: 729 dip->mixer_class = AWACS_OUTPUT_CLASS; 730 strlcpy(dip->label.name, AudioNheadphone, 731 sizeof dip->label.name); 732 dip->type = AUDIO_MIXER_VALUE; 733 dip->prev = dip->next = AUDIO_MIXER_LAST; 734 dip->un.v.num_channels = 2; 735 strlcpy(dip->un.v.units.name, AudioNvolume, 736 sizeof dip->un.v.units.name); 737 return 0; 738 739 case AWACS_INPUT_SELECT: 740 dip->mixer_class = AWACS_RECORD_CLASS; 741 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 742 dip->type = AUDIO_MIXER_SET; 743 dip->prev = dip->next = AUDIO_MIXER_LAST; 744 dip->un.s.num_mem = 3; 745 strlcpy(dip->un.s.member[0].label.name, AudioNcd, 746 sizeof dip->un.s.member[0].label.name); 747 dip->un.s.member[0].mask = 1 << 0; 748 strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone, 749 sizeof dip->un.s.member[1].label.name); 750 dip->un.s.member[1].mask = 1 << 1; 751 strlcpy(dip->un.s.member[2].label.name, AudioNline, 752 sizeof dip->un.s.member[2].label.name); 753 dip->un.s.member[2].mask = 1 << 2; 754 return 0; 755 756 case AWACS_VOL_INPUT: 757 dip->mixer_class = AWACS_RECORD_CLASS; 758 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); 759 dip->type = AUDIO_MIXER_VALUE; 760 dip->prev = dip->next = AUDIO_MIXER_LAST; 761 dip->un.v.num_channels = 2; 762 strlcpy(dip->un.v.units.name, AudioNvolume, 763 sizeof dip->un.v.units.name); 764 return 0; 765 766 case AWACS_MONITOR_CLASS: 767 dip->mixer_class = AWACS_MONITOR_CLASS; 768 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 769 dip->type = AUDIO_MIXER_CLASS; 770 dip->next = dip->prev = AUDIO_MIXER_LAST; 771 return 0; 772 773 case AWACS_OUTPUT_CLASS: 774 dip->mixer_class = AWACS_OUTPUT_CLASS; 775 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 776 dip->type = AUDIO_MIXER_CLASS; 777 dip->next = dip->prev = AUDIO_MIXER_LAST; 778 return 0; 779 780 case AWACS_RECORD_CLASS: 781 dip->mixer_class = AWACS_MONITOR_CLASS; 782 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 783 dip->type = AUDIO_MIXER_CLASS; 784 dip->next = dip->prev = AUDIO_MIXER_LAST; 785 return 0; 786 } 787 788 return ENXIO; 789 } 790 791 size_t 792 awacs_round_buffersize(void *h, int dir, size_t size) 793 { 794 size = (size + PGOFSET) & ~(PGOFSET); 795 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 796 size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX; 797 return (size); 798 } 799 800 void * 801 awacs_allocm(void *h, int dir, size_t size, int type, int flags) 802 { 803 struct awacs_softc *sc = h; 804 struct awacs_dma *p; 805 int error; 806 807 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 808 return (NULL); 809 810 p = malloc(sizeof(*p), type, flags | M_ZERO); 811 if (!p) 812 return (NULL); 813 814 /* convert to the bus.h style, not used otherwise */ 815 if (flags & M_NOWAIT) 816 flags = BUS_DMA_NOWAIT; 817 818 p->size = size; 819 if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs, 820 1, &p->nsegs, flags)) != 0) { 821 printf("%s: unable to allocate dma, error = %d\n", 822 sc->sc_dev.dv_xname, error); 823 free(p, type, sizeof *p); 824 return NULL; 825 } 826 827 if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, 828 &p->addr, flags | BUS_DMA_COHERENT)) != 0) { 829 printf("%s: unable to map dma, error = %d\n", 830 sc->sc_dev.dv_xname, error); 831 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 832 free(p, type, sizeof *p); 833 return NULL; 834 } 835 836 if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1, 837 p->size, 0, flags, &p->map)) != 0) { 838 printf("%s: unable to create dma map, error = %d\n", 839 sc->sc_dev.dv_xname, error); 840 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 841 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 842 free(p, type, sizeof *p); 843 return NULL; 844 } 845 846 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, 847 NULL, flags)) != 0) { 848 printf("%s: unable to load dma map, error = %d\n", 849 sc->sc_dev.dv_xname, error); 850 bus_dmamap_destroy(sc->sc_dmat, p->map); 851 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 852 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 853 free(p, type, sizeof *p); 854 return NULL; 855 } 856 857 p->next = sc->sc_dmas; 858 sc->sc_dmas = p; 859 860 return p->addr; 861 } 862 863 int 864 awacs_trigger_output(void *h, void *start, void *end, int bsize, 865 void (*intr)(void *), void *arg, struct audio_params *param) 866 { 867 struct awacs_softc *sc = h; 868 struct awacs_dma *p; 869 struct dbdma_command *cmd = sc->sc_odmacmd; 870 vaddr_t spa, pa, epa; 871 int c; 872 873 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); 874 875 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 876 if (!p) 877 return -1; 878 879 sc->sc_ointr = intr; 880 sc->sc_oarg = arg; 881 sc->sc_odmap = sc->sc_odmacmd; 882 883 mtx_enter(&audio_lock); 884 spa = p->segs[0].ds_addr; 885 c = DBDMA_CMD_OUT_MORE; 886 for (pa = spa, epa = spa + (end - start); 887 pa < epa; pa += bsize, cmd++) { 888 889 if (pa + bsize == epa) 890 c = DBDMA_CMD_OUT_LAST; 891 892 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 893 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 894 } 895 896 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 897 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 898 dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr); 899 900 dbdma_start(sc->sc_odma, sc->sc_odbdma); 901 902 mtx_leave(&audio_lock); 903 return 0; 904 } 905 906 int 907 awacs_trigger_input(void *h, void *start, void *end, int bsize, 908 void (*intr)(void *), void *arg, struct audio_params *param) 909 { 910 struct awacs_softc *sc = h; 911 struct awacs_dma *p; 912 struct dbdma_command *cmd = sc->sc_idmacmd; 913 vaddr_t spa, pa, epa; 914 int c; 915 916 DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize); 917 918 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 919 if (!p) 920 return -1; 921 922 sc->sc_iintr = intr; 923 sc->sc_iarg = arg; 924 sc->sc_idmap = sc->sc_idmacmd; 925 926 mtx_enter(&audio_lock); 927 spa = p->segs[0].ds_addr; 928 c = DBDMA_CMD_IN_MORE; 929 for (pa = spa, epa = spa + (end - start); 930 pa < epa; pa += bsize, cmd++) { 931 932 if (pa + bsize == epa) 933 c = DBDMA_CMD_IN_LAST; 934 935 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 936 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 937 } 938 939 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 940 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 941 dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr); 942 943 dbdma_start(sc->sc_idma, sc->sc_idbdma); 944 945 mtx_leave(&audio_lock); 946 return 0; 947 } 948 949 void 950 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right) 951 { 952 int lval = 15 - (left & 0xff) / 16; 953 int rval = 15 - (right & 0xff) / 16; 954 955 DPRINTF("speaker_volume %d %d\n", lval, rval); 956 957 sc->sc_codecctl4 &= ~0x3cf; 958 sc->sc_codecctl4 |= (lval << 6) | rval; 959 awacs_write_codec(sc, sc->sc_codecctl4); 960 } 961 962 void 963 awacs_set_ext_volume(struct awacs_softc *sc, int left, int right) 964 { 965 int lval = 15 - (left & 0xff) / 16; 966 int rval = 15 - (right & 0xff) / 16; 967 968 DPRINTF("ext_volume %d %d\n", lval, rval); 969 970 sc->sc_codecctl2 &= ~0x3cf; 971 sc->sc_codecctl2 |= (lval << 6) | rval; 972 awacs_write_codec(sc, sc->sc_codecctl2); 973 } 974 975 void 976 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p) 977 { 978 int selected = -1; 979 size_t n, i; 980 981 n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]); 982 983 if (p->sample_rate < awacs_speeds[0].rate) 984 selected = 0; 985 if (p->sample_rate > awacs_speeds[n - 1].rate) 986 selected = n - 1; 987 988 for (i = 1; selected == -1 && i < n; i++) { 989 if (p->sample_rate == awacs_speeds[i].rate) 990 selected = i; 991 else if (p->sample_rate < awacs_speeds[i].rate) { 992 u_int diff1, diff2; 993 994 diff1 = p->sample_rate - awacs_speeds[i - 1].rate; 995 diff2 = awacs_speeds[i].rate - p->sample_rate; 996 selected = (diff1 < diff2) ? i - 1 : i; 997 } 998 } 999 1000 if (selected == -1) 1001 selected = 0; 1002 1003 sc->sc_soundctl &= ~AWACS_RATE_MASK; 1004 sc->sc_soundctl |= awacs_speeds[selected].bits; 1005 p->sample_rate = awacs_speeds[selected].rate; 1006 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 1007 } 1008