Annotation of sys/arch/sparc64/dev/ce4231.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ce4231.c,v 1.21 2005/09/08 15:25:54 martin 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: #include <dev/auconv.h>
! 55:
! 56: #include <sparc64/dev/ebusreg.h>
! 57: #include <sparc64/dev/ebusvar.h>
! 58: #include <sparc64/dev/ce4231var.h>
! 59:
! 60: #include <dev/ic/ad1848reg.h>
! 61: #include <dev/ic/cs4231reg.h>
! 62:
! 63: #define CSAUDIO_DAC_LVL 0
! 64: #define CSAUDIO_LINE_IN_LVL 1
! 65: #define CSAUDIO_MIC_LVL 2
! 66: #define CSAUDIO_CD_LVL 3
! 67: #define CSAUDIO_MONITOR_LVL 4
! 68: #define CSAUDIO_OUTPUT_LVL 5
! 69: #define CSAUDIO_LINE_IN_MUTE 6
! 70: #define CSAUDIO_DAC_MUTE 7
! 71: #define CSAUDIO_CD_MUTE 8
! 72: #define CSAUDIO_MIC_MUTE 9
! 73: #define CSAUDIO_MONITOR_MUTE 10
! 74: #define CSAUDIO_OUTPUT_MUTE 11
! 75: #define CSAUDIO_REC_LVL 12
! 76: #define CSAUDIO_RECORD_SOURCE 13
! 77: #define CSAUDIO_OUTPUT 14
! 78: #define CSAUDIO_INPUT_CLASS 15
! 79: #define CSAUDIO_OUTPUT_CLASS 16
! 80: #define CSAUDIO_RECORD_CLASS 17
! 81: #define CSAUDIO_MONITOR_CLASS 18
! 82:
! 83: #define CSPORT_AUX2 0
! 84: #define CSPORT_AUX1 1
! 85: #define CSPORT_DAC 2
! 86: #define CSPORT_LINEIN 3
! 87: #define CSPORT_MONO 4
! 88: #define CSPORT_MONITOR 5
! 89: #define CSPORT_SPEAKER 6
! 90: #define CSPORT_LINEOUT 7
! 91: #define CSPORT_HEADPHONE 8
! 92:
! 93: #define MIC_IN_PORT 0
! 94: #define LINE_IN_PORT 1
! 95: #define AUX1_IN_PORT 2
! 96: #define DAC_IN_PORT 3
! 97:
! 98: #ifdef AUDIO_DEBUG
! 99: #define DPRINTF(x) printf x
! 100: #else
! 101: #define DPRINTF(x)
! 102: #endif
! 103:
! 104: #define CS_TIMEOUT 90000
! 105:
! 106: #define CS_PC_LINEMUTE XCTL0_ENABLE
! 107: #define CS_PC_HDPHMUTE XCTL1_ENABLE
! 108: #define CS_AFS_PI 0x10
! 109:
! 110: /* Read/write CS4231 direct registers */
! 111: #define CS_WRITE(sc,r,v) \
! 112: bus_space_write_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2, (v))
! 113: #define CS_READ(sc,r) \
! 114: bus_space_read_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2)
! 115:
! 116: /* Read/write EBDMA playback registers */
! 117: #define P_WRITE(sc,r,v) \
! 118: bus_space_write_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r), (v))
! 119: #define P_READ(sc,r) \
! 120: bus_space_read_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r))
! 121:
! 122: /* Read/write EBDMA capture registers */
! 123: #define C_WRITE(sc,r,v) \
! 124: bus_space_write_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r), (v))
! 125: #define C_READ(sc,r) \
! 126: bus_space_read_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r))
! 127:
! 128: int ce4231_match(struct device *, void *, void *);
! 129: void ce4231_attach(struct device *, struct device *, void *);
! 130: int ce4231_cintr(void *);
! 131: int ce4231_pintr(void *);
! 132:
! 133: int ce4231_set_speed(struct ce4231_softc *, u_long *);
! 134: void ce4231_setup_output(struct ce4231_softc *sc);
! 135:
! 136: void ce4231_write(struct ce4231_softc *, u_int8_t, u_int8_t);
! 137: u_int8_t ce4231_read(struct ce4231_softc *, u_int8_t);
! 138:
! 139: /* Audio interface */
! 140: int ce4231_open(void *, int);
! 141: void ce4231_close(void *);
! 142: int ce4231_query_encoding(void *, struct audio_encoding *);
! 143: int ce4231_set_params(void *, int, int, struct audio_params *,
! 144: struct audio_params *);
! 145: int ce4231_round_blocksize(void *, int);
! 146: int ce4231_commit_settings(void *);
! 147: int ce4231_halt_output(void *);
! 148: int ce4231_halt_input(void *);
! 149: int ce4231_getdev(void *, struct audio_device *);
! 150: int ce4231_set_port(void *, mixer_ctrl_t *);
! 151: int ce4231_get_port(void *, mixer_ctrl_t *);
! 152: int ce4231_query_devinfo(void *addr, mixer_devinfo_t *);
! 153: void * ce4231_alloc(void *, int, size_t, int, int);
! 154: void ce4231_free(void *, void *, int);
! 155: int ce4231_get_props(void *);
! 156: int ce4231_trigger_output(void *, void *, void *, int,
! 157: void (*intr)(void *), void *arg, struct audio_params *);
! 158: int ce4231_trigger_input(void *, void *, void *, int,
! 159: void (*intr)(void *), void *arg, struct audio_params *);
! 160:
! 161: struct audio_hw_if ce4231_sa_hw_if = {
! 162: ce4231_open,
! 163: ce4231_close,
! 164: 0,
! 165: ce4231_query_encoding,
! 166: ce4231_set_params,
! 167: ce4231_round_blocksize,
! 168: ce4231_commit_settings,
! 169: 0,
! 170: 0,
! 171: 0,
! 172: 0,
! 173: ce4231_halt_output,
! 174: ce4231_halt_input,
! 175: 0,
! 176: ce4231_getdev,
! 177: 0,
! 178: ce4231_set_port,
! 179: ce4231_get_port,
! 180: ce4231_query_devinfo,
! 181: ce4231_alloc,
! 182: ce4231_free,
! 183: 0,
! 184: 0,
! 185: ce4231_get_props,
! 186: ce4231_trigger_output,
! 187: ce4231_trigger_input
! 188: };
! 189:
! 190: struct cfattach audioce_ca = {
! 191: sizeof (struct ce4231_softc), ce4231_match, ce4231_attach
! 192: };
! 193:
! 194: struct cfdriver audioce_cd = {
! 195: NULL, "audioce", DV_DULL
! 196: };
! 197:
! 198: struct audio_device ce4231_device = {
! 199: "SUNW,CS4231",
! 200: "b",
! 201: "onboard1",
! 202: };
! 203:
! 204: int
! 205: ce4231_match(parent, vcf, aux)
! 206: struct device *parent;
! 207: void *vcf, *aux;
! 208: {
! 209: struct ebus_attach_args *ea = aux;
! 210:
! 211: if (!strcmp("SUNW,CS4231", ea->ea_name) ||
! 212: !strcmp("audio", ea->ea_name))
! 213: return (1);
! 214: return (0);
! 215: }
! 216:
! 217: void
! 218: ce4231_attach(parent, self, aux)
! 219: struct device *parent, *self;
! 220: void *aux;
! 221: {
! 222: struct ebus_attach_args *ea = aux;
! 223: struct ce4231_softc *sc = (struct ce4231_softc *)self;
! 224: int node;
! 225:
! 226: node = ea->ea_node;
! 227:
! 228: sc->sc_last_format = 0xffffffff;
! 229:
! 230: /* Pass on the bus tags */
! 231: sc->sc_bustag = ea->ea_memtag;
! 232: sc->sc_dmatag = ea->ea_dmatag;
! 233:
! 234: /* Make sure things are sane. */
! 235: if (ea->ea_nintrs != 2) {
! 236: printf(": expected 2 interrupts, got %d\n", ea->ea_nintrs);
! 237: return;
! 238: }
! 239: if (ea->ea_nregs != 4) {
! 240: printf(": expected 4 register set, got %d\n",
! 241: ea->ea_nregs);
! 242: return;
! 243: }
! 244:
! 245: sc->sc_cih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[0],
! 246: IPL_AUDIO, 0, ce4231_cintr, sc, self->dv_xname);
! 247: if (sc->sc_cih == NULL) {
! 248: printf(": couldn't establish capture interrupt\n");
! 249: return;
! 250: }
! 251: sc->sc_pih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[1],
! 252: IPL_AUDIO, 0, ce4231_pintr, sc, self->dv_xname);
! 253: if (sc->sc_pih == NULL) {
! 254: printf(": couldn't establish play interrupt1\n");
! 255: return;
! 256: }
! 257:
! 258: /* XXX what if prom has already mapped?! */
! 259:
! 260: if (ebus_bus_map(sc->sc_bustag, 0,
! 261: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size,
! 262: BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cshandle) != 0) {
! 263: printf(": couldn't map cs4231 registers\n");
! 264: return;
! 265: }
! 266:
! 267: if (ebus_bus_map(sc->sc_bustag, 0,
! 268: EBUS_PADDR_FROM_REG(&ea->ea_regs[1]), ea->ea_regs[1].size,
! 269: BUS_SPACE_MAP_LINEAR, 0, &sc->sc_pdmahandle) != 0) {
! 270: printf(": couldn't map dma1 registers\n");
! 271: return;
! 272: }
! 273:
! 274: if (ebus_bus_map(sc->sc_bustag, 0,
! 275: EBUS_PADDR_FROM_REG(&ea->ea_regs[2]), ea->ea_regs[2].size,
! 276: BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cdmahandle) != 0) {
! 277: printf(": couldn't map dma2 registers\n");
! 278: return;
! 279: }
! 280:
! 281: if (ebus_bus_map(sc->sc_bustag, 0,
! 282: EBUS_PADDR_FROM_REG(&ea->ea_regs[3]), ea->ea_regs[3].size,
! 283: BUS_SPACE_MAP_LINEAR, 0, &sc->sc_auxhandle) != 0) {
! 284: printf(": couldn't map aux registers\n");
! 285: return;
! 286: }
! 287:
! 288: printf(": nvaddrs %d\n", ea->ea_nvaddrs);
! 289:
! 290: audio_attach_mi(&ce4231_sa_hw_if, sc, &sc->sc_dev);
! 291:
! 292: /* Default to speaker, unmuted, reasonable volume */
! 293: sc->sc_out_port = CSPORT_SPEAKER;
! 294: sc->sc_mute[CSPORT_SPEAKER] = 1;
! 295: sc->sc_mute[CSPORT_MONITOR] = 1;
! 296: sc->sc_volume[CSPORT_SPEAKER].left = 192;
! 297: sc->sc_volume[CSPORT_SPEAKER].right = 192;
! 298:
! 299: /* XXX get real burst... */
! 300: sc->sc_burst = EBDCSR_BURST_8;
! 301: }
! 302:
! 303: /*
! 304: * Write to one of the indexed registers of cs4231.
! 305: */
! 306: void
! 307: ce4231_write(sc, r, v)
! 308: struct ce4231_softc *sc;
! 309: u_int8_t r, v;
! 310: {
! 311: CS_WRITE(sc, AD1848_IADDR, r);
! 312: CS_WRITE(sc, AD1848_IDATA, v);
! 313: }
! 314:
! 315: /*
! 316: * Read from one of the indexed registers of cs4231.
! 317: */
! 318: u_int8_t
! 319: ce4231_read(sc, r)
! 320: struct ce4231_softc *sc;
! 321: u_int8_t r;
! 322: {
! 323: CS_WRITE(sc, AD1848_IADDR, r);
! 324: return (CS_READ(sc, AD1848_IDATA));
! 325: }
! 326:
! 327: int
! 328: ce4231_set_speed(sc, argp)
! 329: struct ce4231_softc *sc;
! 330: u_long *argp;
! 331:
! 332: {
! 333: /*
! 334: * The available speeds are in the following table. Keep the speeds in
! 335: * the increasing order.
! 336: */
! 337: typedef struct {
! 338: int speed;
! 339: u_char bits;
! 340: } speed_struct;
! 341: u_long arg = *argp;
! 342:
! 343: static speed_struct speed_table[] = {
! 344: {5510, (0 << 1) | CLOCK_XTAL2},
! 345: {5510, (0 << 1) | CLOCK_XTAL2},
! 346: {6620, (7 << 1) | CLOCK_XTAL2},
! 347: {8000, (0 << 1) | CLOCK_XTAL1},
! 348: {9600, (7 << 1) | CLOCK_XTAL1},
! 349: {11025, (1 << 1) | CLOCK_XTAL2},
! 350: {16000, (1 << 1) | CLOCK_XTAL1},
! 351: {18900, (2 << 1) | CLOCK_XTAL2},
! 352: {22050, (3 << 1) | CLOCK_XTAL2},
! 353: {27420, (2 << 1) | CLOCK_XTAL1},
! 354: {32000, (3 << 1) | CLOCK_XTAL1},
! 355: {33075, (6 << 1) | CLOCK_XTAL2},
! 356: {33075, (4 << 1) | CLOCK_XTAL2},
! 357: {44100, (5 << 1) | CLOCK_XTAL2},
! 358: {48000, (6 << 1) | CLOCK_XTAL1},
! 359: };
! 360:
! 361: int i, n, selected = -1;
! 362:
! 363: n = sizeof(speed_table) / sizeof(speed_struct);
! 364:
! 365: if (arg < speed_table[0].speed)
! 366: selected = 0;
! 367: if (arg > speed_table[n - 1].speed)
! 368: selected = n - 1;
! 369:
! 370: for (i = 1; selected == -1 && i < n; i++) {
! 371: if (speed_table[i].speed == arg)
! 372: selected = i;
! 373: else if (speed_table[i].speed > arg) {
! 374: int diff1, diff2;
! 375:
! 376: diff1 = arg - speed_table[i - 1].speed;
! 377: diff2 = speed_table[i].speed - arg;
! 378: if (diff1 < diff2)
! 379: selected = i - 1;
! 380: else
! 381: selected = i;
! 382: }
! 383: }
! 384:
! 385: if (selected == -1)
! 386: selected = 3;
! 387:
! 388: sc->sc_speed_bits = speed_table[selected].bits;
! 389: sc->sc_need_commit = 1;
! 390: *argp = speed_table[selected].speed;
! 391:
! 392: return (0);
! 393: }
! 394:
! 395: /*
! 396: * Audio interface functions
! 397: */
! 398: int
! 399: ce4231_open(addr, flags)
! 400: void *addr;
! 401: int flags;
! 402: {
! 403: struct ce4231_softc *sc = addr;
! 404: int tries;
! 405:
! 406: if (sc->sc_open)
! 407: return (EBUSY);
! 408: sc->sc_open = 1;
! 409: sc->sc_locked = 0;
! 410: sc->sc_rintr = 0;
! 411: sc->sc_rarg = 0;
! 412: sc->sc_pintr = 0;
! 413: sc->sc_parg = 0;
! 414:
! 415: P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
! 416: C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
! 417: P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
! 418: C_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
! 419:
! 420: DELAY(20);
! 421:
! 422: for (tries = CS_TIMEOUT;
! 423: tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
! 424: DELAY(10);
! 425: if (tries == 0)
! 426: printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
! 427:
! 428: /* Turn on cs4231 mode */
! 429: ce4231_write(sc, SP_MISC_INFO,
! 430: ce4231_read(sc, SP_MISC_INFO) | MODE2);
! 431:
! 432: ce4231_setup_output(sc);
! 433:
! 434: ce4231_write(sc, SP_PIN_CONTROL,
! 435: ce4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
! 436:
! 437: return (0);
! 438: }
! 439:
! 440: void
! 441: ce4231_setup_output(sc)
! 442: struct ce4231_softc *sc;
! 443: {
! 444: u_int8_t pc, mi, rm, lm;
! 445:
! 446: pc = ce4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
! 447:
! 448: mi = ce4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
! 449:
! 450: lm = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
! 451: lm &= ~OUTPUT_ATTEN_BITS;
! 452: lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
! 453: OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
! 454:
! 455: rm = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
! 456: rm &= ~OUTPUT_ATTEN_BITS;
! 457: rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
! 458: OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
! 459:
! 460: if (sc->sc_mute[CSPORT_MONITOR]) {
! 461: lm &= ~OUTPUT_MUTE;
! 462: rm &= ~OUTPUT_MUTE;
! 463: }
! 464:
! 465: switch (sc->sc_out_port) {
! 466: case CSPORT_HEADPHONE:
! 467: if (sc->sc_mute[CSPORT_SPEAKER])
! 468: pc &= ~CS_PC_HDPHMUTE;
! 469: break;
! 470: case CSPORT_SPEAKER:
! 471: if (sc->sc_mute[CSPORT_SPEAKER])
! 472: mi &= ~MONO_OUTPUT_MUTE;
! 473: break;
! 474: case CSPORT_LINEOUT:
! 475: if (sc->sc_mute[CSPORT_SPEAKER])
! 476: pc &= ~CS_PC_LINEMUTE;
! 477: break;
! 478: }
! 479:
! 480: ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
! 481: ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
! 482: ce4231_write(sc, SP_PIN_CONTROL, pc);
! 483: ce4231_write(sc, CS_MONO_IO_CONTROL, mi);
! 484: }
! 485:
! 486: void
! 487: ce4231_close(addr)
! 488: void *addr;
! 489: {
! 490: struct ce4231_softc *sc = addr;
! 491:
! 492: ce4231_halt_input(sc);
! 493: ce4231_halt_output(sc);
! 494: ce4231_write(sc, SP_PIN_CONTROL,
! 495: ce4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
! 496: sc->sc_open = 0;
! 497: }
! 498:
! 499: int
! 500: ce4231_query_encoding(addr, fp)
! 501: void *addr;
! 502: struct audio_encoding *fp;
! 503: {
! 504: int err = 0;
! 505:
! 506: switch (fp->index) {
! 507: case 0:
! 508: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 509: fp->encoding = AUDIO_ENCODING_ULAW;
! 510: fp->precision = 8;
! 511: fp->flags = 0;
! 512: break;
! 513: case 1:
! 514: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 515: fp->encoding = AUDIO_ENCODING_ALAW;
! 516: fp->precision = 8;
! 517: fp->flags = 0;
! 518: break;
! 519: case 2:
! 520: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 521: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 522: fp->precision = 16;
! 523: fp->flags = 0;
! 524: break;
! 525: case 3:
! 526: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 527: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 528: fp->precision = 8;
! 529: fp->flags = 0;
! 530: break;
! 531: case 4:
! 532: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 533: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 534: fp->precision = 16;
! 535: fp->flags = 0;
! 536: break;
! 537: case 5:
! 538: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 539: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 540: fp->precision = 8;
! 541: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 542: break;
! 543: case 6:
! 544: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 545: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 546: fp->precision = 16;
! 547: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 548: break;
! 549: case 7:
! 550: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 551: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 552: fp->precision = 16;
! 553: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 554: break;
! 555: case 8:
! 556: strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
! 557: fp->encoding = AUDIO_ENCODING_ADPCM;
! 558: fp->precision = 8;
! 559: fp->flags = 0;
! 560: break;
! 561: default:
! 562: err = EINVAL;
! 563: }
! 564: return (err);
! 565: }
! 566:
! 567: int
! 568: ce4231_set_params(addr, setmode, usemode, p, r)
! 569: void *addr;
! 570: int setmode, usemode;
! 571: struct audio_params *p, *r;
! 572: {
! 573: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 574: int err, bits, enc = p->encoding;
! 575: void (*pswcode)(void *, u_char *, int cnt) = NULL;
! 576: void (*rswcode)(void *, u_char *, int cnt) = NULL;
! 577:
! 578: switch (enc) {
! 579: case AUDIO_ENCODING_ULAW:
! 580: if (p->precision != 8)
! 581: return (EINVAL);
! 582: bits = FMT_ULAW >> 5;
! 583: break;
! 584: case AUDIO_ENCODING_ALAW:
! 585: if (p->precision != 8)
! 586: return (EINVAL);
! 587: bits = FMT_ALAW >> 5;
! 588: break;
! 589: case AUDIO_ENCODING_SLINEAR_LE:
! 590: if (p->precision == 8) {
! 591: bits = FMT_PCM8 >> 5;
! 592: pswcode = rswcode = change_sign8;
! 593: } else if (p->precision == 16)
! 594: bits = FMT_TWOS_COMP >> 5;
! 595: else
! 596: return (EINVAL);
! 597: break;
! 598: case AUDIO_ENCODING_ULINEAR:
! 599: if (p->precision != 8)
! 600: return (EINVAL);
! 601: bits = FMT_PCM8 >> 5;
! 602: break;
! 603: case AUDIO_ENCODING_SLINEAR_BE:
! 604: if (p->precision == 8) {
! 605: bits = FMT_PCM8 >> 5;
! 606: pswcode = rswcode = change_sign8;
! 607: } else if (p->precision == 16)
! 608: bits = FMT_TWOS_COMP_BE >> 5;
! 609: else
! 610: return (EINVAL);
! 611: break;
! 612: case AUDIO_ENCODING_SLINEAR:
! 613: if (p->precision != 8)
! 614: return (EINVAL);
! 615: bits = FMT_PCM8 >> 5;
! 616: pswcode = rswcode = change_sign8;
! 617: break;
! 618: case AUDIO_ENCODING_ULINEAR_LE:
! 619: if (p->precision == 8)
! 620: bits = FMT_PCM8 >> 5;
! 621: else if (p->precision == 16) {
! 622: bits = FMT_TWOS_COMP >> 5;
! 623: pswcode = rswcode = change_sign16_le;
! 624: } else
! 625: return (EINVAL);
! 626: break;
! 627: case AUDIO_ENCODING_ULINEAR_BE:
! 628: if (p->precision == 8)
! 629: bits = FMT_PCM8 >> 5;
! 630: else if (p->precision == 16) {
! 631: bits = FMT_TWOS_COMP_BE >> 5;
! 632: pswcode = rswcode = change_sign16_be;
! 633: } else
! 634: return (EINVAL);
! 635: break;
! 636: case AUDIO_ENCODING_ADPCM:
! 637: if (p->precision != 8)
! 638: return (EINVAL);
! 639: bits = FMT_ADPCM >> 5;
! 640: break;
! 641: default:
! 642: return (EINVAL);
! 643: }
! 644:
! 645: if (p->channels != 1 && p->channels != 2)
! 646: return (EINVAL);
! 647:
! 648: err = ce4231_set_speed(sc, &p->sample_rate);
! 649: if (err)
! 650: return (err);
! 651:
! 652: p->sw_code = pswcode;
! 653: r->sw_code = rswcode;
! 654:
! 655: sc->sc_format_bits = bits;
! 656: sc->sc_channels = p->channels;
! 657: sc->sc_precision = p->precision;
! 658: sc->sc_need_commit = 1;
! 659: return (0);
! 660: }
! 661:
! 662: int
! 663: ce4231_round_blocksize(addr, blk)
! 664: void *addr;
! 665: int blk;
! 666: {
! 667: return ((blk + 3) & (-4));
! 668: }
! 669:
! 670: int
! 671: ce4231_commit_settings(addr)
! 672: void *addr;
! 673: {
! 674: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 675: int s, tries;
! 676: u_int8_t r, fs;
! 677:
! 678: if (sc->sc_need_commit == 0)
! 679: return (0);
! 680:
! 681: fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
! 682: if (sc->sc_channels == 2)
! 683: fs |= FMT_STEREO;
! 684:
! 685: if (sc->sc_last_format == fs) {
! 686: sc->sc_need_commit = 0;
! 687: return (0);
! 688: }
! 689:
! 690: s = splaudio();
! 691:
! 692: r = ce4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
! 693: CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
! 694: CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
! 695: CS_WRITE(sc, AD1848_IDATA, r);
! 696:
! 697: CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
! 698: CS_WRITE(sc, AD1848_IDATA, fs);
! 699: CS_READ(sc, AD1848_IDATA);
! 700: CS_READ(sc, AD1848_IDATA);
! 701: tries = CS_TIMEOUT;
! 702: for (tries = CS_TIMEOUT;
! 703: tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
! 704: DELAY(10);
! 705: if (tries == 0)
! 706: printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
! 707:
! 708: CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
! 709: CS_WRITE(sc, AD1848_IDATA, fs);
! 710: CS_READ(sc, AD1848_IDATA);
! 711: CS_READ(sc, AD1848_IDATA);
! 712: for (tries = CS_TIMEOUT;
! 713: tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
! 714: DELAY(10);
! 715: if (tries == 0)
! 716: printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
! 717:
! 718: CS_WRITE(sc, AD1848_IADDR, 0);
! 719: for (tries = CS_TIMEOUT;
! 720: tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
! 721: DELAY(10);
! 722: if (tries == 0)
! 723: printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
! 724:
! 725: CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
! 726: for (tries = CS_TIMEOUT;
! 727: tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
! 728: DELAY(10);
! 729: if (tries == 0)
! 730: printf("%s: timeout waiting for autocalibration\n",
! 731: sc->sc_dev.dv_xname);
! 732:
! 733: splx(s);
! 734:
! 735: sc->sc_need_commit = 0;
! 736: return (0);
! 737: }
! 738:
! 739: int
! 740: ce4231_halt_output(addr)
! 741: void *addr;
! 742: {
! 743: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 744:
! 745: P_WRITE(sc, EBDMA_DCSR,
! 746: P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
! 747: ce4231_write(sc, SP_INTERFACE_CONFIG,
! 748: ce4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
! 749: sc->sc_locked = 0;
! 750: return (0);
! 751: }
! 752:
! 753: int
! 754: ce4231_halt_input(addr)
! 755: void *addr;
! 756: {
! 757: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 758:
! 759: C_WRITE(sc, EBDMA_DCSR,
! 760: C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
! 761: ce4231_write(sc, SP_INTERFACE_CONFIG,
! 762: ce4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
! 763: sc->sc_locked = 0;
! 764: return (0);
! 765: }
! 766:
! 767: int
! 768: ce4231_getdev(addr, retp)
! 769: void *addr;
! 770: struct audio_device *retp;
! 771: {
! 772: *retp = ce4231_device;
! 773: return (0);
! 774: }
! 775:
! 776: int
! 777: ce4231_set_port(addr, cp)
! 778: void *addr;
! 779: mixer_ctrl_t *cp;
! 780: {
! 781: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 782: int error = EINVAL;
! 783:
! 784: DPRINTF(("ce4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
! 785:
! 786: switch (cp->dev) {
! 787: case CSAUDIO_DAC_LVL:
! 788: if (cp->type != AUDIO_MIXER_VALUE)
! 789: break;
! 790: if (cp->un.value.num_channels == 1)
! 791: ce4231_write(sc, SP_LEFT_AUX1_CONTROL,
! 792: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
! 793: LINE_INPUT_ATTEN_BITS);
! 794: else if (cp->un.value.num_channels == 2) {
! 795: ce4231_write(sc, SP_LEFT_AUX1_CONTROL,
! 796: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
! 797: LINE_INPUT_ATTEN_BITS);
! 798: ce4231_write(sc, SP_RIGHT_AUX1_CONTROL,
! 799: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
! 800: LINE_INPUT_ATTEN_BITS);
! 801: } else
! 802: break;
! 803: error = 0;
! 804: break;
! 805: case CSAUDIO_LINE_IN_LVL:
! 806: if (cp->type != AUDIO_MIXER_VALUE)
! 807: break;
! 808: if (cp->un.value.num_channels == 1)
! 809: ce4231_write(sc, CS_LEFT_LINE_CONTROL,
! 810: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
! 811: AUX_INPUT_ATTEN_BITS);
! 812: else if (cp->un.value.num_channels == 2) {
! 813: ce4231_write(sc, CS_LEFT_LINE_CONTROL,
! 814: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
! 815: AUX_INPUT_ATTEN_BITS);
! 816: ce4231_write(sc, CS_RIGHT_LINE_CONTROL,
! 817: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
! 818: AUX_INPUT_ATTEN_BITS);
! 819: } else
! 820: break;
! 821: error = 0;
! 822: break;
! 823: case CSAUDIO_MIC_LVL:
! 824: if (cp->type != AUDIO_MIXER_VALUE)
! 825: break;
! 826: if (cp->un.value.num_channels == 1) {
! 827: #if 0
! 828: ce4231_write(sc, CS_MONO_IO_CONTROL,
! 829: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
! 830: MONO_INPUT_ATTEN_BITS);
! 831: #endif
! 832: } else
! 833: break;
! 834: error = 0;
! 835: break;
! 836: case CSAUDIO_CD_LVL:
! 837: if (cp->type != AUDIO_MIXER_VALUE)
! 838: break;
! 839: if (cp->un.value.num_channels == 1) {
! 840: ce4231_write(sc, SP_LEFT_AUX2_CONTROL,
! 841: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
! 842: LINE_INPUT_ATTEN_BITS);
! 843: } else if (cp->un.value.num_channels == 2) {
! 844: ce4231_write(sc, SP_LEFT_AUX2_CONTROL,
! 845: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
! 846: LINE_INPUT_ATTEN_BITS);
! 847: ce4231_write(sc, SP_RIGHT_AUX2_CONTROL,
! 848: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
! 849: LINE_INPUT_ATTEN_BITS);
! 850: } else
! 851: break;
! 852: error = 0;
! 853: break;
! 854: case CSAUDIO_MONITOR_LVL:
! 855: if (cp->type != AUDIO_MIXER_VALUE)
! 856: break;
! 857: if (cp->un.value.num_channels == 1)
! 858: ce4231_write(sc, SP_DIGITAL_MIX,
! 859: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
! 860: else
! 861: break;
! 862: error = 0;
! 863: break;
! 864: case CSAUDIO_OUTPUT_LVL:
! 865: if (cp->type != AUDIO_MIXER_VALUE)
! 866: break;
! 867: if (cp->un.value.num_channels == 1) {
! 868: sc->sc_volume[CSPORT_SPEAKER].left =
! 869: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
! 870: sc->sc_volume[CSPORT_SPEAKER].right =
! 871: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
! 872: }
! 873: else if (cp->un.value.num_channels == 2) {
! 874: sc->sc_volume[CSPORT_SPEAKER].left =
! 875: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
! 876: sc->sc_volume[CSPORT_SPEAKER].right =
! 877: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
! 878: }
! 879: else
! 880: break;
! 881:
! 882: ce4231_setup_output(sc);
! 883: error = 0;
! 884: break;
! 885: case CSAUDIO_OUTPUT:
! 886: if (cp->type != AUDIO_MIXER_ENUM)
! 887: break;
! 888: if (cp->un.ord != CSPORT_LINEOUT &&
! 889: cp->un.ord != CSPORT_SPEAKER &&
! 890: cp->un.ord != CSPORT_HEADPHONE)
! 891: return (EINVAL);
! 892: sc->sc_out_port = cp->un.ord;
! 893: ce4231_setup_output(sc);
! 894: error = 0;
! 895: break;
! 896: case CSAUDIO_LINE_IN_MUTE:
! 897: if (cp->type != AUDIO_MIXER_ENUM)
! 898: break;
! 899: sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
! 900: error = 0;
! 901: break;
! 902: case CSAUDIO_DAC_MUTE:
! 903: if (cp->type != AUDIO_MIXER_ENUM)
! 904: break;
! 905: sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
! 906: error = 0;
! 907: break;
! 908: case CSAUDIO_CD_MUTE:
! 909: if (cp->type != AUDIO_MIXER_ENUM)
! 910: break;
! 911: sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
! 912: error = 0;
! 913: break;
! 914: case CSAUDIO_MIC_MUTE:
! 915: if (cp->type != AUDIO_MIXER_ENUM)
! 916: break;
! 917: sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
! 918: error = 0;
! 919: break;
! 920: case CSAUDIO_MONITOR_MUTE:
! 921: if (cp->type != AUDIO_MIXER_ENUM)
! 922: break;
! 923: sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
! 924: error = 0;
! 925: break;
! 926: case CSAUDIO_OUTPUT_MUTE:
! 927: if (cp->type != AUDIO_MIXER_ENUM)
! 928: break;
! 929: sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
! 930: ce4231_setup_output(sc);
! 931: error = 0;
! 932: break;
! 933: case CSAUDIO_REC_LVL:
! 934: if (cp->type != AUDIO_MIXER_VALUE)
! 935: break;
! 936: break;
! 937: case CSAUDIO_RECORD_SOURCE:
! 938: if (cp->type != AUDIO_MIXER_ENUM)
! 939: break;
! 940: break;
! 941: }
! 942:
! 943: return (error);
! 944: }
! 945:
! 946: int
! 947: ce4231_get_port(addr, cp)
! 948: void *addr;
! 949: mixer_ctrl_t *cp;
! 950: {
! 951: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 952: int error = EINVAL;
! 953:
! 954: DPRINTF(("ce4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
! 955:
! 956: switch (cp->dev) {
! 957: case CSAUDIO_DAC_LVL:
! 958: if (cp->type != AUDIO_MIXER_VALUE)
! 959: break;
! 960: if (cp->un.value.num_channels == 1)
! 961: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
! 962: ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
! 963: LINE_INPUT_ATTEN_BITS;
! 964: else if (cp->un.value.num_channels == 2) {
! 965: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 966: ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
! 967: LINE_INPUT_ATTEN_BITS;
! 968: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 969: ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
! 970: LINE_INPUT_ATTEN_BITS;
! 971: } else
! 972: break;
! 973: error = 0;
! 974: break;
! 975: case CSAUDIO_LINE_IN_LVL:
! 976: if (cp->type != AUDIO_MIXER_VALUE)
! 977: break;
! 978: if (cp->un.value.num_channels == 1)
! 979: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 980: ce4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
! 981: else if (cp->un.value.num_channels == 2) {
! 982: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 983: ce4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
! 984: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 985: ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
! 986: } else
! 987: break;
! 988: error = 0;
! 989: break;
! 990: case CSAUDIO_MIC_LVL:
! 991: if (cp->type != AUDIO_MIXER_VALUE)
! 992: break;
! 993: if (cp->un.value.num_channels == 1) {
! 994: #if 0
! 995: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 996: ce4231_read(sc, CS_MONO_IO_CONTROL) &
! 997: MONO_INPUT_ATTEN_BITS;
! 998: #endif
! 999: } else
! 1000: break;
! 1001: error = 0;
! 1002: break;
! 1003: case CSAUDIO_CD_LVL:
! 1004: if (cp->type != AUDIO_MIXER_VALUE)
! 1005: break;
! 1006: if (cp->un.value.num_channels == 1)
! 1007: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1008: ce4231_read(sc, SP_LEFT_AUX2_CONTROL) &
! 1009: LINE_INPUT_ATTEN_BITS;
! 1010: else if (cp->un.value.num_channels == 2) {
! 1011: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1012: ce4231_read(sc, SP_LEFT_AUX2_CONTROL) &
! 1013: LINE_INPUT_ATTEN_BITS;
! 1014: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1015: ce4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
! 1016: LINE_INPUT_ATTEN_BITS;
! 1017: }
! 1018: else
! 1019: break;
! 1020: error = 0;
! 1021: break;
! 1022: case CSAUDIO_MONITOR_LVL:
! 1023: if (cp->type != AUDIO_MIXER_VALUE)
! 1024: break;
! 1025: if (cp->un.value.num_channels != 1)
! 1026: break;
! 1027: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1028: ce4231_read(sc, SP_DIGITAL_MIX) >> 2;
! 1029: error = 0;
! 1030: break;
! 1031: case CSAUDIO_OUTPUT_LVL:
! 1032: if (cp->type != AUDIO_MIXER_VALUE)
! 1033: break;
! 1034: if (cp->un.value.num_channels == 1)
! 1035: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1036: sc->sc_volume[CSPORT_SPEAKER].left;
! 1037: else if (cp->un.value.num_channels == 2) {
! 1038: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1039: sc->sc_volume[CSPORT_SPEAKER].left;
! 1040: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1041: sc->sc_volume[CSPORT_SPEAKER].right;
! 1042: }
! 1043: else
! 1044: break;
! 1045: error = 0;
! 1046: break;
! 1047: case CSAUDIO_LINE_IN_MUTE:
! 1048: if (cp->type != AUDIO_MIXER_ENUM)
! 1049: break;
! 1050: cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
! 1051: error = 0;
! 1052: break;
! 1053: case CSAUDIO_DAC_MUTE:
! 1054: if (cp->type != AUDIO_MIXER_ENUM)
! 1055: break;
! 1056: cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
! 1057: error = 0;
! 1058: break;
! 1059: case CSAUDIO_CD_MUTE:
! 1060: if (cp->type != AUDIO_MIXER_ENUM)
! 1061: break;
! 1062: cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
! 1063: error = 0;
! 1064: break;
! 1065: case CSAUDIO_MIC_MUTE:
! 1066: if (cp->type != AUDIO_MIXER_ENUM)
! 1067: break;
! 1068: cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
! 1069: error = 0;
! 1070: break;
! 1071: case CSAUDIO_MONITOR_MUTE:
! 1072: if (cp->type != AUDIO_MIXER_ENUM)
! 1073: break;
! 1074: cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
! 1075: error = 0;
! 1076: break;
! 1077: case CSAUDIO_OUTPUT_MUTE:
! 1078: if (cp->type != AUDIO_MIXER_ENUM)
! 1079: break;
! 1080: cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
! 1081: error = 0;
! 1082: break;
! 1083: case CSAUDIO_REC_LVL:
! 1084: if (cp->type != AUDIO_MIXER_VALUE)
! 1085: break;
! 1086: if (cp->un.value.num_channels == 1) {
! 1087: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1088: AUDIO_MIN_GAIN;
! 1089: } else if (cp->un.value.num_channels == 2) {
! 1090: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1091: AUDIO_MIN_GAIN;
! 1092: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1093: AUDIO_MIN_GAIN;
! 1094: } else
! 1095: break;
! 1096: error = 0;
! 1097: break;
! 1098: case CSAUDIO_RECORD_SOURCE:
! 1099: if (cp->type != AUDIO_MIXER_ENUM)
! 1100: break;
! 1101: cp->un.ord = MIC_IN_PORT;
! 1102: error = 0;
! 1103: break;
! 1104: case CSAUDIO_OUTPUT:
! 1105: if (cp->type != AUDIO_MIXER_ENUM)
! 1106: break;
! 1107: cp->un.ord = sc->sc_out_port;
! 1108: error = 0;
! 1109: break;
! 1110: }
! 1111: return (error);
! 1112: }
! 1113:
! 1114: int
! 1115: ce4231_query_devinfo(addr, dip)
! 1116: void *addr;
! 1117: mixer_devinfo_t *dip;
! 1118: {
! 1119: int err = 0;
! 1120:
! 1121: switch (dip->index) {
! 1122: case CSAUDIO_MIC_LVL: /* mono/microphone mixer */
! 1123: dip->type = AUDIO_MIXER_VALUE;
! 1124: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1125: dip->prev = AUDIO_MIXER_LAST;
! 1126: dip->next = CSAUDIO_MIC_MUTE;
! 1127: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
! 1128: dip->un.v.num_channels = 1;
! 1129: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1130: sizeof dip->un.v.units.name);
! 1131: break;
! 1132: case CSAUDIO_DAC_LVL: /* dacout */
! 1133: dip->type = AUDIO_MIXER_VALUE;
! 1134: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1135: dip->prev = AUDIO_MIXER_LAST;
! 1136: dip->next = CSAUDIO_DAC_MUTE;
! 1137: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
! 1138: dip->un.v.num_channels = 2;
! 1139: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1140: sizeof dip->un.v.units.name);
! 1141: break;
! 1142: case CSAUDIO_LINE_IN_LVL: /* line */
! 1143: dip->type = AUDIO_MIXER_VALUE;
! 1144: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1145: dip->prev = AUDIO_MIXER_LAST;
! 1146: dip->next = CSAUDIO_LINE_IN_MUTE;
! 1147: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
! 1148: dip->un.v.num_channels = 2;
! 1149: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1150: sizeof dip->un.v.units.name);
! 1151: break;
! 1152: case CSAUDIO_CD_LVL: /* cd */
! 1153: dip->type = AUDIO_MIXER_VALUE;
! 1154: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1155: dip->prev = AUDIO_MIXER_LAST;
! 1156: dip->next = CSAUDIO_CD_MUTE;
! 1157: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
! 1158: dip->un.v.num_channels = 2;
! 1159: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1160: sizeof dip->un.v.units.name);
! 1161: break;
! 1162: case CSAUDIO_MONITOR_LVL: /* monitor level */
! 1163: dip->type = AUDIO_MIXER_VALUE;
! 1164: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
! 1165: dip->prev = AUDIO_MIXER_LAST;
! 1166: dip->next = CSAUDIO_MONITOR_MUTE;
! 1167: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
! 1168: dip->un.v.num_channels = 1;
! 1169: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1170: sizeof dip->un.v.units.name);
! 1171: break;
! 1172: case CSAUDIO_OUTPUT_LVL:
! 1173: dip->type = AUDIO_MIXER_VALUE;
! 1174: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
! 1175: dip->prev = AUDIO_MIXER_LAST;
! 1176: dip->next = CSAUDIO_OUTPUT_MUTE;
! 1177: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
! 1178: dip->un.v.num_channels = 2;
! 1179: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1180: sizeof dip->un.v.units.name);
! 1181: break;
! 1182: case CSAUDIO_LINE_IN_MUTE:
! 1183: dip->type = AUDIO_MIXER_ENUM;
! 1184: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1185: dip->prev = CSAUDIO_LINE_IN_LVL;
! 1186: dip->next = AUDIO_MIXER_LAST;
! 1187: goto mute;
! 1188: case CSAUDIO_DAC_MUTE:
! 1189: dip->type = AUDIO_MIXER_ENUM;
! 1190: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1191: dip->prev = CSAUDIO_DAC_LVL;
! 1192: dip->next = AUDIO_MIXER_LAST;
! 1193: goto mute;
! 1194: case CSAUDIO_CD_MUTE:
! 1195: dip->type = AUDIO_MIXER_ENUM;
! 1196: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1197: dip->prev = CSAUDIO_CD_LVL;
! 1198: dip->next = AUDIO_MIXER_LAST;
! 1199: goto mute;
! 1200: case CSAUDIO_MIC_MUTE:
! 1201: dip->type = AUDIO_MIXER_ENUM;
! 1202: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1203: dip->prev = CSAUDIO_MIC_LVL;
! 1204: dip->next = AUDIO_MIXER_LAST;
! 1205: goto mute;
! 1206: case CSAUDIO_MONITOR_MUTE:
! 1207: dip->type = AUDIO_MIXER_ENUM;
! 1208: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
! 1209: dip->prev = CSAUDIO_MONITOR_LVL;
! 1210: dip->next = AUDIO_MIXER_LAST;
! 1211: goto mute;
! 1212: case CSAUDIO_OUTPUT_MUTE:
! 1213: dip->type = AUDIO_MIXER_ENUM;
! 1214: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
! 1215: dip->prev = CSAUDIO_OUTPUT_LVL;
! 1216: dip->next = AUDIO_MIXER_LAST;
! 1217: goto mute;
! 1218:
! 1219: mute:
! 1220: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
! 1221: dip->un.e.num_mem = 2;
! 1222: strlcpy(dip->un.e.member[0].label.name, AudioNon,
! 1223: sizeof dip->un.e.member[0].label.name);
! 1224: dip->un.e.member[0].ord = 0;
! 1225: strlcpy(dip->un.e.member[1].label.name, AudioNoff,
! 1226: sizeof dip->un.e.member[1].label.name);
! 1227: dip->un.e.member[1].ord = 1;
! 1228: break;
! 1229: case CSAUDIO_REC_LVL: /* record level */
! 1230: dip->type = AUDIO_MIXER_VALUE;
! 1231: dip->mixer_class = CSAUDIO_RECORD_CLASS;
! 1232: dip->prev = AUDIO_MIXER_LAST;
! 1233: dip->next = CSAUDIO_RECORD_SOURCE;
! 1234: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
! 1235: dip->un.v.num_channels = 2;
! 1236: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1237: sizeof dip->un.v.units.name);
! 1238: break;
! 1239: case CSAUDIO_RECORD_SOURCE:
! 1240: dip->type = AUDIO_MIXER_ENUM;
! 1241: dip->mixer_class = CSAUDIO_RECORD_CLASS;
! 1242: dip->prev = CSAUDIO_REC_LVL;
! 1243: dip->next = AUDIO_MIXER_LAST;
! 1244: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
! 1245: dip->un.e.num_mem = 3;
! 1246: strlcpy(dip->un.e.member[0].label.name, AudioNcd,
! 1247: sizeof dip->un.e.member[0].label.name);
! 1248: dip->un.e.member[0].ord = DAC_IN_PORT;
! 1249: strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone,
! 1250: sizeof dip->un.e.member[1].label.name);
! 1251: dip->un.e.member[1].ord = MIC_IN_PORT;
! 1252: strlcpy(dip->un.e.member[2].label.name, AudioNdac,
! 1253: sizeof dip->un.e.member[2].label.name);
! 1254: dip->un.e.member[2].ord = AUX1_IN_PORT;
! 1255: strlcpy(dip->un.e.member[3].label.name, AudioNline,
! 1256: sizeof dip->un.e.member[3].label.name);
! 1257: dip->un.e.member[3].ord = LINE_IN_PORT;
! 1258: break;
! 1259: case CSAUDIO_OUTPUT:
! 1260: dip->type = AUDIO_MIXER_ENUM;
! 1261: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
! 1262: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 1263: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
! 1264: dip->un.e.num_mem = 3;
! 1265: strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
! 1266: sizeof dip->un.e.member[0].label.name);
! 1267: dip->un.e.member[0].ord = CSPORT_SPEAKER;
! 1268: strlcpy(dip->un.e.member[1].label.name, AudioNline,
! 1269: sizeof dip->un.e.member[1].label.name);
! 1270: dip->un.e.member[1].ord = CSPORT_LINEOUT;
! 1271: strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
! 1272: sizeof dip->un.e.member[2].label.name);
! 1273: dip->un.e.member[2].ord = CSPORT_HEADPHONE;
! 1274: break;
! 1275: case CSAUDIO_INPUT_CLASS: /* input class descriptor */
! 1276: dip->type = AUDIO_MIXER_CLASS;
! 1277: dip->mixer_class = CSAUDIO_INPUT_CLASS;
! 1278: dip->prev = AUDIO_MIXER_LAST;
! 1279: dip->next = AUDIO_MIXER_LAST;
! 1280: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
! 1281: break;
! 1282: case CSAUDIO_OUTPUT_CLASS: /* output class descriptor */
! 1283: dip->type = AUDIO_MIXER_CLASS;
! 1284: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
! 1285: dip->prev = AUDIO_MIXER_LAST;
! 1286: dip->next = AUDIO_MIXER_LAST;
! 1287: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
! 1288: break;
! 1289: case CSAUDIO_MONITOR_CLASS: /* monitor class descriptor */
! 1290: dip->type = AUDIO_MIXER_CLASS;
! 1291: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
! 1292: dip->prev = AUDIO_MIXER_LAST;
! 1293: dip->next = AUDIO_MIXER_LAST;
! 1294: strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
! 1295: break;
! 1296: case CSAUDIO_RECORD_CLASS: /* record class descriptor */
! 1297: dip->type = AUDIO_MIXER_CLASS;
! 1298: dip->mixer_class = CSAUDIO_RECORD_CLASS;
! 1299: dip->prev = AUDIO_MIXER_LAST;
! 1300: dip->next = AUDIO_MIXER_LAST;
! 1301: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
! 1302: break;
! 1303: default:
! 1304: err = ENXIO;
! 1305: }
! 1306:
! 1307: return (err);
! 1308: }
! 1309:
! 1310: int
! 1311: ce4231_get_props(addr)
! 1312: void *addr;
! 1313: {
! 1314: return (AUDIO_PROP_FULLDUPLEX);
! 1315: }
! 1316:
! 1317: /*
! 1318: * Hardware interrupt handler
! 1319: */
! 1320: int
! 1321: ce4231_cintr(v)
! 1322: void *v;
! 1323: {
! 1324: return (0);
! 1325: }
! 1326:
! 1327: int
! 1328: ce4231_pintr(v)
! 1329: void *v;
! 1330: {
! 1331: struct ce4231_softc *sc = (struct ce4231_softc *)v;
! 1332: u_int32_t csr;
! 1333: u_int8_t reg, status;
! 1334: struct cs_dma *p;
! 1335: int r = 0;
! 1336:
! 1337: csr = P_READ(sc, EBDMA_DCSR);
! 1338: status = CS_READ(sc, AD1848_STATUS);
! 1339: if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
! 1340: reg = ce4231_read(sc, CS_IRQ_STATUS);
! 1341: if (reg & CS_AFS_PI) {
! 1342: ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
! 1343: ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
! 1344: }
! 1345: CS_WRITE(sc, AD1848_STATUS, 0);
! 1346: }
! 1347:
! 1348: P_WRITE(sc, EBDMA_DCSR, csr);
! 1349:
! 1350: if (csr & EBDCSR_INT)
! 1351: r = 1;
! 1352:
! 1353: if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) {
! 1354: u_long nextaddr, togo;
! 1355:
! 1356: p = sc->sc_nowplaying;
! 1357: togo = sc->sc_playsegsz - sc->sc_playcnt;
! 1358: if (togo == 0) {
! 1359: nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
! 1360: sc->sc_playcnt = togo = sc->sc_blksz;
! 1361: } else {
! 1362: nextaddr = sc->sc_lastaddr;
! 1363: if (togo > sc->sc_blksz)
! 1364: togo = sc->sc_blksz;
! 1365: sc->sc_playcnt += togo;
! 1366: }
! 1367:
! 1368: P_WRITE(sc, EBDMA_DCNT, togo);
! 1369: P_WRITE(sc, EBDMA_DADDR, nextaddr);
! 1370: sc->sc_lastaddr = nextaddr + togo;
! 1371:
! 1372: if (sc->sc_pintr != NULL)
! 1373: (*sc->sc_pintr)(sc->sc_parg);
! 1374: r = 1;
! 1375: }
! 1376:
! 1377: return (r);
! 1378: }
! 1379:
! 1380: void *
! 1381: ce4231_alloc(addr, direction, size, pool, flags)
! 1382: void *addr;
! 1383: int direction;
! 1384: size_t size;
! 1385: int pool;
! 1386: int flags;
! 1387: {
! 1388: struct ce4231_softc *sc = (struct ce4231_softc *)addr;
! 1389: bus_dma_tag_t dmat = sc->sc_dmatag;
! 1390: struct cs_dma *p;
! 1391:
! 1392: p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
! 1393: if (p == NULL)
! 1394: return (NULL);
! 1395:
! 1396: if (bus_dmamap_create(dmat, size, 1, size, 0,
! 1397: BUS_DMA_NOWAIT, &p->dmamap) != 0)
! 1398: goto fail;
! 1399:
! 1400: p->size = size;
! 1401:
! 1402: if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
! 1403: sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs,
! 1404: BUS_DMA_NOWAIT) != 0)
! 1405: goto fail1;
! 1406:
! 1407: if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
! 1408: &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
! 1409: goto fail2;
! 1410:
! 1411: if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
! 1412: BUS_DMA_NOWAIT) != 0)
! 1413: goto fail3;
! 1414:
! 1415: p->next = sc->sc_dmas;
! 1416: sc->sc_dmas = p;
! 1417: return (p->addr);
! 1418:
! 1419: fail3:
! 1420: bus_dmamem_unmap(dmat, p->addr, p->size);
! 1421: fail2:
! 1422: bus_dmamem_free(dmat, p->segs, p->nsegs);
! 1423: fail1:
! 1424: bus_dmamap_destroy(dmat, p->dmamap);
! 1425: fail:
! 1426: free(p, pool);
! 1427: return (NULL);
! 1428: }
! 1429:
! 1430: void
! 1431: ce4231_free(addr, ptr, pool)
! 1432: void *addr;
! 1433: void *ptr;
! 1434: int pool;
! 1435: {
! 1436: struct ce4231_softc *sc = addr;
! 1437: bus_dma_tag_t dmat = sc->sc_dmatag;
! 1438: struct cs_dma *p, **pp;
! 1439:
! 1440: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
! 1441: if (p->addr != ptr)
! 1442: continue;
! 1443: bus_dmamap_unload(dmat, p->dmamap);
! 1444: bus_dmamem_unmap(dmat, p->addr, p->size);
! 1445: bus_dmamem_free(dmat, p->segs, p->nsegs);
! 1446: bus_dmamap_destroy(dmat, p->dmamap);
! 1447: *pp = p->next;
! 1448: free(p, pool);
! 1449: return;
! 1450: }
! 1451: printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
! 1452: }
! 1453:
! 1454: int
! 1455: ce4231_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1456: void *addr, *start, *end;
! 1457: int blksize;
! 1458: void (*intr)(void *);
! 1459: void *arg;
! 1460: struct audio_params *param;
! 1461: {
! 1462: struct ce4231_softc *sc = addr;
! 1463: struct cs_dma *p;
! 1464: u_int32_t csr;
! 1465: vaddr_t n;
! 1466:
! 1467: if (sc->sc_locked != 0) {
! 1468: printf("%s: trigger_output: already running\n",
! 1469: sc->sc_dev.dv_xname);
! 1470: return (EINVAL);
! 1471: }
! 1472:
! 1473: sc->sc_locked = 1;
! 1474: sc->sc_pintr = intr;
! 1475: sc->sc_parg = arg;
! 1476:
! 1477: for (p = sc->sc_dmas; p->addr != start; p = p->next)
! 1478: /*EMPTY*/;
! 1479: if (p == NULL) {
! 1480: printf("%s: trigger_output: bad addr: %p\n",
! 1481: sc->sc_dev.dv_xname, start);
! 1482: return (EINVAL);
! 1483: }
! 1484:
! 1485: n = (char *)end - (char *)start;
! 1486:
! 1487: /*
! 1488: * Do only `blksize' at a time, so audio_pint() is kept
! 1489: * synchronous with us...
! 1490: */
! 1491: sc->sc_blksz = blksize;
! 1492: sc->sc_nowplaying = p;
! 1493: sc->sc_playsegsz = n;
! 1494:
! 1495: if (n > sc->sc_blksz)
! 1496: n = sc->sc_blksz;
! 1497:
! 1498: sc->sc_playcnt = n;
! 1499:
! 1500: csr = P_READ(sc, EBDMA_DCSR);
! 1501: if (csr & EBDCSR_DMAEN) {
! 1502: P_WRITE(sc, EBDMA_DCNT, (u_long)n);
! 1503: P_WRITE(sc, EBDMA_DADDR,
! 1504: (u_long)p->dmamap->dm_segs[0].ds_addr);
! 1505: } else {
! 1506: P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
! 1507: P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
! 1508:
! 1509: P_WRITE(sc, EBDMA_DCNT, (u_long)n);
! 1510: P_WRITE(sc, EBDMA_DADDR,
! 1511: (u_long)p->dmamap->dm_segs[0].ds_addr);
! 1512:
! 1513: P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_DMAEN |
! 1514: EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN);
! 1515:
! 1516: ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
! 1517: ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
! 1518: ce4231_write(sc, SP_INTERFACE_CONFIG,
! 1519: ce4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
! 1520: }
! 1521: sc->sc_lastaddr = p->dmamap->dm_segs[0].ds_addr + n;
! 1522:
! 1523: return (0);
! 1524: }
! 1525:
! 1526: int
! 1527: ce4231_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1528: void *addr, *start, *end;
! 1529: int blksize;
! 1530: void (*intr)(void *);
! 1531: void *arg;
! 1532: struct audio_params *param;
! 1533: {
! 1534: return (ENXIO);
! 1535: }
CVSweb