1 /* $OpenBSD: awacs.c,v 1.24 2008/10/30 06:22:38 todd 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 return (0); 553 } 554 555 int 556 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play, 557 struct audio_params *rec) 558 { 559 struct awacs_softc *sc = h; 560 struct audio_params *p; 561 int mode; 562 563 /* 564 * This device only has one clock, so make the sample rates match. 565 */ 566 if (play->sample_rate != rec->sample_rate && 567 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 568 if (setmode == AUMODE_PLAY) { 569 rec->sample_rate = play->sample_rate; 570 setmode |= AUMODE_RECORD; 571 } else if (setmode == AUMODE_RECORD) { 572 play->sample_rate = rec->sample_rate; 573 setmode |= AUMODE_PLAY; 574 } else 575 return EINVAL; 576 } 577 578 for (mode = AUMODE_RECORD; mode != -1; 579 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 580 if ((setmode & mode) == 0) 581 continue; 582 583 p = mode == AUMODE_PLAY ? play : rec; 584 585 if (p->sample_rate < 4000) 586 p->sample_rate = 4000; 587 if (p->sample_rate > 50000) 588 p->sample_rate = 50000; 589 if (p->precision > 16) 590 p->precision = 16; 591 if (p->channels > 2) 592 p->channels = 2; 593 594 p->factor = 1; 595 p->sw_code = NULL; 596 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0); 597 598 switch (p->encoding) { 599 600 case AUDIO_ENCODING_SLINEAR_LE: 601 if (p->precision != 16) 602 p->precision = 16; 603 if (p->channels == 2) 604 p->sw_code = swap_bytes; 605 else { 606 p->factor = 2; 607 p->sw_code = swap_bytes_mts; 608 } 609 break; 610 case AUDIO_ENCODING_SLINEAR_BE: 611 if (p->precision != 16) 612 p->precision = 16; 613 if (p->channels == 1) { 614 p->factor = 2; 615 p->sw_code = noswap_bytes_mts; 616 } 617 break; 618 case AUDIO_ENCODING_ULINEAR_LE: 619 if (p->precision != 16) 620 p->precision = 16; 621 if (p->channels == 2) 622 p->sw_code = swap_bytes_change_sign16_be; 623 else { 624 p->factor = 2; 625 p->sw_code = swap_bytes_change_sign16_be_mts; 626 } 627 break; 628 case AUDIO_ENCODING_ULINEAR_BE: 629 if (p->precision != 16) 630 p->precision = 16; 631 if (p->channels == 2) 632 p->sw_code = change_sign16_be; 633 else { 634 p->factor = 2; 635 p->sw_code = change_sign16_be_mts; 636 } 637 break; 638 case AUDIO_ENCODING_ULAW: 639 if (mode == AUMODE_PLAY) { 640 p->factor = 2; 641 p->sw_code = mulaw_to_slinear16_be; 642 break; 643 } else 644 break; /* XXX */ 645 return (EINVAL); 646 case AUDIO_ENCODING_ALAW: 647 if (mode == AUMODE_PLAY) { 648 p->factor = 2; 649 p->sw_code = alaw_to_slinear16_be; 650 break; 651 } 652 return (EINVAL); 653 default: 654 return (EINVAL); 655 } 656 } 657 658 /* Set the speed */ 659 awacs_set_rate(sc, p); 660 661 return (0); 662 } 663 664 int 665 awacs_round_blocksize(void *h, int size) 666 { 667 if (size < PAGE_SIZE) 668 size = PAGE_SIZE; 669 return (size + PAGE_SIZE / 2) & ~(PGOFSET); 670 } 671 672 int 673 awacs_halt_output(void *h) 674 { 675 struct awacs_softc *sc = h; 676 677 dbdma_stop(sc->sc_odma); 678 dbdma_reset(sc->sc_odma); 679 dbdma_stop(sc->sc_odma); 680 sc->sc_odmap = NULL; 681 return 0; 682 } 683 684 int 685 awacs_halt_input(void *h) 686 { 687 struct awacs_softc *sc = h; 688 689 dbdma_stop(sc->sc_idma); 690 dbdma_reset(sc->sc_idma); 691 return 0; 692 } 693 694 int 695 awacs_getdev(void *h, struct audio_device *retp) 696 { 697 *retp = awacs_device; 698 return 0; 699 } 700 701 enum { 702 AWACS_OUTPUT_SELECT, 703 AWACS_VOL_SPEAKER, 704 AWACS_VOL_HEADPHONE, 705 AWACS_OUTPUT_CLASS, 706 AWACS_MONITOR_CLASS, 707 AWACS_INPUT_SELECT, 708 AWACS_VOL_INPUT, 709 AWACS_INPUT_CLASS, 710 AWACS_RECORD_CLASS, 711 AWACS_ENUM_LAST 712 }; 713 714 int 715 awacs_set_port(void *h, mixer_ctrl_t *mc) 716 { 717 struct awacs_softc *sc = h; 718 int l, r; 719 720 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type); 721 722 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 723 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 724 725 switch (mc->dev) { 726 case AWACS_OUTPUT_SELECT: 727 /* no change necessary? */ 728 if (mc->un.mask == sc->sc_output_mask) 729 return 0; 730 sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE; 731 if (mc->un.mask & 1 << 0) 732 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER; 733 if (mc->un.mask & 1 << 1) 734 sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE; 735 736 awacs_write_codec(sc, sc->sc_codecctl1); 737 sc->sc_output_mask = mc->un.mask; 738 return 0; 739 740 case AWACS_VOL_SPEAKER: 741 awacs_set_speaker_volume(sc, l, r); 742 return 0; 743 744 case AWACS_VOL_HEADPHONE: 745 awacs_set_ext_volume(sc, l, r); 746 return 0; 747 748 case AWACS_VOL_INPUT: 749 sc->sc_codecctl0 &= ~0xff; 750 sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4); 751 awacs_write_codec(sc, sc->sc_codecctl0); 752 return 0; 753 754 case AWACS_INPUT_SELECT: 755 /* no change necessary? */ 756 if (mc->un.mask == sc->sc_record_source) 757 return 0; 758 switch(mc->un.mask) { 759 case 1<<0: /* CD */ 760 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 761 sc->sc_codecctl0 |= AWACS_INPUT_CD; 762 awacs_write_codec(sc, sc->sc_codecctl0); 763 break; 764 case 1<<1: /* microphone */ 765 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 766 sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE; 767 awacs_write_codec(sc, sc->sc_codecctl0); 768 break; 769 case 1<<2: /* line in */ 770 sc->sc_codecctl0 &= ~AWACS_INPUT_MASK; 771 sc->sc_codecctl0 |= AWACS_INPUT_LINE; 772 awacs_write_codec(sc, sc->sc_codecctl0); 773 break; 774 default: /* invalid argument */ 775 return -1; 776 } 777 sc->sc_record_source = mc->un.mask; 778 return 0; 779 } 780 781 return ENXIO; 782 } 783 784 int 785 awacs_get_port(void *h, mixer_ctrl_t *mc) 786 { 787 struct awacs_softc *sc = h; 788 int vol, l, r; 789 790 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type); 791 792 switch (mc->dev) { 793 case AWACS_OUTPUT_SELECT: 794 mc->un.mask = sc->sc_output_mask; 795 return 0; 796 797 case AWACS_VOL_SPEAKER: 798 vol = sc->sc_codecctl4; 799 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 800 r = (15 - (vol & 0x0f)) * 16; 801 mc->un.mask = 1 << 0; 802 mc->un.value.num_channels = 2; 803 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 804 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 805 return 0; 806 807 case AWACS_VOL_HEADPHONE: 808 vol = sc->sc_codecctl2; 809 l = (15 - ((vol & 0x3c0) >> 6)) * 16; 810 r = (15 - (vol & 0x0f)) * 16; 811 mc->un.mask = 1 << 1; 812 mc->un.value.num_channels = 2; 813 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 814 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 815 return 0; 816 817 case AWACS_INPUT_SELECT: 818 mc->un.mask = sc->sc_record_source; 819 return 0; 820 821 case AWACS_VOL_INPUT: 822 vol = sc->sc_codecctl0 & 0xff; 823 l = (vol & 0xf0); 824 r = (vol & 0x0f) << 4; 825 mc->un.mask = sc->sc_record_source; 826 mc->un.value.num_channels = 2; 827 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 828 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 829 return 0; 830 831 default: 832 return ENXIO; 833 } 834 835 return 0; 836 } 837 838 int 839 awacs_query_devinfo(void *h, mixer_devinfo_t *dip) 840 { 841 DPRINTF("query_devinfo %d\n", dip->index); 842 843 switch (dip->index) { 844 845 case AWACS_OUTPUT_SELECT: 846 dip->mixer_class = AWACS_OUTPUT_CLASS; 847 strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name); 848 dip->type = AUDIO_MIXER_SET; 849 dip->prev = dip->next = AUDIO_MIXER_LAST; 850 dip->un.s.num_mem = 2; 851 strlcpy(dip->un.s.member[0].label.name, AudioNspeaker, 852 sizeof dip->un.s.member[0].label.name); 853 dip->un.s.member[0].mask = 1 << 0; 854 strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, 855 sizeof dip->un.s.member[0].label.name); 856 dip->un.s.member[1].mask = 1 << 1; 857 return 0; 858 859 case AWACS_VOL_SPEAKER: 860 dip->mixer_class = AWACS_OUTPUT_CLASS; 861 strlcpy(dip->label.name, AudioNspeaker, 862 sizeof dip->label.name); 863 dip->type = AUDIO_MIXER_VALUE; 864 dip->prev = dip->next = AUDIO_MIXER_LAST; 865 dip->un.v.num_channels = 2; 866 strlcpy(dip->un.v.units.name, AudioNvolume, 867 sizeof dip->un.v.units.name); 868 return 0; 869 870 case AWACS_VOL_HEADPHONE: 871 dip->mixer_class = AWACS_OUTPUT_CLASS; 872 strlcpy(dip->label.name, AudioNheadphone, 873 sizeof dip->label.name); 874 dip->type = AUDIO_MIXER_VALUE; 875 dip->prev = dip->next = AUDIO_MIXER_LAST; 876 dip->un.v.num_channels = 2; 877 strlcpy(dip->un.v.units.name, AudioNvolume, 878 sizeof dip->un.v.units.name); 879 return 0; 880 881 case AWACS_INPUT_SELECT: 882 dip->mixer_class = AWACS_RECORD_CLASS; 883 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 884 dip->type = AUDIO_MIXER_SET; 885 dip->prev = dip->next = AUDIO_MIXER_LAST; 886 dip->un.s.num_mem = 3; 887 strlcpy(dip->un.s.member[0].label.name, AudioNcd, 888 sizeof dip->un.s.member[0].label.name); 889 dip->un.s.member[0].mask = 1 << 0; 890 strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone, 891 sizeof dip->un.s.member[1].label.name); 892 dip->un.s.member[1].mask = 1 << 1; 893 strlcpy(dip->un.s.member[2].label.name, AudioNline, 894 sizeof dip->un.s.member[2].label.name); 895 dip->un.s.member[2].mask = 1 << 2; 896 return 0; 897 898 case AWACS_VOL_INPUT: 899 dip->mixer_class = AWACS_RECORD_CLASS; 900 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); 901 dip->type = AUDIO_MIXER_VALUE; 902 dip->prev = dip->next = AUDIO_MIXER_LAST; 903 dip->un.v.num_channels = 2; 904 strlcpy(dip->un.v.units.name, AudioNvolume, 905 sizeof dip->un.v.units.name); 906 return 0; 907 908 case AWACS_MONITOR_CLASS: 909 dip->mixer_class = AWACS_MONITOR_CLASS; 910 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 911 dip->type = AUDIO_MIXER_CLASS; 912 dip->next = dip->prev = AUDIO_MIXER_LAST; 913 return 0; 914 915 case AWACS_OUTPUT_CLASS: 916 dip->mixer_class = AWACS_OUTPUT_CLASS; 917 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 918 dip->type = AUDIO_MIXER_CLASS; 919 dip->next = dip->prev = AUDIO_MIXER_LAST; 920 return 0; 921 922 case AWACS_RECORD_CLASS: 923 dip->mixer_class = AWACS_MONITOR_CLASS; 924 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 925 dip->type = AUDIO_MIXER_CLASS; 926 dip->next = dip->prev = AUDIO_MIXER_LAST; 927 return 0; 928 } 929 930 return ENXIO; 931 } 932 933 size_t 934 awacs_round_buffersize(void *h, int dir, size_t size) 935 { 936 size = (size + PGOFSET) & ~(PGOFSET); 937 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 938 size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX; 939 return (size); 940 } 941 942 void * 943 awacs_allocm(void *h, int dir, size_t size, int type, int flags) 944 { 945 struct awacs_softc *sc = h; 946 struct awacs_dma *p; 947 int error; 948 949 if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX) 950 return (NULL); 951 952 p = malloc(sizeof(*p), type, flags | M_ZERO); 953 if (!p) 954 return (NULL); 955 956 /* convert to the bus.h style, not used otherwise */ 957 if (flags & M_NOWAIT) 958 flags = BUS_DMA_NOWAIT; 959 960 p->size = size; 961 if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs, 962 1, &p->nsegs, flags)) != 0) { 963 printf("%s: unable to allocate dma, error = %d\n", 964 sc->sc_dev.dv_xname, error); 965 free(p, type); 966 return NULL; 967 } 968 969 if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size, 970 &p->addr, flags | BUS_DMA_COHERENT)) != 0) { 971 printf("%s: unable to map dma, error = %d\n", 972 sc->sc_dev.dv_xname, error); 973 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 974 free(p, type); 975 return NULL; 976 } 977 978 if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1, 979 p->size, 0, flags, &p->map)) != 0) { 980 printf("%s: unable to create dma map, error = %d\n", 981 sc->sc_dev.dv_xname, error); 982 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 983 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 984 free(p, type); 985 return NULL; 986 } 987 988 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, 989 NULL, flags)) != 0) { 990 printf("%s: unable to load dma map, error = %d\n", 991 sc->sc_dev.dv_xname, error); 992 bus_dmamap_destroy(sc->sc_dmat, p->map); 993 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 994 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 995 free(p, type); 996 return NULL; 997 } 998 999 p->next = sc->sc_dmas; 1000 sc->sc_dmas = p; 1001 1002 return p->addr; 1003 } 1004 1005 paddr_t 1006 awacs_mappage(void *h, void *mem, off_t off, int prot) 1007 { 1008 if (off < 0) 1009 return -1; 1010 return -1; /* XXX */ 1011 } 1012 1013 int 1014 awacs_get_props(void *h) 1015 { 1016 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */; 1017 } 1018 1019 int 1020 awacs_trigger_output(void *h, void *start, void *end, int bsize, 1021 void (*intr)(void *), void *arg, struct audio_params *param) 1022 { 1023 struct awacs_softc *sc = h; 1024 struct awacs_dma *p; 1025 struct dbdma_command *cmd = sc->sc_odmacmd; 1026 vaddr_t spa, pa, epa; 1027 int c; 1028 1029 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); 1030 1031 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1032 if (!p) 1033 return -1; 1034 1035 sc->sc_ointr = intr; 1036 sc->sc_oarg = arg; 1037 sc->sc_odmap = sc->sc_odmacmd; 1038 1039 spa = p->segs[0].ds_addr; 1040 c = DBDMA_CMD_OUT_MORE; 1041 for (pa = spa, epa = spa + (end - start); 1042 pa < epa; pa += bsize, cmd++) { 1043 1044 if (pa + bsize == epa) 1045 c = DBDMA_CMD_OUT_LAST; 1046 1047 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1048 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1049 } 1050 1051 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1052 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1053 dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr); 1054 1055 dbdma_start(sc->sc_odma, sc->sc_odbdma); 1056 1057 return 0; 1058 } 1059 1060 int 1061 awacs_trigger_input(void *h, void *start, void *end, int bsize, 1062 void (*intr)(void *), void *arg, struct audio_params *param) 1063 { 1064 struct awacs_softc *sc = h; 1065 struct awacs_dma *p; 1066 struct dbdma_command *cmd = sc->sc_idmacmd; 1067 vaddr_t spa, pa, epa; 1068 int c; 1069 1070 printf("trigger_input %p %p 0x%x\n", start, end, bsize); 1071 1072 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1073 if (!p) 1074 return -1; 1075 1076 sc->sc_iintr = intr; 1077 sc->sc_iarg = arg; 1078 sc->sc_idmap = sc->sc_idmacmd; 1079 1080 spa = p->segs[0].ds_addr; 1081 c = DBDMA_CMD_IN_MORE; 1082 for (pa = spa, epa = spa + (end - start); 1083 pa < epa; pa += bsize, cmd++) { 1084 1085 if (pa + bsize == epa) 1086 c = DBDMA_CMD_IN_LAST; 1087 1088 DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS, 1089 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1090 } 1091 1092 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 1093 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 1094 dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr); 1095 1096 dbdma_start(sc->sc_idma, sc->sc_idbdma); 1097 1098 return 0; 1099 } 1100 1101 void 1102 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right) 1103 { 1104 int lval = 15 - (left & 0xff) / 16; 1105 int rval = 15 - (right & 0xff) / 16; 1106 1107 DPRINTF("speaker_volume %d %d\n", lval, rval); 1108 1109 sc->sc_codecctl4 &= ~0x3cf; 1110 sc->sc_codecctl4 |= (lval << 6) | rval; 1111 awacs_write_codec(sc, sc->sc_codecctl4); 1112 } 1113 1114 void 1115 awacs_set_ext_volume(struct awacs_softc *sc, int left, int right) 1116 { 1117 int lval = 15 - (left & 0xff) / 16; 1118 int rval = 15 - (right & 0xff) / 16; 1119 1120 DPRINTF("ext_volume %d %d\n", lval, rval); 1121 1122 sc->sc_codecctl2 &= ~0x3cf; 1123 sc->sc_codecctl2 |= (lval << 6) | rval; 1124 awacs_write_codec(sc, sc->sc_codecctl2); 1125 } 1126 1127 void 1128 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p) 1129 { 1130 int selected = -1; 1131 size_t n, i; 1132 1133 n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]); 1134 1135 if (p->sample_rate < awacs_speeds[0].rate) 1136 selected = 0; 1137 if (p->sample_rate > awacs_speeds[n - 1].rate) 1138 selected = n - 1; 1139 1140 for (i = 1; selected == -1 && i < n; i++) { 1141 if (p->sample_rate == awacs_speeds[i].rate) 1142 selected = i; 1143 else if (p->sample_rate < awacs_speeds[i].rate) { 1144 u_int diff1, diff2; 1145 1146 diff1 = p->sample_rate - awacs_speeds[i - 1].rate; 1147 diff2 = awacs_speeds[i].rate - p->sample_rate; 1148 selected = (diff1 < diff2) ? i - 1 : i; 1149 } 1150 } 1151 1152 if (selected == -1) 1153 selected = 0; 1154 1155 sc->sc_soundctl &= ~AWACS_RATE_MASK; 1156 sc->sc_soundctl |= awacs_speeds[selected].bits; 1157 p->sample_rate = awacs_speeds[selected].rate; 1158 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl); 1159 } 1160