Annotation of sys/dev/isa/ess.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ess.c,v 1.11 2006/02/22 19:43:42 miod Exp $ */
! 2: /* $NetBSD: ess.c,v 1.44.4.1 1999/06/21 01:18:00 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright 1997
! 6: * Digital Equipment Corporation. All rights reserved.
! 7: *
! 8: * This software is furnished under license and may be used and
! 9: * copied only in accordance with the following terms and conditions.
! 10: * Subject to these conditions, you may download, copy, install,
! 11: * use, modify and distribute this software in source and/or binary
! 12: * form. No title or ownership is transferred hereby.
! 13: *
! 14: * 1) Any source code used, modified or distributed must reproduce
! 15: * and retain this copyright notice and list of conditions as
! 16: * they appear in the source file.
! 17: *
! 18: * 2) No right is granted to use any trade name, trademark, or logo of
! 19: * Digital Equipment Corporation. Neither the "Digital Equipment
! 20: * Corporation" name nor any trademark or logo of Digital Equipment
! 21: * Corporation may be used to endorse or promote products derived
! 22: * from this software without the prior written permission of
! 23: * Digital Equipment Corporation.
! 24: *
! 25: * 3) This software is provided "AS-IS" and any express or implied
! 26: * warranties, including but not limited to, any implied warranties
! 27: * of merchantability, fitness for a particular purpose, or
! 28: * non-infringement are disclaimed. In no event shall DIGITAL be
! 29: * liable for any damages whatsoever, and in particular, DIGITAL
! 30: * shall not be liable for special, indirect, consequential, or
! 31: * incidental damages or damages for lost profits, loss of
! 32: * revenue or loss of use, whether such damages arise in contract,
! 33: * negligence, tort, under statute, in equity, at law or otherwise,
! 34: * even if advised of the possibility of such damage.
! 35: */
! 36:
! 37: /*
! 38: **++
! 39: **
! 40: ** ess.c
! 41: **
! 42: ** FACILITY:
! 43: **
! 44: ** DIGITAL Network Appliance Reference Design (DNARD)
! 45: **
! 46: ** MODULE DESCRIPTION:
! 47: **
! 48: ** This module contains the device driver for the ESS
! 49: ** Technologies 1888/1887/888 sound chip. The code in sbdsp.c was
! 50: ** used as a reference point when implementing this driver.
! 51: **
! 52: ** AUTHORS:
! 53: **
! 54: ** Blair Fidler Software Engineering Australia
! 55: ** Gold Coast, Australia.
! 56: **
! 57: ** CREATION DATE:
! 58: **
! 59: ** March 10, 1997.
! 60: **
! 61: ** MODIFICATION HISTORY:
! 62: **
! 63: ** Heavily modified by Lennart Augustsson and Charles M. Hannum for
! 64: ** bus_dma, changes to audio interface, and many bug fixes.
! 65: ** ESS1788 support by Nathan J. Williams and Charles M. Hannum.
! 66: **--
! 67: */
! 68:
! 69: #include <sys/param.h>
! 70: #include <sys/systm.h>
! 71: #include <sys/errno.h>
! 72: #include <sys/ioctl.h>
! 73: #include <sys/syslog.h>
! 74: #include <sys/device.h>
! 75: #include <sys/proc.h>
! 76: #include <sys/kernel.h>
! 77: #include <sys/timeout.h>
! 78:
! 79: #include <machine/cpu.h>
! 80: #include <machine/intr.h>
! 81: #include <machine/bus.h>
! 82:
! 83: #include <sys/audioio.h>
! 84: #include <dev/audio_if.h>
! 85: #include <dev/auconv.h>
! 86: #include <dev/mulaw.h>
! 87:
! 88: #include <dev/isa/isavar.h>
! 89: #include <dev/isa/isadmavar.h>
! 90:
! 91: #include <dev/isa/essvar.h>
! 92: #include <dev/isa/essreg.h>
! 93:
! 94: #ifdef AUDIO_DEBUG
! 95: #define DPRINTF(x) if (essdebug) printf x
! 96: #define DPRINTFN(n,x) if (essdebug>(n)) printf x
! 97: int essdebug = 0;
! 98: #else
! 99: #define DPRINTF(x)
! 100: #define DPRINTFN(n,x)
! 101: #endif
! 102:
! 103: #if 0
! 104: unsigned uuu;
! 105: #define EREAD1(t, h, a) (uuu=bus_space_read_1(t, h, a),printf("EREAD %02x=%02x\n", ((int)h&0xfff)+a, uuu),uuu)
! 106: #define EWRITE1(t, h, a, d) (printf("EWRITE %02x=%02x\n", ((int)h & 0xfff)+a, d), bus_space_write_1(t, h, a, d))
! 107: #else
! 108: #define EREAD1(t, h, a) bus_space_read_1(t, h, a)
! 109: #define EWRITE1(t, h, a, d) bus_space_write_1(t, h, a, d)
! 110: #endif
! 111:
! 112: struct cfdriver ess_cd = {
! 113: NULL, "ess", DV_DULL
! 114: };
! 115:
! 116: int ess_setup_sc(struct ess_softc *, int);
! 117:
! 118: int ess_open(void *, int);
! 119: void ess_1788_close(void *);
! 120: void ess_1888_close(void *);
! 121: int ess_getdev(void *, struct audio_device *);
! 122: int ess_drain(void *);
! 123:
! 124: int ess_query_encoding(void *, struct audio_encoding *);
! 125:
! 126: int ess_set_params(void *, int, int, struct audio_params *,
! 127: struct audio_params *);
! 128:
! 129: int ess_round_blocksize(void *, int);
! 130:
! 131: int ess_audio1_trigger_output(void *, void *, void *, int,
! 132: void (*)(void *), void *, struct audio_params *);
! 133: int ess_audio2_trigger_output(void *, void *, void *, int,
! 134: void (*)(void *), void *, struct audio_params *);
! 135: int ess_audio1_trigger_input(void *, void *, void *, int,
! 136: void (*)(void *), void *, struct audio_params *);
! 137: int ess_audio1_halt(void *);
! 138: int ess_audio2_halt(void *);
! 139: int ess_audio1_intr(void *);
! 140: int ess_audio2_intr(void *);
! 141: void ess_audio1_poll(void *);
! 142: void ess_audio2_poll(void *);
! 143:
! 144: int ess_speaker_ctl(void *, int);
! 145:
! 146: int ess_getdev(void *, struct audio_device *);
! 147:
! 148: int ess_set_port(void *, mixer_ctrl_t *);
! 149: int ess_get_port(void *, mixer_ctrl_t *);
! 150:
! 151: void *ess_malloc(void *, int, size_t, int, int);
! 152: void ess_free(void *, void *, int);
! 153: size_t ess_round_buffersize(void *, int, size_t);
! 154: paddr_t ess_mappage(void *, void *, off_t, int);
! 155:
! 156:
! 157: int ess_query_devinfo(void *, mixer_devinfo_t *);
! 158: int ess_1788_get_props(void *);
! 159: int ess_1888_get_props(void *);
! 160:
! 161: void ess_speaker_on(struct ess_softc *);
! 162: void ess_speaker_off(struct ess_softc *);
! 163:
! 164: int ess_config_addr(struct ess_softc *);
! 165: void ess_config_irq(struct ess_softc *);
! 166: void ess_config_drq(struct ess_softc *);
! 167: void ess_setup(struct ess_softc *);
! 168: int ess_identify(struct ess_softc *);
! 169:
! 170: int ess_reset(struct ess_softc *);
! 171: void ess_set_gain(struct ess_softc *, int, int);
! 172: int ess_set_in_port(struct ess_softc *, int);
! 173: int ess_set_in_ports(struct ess_softc *, int);
! 174: u_int ess_srtotc(u_int);
! 175: u_int ess_srtofc(u_int);
! 176: u_char ess_get_dsp_status(struct ess_softc *);
! 177: u_char ess_dsp_read_ready(struct ess_softc *);
! 178: u_char ess_dsp_write_ready(struct ess_softc *);
! 179: int ess_rdsp(struct ess_softc *);
! 180: int ess_wdsp(struct ess_softc *, u_char);
! 181: u_char ess_read_x_reg(struct ess_softc *, u_char);
! 182: int ess_write_x_reg(struct ess_softc *, u_char, u_char);
! 183: void ess_clear_xreg_bits(struct ess_softc *, u_char, u_char);
! 184: void ess_set_xreg_bits(struct ess_softc *, u_char, u_char);
! 185: u_char ess_read_mix_reg(struct ess_softc *, u_char);
! 186: void ess_write_mix_reg(struct ess_softc *, u_char, u_char);
! 187: void ess_clear_mreg_bits(struct ess_softc *, u_char, u_char);
! 188: void ess_set_mreg_bits(struct ess_softc *, u_char, u_char);
! 189: void ess_read_multi_mix_reg(struct ess_softc *, u_char, u_int8_t *, bus_size_t);
! 190:
! 191: static char *essmodel[] = {
! 192: "unsupported",
! 193: "1888",
! 194: "1887",
! 195: "888",
! 196: "1788",
! 197: "1869",
! 198: "1879",
! 199: "1868",
! 200: "1878",
! 201: };
! 202:
! 203: struct audio_device ess_device = {
! 204: "ESS Technology",
! 205: "x",
! 206: "ess"
! 207: };
! 208:
! 209: /*
! 210: * Define our interface to the higher level audio driver.
! 211: */
! 212:
! 213: struct audio_hw_if ess_1788_hw_if = {
! 214: ess_open,
! 215: ess_1788_close,
! 216: ess_drain,
! 217: ess_query_encoding,
! 218: ess_set_params,
! 219: ess_round_blocksize,
! 220: NULL,
! 221: NULL,
! 222: NULL,
! 223: NULL,
! 224: NULL,
! 225: ess_audio1_halt,
! 226: ess_audio1_halt,
! 227: ess_speaker_ctl,
! 228: ess_getdev,
! 229: NULL,
! 230: ess_set_port,
! 231: ess_get_port,
! 232: ess_query_devinfo,
! 233: ess_malloc,
! 234: ess_free,
! 235: ess_round_buffersize,
! 236: ess_mappage,
! 237: ess_1788_get_props,
! 238: ess_audio1_trigger_output,
! 239: ess_audio1_trigger_input,
! 240: };
! 241:
! 242: struct audio_hw_if ess_1888_hw_if = {
! 243: ess_open,
! 244: ess_1888_close,
! 245: ess_drain,
! 246: ess_query_encoding,
! 247: ess_set_params,
! 248: ess_round_blocksize,
! 249: NULL,
! 250: NULL,
! 251: NULL,
! 252: NULL,
! 253: NULL,
! 254: ess_audio2_halt,
! 255: ess_audio1_halt,
! 256: ess_speaker_ctl,
! 257: ess_getdev,
! 258: NULL,
! 259: ess_set_port,
! 260: ess_get_port,
! 261: ess_query_devinfo,
! 262: ess_malloc,
! 263: ess_free,
! 264: ess_round_buffersize,
! 265: ess_mappage,
! 266: ess_1888_get_props,
! 267: ess_audio2_trigger_output,
! 268: ess_audio1_trigger_input,
! 269: };
! 270:
! 271: #ifdef AUDIO_DEBUG
! 272: void ess_printsc(struct ess_softc *);
! 273: void ess_dump_mixer(struct ess_softc *);
! 274:
! 275: void
! 276: ess_printsc(sc)
! 277: struct ess_softc *sc;
! 278: {
! 279: int i;
! 280:
! 281: printf("open %d iobase 0x%x outport %u inport %u speaker %s\n",
! 282: (int)sc->sc_open, sc->sc_iobase, sc->out_port,
! 283: sc->in_port, sc->spkr_state ? "on" : "off");
! 284:
! 285: printf("audio1: dmachan %d irq %d nintr %lu intr %p arg %p\n",
! 286: sc->sc_audio1.drq, sc->sc_audio1.irq, sc->sc_audio1.nintr,
! 287: sc->sc_audio1.intr, sc->sc_audio1.arg);
! 288:
! 289: if (!ESS_USE_AUDIO1(sc->sc_model)) {
! 290: printf("audio2: dmachan %d irq %d nintr %lu intr %p arg %p\n",
! 291: sc->sc_audio2.drq, sc->sc_audio2.irq, sc->sc_audio2.nintr,
! 292: sc->sc_audio2.intr, sc->sc_audio2.arg);
! 293: }
! 294:
! 295: printf("gain:");
! 296: for (i = 0; i < sc->ndevs; i++)
! 297: printf(" %u,%u", sc->gain[i][ESS_LEFT], sc->gain[i][ESS_RIGHT]);
! 298: printf("\n");
! 299: }
! 300:
! 301: void
! 302: ess_dump_mixer(sc)
! 303: struct ess_softc *sc;
! 304: {
! 305: printf("ESS_DAC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 306: 0x7C, ess_read_mix_reg(sc, 0x7C));
! 307: printf("ESS_MIC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 308: 0x1A, ess_read_mix_reg(sc, 0x1A));
! 309: printf("ESS_LINE_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 310: 0x3E, ess_read_mix_reg(sc, 0x3E));
! 311: printf("ESS_SYNTH_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 312: 0x36, ess_read_mix_reg(sc, 0x36));
! 313: printf("ESS_CD_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 314: 0x38, ess_read_mix_reg(sc, 0x38));
! 315: printf("ESS_AUXB_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
! 316: 0x3A, ess_read_mix_reg(sc, 0x3A));
! 317: printf("ESS_MASTER_VOL: mix reg 0x%02x=0x%02x\n",
! 318: 0x32, ess_read_mix_reg(sc, 0x32));
! 319: printf("ESS_PCSPEAKER_VOL: mix reg 0x%02x=0x%02x\n",
! 320: 0x3C, ess_read_mix_reg(sc, 0x3C));
! 321: printf("ESS_DAC_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 322: 0x69, ess_read_mix_reg(sc, 0x69));
! 323: printf("ESS_MIC_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 324: 0x68, ess_read_mix_reg(sc, 0x68));
! 325: printf("ESS_LINE_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 326: 0x6E, ess_read_mix_reg(sc, 0x6E));
! 327: printf("ESS_SYNTH_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 328: 0x6B, ess_read_mix_reg(sc, 0x6B));
! 329: printf("ESS_CD_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 330: 0x6A, ess_read_mix_reg(sc, 0x6A));
! 331: printf("ESS_AUXB_REC_VOL: mix reg 0x%02x=0x%02x\n",
! 332: 0x6C, ess_read_mix_reg(sc, 0x6C));
! 333: printf("ESS_RECORD_VOL: x reg 0x%02x=0x%02x\n",
! 334: 0xB4, ess_read_x_reg(sc, 0xB4));
! 335: printf("Audio 1 play vol (unused): mix reg 0x%02x=0x%02x\n",
! 336: 0x14, ess_read_mix_reg(sc, 0x14));
! 337:
! 338: printf("ESS_MIC_PREAMP: x reg 0x%02x=0x%02x\n",
! 339: ESS_XCMD_PREAMP_CTRL, ess_read_x_reg(sc, ESS_XCMD_PREAMP_CTRL));
! 340: printf("ESS_RECORD_MONITOR: x reg 0x%02x=0x%02x\n",
! 341: ESS_XCMD_AUDIO_CTRL, ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL));
! 342: printf("Record source: mix reg 0x%02x=0x%02x, 0x%02x=0x%02x\n",
! 343: ESS_MREG_ADC_SOURCE, ess_read_mix_reg(sc, ESS_MREG_ADC_SOURCE),
! 344: ESS_MREG_AUDIO2_CTRL2, ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2));
! 345: }
! 346:
! 347: #endif
! 348:
! 349: /*
! 350: * Configure the ESS chip for the desired audio base address.
! 351: */
! 352: int
! 353: ess_config_addr(sc)
! 354: struct ess_softc *sc;
! 355: {
! 356: int iobase = sc->sc_iobase;
! 357: bus_space_tag_t iot = sc->sc_iot;
! 358:
! 359: /*
! 360: * Configure using the System Control Register method. This
! 361: * method is used when the AMODE line is tied high, which is
! 362: * the case for the Shark, but not for the evaluation board.
! 363: */
! 364:
! 365: bus_space_handle_t scr_access_ioh;
! 366: bus_space_handle_t scr_ioh;
! 367: u_short scr_value;
! 368:
! 369: /*
! 370: * Set the SCR bit to enable audio.
! 371: */
! 372: scr_value = ESS_SCR_AUDIO_ENABLE;
! 373:
! 374: /*
! 375: * Set the SCR bits necessary to select the specified audio
! 376: * base address.
! 377: */
! 378: switch(iobase) {
! 379: case 0x220:
! 380: scr_value |= ESS_SCR_AUDIO_220;
! 381: break;
! 382: case 0x230:
! 383: scr_value |= ESS_SCR_AUDIO_230;
! 384: break;
! 385: case 0x240:
! 386: scr_value |= ESS_SCR_AUDIO_240;
! 387: break;
! 388: case 0x250:
! 389: scr_value |= ESS_SCR_AUDIO_250;
! 390: break;
! 391: default:
! 392: printf("ess: configured iobase 0x%x invalid\n", iobase);
! 393: return (1);
! 394: break;
! 395: }
! 396:
! 397: /*
! 398: * Get a mapping for the System Control Register (SCR) access
! 399: * registers and the SCR data registers.
! 400: */
! 401: if (bus_space_map(iot, ESS_SCR_ACCESS_BASE, ESS_SCR_ACCESS_PORTS,
! 402: 0, &scr_access_ioh)) {
! 403: printf("ess: can't map SCR access registers\n");
! 404: return (1);
! 405: }
! 406: if (bus_space_map(iot, ESS_SCR_BASE, ESS_SCR_PORTS,
! 407: 0, &scr_ioh)) {
! 408: printf("ess: can't map SCR registers\n");
! 409: bus_space_unmap(iot, scr_access_ioh, ESS_SCR_ACCESS_PORTS);
! 410: return (1);
! 411: }
! 412:
! 413: /* Unlock the SCR. */
! 414: EWRITE1(iot, scr_access_ioh, ESS_SCR_UNLOCK, 0);
! 415:
! 416: /* Write the base address information into SCR[0]. */
! 417: EWRITE1(iot, scr_ioh, ESS_SCR_INDEX, 0);
! 418: EWRITE1(iot, scr_ioh, ESS_SCR_DATA, scr_value);
! 419:
! 420: /* Lock the SCR. */
! 421: EWRITE1(iot, scr_access_ioh, ESS_SCR_LOCK, 0);
! 422:
! 423: /* Unmap the SCR access ports and the SCR data ports. */
! 424: bus_space_unmap(iot, scr_access_ioh, ESS_SCR_ACCESS_PORTS);
! 425: bus_space_unmap(iot, scr_ioh, ESS_SCR_PORTS);
! 426:
! 427: return 0;
! 428: }
! 429:
! 430:
! 431: /*
! 432: * Configure the ESS chip for the desired IRQ and DMA channels.
! 433: * ESS ISA
! 434: * --------
! 435: * IRQA irq9
! 436: * IRQB irq5
! 437: * IRQC irq7
! 438: * IRQD irq10
! 439: * IRQE irq15
! 440: *
! 441: * DRQA drq0
! 442: * DRQB drq1
! 443: * DRQC drq3
! 444: * DRQD drq5
! 445: */
! 446: void
! 447: ess_config_irq(sc)
! 448: struct ess_softc *sc;
! 449: {
! 450: int v;
! 451:
! 452: DPRINTFN(2,("ess_config_irq\n"));
! 453:
! 454: if (sc->sc_model == ESS_1887 &&
! 455: sc->sc_audio1.irq == sc->sc_audio2.irq &&
! 456: sc->sc_audio1.irq != -1) {
! 457: /* Use new method, both interrupts are the same. */
! 458: v = ESS_IS_SELECT_IRQ; /* enable intrs */
! 459: switch (sc->sc_audio1.irq) {
! 460: case 5:
! 461: v |= ESS_IS_INTRB;
! 462: break;
! 463: case 7:
! 464: v |= ESS_IS_INTRC;
! 465: break;
! 466: case 9:
! 467: v |= ESS_IS_INTRA;
! 468: break;
! 469: case 10:
! 470: v |= ESS_IS_INTRD;
! 471: break;
! 472: case 15:
! 473: v |= ESS_IS_INTRE;
! 474: break;
! 475: #ifdef DIAGNOSTIC
! 476: default:
! 477: printf("ess_config_irq: configured irq %d not supported for Audio 1\n",
! 478: sc->sc_audio1.irq);
! 479: return;
! 480: #endif
! 481: }
! 482: /* Set the IRQ */
! 483: ess_write_mix_reg(sc, ESS_MREG_INTR_ST, v);
! 484: return;
! 485: }
! 486:
! 487: if (sc->sc_model == ESS_1887) {
! 488: /* Tell the 1887 to use the old interrupt method. */
! 489: ess_write_mix_reg(sc, ESS_MREG_INTR_ST, ESS_IS_ES1888);
! 490: }
! 491:
! 492: if (sc->sc_audio1.polled) {
! 493: /* Turn off Audio1 interrupts. */
! 494: v = 0;
! 495: } else {
! 496: /* Configure Audio 1 for the appropriate IRQ line. */
! 497: v = ESS_IRQ_CTRL_MASK | ESS_IRQ_CTRL_EXT; /* All intrs on */
! 498: switch (sc->sc_audio1.irq) {
! 499: case 5:
! 500: v |= ESS_IRQ_CTRL_INTRB;
! 501: break;
! 502: case 7:
! 503: v |= ESS_IRQ_CTRL_INTRC;
! 504: break;
! 505: case 9:
! 506: v |= ESS_IRQ_CTRL_INTRA;
! 507: break;
! 508: case 10:
! 509: v |= ESS_IRQ_CTRL_INTRD;
! 510: break;
! 511: #ifdef DIAGNOSTIC
! 512: default:
! 513: printf("ess: configured irq %d not supported for Audio 1\n",
! 514: sc->sc_audio1.irq);
! 515: return;
! 516: #endif
! 517: }
! 518: }
! 519: ess_write_x_reg(sc, ESS_XCMD_IRQ_CTRL, v);
! 520:
! 521: if (ESS_USE_AUDIO1(sc->sc_model))
! 522: return;
! 523:
! 524: if (sc->sc_audio2.polled) {
! 525: /* Turn off Audio2 interrupts. */
! 526: ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
! 527: ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
! 528: } else {
! 529: /* Audio2 is hardwired to INTRE in this mode. */
! 530: ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
! 531: ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
! 532: }
! 533: }
! 534:
! 535:
! 536: void
! 537: ess_config_drq(sc)
! 538: struct ess_softc *sc;
! 539: {
! 540: int v;
! 541:
! 542: DPRINTFN(2,("ess_config_drq\n"));
! 543:
! 544: /* Configure Audio 1 (record) for DMA on the appropriate channel. */
! 545: v = ESS_DRQ_CTRL_PU | ESS_DRQ_CTRL_EXT;
! 546: switch (sc->sc_audio1.drq) {
! 547: case 0:
! 548: v |= ESS_DRQ_CTRL_DRQA;
! 549: break;
! 550: case 1:
! 551: v |= ESS_DRQ_CTRL_DRQB;
! 552: break;
! 553: case 3:
! 554: v |= ESS_DRQ_CTRL_DRQC;
! 555: break;
! 556: #ifdef DIAGNOSTIC
! 557: default:
! 558: printf("ess_config_drq: configured dma chan %d not supported for Audio 1\n",
! 559: sc->sc_audio1.drq);
! 560: return;
! 561: #endif
! 562: }
! 563: /* Set DRQ1 */
! 564: ess_write_x_reg(sc, ESS_XCMD_DRQ_CTRL, v);
! 565:
! 566: if (ESS_USE_AUDIO1(sc->sc_model))
! 567: return;
! 568:
! 569: /* Configure DRQ2 */
! 570: v = ESS_AUDIO2_CTRL3_DRQ_PD;
! 571: switch (sc->sc_audio2.drq) {
! 572: case 0:
! 573: v |= ESS_AUDIO2_CTRL3_DRQA;
! 574: break;
! 575: case 1:
! 576: v |= ESS_AUDIO2_CTRL3_DRQB;
! 577: break;
! 578: case 3:
! 579: v |= ESS_AUDIO2_CTRL3_DRQC;
! 580: break;
! 581: case 5:
! 582: v |= ESS_AUDIO2_CTRL3_DRQD;
! 583: break;
! 584: #ifdef DIAGNOSTIC
! 585: default:
! 586: printf("ess_config_drq: configured dma chan %d not supported for Audio 2\n",
! 587: sc->sc_audio2.drq);
! 588: return;
! 589: #endif
! 590: }
! 591: ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL3, v);
! 592: /* Enable DMA 2 */
! 593: ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
! 594: ESS_AUDIO2_CTRL2_DMA_ENABLE);
! 595: }
! 596:
! 597: /*
! 598: * Set up registers after a reset.
! 599: */
! 600: void
! 601: ess_setup(sc)
! 602: struct ess_softc *sc;
! 603: {
! 604:
! 605: ess_config_irq(sc);
! 606: ess_config_drq(sc);
! 607:
! 608: DPRINTFN(2,("ess_setup: done\n"));
! 609: }
! 610:
! 611: /*
! 612: * Determine the model of ESS chip we are talking to. Currently we
! 613: * only support ES1888, ES1887 and ES888. The method of determining
! 614: * the chip is based on the information on page 27 of the ES1887 data
! 615: * sheet.
! 616: *
! 617: * This routine sets the values of sc->sc_model and sc->sc_version.
! 618: */
! 619: int
! 620: ess_identify(sc)
! 621: struct ess_softc *sc;
! 622: {
! 623: u_char reg1;
! 624: u_char reg2;
! 625: u_char reg3;
! 626: u_int8_t ident[4];
! 627:
! 628: sc->sc_model = ESS_UNSUPPORTED;
! 629: sc->sc_version = 0;
! 630:
! 631: memset(ident, 0, sizeof(ident));
! 632:
! 633: /*
! 634: * 1. Check legacy ID bytes. These should be 0x68 0x8n, where
! 635: * n >= 8 for an ES1887 or an ES888. Other values indicate
! 636: * earlier (unsupported) chips.
! 637: */
! 638: ess_wdsp(sc, ESS_ACMD_LEGACY_ID);
! 639:
! 640: if ((reg1 = ess_rdsp(sc)) != 0x68) {
! 641: printf("ess: First ID byte wrong (0x%02x)\n", reg1);
! 642: return 1;
! 643: }
! 644:
! 645: reg2 = ess_rdsp(sc);
! 646: if (((reg2 & 0xf0) != 0x80) ||
! 647: ((reg2 & 0x0f) < 8)) {
! 648: printf("ess: Second ID byte wrong (0x%02x)\n", reg2);
! 649: return 1;
! 650: }
! 651:
! 652: /*
! 653: * Store the ID bytes as the version.
! 654: */
! 655: sc->sc_version = (reg1 << 8) + reg2;
! 656:
! 657:
! 658: /*
! 659: * 2. Verify we can change bit 2 in mixer register 0x64. This
! 660: * should be possible on all supported chips.
! 661: */
! 662: reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
! 663: reg2 = reg1 ^ 0x04; /* toggle bit 2 */
! 664:
! 665: ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
! 666:
! 667: if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) != reg2) {
! 668: printf("ess: Hardware error (unable to toggle bit 2 of mixer register 0x64)\n");
! 669: return 1;
! 670: }
! 671:
! 672: /*
! 673: * Restore the original value of mixer register 0x64.
! 674: */
! 675: ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
! 676:
! 677:
! 678: /*
! 679: * 3. Verify we can change the value of mixer register
! 680: * ESS_MREG_SAMPLE_RATE.
! 681: * This is possible on the 1888/1887/888, but not on the 1788.
! 682: * It is not necessary to restore the value of this mixer register.
! 683: */
! 684: reg1 = ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE);
! 685: reg2 = reg1 ^ 0xff; /* toggle all bits */
! 686:
! 687: ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, reg2);
! 688:
! 689: if (ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE) != reg2) {
! 690: /* If we got this far before failing, it's a 1788. */
! 691: sc->sc_model = ESS_1788;
! 692:
! 693: /*
! 694: * Identify ESS model for ES18[67]8.
! 695: */
! 696: ess_read_multi_mix_reg(sc, 0x40, ident, sizeof(ident));
! 697: if(ident[0] == 0x18) {
! 698: switch(ident[1]) {
! 699: case 0x68:
! 700: sc->sc_model = ESS_1868;
! 701: break;
! 702: case 0x78:
! 703: sc->sc_model = ESS_1878;
! 704: break;
! 705: }
! 706: }
! 707: } else {
! 708: /*
! 709: * 4. Determine if we can change bit 5 in mixer register 0x64.
! 710: * This determines whether we have an ES1887:
! 711: *
! 712: * - can change indicates ES1887
! 713: * - can't change indicates ES1888 or ES888
! 714: */
! 715: reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
! 716: reg2 = reg1 ^ 0x20; /* toggle bit 5 */
! 717:
! 718: ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
! 719:
! 720: if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) == reg2) {
! 721: sc->sc_model = ESS_1887;
! 722:
! 723: /*
! 724: * Restore the original value of mixer register 0x64.
! 725: */
! 726: ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
! 727:
! 728: /*
! 729: * Identify ESS model for ES18[67]9.
! 730: */
! 731: ess_read_multi_mix_reg(sc, 0x40, ident, sizeof(ident));
! 732: if(ident[0] == 0x18) {
! 733: switch(ident[1]) {
! 734: case 0x69:
! 735: sc->sc_model = ESS_1869;
! 736: break;
! 737: case 0x79:
! 738: sc->sc_model = ESS_1879;
! 739: break;
! 740: }
! 741: }
! 742: } else {
! 743: /*
! 744: * 5. Determine if we can change the value of mixer
! 745: * register 0x69 independently of mixer register
! 746: * 0x68. This determines which chip we have:
! 747: *
! 748: * - can modify idependently indicates ES888
! 749: * - register 0x69 is an alias of 0x68 indicates ES1888
! 750: */
! 751: reg1 = ess_read_mix_reg(sc, 0x68);
! 752: reg2 = ess_read_mix_reg(sc, 0x69);
! 753: reg3 = reg2 ^ 0xff; /* toggle all bits */
! 754:
! 755: /*
! 756: * Write different values to each register.
! 757: */
! 758: ess_write_mix_reg(sc, 0x68, reg2);
! 759: ess_write_mix_reg(sc, 0x69, reg3);
! 760:
! 761: if (ess_read_mix_reg(sc, 0x68) == reg2 &&
! 762: ess_read_mix_reg(sc, 0x69) == reg3)
! 763: sc->sc_model = ESS_888;
! 764: else
! 765: sc->sc_model = ESS_1888;
! 766:
! 767: /*
! 768: * Restore the original value of the registers.
! 769: */
! 770: ess_write_mix_reg(sc, 0x68, reg1);
! 771: ess_write_mix_reg(sc, 0x69, reg2);
! 772: }
! 773: }
! 774:
! 775: return 0;
! 776: }
! 777:
! 778:
! 779: int
! 780: ess_setup_sc(sc, doinit)
! 781: struct ess_softc *sc;
! 782: int doinit;
! 783: {
! 784: /* Reset the chip. */
! 785: if (ess_reset(sc) != 0) {
! 786: DPRINTF(("ess_setup_sc: couldn't reset chip\n"));
! 787: return (1);
! 788: }
! 789:
! 790: /* Identify the ESS chip, and check that it is supported. */
! 791: if (ess_identify(sc)) {
! 792: DPRINTF(("ess_setup_sc: couldn't identify\n"));
! 793: return (1);
! 794: }
! 795:
! 796: return (0);
! 797: }
! 798:
! 799: /*
! 800: * Probe for the ESS hardware.
! 801: */
! 802: int
! 803: essmatch(sc)
! 804: struct ess_softc *sc;
! 805: {
! 806: if (!ESS_BASE_VALID(sc->sc_iobase)) {
! 807: printf("ess: configured iobase 0x%x invalid\n", sc->sc_iobase);
! 808: return (0);
! 809: }
! 810:
! 811: /* Configure the ESS chip for the desired audio base address. */
! 812: if (ess_config_addr(sc))
! 813: return (0);
! 814:
! 815: if (ess_setup_sc(sc, 1))
! 816: return (0);
! 817:
! 818: if (sc->sc_model == ESS_UNSUPPORTED) {
! 819: DPRINTF(("ess: Unsupported model\n"));
! 820: return (0);
! 821: }
! 822:
! 823: /* Check that requested DMA channels are valid and different. */
! 824: if (!ESS_DRQ1_VALID(sc->sc_audio1.drq)) {
! 825: printf("ess: record drq %d invalid\n", sc->sc_audio1.drq);
! 826: return (0);
! 827: }
! 828: if (!isa_drq_isfree(sc->sc_isa, sc->sc_audio1.drq))
! 829: return (0);
! 830: if (!ESS_USE_AUDIO1(sc->sc_model)) {
! 831: if (!ESS_DRQ2_VALID(sc->sc_audio2.drq)) {
! 832: printf("ess: play drq %d invalid\n", sc->sc_audio2.drq);
! 833: return (0);
! 834: }
! 835: if (sc->sc_audio1.drq == sc->sc_audio2.drq) {
! 836: printf("ess: play and record drq both %d\n",
! 837: sc->sc_audio1.drq);
! 838: return (0);
! 839: }
! 840: if (!isa_drq_isfree(sc->sc_isa, sc->sc_audio2.drq))
! 841: return (0);
! 842: }
! 843:
! 844: /*
! 845: * The 1887 has an additional IRQ mode where both channels are mapped
! 846: * to the same IRQ.
! 847: */
! 848: if (sc->sc_model == ESS_1887 &&
! 849: sc->sc_audio1.irq == sc->sc_audio2.irq &&
! 850: sc->sc_audio1.irq != -1 &&
! 851: ESS_IRQ12_VALID(sc->sc_audio1.irq))
! 852: goto irq_not1888;
! 853:
! 854: /* Check that requested IRQ lines are valid and different. */
! 855: if (sc->sc_audio1.irq != -1 &&
! 856: !ESS_IRQ1_VALID(sc->sc_audio1.irq)) {
! 857: printf("ess: record irq %d invalid\n", sc->sc_audio1.irq);
! 858: return (0);
! 859: }
! 860: if (!ESS_USE_AUDIO1(sc->sc_model)) {
! 861: if (sc->sc_audio2.irq != -1 &&
! 862: !ESS_IRQ2_VALID(sc->sc_audio2.irq)) {
! 863: printf("ess: play irq %d invalid\n", sc->sc_audio2.irq);
! 864: return (0);
! 865: }
! 866: if (sc->sc_audio1.irq == sc->sc_audio2.irq &&
! 867: sc->sc_audio1.irq != -1) {
! 868: printf("ess: play and record irq both %d\n",
! 869: sc->sc_audio1.irq);
! 870: return (0);
! 871: }
! 872: }
! 873:
! 874: irq_not1888:
! 875: /* XXX should we check IRQs as well? */
! 876:
! 877: return (1);
! 878: }
! 879:
! 880:
! 881: /*
! 882: * Attach hardware to driver, attach hardware driver to audio
! 883: * pseudo-device driver.
! 884: */
! 885: void
! 886: essattach(sc)
! 887: struct ess_softc *sc;
! 888: {
! 889: struct audio_attach_args arg;
! 890: struct audio_params pparams, rparams;
! 891: int i;
! 892: u_int v;
! 893:
! 894: if (ess_setup_sc(sc, 0)) {
! 895: printf(": setup failed\n");
! 896: return;
! 897: }
! 898:
! 899: printf(": ESS Technology ES%s [version 0x%04x]\n",
! 900: essmodel[sc->sc_model], sc->sc_version);
! 901:
! 902: sc->sc_audio1.polled = sc->sc_audio1.irq == -1;
! 903: if (!sc->sc_audio1.polled) {
! 904: sc->sc_audio1.ih = isa_intr_establish(sc->sc_ic,
! 905: sc->sc_audio1.irq, sc->sc_audio1.ist, IPL_AUDIO,
! 906: ess_audio1_intr, sc, sc->sc_dev.dv_xname);
! 907: printf("%s: audio1 interrupting at irq %d\n",
! 908: sc->sc_dev.dv_xname, sc->sc_audio1.irq);
! 909: } else
! 910: printf("%s: audio1 polled\n", sc->sc_dev.dv_xname);
! 911: if (isa_dmamap_create(sc->sc_isa, sc->sc_audio1.drq,
! 912: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 913: printf("%s: can't create map for drq %d\n",
! 914: sc->sc_dev.dv_xname, sc->sc_audio1.drq);
! 915: return;
! 916: }
! 917:
! 918: if (!ESS_USE_AUDIO1(sc->sc_model)) {
! 919: sc->sc_audio2.polled = sc->sc_audio2.irq == -1;
! 920: if (!sc->sc_audio2.polled) {
! 921: sc->sc_audio2.ih = isa_intr_establish(sc->sc_ic,
! 922: sc->sc_audio2.irq, sc->sc_audio2.ist, IPL_AUDIO,
! 923: ess_audio2_intr, sc, sc->sc_dev.dv_xname);
! 924: printf("%s: audio2 interrupting at irq %d\n",
! 925: sc->sc_dev.dv_xname, sc->sc_audio2.irq);
! 926: } else
! 927: printf("%s: audio2 polled\n", sc->sc_dev.dv_xname);
! 928: if (isa_dmamap_create(sc->sc_isa, sc->sc_audio2.drq,
! 929: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 930: printf("%s: can't create map for drq %d\n",
! 931: sc->sc_dev.dv_xname, sc->sc_audio2.drq);
! 932: return;
! 933: }
! 934: }
! 935:
! 936: timeout_set(&sc->sc_tmo1, ess_audio1_poll, sc);
! 937: timeout_set(&sc->sc_tmo2, ess_audio2_poll, sc);
! 938:
! 939: /*
! 940: * Set record and play parameters to default values defined in
! 941: * generic audio driver.
! 942: */
! 943: pparams = audio_default;
! 944: rparams = audio_default;
! 945: ess_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
! 946:
! 947: /* Do a hardware reset on the mixer. */
! 948: ess_write_mix_reg(sc, ESS_MIX_RESET, ESS_MIX_RESET);
! 949:
! 950: /*
! 951: * Set volume of Audio 1 to zero and disable Audio 1 DAC input
! 952: * to playback mixer, since playback is always through Audio 2.
! 953: */
! 954: if (!ESS_USE_AUDIO1(sc->sc_model))
! 955: ess_write_mix_reg(sc, ESS_MREG_VOLUME_VOICE, 0);
! 956: ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
! 957:
! 958: if (ESS_USE_AUDIO1(sc->sc_model)) {
! 959: ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIC);
! 960: sc->in_port = ESS_SOURCE_MIC;
! 961: sc->ndevs = ESS_1788_NDEVS;
! 962: } else {
! 963: /*
! 964: * Set hardware record source to use output of the record
! 965: * mixer. We do the selection of record source in software by
! 966: * setting the gain of the unused sources to zero. (See
! 967: * ess_set_in_ports.)
! 968: */
! 969: ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIXER);
! 970: sc->in_mask = 1 << ESS_MIC_REC_VOL;
! 971: sc->ndevs = ESS_1888_NDEVS;
! 972: ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x10);
! 973: ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x08);
! 974: }
! 975:
! 976: /*
! 977: * Set gain on each mixer device to a sensible value.
! 978: * Devices not normally used are turned off, and other devices
! 979: * are set to 50% volume.
! 980: */
! 981: for (i = 0; i < sc->ndevs; i++) {
! 982: switch (i) {
! 983: case ESS_MIC_PLAY_VOL:
! 984: case ESS_LINE_PLAY_VOL:
! 985: case ESS_CD_PLAY_VOL:
! 986: case ESS_AUXB_PLAY_VOL:
! 987: case ESS_DAC_REC_VOL:
! 988: case ESS_LINE_REC_VOL:
! 989: case ESS_SYNTH_REC_VOL:
! 990: case ESS_CD_REC_VOL:
! 991: case ESS_AUXB_REC_VOL:
! 992: v = 0;
! 993: break;
! 994: default:
! 995: v = ESS_4BIT_GAIN(AUDIO_MAX_GAIN / 2);
! 996: break;
! 997: }
! 998: sc->gain[i][ESS_LEFT] = sc->gain[i][ESS_RIGHT] = v;
! 999: ess_set_gain(sc, i, 1);
! 1000: }
! 1001:
! 1002: ess_setup(sc);
! 1003:
! 1004: /* Disable the speaker until the device is opened. */
! 1005: ess_speaker_off(sc);
! 1006: sc->spkr_state = SPKR_OFF;
! 1007:
! 1008: snprintf(ess_device.name, sizeof ess_device.name, "ES%s",
! 1009: essmodel[sc->sc_model]);
! 1010: snprintf(ess_device.version, sizeof ess_device.version, "0x%04x",
! 1011: sc->sc_version);
! 1012:
! 1013: if (ESS_USE_AUDIO1(sc->sc_model))
! 1014: audio_attach_mi(&ess_1788_hw_if, sc, &sc->sc_dev);
! 1015: else
! 1016: audio_attach_mi(&ess_1888_hw_if, sc, &sc->sc_dev);
! 1017:
! 1018: arg.type = AUDIODEV_TYPE_OPL;
! 1019: arg.hwif = 0;
! 1020: arg.hdl = 0;
! 1021: (void)config_found(&sc->sc_dev, &arg, audioprint);
! 1022:
! 1023: #ifdef AUDIO_DEBUG
! 1024: if (essdebug > 0)
! 1025: ess_printsc(sc);
! 1026: #endif
! 1027: }
! 1028:
! 1029: /*
! 1030: * Various routines to interface to higher level audio driver
! 1031: */
! 1032:
! 1033: int
! 1034: ess_open(addr, flags)
! 1035: void *addr;
! 1036: int flags;
! 1037: {
! 1038: struct ess_softc *sc = addr;
! 1039:
! 1040: DPRINTF(("ess_open: sc=%p\n", sc));
! 1041:
! 1042: if (sc->sc_open != 0 || ess_reset(sc) != 0)
! 1043: return ENXIO;
! 1044:
! 1045: ess_setup(sc); /* because we did a reset */
! 1046:
! 1047: sc->sc_open = 1;
! 1048:
! 1049: DPRINTF(("ess_open: opened\n"));
! 1050:
! 1051: return (0);
! 1052: }
! 1053:
! 1054: void
! 1055: ess_1788_close(addr)
! 1056: void *addr;
! 1057: {
! 1058: struct ess_softc *sc = addr;
! 1059:
! 1060: DPRINTF(("ess_1788_close: sc=%p\n", sc));
! 1061:
! 1062: ess_speaker_off(sc);
! 1063: sc->spkr_state = SPKR_OFF;
! 1064:
! 1065: ess_audio1_halt(sc);
! 1066:
! 1067: sc->sc_open = 0;
! 1068: DPRINTF(("ess_1788_close: closed\n"));
! 1069: }
! 1070:
! 1071: void
! 1072: ess_1888_close(addr)
! 1073: void *addr;
! 1074: {
! 1075: struct ess_softc *sc = addr;
! 1076:
! 1077: DPRINTF(("ess_1888_close: sc=%p\n", sc));
! 1078:
! 1079: ess_speaker_off(sc);
! 1080: sc->spkr_state = SPKR_OFF;
! 1081:
! 1082: ess_audio1_halt(sc);
! 1083: ess_audio2_halt(sc);
! 1084:
! 1085: sc->sc_open = 0;
! 1086: DPRINTF(("ess_1888_close: closed\n"));
! 1087: }
! 1088:
! 1089: /*
! 1090: * Wait for FIFO to drain, and analog section to settle.
! 1091: * XXX should check FIFO empty bit.
! 1092: */
! 1093: int
! 1094: ess_drain(addr)
! 1095: void *addr;
! 1096: {
! 1097: tsleep(addr, PWAIT | PCATCH, "essdr", hz/20); /* XXX */
! 1098: return (0);
! 1099: }
! 1100:
! 1101: /* XXX should use reference count */
! 1102: int
! 1103: ess_speaker_ctl(addr, newstate)
! 1104: void *addr;
! 1105: int newstate;
! 1106: {
! 1107: struct ess_softc *sc = addr;
! 1108:
! 1109: if ((newstate == SPKR_ON) && (sc->spkr_state == SPKR_OFF)) {
! 1110: ess_speaker_on(sc);
! 1111: sc->spkr_state = SPKR_ON;
! 1112: }
! 1113: if ((newstate == SPKR_OFF) && (sc->spkr_state == SPKR_ON)) {
! 1114: ess_speaker_off(sc);
! 1115: sc->spkr_state = SPKR_OFF;
! 1116: }
! 1117: return (0);
! 1118: }
! 1119:
! 1120: int
! 1121: ess_getdev(addr, retp)
! 1122: void *addr;
! 1123: struct audio_device *retp;
! 1124: {
! 1125: *retp = ess_device;
! 1126: return (0);
! 1127: }
! 1128:
! 1129: int
! 1130: ess_query_encoding(addr, fp)
! 1131: void *addr;
! 1132: struct audio_encoding *fp;
! 1133: {
! 1134: /*struct ess_softc *sc = addr;*/
! 1135:
! 1136: switch (fp->index) {
! 1137: case 0:
! 1138: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 1139: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 1140: fp->precision = 8;
! 1141: fp->flags = 0;
! 1142: return (0);
! 1143: case 1:
! 1144: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 1145: fp->encoding = AUDIO_ENCODING_ULAW;
! 1146: fp->precision = 8;
! 1147: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1148: return (0);
! 1149: case 2:
! 1150: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 1151: fp->encoding = AUDIO_ENCODING_ALAW;
! 1152: fp->precision = 8;
! 1153: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1154: return (0);
! 1155: case 3:
! 1156: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 1157: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 1158: fp->precision = 8;
! 1159: fp->flags = 0;
! 1160: return (0);
! 1161: case 4:
! 1162: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 1163: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 1164: fp->precision = 16;
! 1165: fp->flags = 0;
! 1166: return (0);
! 1167: case 5:
! 1168: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 1169: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 1170: fp->precision = 16;
! 1171: fp->flags = 0;
! 1172: return (0);
! 1173: case 6:
! 1174: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 1175: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 1176: fp->precision = 16;
! 1177: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1178: return (0);
! 1179: case 7:
! 1180: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 1181: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 1182: fp->precision = 16;
! 1183: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1184: return (0);
! 1185: default:
! 1186: return EINVAL;
! 1187: }
! 1188: return (0);
! 1189: }
! 1190:
! 1191: int
! 1192: ess_set_params(addr, setmode, usemode, play, rec)
! 1193: void *addr;
! 1194: int setmode, usemode;
! 1195: struct audio_params *play, *rec;
! 1196: {
! 1197: struct ess_softc *sc = addr;
! 1198: struct audio_params *p;
! 1199: int mode;
! 1200: int rate;
! 1201:
! 1202: DPRINTF(("ess_set_params: set=%d use=%d\n", setmode, usemode));
! 1203:
! 1204: /*
! 1205: * The ES1887 manual (page 39, `Full-Duplex DMA Mode') claims that in
! 1206: * full-duplex operation the sample rates must be the same for both
! 1207: * channels. This appears to be false; the only bit in common is the
! 1208: * clock source selection. However, we'll be conservative here.
! 1209: * - mycroft
! 1210: */
! 1211: if (play->sample_rate != rec->sample_rate &&
! 1212: usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
! 1213: if (setmode == AUMODE_PLAY) {
! 1214: rec->sample_rate = play->sample_rate;
! 1215: setmode |= AUMODE_RECORD;
! 1216: } else if (setmode == AUMODE_RECORD) {
! 1217: play->sample_rate = rec->sample_rate;
! 1218: setmode |= AUMODE_PLAY;
! 1219: } else
! 1220: return (EINVAL);
! 1221: }
! 1222:
! 1223: for (mode = AUMODE_RECORD; mode != -1;
! 1224: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 1225: if ((setmode & mode) == 0)
! 1226: continue;
! 1227:
! 1228: p = mode == AUMODE_PLAY ? play : rec;
! 1229:
! 1230: if (p->sample_rate < ESS_MINRATE ||
! 1231: p->sample_rate > ESS_MAXRATE ||
! 1232: (p->precision != 8 && p->precision != 16) ||
! 1233: (p->channels != 1 && p->channels != 2))
! 1234: return (EINVAL);
! 1235:
! 1236: p->factor = 1;
! 1237: p->sw_code = 0;
! 1238: switch (p->encoding) {
! 1239: case AUDIO_ENCODING_SLINEAR_BE:
! 1240: case AUDIO_ENCODING_ULINEAR_BE:
! 1241: if (p->precision == 16)
! 1242: p->sw_code = swap_bytes;
! 1243: break;
! 1244: case AUDIO_ENCODING_SLINEAR_LE:
! 1245: case AUDIO_ENCODING_ULINEAR_LE:
! 1246: break;
! 1247: case AUDIO_ENCODING_ULAW:
! 1248: if (mode == AUMODE_PLAY) {
! 1249: p->factor = 2;
! 1250: p->sw_code = mulaw_to_ulinear16;
! 1251: } else
! 1252: p->sw_code = ulinear8_to_mulaw;
! 1253: break;
! 1254: case AUDIO_ENCODING_ALAW:
! 1255: if (mode == AUMODE_PLAY) {
! 1256: p->factor = 2;
! 1257: p->sw_code = alaw_to_ulinear16;
! 1258: } else
! 1259: p->sw_code = ulinear8_to_alaw;
! 1260: break;
! 1261: default:
! 1262: return (EINVAL);
! 1263: }
! 1264: }
! 1265:
! 1266: if (usemode == AUMODE_RECORD)
! 1267: rate = rec->sample_rate;
! 1268: else
! 1269: rate = play->sample_rate;
! 1270:
! 1271: ess_write_x_reg(sc, ESS_XCMD_SAMPLE_RATE, ess_srtotc(rate));
! 1272: ess_write_x_reg(sc, ESS_XCMD_FILTER_CLOCK, ess_srtofc(rate));
! 1273:
! 1274: if (!ESS_USE_AUDIO1(sc->sc_model)) {
! 1275: ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, ess_srtotc(rate));
! 1276: ess_write_mix_reg(sc, ESS_MREG_FILTER_CLOCK, ess_srtofc(rate));
! 1277: }
! 1278:
! 1279: return (0);
! 1280: }
! 1281:
! 1282: int
! 1283: ess_audio1_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1284: void *addr;
! 1285: void *start, *end;
! 1286: int blksize;
! 1287: void (*intr)(void *);
! 1288: void *arg;
! 1289: struct audio_params *param;
! 1290: {
! 1291: struct ess_softc *sc = addr;
! 1292: u_int8_t reg;
! 1293:
! 1294: DPRINTFN(1, ("ess_audio1_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
! 1295: addr, start, end, blksize, intr, arg));
! 1296:
! 1297: if (sc->sc_audio1.active)
! 1298: panic("ess_audio1_trigger_output: already running");
! 1299:
! 1300: sc->sc_audio1.active = 1;
! 1301: sc->sc_audio1.intr = intr;
! 1302: sc->sc_audio1.arg = arg;
! 1303: if (sc->sc_audio1.polled) {
! 1304: sc->sc_audio1.dmapos = 0;
! 1305: sc->sc_audio1.buffersize = (char *)end - (char *)start;
! 1306: sc->sc_audio1.dmacount = 0;
! 1307: sc->sc_audio1.blksize = blksize;
! 1308: timeout_add(&sc->sc_tmo1, hz/30);
! 1309: }
! 1310:
! 1311: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
! 1312: if (param->channels == 2) {
! 1313: reg &= ~ESS_AUDIO_CTRL_MONO;
! 1314: reg |= ESS_AUDIO_CTRL_STEREO;
! 1315: } else {
! 1316: reg |= ESS_AUDIO_CTRL_MONO;
! 1317: reg &= ~ESS_AUDIO_CTRL_STEREO;
! 1318: }
! 1319: ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
! 1320:
! 1321: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
! 1322: if (param->precision * param->factor == 16)
! 1323: reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
! 1324: else
! 1325: reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
! 1326: if (param->channels == 2)
! 1327: reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
! 1328: else
! 1329: reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
! 1330: if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
! 1331: param->encoding == AUDIO_ENCODING_SLINEAR_LE)
! 1332: reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
! 1333: else
! 1334: reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
! 1335: reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
! 1336: ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
! 1337:
! 1338: isa_dmastart(sc->sc_isa, sc->sc_audio1.drq, start,
! 1339: (char *)end - (char *)start, NULL,
! 1340: DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
! 1341:
! 1342: /* Program transfer count registers with 2's complement of count. */
! 1343: blksize = -blksize;
! 1344: ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
! 1345: ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
! 1346:
! 1347: /* Use 4 bytes per output DMA. */
! 1348: ess_set_xreg_bits(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
! 1349:
! 1350: /* Start auto-init DMA */
! 1351: ess_wdsp(sc, ESS_ACMD_ENABLE_SPKR);
! 1352: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
! 1353: reg &= ~(ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE);
! 1354: reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
! 1355: ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
! 1356:
! 1357: return (0);
! 1358: }
! 1359:
! 1360: int
! 1361: ess_audio2_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1362: void *addr;
! 1363: void *start, *end;
! 1364: int blksize;
! 1365: void (*intr)(void *);
! 1366: void *arg;
! 1367: struct audio_params *param;
! 1368: {
! 1369: struct ess_softc *sc = addr;
! 1370: u_int8_t reg;
! 1371:
! 1372: DPRINTFN(1, ("ess_audio2_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
! 1373: addr, start, end, blksize, intr, arg));
! 1374:
! 1375: if (sc->sc_audio2.active)
! 1376: panic("ess_audio2_trigger_output: already running");
! 1377:
! 1378: sc->sc_audio2.active = 1;
! 1379: sc->sc_audio2.intr = intr;
! 1380: sc->sc_audio2.arg = arg;
! 1381: if (sc->sc_audio2.polled) {
! 1382: sc->sc_audio2.dmapos = 0;
! 1383: sc->sc_audio2.buffersize = (char *)end - (char *)start;
! 1384: sc->sc_audio2.dmacount = 0;
! 1385: sc->sc_audio2.blksize = blksize;
! 1386: timeout_add(&sc->sc_tmo2, hz/30);
! 1387: }
! 1388:
! 1389: reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2);
! 1390: if (param->precision * param->factor == 16)
! 1391: reg |= ESS_AUDIO2_CTRL2_FIFO_SIZE;
! 1392: else
! 1393: reg &= ~ESS_AUDIO2_CTRL2_FIFO_SIZE;
! 1394: if (param->channels == 2)
! 1395: reg |= ESS_AUDIO2_CTRL2_CHANNELS;
! 1396: else
! 1397: reg &= ~ESS_AUDIO2_CTRL2_CHANNELS;
! 1398: if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
! 1399: param->encoding == AUDIO_ENCODING_SLINEAR_LE)
! 1400: reg |= ESS_AUDIO2_CTRL2_FIFO_SIGNED;
! 1401: else
! 1402: reg &= ~ESS_AUDIO2_CTRL2_FIFO_SIGNED;
! 1403: ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2, reg);
! 1404:
! 1405: isa_dmastart(sc->sc_isa, sc->sc_audio2.drq, start,
! 1406: (char *)end - (char *)start, NULL,
! 1407: DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
! 1408:
! 1409: if (IS16BITDRQ(sc->sc_audio2.drq))
! 1410: blksize >>= 1; /* use word count for 16 bit DMA */
! 1411: /* Program transfer count registers with 2's complement of count. */
! 1412: blksize = -blksize;
! 1413: ess_write_mix_reg(sc, ESS_MREG_XFER_COUNTLO, blksize);
! 1414: ess_write_mix_reg(sc, ESS_MREG_XFER_COUNTHI, blksize >> 8);
! 1415:
! 1416: reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL1);
! 1417: if (IS16BITDRQ(sc->sc_audio2.drq))
! 1418: reg |= ESS_AUDIO2_CTRL1_XFER_SIZE;
! 1419: else
! 1420: reg &= ~ESS_AUDIO2_CTRL1_XFER_SIZE;
! 1421: reg |= ESS_AUDIO2_CTRL1_DEMAND_8;
! 1422: reg |= ESS_AUDIO2_CTRL1_DAC_ENABLE | ESS_AUDIO2_CTRL1_FIFO_ENABLE |
! 1423: ESS_AUDIO2_CTRL1_AUTO_INIT;
! 1424: ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL1, reg);
! 1425:
! 1426: return (0);
! 1427: }
! 1428:
! 1429: int
! 1430: ess_audio1_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1431: void *addr;
! 1432: void *start, *end;
! 1433: int blksize;
! 1434: void (*intr)(void *);
! 1435: void *arg;
! 1436: struct audio_params *param;
! 1437: {
! 1438: struct ess_softc *sc = addr;
! 1439: u_int8_t reg;
! 1440:
! 1441: DPRINTFN(1, ("ess_audio1_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
! 1442: addr, start, end, blksize, intr, arg));
! 1443:
! 1444: if (sc->sc_audio1.active)
! 1445: panic("ess_audio1_trigger_input: already running");
! 1446:
! 1447: sc->sc_audio1.active = 1;
! 1448: sc->sc_audio1.intr = intr;
! 1449: sc->sc_audio1.arg = arg;
! 1450: if (sc->sc_audio1.polled) {
! 1451: sc->sc_audio1.dmapos = 0;
! 1452: sc->sc_audio1.buffersize = (char *)end - (char *)start;
! 1453: sc->sc_audio1.dmacount = 0;
! 1454: sc->sc_audio1.blksize = blksize;
! 1455: timeout_add(&sc->sc_tmo1, hz/30);
! 1456: }
! 1457:
! 1458: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
! 1459: if (param->channels == 2) {
! 1460: reg &= ~ESS_AUDIO_CTRL_MONO;
! 1461: reg |= ESS_AUDIO_CTRL_STEREO;
! 1462: } else {
! 1463: reg |= ESS_AUDIO_CTRL_MONO;
! 1464: reg &= ~ESS_AUDIO_CTRL_STEREO;
! 1465: }
! 1466: ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
! 1467:
! 1468: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
! 1469: if (param->precision * param->factor == 16)
! 1470: reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
! 1471: else
! 1472: reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
! 1473: if (param->channels == 2)
! 1474: reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
! 1475: else
! 1476: reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
! 1477: if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
! 1478: param->encoding == AUDIO_ENCODING_SLINEAR_LE)
! 1479: reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
! 1480: else
! 1481: reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
! 1482: reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
! 1483: ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
! 1484:
! 1485: isa_dmastart(sc->sc_isa, sc->sc_audio1.drq, start,
! 1486: (char *)end - (char *)start, NULL,
! 1487: DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT);
! 1488:
! 1489: /* Program transfer count registers with 2's complement of count. */
! 1490: blksize = -blksize;
! 1491: ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
! 1492: ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
! 1493:
! 1494: /* Use 4 bytes per input DMA. */
! 1495: ess_set_xreg_bits(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
! 1496:
! 1497: /* Start auto-init DMA */
! 1498: ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
! 1499: reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
! 1500: reg |= ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE;
! 1501: reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
! 1502: ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
! 1503:
! 1504: return (0);
! 1505: }
! 1506:
! 1507: int
! 1508: ess_audio1_halt(addr)
! 1509: void *addr;
! 1510: {
! 1511: struct ess_softc *sc = addr;
! 1512:
! 1513: DPRINTF(("ess_audio1_halt: sc=%p\n", sc));
! 1514:
! 1515: if (sc->sc_audio1.active) {
! 1516: ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
! 1517: ESS_AUDIO1_CTRL2_FIFO_ENABLE);
! 1518: isa_dmaabort(sc->sc_isa, sc->sc_audio1.drq);
! 1519: if (sc->sc_audio1.polled)
! 1520: timeout_del(&sc->sc_tmo1);
! 1521: sc->sc_audio1.active = 0;
! 1522: }
! 1523:
! 1524: return (0);
! 1525: }
! 1526:
! 1527: int
! 1528: ess_audio2_halt(addr)
! 1529: void *addr;
! 1530: {
! 1531: struct ess_softc *sc = addr;
! 1532:
! 1533: DPRINTF(("ess_audio2_halt: sc=%p\n", sc));
! 1534:
! 1535: if (sc->sc_audio2.active) {
! 1536: ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
! 1537: ESS_AUDIO2_CTRL1_DAC_ENABLE |
! 1538: ESS_AUDIO2_CTRL1_FIFO_ENABLE);
! 1539: isa_dmaabort(sc->sc_isa, sc->sc_audio2.drq);
! 1540: if (sc->sc_audio2.polled)
! 1541: timeout_del(&sc->sc_tmo2);
! 1542: sc->sc_audio2.active = 0;
! 1543: }
! 1544:
! 1545: return (0);
! 1546: }
! 1547:
! 1548: int
! 1549: ess_audio1_intr(arg)
! 1550: void *arg;
! 1551: {
! 1552: struct ess_softc *sc = arg;
! 1553: u_int8_t reg;
! 1554:
! 1555: DPRINTFN(1,("ess_audio1_intr: intr=%p\n", sc->sc_audio1.intr));
! 1556:
! 1557: /* Check and clear interrupt on Audio1. */
! 1558: reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_RW_STATUS);
! 1559: if ((reg & ESS_DSP_READ_OFLOW) == 0)
! 1560: return (0);
! 1561: reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_CLEAR_INTR);
! 1562:
! 1563: sc->sc_audio1.nintr++;
! 1564:
! 1565: if (sc->sc_audio1.active) {
! 1566: (*sc->sc_audio1.intr)(sc->sc_audio1.arg);
! 1567: return (1);
! 1568: } else
! 1569: return (0);
! 1570: }
! 1571:
! 1572: int
! 1573: ess_audio2_intr(arg)
! 1574: void *arg;
! 1575: {
! 1576: struct ess_softc *sc = arg;
! 1577: u_int8_t reg;
! 1578:
! 1579: DPRINTFN(1,("ess_audio2_intr: intr=%p\n", sc->sc_audio2.intr));
! 1580:
! 1581: /* Check and clear interrupt on Audio2. */
! 1582: reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2);
! 1583: if ((reg & ESS_AUDIO2_CTRL2_IRQ_LATCH) == 0)
! 1584: return (0);
! 1585: reg &= ~ESS_AUDIO2_CTRL2_IRQ_LATCH;
! 1586: ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2, reg);
! 1587:
! 1588: sc->sc_audio2.nintr++;
! 1589:
! 1590: if (sc->sc_audio2.active) {
! 1591: (*sc->sc_audio2.intr)(sc->sc_audio2.arg);
! 1592: return (1);
! 1593: } else
! 1594: return (0);
! 1595: }
! 1596:
! 1597: void
! 1598: ess_audio1_poll(addr)
! 1599: void *addr;
! 1600: {
! 1601: struct ess_softc *sc = addr;
! 1602: int dmapos, dmacount;
! 1603:
! 1604: if (!sc->sc_audio1.active)
! 1605: return;
! 1606:
! 1607: sc->sc_audio1.nintr++;
! 1608:
! 1609: dmapos = isa_dmacount(sc->sc_isa, sc->sc_audio1.drq);
! 1610: dmacount = sc->sc_audio1.dmapos - dmapos;
! 1611: if (dmacount < 0)
! 1612: dmacount += sc->sc_audio1.buffersize;
! 1613: sc->sc_audio1.dmapos = dmapos;
! 1614: #if 1
! 1615: dmacount += sc->sc_audio1.dmacount;
! 1616: while (dmacount > sc->sc_audio1.blksize) {
! 1617: dmacount -= sc->sc_audio1.blksize;
! 1618: (*sc->sc_audio1.intr)(sc->sc_audio1.arg);
! 1619: }
! 1620: sc->sc_audio1.dmacount = dmacount;
! 1621: #else
! 1622: (*sc->sc_audio1.intr)(sc->sc_audio1.arg, dmacount);
! 1623: #endif
! 1624:
! 1625: timeout_add(&sc->sc_tmo1, hz/30);
! 1626: }
! 1627:
! 1628: void
! 1629: ess_audio2_poll(addr)
! 1630: void *addr;
! 1631: {
! 1632: struct ess_softc *sc = addr;
! 1633: int dmapos, dmacount;
! 1634:
! 1635: if (!sc->sc_audio2.active)
! 1636: return;
! 1637:
! 1638: sc->sc_audio2.nintr++;
! 1639:
! 1640: dmapos = isa_dmacount(sc->sc_isa, sc->sc_audio2.drq);
! 1641: dmacount = sc->sc_audio2.dmapos - dmapos;
! 1642: if (dmacount < 0)
! 1643: dmacount += sc->sc_audio2.buffersize;
! 1644: sc->sc_audio2.dmapos = dmapos;
! 1645: #if 1
! 1646: dmacount += sc->sc_audio2.dmacount;
! 1647: while (dmacount > sc->sc_audio2.blksize) {
! 1648: dmacount -= sc->sc_audio2.blksize;
! 1649: (*sc->sc_audio2.intr)(sc->sc_audio2.arg);
! 1650: }
! 1651: sc->sc_audio2.dmacount = dmacount;
! 1652: #else
! 1653: (*sc->sc_audio2.intr)(sc->sc_audio2.arg, dmacount);
! 1654: #endif
! 1655:
! 1656: timeout_add(&sc->sc_tmo2, hz/30);
! 1657: }
! 1658:
! 1659: int
! 1660: ess_round_blocksize(addr, blk)
! 1661: void *addr;
! 1662: int blk;
! 1663: {
! 1664: return ((blk + 7) & -8); /* round for max DMA size */
! 1665: }
! 1666:
! 1667: int
! 1668: ess_set_port(addr, cp)
! 1669: void *addr;
! 1670: mixer_ctrl_t *cp;
! 1671: {
! 1672: struct ess_softc *sc = addr;
! 1673: int lgain, rgain;
! 1674:
! 1675: DPRINTFN(5,("ess_set_port: port=%d num_channels=%d\n",
! 1676: cp->dev, cp->un.value.num_channels));
! 1677:
! 1678: switch (cp->dev) {
! 1679: /*
! 1680: * The following mixer ports are all stereo. If we get a
! 1681: * single-channel gain value passed in, then we duplicate it
! 1682: * to both left and right channels.
! 1683: */
! 1684: case ESS_MASTER_VOL:
! 1685: case ESS_DAC_PLAY_VOL:
! 1686: case ESS_MIC_PLAY_VOL:
! 1687: case ESS_LINE_PLAY_VOL:
! 1688: case ESS_SYNTH_PLAY_VOL:
! 1689: case ESS_CD_PLAY_VOL:
! 1690: case ESS_AUXB_PLAY_VOL:
! 1691: case ESS_RECORD_VOL:
! 1692: if (cp->type != AUDIO_MIXER_VALUE)
! 1693: return EINVAL;
! 1694:
! 1695: switch (cp->un.value.num_channels) {
! 1696: case 1:
! 1697: lgain = rgain = ESS_4BIT_GAIN(
! 1698: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1699: break;
! 1700: case 2:
! 1701: lgain = ESS_4BIT_GAIN(
! 1702: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
! 1703: rgain = ESS_4BIT_GAIN(
! 1704: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
! 1705: break;
! 1706: default:
! 1707: return EINVAL;
! 1708: }
! 1709:
! 1710: sc->gain[cp->dev][ESS_LEFT] = lgain;
! 1711: sc->gain[cp->dev][ESS_RIGHT] = rgain;
! 1712: ess_set_gain(sc, cp->dev, 1);
! 1713: return (0);
! 1714:
! 1715: /*
! 1716: * The PC speaker port is mono. If we get a stereo gain value
! 1717: * passed in, then we return EINVAL.
! 1718: */
! 1719: case ESS_PCSPEAKER_VOL:
! 1720: if (cp->un.value.num_channels != 1)
! 1721: return EINVAL;
! 1722:
! 1723: sc->gain[cp->dev][ESS_LEFT] = sc->gain[cp->dev][ESS_RIGHT] =
! 1724: ESS_3BIT_GAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1725: ess_set_gain(sc, cp->dev, 1);
! 1726: return (0);
! 1727:
! 1728: case ESS_RECORD_SOURCE:
! 1729: if (ESS_USE_AUDIO1(sc->sc_model)) {
! 1730: if (cp->type == AUDIO_MIXER_ENUM)
! 1731: return (ess_set_in_port(sc, cp->un.ord));
! 1732: else
! 1733: return (EINVAL);
! 1734: } else {
! 1735: if (cp->type == AUDIO_MIXER_SET)
! 1736: return (ess_set_in_ports(sc, cp->un.mask));
! 1737: else
! 1738: return (EINVAL);
! 1739: }
! 1740: return (0);
! 1741:
! 1742: case ESS_RECORD_MONITOR:
! 1743: if (cp->type != AUDIO_MIXER_ENUM)
! 1744: return EINVAL;
! 1745:
! 1746: if (cp->un.ord)
! 1747: /* Enable monitor */
! 1748: ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
! 1749: ESS_AUDIO_CTRL_MONITOR);
! 1750: else
! 1751: /* Disable monitor */
! 1752: ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
! 1753: ESS_AUDIO_CTRL_MONITOR);
! 1754: return (0);
! 1755: }
! 1756:
! 1757: if (ESS_USE_AUDIO1(sc->sc_model))
! 1758: return (EINVAL);
! 1759:
! 1760: switch (cp->dev) {
! 1761: case ESS_DAC_REC_VOL:
! 1762: case ESS_MIC_REC_VOL:
! 1763: case ESS_LINE_REC_VOL:
! 1764: case ESS_SYNTH_REC_VOL:
! 1765: case ESS_CD_REC_VOL:
! 1766: case ESS_AUXB_REC_VOL:
! 1767: if (cp->type != AUDIO_MIXER_VALUE)
! 1768: return EINVAL;
! 1769:
! 1770: switch (cp->un.value.num_channels) {
! 1771: case 1:
! 1772: lgain = rgain = ESS_4BIT_GAIN(
! 1773: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1774: break;
! 1775: case 2:
! 1776: lgain = ESS_4BIT_GAIN(
! 1777: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
! 1778: rgain = ESS_4BIT_GAIN(
! 1779: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
! 1780: break;
! 1781: default:
! 1782: return EINVAL;
! 1783: }
! 1784:
! 1785: sc->gain[cp->dev][ESS_LEFT] = lgain;
! 1786: sc->gain[cp->dev][ESS_RIGHT] = rgain;
! 1787: ess_set_gain(sc, cp->dev, 1);
! 1788: return (0);
! 1789:
! 1790: case ESS_MIC_PREAMP:
! 1791: if (cp->type != AUDIO_MIXER_ENUM)
! 1792: return EINVAL;
! 1793:
! 1794: if (cp->un.ord)
! 1795: /* Enable microphone preamp */
! 1796: ess_set_xreg_bits(sc, ESS_XCMD_PREAMP_CTRL,
! 1797: ESS_PREAMP_CTRL_ENABLE);
! 1798: else
! 1799: /* Disable microphone preamp */
! 1800: ess_clear_xreg_bits(sc, ESS_XCMD_PREAMP_CTRL,
! 1801: ESS_PREAMP_CTRL_ENABLE);
! 1802: return (0);
! 1803: }
! 1804:
! 1805: return (EINVAL);
! 1806: }
! 1807:
! 1808: int
! 1809: ess_get_port(addr, cp)
! 1810: void *addr;
! 1811: mixer_ctrl_t *cp;
! 1812: {
! 1813: struct ess_softc *sc = addr;
! 1814:
! 1815: DPRINTFN(5,("ess_get_port: port=%d\n", cp->dev));
! 1816:
! 1817: switch (cp->dev) {
! 1818: case ESS_MASTER_VOL:
! 1819: case ESS_DAC_PLAY_VOL:
! 1820: case ESS_MIC_PLAY_VOL:
! 1821: case ESS_LINE_PLAY_VOL:
! 1822: case ESS_SYNTH_PLAY_VOL:
! 1823: case ESS_CD_PLAY_VOL:
! 1824: case ESS_AUXB_PLAY_VOL:
! 1825: case ESS_RECORD_VOL:
! 1826: switch (cp->un.value.num_channels) {
! 1827: case 1:
! 1828: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1829: sc->gain[cp->dev][ESS_LEFT];
! 1830: break;
! 1831: case 2:
! 1832: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1833: sc->gain[cp->dev][ESS_LEFT];
! 1834: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1835: sc->gain[cp->dev][ESS_RIGHT];
! 1836: break;
! 1837: default:
! 1838: return EINVAL;
! 1839: }
! 1840: return (0);
! 1841:
! 1842: case ESS_PCSPEAKER_VOL:
! 1843: if (cp->un.value.num_channels != 1)
! 1844: return EINVAL;
! 1845:
! 1846: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1847: sc->gain[cp->dev][ESS_LEFT];
! 1848: return (0);
! 1849:
! 1850: case ESS_RECORD_SOURCE:
! 1851: if (ESS_USE_AUDIO1(sc->sc_model))
! 1852: cp->un.ord = sc->in_port;
! 1853: else
! 1854: cp->un.mask = sc->in_mask;
! 1855: return (0);
! 1856:
! 1857: case ESS_RECORD_MONITOR:
! 1858: cp->un.ord = (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) &
! 1859: ESS_AUDIO_CTRL_MONITOR) ? 1 : 0;
! 1860: return (0);
! 1861: }
! 1862:
! 1863: if (ESS_USE_AUDIO1(sc->sc_model))
! 1864: return (EINVAL);
! 1865:
! 1866: switch (cp->dev) {
! 1867: case ESS_DAC_REC_VOL:
! 1868: case ESS_MIC_REC_VOL:
! 1869: case ESS_LINE_REC_VOL:
! 1870: case ESS_SYNTH_REC_VOL:
! 1871: case ESS_CD_REC_VOL:
! 1872: case ESS_AUXB_REC_VOL:
! 1873: switch (cp->un.value.num_channels) {
! 1874: case 1:
! 1875: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1876: sc->gain[cp->dev][ESS_LEFT];
! 1877: break;
! 1878: case 2:
! 1879: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1880: sc->gain[cp->dev][ESS_LEFT];
! 1881: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1882: sc->gain[cp->dev][ESS_RIGHT];
! 1883: break;
! 1884: default:
! 1885: return EINVAL;
! 1886: }
! 1887: return (0);
! 1888:
! 1889: case ESS_MIC_PREAMP:
! 1890: cp->un.ord = (ess_read_x_reg(sc, ESS_XCMD_PREAMP_CTRL) &
! 1891: ESS_PREAMP_CTRL_ENABLE) ? 1 : 0;
! 1892: return (0);
! 1893: }
! 1894:
! 1895: return (EINVAL);
! 1896: }
! 1897:
! 1898: int
! 1899: ess_query_devinfo(addr, dip)
! 1900: void *addr;
! 1901: mixer_devinfo_t *dip;
! 1902: {
! 1903: struct ess_softc *sc = addr;
! 1904:
! 1905: DPRINTFN(5,("ess_query_devinfo: model=%d index=%d\n",
! 1906: sc->sc_model, dip->index));
! 1907:
! 1908: /*
! 1909: * REVISIT: There are some slight differences between the
! 1910: * mixers on the different ESS chips, which can
! 1911: * be sorted out using the chip model rather than a
! 1912: * separate mixer model.
! 1913: * This is currently coded assuming an ES1887; we
! 1914: * need to work out which bits are not applicable to
! 1915: * the other models (1888 and 888).
! 1916: */
! 1917: switch (dip->index) {
! 1918: case ESS_DAC_PLAY_VOL:
! 1919: dip->mixer_class = ESS_INPUT_CLASS;
! 1920: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1921: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
! 1922: dip->type = AUDIO_MIXER_VALUE;
! 1923: dip->un.v.num_channels = 2;
! 1924: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1925: sizeof dip->un.v.units.name);
! 1926: return (0);
! 1927:
! 1928: case ESS_MIC_PLAY_VOL:
! 1929: dip->mixer_class = ESS_INPUT_CLASS;
! 1930: dip->prev = AUDIO_MIXER_LAST;
! 1931: if (ESS_USE_AUDIO1(sc->sc_model))
! 1932: dip->next = AUDIO_MIXER_LAST;
! 1933: else
! 1934: dip->next = ESS_MIC_PREAMP;
! 1935: strlcpy(dip->label.name, AudioNmicrophone,
! 1936: sizeof dip->label.name);
! 1937: dip->type = AUDIO_MIXER_VALUE;
! 1938: dip->un.v.num_channels = 2;
! 1939: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1940: sizeof dip->un.v.units.name);
! 1941: return (0);
! 1942:
! 1943: case ESS_LINE_PLAY_VOL:
! 1944: dip->mixer_class = ESS_INPUT_CLASS;
! 1945: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1946: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
! 1947: dip->type = AUDIO_MIXER_VALUE;
! 1948: dip->un.v.num_channels = 2;
! 1949: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1950: sizeof dip->un.v.units.name);
! 1951: return (0);
! 1952:
! 1953: case ESS_SYNTH_PLAY_VOL:
! 1954: dip->mixer_class = ESS_INPUT_CLASS;
! 1955: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1956: strlcpy(dip->label.name, AudioNfmsynth,
! 1957: sizeof dip->label.name);
! 1958: dip->type = AUDIO_MIXER_VALUE;
! 1959: dip->un.v.num_channels = 2;
! 1960: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1961: sizeof dip->un.v.units.name);
! 1962: return (0);
! 1963:
! 1964: case ESS_CD_PLAY_VOL:
! 1965: dip->mixer_class = ESS_INPUT_CLASS;
! 1966: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1967: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
! 1968: dip->type = AUDIO_MIXER_VALUE;
! 1969: dip->un.v.num_channels = 2;
! 1970: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1971: sizeof dip->un.v.units.name);
! 1972: return (0);
! 1973:
! 1974: case ESS_AUXB_PLAY_VOL:
! 1975: dip->mixer_class = ESS_INPUT_CLASS;
! 1976: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1977: strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
! 1978: dip->type = AUDIO_MIXER_VALUE;
! 1979: dip->un.v.num_channels = 2;
! 1980: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1981: sizeof dip->un.v.units.name);
! 1982: return (0);
! 1983:
! 1984: case ESS_INPUT_CLASS:
! 1985: dip->mixer_class = ESS_INPUT_CLASS;
! 1986: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1987: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
! 1988: dip->type = AUDIO_MIXER_CLASS;
! 1989: return (0);
! 1990:
! 1991: case ESS_MASTER_VOL:
! 1992: dip->mixer_class = ESS_OUTPUT_CLASS;
! 1993: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1994: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
! 1995: dip->type = AUDIO_MIXER_VALUE;
! 1996: dip->un.v.num_channels = 2;
! 1997: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1998: sizeof dip->un.v.units.name);
! 1999: return (0);
! 2000:
! 2001: case ESS_PCSPEAKER_VOL:
! 2002: dip->mixer_class = ESS_OUTPUT_CLASS;
! 2003: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2004: strlcpy(dip->label.name, "pc_speaker", sizeof dip->label.name);
! 2005: dip->type = AUDIO_MIXER_VALUE;
! 2006: dip->un.v.num_channels = 1;
! 2007: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2008: sizeof dip->un.v.units.name);
! 2009: return (0);
! 2010:
! 2011: case ESS_OUTPUT_CLASS:
! 2012: dip->mixer_class = ESS_OUTPUT_CLASS;
! 2013: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2014: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
! 2015: dip->type = AUDIO_MIXER_CLASS;
! 2016: return (0);
! 2017:
! 2018: case ESS_RECORD_VOL:
! 2019: dip->mixer_class = ESS_RECORD_CLASS;
! 2020: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2021: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
! 2022: dip->type = AUDIO_MIXER_VALUE;
! 2023: dip->un.v.num_channels = 2;
! 2024: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2025: sizeof dip->un.v.units.name);
! 2026: return (0);
! 2027:
! 2028: case ESS_RECORD_SOURCE:
! 2029: dip->mixer_class = ESS_RECORD_CLASS;
! 2030: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2031: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
! 2032: if (ESS_USE_AUDIO1(sc->sc_model)) {
! 2033: /*
! 2034: * The 1788 doesn't use the input mixer control that
! 2035: * the 1888 uses, because it's a pain when you only
! 2036: * have one mixer.
! 2037: * Perhaps it could be emulated by keeping both sets of
! 2038: * gain values, and doing a `context switch' of the
! 2039: * mixer registers when shifting from playing to
! 2040: * recording.
! 2041: */
! 2042: dip->type = AUDIO_MIXER_ENUM;
! 2043: dip->un.e.num_mem = 4;
! 2044: strlcpy(dip->un.e.member[0].label.name,
! 2045: AudioNmicrophone,
! 2046: sizeof dip->un.e.member[0].label.name);
! 2047: dip->un.e.member[0].ord = ESS_SOURCE_MIC;
! 2048: strlcpy(dip->un.e.member[1].label.name, AudioNline,
! 2049: sizeof dip->un.e.member[1].label.name);
! 2050: dip->un.e.member[1].ord = ESS_SOURCE_LINE;
! 2051: strlcpy(dip->un.e.member[2].label.name, AudioNcd,
! 2052: sizeof dip->un.e.member[2].label.name);
! 2053: dip->un.e.member[2].ord = ESS_SOURCE_CD;
! 2054: strlcpy(dip->un.e.member[3].label.name, AudioNmixerout,
! 2055: sizeof dip->un.e.member[3].label.name);
! 2056: dip->un.e.member[3].ord = ESS_SOURCE_MIXER;
! 2057: } else {
! 2058: dip->type = AUDIO_MIXER_SET;
! 2059: dip->un.s.num_mem = 6;
! 2060: strlcpy(dip->un.s.member[0].label.name, AudioNdac,
! 2061: sizeof dip->un.e.member[0].label.name);
! 2062: dip->un.s.member[0].mask = 1 << ESS_DAC_REC_VOL;
! 2063: strlcpy(dip->un.s.member[1].label.name,
! 2064: AudioNmicrophone,
! 2065: sizeof dip->un.e.member[1].label.name);
! 2066: dip->un.s.member[1].mask = 1 << ESS_MIC_REC_VOL;
! 2067: strlcpy(dip->un.s.member[2].label.name, AudioNline,
! 2068: sizeof dip->un.e.member[2].label.name);
! 2069: dip->un.s.member[2].mask = 1 << ESS_LINE_REC_VOL;
! 2070: strlcpy(dip->un.s.member[3].label.name, AudioNfmsynth,
! 2071: sizeof dip->un.e.member[3].label.name);
! 2072: dip->un.s.member[3].mask = 1 << ESS_SYNTH_REC_VOL;
! 2073: strlcpy(dip->un.s.member[4].label.name, AudioNcd,
! 2074: sizeof dip->un.e.member[4].label.name);
! 2075: dip->un.s.member[4].mask = 1 << ESS_CD_REC_VOL;
! 2076: strlcpy(dip->un.s.member[5].label.name, "auxb",
! 2077: sizeof dip->un.e.member[5].label.name);
! 2078: dip->un.s.member[5].mask = 1 << ESS_AUXB_REC_VOL;
! 2079: }
! 2080: return (0);
! 2081:
! 2082: case ESS_RECORD_CLASS:
! 2083: dip->mixer_class = ESS_RECORD_CLASS;
! 2084: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2085: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
! 2086: dip->type = AUDIO_MIXER_CLASS;
! 2087: return (0);
! 2088:
! 2089: case ESS_RECORD_MONITOR:
! 2090: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2091: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
! 2092: dip->type = AUDIO_MIXER_ENUM;
! 2093: dip->mixer_class = ESS_MONITOR_CLASS;
! 2094: dip->un.e.num_mem = 2;
! 2095: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2096: sizeof dip->un.e.member[0].label.name);
! 2097: dip->un.e.member[0].ord = 0;
! 2098: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2099: sizeof dip->un.e.member[1].label.name);
! 2100: dip->un.e.member[1].ord = 1;
! 2101: return (0);
! 2102:
! 2103: case ESS_MONITOR_CLASS:
! 2104: dip->mixer_class = ESS_MONITOR_CLASS;
! 2105: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2106: strlcpy(dip->label.name, AudioCmonitor,
! 2107: sizeof dip->label.name);
! 2108: dip->type = AUDIO_MIXER_CLASS;
! 2109: return (0);
! 2110: }
! 2111:
! 2112: if (ESS_USE_AUDIO1(sc->sc_model))
! 2113: return (ENXIO);
! 2114:
! 2115: switch (dip->index) {
! 2116: case ESS_DAC_REC_VOL:
! 2117: dip->mixer_class = ESS_RECORD_CLASS;
! 2118: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2119: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
! 2120: dip->type = AUDIO_MIXER_VALUE;
! 2121: dip->un.v.num_channels = 2;
! 2122: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2123: sizeof dip->un.v.units.name);
! 2124: return (0);
! 2125:
! 2126: case ESS_MIC_REC_VOL:
! 2127: dip->mixer_class = ESS_RECORD_CLASS;
! 2128: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2129: strlcpy(dip->label.name, AudioNmicrophone,
! 2130: sizeof dip->label.name);
! 2131: dip->type = AUDIO_MIXER_VALUE;
! 2132: dip->un.v.num_channels = 2;
! 2133: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2134: sizeof dip->un.v.units.name);
! 2135: return (0);
! 2136:
! 2137: case ESS_LINE_REC_VOL:
! 2138: dip->mixer_class = ESS_RECORD_CLASS;
! 2139: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2140: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
! 2141: dip->type = AUDIO_MIXER_VALUE;
! 2142: dip->un.v.num_channels = 2;
! 2143: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2144: sizeof dip->un.v.units.name);
! 2145: return (0);
! 2146:
! 2147: case ESS_SYNTH_REC_VOL:
! 2148: dip->mixer_class = ESS_RECORD_CLASS;
! 2149: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2150: strlcpy(dip->label.name, AudioNfmsynth,
! 2151: sizeof dip->label.name);
! 2152: dip->type = AUDIO_MIXER_VALUE;
! 2153: dip->un.v.num_channels = 2;
! 2154: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2155: sizeof dip->un.v.units.name);
! 2156: return (0);
! 2157:
! 2158: case ESS_CD_REC_VOL:
! 2159: dip->mixer_class = ESS_RECORD_CLASS;
! 2160: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2161: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
! 2162: dip->type = AUDIO_MIXER_VALUE;
! 2163: dip->un.v.num_channels = 2;
! 2164: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2165: sizeof dip->un.v.units.name);
! 2166: return (0);
! 2167:
! 2168: case ESS_AUXB_REC_VOL:
! 2169: dip->mixer_class = ESS_RECORD_CLASS;
! 2170: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2171: strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
! 2172: dip->type = AUDIO_MIXER_VALUE;
! 2173: dip->un.v.num_channels = 2;
! 2174: strlcpy(dip->un.v.units.name, AudioNvolume,
! 2175: sizeof dip->un.v.units.name);
! 2176: return (0);
! 2177:
! 2178: case ESS_MIC_PREAMP:
! 2179: dip->mixer_class = ESS_INPUT_CLASS;
! 2180: dip->prev = ESS_MIC_PLAY_VOL;
! 2181: dip->next = AUDIO_MIXER_LAST;
! 2182: strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
! 2183: dip->type = AUDIO_MIXER_ENUM;
! 2184: dip->un.e.num_mem = 2;
! 2185: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2186: sizeof dip->un.e.member[0].label.name);
! 2187: dip->un.e.member[0].ord = 0;
! 2188: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2189: sizeof dip->un.e.member[1].label.name);
! 2190: dip->un.e.member[1].ord = 1;
! 2191: return (0);
! 2192: }
! 2193:
! 2194: return (ENXIO);
! 2195: }
! 2196:
! 2197: void *
! 2198: ess_malloc(addr, direction, size, pool, flags)
! 2199: void *addr;
! 2200: int direction;
! 2201: size_t size;
! 2202: int pool, flags;
! 2203: {
! 2204: struct ess_softc *sc = addr;
! 2205: int drq;
! 2206:
! 2207: if (!ESS_USE_AUDIO1(sc->sc_model))
! 2208: drq = sc->sc_audio2.drq;
! 2209: else
! 2210: drq = sc->sc_audio1.drq;
! 2211: return (isa_malloc(sc->sc_isa, drq, size, pool, flags));
! 2212: }
! 2213:
! 2214: void
! 2215: ess_free(addr, ptr, pool)
! 2216: void *addr;
! 2217: void *ptr;
! 2218: int pool;
! 2219: {
! 2220: isa_free(ptr, pool);
! 2221: }
! 2222:
! 2223: size_t
! 2224: ess_round_buffersize(addr, direction, size)
! 2225: void *addr;
! 2226: int direction;
! 2227: size_t size;
! 2228: {
! 2229: if (size > MAX_ISADMA)
! 2230: size = MAX_ISADMA;
! 2231: return (size);
! 2232: }
! 2233:
! 2234: paddr_t
! 2235: ess_mappage(addr, mem, off, prot)
! 2236: void *addr;
! 2237: void *mem;
! 2238: off_t off;
! 2239: int prot;
! 2240: {
! 2241: return (isa_mappage(mem, off, prot));
! 2242: }
! 2243:
! 2244: int
! 2245: ess_1788_get_props(addr)
! 2246: void *addr;
! 2247: {
! 2248:
! 2249: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT);
! 2250: }
! 2251:
! 2252: int
! 2253: ess_1888_get_props(addr)
! 2254: void *addr;
! 2255: {
! 2256:
! 2257: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
! 2258: }
! 2259:
! 2260: /* ============================================
! 2261: * Generic functions for ess, not used by audio h/w i/f
! 2262: * =============================================
! 2263: */
! 2264:
! 2265: /*
! 2266: * Reset the chip.
! 2267: * Return non-zero if the chip isn't detected.
! 2268: */
! 2269: int
! 2270: ess_reset(sc)
! 2271: struct ess_softc *sc;
! 2272: {
! 2273: bus_space_tag_t iot = sc->sc_iot;
! 2274: bus_space_handle_t ioh = sc->sc_ioh;
! 2275:
! 2276: sc->sc_audio1.active = 0;
! 2277: sc->sc_audio2.active = 0;
! 2278:
! 2279: EWRITE1(iot, ioh, ESS_DSP_RESET, ESS_RESET_EXT);
! 2280: delay(10000);
! 2281: EWRITE1(iot, ioh, ESS_DSP_RESET, 0);
! 2282: if (ess_rdsp(sc) != ESS_MAGIC)
! 2283: return (1);
! 2284:
! 2285: /* Enable access to the ESS extension commands. */
! 2286: ess_wdsp(sc, ESS_ACMD_ENABLE_EXT);
! 2287:
! 2288: return (0);
! 2289: }
! 2290:
! 2291: void
! 2292: ess_set_gain(sc, port, on)
! 2293: struct ess_softc *sc;
! 2294: int port;
! 2295: int on;
! 2296: {
! 2297: int gain, left, right;
! 2298: int mix;
! 2299: int src;
! 2300: int stereo;
! 2301:
! 2302: /*
! 2303: * Most gain controls are found in the mixer registers and
! 2304: * are stereo. Any that are not, must set mix and stereo as
! 2305: * required.
! 2306: */
! 2307: mix = 1;
! 2308: stereo = 1;
! 2309:
! 2310: switch (port) {
! 2311: case ESS_MASTER_VOL:
! 2312: src = ESS_MREG_VOLUME_MASTER;
! 2313: break;
! 2314: case ESS_DAC_PLAY_VOL:
! 2315: if (ESS_USE_AUDIO1(sc->sc_model))
! 2316: src = ESS_MREG_VOLUME_VOICE;
! 2317: else
! 2318: src = 0x7C;
! 2319: break;
! 2320: case ESS_MIC_PLAY_VOL:
! 2321: src = ESS_MREG_VOLUME_MIC;
! 2322: break;
! 2323: case ESS_LINE_PLAY_VOL:
! 2324: src = ESS_MREG_VOLUME_LINE;
! 2325: break;
! 2326: case ESS_SYNTH_PLAY_VOL:
! 2327: src = ESS_MREG_VOLUME_SYNTH;
! 2328: break;
! 2329: case ESS_CD_PLAY_VOL:
! 2330: src = ESS_MREG_VOLUME_CD;
! 2331: break;
! 2332: case ESS_AUXB_PLAY_VOL:
! 2333: src = ESS_MREG_VOLUME_AUXB;
! 2334: break;
! 2335: case ESS_PCSPEAKER_VOL:
! 2336: src = ESS_MREG_VOLUME_PCSPKR;
! 2337: stereo = 0;
! 2338: break;
! 2339: case ESS_DAC_REC_VOL:
! 2340: src = 0x69;
! 2341: break;
! 2342: case ESS_MIC_REC_VOL:
! 2343: src = 0x68;
! 2344: break;
! 2345: case ESS_LINE_REC_VOL:
! 2346: src = 0x6E;
! 2347: break;
! 2348: case ESS_SYNTH_REC_VOL:
! 2349: src = 0x6B;
! 2350: break;
! 2351: case ESS_CD_REC_VOL:
! 2352: src = 0x6A;
! 2353: break;
! 2354: case ESS_AUXB_REC_VOL:
! 2355: src = 0x6C;
! 2356: break;
! 2357: case ESS_RECORD_VOL:
! 2358: src = ESS_XCMD_VOLIN_CTRL;
! 2359: mix = 0;
! 2360: break;
! 2361: default:
! 2362: return;
! 2363: }
! 2364:
! 2365: /* 1788 doesn't have a separate recording mixer */
! 2366: if (ESS_USE_AUDIO1(sc->sc_model) && mix && src > 0x62)
! 2367: return;
! 2368:
! 2369: if (on) {
! 2370: left = sc->gain[port][ESS_LEFT];
! 2371: right = sc->gain[port][ESS_RIGHT];
! 2372: } else {
! 2373: left = right = 0;
! 2374: }
! 2375:
! 2376: if (stereo)
! 2377: gain = ESS_STEREO_GAIN(left, right);
! 2378: else
! 2379: gain = ESS_MONO_GAIN(left);
! 2380:
! 2381: if (mix)
! 2382: ess_write_mix_reg(sc, src, gain);
! 2383: else
! 2384: ess_write_x_reg(sc, src, gain);
! 2385: }
! 2386:
! 2387: /* Set the input device on devices without an input mixer. */
! 2388: int
! 2389: ess_set_in_port(sc, ord)
! 2390: struct ess_softc *sc;
! 2391: int ord;
! 2392: {
! 2393: mixer_devinfo_t di;
! 2394: int i;
! 2395:
! 2396: DPRINTF(("ess_set_in_port: ord=0x%x\n", ord));
! 2397:
! 2398: /*
! 2399: * Get the device info for the record source control,
! 2400: * including the list of available sources.
! 2401: */
! 2402: di.index = ESS_RECORD_SOURCE;
! 2403: if (ess_query_devinfo(sc, &di))
! 2404: return EINVAL;
! 2405:
! 2406: /* See if the given ord value was anywhere in the list. */
! 2407: for (i = 0; i < di.un.e.num_mem; i++) {
! 2408: if (ord == di.un.e.member[i].ord)
! 2409: break;
! 2410: }
! 2411: if (i == di.un.e.num_mem)
! 2412: return EINVAL;
! 2413:
! 2414: ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ord);
! 2415:
! 2416: sc->in_port = ord;
! 2417: return (0);
! 2418: }
! 2419:
! 2420: /* Set the input device levels on input-mixer-enabled devices. */
! 2421: int
! 2422: ess_set_in_ports(sc, mask)
! 2423: struct ess_softc *sc;
! 2424: int mask;
! 2425: {
! 2426: mixer_devinfo_t di;
! 2427: int i, port;
! 2428:
! 2429: DPRINTF(("ess_set_in_ports: mask=0x%x\n", mask));
! 2430:
! 2431: /*
! 2432: * Get the device info for the record source control,
! 2433: * including the list of available sources.
! 2434: */
! 2435: di.index = ESS_RECORD_SOURCE;
! 2436: if (ess_query_devinfo(sc, &di))
! 2437: return EINVAL;
! 2438:
! 2439: /*
! 2440: * Set or disable the record volume control for each of the
! 2441: * possible sources.
! 2442: */
! 2443: for (i = 0; i < di.un.s.num_mem; i++) {
! 2444: /*
! 2445: * Calculate the source port number from its mask.
! 2446: */
! 2447: port = ffs(di.un.s.member[i].mask);
! 2448:
! 2449: /*
! 2450: * Set the source gain:
! 2451: * to the current value if source is enabled
! 2452: * to zero if source is disabled
! 2453: */
! 2454: ess_set_gain(sc, port, mask & di.un.s.member[i].mask);
! 2455: }
! 2456:
! 2457: sc->in_mask = mask;
! 2458: return (0);
! 2459: }
! 2460:
! 2461: void
! 2462: ess_speaker_on(sc)
! 2463: struct ess_softc *sc;
! 2464: {
! 2465: /* Unmute the DAC. */
! 2466: ess_set_gain(sc, ESS_DAC_PLAY_VOL, 1);
! 2467: }
! 2468:
! 2469: void
! 2470: ess_speaker_off(sc)
! 2471: struct ess_softc *sc;
! 2472: {
! 2473: /* Mute the DAC. */
! 2474: ess_set_gain(sc, ESS_DAC_PLAY_VOL, 0);
! 2475: }
! 2476:
! 2477: /*
! 2478: * Calculate the time constant for the requested sampling rate.
! 2479: */
! 2480: u_int
! 2481: ess_srtotc(rate)
! 2482: u_int rate;
! 2483: {
! 2484: u_int tc;
! 2485:
! 2486: /* The following formulae are from the ESS data sheet. */
! 2487: if (rate <= 22050)
! 2488: tc = 128 - 397700L / rate;
! 2489: else
! 2490: tc = 256 - 795500L / rate;
! 2491:
! 2492: return (tc);
! 2493: }
! 2494:
! 2495:
! 2496: /*
! 2497: * Calculate the filter constant for the reuqested sampling rate.
! 2498: */
! 2499: u_int
! 2500: ess_srtofc(rate)
! 2501: u_int rate;
! 2502: {
! 2503: /*
! 2504: * The following formula is derived from the information in
! 2505: * the ES1887 data sheet, based on a roll-off frequency of
! 2506: * 87%.
! 2507: */
! 2508: return (256 - 200279L / rate);
! 2509: }
! 2510:
! 2511:
! 2512: /*
! 2513: * Return the status of the DSP.
! 2514: */
! 2515: u_char
! 2516: ess_get_dsp_status(sc)
! 2517: struct ess_softc *sc;
! 2518: {
! 2519: return (EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_RW_STATUS));
! 2520: }
! 2521:
! 2522:
! 2523: /*
! 2524: * Return the read status of the DSP: 1 -> DSP ready for reading
! 2525: * 0 -> DSP not ready for reading
! 2526: */
! 2527: u_char
! 2528: ess_dsp_read_ready(sc)
! 2529: struct ess_softc *sc;
! 2530: {
! 2531: return ((ess_get_dsp_status(sc) & ESS_DSP_READ_READY) ? 1 : 0);
! 2532: }
! 2533:
! 2534:
! 2535: /*
! 2536: * Return the write status of the DSP: 1 -> DSP ready for writing
! 2537: * 0 -> DSP not ready for writing
! 2538: */
! 2539: u_char
! 2540: ess_dsp_write_ready(sc)
! 2541: struct ess_softc *sc;
! 2542: {
! 2543: return ((ess_get_dsp_status(sc) & ESS_DSP_WRITE_BUSY) ? 0 : 1);
! 2544: }
! 2545:
! 2546:
! 2547: /*
! 2548: * Read a byte from the DSP.
! 2549: */
! 2550: int
! 2551: ess_rdsp(sc)
! 2552: struct ess_softc *sc;
! 2553: {
! 2554: bus_space_tag_t iot = sc->sc_iot;
! 2555: bus_space_handle_t ioh = sc->sc_ioh;
! 2556: int i;
! 2557:
! 2558: for (i = ESS_READ_TIMEOUT; i > 0; --i) {
! 2559: if (ess_dsp_read_ready(sc)) {
! 2560: i = EREAD1(iot, ioh, ESS_DSP_READ);
! 2561: DPRINTFN(8,("ess_rdsp() = 0x%02x\n", i));
! 2562: return i;
! 2563: } else
! 2564: delay(10);
! 2565: }
! 2566:
! 2567: DPRINTF(("ess_rdsp: timed out\n"));
! 2568: return (-1);
! 2569: }
! 2570:
! 2571: /*
! 2572: * Write a byte to the DSP.
! 2573: */
! 2574: int
! 2575: ess_wdsp(sc, v)
! 2576: struct ess_softc *sc;
! 2577: u_char v;
! 2578: {
! 2579: bus_space_tag_t iot = sc->sc_iot;
! 2580: bus_space_handle_t ioh = sc->sc_ioh;
! 2581: int i;
! 2582:
! 2583: DPRINTFN(8,("ess_wdsp(0x%02x)\n", v));
! 2584:
! 2585: for (i = ESS_WRITE_TIMEOUT; i > 0; --i) {
! 2586: if (ess_dsp_write_ready(sc)) {
! 2587: EWRITE1(iot, ioh, ESS_DSP_WRITE, v);
! 2588: return (0);
! 2589: } else
! 2590: delay(10);
! 2591: }
! 2592:
! 2593: DPRINTF(("ess_wdsp(0x%02x): timed out\n", v));
! 2594: return (-1);
! 2595: }
! 2596:
! 2597: /*
! 2598: * Write a value to one of the ESS extended registers.
! 2599: */
! 2600: int
! 2601: ess_write_x_reg(sc, reg, val)
! 2602: struct ess_softc *sc;
! 2603: u_char reg;
! 2604: u_char val;
! 2605: {
! 2606: int error;
! 2607:
! 2608: DPRINTFN(2,("ess_write_x_reg: %02x=%02x\n", reg, val));
! 2609: if ((error = ess_wdsp(sc, reg)) == 0)
! 2610: error = ess_wdsp(sc, val);
! 2611:
! 2612: return error;
! 2613: }
! 2614:
! 2615: /*
! 2616: * Read the value of one of the ESS extended registers.
! 2617: */
! 2618: u_char
! 2619: ess_read_x_reg(sc, reg)
! 2620: struct ess_softc *sc;
! 2621: u_char reg;
! 2622: {
! 2623: int error;
! 2624: int val;
! 2625:
! 2626: if ((error = ess_wdsp(sc, 0xC0)) == 0)
! 2627: error = ess_wdsp(sc, reg);
! 2628: if (error)
! 2629: DPRINTF(("Error reading extended register 0x%02x\n", reg));
! 2630: /* REVISIT: what if an error is returned above? */
! 2631: val = ess_rdsp(sc);
! 2632: DPRINTFN(2,("ess_read_x_reg: %02x=%02x\n", reg, val));
! 2633: return val;
! 2634: }
! 2635:
! 2636: void
! 2637: ess_clear_xreg_bits(sc, reg, mask)
! 2638: struct ess_softc *sc;
! 2639: u_char reg;
! 2640: u_char mask;
! 2641: {
! 2642: if (ess_write_x_reg(sc, reg, ess_read_x_reg(sc, reg) & ~mask) == -1)
! 2643: DPRINTF(("Error clearing bits in extended register 0x%02x\n",
! 2644: reg));
! 2645: }
! 2646:
! 2647: void
! 2648: ess_set_xreg_bits(sc, reg, mask)
! 2649: struct ess_softc *sc;
! 2650: u_char reg;
! 2651: u_char mask;
! 2652: {
! 2653: if (ess_write_x_reg(sc, reg, ess_read_x_reg(sc, reg) | mask) == -1)
! 2654: DPRINTF(("Error setting bits in extended register 0x%02x\n",
! 2655: reg));
! 2656: }
! 2657:
! 2658:
! 2659: /*
! 2660: * Write a value to one of the ESS mixer registers.
! 2661: */
! 2662: void
! 2663: ess_write_mix_reg(sc, reg, val)
! 2664: struct ess_softc *sc;
! 2665: u_char reg;
! 2666: u_char val;
! 2667: {
! 2668: bus_space_tag_t iot = sc->sc_iot;
! 2669: bus_space_handle_t ioh = sc->sc_ioh;
! 2670: int s;
! 2671:
! 2672: DPRINTFN(2,("ess_write_mix_reg: %x=%x\n", reg, val));
! 2673:
! 2674: s = splaudio();
! 2675: EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
! 2676: EWRITE1(iot, ioh, ESS_MIX_REG_DATA, val);
! 2677: splx(s);
! 2678: }
! 2679:
! 2680: /*
! 2681: * Read the value of one of the ESS mixer registers.
! 2682: */
! 2683: u_char
! 2684: ess_read_mix_reg(sc, reg)
! 2685: struct ess_softc *sc;
! 2686: u_char reg;
! 2687: {
! 2688: bus_space_tag_t iot = sc->sc_iot;
! 2689: bus_space_handle_t ioh = sc->sc_ioh;
! 2690: int s;
! 2691: u_char val;
! 2692:
! 2693: s = splaudio();
! 2694: EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
! 2695: val = EREAD1(iot, ioh, ESS_MIX_REG_DATA);
! 2696: splx(s);
! 2697:
! 2698: DPRINTFN(2,("ess_read_mix_reg: %x=%x\n", reg, val));
! 2699: return val;
! 2700: }
! 2701:
! 2702: void
! 2703: ess_clear_mreg_bits(sc, reg, mask)
! 2704: struct ess_softc *sc;
! 2705: u_char reg;
! 2706: u_char mask;
! 2707: {
! 2708: ess_write_mix_reg(sc, reg, ess_read_mix_reg(sc, reg) & ~mask);
! 2709: }
! 2710:
! 2711: void
! 2712: ess_set_mreg_bits(sc, reg, mask)
! 2713: struct ess_softc *sc;
! 2714: u_char reg;
! 2715: u_char mask;
! 2716: {
! 2717: ess_write_mix_reg(sc, reg, ess_read_mix_reg(sc, reg) | mask);
! 2718: }
! 2719:
! 2720: void
! 2721: ess_read_multi_mix_reg(sc, reg, datap, count)
! 2722: struct ess_softc *sc;
! 2723: u_char reg;
! 2724: u_int8_t *datap;
! 2725: bus_size_t count;
! 2726: {
! 2727: bus_space_tag_t iot = sc->sc_iot;
! 2728: bus_space_handle_t ioh = sc->sc_ioh;
! 2729: int s;
! 2730:
! 2731: s = splaudio();
! 2732: EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
! 2733: bus_space_read_multi_1(iot, ioh, ESS_MIX_REG_DATA, datap, count);
! 2734: splx(s);
! 2735: }
CVSweb