1 /* $OpenBSD: awacs.c,v 1.27 2011/09/04 18:48:10 miod 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 reason = awacs_read_reg(sc, AWACS_SOUND_CTRL); 391 392 if (reason & AWACS_CTL_CNTRLERR) { 393 /* change outputs ?? */ 394 } 395 if (reason & AWACS_CTL_PORTCHG) { 396 #ifdef DEBUG 397 printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS)); 398 #endif 399 400 if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) { 401 /* default output to speakers */ 402 sc->sc_output_mask = 1 << 1; 403 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 404 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER; 405 awacs_write_codec(sc, sc->sc_codecctl1); 406 } else { 407 /* default output to speakers */ 408 sc->sc_output_mask = 1 << 0; 409 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 410 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE; 411 awacs_write_codec(sc, sc->sc_codecctl1); 412 } 413 } 414 415 awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */ 416 return 1; 417 } 418 419 int 420 awacs_tx_intr(void *v) 421 { 422 struct awacs_softc *sc = v; 423 struct dbdma_command *cmd = sc->sc_odmap; 424 u_int16_t c, status; 425 426 /* if not set we are not running */ 427 if (!cmd) 428 return (0); 429 430 c = in16rb(&cmd->d_command); 431 status = in16rb(&cmd->d_status); 432 433 if (c >> 12 == DBDMA_CMD_OUT_LAST) 434 sc->sc_odmap = sc->sc_odmacmd; 435 else 436 sc->sc_odmap++; 437 438 if (c & (DBDMA_INT_ALWAYS << 4)) { 439 cmd->d_status = 0; 440 if (status) /* status == 0x8400 */ 441 if (sc->sc_ointr) 442 (*sc->sc_ointr)(sc->sc_oarg); 443 } 444 445 return (1); 446 } 447 int 448 awacs_rx_intr(void *v) 449 { 450 struct awacs_softc *sc = v; 451 struct dbdma_command *cmd = sc->sc_idmap; 452 u_int16_t c, status; 453 454 /* if not set we are not running */ 455 if (!cmd) 456 return (0); 457 458 c = in16rb(&cmd->d_command); 459 status = in16rb(&cmd->d_status); 460 461 if (c >> 12 == DBDMA_CMD_IN_LAST) 462 sc->sc_idmap = sc->sc_idmacmd; 463 else 464 sc->sc_idmap++; 465 466 if (c & (DBDMA_INT_ALWAYS << 4)) { 467 cmd->d_status = 0; 468 if (status) /* status == 0x8400 */ 469 if (sc->sc_iintr) 470 (*sc->sc_iintr)(sc->sc_iarg); 471 } 472 473 return (1); 474 } 475 476 int 477 awacs_open(void *h, int flags) 478 { 479 return 0; 480 } 481 482 /* 483 * Close function is called at splaudio(). 484 */ 485 void 486 awacs_close(void *h) 487 { 488 struct awacs_softc *sc = h; 489 490 awacs_halt_output(sc); 491 awacs_halt_input(sc); 492 493 sc->sc_ointr = 0; 494 sc->sc_iintr = 0; 495 } 496 497 int 498 awacs_query_encoding(void *h, struct audio_encoding *ae) 499 { 500 switch (ae->index) { 501 case 0: 502 strlcpy(ae->name, AudioEslinear, sizeof ae->name); 503 ae->encoding = AUDIO_ENCODING_SLINEAR; 504 ae->precision = 16; 505 ae->flags = 0; 506 break; 507 case 1: 508 strlcpy(ae->name, AudioEslinear_be, sizeof ae->name); 509 ae->encoding = AUDIO_ENCODING_SLINEAR_BE; 510 ae->precision = 16; 511 ae->flags = 0; 512 break; 513 case 2: 514 strlcpy(ae->name, AudioEslinear_le, sizeof ae->name); 515 ae->encoding = AUDIO_ENCODING_SLINEAR_LE; 516 ae->precision = 16; 517 ae->flags = 0; 518 break; 519 case 3: 520 strlcpy(ae->name, AudioEmulaw, sizeof ae->name); 521 ae->encoding = AUDIO_ENCODING_ULAW; 522 ae->precision = 8; 523 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 524 break; 525 case 4: 526 strlcpy(ae->name, AudioEalaw, sizeof ae->name); 527 ae->encoding = AUDIO_ENCODING_ALAW; 528 ae->precision = 8; 529 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 530 break; 531 case 5: 532 strlcpy(ae->name, AudioEulinear, sizeof ae->name); 533 ae->encoding = AUDIO_ENCODING_ULINEAR; 534 ae->precision = 16; 535 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 536 break; 537 case 6: 538 strlcpy(ae->name, AudioEulinear_le, sizeof ae->name); 539 ae->encoding = AUDIO_ENCODING_ULINEAR_LE; 540 ae->precision = 16; 541 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 542 break; 543 case 7: 544 strlcpy(ae->name, AudioEulinear_be, sizeof ae->name); 545 ae->encoding = AUDIO_ENCODING_ULINEAR_BE; 546 ae->precision = 16; 547 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 548 break; 549 default: 550 return (EINVAL); 551 } 552 ae->bps = AUDIO_BPS(ae->precision); 553 ae->msb = 1; 554 555 return (0); 556 } 557 558 int 559 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play, 560 struct audio_params *rec) 561 { 562 struct awacs_softc *sc = h; 563 struct audio_params *p; 564 int mode; 565 566 /* 567 * This device only has one clock, so make the sample rates match. 568 */ 569 if (play->sample_rate != rec->sample_rate && 570 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 571 if (setmode == AUMODE_PLAY) { 572 rec->sample_rate = play->sample_rate; 573 setmode |= AUMODE_RECORD; 574 } else if (setmode == AUMODE_RECORD) { 575 play->sample_rate = rec->sample_rate; 576 setmode |= AUMODE_PLAY; 577 } else 578 return EINVAL; 579 } 580 581 for (mode = AUMODE_RECORD; mode != -1; 582 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 583 if ((setmode & mode) == 0) 584 continue; 585 586 p = mode == AUMODE_PLAY ? play : rec; 587 588 if (p->sample_rate < 4000) 589 p->sample_rate = 4000; 590 if (p->sample_rate > 50000) 591 p->sample_rate = 50000; 592 if (p->precision > 16) 593 p->precision = 16; 594 if (p->channels > 2) 595 p->channels = 2; 596 597 p->factor = 1; 598 p->sw_code = NULL; 599 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0); 600 601 switch (p->encoding) { 602 603 case AUDIO_ENCODING_SLINEAR_LE: 604 if (p->precision != 16) 605 p->precision = 16; 606 if (p->channels == 2) 607 p->sw_code = swap_bytes; 608 else { 609 p->factor = 2; 610 p->sw_code = swap_bytes_mts; 611 } 612 break; 613 case AUDIO_ENCODING_SLINEAR_BE: 614 if (p->precision != 16) 615 p->precision = 16; 616 if (p->channels == 1) { 617 p->factor = 2; 618 p->sw_code = noswap_bytes_mts; 619 } 620 break; 621 case AUDIO_ENCODING_ULINEAR_LE: 622 if (p->precision != 16) 623 p->precision = 16; 624 if (p->channels == 2) 625 p->sw_code = swap_bytes_change_sign16_be; 626 else { 627 p->factor = 2; 628 p->sw_code = swap_bytes_change_sign16_be_mts; 629 } 630 break; 631 case AUDIO_ENCODING_ULINEAR_BE: 632 if (p->precision != 16) 633 p->precision = 16; 634 if (p->channels == 2) 635 p->sw_code = change_sign16_be; 636 else { 637 p->factor = 2; 638 p->sw_code = change_sign16_be_mts; 639 } 640 break; 641 case AUDIO_ENCODING_ULAW: 642 if (mode == AUMODE_PLAY) { 643 p->factor = 2; 644 p->sw_code = mulaw_to_slinear16_be; 645 break; 646 } else 647 break; /* XXX */ 648 return (EINVAL); 649 case AUDIO_ENCODING_ALAW: 650 if (mode == AUMODE_PLAY) { 651 p->factor = 2; 652 p->sw_code = alaw_to_slinear16_be; 653 break; 654 } 655 return (EINVAL); 656 default: 657 return (EINVAL); 658 } 659 p->bps = AUDIO_BPS(p->precision); 660 p->msb = 1; 661 } 662 663 /* Set the speed */ 664 awacs_set_rate(sc, p); 665 666 return (0); 667 } 668 669 int 670 awacs_round_blocksize(void *h, int size) 671 { 672 if (size < PAGE_SIZE) 673 size = PAGE_SIZE; 674 return (size + PAGE_SIZE / 2) & ~(PGOFSET); 675 } 676 677 int 678 awacs_halt_output(void *h) 679 { 680 struct awacs_softc *sc = h; 681 682 dbdma_stop(sc->sc_odma); 683 dbdma_reset(sc->sc_odma); 684 dbdma_stop(sc->sc_odma); 685 sc->sc_odmap = NULL; 686 return 0; 687 } 688 689 int 690 awacs_halt_input(void *h) 691 { 692 struct awacs_softc *sc = h; 693 694 dbdma_stop(sc->sc_idma); 695 dbdma_reset(sc->sc_idma); 696 return 0; 697 } 698 699 int 700 awacs_getdev(void *h, struct audio_device *retp) 701 { 702 *retp = awacs_device; 703 return 0; 704 } 705 706 enum { 707 AWACS_OUTPUT_SELECT, 708 AWACS_VOL_SPEAKER, 709 AWACS_VOL_HEADPHONE, 710 AWACS_OUTPUT_CLASS, 711 AWACS_MONITOR_CLASS, 712 AWACS_INPUT_SELECT, 713 AWACS_VOL_INPUT, 714 AWACS_INPUT_CLASS, 715 AWACS_RECORD_CLASS, 716 AWACS_ENUM_LAST 717 }; 718 719 int 720 awacs_set_port(void *h, mixer_ctrl_t *mc) 721 { 722 struct awacs_softc *sc = h; 723 int l, r; 724 725 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type); 726 727 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 728 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 729 730 switch (mc->dev) { 731 case AWACS_OUTPUT_SELECT: 732 /* no change necessary? */ 733 if (mc->un.mask == sc->sc_output_mask) 734 return 0; 735 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE; 736 if (mc->un.mask & 1 << 0) 737 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 738 if (mc->un.mask & 1 << 1) 739 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 740 741 awacs_write_codec(sc, sc->sc_codecctl1); 742 sc->sc_output_mask = mc->un.mask; 743 return 0; 744 745 case AWACS_VOL_SPEAKER: 746 awacs_set_speaker_volume(sc, l, r); 747 return 0; 748 749 case AWACS_VOL_HEADPHONE: 750 awacs_set_ext_volume(sc, l, r); 751 return 0; 752 753 case AWACS_VOL_INPUT: 754 sc->sc_codecctl0 &= ~0xff; 755 sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4); 756 awacs_write_codec(sc, sc->sc_codecctl0); 757 return 0; 758 759 case AWACS_INPUT_SELECT: 760 /* no change necessary? */ 761 if (mc->un.mask == sc->sc_record_source) 762 return 0; 763 switch(mc->un.mask) { 764 case 1<<0: /* CD */ 765 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 766 sc->sc_codecctl0 |= AWACS_INPUT_CD; 767 awacs_write_codec(sc, sc->sc_codecctl0); 768 break; 769 case 1<<1: /* microphone */ 770 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 771 sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE; 772 awacs_write_codec(sc, sc->sc_codecctl0); 773 break; 774 case 1<<2: /* line in */ 775 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 776 sc->sc_codecctl0 |= AWACS_INPUT_LINE; 777 awacs_write_codec(sc, sc->sc_codecctl0); 778 break; 779 default: /* invalid argument */ 780 return -1; 781 } 782 sc->sc_record_source = mc->un.mask; 783 return 0; 784 } 785 786 return ENXIO; 787 } 788 789 int 790 awacs_get_port(void *h, mixer_ctrl_t *mc) 791 { 792 struct awacs_softc *sc = h; 793 int vol, l, r; 794 795 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type); 796 797 switch (mc->dev) { 798 case AWACS_OUTPUT_SELECT: 799 mc->un.mask = sc->sc_output_mask; 800 return 0; 801 802 case AWACS_VOL_SPEAKER: 803 vol = sc->sc_codecctl4; 804 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 805 r = (15 - (vol & 0x0f)) * 16; 806 mc->un.mask = 1 << 0; 807 mc->un.value.num_channels = 2; 808 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 809 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 810 return 0; 811 812 case AWACS_VOL_HEADPHONE: 813 vol = sc->sc_codecctl2; 814 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 815 r = (15 - (vol & 0x0f)) * 16; 816 mc->un.mask = 1 << 1; 817 mc->un.value.num_channels = 2; 818 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 819 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 820 return 0; 821 822 case AWACS_INPUT_SELECT: 823 mc->un.mask = sc->sc_record_source; 824 return 0; 825 826 case AWACS_VOL_INPUT: 827 vol = sc->sc_codecctl0 & 0xff; 828 l = (vol & 0xf0); 829 r = (vol & 0x0f) << 4; 830 mc->un.mask = sc->sc_record_source; 831 mc->un.value.num_channels = 2; 832 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 833 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 834 return 0; 835 836 default: 837 return ENXIO; 838 } 839 840 return 0; 841 } 842 843 int 844 awacs_query_devinfo(void *h, mixer_devinfo_t *dip) 845 { 846 DPRINTF("query_devinfo %d\n", dip->index); 847 848 switch (dip->index) { 849 850 case AWACS_OUTPUT_SELECT: 851 dip->mixer_class = AWACS_OUTPUT_CLASS; 852 strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name); 853 dip->type = AUDIO_MIXER_SET; 854 dip->prev = dip->next = AUDIO_MIXER_LAST; 855 dip->un.s.num_mem = 2; 856 strlcpy(dip->un.s.member[0].label.name, AudioNspeaker, 857 sizeof dip->un.s.member[0].label.name); 858 dip->un.s.member[0].mask = 1 << 0; 859 strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, 860 sizeof dip->un.s.member[0].label.name); 861 dip->un.s.member[1].mask = 1 << 1; 862 return 0; 863 864 case AWACS_VOL_SPEAKER: 865 dip->mixer_class = AWACS_OUTPUT_CLASS; 866 strlcpy(dip->label.name, AudioNspeaker, 867 sizeof dip->label.name); 868 dip->type = AUDIO_MIXER_VALUE; 869 dip->prev = dip->next = AUDIO_MIXER_LAST; 870 dip->un.v.num_channels = 2; 871 strlcpy(dip->un.v.units.name, AudioNvolume, 872 sizeof dip->un.v.units.name); 873 return 0; 874 875 case AWACS_VOL_HEADPHONE: 876 dip->mixer_class = AWACS_OUTPUT_CLASS; 877 strlcpy(dip->label.name, AudioNheadphone, 878 sizeof dip->label.name); 879 dip->type = AUDIO_MIXER_VALUE; 880 dip->prev = dip->next = AUDIO_MIXER_LAST; 881 dip->un.v.num_channels = 2; 882 strlcpy(dip->un.v.units.name, AudioNvolume, 883 sizeof dip->un.v.units.name); 884 return 0; 885 886 case AWACS_INPUT_SELECT: 887 dip->mixer_class = AWACS_RECORD_CLASS; 888 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 889 dip->type = AUDIO_MIXER_SET; 890 dip->prev = dip->next = AUDIO_MIXER_LAST; 891 dip->un.s.num_mem = 3; 892 strlcpy(dip->un.s.member[0].label.name, AudioNcd, 893 sizeof dip->un.s.member[0].label.name); 894 dip->un.s.member[0].mask = 1 << 0; 895 strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone, 896 sizeof dip->un.s.member[1].label.name); 897 dip->un.s.member[1].mask = 1 << 1; 898 strlcpy(dip->un.s.member[2].label.name, AudioNline, 899 sizeof dip->un.s.member[2].label.name); 900 dip->un.s.member[2].mask = 1 << 2; 901 return 0; 902 903 case AWACS_VOL_INPUT: 904 dip->mixer_class = AWACS_RECORD_CLASS; 905 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); 906 dip->type = AUDIO_MIXER_VALUE; 907 dip->prev = dip->next = AUDIO_MIXER_LAST; 908 dip->un.v.num_channels = 2; 909 strlcpy(dip->un.v.units.name, AudioNvolume, 910 sizeof dip->un.v.units.name); 911 return 0; 912 913 case AWACS_MONITOR_CLASS: 914 dip->mixer_class = AWACS_MONITOR_CLASS; 915 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 916 dip->type = AUDIO_MIXER_CLASS; 917 dip->next = dip->prev = AUDIO_MIXER_LAST; 918 return 0; 919 920 case AWACS_OUTPUT_CLASS: 921 dip->mixer_class = AWACS_OUTPUT_CLASS; 922 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 923 dip->type = AUDIO_MIXER_CLASS; 924 dip->next = dip->prev = AUDIO_MIXER_LAST; 925 return 0; 926 927 case AWACS_RECORD_CLASS: 928 dip->mixer_class = AWACS_MONITOR_CLASS; 929 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 930 dip->type = AUDIO_MIXER_CLASS; 931 dip->next = dip->prev = AUDIO_MIXER_LAST; 932 return 0; 933 } 934 935 return ENXIO; 936 } 937 938 size_t 939 awacs_round_buffersize(void *h, int dir, size_t size) 940 { 941 size = (size + PGOFSET) & ~(PGOFSET); 942 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 943 size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX; 944 return (size); 945 } 946 947 void * 948 awacs_allocm(void *h, int dir, size_t size, int type, int flags) 949 { 950 struct awacs_softc *sc = h; 951 struct awacs_dma *p; 952 int error; 953 954 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 955 return (NULL); 956 957 p = malloc(sizeof(*p), type, flags | M_ZERO); 958 if (!p) 959 return (NULL); 960 961 /* convert to the bus.h style, not used otherwise */ 962 if (flags & M_NOWAIT) 963 flags = BUS_DMA_NOWAIT; 964 965 p->size = size; 966 if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs, 967 1, &p->nsegs, flags)) != 0) { 968 printf("%s: unable to allocate dma, error = %d\n", 969 sc->sc_dev.dv_xname, error); 970 free(p, type); 971 return NULL; 972 } 973 974 if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, 975 &p->addr, flags | BUS_DMA_COHERENT)) != 0) { 976 printf("%s: unable to map dma, error = %d\n", 977 sc->sc_dev.dv_xname, error); 978 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 979 free(p, type); 980 return NULL; 981 } 982 983 if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1, 984 p->size, 0, flags, &p->map)) != 0) { 985 printf("%s: unable to create dma map, error = %d\n", 986 sc->sc_dev.dv_xname, error); 987 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 988 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 989 free(p, type); 990 return NULL; 991 } 992 993 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, 994 NULL, flags)) != 0) { 995 printf("%s: unable to load dma map, error = %d\n", 996 sc->sc_dev.dv_xname, error); 997 bus_dmamap_destroy(sc->sc_dmat, p->map); 998 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 999 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 1000 free(p, type); 1001 return NULL; 1002 } 1003 1004 p->next = sc->sc_dmas; 1005 sc->sc_dmas = p; 1006 1007 return p->addr; 1008 } 1009 1010 paddr_t 1011 awacs_mappage(void *h, void *mem, off_t off, int prot) 1012 { 1013 if (off < 0) 1014 return -1; 1015 return -1; /* XXX */ 1016 } 1017 1018 int 1019 awacs_get_props(void *h) 1020 { 1021 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */; 1022 } 1023 1024 int 1025 awacs_trigger_output(void *h, void *start, void *end, int bsize, 1026 void (*intr)(void *), void *arg, struct audio_params *param) 1027 { 1028 struct awacs_softc *sc = h; 1029 struct awacs_dma *p; 1030 struct dbdma_command *cmd = sc->sc_odmacmd; 1031 vaddr_t spa, pa, epa; 1032 int c; 1033 1034 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); 1035 1036 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1037 if (!p) 1038 return -1; 1039 1040 sc->sc_ointr = intr; 1041 sc->sc_oarg = arg; 1042 sc->sc_odmap = sc->sc_odmacmd; 1043 1044 spa = p->segs[0].ds_addr; 1045 c = DBDMA_CMD_OUT_MORE; 1046 for (pa = spa, epa = spa + (end - start); 1047 pa < epa; pa += bsize, cmd++) { 1048 1049 if (pa + bsize == epa) 1050 c = DBDMA_CMD_OUT_LAST; 1051 1052 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1053 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1054 } 1055 1056 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1057 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1058 dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr); 1059 1060 dbdma_start(sc->sc_odma, sc->sc_odbdma); 1061 1062 return 0; 1063 } 1064 1065 int 1066 awacs_trigger_input(void *h, void *start, void *end, int bsize, 1067 void (*intr)(void *), void *arg, struct audio_params *param) 1068 { 1069 struct awacs_softc *sc = h; 1070 struct awacs_dma *p; 1071 struct dbdma_command *cmd = sc->sc_idmacmd; 1072 vaddr_t spa, pa, epa; 1073 int c; 1074 1075 DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize); 1076 1077 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1078 if (!p) 1079 return -1; 1080 1081 sc->sc_iintr = intr; 1082 sc->sc_iarg = arg; 1083 sc->sc_idmap = sc->sc_idmacmd; 1084 1085 spa = p->segs[0].ds_addr; 1086 c = DBDMA_CMD_IN_MORE; 1087 for (pa = spa, epa = spa + (end - start); 1088 pa < epa; pa += bsize, cmd++) { 1089 1090 if (pa + bsize == epa) 1091 c = DBDMA_CMD_IN_LAST; 1092 1093 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1094 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1095 } 1096 1097 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1098 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1099 dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr); 1100 1101 dbdma_start(sc->sc_idma, sc->sc_idbdma); 1102 1103 return 0; 1104 } 1105 1106 void 1107 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right) 1108 { 1109 int lval = 15 - (left & 0xff) / 16; 1110 int rval = 15 - (right & 0xff) / 16; 1111 1112 DPRINTF("speaker_volume %d %d\n", lval, rval); 1113 1114 sc->sc_codecctl4 &= ~0x3cf; 1115 sc->sc_codecctl4 |= (lval << 6) | rval; 1116 awacs_write_codec(sc, sc->sc_codecctl4); 1117 } 1118 1119 void 1120 awacs_set_ext_volume(struct awacs_softc *sc, int left, int right) 1121 { 1122 int lval = 15 - (left & 0xff) / 16; 1123 int rval = 15 - (right & 0xff) / 16; 1124 1125 DPRINTF("ext_volume %d %d\n", lval, rval); 1126 1127 sc->sc_codecctl2 &= ~0x3cf; 1128 sc->sc_codecctl2 |= (lval << 6) | rval; 1129 awacs_write_codec(sc, sc->sc_codecctl2); 1130 } 1131 1132 void 1133 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p) 1134 { 1135 int selected = -1; 1136 size_t n, i; 1137 1138 n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]); 1139 1140 if (p->sample_rate < awacs_speeds[0].rate) 1141 selected = 0; 1142 if (p->sample_rate > awacs_speeds[n - 1].rate) 1143 selected = n - 1; 1144 1145 for (i = 1; selected == -1 && i < n; i++) { 1146 if (p->sample_rate == awacs_speeds[i].rate) 1147 selected = i; 1148 else if (p->sample_rate < awacs_speeds[i].rate) { 1149 u_int diff1, diff2; 1150 1151 diff1 = p->sample_rate - awacs_speeds[i - 1].rate; 1152 diff2 = awacs_speeds[i].rate - p->sample_rate; 1153 selected = (diff1 < diff2) ? i - 1 : i; 1154 } 1155 } 1156 1157 if (selected == -1) 1158 selected = 0; 1159 1160 sc->sc_soundctl &= ~AWACS_RATE_MASK; 1161 sc->sc_soundctl |= awacs_speeds[selected].bits; 1162 p->sample_rate = awacs_speeds[selected].rate; 1163 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 1164 } 1165