1 /* $OpenBSD: awacs.c,v 1.29 2014/07/12 18:44:42 tedu 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/auconv.h> 37 #include <dev/audio_if.h> 38 #include <dev/mulaw.h> 39 40 #include <machine/bus.h> 41 #include <machine/autoconf.h> 42 #include <macppc/dev/dbdma.h> 43 44 #ifdef AWACS_DEBUG 45 # define DPRINTF printf 46 #else 47 # define DPRINTF while (0) printf 48 #endif 49 50 #define AWACS_DMALIST_MAX 32 51 #define AWACS_DMASEG_MAX NBPG 52 53 struct awacs_dma { 54 bus_dmamap_t map; 55 caddr_t addr; 56 bus_dma_segment_t segs[AWACS_DMALIST_MAX]; 57 int nsegs; 58 size_t size; 59 struct awacs_dma *next; 60 }; 61 62 63 struct awacs_softc { 64 struct device sc_dev; 65 66 void (*sc_ointr)(void *); /* dma completion intr handler */ 67 void *sc_oarg; /* arg for sc_ointr() */ 68 69 void (*sc_iintr)(void *); /* dma completion intr handler */ 70 void *sc_iarg; /* arg for sc_iintr() */ 71 72 u_int sc_record_source; /* recording source mask */ 73 u_int sc_output_mask; /* output source mask */ 74 75 char *sc_reg; 76 u_int sc_codecctl0; 77 u_int sc_codecctl1; 78 u_int sc_codecctl2; 79 u_int sc_codecctl4; 80 u_int sc_soundctl; 81 82 bus_dma_tag_t sc_dmat; 83 struct dbdma_regmap *sc_odma; 84 struct dbdma_regmap *sc_idma; 85 struct dbdma_command *sc_odmacmd, *sc_odmap; 86 struct dbdma_command *sc_idmacmd, *sc_idmap; 87 dbdma_t sc_odbdma, sc_idbdma; 88 89 struct awacs_dma *sc_dmas; 90 }; 91 92 int awacs_match(struct device *, void *, void *); 93 void awacs_attach(struct device *, struct device *, void *); 94 int awacs_intr(void *); 95 int awacs_tx_intr(void *); 96 int awacs_rx_intr(void *); 97 98 int awacs_open(void *, int); 99 void awacs_close(void *); 100 int awacs_query_encoding(void *, struct audio_encoding *); 101 int awacs_set_params(void *, int, int, struct audio_params *, 102 struct audio_params *); 103 int awacs_round_blocksize(void *, int); 104 int awacs_trigger_output(void *, void *, void *, int, void (*)(void *), 105 void *, struct audio_params *); 106 int awacs_trigger_input(void *, void *, void *, int, void (*)(void *), 107 void *, struct audio_params *); 108 int awacs_halt_output(void *); 109 int awacs_halt_input(void *); 110 int awacs_getdev(void *, struct audio_device *); 111 int awacs_set_port(void *, mixer_ctrl_t *); 112 int awacs_get_port(void *, mixer_ctrl_t *); 113 int awacs_query_devinfo(void *, mixer_devinfo_t *); 114 size_t awacs_round_buffersize(void *, int, size_t); 115 paddr_t awacs_mappage(void *, void *, off_t, int); 116 int awacs_get_props(void *); 117 void *awacs_allocm(void *, int, size_t, int, int); 118 119 static inline u_int awacs_read_reg(struct awacs_softc *, int); 120 static inline void awacs_write_reg(struct awacs_softc *, int, int); 121 void awacs_write_codec(struct awacs_softc *, int); 122 void awacs_set_speaker_volume(struct awacs_softc *, int, int); 123 void awacs_set_ext_volume(struct awacs_softc *, int, int); 124 void awacs_set_rate(struct awacs_softc *, struct audio_params *); 125 126 struct cfattach awacs_ca = { 127 sizeof(struct awacs_softc), awacs_match, awacs_attach 128 }; 129 130 struct cfdriver awacs_cd = { 131 NULL, "awacs", DV_DULL 132 }; 133 134 struct audio_hw_if awacs_hw_if = { 135 awacs_open, 136 awacs_close, 137 NULL, /* drain */ 138 awacs_query_encoding, 139 awacs_set_params, 140 awacs_round_blocksize, 141 NULL, /* commit_setting */ 142 NULL, /* init_output */ 143 NULL, /* init_input */ 144 NULL, /* start_output */ 145 NULL, /* start_input */ 146 awacs_halt_output, 147 awacs_halt_input, 148 NULL, /* speaker_ctl */ 149 awacs_getdev, 150 NULL, /* getfd */ 151 awacs_set_port, 152 awacs_get_port, 153 awacs_query_devinfo, 154 awacs_allocm, /* allocm */ 155 NULL, /* freem */ 156 awacs_round_buffersize, /* round_buffersize */ 157 awacs_mappage, 158 awacs_get_props, 159 awacs_trigger_output, 160 awacs_trigger_input, 161 NULL 162 }; 163 164 struct audio_device awacs_device = { 165 "AWACS", 166 "", 167 "awacs" 168 }; 169 170 /* register offset */ 171 #define AWACS_SOUND_CTRL 0x00 172 #define AWACS_CODEC_CTRL 0x10 173 #define AWACS_CODEC_STATUS 0x20 174 #define AWACS_CLIP_COUNT 0x30 175 #define AWACS_BYTE_SWAP 0x40 176 177 /* sound control */ 178 #define AWACS_INPUT_SUBFRAME0 0x00000001 179 #define AWACS_INPUT_SUBFRAME1 0x00000002 180 #define AWACS_INPUT_SUBFRAME2 0x00000004 181 #define AWACS_INPUT_SUBFRAME3 0x00000008 182 183 #define AWACS_OUTPUT_SUBFRAME0 0x00000010 184 #define AWACS_OUTPUT_SUBFRAME1 0x00000020 185 #define AWACS_OUTPUT_SUBFRAME2 0x00000040 186 #define AWACS_OUTPUT_SUBFRAME3 0x00000080 187 188 #define AWACS_RATE_44100 0x00000000 189 #define AWACS_RATE_29400 0x00000100 190 #define AWACS_RATE_22050 0x00000200 191 #define AWACS_RATE_17640 0x00000300 192 #define AWACS_RATE_14700 0x00000400 193 #define AWACS_RATE_11025 0x00000500 194 #define AWACS_RATE_8820 0x00000600 195 #define AWACS_RATE_7350 0x00000700 196 #define AWACS_RATE_MASK 0x00000700 197 198 #define AWACS_CTL_CNTRLERR (1 << 11) 199 #define AWACS_CTL_PORTCHG (1 << 12) 200 #define AWACS_INT_CNTRLERR (1 << 13) 201 #define AWACS_INT_PORTCHG (1 << 14) 202 203 /* codec control */ 204 #define AWACS_CODEC_ADDR0 0x00000000 205 #define AWACS_CODEC_ADDR1 0x00001000 206 #define AWACS_CODEC_ADDR2 0x00002000 207 #define AWACS_CODEC_ADDR4 0x00004000 208 #define AWACS_CODEC_EMSEL0 0x00000000 209 #define AWACS_CODEC_EMSEL1 0x00400000 210 #define AWACS_CODEC_EMSEL2 0x00800000 211 #define AWACS_CODEC_EMSEL4 0x00c00000 212 #define AWACS_CODEC_BUSY 0x01000000 213 214 /* cc0 */ 215 #define AWACS_DEFAULT_CD_GAIN 0x000000bb 216 #define AWACS_INPUT_CD 0x00000200 217 #define AWACS_INPUT_LINE 0x00000400 218 #define AWACS_INPUT_MICROPHONE 0x00000800 219 #define AWACS_INPUT_MASK 0x00000e00 220 221 /* cc1 */ 222 #define AWACS_MUTE_SPEAKER 0x00000080 223 #define AWACS_MUTE_HEADPHONE 0x00000200 224 225 const struct awacs_speed_tab { 226 int rate; 227 u_int32_t bits; 228 } awacs_speeds[] = { 229 { 7350, AWACS_RATE_7350 }, 230 { 8820, AWACS_RATE_8820 }, 231 { 11025, AWACS_RATE_11025 }, 232 { 14700, AWACS_RATE_14700 }, 233 { 17640, AWACS_RATE_17640 }, 234 { 22050, AWACS_RATE_22050 }, 235 { 29400, AWACS_RATE_29400 }, 236 { 44100, AWACS_RATE_44100 }, 237 }; 238 239 int 240 awacs_match(struct device *parent, void *match, void *aux) 241 { 242 struct confargs *ca = aux; 243 244 if (strcmp(ca->ca_name, "awacs") != 0 && 245 strcmp(ca->ca_name, "davbus") != 0) 246 return 0; 247 248 #ifdef DEBUG 249 printf("awacs: matched %s nreg %d nintr %d\n", 250 ca->ca_name, ca->ca_nreg, ca->ca_nintr); 251 #endif 252 253 if (ca->ca_nreg < 24 || ca->ca_nintr < 12) 254 return 0; 255 256 /* XXX for now 257 if (ca->ca_nintr > 12) 258 return 0; 259 */ 260 261 return 1; 262 } 263 264 void 265 awacs_attach(struct device *parent, struct device *self, void *aux) 266 { 267 struct awacs_softc *sc = (struct awacs_softc *)self; 268 struct confargs *ca = aux; 269 int cirq, oirq, iirq; 270 int cirq_type, oirq_type, iirq_type; 271 272 ca->ca_reg[0] += ca->ca_baseaddr; 273 ca->ca_reg[2] += ca->ca_baseaddr; 274 ca->ca_reg[4] += ca->ca_baseaddr; 275 276 sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]); 277 278 sc->sc_dmat = ca->ca_dmat; 279 sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */ 280 sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */ 281 sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); 282 sc->sc_odmacmd = sc->sc_odbdma->d_addr; 283 sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX); 284 sc->sc_idmacmd = sc->sc_idbdma->d_addr; 285 286 if (ca->ca_nintr == 24) { 287 cirq = ca->ca_intr[0]; 288 oirq = ca->ca_intr[2]; 289 iirq = ca->ca_intr[4]; 290 cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE; 291 oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE; 292 iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE; 293 } else { 294 cirq = ca->ca_intr[0]; 295 oirq = ca->ca_intr[1]; 296 iirq = ca->ca_intr[2]; 297 cirq_type = oirq_type = iirq_type = IST_LEVEL; 298 } 299 mac_intr_establish(parent, cirq, cirq_type, IPL_AUDIO, awacs_intr, 300 sc, sc->sc_dev.dv_xname); 301 mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO, awacs_tx_intr, 302 sc, sc->sc_dev.dv_xname); 303 mac_intr_establish(parent, iirq, iirq_type, IPL_AUDIO, awacs_rx_intr, 304 sc, sc->sc_dev.dv_xname); 305 306 printf(": irq %d,%d,%d", 307 cirq, oirq, iirq); 308 309 sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 | 310 AWACS_RATE_44100 | AWACS_INT_PORTCHG; 311 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 312 313 sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0; 314 sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0; 315 sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0; 316 sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0; 317 318 sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN; 319 awacs_write_codec(sc, sc->sc_codecctl0); 320 321 /* Set initial volume[s] */ 322 awacs_set_speaker_volume(sc, 80, 80); 323 awacs_set_ext_volume(sc, 80, 80); 324 325 /* Set loopback (for CD?) */ 326 /* sc->sc_codecctl1 |= 0x440; */ 327 sc->sc_codecctl1 |= 0x40; 328 awacs_write_codec(sc, sc->sc_codecctl1); 329 330 /* check for headphone present */ 331 if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) { 332 /* default output to speakers */ 333 printf(" headphones"); 334 sc->sc_output_mask = 1 << 1; 335 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 336 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER; 337 awacs_write_codec(sc, sc->sc_codecctl1); 338 } else { 339 /* default output to speakers */ 340 printf(" speaker"); 341 sc->sc_output_mask = 1 << 0; 342 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 343 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 344 awacs_write_codec(sc, sc->sc_codecctl1); 345 } 346 347 /* default input from CD */ 348 sc->sc_record_source = 1 << 0; 349 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 350 sc->sc_codecctl0 |= AWACS_INPUT_CD; 351 awacs_write_codec(sc, sc->sc_codecctl0); 352 353 /* Enable interrupts and looping mode. */ 354 /* XXX ... */ 355 awacs_halt_output(sc); 356 awacs_halt_input(sc); 357 printf("\n"); 358 359 audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev); 360 } 361 362 u_int 363 awacs_read_reg(struct awacs_softc *sc, int reg) 364 { 365 char *addr = sc->sc_reg; 366 367 return in32rb(addr + reg); 368 } 369 370 void 371 awacs_write_reg(struct awacs_softc *sc, int reg, int val) 372 { 373 char *addr = sc->sc_reg; 374 375 out32rb(addr + reg, val); 376 } 377 378 void 379 awacs_write_codec(struct awacs_softc *sc, int value) 380 { 381 awacs_write_reg(sc, AWACS_CODEC_CTRL, value); 382 while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY); 383 } 384 385 int 386 awacs_intr(void *v) 387 { 388 int reason; 389 struct awacs_softc *sc = v; 390 391 mtx_enter(&audio_lock); 392 reason = awacs_read_reg(sc, AWACS_SOUND_CTRL); 393 if (reason & AWACS_CTL_CNTRLERR) { 394 /* change outputs ?? */ 395 } 396 if (reason & AWACS_CTL_PORTCHG) { 397 #ifdef DEBUG 398 printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS)); 399 #endif 400 401 if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) { 402 /* default output to speakers */ 403 sc->sc_output_mask = 1 << 1; 404 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 405 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER; 406 awacs_write_codec(sc, sc->sc_codecctl1); 407 } else { 408 /* default output to speakers */ 409 sc->sc_output_mask = 1 << 0; 410 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 411 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 412 awacs_write_codec(sc, sc->sc_codecctl1); 413 } 414 } 415 416 awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */ 417 mtx_leave(&audio_lock); 418 return 1; 419 } 420 421 int 422 awacs_tx_intr(void *v) 423 { 424 struct awacs_softc *sc = v; 425 struct dbdma_command *cmd = sc->sc_odmap; 426 u_int16_t c, status; 427 428 /* if not set we are not running */ 429 if (!cmd) 430 return (0); 431 mtx_enter(&audio_lock); 432 c = in16rb(&cmd->d_command); 433 status = in16rb(&cmd->d_status); 434 435 if (c >> 12 == DBDMA_CMD_OUT_LAST) 436 sc->sc_odmap = sc->sc_odmacmd; 437 else 438 sc->sc_odmap++; 439 440 if (c & (DBDMA_INT_ALWAYS << 4)) { 441 cmd->d_status = 0; 442 if (status) /* status == 0x8400 */ 443 if (sc->sc_ointr) 444 (*sc->sc_ointr)(sc->sc_oarg); 445 } 446 mtx_leave(&audio_lock); 447 return (1); 448 } 449 int 450 awacs_rx_intr(void *v) 451 { 452 struct awacs_softc *sc = v; 453 struct dbdma_command *cmd = sc->sc_idmap; 454 u_int16_t c, status; 455 456 /* if not set we are not running */ 457 if (!cmd) 458 return (0); 459 460 mtx_enter(&audio_lock); 461 c = in16rb(&cmd->d_command); 462 status = in16rb(&cmd->d_status); 463 464 if (c >> 12 == DBDMA_CMD_IN_LAST) 465 sc->sc_idmap = sc->sc_idmacmd; 466 else 467 sc->sc_idmap++; 468 469 if (c & (DBDMA_INT_ALWAYS << 4)) { 470 cmd->d_status = 0; 471 if (status) /* status == 0x8400 */ 472 if (sc->sc_iintr) 473 (*sc->sc_iintr)(sc->sc_iarg); 474 } 475 mtx_leave(&audio_lock); 476 return (1); 477 } 478 479 int 480 awacs_open(void *h, int flags) 481 { 482 return 0; 483 } 484 485 /* 486 * Close function is called at splaudio(). 487 */ 488 void 489 awacs_close(void *h) 490 { 491 struct awacs_softc *sc = h; 492 493 /* XXX: halt_xxx() already called by upper layer */ 494 awacs_halt_output(sc); 495 awacs_halt_input(sc); 496 497 sc->sc_ointr = 0; 498 sc->sc_iintr = 0; 499 } 500 501 int 502 awacs_query_encoding(void *h, struct audio_encoding *ae) 503 { 504 switch (ae->index) { 505 case 0: 506 strlcpy(ae->name, AudioEslinear, sizeof ae->name); 507 ae->encoding = AUDIO_ENCODING_SLINEAR; 508 ae->precision = 16; 509 ae->flags = 0; 510 break; 511 case 1: 512 strlcpy(ae->name, AudioEslinear_be, sizeof ae->name); 513 ae->encoding = AUDIO_ENCODING_SLINEAR_BE; 514 ae->precision = 16; 515 ae->flags = 0; 516 break; 517 case 2: 518 strlcpy(ae->name, AudioEslinear_le, sizeof ae->name); 519 ae->encoding = AUDIO_ENCODING_SLINEAR_LE; 520 ae->precision = 16; 521 ae->flags = 0; 522 break; 523 case 3: 524 strlcpy(ae->name, AudioEmulaw, sizeof ae->name); 525 ae->encoding = AUDIO_ENCODING_ULAW; 526 ae->precision = 8; 527 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 528 break; 529 case 4: 530 strlcpy(ae->name, AudioEalaw, sizeof ae->name); 531 ae->encoding = AUDIO_ENCODING_ALAW; 532 ae->precision = 8; 533 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 534 break; 535 case 5: 536 strlcpy(ae->name, AudioEulinear, sizeof ae->name); 537 ae->encoding = AUDIO_ENCODING_ULINEAR; 538 ae->precision = 16; 539 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 540 break; 541 case 6: 542 strlcpy(ae->name, AudioEulinear_le, sizeof ae->name); 543 ae->encoding = AUDIO_ENCODING_ULINEAR_LE; 544 ae->precision = 16; 545 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 546 break; 547 case 7: 548 strlcpy(ae->name, AudioEulinear_be, sizeof ae->name); 549 ae->encoding = AUDIO_ENCODING_ULINEAR_BE; 550 ae->precision = 16; 551 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 552 break; 553 default: 554 return (EINVAL); 555 } 556 ae->bps = AUDIO_BPS(ae->precision); 557 ae->msb = 1; 558 559 return (0); 560 } 561 562 int 563 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play, 564 struct audio_params *rec) 565 { 566 struct awacs_softc *sc = h; 567 struct audio_params *p; 568 int mode; 569 570 /* 571 * This device only has one clock, so make the sample rates match. 572 */ 573 if (play->sample_rate != rec->sample_rate && 574 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 575 if (setmode == AUMODE_PLAY) { 576 rec->sample_rate = play->sample_rate; 577 setmode |= AUMODE_RECORD; 578 } else if (setmode == AUMODE_RECORD) { 579 play->sample_rate = rec->sample_rate; 580 setmode |= AUMODE_PLAY; 581 } else 582 return EINVAL; 583 } 584 585 for (mode = AUMODE_RECORD; mode != -1; 586 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 587 if ((setmode & mode) == 0) 588 continue; 589 590 p = mode == AUMODE_PLAY ? play : rec; 591 592 if (p->sample_rate < 4000) 593 p->sample_rate = 4000; 594 if (p->sample_rate > 50000) 595 p->sample_rate = 50000; 596 if (p->precision > 16) 597 p->precision = 16; 598 if (p->channels > 2) 599 p->channels = 2; 600 601 p->factor = 1; 602 p->sw_code = NULL; 603 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0); 604 605 switch (p->encoding) { 606 607 case AUDIO_ENCODING_SLINEAR_LE: 608 if (p->precision != 16) 609 p->precision = 16; 610 if (p->channels == 2) 611 p->sw_code = swap_bytes; 612 else { 613 p->factor = 2; 614 p->sw_code = swap_bytes_mts; 615 } 616 break; 617 case AUDIO_ENCODING_SLINEAR_BE: 618 if (p->precision != 16) 619 p->precision = 16; 620 if (p->channels == 1) { 621 p->factor = 2; 622 p->sw_code = noswap_bytes_mts; 623 } 624 break; 625 case AUDIO_ENCODING_ULINEAR_LE: 626 if (p->precision != 16) 627 p->precision = 16; 628 if (p->channels == 2) 629 p->sw_code = swap_bytes_change_sign16_be; 630 else { 631 p->factor = 2; 632 p->sw_code = swap_bytes_change_sign16_be_mts; 633 } 634 break; 635 case AUDIO_ENCODING_ULINEAR_BE: 636 if (p->precision != 16) 637 p->precision = 16; 638 if (p->channels == 2) 639 p->sw_code = change_sign16_be; 640 else { 641 p->factor = 2; 642 p->sw_code = change_sign16_be_mts; 643 } 644 break; 645 case AUDIO_ENCODING_ULAW: 646 if (mode == AUMODE_PLAY) { 647 p->factor = 2; 648 p->sw_code = mulaw_to_slinear16_be; 649 break; 650 } else 651 break; /* XXX */ 652 return (EINVAL); 653 case AUDIO_ENCODING_ALAW: 654 if (mode == AUMODE_PLAY) { 655 p->factor = 2; 656 p->sw_code = alaw_to_slinear16_be; 657 break; 658 } 659 return (EINVAL); 660 default: 661 return (EINVAL); 662 } 663 p->bps = AUDIO_BPS(p->precision); 664 p->msb = 1; 665 } 666 667 /* Set the speed */ 668 awacs_set_rate(sc, p); 669 670 return (0); 671 } 672 673 int 674 awacs_round_blocksize(void *h, int size) 675 { 676 if (size < PAGE_SIZE) 677 size = PAGE_SIZE; 678 return (size + PAGE_SIZE / 2) & ~(PGOFSET); 679 } 680 681 int 682 awacs_halt_output(void *h) 683 { 684 struct awacs_softc *sc = h; 685 686 mtx_enter(&audio_lock); 687 dbdma_stop(sc->sc_odma); 688 dbdma_reset(sc->sc_odma); 689 dbdma_stop(sc->sc_odma); 690 sc->sc_odmap = NULL; 691 mtx_leave(&audio_lock); 692 return 0; 693 } 694 695 int 696 awacs_halt_input(void *h) 697 { 698 struct awacs_softc *sc = h; 699 700 mtx_enter(&audio_lock); 701 dbdma_stop(sc->sc_idma); 702 dbdma_reset(sc->sc_idma); 703 mtx_leave(&audio_lock); 704 return 0; 705 } 706 707 int 708 awacs_getdev(void *h, struct audio_device *retp) 709 { 710 *retp = awacs_device; 711 return 0; 712 } 713 714 enum { 715 AWACS_OUTPUT_SELECT, 716 AWACS_VOL_SPEAKER, 717 AWACS_VOL_HEADPHONE, 718 AWACS_OUTPUT_CLASS, 719 AWACS_MONITOR_CLASS, 720 AWACS_INPUT_SELECT, 721 AWACS_VOL_INPUT, 722 AWACS_INPUT_CLASS, 723 AWACS_RECORD_CLASS, 724 AWACS_ENUM_LAST 725 }; 726 727 int 728 awacs_set_port(void *h, mixer_ctrl_t *mc) 729 { 730 struct awacs_softc *sc = h; 731 int l, r; 732 733 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type); 734 735 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 736 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 737 738 switch (mc->dev) { 739 case AWACS_OUTPUT_SELECT: 740 /* no change necessary? */ 741 if (mc->un.mask == sc->sc_output_mask) 742 return 0; 743 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE; 744 if (mc->un.mask & 1 << 0) 745 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 746 if (mc->un.mask & 1 << 1) 747 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 748 749 awacs_write_codec(sc, sc->sc_codecctl1); 750 sc->sc_output_mask = mc->un.mask; 751 return 0; 752 753 case AWACS_VOL_SPEAKER: 754 awacs_set_speaker_volume(sc, l, r); 755 return 0; 756 757 case AWACS_VOL_HEADPHONE: 758 awacs_set_ext_volume(sc, l, r); 759 return 0; 760 761 case AWACS_VOL_INPUT: 762 sc->sc_codecctl0 &= ~0xff; 763 sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4); 764 awacs_write_codec(sc, sc->sc_codecctl0); 765 return 0; 766 767 case AWACS_INPUT_SELECT: 768 /* no change necessary? */ 769 if (mc->un.mask == sc->sc_record_source) 770 return 0; 771 switch(mc->un.mask) { 772 case 1<<0: /* CD */ 773 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 774 sc->sc_codecctl0 |= AWACS_INPUT_CD; 775 awacs_write_codec(sc, sc->sc_codecctl0); 776 break; 777 case 1<<1: /* microphone */ 778 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 779 sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE; 780 awacs_write_codec(sc, sc->sc_codecctl0); 781 break; 782 case 1<<2: /* line in */ 783 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 784 sc->sc_codecctl0 |= AWACS_INPUT_LINE; 785 awacs_write_codec(sc, sc->sc_codecctl0); 786 break; 787 default: /* invalid argument */ 788 return -1; 789 } 790 sc->sc_record_source = mc->un.mask; 791 return 0; 792 } 793 794 return ENXIO; 795 } 796 797 int 798 awacs_get_port(void *h, mixer_ctrl_t *mc) 799 { 800 struct awacs_softc *sc = h; 801 int vol, l, r; 802 803 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type); 804 805 switch (mc->dev) { 806 case AWACS_OUTPUT_SELECT: 807 mc->un.mask = sc->sc_output_mask; 808 return 0; 809 810 case AWACS_VOL_SPEAKER: 811 vol = sc->sc_codecctl4; 812 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 813 r = (15 - (vol & 0x0f)) * 16; 814 mc->un.mask = 1 << 0; 815 mc->un.value.num_channels = 2; 816 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 817 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 818 return 0; 819 820 case AWACS_VOL_HEADPHONE: 821 vol = sc->sc_codecctl2; 822 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 823 r = (15 - (vol & 0x0f)) * 16; 824 mc->un.mask = 1 << 1; 825 mc->un.value.num_channels = 2; 826 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 827 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 828 return 0; 829 830 case AWACS_INPUT_SELECT: 831 mc->un.mask = sc->sc_record_source; 832 return 0; 833 834 case AWACS_VOL_INPUT: 835 vol = sc->sc_codecctl0 & 0xff; 836 l = (vol & 0xf0); 837 r = (vol & 0x0f) << 4; 838 mc->un.mask = sc->sc_record_source; 839 mc->un.value.num_channels = 2; 840 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 841 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 842 return 0; 843 844 default: 845 return ENXIO; 846 } 847 848 return 0; 849 } 850 851 int 852 awacs_query_devinfo(void *h, mixer_devinfo_t *dip) 853 { 854 DPRINTF("query_devinfo %d\n", dip->index); 855 856 switch (dip->index) { 857 858 case AWACS_OUTPUT_SELECT: 859 dip->mixer_class = AWACS_OUTPUT_CLASS; 860 strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name); 861 dip->type = AUDIO_MIXER_SET; 862 dip->prev = dip->next = AUDIO_MIXER_LAST; 863 dip->un.s.num_mem = 2; 864 strlcpy(dip->un.s.member[0].label.name, AudioNspeaker, 865 sizeof dip->un.s.member[0].label.name); 866 dip->un.s.member[0].mask = 1 << 0; 867 strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, 868 sizeof dip->un.s.member[0].label.name); 869 dip->un.s.member[1].mask = 1 << 1; 870 return 0; 871 872 case AWACS_VOL_SPEAKER: 873 dip->mixer_class = AWACS_OUTPUT_CLASS; 874 strlcpy(dip->label.name, AudioNspeaker, 875 sizeof dip->label.name); 876 dip->type = AUDIO_MIXER_VALUE; 877 dip->prev = dip->next = AUDIO_MIXER_LAST; 878 dip->un.v.num_channels = 2; 879 strlcpy(dip->un.v.units.name, AudioNvolume, 880 sizeof dip->un.v.units.name); 881 return 0; 882 883 case AWACS_VOL_HEADPHONE: 884 dip->mixer_class = AWACS_OUTPUT_CLASS; 885 strlcpy(dip->label.name, AudioNheadphone, 886 sizeof dip->label.name); 887 dip->type = AUDIO_MIXER_VALUE; 888 dip->prev = dip->next = AUDIO_MIXER_LAST; 889 dip->un.v.num_channels = 2; 890 strlcpy(dip->un.v.units.name, AudioNvolume, 891 sizeof dip->un.v.units.name); 892 return 0; 893 894 case AWACS_INPUT_SELECT: 895 dip->mixer_class = AWACS_RECORD_CLASS; 896 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 897 dip->type = AUDIO_MIXER_SET; 898 dip->prev = dip->next = AUDIO_MIXER_LAST; 899 dip->un.s.num_mem = 3; 900 strlcpy(dip->un.s.member[0].label.name, AudioNcd, 901 sizeof dip->un.s.member[0].label.name); 902 dip->un.s.member[0].mask = 1 << 0; 903 strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone, 904 sizeof dip->un.s.member[1].label.name); 905 dip->un.s.member[1].mask = 1 << 1; 906 strlcpy(dip->un.s.member[2].label.name, AudioNline, 907 sizeof dip->un.s.member[2].label.name); 908 dip->un.s.member[2].mask = 1 << 2; 909 return 0; 910 911 case AWACS_VOL_INPUT: 912 dip->mixer_class = AWACS_RECORD_CLASS; 913 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); 914 dip->type = AUDIO_MIXER_VALUE; 915 dip->prev = dip->next = AUDIO_MIXER_LAST; 916 dip->un.v.num_channels = 2; 917 strlcpy(dip->un.v.units.name, AudioNvolume, 918 sizeof dip->un.v.units.name); 919 return 0; 920 921 case AWACS_MONITOR_CLASS: 922 dip->mixer_class = AWACS_MONITOR_CLASS; 923 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 924 dip->type = AUDIO_MIXER_CLASS; 925 dip->next = dip->prev = AUDIO_MIXER_LAST; 926 return 0; 927 928 case AWACS_OUTPUT_CLASS: 929 dip->mixer_class = AWACS_OUTPUT_CLASS; 930 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 931 dip->type = AUDIO_MIXER_CLASS; 932 dip->next = dip->prev = AUDIO_MIXER_LAST; 933 return 0; 934 935 case AWACS_RECORD_CLASS: 936 dip->mixer_class = AWACS_MONITOR_CLASS; 937 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 938 dip->type = AUDIO_MIXER_CLASS; 939 dip->next = dip->prev = AUDIO_MIXER_LAST; 940 return 0; 941 } 942 943 return ENXIO; 944 } 945 946 size_t 947 awacs_round_buffersize(void *h, int dir, size_t size) 948 { 949 size = (size + PGOFSET) & ~(PGOFSET); 950 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 951 size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX; 952 return (size); 953 } 954 955 void * 956 awacs_allocm(void *h, int dir, size_t size, int type, int flags) 957 { 958 struct awacs_softc *sc = h; 959 struct awacs_dma *p; 960 int error; 961 962 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 963 return (NULL); 964 965 p = malloc(sizeof(*p), type, flags | M_ZERO); 966 if (!p) 967 return (NULL); 968 969 /* convert to the bus.h style, not used otherwise */ 970 if (flags & M_NOWAIT) 971 flags = BUS_DMA_NOWAIT; 972 973 p->size = size; 974 if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs, 975 1, &p->nsegs, flags)) != 0) { 976 printf("%s: unable to allocate dma, error = %d\n", 977 sc->sc_dev.dv_xname, error); 978 free(p, type, 0); 979 return NULL; 980 } 981 982 if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, 983 &p->addr, flags | BUS_DMA_COHERENT)) != 0) { 984 printf("%s: unable to map dma, error = %d\n", 985 sc->sc_dev.dv_xname, error); 986 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 987 free(p, type, 0); 988 return NULL; 989 } 990 991 if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1, 992 p->size, 0, flags, &p->map)) != 0) { 993 printf("%s: unable to create dma map, error = %d\n", 994 sc->sc_dev.dv_xname, error); 995 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 996 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 997 free(p, type, 0); 998 return NULL; 999 } 1000 1001 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, 1002 NULL, flags)) != 0) { 1003 printf("%s: unable to load dma map, error = %d\n", 1004 sc->sc_dev.dv_xname, error); 1005 bus_dmamap_destroy(sc->sc_dmat, p->map); 1006 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 1007 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 1008 free(p, type, 0); 1009 return NULL; 1010 } 1011 1012 p->next = sc->sc_dmas; 1013 sc->sc_dmas = p; 1014 1015 return p->addr; 1016 } 1017 1018 paddr_t 1019 awacs_mappage(void *h, void *mem, off_t off, int prot) 1020 { 1021 if (off < 0) 1022 return -1; 1023 return -1; /* XXX */ 1024 } 1025 1026 int 1027 awacs_get_props(void *h) 1028 { 1029 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */; 1030 } 1031 1032 int 1033 awacs_trigger_output(void *h, void *start, void *end, int bsize, 1034 void (*intr)(void *), void *arg, struct audio_params *param) 1035 { 1036 struct awacs_softc *sc = h; 1037 struct awacs_dma *p; 1038 struct dbdma_command *cmd = sc->sc_odmacmd; 1039 vaddr_t spa, pa, epa; 1040 int c; 1041 1042 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); 1043 1044 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1045 if (!p) 1046 return -1; 1047 1048 sc->sc_ointr = intr; 1049 sc->sc_oarg = arg; 1050 sc->sc_odmap = sc->sc_odmacmd; 1051 1052 mtx_enter(&audio_lock); 1053 spa = p->segs[0].ds_addr; 1054 c = DBDMA_CMD_OUT_MORE; 1055 for (pa = spa, epa = spa + (end - start); 1056 pa < epa; pa += bsize, cmd++) { 1057 1058 if (pa + bsize == epa) 1059 c = DBDMA_CMD_OUT_LAST; 1060 1061 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1062 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1063 } 1064 1065 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1066 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1067 dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr); 1068 1069 dbdma_start(sc->sc_odma, sc->sc_odbdma); 1070 1071 mtx_leave(&audio_lock); 1072 return 0; 1073 } 1074 1075 int 1076 awacs_trigger_input(void *h, void *start, void *end, int bsize, 1077 void (*intr)(void *), void *arg, struct audio_params *param) 1078 { 1079 struct awacs_softc *sc = h; 1080 struct awacs_dma *p; 1081 struct dbdma_command *cmd = sc->sc_idmacmd; 1082 vaddr_t spa, pa, epa; 1083 int c; 1084 1085 DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize); 1086 1087 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1088 if (!p) 1089 return -1; 1090 1091 sc->sc_iintr = intr; 1092 sc->sc_iarg = arg; 1093 sc->sc_idmap = sc->sc_idmacmd; 1094 1095 mtx_enter(&audio_lock); 1096 spa = p->segs[0].ds_addr; 1097 c = DBDMA_CMD_IN_MORE; 1098 for (pa = spa, epa = spa + (end - start); 1099 pa < epa; pa += bsize, cmd++) { 1100 1101 if (pa + bsize == epa) 1102 c = DBDMA_CMD_IN_LAST; 1103 1104 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1105 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1106 } 1107 1108 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1109 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1110 dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr); 1111 1112 dbdma_start(sc->sc_idma, sc->sc_idbdma); 1113 1114 mtx_leave(&audio_lock); 1115 return 0; 1116 } 1117 1118 void 1119 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right) 1120 { 1121 int lval = 15 - (left & 0xff) / 16; 1122 int rval = 15 - (right & 0xff) / 16; 1123 1124 DPRINTF("speaker_volume %d %d\n", lval, rval); 1125 1126 sc->sc_codecctl4 &= ~0x3cf; 1127 sc->sc_codecctl4 |= (lval << 6) | rval; 1128 awacs_write_codec(sc, sc->sc_codecctl4); 1129 } 1130 1131 void 1132 awacs_set_ext_volume(struct awacs_softc *sc, int left, int right) 1133 { 1134 int lval = 15 - (left & 0xff) / 16; 1135 int rval = 15 - (right & 0xff) / 16; 1136 1137 DPRINTF("ext_volume %d %d\n", lval, rval); 1138 1139 sc->sc_codecctl2 &= ~0x3cf; 1140 sc->sc_codecctl2 |= (lval << 6) | rval; 1141 awacs_write_codec(sc, sc->sc_codecctl2); 1142 } 1143 1144 void 1145 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p) 1146 { 1147 int selected = -1; 1148 size_t n, i; 1149 1150 n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]); 1151 1152 if (p->sample_rate < awacs_speeds[0].rate) 1153 selected = 0; 1154 if (p->sample_rate > awacs_speeds[n - 1].rate) 1155 selected = n - 1; 1156 1157 for (i = 1; selected == -1 && i < n; i++) { 1158 if (p->sample_rate == awacs_speeds[i].rate) 1159 selected = i; 1160 else if (p->sample_rate < awacs_speeds[i].rate) { 1161 u_int diff1, diff2; 1162 1163 diff1 = p->sample_rate - awacs_speeds[i - 1].rate; 1164 diff2 = awacs_speeds[i].rate - p->sample_rate; 1165 selected = (diff1 < diff2) ? i - 1 : i; 1166 } 1167 } 1168 1169 if (selected == -1) 1170 selected = 0; 1171 1172 sc->sc_soundctl &= ~AWACS_RATE_MASK; 1173 sc->sc_soundctl |= awacs_speeds[selected].bits; 1174 p->sample_rate = awacs_speeds[selected].rate; 1175 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 1176 } 1177