ce4231.c revision 1.34
1/* $OpenBSD: ce4231.c,v 1.34 2016/09/14 06:12:19 ratchov Exp $ */ 2 3/* 4 * Copyright (c) 1999 Jason L. Wright (jason@thought.net) 5 * 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Driver for CS4231 based audio found in some sun4u systems (cs4231) 31 * based on ideas from the S/Linux project and the NetBSD project. 32 * 33 * Effort sponsored in part by the Defense Advanced Research Projects 34 * Agency (DARPA) and Air Force Research Laboratory, Air Force 35 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 36 * 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/errno.h> 42#include <sys/ioctl.h> 43#include <sys/device.h> 44#include <sys/proc.h> 45#include <sys/malloc.h> 46 47#include <machine/cpu.h> 48#include <machine/bus.h> 49#include <machine/intr.h> 50#include <machine/autoconf.h> 51 52#include <sys/audioio.h> 53#include <dev/audio_if.h> 54 55#include <sparc64/dev/ebusreg.h> 56#include <sparc64/dev/ebusvar.h> 57#include <sparc64/dev/ce4231var.h> 58 59/* AD1418 provides basic registers, CS4231 extends with more */ 60#include <dev/ic/ad1848reg.h> 61#include <dev/ic/cs4231reg.h> 62 63/* Mixer classes and mixer knobs */ 64#define CSAUDIO_INPUT_CLASS 0 65#define CSAUDIO_OUTPUT_CLASS 1 66#define CSAUDIO_RECORD_CLASS 2 67#define CSAUDIO_DAC_LVL 3 68#define CSAUDIO_DAC_MUTE 4 69#define CSAUDIO_OUTPUTS 5 70#define CSAUDIO_CD_LVL 6 71#define CSAUDIO_CD_MUTE 7 72#define CSAUDIO_LINE_IN_LVL 8 73#define CSAUDIO_LINE_IN_MUTE 9 74#define CSAUDIO_MONITOR_LVL 10 75#define CSAUDIO_MONITOR_MUTE 11 76#define CSAUDIO_REC_LVL 12 77#define CSAUDIO_RECORD_SOURCE 13 78#define CSAUDIO_MIC_PREAMP 14 79 80/* Recording sources */ 81#define REC_PORT_LINE 0 82#define REC_PORT_CD 1 83#define REC_PORT_MIC 2 84#define REC_PORT_MIX 3 85 86/* Output ports. */ 87#define OUT_PORT_LINE 0x1 88#define OUT_PORT_HP 0x2 89#define OUT_PORT_SPKR 0x4 90 91/* Bits on the ADC reg that determine recording source */ 92#define CS_REC_SRC_BITS 0xc0 93 94#ifdef AUDIO_DEBUG 95#define DPRINTF(x) printf x 96#else 97#define DPRINTF(x) 98#endif 99 100#define CS_TIMEOUT 90000 101 102/* Read/write CS4231 direct registers */ 103#define CS_WRITE(sc,r,v) \ 104 bus_space_write_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2, (v)) 105#define CS_READ(sc,r) \ 106 bus_space_read_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2) 107 108/* Read/write EBDMA playback registers */ 109#define P_WRITE(sc,r,v) \ 110 bus_space_write_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r), (v)) 111#define P_READ(sc,r) \ 112 bus_space_read_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r)) 113 114/* Read/write EBDMA capture registers */ 115#define C_WRITE(sc,r,v) \ 116 bus_space_write_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r), (v)) 117#define C_READ(sc,r) \ 118 bus_space_read_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r)) 119 120int ce4231_match(struct device *, void *, void *); 121void ce4231_attach(struct device *, struct device *, void *); 122int ce4231_cintr(void *); 123int ce4231_pintr(void *); 124 125int ce4231_set_speed(struct ce4231_softc *, u_long *); 126 127void ce4231_set_outputs(struct ce4231_softc *, int); 128int ce4231_get_outputs(struct ce4231_softc *); 129 130void ce4231_write(struct ce4231_softc *, u_int8_t, u_int8_t); 131u_int8_t ce4231_read(struct ce4231_softc *, u_int8_t); 132 133/* Audio interface */ 134int ce4231_open(void *, int); 135void ce4231_close(void *); 136int ce4231_set_params(void *, int, int, struct audio_params *, 137 struct audio_params *); 138int ce4231_round_blocksize(void *, int); 139int ce4231_commit_settings(void *); 140int ce4231_halt_output(void *); 141int ce4231_halt_input(void *); 142int ce4231_getdev(void *, struct audio_device *); 143int ce4231_set_port(void *, mixer_ctrl_t *); 144int ce4231_get_port(void *, mixer_ctrl_t *); 145int ce4231_query_devinfo(void *addr, mixer_devinfo_t *); 146void * ce4231_alloc(void *, int, size_t, int, int); 147void ce4231_free(void *, void *, int); 148int ce4231_get_props(void *); 149int ce4231_trigger_output(void *, void *, void *, int, 150 void (*intr)(void *), void *arg, struct audio_params *); 151int ce4231_trigger_input(void *, void *, void *, int, 152 void (*intr)(void *), void *arg, struct audio_params *); 153 154struct audio_hw_if ce4231_sa_hw_if = { 155 ce4231_open, 156 ce4231_close, 157 ce4231_set_params, 158 ce4231_round_blocksize, 159 ce4231_commit_settings, 160 0, 161 0, 162 0, 163 0, 164 ce4231_halt_output, 165 ce4231_halt_input, 166 0, 167 ce4231_getdev, 168 0, 169 ce4231_set_port, 170 ce4231_get_port, 171 ce4231_query_devinfo, 172 ce4231_alloc, 173 ce4231_free, 174 0, 175 ce4231_get_props, 176 ce4231_trigger_output, 177 ce4231_trigger_input 178}; 179 180struct cfattach audioce_ca = { 181 sizeof (struct ce4231_softc), ce4231_match, ce4231_attach 182}; 183 184struct cfdriver audioce_cd = { 185 NULL, "audioce", DV_DULL 186}; 187 188struct audio_device ce4231_device = { 189 "SUNW,CS4231", 190 "b", 191 "onboard1", 192}; 193 194int 195ce4231_match(parent, vcf, aux) 196 struct device *parent; 197 void *vcf, *aux; 198{ 199 struct ebus_attach_args *ea = aux; 200 201 if (!strcmp("SUNW,CS4231", ea->ea_name) || 202 !strcmp("audio", ea->ea_name)) 203 return (1); 204 return (0); 205} 206 207void 208ce4231_attach(parent, self, aux) 209 struct device *parent, *self; 210 void *aux; 211{ 212 struct ebus_attach_args *ea = aux; 213 struct ce4231_softc *sc = (struct ce4231_softc *)self; 214 mixer_ctrl_t cp; 215 int node; 216 217 node = ea->ea_node; 218 219 sc->sc_last_format = 0xffffffff; 220 221 /* Pass on the bus tags */ 222 sc->sc_bustag = ea->ea_memtag; 223 sc->sc_dmatag = ea->ea_dmatag; 224 225 /* Make sure things are sane. */ 226 if (ea->ea_nintrs != 2) { 227 printf(": expected 2 interrupts, got %d\n", ea->ea_nintrs); 228 return; 229 } 230 if (ea->ea_nregs != 4) { 231 printf(": expected 4 register set, got %d\n", 232 ea->ea_nregs); 233 return; 234 } 235 236 sc->sc_cih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[0], 237 IPL_AUDIO, BUS_INTR_ESTABLISH_MPSAFE, ce4231_cintr, 238 sc, self->dv_xname); 239 if (sc->sc_cih == NULL) { 240 printf(": couldn't establish capture interrupt\n"); 241 return; 242 } 243 sc->sc_pih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[1], 244 IPL_AUDIO, BUS_INTR_ESTABLISH_MPSAFE, ce4231_pintr, 245 sc, self->dv_xname); 246 if (sc->sc_pih == NULL) { 247 printf(": couldn't establish play interrupt1\n"); 248 return; 249 } 250 251 /* XXX what if prom has already mapped?! */ 252 253 if (ebus_bus_map(sc->sc_bustag, 0, 254 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 255 BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cshandle) != 0) { 256 printf(": couldn't map cs4231 registers\n"); 257 return; 258 } 259 260 if (ebus_bus_map(sc->sc_bustag, 0, 261 EBUS_PADDR_FROM_REG(&ea->ea_regs[1]), ea->ea_regs[1].size, 262 BUS_SPACE_MAP_LINEAR, 0, &sc->sc_pdmahandle) != 0) { 263 printf(": couldn't map dma1 registers\n"); 264 return; 265 } 266 267 if (ebus_bus_map(sc->sc_bustag, 0, 268 EBUS_PADDR_FROM_REG(&ea->ea_regs[2]), ea->ea_regs[2].size, 269 BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cdmahandle) != 0) { 270 printf(": couldn't map dma2 registers\n"); 271 return; 272 } 273 274 if (ebus_bus_map(sc->sc_bustag, 0, 275 EBUS_PADDR_FROM_REG(&ea->ea_regs[3]), ea->ea_regs[3].size, 276 BUS_SPACE_MAP_LINEAR, 0, &sc->sc_auxhandle) != 0) { 277 printf(": couldn't map aux registers\n"); 278 return; 279 } 280 281 printf(": nvaddrs %d\n", ea->ea_nvaddrs); 282 283 audio_attach_mi(&ce4231_sa_hw_if, sc, &sc->sc_dev); 284 285 /* Enable mode 2. */ 286 ce4231_write(sc, SP_MISC_INFO, ce4231_read(sc, SP_MISC_INFO) | MODE2); 287 288 /* Attenuate DAC, CD and line-in. -22.5 dB for all. */ 289 cp.dev = CSAUDIO_DAC_LVL; 290 cp.type = AUDIO_MIXER_VALUE; 291 cp.un.value.num_channels = 2; 292 cp.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 195; 293 cp.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 195; 294 ce4231_set_port(sc, &cp); 295 296 cp.dev = CSAUDIO_CD_LVL; 297 cp.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 135; 298 cp.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 135; 299 ce4231_set_port(sc, &cp); 300 301 cp.dev = CSAUDIO_LINE_IN_LVL; 302 ce4231_set_port(sc, &cp); 303 304 /* Unmute DAC, CD and line-in */ 305 cp.dev = CSAUDIO_DAC_MUTE; 306 cp.type = AUDIO_MIXER_ENUM; 307 cp.un.ord = 0; 308 ce4231_set_port(sc, &cp); 309 310 cp.dev = CSAUDIO_CD_MUTE; 311 ce4231_set_port(sc, &cp); 312 313 cp.dev = CSAUDIO_LINE_IN_MUTE; 314 ce4231_set_port(sc, &cp); 315 316 /* XXX get real burst... */ 317 sc->sc_burst = EBDCSR_BURST_8; 318} 319 320/* 321 * Write to one of the indexed registers of cs4231. 322 */ 323void 324ce4231_write(sc, r, v) 325 struct ce4231_softc *sc; 326 u_int8_t r, v; 327{ 328 CS_WRITE(sc, AD1848_IADDR, r); 329 CS_WRITE(sc, AD1848_IDATA, v); 330} 331 332/* 333 * Read from one of the indexed registers of cs4231. 334 */ 335u_int8_t 336ce4231_read(sc, r) 337 struct ce4231_softc *sc; 338 u_int8_t r; 339{ 340 CS_WRITE(sc, AD1848_IADDR, r); 341 return (CS_READ(sc, AD1848_IDATA)); 342} 343 344int 345ce4231_set_speed(sc, argp) 346 struct ce4231_softc *sc; 347 u_long *argp; 348 349{ 350 /* 351 * The available speeds are in the following table. Keep the speeds in 352 * the increasing order. 353 */ 354 typedef struct { 355 int speed; 356 u_char bits; 357 } speed_struct; 358 u_long arg = *argp; 359 360 static speed_struct speed_table[] = { 361 {5510, (0 << 1) | CLOCK_XTAL2}, 362 {5510, (0 << 1) | CLOCK_XTAL2}, 363 {6620, (7 << 1) | CLOCK_XTAL2}, 364 {8000, (0 << 1) | CLOCK_XTAL1}, 365 {9600, (7 << 1) | CLOCK_XTAL1}, 366 {11025, (1 << 1) | CLOCK_XTAL2}, 367 {16000, (1 << 1) | CLOCK_XTAL1}, 368 {18900, (2 << 1) | CLOCK_XTAL2}, 369 {22050, (3 << 1) | CLOCK_XTAL2}, 370 {27420, (2 << 1) | CLOCK_XTAL1}, 371 {32000, (3 << 1) | CLOCK_XTAL1}, 372 {33075, (6 << 1) | CLOCK_XTAL2}, 373 {33075, (4 << 1) | CLOCK_XTAL2}, 374 {44100, (5 << 1) | CLOCK_XTAL2}, 375 {48000, (6 << 1) | CLOCK_XTAL1}, 376 }; 377 378 int i, n, selected = -1; 379 380 n = sizeof(speed_table) / sizeof(speed_struct); 381 382 if (arg < speed_table[0].speed) 383 selected = 0; 384 if (arg > speed_table[n - 1].speed) 385 selected = n - 1; 386 387 for (i = 1; selected == -1 && i < n; i++) { 388 if (speed_table[i].speed == arg) 389 selected = i; 390 else if (speed_table[i].speed > arg) { 391 int diff1, diff2; 392 393 diff1 = arg - speed_table[i - 1].speed; 394 diff2 = speed_table[i].speed - arg; 395 if (diff1 < diff2) 396 selected = i - 1; 397 else 398 selected = i; 399 } 400 } 401 402 if (selected == -1) 403 selected = 3; 404 405 sc->sc_speed_bits = speed_table[selected].bits; 406 sc->sc_need_commit = 1; 407 *argp = speed_table[selected].speed; 408 409 return (0); 410} 411 412/* 413 * Audio interface functions 414 */ 415int 416ce4231_open(addr, flags) 417 void *addr; 418 int flags; 419{ 420 struct ce4231_softc *sc = addr; 421 int tries; 422 423 DPRINTF(("ce4231_open\n")); 424 425 if (sc->sc_open) 426 return (EBUSY); 427 428 sc->sc_open = 1; 429 sc->sc_rintr = 0; 430 sc->sc_rarg = 0; 431 sc->sc_pintr = 0; 432 sc->sc_parg = 0; 433 434 P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 435 C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 436 P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 437 C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 438 439 DELAY(20); 440 441 for (tries = CS_TIMEOUT; 442 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--) 443 DELAY(10); 444 if (tries == 0) 445 printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname); 446 447 ce4231_write(sc, SP_PIN_CONTROL, 448 ce4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE); 449 450 return (0); 451} 452 453void 454ce4231_close(addr) 455 void *addr; 456{ 457 struct ce4231_softc *sc = addr; 458 459 ce4231_halt_input(sc); 460 ce4231_halt_output(sc); 461 ce4231_write(sc, SP_PIN_CONTROL, 462 ce4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE)); 463 sc->sc_open = 0; 464} 465 466int 467ce4231_set_params(addr, setmode, usemode, p, r) 468 void *addr; 469 int setmode, usemode; 470 struct audio_params *p, *r; 471{ 472 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 473 int err, bits, enc = p->encoding; 474 475 if (p->precision > 16) 476 p->precision = 16; 477 switch (enc) { 478 case AUDIO_ENCODING_ULAW: 479 p->precision = 8; 480 bits = FMT_ULAW >> 5; 481 break; 482 case AUDIO_ENCODING_ALAW: 483 p->precision = 8; 484 bits = FMT_ALAW >> 5; 485 break; 486 case AUDIO_ENCODING_SLINEAR_LE: 487 p->precision = 16; 488 bits = FMT_TWOS_COMP >> 5; 489 break; 490 case AUDIO_ENCODING_SLINEAR_BE: 491 p->precision = 16; 492 bits = FMT_TWOS_COMP_BE >> 5; 493 break; 494 case AUDIO_ENCODING_ULINEAR_LE: 495 case AUDIO_ENCODING_ULINEAR_BE: 496 p->precision = 8; 497 break; 498 default: 499 return (EINVAL); 500 } 501 502 if (p->channels > 2) 503 p->channels = 2; 504 505 err = ce4231_set_speed(sc, &p->sample_rate); 506 if (err) 507 return (err); 508 509 p->bps = AUDIO_BPS(p->precision); 510 r->bps = AUDIO_BPS(r->precision); 511 p->msb = r->msb = 1; 512 513 sc->sc_format_bits = bits; 514 sc->sc_channels = p->channels; 515 sc->sc_precision = p->precision; 516 sc->sc_need_commit = 1; 517 return (0); 518} 519 520int 521ce4231_round_blocksize(addr, blk) 522 void *addr; 523 int blk; 524{ 525 return ((blk + 3) & (-4)); 526} 527 528int 529ce4231_commit_settings(addr) 530 void *addr; 531{ 532 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 533 int tries; 534 u_int8_t r, fs; 535 536 if (sc->sc_need_commit == 0) 537 return (0); 538 539 fs = sc->sc_speed_bits | (sc->sc_format_bits << 5); 540 if (sc->sc_channels == 2) 541 fs |= FMT_STEREO; 542 543 if (sc->sc_last_format == fs) { 544 sc->sc_need_commit = 0; 545 return (0); 546 } 547 548 /* XXX: this code is called before DMA (this intrs) is stopped */ 549 mtx_enter(&audio_lock); 550 551 r = ce4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE; 552 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE); 553 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG); 554 CS_WRITE(sc, AD1848_IDATA, r); 555 556 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT); 557 CS_WRITE(sc, AD1848_IDATA, fs); 558 CS_READ(sc, AD1848_IDATA); 559 CS_READ(sc, AD1848_IDATA); 560 tries = CS_TIMEOUT; 561 for (tries = CS_TIMEOUT; 562 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--) 563 DELAY(10); 564 if (tries == 0) 565 printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname); 566 567 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT); 568 CS_WRITE(sc, AD1848_IDATA, fs); 569 CS_READ(sc, AD1848_IDATA); 570 CS_READ(sc, AD1848_IDATA); 571 for (tries = CS_TIMEOUT; 572 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--) 573 DELAY(10); 574 if (tries == 0) 575 printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname); 576 577 CS_WRITE(sc, AD1848_IADDR, 0); 578 for (tries = CS_TIMEOUT; 579 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--) 580 DELAY(10); 581 if (tries == 0) 582 printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname); 583 584 CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT); 585 for (tries = CS_TIMEOUT; 586 tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--) 587 DELAY(10); 588 if (tries == 0) 589 printf("%s: timeout waiting for autocalibration\n", 590 sc->sc_dev.dv_xname); 591 592 mtx_leave(&audio_lock); 593 594 sc->sc_need_commit = 0; 595 return (0); 596} 597 598int 599ce4231_halt_output(addr) 600 void *addr; 601{ 602 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 603 604 P_WRITE(sc, EBDMA_DCSR, 605 P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 606 ce4231_write(sc, SP_INTERFACE_CONFIG, 607 ce4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE)); 608 return (0); 609} 610 611int 612ce4231_halt_input(addr) 613 void *addr; 614{ 615 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 616 617 C_WRITE(sc, EBDMA_DCSR, 618 C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 619 ce4231_write(sc, SP_INTERFACE_CONFIG, 620 ce4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE)); 621 return (0); 622} 623 624int 625ce4231_getdev(addr, retp) 626 void *addr; 627 struct audio_device *retp; 628{ 629 *retp = ce4231_device; 630 return (0); 631} 632 633void 634ce4231_set_outputs(struct ce4231_softc *sc, int mask) 635{ 636 u_int8_t val; 637 638 val = ce4231_read(sc, CS_MONO_IO_CONTROL) & ~MONO_OUTPUT_MUTE; 639 if (!(mask & OUT_PORT_SPKR)) 640 val |= MONO_OUTPUT_MUTE; 641 ce4231_write(sc, CS_MONO_IO_CONTROL, val); 642 643 val = ce4231_read(sc, SP_PIN_CONTROL) & ~(XCTL0_ENABLE | XCTL1_ENABLE); 644 if (!(mask & OUT_PORT_LINE)) 645 val |= XCTL0_ENABLE; 646 if (!(mask & OUT_PORT_HP)) 647 val |= XCTL1_ENABLE; 648 ce4231_write(sc, SP_PIN_CONTROL, val); 649} 650 651int 652ce4231_get_outputs(struct ce4231_softc *sc) 653{ 654 int mask = 0; 655 u_int8_t val; 656 657 if (!(ce4231_read(sc, CS_MONO_IO_CONTROL) & MONO_OUTPUT_MUTE)) 658 mask |= OUT_PORT_SPKR; 659 660 val = ce4231_read(sc, SP_PIN_CONTROL); 661 if (!(val & XCTL0_ENABLE)) 662 mask |= OUT_PORT_LINE; 663 if (!(val & XCTL1_ENABLE)) 664 mask |= OUT_PORT_HP; 665 666 return (mask); 667} 668 669int 670ce4231_set_port(void *addr, mixer_ctrl_t *cp) 671{ 672 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 673 u_int8_t l, r; 674 675 DPRINTF(("ce4231_set_port: dev=%d type=%d\n", cp->dev, cp->type)); 676 677 switch (cp->dev) { 678 679 case CSAUDIO_DAC_LVL: 680 if (cp->type != AUDIO_MIXER_VALUE) 681 return (EINVAL); 682 l = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) & 683 OUTPUT_ATTEN_MASK; 684 r = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) & 685 OUTPUT_ATTEN_MASK; 686 l |= (AUDIO_MAX_GAIN - 687 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 2; 688 r |= (AUDIO_MAX_GAIN - 689 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 2; 690 ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, l); 691 ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, r); 692 break; 693 case CSAUDIO_DAC_MUTE: 694 if (cp->type != AUDIO_MIXER_ENUM) 695 return (EINVAL); 696 l = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) & ~OUTPUT_MUTE; 697 r = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) & ~OUTPUT_MUTE; 698 if (cp->un.ord) { 699 l |= OUTPUT_MUTE; 700 r |= OUTPUT_MUTE; 701 } 702 ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, l); 703 ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, r); 704 break; 705 706 case CSAUDIO_OUTPUTS: 707 if (cp->type != AUDIO_MIXER_SET) 708 return (EINVAL); 709 ce4231_set_outputs(sc, cp->un.mask); 710 break; 711 712 case CSAUDIO_CD_LVL: 713 if (cp->type != AUDIO_MIXER_VALUE) 714 return (EINVAL); 715 l = ce4231_read(sc, SP_LEFT_AUX1_CONTROL) & 716 AUX_INPUT_ATTEN_MASK; 717 r = ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) & 718 AUX_INPUT_ATTEN_MASK; 719 l |= (AUDIO_MAX_GAIN - 720 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 3; 721 r |= (AUDIO_MAX_GAIN - 722 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 3; 723 ce4231_write(sc, SP_LEFT_AUX1_CONTROL, l); 724 ce4231_write(sc, SP_RIGHT_AUX1_CONTROL, r); 725 break; 726 case CSAUDIO_CD_MUTE: 727 if (cp->type != AUDIO_MIXER_ENUM) 728 return (EINVAL); 729 l = ce4231_read(sc, SP_LEFT_AUX1_CONTROL) & ~AUX_INPUT_MUTE; 730 r = ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) & ~AUX_INPUT_MUTE; 731 if (cp->un.ord) { 732 l |= AUX_INPUT_MUTE; 733 r |= AUX_INPUT_MUTE; 734 } 735 ce4231_write(sc, SP_LEFT_AUX1_CONTROL, l); 736 ce4231_write(sc, SP_RIGHT_AUX1_CONTROL, r); 737 break; 738 739 case CSAUDIO_LINE_IN_LVL: 740 if (cp->type != AUDIO_MIXER_VALUE) 741 return (EINVAL); 742 l = ce4231_read(sc, CS_LEFT_LINE_CONTROL) & 743 LINE_INPUT_ATTEN_MASK; 744 r = ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & 745 LINE_INPUT_ATTEN_MASK; 746 l |= (AUDIO_MAX_GAIN - 747 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 3; 748 r |= (AUDIO_MAX_GAIN - 749 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 3; 750 ce4231_write(sc, CS_LEFT_LINE_CONTROL, l); 751 ce4231_write(sc, CS_RIGHT_LINE_CONTROL, r); 752 break; 753 case CSAUDIO_LINE_IN_MUTE: 754 l = ce4231_read(sc, CS_LEFT_LINE_CONTROL) & ~LINE_INPUT_MUTE; 755 r = ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & ~LINE_INPUT_MUTE; 756 if (cp->un.ord) { 757 l |= LINE_INPUT_MUTE; 758 r |= LINE_INPUT_MUTE; 759 } 760 ce4231_write(sc, CS_LEFT_LINE_CONTROL, l); 761 ce4231_write(sc, CS_RIGHT_LINE_CONTROL, r); 762 break; 763 764 case CSAUDIO_MONITOR_LVL: 765 if (cp->type != AUDIO_MIXER_VALUE) 766 return (EINVAL); 767 if (cp->un.value.num_channels != 1) 768 return (EINVAL); 769 l = ce4231_read(sc, SP_DIGITAL_MIX) & ~MIX_ATTEN_MASK; 770 l |= (AUDIO_MAX_GAIN - 771 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]) & 772 MIX_ATTEN_MASK; 773 ce4231_write(sc, SP_DIGITAL_MIX, l); 774 break; 775 case CSAUDIO_MONITOR_MUTE: 776 if (cp->type != AUDIO_MIXER_ENUM) 777 return (EINVAL); 778 l = ce4231_read(sc, SP_DIGITAL_MIX) & ~DIGITAL_MIX1_ENABLE; 779 if (!cp->un.ord) 780 l |= DIGITAL_MIX1_ENABLE; 781 ce4231_write(sc, SP_DIGITAL_MIX, l); 782 break; 783 784 case CSAUDIO_REC_LVL: 785 if (cp->type != AUDIO_MIXER_VALUE) 786 return (EINVAL); 787 l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & INPUT_GAIN_MASK; 788 r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & INPUT_GAIN_MASK; 789 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] >> 4; 790 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] >> 4; 791 ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l); 792 ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r); 793 break; 794 case CSAUDIO_RECORD_SOURCE: 795 if (cp->type != AUDIO_MIXER_ENUM) 796 return (EINVAL); 797 l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & INPUT_SOURCE_MASK; 798 r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & INPUT_SOURCE_MASK; 799 l |= cp->un.ord << 6; 800 r |= cp->un.ord << 6; 801 ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l); 802 ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r); 803 break; 804 805 case CSAUDIO_MIC_PREAMP: 806 if (cp->type != AUDIO_MIXER_ENUM) 807 return (EINVAL); 808 l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & 809 ~INPUT_MIC_GAIN_ENABLE; 810 r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & 811 ~INPUT_MIC_GAIN_ENABLE; 812 if (cp->un.ord) { 813 l |= INPUT_MIC_GAIN_ENABLE; 814 r |= INPUT_MIC_GAIN_ENABLE; 815 } 816 ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l); 817 ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r); 818 break; 819 820 default: 821 return (EINVAL); 822 } 823 824 return (0); 825} 826 827int 828ce4231_get_port(void *addr, mixer_ctrl_t *cp) 829{ 830 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 831 832 DPRINTF(("ce4231_get_port: port=%d type=%d\n", cp->dev, cp->type)); 833 834 switch (cp->dev) { 835 836 case CSAUDIO_DAC_LVL: 837 if (cp->type != AUDIO_MIXER_VALUE) 838 return (EINVAL); 839 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 840 AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) & 841 OUTPUT_ATTEN_BITS) << 2); 842 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 843 AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) & 844 OUTPUT_ATTEN_BITS) << 2); 845 break; 846 case CSAUDIO_DAC_MUTE: 847 if (cp->type != AUDIO_MIXER_ENUM) 848 return (EINVAL); 849 cp->un.ord = (ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) & 850 OUTPUT_MUTE) ? 1 : 0; 851 break; 852 853 case CSAUDIO_OUTPUTS: 854 if (cp->type != AUDIO_MIXER_SET) 855 return (EINVAL); 856 cp->un.mask = ce4231_get_outputs(sc); 857 break; 858 859 case CSAUDIO_CD_LVL: 860 if (cp->type != AUDIO_MIXER_VALUE) 861 return (EINVAL); 862 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 863 AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_LEFT_AUX1_CONTROL) & 864 AUX_INPUT_ATTEN_BITS) << 3); 865 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 866 AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) & 867 AUX_INPUT_ATTEN_BITS) << 3); 868 break; 869 case CSAUDIO_CD_MUTE: 870 if (cp->type != AUDIO_MIXER_ENUM) 871 return (EINVAL); 872 cp->un.ord = (ce4231_read(sc, SP_LEFT_AUX1_CONTROL) & 873 AUX_INPUT_MUTE) ? 1 : 0; 874 break; 875 876 case CSAUDIO_LINE_IN_LVL: 877 if (cp->type != AUDIO_MIXER_VALUE) 878 return (EINVAL); 879 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 880 AUDIO_MAX_GAIN - ((ce4231_read(sc, CS_LEFT_LINE_CONTROL) & 881 LINE_INPUT_ATTEN_BITS) << 3); 882 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 883 AUDIO_MAX_GAIN - ((ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & 884 LINE_INPUT_ATTEN_BITS) << 3); 885 break; 886 case CSAUDIO_LINE_IN_MUTE: 887 if (cp->type != AUDIO_MIXER_ENUM) 888 return (EINVAL); 889 cp->un.ord = (ce4231_read(sc, CS_LEFT_LINE_CONTROL) & 890 LINE_INPUT_MUTE) ? 1 : 0; 891 break; 892 893 case CSAUDIO_MONITOR_LVL: 894 if (cp->type != AUDIO_MIXER_VALUE) 895 return (EINVAL); 896 if (cp->un.value.num_channels != 1) 897 return (EINVAL); 898 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 899 AUDIO_MAX_GAIN - (ce4231_read(sc, SP_DIGITAL_MIX) & 900 MIX_ATTEN_MASK); 901 break; 902 case CSAUDIO_MONITOR_MUTE: 903 if (cp->type != AUDIO_MIXER_ENUM) 904 return (EINVAL); 905 cp->un.ord = (ce4231_read(sc, SP_DIGITAL_MIX) & 906 DIGITAL_MIX1_ENABLE) ? 0 : 1; 907 break; 908 909 case CSAUDIO_REC_LVL: 910 if (cp->type != AUDIO_MIXER_VALUE) 911 return (EINVAL); 912 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 913 (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & 914 ~INPUT_GAIN_MASK) << 4; 915 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 916 (ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & 917 ~INPUT_GAIN_MASK) << 4; 918 break; 919 case CSAUDIO_RECORD_SOURCE: 920 if (cp->type != AUDIO_MIXER_ENUM) 921 return (EINVAL); 922 cp->un.ord = (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & 923 CS_REC_SRC_BITS) >> 6; 924 break; 925 926 case CSAUDIO_MIC_PREAMP: 927 if (cp->type != AUDIO_MIXER_ENUM) 928 return (EINVAL); 929 cp->un.ord = (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & 930 INPUT_MIC_GAIN_ENABLE) ? 1 : 0; 931 break; 932 933 default: 934 return (EINVAL); 935 } 936 return (0); 937} 938 939int 940ce4231_query_devinfo(void *addr, mixer_devinfo_t *dip) 941{ 942 size_t nsize = MAX_AUDIO_DEV_LEN; 943 int err = 0; 944 945 switch (dip->index) { 946 case CSAUDIO_INPUT_CLASS: 947 dip->type = AUDIO_MIXER_CLASS; 948 dip->mixer_class = CSAUDIO_INPUT_CLASS; 949 dip->prev = dip->next = AUDIO_MIXER_LAST; 950 strlcpy(dip->label.name, AudioCinputs, nsize); 951 break; 952 case CSAUDIO_OUTPUT_CLASS: 953 dip->type = AUDIO_MIXER_CLASS; 954 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 955 dip->prev = dip->next = AUDIO_MIXER_LAST; 956 strlcpy(dip->label.name, AudioCoutputs, nsize); 957 break; 958 case CSAUDIO_RECORD_CLASS: 959 dip->type = AUDIO_MIXER_CLASS; 960 dip->mixer_class = CSAUDIO_RECORD_CLASS; 961 dip->prev = dip->next = AUDIO_MIXER_LAST; 962 strlcpy(dip->label.name, AudioCrecord, nsize); 963 break; 964 965 case CSAUDIO_DAC_LVL: 966 dip->type = AUDIO_MIXER_VALUE; 967 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 968 dip->prev = AUDIO_MIXER_LAST; 969 dip->next = CSAUDIO_DAC_MUTE; 970 strlcpy(dip->label.name, AudioNdac, nsize); 971 dip->un.v.num_channels = 2; 972 dip->un.v.delta = 4; 973 strlcpy(dip->un.v.units.name, AudioNvolume, nsize); 974 break; 975 case CSAUDIO_DAC_MUTE: 976 dip->type = AUDIO_MIXER_ENUM; 977 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 978 dip->prev = CSAUDIO_DAC_LVL; 979 dip->next = AUDIO_MIXER_LAST; 980 strlcpy(dip->label.name, AudioNmute, nsize); 981 goto onoff; 982 983 case CSAUDIO_OUTPUTS: 984 dip->type = AUDIO_MIXER_SET; 985 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 986 dip->prev = dip->next = AUDIO_MIXER_LAST; 987 strlcpy(dip->label.name, AudioNoutput, nsize); 988 dip->un.s.num_mem = 3; 989 strlcpy(dip->un.s.member[0].label.name, AudioNline, nsize); 990 dip->un.s.member[0].mask = OUT_PORT_LINE; 991 strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, nsize); 992 dip->un.s.member[1].mask = OUT_PORT_HP; 993 strlcpy(dip->un.s.member[2].label.name, AudioNspeaker, nsize); 994 dip->un.s.member[2].mask = OUT_PORT_SPKR; 995 break; 996 997 case CSAUDIO_CD_LVL: 998 dip->type = AUDIO_MIXER_VALUE; 999 dip->mixer_class = CSAUDIO_INPUT_CLASS; 1000 dip->prev = AUDIO_MIXER_LAST; 1001 dip->next = CSAUDIO_CD_MUTE; 1002 strlcpy(dip->label.name, AudioNcd, nsize); 1003 dip->un.v.num_channels = 2; 1004 dip->un.v.delta = 8; 1005 strlcpy(dip->un.v.units.name, AudioNvolume, nsize); 1006 break; 1007 case CSAUDIO_CD_MUTE: 1008 dip->type = AUDIO_MIXER_ENUM; 1009 dip->mixer_class = CSAUDIO_INPUT_CLASS; 1010 dip->prev = CSAUDIO_CD_LVL; 1011 dip->next = AUDIO_MIXER_LAST; 1012 strlcpy(dip->label.name, AudioNmute, nsize); 1013 goto onoff; 1014 1015 case CSAUDIO_LINE_IN_LVL: 1016 dip->type = AUDIO_MIXER_VALUE; 1017 dip->mixer_class = CSAUDIO_INPUT_CLASS; 1018 dip->prev = AUDIO_MIXER_LAST; 1019 dip->next = CSAUDIO_LINE_IN_MUTE; 1020 strlcpy(dip->label.name, AudioNline, nsize); 1021 dip->un.v.num_channels = 2; 1022 dip->un.v.delta = 8; 1023 strlcpy(dip->un.v.units.name, AudioNvolume, nsize); 1024 break; 1025 case CSAUDIO_LINE_IN_MUTE: 1026 dip->type = AUDIO_MIXER_ENUM; 1027 dip->mixer_class = CSAUDIO_INPUT_CLASS; 1028 dip->prev = CSAUDIO_LINE_IN_LVL; 1029 dip->next = AUDIO_MIXER_LAST; 1030 strlcpy(dip->label.name, AudioNmute, nsize); 1031 goto onoff; 1032 1033 case CSAUDIO_MONITOR_LVL: 1034 dip->type = AUDIO_MIXER_VALUE; 1035 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 1036 dip->prev = AUDIO_MIXER_LAST; 1037 dip->next = CSAUDIO_MONITOR_MUTE; 1038 strlcpy(dip->label.name, AudioNmonitor, nsize); 1039 dip->un.v.num_channels = 1; 1040 dip->un.v.delta = 4; 1041 strlcpy(dip->un.v.units.name, AudioNvolume, nsize); 1042 break; 1043 case CSAUDIO_MONITOR_MUTE: 1044 dip->type = AUDIO_MIXER_ENUM; 1045 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 1046 dip->prev = CSAUDIO_MONITOR_LVL; 1047 dip->next = AUDIO_MIXER_LAST; 1048 strlcpy(dip->label.name, AudioNmute, nsize); 1049 goto onoff; 1050 1051 case CSAUDIO_REC_LVL: 1052 dip->type = AUDIO_MIXER_VALUE; 1053 dip->mixer_class = CSAUDIO_RECORD_CLASS; 1054 dip->prev = dip->next = AUDIO_MIXER_LAST; 1055 strlcpy(dip->label.name, AudioNvolume, nsize); 1056 dip->un.v.num_channels = 2; 1057 dip->un.v.delta = 16; 1058 strlcpy(dip->un.v.units.name, AudioNvolume, nsize); 1059 break; 1060 case CSAUDIO_RECORD_SOURCE: 1061 dip->type = AUDIO_MIXER_ENUM; 1062 dip->mixer_class = CSAUDIO_RECORD_CLASS; 1063 dip->prev = dip->next = AUDIO_MIXER_LAST; 1064 strlcpy(dip->label.name, AudioNsource, nsize); 1065 dip->un.e.num_mem = 4; 1066 strlcpy(dip->un.e.member[0].label.name, AudioNline, nsize); 1067 dip->un.e.member[0].ord = REC_PORT_LINE; 1068 strlcpy(dip->un.e.member[1].label.name, AudioNcd, nsize); 1069 dip->un.e.member[1].ord = REC_PORT_CD; 1070 strlcpy(dip->un.e.member[2].label.name, AudioNmicrophone, nsize); 1071 dip->un.e.member[2].ord = REC_PORT_MIC; 1072 strlcpy(dip->un.e.member[3].label.name, AudioNmixerout, nsize); 1073 dip->un.e.member[3].ord = REC_PORT_MIX; 1074 break; 1075 1076 case CSAUDIO_MIC_PREAMP: 1077 dip->type = AUDIO_MIXER_ENUM; 1078 dip->mixer_class = CSAUDIO_RECORD_CLASS; 1079 dip->prev = dip->next = AUDIO_MIXER_LAST; 1080 snprintf(dip->label.name, nsize, "%s_%s", AudioNmicrophone, 1081 AudioNpreamp); 1082 goto onoff; 1083 1084onoff: 1085 dip->un.e.num_mem = 2; 1086 strlcpy(dip->un.e.member[0].label.name, AudioNon, nsize); 1087 dip->un.e.member[0].ord = 1; 1088 strlcpy(dip->un.e.member[1].label.name, AudioNoff, nsize); 1089 dip->un.e.member[1].ord = 0; 1090 break; 1091 1092 default: 1093 err = ENXIO; 1094 } 1095 1096 return (err); 1097} 1098 1099int 1100ce4231_get_props(addr) 1101 void *addr; 1102{ 1103 return (AUDIO_PROP_FULLDUPLEX); 1104} 1105 1106/* 1107 * Hardware interrupt handler 1108 */ 1109/* 1110 * Don't bother with the AD1848_STATUS register. It's interrupt bit gets 1111 * set for both recording and playback interrupts. But we have separate 1112 * handlers for playback and recording, and if we clear the status in 1113 * one handler while there is an interrupt pending for the other direction 1114 * as well, we'll never notice the interrupt for the other direction. 1115 * 1116 * Instead rely solely on CS_IRQ_STATUS, which has separate bits for 1117 * playback and recording interrupts. Also note that resetting 1118 * AD1848_STATUS clears the interrupt bits in CS_IRQ_STATUS. 1119 */ 1120 1121int 1122ce4231_pintr(v) 1123 void *v; 1124{ 1125 struct ce4231_softc *sc = (struct ce4231_softc *)v; 1126 u_int32_t csr; 1127 u_int8_t reg; 1128 struct cs_dma *p; 1129 struct cs_chdma *chdma = &sc->sc_pchdma; 1130 int r = 0; 1131 1132 mtx_enter(&audio_lock); 1133 csr = P_READ(sc, EBDMA_DCSR); 1134 1135 reg = ce4231_read(sc, CS_IRQ_STATUS); 1136 if (reg & CS_IRQ_PI) { 1137 ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff); 1138 ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff); 1139 ce4231_write(sc, CS_IRQ_STATUS, reg & ~CS_IRQ_PI); 1140 } 1141 1142 P_WRITE(sc, EBDMA_DCSR, csr); 1143 1144 if (csr & EBDCSR_INT) 1145 r = 1; 1146 1147 if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) { 1148 u_long nextaddr, togo; 1149 1150 p = chdma->cur_dma; 1151 togo = chdma->segsz - chdma->count; 1152 if (togo == 0) { 1153 nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr; 1154 chdma->count = togo = chdma->blksz; 1155 } else { 1156 nextaddr = chdma->lastaddr; 1157 if (togo > chdma->blksz) 1158 togo = chdma->blksz; 1159 chdma->count += togo; 1160 } 1161 1162 P_WRITE(sc, EBDMA_DCNT, togo); 1163 P_WRITE(sc, EBDMA_DADDR, nextaddr); 1164 chdma->lastaddr = nextaddr + togo; 1165 1166 if (sc->sc_pintr != NULL) 1167 (*sc->sc_pintr)(sc->sc_parg); 1168 r = 1; 1169 } 1170 mtx_leave(&audio_lock); 1171 return (r); 1172} 1173 1174int 1175ce4231_cintr(v) 1176 void *v; 1177{ 1178 struct ce4231_softc *sc = (struct ce4231_softc *)v; 1179 u_int32_t csr; 1180 u_int8_t reg; 1181 struct cs_dma *p; 1182 struct cs_chdma *chdma = &sc->sc_rchdma; 1183 int r = 0; 1184 1185 mtx_enter(&audio_lock); 1186 csr = C_READ(sc, EBDMA_DCSR); 1187 1188 reg = ce4231_read(sc, CS_IRQ_STATUS); 1189 if (reg & CS_IRQ_CI) { 1190 ce4231_write(sc, CS_LOWER_REC_CNT, 0xff); 1191 ce4231_write(sc, CS_UPPER_REC_CNT, 0xff); 1192 ce4231_write(sc, CS_IRQ_STATUS, reg & ~CS_IRQ_CI); 1193 } 1194 1195 C_WRITE(sc, EBDMA_DCSR, csr); 1196 1197 if (csr & EBDCSR_INT) 1198 r = 1; 1199 1200 if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) { 1201 u_long nextaddr, togo; 1202 1203 p = chdma->cur_dma; 1204 togo = chdma->segsz - chdma->count; 1205 if (togo == 0) { 1206 nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr; 1207 chdma->count = togo = chdma->blksz; 1208 } else { 1209 nextaddr = chdma->lastaddr; 1210 if (togo > chdma->blksz) 1211 togo = chdma->blksz; 1212 chdma->count += togo; 1213 } 1214 1215 C_WRITE(sc, EBDMA_DCNT, togo); 1216 C_WRITE(sc, EBDMA_DADDR, nextaddr); 1217 chdma->lastaddr = nextaddr + togo; 1218 1219 if (sc->sc_rintr != NULL) 1220 (*sc->sc_rintr)(sc->sc_rarg); 1221 r = 1; 1222 } 1223 mtx_leave(&audio_lock); 1224 return (r); 1225} 1226 1227void * 1228ce4231_alloc(addr, direction, size, pool, flags) 1229 void *addr; 1230 int direction; 1231 size_t size; 1232 int pool; 1233 int flags; 1234{ 1235 struct ce4231_softc *sc = (struct ce4231_softc *)addr; 1236 bus_dma_tag_t dmat = sc->sc_dmatag; 1237 struct cs_dma *p; 1238 1239 p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags); 1240 if (p == NULL) 1241 return (NULL); 1242 1243 if (bus_dmamap_create(dmat, size, 1, size, 0, 1244 BUS_DMA_NOWAIT, &p->dmamap) != 0) 1245 goto fail; 1246 1247 p->size = size; 1248 1249 if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs, 1250 sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs, 1251 BUS_DMA_NOWAIT) != 0) 1252 goto fail1; 1253 1254 if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size, 1255 &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) 1256 goto fail2; 1257 1258 if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL, 1259 BUS_DMA_NOWAIT) != 0) 1260 goto fail3; 1261 1262 p->next = sc->sc_dmas; 1263 sc->sc_dmas = p; 1264 return (p->addr); 1265 1266fail3: 1267 bus_dmamem_unmap(dmat, p->addr, p->size); 1268fail2: 1269 bus_dmamem_free(dmat, p->segs, p->nsegs); 1270fail1: 1271 bus_dmamap_destroy(dmat, p->dmamap); 1272fail: 1273 free(p, pool, 0); 1274 return (NULL); 1275} 1276 1277void 1278ce4231_free(addr, ptr, pool) 1279 void *addr; 1280 void *ptr; 1281 int pool; 1282{ 1283 struct ce4231_softc *sc = addr; 1284 bus_dma_tag_t dmat = sc->sc_dmatag; 1285 struct cs_dma *p, **pp; 1286 1287 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) { 1288 if (p->addr != ptr) 1289 continue; 1290 bus_dmamap_unload(dmat, p->dmamap); 1291 bus_dmamem_unmap(dmat, p->addr, p->size); 1292 bus_dmamem_free(dmat, p->segs, p->nsegs); 1293 bus_dmamap_destroy(dmat, p->dmamap); 1294 *pp = p->next; 1295 free(p, pool, 0); 1296 return; 1297 } 1298 printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname); 1299} 1300 1301int 1302ce4231_trigger_output(addr, start, end, blksize, intr, arg, param) 1303 void *addr, *start, *end; 1304 int blksize; 1305 void (*intr)(void *); 1306 void *arg; 1307 struct audio_params *param; 1308{ 1309 struct ce4231_softc *sc = addr; 1310 struct cs_dma *p; 1311 struct cs_chdma *chdma = &sc->sc_pchdma; 1312 u_int32_t csr; 1313 vaddr_t n; 1314 1315 sc->sc_pintr = intr; 1316 sc->sc_parg = arg; 1317 1318 for (p = sc->sc_dmas; p->addr != start; p = p->next) 1319 /*EMPTY*/; 1320 if (p == NULL) { 1321 printf("%s: trigger_output: bad addr: %p\n", 1322 sc->sc_dev.dv_xname, start); 1323 return (EINVAL); 1324 } 1325 1326 n = (char *)end - (char *)start; 1327 1328 /* 1329 * Do only `blksize' at a time, so audio_pint() is kept 1330 * synchronous with us... 1331 */ 1332 chdma->cur_dma = p; 1333 chdma->blksz = blksize; 1334 chdma->segsz = n; 1335 1336 if (n > chdma->blksz) 1337 n = chdma->blksz; 1338 1339 chdma->count = n; 1340 1341 csr = P_READ(sc, EBDMA_DCSR); 1342 if (csr & EBDCSR_DMAEN) { 1343 P_WRITE(sc, EBDMA_DCNT, (u_long)n); 1344 P_WRITE(sc, EBDMA_DADDR, 1345 (u_long)p->dmamap->dm_segs[0].ds_addr); 1346 } else { 1347 P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1348 P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1349 1350 P_WRITE(sc, EBDMA_DCNT, (u_long)n); 1351 P_WRITE(sc, EBDMA_DADDR, 1352 (u_long)p->dmamap->dm_segs[0].ds_addr); 1353 1354 P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_DMAEN | 1355 EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN); 1356 1357 ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff); 1358 ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff); 1359 ce4231_write(sc, SP_INTERFACE_CONFIG, 1360 ce4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE); 1361 } 1362 chdma->lastaddr = p->dmamap->dm_segs[0].ds_addr + n; 1363 1364 return (0); 1365} 1366 1367int 1368ce4231_trigger_input(addr, start, end, blksize, intr, arg, param) 1369 void *addr, *start, *end; 1370 int blksize; 1371 void (*intr)(void *); 1372 void *arg; 1373 struct audio_params *param; 1374{ 1375 struct ce4231_softc *sc = addr; 1376 struct cs_dma *p; 1377 struct cs_chdma *chdma = &sc->sc_rchdma; 1378 u_int32_t csr; 1379 vaddr_t n; 1380 1381 sc->sc_rintr = intr; 1382 sc->sc_rarg = arg; 1383 1384 for (p = sc->sc_dmas; p->addr != start; p = p->next) 1385 /*EMPTY*/; 1386 if (p == NULL) { 1387 printf("%s: trigger_input: bad addr: %p\n", 1388 sc->sc_dev.dv_xname, start); 1389 return (EINVAL); 1390 } 1391 1392 n = (char *)end - (char *)start; 1393 1394 /* 1395 * Do only `blksize' at a time, so audio_rint() is kept 1396 * synchronous with us... 1397 */ 1398 chdma->cur_dma = p; 1399 chdma->blksz = blksize; 1400 chdma->segsz = n; 1401 1402 if (n > chdma->blksz) 1403 n = chdma->blksz; 1404 1405 chdma->count = n; 1406 1407 csr = C_READ(sc, EBDMA_DCSR); 1408 if (csr & EBDCSR_DMAEN) { 1409 C_WRITE(sc, EBDMA_DCNT, (u_long)n); 1410 C_WRITE(sc, EBDMA_DADDR, 1411 (u_long)p->dmamap->dm_segs[0].ds_addr); 1412 } else { 1413 C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1414 C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1415 1416 C_WRITE(sc, EBDMA_DCNT, (u_long)n); 1417 C_WRITE(sc, EBDMA_DADDR, 1418 (u_long)p->dmamap->dm_segs[0].ds_addr); 1419 1420 C_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_WRITE | 1421 EBDCSR_DMAEN | EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN); 1422 1423 ce4231_write(sc, CS_LOWER_REC_CNT, 0xff); 1424 ce4231_write(sc, CS_UPPER_REC_CNT, 0xff); 1425 ce4231_write(sc, SP_INTERFACE_CONFIG, 1426 ce4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE); 1427 } 1428 chdma->lastaddr = p->dmamap->dm_segs[0].ds_addr + n; 1429 1430 return (0); 1431} 1432