Annotation of sys/dev/isa/sbdsp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sbdsp.c,v 1.25 2006/12/29 13:04:37 pedro Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1991-1993 Regents of the University of California.
! 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: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by the Computer Systems
! 18: * Engineering Group at Lawrence Berkeley Laboratory.
! 19: * 4. Neither the name of the University nor of the Laboratory may be used
! 20: * to endorse or promote products derived from this software without
! 21: * specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: */
! 36:
! 37: /*
! 38: * SoundBlaster Pro code provided by John Kohl, based on lots of
! 39: * information he gleaned from Steve Haehnichen <steve@vigra.com>'s
! 40: * SBlast driver for 386BSD and DOS driver code from Daniel Sachs
! 41: * <sachs@meibm15.cen.uiuc.edu>.
! 42: * Lots of rewrites by Lennart Augustsson <augustss@cs.chalmers.se>
! 43: * with information from SB "Hardware Programming Guide" and the
! 44: * Linux drivers.
! 45: */
! 46:
! 47: #include "midi.h"
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/errno.h>
! 52: #include <sys/ioctl.h>
! 53: #include <sys/syslog.h>
! 54: #include <sys/device.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/buf.h>
! 57:
! 58: #include <machine/cpu.h>
! 59: #include <machine/intr.h>
! 60: #include <machine/bus.h>
! 61:
! 62: #include <sys/audioio.h>
! 63: #include <dev/audio_if.h>
! 64: #include <dev/midi_if.h>
! 65: #include <dev/mulaw.h>
! 66: #include <dev/auconv.h>
! 67:
! 68: #include <dev/isa/isavar.h>
! 69: #include <dev/isa/isadmavar.h>
! 70:
! 71: #include <dev/isa/sbreg.h>
! 72: #include <dev/isa/sbdspvar.h>
! 73:
! 74:
! 75: #ifdef AUDIO_DEBUG
! 76: #define DPRINTF(x) if (sbdspdebug) printf x
! 77: #define DPRINTFN(n,x) if (sbdspdebug >= (n)) printf x
! 78: int sbdspdebug = 0;
! 79: #else
! 80: #define DPRINTF(x)
! 81: #define DPRINTFN(n,x)
! 82: #endif
! 83:
! 84: #ifndef SBDSP_NPOLL
! 85: #define SBDSP_NPOLL 3000
! 86: #endif
! 87:
! 88: struct {
! 89: int wdsp;
! 90: int rdsp;
! 91: int wmidi;
! 92: } sberr;
! 93:
! 94: /*
! 95: * Time constant routines follow. See SBK, section 12.
! 96: * Although they don't come out and say it (in the docs),
! 97: * the card clearly uses a 1MHz countdown timer, as the
! 98: * low-speed formula (p. 12-4) is:
! 99: * tc = 256 - 10^6 / sr
! 100: * In high-speed mode, the constant is the upper byte of a 16-bit counter,
! 101: * and a 256MHz clock is used:
! 102: * tc = 65536 - 256 * 10^ 6 / sr
! 103: * Since we can only use the upper byte of the HS TC, the two formulae
! 104: * are equivalent. (Why didn't they say so?) E.g.,
! 105: * (65536 - 256 * 10 ^ 6 / x) >> 8 = 256 - 10^6 / x
! 106: *
! 107: * The crossover point (from low- to high-speed modes) is different
! 108: * for the SBPRO and SB20. The table on p. 12-5 gives the following data:
! 109: *
! 110: * SBPRO SB20
! 111: * ----- --------
! 112: * input ls min 4 KHz 4 KHz
! 113: * input ls max 23 KHz 13 KHz
! 114: * input hs max 44.1 KHz 15 KHz
! 115: * output ls min 4 KHz 4 KHz
! 116: * output ls max 23 KHz 23 KHz
! 117: * output hs max 44.1 KHz 44.1 KHz
! 118: */
! 119: /* XXX Should we round the tc?
! 120: #define SB_RATE_TO_TC(x) (((65536 - 256 * 1000000 / (x)) + 128) >> 8)
! 121: */
! 122: #define SB_RATE_TO_TC(x) (256 - 1000000 / (x))
! 123: #define SB_TC_TO_RATE(tc) (1000000 / (256 - (tc)))
! 124:
! 125: struct sbmode {
! 126: short model;
! 127: u_char channels;
! 128: u_char precision;
! 129: u_short lowrate, highrate;
! 130: u_char cmd;
! 131: u_char cmdchan;
! 132: };
! 133: static struct sbmode sbpmodes[] = {
! 134: { SB_1, 1, 8, 4000, 22727, SB_DSP_WDMA },
! 135: { SB_20, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP },
! 136: { SB_2x, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP },
! 137: { SB_2x, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT },
! 138: { SB_PRO, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP },
! 139: { SB_PRO, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT },
! 140: { SB_PRO, 2, 8, 11025, 22727, SB_DSP_HS_OUTPUT },
! 141: /* Yes, we write the record mode to set 16-bit playback mode. weird, huh? */
! 142: { SB_JAZZ, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP, SB_DSP_RECORD_MONO },
! 143: { SB_JAZZ, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT, SB_DSP_RECORD_MONO },
! 144: { SB_JAZZ, 2, 8, 11025, 22727, SB_DSP_HS_OUTPUT, SB_DSP_RECORD_STEREO },
! 145: { SB_JAZZ, 1, 16, 4000, 22727, SB_DSP_WDMA_LOOP, JAZZ16_RECORD_MONO },
! 146: { SB_JAZZ, 1, 16, 22727, 45454, SB_DSP_HS_OUTPUT, JAZZ16_RECORD_MONO },
! 147: { SB_JAZZ, 2, 16, 11025, 22727, SB_DSP_HS_OUTPUT, JAZZ16_RECORD_STEREO },
! 148: { SB_16, 1, 8, 5000, 45000, SB_DSP16_WDMA_8 },
! 149: { SB_16, 2, 8, 5000, 45000, SB_DSP16_WDMA_8 },
! 150: #define PLAY16 15 /* must be the index of the next entry in the table */
! 151: { SB_16, 1, 16, 5000, 45000, SB_DSP16_WDMA_16 },
! 152: { SB_16, 2, 16, 5000, 45000, SB_DSP16_WDMA_16 },
! 153: { -1 }
! 154: };
! 155: static struct sbmode sbrmodes[] = {
! 156: { SB_1, 1, 8, 4000, 12987, SB_DSP_RDMA },
! 157: { SB_20, 1, 8, 4000, 12987, SB_DSP_RDMA_LOOP },
! 158: { SB_2x, 1, 8, 4000, 12987, SB_DSP_RDMA_LOOP },
! 159: { SB_2x, 1, 8, 12987, 14925, SB_DSP_HS_INPUT },
! 160: { SB_PRO, 1, 8, 4000, 22727, SB_DSP_RDMA_LOOP, SB_DSP_RECORD_MONO },
! 161: { SB_PRO, 1, 8, 22727, 45454, SB_DSP_HS_INPUT, SB_DSP_RECORD_MONO },
! 162: { SB_PRO, 2, 8, 11025, 22727, SB_DSP_HS_INPUT, SB_DSP_RECORD_STEREO },
! 163: { SB_JAZZ, 1, 8, 4000, 22727, SB_DSP_RDMA_LOOP, SB_DSP_RECORD_MONO },
! 164: { SB_JAZZ, 1, 8, 22727, 45454, SB_DSP_HS_INPUT, SB_DSP_RECORD_MONO },
! 165: { SB_JAZZ, 2, 8, 11025, 22727, SB_DSP_HS_INPUT, SB_DSP_RECORD_STEREO },
! 166: { SB_JAZZ, 1, 16, 4000, 22727, SB_DSP_RDMA_LOOP, JAZZ16_RECORD_MONO },
! 167: { SB_JAZZ, 1, 16, 22727, 45454, SB_DSP_HS_INPUT, JAZZ16_RECORD_MONO },
! 168: { SB_JAZZ, 2, 16, 11025, 22727, SB_DSP_HS_INPUT, JAZZ16_RECORD_STEREO },
! 169: { SB_16, 1, 8, 5000, 45000, SB_DSP16_RDMA_8 },
! 170: { SB_16, 2, 8, 5000, 45000, SB_DSP16_RDMA_8 },
! 171: { SB_16, 1, 16, 5000, 45000, SB_DSP16_RDMA_16 },
! 172: { SB_16, 2, 16, 5000, 45000, SB_DSP16_RDMA_16 },
! 173: { -1 }
! 174: };
! 175:
! 176: void sbversion(struct sbdsp_softc *);
! 177: void sbdsp_jazz16_probe(struct sbdsp_softc *);
! 178: void sbdsp_set_mixer_gain(struct sbdsp_softc *sc, int port);
! 179: void sbdsp_to(void *);
! 180: void sbdsp_pause(struct sbdsp_softc *);
! 181: int sbdsp_set_timeconst(struct sbdsp_softc *, int);
! 182: int sbdsp16_set_rate(struct sbdsp_softc *, int, int);
! 183: int sbdsp_set_in_ports(struct sbdsp_softc *, int);
! 184: void sbdsp_set_ifilter(void *, int);
! 185: int sbdsp_get_ifilter(void *);
! 186:
! 187: int sbdsp_block_output(void *);
! 188: int sbdsp_block_input(void *);
! 189: static int sbdsp_adjust(int, int);
! 190:
! 191: int sbdsp_midi_intr(void *);
! 192:
! 193: #ifdef AUDIO_DEBUG
! 194: void sb_printsc(struct sbdsp_softc *);
! 195:
! 196: void
! 197: sb_printsc(sc)
! 198: struct sbdsp_softc *sc;
! 199: {
! 200: int i;
! 201:
! 202: printf("open %d dmachan %d/%d %d/%d iobase 0x%x irq %d\n",
! 203: (int)sc->sc_open, sc->sc_i.run, sc->sc_o.run,
! 204: sc->sc_drq8, sc->sc_drq16,
! 205: sc->sc_iobase, sc->sc_irq);
! 206: printf("irate %d itc %x orate %d otc %x\n",
! 207: sc->sc_i.rate, sc->sc_i.tc,
! 208: sc->sc_o.rate, sc->sc_o.tc);
! 209: printf("spkron %u nintr %lu\n",
! 210: sc->spkr_state, sc->sc_interrupts);
! 211: printf("intr8 %p arg8 %p\n",
! 212: sc->sc_intr8, sc->sc_arg16);
! 213: printf("intr16 %p arg16 %p\n",
! 214: sc->sc_intr8, sc->sc_arg16);
! 215: printf("gain:");
! 216: for (i = 0; i < SB_NDEVS; i++)
! 217: printf(" %u,%u", sc->gain[i][SB_LEFT], sc->gain[i][SB_RIGHT]);
! 218: printf("\n");
! 219: }
! 220: #endif /* AUDIO_DEBUG */
! 221:
! 222: /*
! 223: * Probe / attach routines.
! 224: */
! 225:
! 226: /*
! 227: * Probe for the soundblaster hardware.
! 228: */
! 229: int
! 230: sbdsp_probe(sc)
! 231: struct sbdsp_softc *sc;
! 232: {
! 233:
! 234: if (sbdsp_reset(sc) < 0) {
! 235: DPRINTF(("sbdsp: couldn't reset card\n"));
! 236: return 0;
! 237: }
! 238: /* if flags set, go and probe the jazz16 stuff */
! 239: if (sc->sc_dev.dv_cfdata->cf_flags & 1)
! 240: sbdsp_jazz16_probe(sc);
! 241: else
! 242: sbversion(sc);
! 243: if (sc->sc_model == SB_UNK) {
! 244: /* Unknown SB model found. */
! 245: DPRINTF(("sbdsp: unknown SB model found\n"));
! 246: return 0;
! 247: }
! 248: return 1;
! 249: }
! 250:
! 251: /*
! 252: * Try add-on stuff for Jazz16.
! 253: */
! 254: void
! 255: sbdsp_jazz16_probe(sc)
! 256: struct sbdsp_softc *sc;
! 257: {
! 258: static u_char jazz16_irq_conf[16] = {
! 259: -1, -1, 0x02, 0x03,
! 260: -1, 0x01, -1, 0x04,
! 261: -1, 0x02, 0x05, -1,
! 262: -1, -1, -1, 0x06};
! 263: static u_char jazz16_drq_conf[8] = {
! 264: -1, 0x01, -1, 0x02,
! 265: -1, 0x03, -1, 0x04};
! 266:
! 267: bus_space_tag_t iot = sc->sc_iot;
! 268: bus_space_handle_t ioh;
! 269:
! 270: sbversion(sc);
! 271:
! 272: DPRINTF(("jazz16 probe\n"));
! 273:
! 274: if (bus_space_map(iot, JAZZ16_CONFIG_PORT, 1, 0, &ioh)) {
! 275: DPRINTF(("bus map failed\n"));
! 276: return;
! 277: }
! 278:
! 279: if (jazz16_drq_conf[sc->sc_drq8] == (u_char)-1 ||
! 280: jazz16_irq_conf[sc->sc_irq] == (u_char)-1) {
! 281: DPRINTF(("drq/irq check failed\n"));
! 282: goto done; /* give up, we can't do it. */
! 283: }
! 284:
! 285: bus_space_write_1(iot, ioh, 0, JAZZ16_WAKEUP);
! 286: delay(10000); /* delay 10 ms */
! 287: bus_space_write_1(iot, ioh, 0, JAZZ16_SETBASE);
! 288: bus_space_write_1(iot, ioh, 0, sc->sc_iobase & 0x70);
! 289:
! 290: if (sbdsp_reset(sc) < 0) {
! 291: DPRINTF(("sbdsp_reset check failed\n"));
! 292: goto done; /* XXX? what else could we do? */
! 293: }
! 294:
! 295: if (sbdsp_wdsp(sc, JAZZ16_READ_VER)) {
! 296: DPRINTF(("read16 setup failed\n"));
! 297: goto done;
! 298: }
! 299:
! 300: if (sbdsp_rdsp(sc) != JAZZ16_VER_JAZZ) {
! 301: DPRINTF(("read16 failed\n"));
! 302: goto done;
! 303: }
! 304:
! 305: /* XXX set both 8 & 16-bit drq to same channel, it works fine. */
! 306: sc->sc_drq16 = sc->sc_drq8;
! 307: if (sbdsp_wdsp(sc, JAZZ16_SET_DMAINTR) ||
! 308: sbdsp_wdsp(sc, (jazz16_drq_conf[sc->sc_drq16] << 4) |
! 309: jazz16_drq_conf[sc->sc_drq8]) ||
! 310: sbdsp_wdsp(sc, jazz16_irq_conf[sc->sc_irq])) {
! 311: DPRINTF(("sbdsp: can't write jazz16 probe stuff\n"));
! 312: } else {
! 313: DPRINTF(("jazz16 detected!\n"));
! 314: sc->sc_model = SB_JAZZ;
! 315: sc->sc_mixer_model = SBM_CT1345; /* XXX really? */
! 316: }
! 317:
! 318: done:
! 319: bus_space_unmap(iot, ioh, 1);
! 320: }
! 321:
! 322: /*
! 323: * Attach hardware to driver, attach hardware driver to audio
! 324: * pseudo-device driver .
! 325: */
! 326: void
! 327: sbdsp_attach(sc)
! 328: struct sbdsp_softc *sc;
! 329: {
! 330: struct audio_params pparams, rparams;
! 331: int i;
! 332: u_int v;
! 333:
! 334: /*
! 335: * Create our DMA maps.
! 336: */
! 337: if (sc->sc_drq8 != -1) {
! 338: if (isa_dmamap_create(sc->sc_isa, sc->sc_drq8,
! 339: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 340: printf("%s: can't create map for drq %d\n",
! 341: sc->sc_dev.dv_xname, sc->sc_drq8);
! 342: return;
! 343: }
! 344: }
! 345: if (sc->sc_drq16 != -1 && sc->sc_drq16 != sc->sc_drq8) {
! 346: if (isa_dmamap_create(sc->sc_isa, sc->sc_drq16,
! 347: MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
! 348: printf("%s: can't create map for drq %d\n",
! 349: sc->sc_dev.dv_xname, sc->sc_drq16);
! 350: return;
! 351: }
! 352: }
! 353:
! 354: pparams = audio_default;
! 355: rparams = audio_default;
! 356: sbdsp_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
! 357:
! 358: sbdsp_set_in_ports(sc, 1 << SB_MIC_VOL);
! 359:
! 360: if (sc->sc_mixer_model != SBM_NONE) {
! 361: /* Reset the mixer.*/
! 362: sbdsp_mix_write(sc, SBP_MIX_RESET, SBP_MIX_RESET);
! 363: /* And set our own default values */
! 364: for (i = 0; i < SB_NDEVS; i++) {
! 365: switch(i) {
! 366: case SB_MIC_VOL:
! 367: case SB_LINE_IN_VOL:
! 368: v = 0;
! 369: break;
! 370: case SB_BASS:
! 371: case SB_TREBLE:
! 372: v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN/2);
! 373: break;
! 374: case SB_CD_IN_MUTE:
! 375: case SB_MIC_IN_MUTE:
! 376: case SB_LINE_IN_MUTE:
! 377: case SB_MIDI_IN_MUTE:
! 378: case SB_CD_SWAP:
! 379: case SB_MIC_SWAP:
! 380: case SB_LINE_SWAP:
! 381: case SB_MIDI_SWAP:
! 382: case SB_CD_OUT_MUTE:
! 383: case SB_MIC_OUT_MUTE:
! 384: case SB_LINE_OUT_MUTE:
! 385: v = 0;
! 386: break;
! 387: default:
! 388: v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2);
! 389: break;
! 390: }
! 391: sc->gain[i][SB_LEFT] = sc->gain[i][SB_RIGHT] = v;
! 392: sbdsp_set_mixer_gain(sc, i);
! 393: }
! 394: sc->in_filter = 0; /* no filters turned on, please */
! 395: }
! 396:
! 397: printf(": dsp v%d.%02d%s\n",
! 398: SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version),
! 399: sc->sc_model == SB_JAZZ ? ": <Jazz16>" : "");
! 400:
! 401: timeout_set(&sc->sc_tmo, sbdsp_to, sbdsp_to);
! 402: sc->sc_fullduplex = ISSB16CLASS(sc) &&
! 403: sc->sc_drq8 != -1 && sc->sc_drq16 != -1 &&
! 404: sc->sc_drq8 != sc->sc_drq16;
! 405: }
! 406:
! 407: void
! 408: sbdsp_mix_write(sc, mixerport, val)
! 409: struct sbdsp_softc *sc;
! 410: int mixerport;
! 411: int val;
! 412: {
! 413: bus_space_tag_t iot = sc->sc_iot;
! 414: bus_space_handle_t ioh = sc->sc_ioh;
! 415: int s;
! 416:
! 417: s = splaudio();
! 418: bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport);
! 419: delay(20);
! 420: bus_space_write_1(iot, ioh, SBP_MIXER_DATA, val);
! 421: delay(30);
! 422: splx(s);
! 423: }
! 424:
! 425: int
! 426: sbdsp_mix_read(sc, mixerport)
! 427: struct sbdsp_softc *sc;
! 428: int mixerport;
! 429: {
! 430: bus_space_tag_t iot = sc->sc_iot;
! 431: bus_space_handle_t ioh = sc->sc_ioh;
! 432: int val;
! 433: int s;
! 434:
! 435: s = splaudio();
! 436: bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport);
! 437: delay(20);
! 438: val = bus_space_read_1(iot, ioh, SBP_MIXER_DATA);
! 439: delay(30);
! 440: splx(s);
! 441: return val;
! 442: }
! 443:
! 444: /*
! 445: * Various routines to interface to higher level audio driver
! 446: */
! 447:
! 448: int
! 449: sbdsp_query_encoding(addr, fp)
! 450: void *addr;
! 451: struct audio_encoding *fp;
! 452: {
! 453: struct sbdsp_softc *sc = addr;
! 454: int emul;
! 455:
! 456: emul = ISSB16CLASS(sc) ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
! 457:
! 458: switch (fp->index) {
! 459: case 0:
! 460: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 461: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 462: fp->precision = 8;
! 463: fp->flags = 0;
! 464: return 0;
! 465: case 1:
! 466: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 467: fp->encoding = AUDIO_ENCODING_ULAW;
! 468: fp->precision = 8;
! 469: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 470: return 0;
! 471: case 2:
! 472: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 473: fp->encoding = AUDIO_ENCODING_ALAW;
! 474: fp->precision = 8;
! 475: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 476: return 0;
! 477: case 3:
! 478: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 479: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 480: fp->precision = 8;
! 481: fp->flags = emul;
! 482: return 0;
! 483: }
! 484: if (!ISSB16CLASS(sc) && sc->sc_model != SB_JAZZ)
! 485: return EINVAL;
! 486:
! 487: switch(fp->index) {
! 488: case 4:
! 489: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 490: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 491: fp->precision = 16;
! 492: fp->flags = 0;
! 493: return 0;
! 494: case 5:
! 495: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 496: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 497: fp->precision = 16;
! 498: fp->flags = emul;
! 499: return 0;
! 500: case 6:
! 501: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 502: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 503: fp->precision = 16;
! 504: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 505: return 0;
! 506: case 7:
! 507: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 508: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 509: fp->precision = 16;
! 510: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 511: return 0;
! 512: default:
! 513: return EINVAL;
! 514: }
! 515: return 0;
! 516: }
! 517:
! 518: int
! 519: sbdsp_set_params(addr, setmode, usemode, play, rec)
! 520: void *addr;
! 521: int setmode, usemode;
! 522: struct audio_params *play, *rec;
! 523: {
! 524: struct sbdsp_softc *sc = addr;
! 525: struct sbmode *m;
! 526: u_int rate, tc, bmode;
! 527: void (*swcode)(void *, u_char *buf, int cnt);
! 528: int factor;
! 529: int model;
! 530: int chan;
! 531: struct audio_params *p;
! 532: int mode;
! 533:
! 534: if (sc->sc_open == SB_OPEN_MIDI)
! 535: return EBUSY;
! 536:
! 537: model = sc->sc_model;
! 538: if (model > SB_16)
! 539: model = SB_16; /* later models work like SB16 */
! 540:
! 541: /*
! 542: * Prior to the SB16, we have only one clock, so make the sample
! 543: * rates match.
! 544: */
! 545: if (!ISSB16CLASS(sc) &&
! 546: play->sample_rate != rec->sample_rate &&
! 547: usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
! 548: if (setmode == AUMODE_PLAY) {
! 549: rec->sample_rate = play->sample_rate;
! 550: setmode |= AUMODE_RECORD;
! 551: } else if (setmode == AUMODE_RECORD) {
! 552: play->sample_rate = rec->sample_rate;
! 553: setmode |= AUMODE_PLAY;
! 554: } else
! 555: return (EINVAL);
! 556: }
! 557:
! 558: /* Set first record info, then play info */
! 559: for (mode = AUMODE_RECORD; mode != -1;
! 560: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 561: if ((setmode & mode) == 0)
! 562: continue;
! 563:
! 564: p = mode == AUMODE_PLAY ? play : rec;
! 565: /* Locate proper commands */
! 566: for(m = mode == AUMODE_PLAY ? sbpmodes : sbrmodes;
! 567: m->model != -1; m++) {
! 568: if (model == m->model &&
! 569: p->channels == m->channels &&
! 570: p->precision == m->precision &&
! 571: p->sample_rate >= m->lowrate &&
! 572: p->sample_rate <= m->highrate)
! 573: break;
! 574: }
! 575: if (m->model == -1)
! 576: return EINVAL;
! 577: rate = p->sample_rate;
! 578: swcode = 0;
! 579: factor = 1;
! 580: tc = 1;
! 581: bmode = -1;
! 582: if (model == SB_16) {
! 583: switch (p->encoding) {
! 584: case AUDIO_ENCODING_SLINEAR_BE:
! 585: if (p->precision == 16)
! 586: swcode = swap_bytes;
! 587: /* fall into */
! 588: case AUDIO_ENCODING_SLINEAR_LE:
! 589: bmode = SB_BMODE_SIGNED;
! 590: break;
! 591: case AUDIO_ENCODING_ULINEAR_BE:
! 592: if (p->precision == 16)
! 593: swcode = swap_bytes;
! 594: /* fall into */
! 595: case AUDIO_ENCODING_ULINEAR_LE:
! 596: bmode = SB_BMODE_UNSIGNED;
! 597: break;
! 598: case AUDIO_ENCODING_ULAW:
! 599: if (mode == AUMODE_PLAY) {
! 600: swcode = mulaw_to_ulinear16;
! 601: factor = 2;
! 602: m = &sbpmodes[PLAY16];
! 603: } else
! 604: swcode = ulinear8_to_mulaw;
! 605: bmode = SB_BMODE_UNSIGNED;
! 606: break;
! 607: case AUDIO_ENCODING_ALAW:
! 608: if (mode == AUMODE_PLAY) {
! 609: swcode = alaw_to_ulinear16;
! 610: factor = 2;
! 611: m = &sbpmodes[PLAY16];
! 612: } else
! 613: swcode = ulinear8_to_alaw;
! 614: bmode = SB_BMODE_UNSIGNED;
! 615: break;
! 616: default:
! 617: return EINVAL;
! 618: }
! 619: if (p->channels == 2)
! 620: bmode |= SB_BMODE_STEREO;
! 621: } else if (m->model == SB_JAZZ && m->precision == 16) {
! 622: switch (p->encoding) {
! 623: case AUDIO_ENCODING_SLINEAR_LE:
! 624: break;
! 625: case AUDIO_ENCODING_ULINEAR_LE:
! 626: swcode = change_sign16;
! 627: break;
! 628: case AUDIO_ENCODING_SLINEAR_BE:
! 629: swcode = swap_bytes;
! 630: break;
! 631: case AUDIO_ENCODING_ULINEAR_BE:
! 632: swcode = mode == AUMODE_PLAY ?
! 633: swap_bytes_change_sign16 : change_sign16_swap_bytes;
! 634: break;
! 635: case AUDIO_ENCODING_ULAW:
! 636: swcode = mode == AUMODE_PLAY ?
! 637: mulaw_to_ulinear8 : ulinear8_to_mulaw;
! 638: break;
! 639: case AUDIO_ENCODING_ALAW:
! 640: swcode = mode == AUMODE_PLAY ?
! 641: alaw_to_ulinear8 : ulinear8_to_alaw;
! 642: break;
! 643: default:
! 644: return EINVAL;
! 645: }
! 646: tc = SB_RATE_TO_TC(p->sample_rate * p->channels);
! 647: p->sample_rate = SB_TC_TO_RATE(tc) / p->channels;
! 648: } else {
! 649: switch (p->encoding) {
! 650: case AUDIO_ENCODING_SLINEAR_BE:
! 651: case AUDIO_ENCODING_SLINEAR_LE:
! 652: swcode = change_sign8;
! 653: break;
! 654: case AUDIO_ENCODING_ULINEAR_BE:
! 655: case AUDIO_ENCODING_ULINEAR_LE:
! 656: break;
! 657: case AUDIO_ENCODING_ULAW:
! 658: swcode = mode == AUMODE_PLAY ?
! 659: mulaw_to_ulinear8 : ulinear8_to_mulaw;
! 660: break;
! 661: case AUDIO_ENCODING_ALAW:
! 662: swcode = mode == AUMODE_PLAY ?
! 663: alaw_to_ulinear8 : ulinear8_to_alaw;
! 664: break;
! 665: default:
! 666: return EINVAL;
! 667: }
! 668: tc = SB_RATE_TO_TC(p->sample_rate * p->channels);
! 669: p->sample_rate = SB_TC_TO_RATE(tc) / p->channels;
! 670: }
! 671:
! 672: chan = m->precision == 16 ? sc->sc_drq16 : sc->sc_drq8;
! 673: if (mode == AUMODE_PLAY) {
! 674: sc->sc_o.rate = rate;
! 675: sc->sc_o.tc = tc;
! 676: sc->sc_o.modep = m;
! 677: sc->sc_o.bmode = bmode;
! 678: sc->sc_o.dmachan = chan;
! 679: } else {
! 680: sc->sc_i.rate = rate;
! 681: sc->sc_i.tc = tc;
! 682: sc->sc_i.modep = m;
! 683: sc->sc_i.bmode = bmode;
! 684: sc->sc_i.dmachan = chan;
! 685: }
! 686:
! 687: p->sw_code = swcode;
! 688: p->factor = factor;
! 689: DPRINTF(("sbdsp_set_params: model=%d, mode=%d, rate=%ld, prec=%d, chan=%d, enc=%d -> tc=%02x, cmd=%02x, bmode=%02x, cmdchan=%02x, swcode=%p, factor=%d\n",
! 690: sc->sc_model, mode, p->sample_rate, p->precision, p->channels,
! 691: p->encoding, tc, m->cmd, bmode, m->cmdchan, swcode, factor));
! 692:
! 693: }
! 694:
! 695: /*
! 696: * XXX
! 697: * Should wait for chip to be idle.
! 698: */
! 699: sc->sc_i.run = SB_NOTRUNNING;
! 700: sc->sc_o.run = SB_NOTRUNNING;
! 701:
! 702: if (sc->sc_fullduplex &&
! 703: usemode == (AUMODE_PLAY | AUMODE_RECORD) &&
! 704: sc->sc_i.dmachan == sc->sc_o.dmachan) {
! 705: DPRINTF(("sbdsp_set_params: fd=%d, usemode=%d, idma=%d, odma=%d\n", sc->sc_fullduplex, usemode, sc->sc_i.dmachan, sc->sc_o.dmachan));
! 706: if (sc->sc_o.dmachan == sc->sc_drq8) {
! 707: /* Use 16 bit DMA for playing by expanding the samples. */
! 708: play->sw_code = linear8_to_linear16;
! 709: play->factor = 2;
! 710: sc->sc_o.modep = &sbpmodes[PLAY16];
! 711: sc->sc_o.dmachan = sc->sc_drq16;
! 712: } else {
! 713: return EINVAL;
! 714: }
! 715: }
! 716: DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n",
! 717: sc->sc_i.dmachan, sc->sc_o.dmachan));
! 718:
! 719: return 0;
! 720: }
! 721:
! 722: void
! 723: sbdsp_set_ifilter(addr, which)
! 724: void *addr;
! 725: int which;
! 726: {
! 727: struct sbdsp_softc *sc = addr;
! 728: int mixval;
! 729:
! 730: mixval = sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK;
! 731: switch (which) {
! 732: case 0:
! 733: mixval |= SBP_FILTER_OFF;
! 734: break;
! 735: case SB_TREBLE:
! 736: mixval |= SBP_FILTER_ON | SBP_IFILTER_HIGH;
! 737: break;
! 738: case SB_BASS:
! 739: mixval |= SBP_FILTER_ON | SBP_IFILTER_LOW;
! 740: break;
! 741: default:
! 742: return;
! 743: }
! 744: sc->in_filter = mixval & SBP_IFILTER_MASK;
! 745: sbdsp_mix_write(sc, SBP_INFILTER, mixval);
! 746: }
! 747:
! 748: int
! 749: sbdsp_get_ifilter(addr)
! 750: void *addr;
! 751: {
! 752: struct sbdsp_softc *sc = addr;
! 753:
! 754: sc->in_filter =
! 755: sbdsp_mix_read(sc, SBP_INFILTER) & SBP_IFILTER_MASK;
! 756: switch (sc->in_filter) {
! 757: case SBP_FILTER_ON|SBP_IFILTER_HIGH:
! 758: return SB_TREBLE;
! 759: case SBP_FILTER_ON|SBP_IFILTER_LOW:
! 760: return SB_BASS;
! 761: default:
! 762: return 0;
! 763: }
! 764: }
! 765:
! 766: int
! 767: sbdsp_set_in_ports(sc, mask)
! 768: struct sbdsp_softc *sc;
! 769: int mask;
! 770: {
! 771: int bitsl, bitsr;
! 772: int sbport;
! 773:
! 774: if (sc->sc_open == SB_OPEN_MIDI)
! 775: return EBUSY;
! 776:
! 777: DPRINTF(("sbdsp_set_in_ports: model=%d, mask=%x\n",
! 778: sc->sc_mixer_model, mask));
! 779:
! 780: switch(sc->sc_mixer_model) {
! 781: case SBM_NONE:
! 782: return EINVAL;
! 783: case SBM_CT1335:
! 784: if (mask != (1 << SB_MIC_VOL))
! 785: return EINVAL;
! 786: break;
! 787: case SBM_CT1345:
! 788: switch (mask) {
! 789: case 1 << SB_MIC_VOL:
! 790: sbport = SBP_FROM_MIC;
! 791: break;
! 792: case 1 << SB_LINE_IN_VOL:
! 793: sbport = SBP_FROM_LINE;
! 794: break;
! 795: case 1 << SB_CD_VOL:
! 796: sbport = SBP_FROM_CD;
! 797: break;
! 798: default:
! 799: return (EINVAL);
! 800: }
! 801: sbdsp_mix_write(sc, SBP_RECORD_SOURCE, sbport | sc->in_filter);
! 802: break;
! 803: case SBM_CT1XX5:
! 804: case SBM_CT1745:
! 805: if (mask & ~((1<<SB_MIDI_VOL) | (1<<SB_LINE_IN_VOL) |
! 806: (1<<SB_CD_VOL) | (1<<SB_MIC_VOL)))
! 807: return EINVAL;
! 808: bitsr = 0;
! 809: if (mask & (1<<SB_MIDI_VOL)) bitsr |= SBP_MIDI_SRC_R;
! 810: if (mask & (1<<SB_LINE_IN_VOL)) bitsr |= SBP_LINE_SRC_R;
! 811: if (mask & (1<<SB_CD_VOL)) bitsr |= SBP_CD_SRC_R;
! 812: bitsl = SB_SRC_R_TO_L(bitsr);
! 813: if (mask & (1<<SB_MIC_VOL)) {
! 814: bitsl |= SBP_MIC_SRC;
! 815: bitsr |= SBP_MIC_SRC;
! 816: }
! 817: sbdsp_mix_write(sc, SBP_RECORD_SOURCE_L, bitsl);
! 818: sbdsp_mix_write(sc, SBP_RECORD_SOURCE_R, bitsr);
! 819: break;
! 820: }
! 821: sc->in_mask = mask;
! 822:
! 823: return 0;
! 824: }
! 825:
! 826: int
! 827: sbdsp_speaker_ctl(addr, newstate)
! 828: void *addr;
! 829: int newstate;
! 830: {
! 831: struct sbdsp_softc *sc = addr;
! 832:
! 833: if (sc->sc_open == SB_OPEN_MIDI)
! 834: return EBUSY;
! 835:
! 836: if ((newstate == SPKR_ON) &&
! 837: (sc->spkr_state == SPKR_OFF)) {
! 838: sbdsp_spkron(sc);
! 839: sc->spkr_state = SPKR_ON;
! 840: }
! 841: if ((newstate == SPKR_OFF) &&
! 842: (sc->spkr_state == SPKR_ON)) {
! 843: sbdsp_spkroff(sc);
! 844: sc->spkr_state = SPKR_OFF;
! 845: }
! 846: return 0;
! 847: }
! 848:
! 849: int
! 850: sbdsp_round_blocksize(addr, blk)
! 851: void *addr;
! 852: int blk;
! 853: {
! 854: return (blk + 3) & -4; /* round to biggest sample size */
! 855: }
! 856:
! 857: int
! 858: sbdsp_open(addr, flags)
! 859: void *addr;
! 860: int flags;
! 861: {
! 862: struct sbdsp_softc *sc = addr;
! 863:
! 864: DPRINTF(("sbdsp_open: sc=%p\n", sc));
! 865:
! 866: if (sc->sc_open != SB_CLOSED)
! 867: return EBUSY;
! 868: if (sbdsp_reset(sc) != 0)
! 869: return EIO;
! 870:
! 871: sc->sc_open = SB_OPEN_AUDIO;
! 872: sc->sc_openflags = flags;
! 873: sc->sc_intrm = 0;
! 874: if (ISSBPRO(sc) &&
! 875: sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) {
! 876: DPRINTF(("sbdsp_open: can't set mono mode\n"));
! 877: /* we'll readjust when it's time for DMA. */
! 878: }
! 879:
! 880: /*
! 881: * Leave most things as they were; users must change things if
! 882: * the previous process didn't leave it they way they wanted.
! 883: * Looked at another way, it's easy to set up a configuration
! 884: * in one program and leave it for another to inherit.
! 885: */
! 886: DPRINTF(("sbdsp_open: opened\n"));
! 887:
! 888: return 0;
! 889: }
! 890:
! 891: void
! 892: sbdsp_close(addr)
! 893: void *addr;
! 894: {
! 895: struct sbdsp_softc *sc = addr;
! 896:
! 897: DPRINTF(("sbdsp_close: sc=%p\n", sc));
! 898:
! 899: sc->sc_open = SB_CLOSED;
! 900: sbdsp_spkroff(sc);
! 901: sc->spkr_state = SPKR_OFF;
! 902: sc->sc_intr8 = 0;
! 903: sc->sc_intr16 = 0;
! 904: sc->sc_intrm = 0;
! 905: sbdsp_haltdma(sc);
! 906:
! 907: DPRINTF(("sbdsp_close: closed\n"));
! 908: }
! 909:
! 910: /*
! 911: * Lower-level routines
! 912: */
! 913:
! 914: /*
! 915: * Reset the card.
! 916: * Return non-zero if the card isn't detected.
! 917: */
! 918: int
! 919: sbdsp_reset(sc)
! 920: struct sbdsp_softc *sc;
! 921: {
! 922: bus_space_tag_t iot = sc->sc_iot;
! 923: bus_space_handle_t ioh = sc->sc_ioh;
! 924:
! 925: sc->sc_intr8 = 0;
! 926: sc->sc_intr16 = 0;
! 927: if (sc->sc_i.run != SB_NOTRUNNING) {
! 928: isa_dmaabort(sc->sc_isa, sc->sc_i.dmachan);
! 929: sc->sc_i.run = SB_NOTRUNNING;
! 930: }
! 931: if (sc->sc_o.run != SB_NOTRUNNING) {
! 932: isa_dmaabort(sc->sc_isa, sc->sc_o.dmachan);
! 933: sc->sc_o.run = SB_NOTRUNNING;
! 934: }
! 935:
! 936: /*
! 937: * See SBK, section 11.3.
! 938: * We pulse a reset signal into the card.
! 939: * Gee, what a brilliant hardware design.
! 940: */
! 941: bus_space_write_1(iot, ioh, SBP_DSP_RESET, 1);
! 942: delay(10);
! 943: bus_space_write_1(iot, ioh, SBP_DSP_RESET, 0);
! 944: delay(30);
! 945: if (sbdsp_rdsp(sc) != SB_MAGIC)
! 946: return -1;
! 947:
! 948: return 0;
! 949: }
! 950:
! 951: /*
! 952: * Write a byte to the dsp.
! 953: * We are at the mercy of the card as we use a
! 954: * polling loop and wait until it can take the byte.
! 955: */
! 956: int
! 957: sbdsp_wdsp(sc, v)
! 958: struct sbdsp_softc *sc;
! 959: int v;
! 960: {
! 961: bus_space_tag_t iot = sc->sc_iot;
! 962: bus_space_handle_t ioh = sc->sc_ioh;
! 963: int i;
! 964: u_char x;
! 965:
! 966: for (i = SBDSP_NPOLL; --i >= 0; ) {
! 967: x = bus_space_read_1(iot, ioh, SBP_DSP_WSTAT);
! 968: delay(10);
! 969: if ((x & SB_DSP_BUSY) == 0) {
! 970: bus_space_write_1(iot, ioh, SBP_DSP_WRITE, v);
! 971: delay(10);
! 972: return 0;
! 973: }
! 974: }
! 975: ++sberr.wdsp;
! 976: return -1;
! 977: }
! 978:
! 979: /*
! 980: * Read a byte from the DSP, using polling.
! 981: */
! 982: int
! 983: sbdsp_rdsp(sc)
! 984: struct sbdsp_softc *sc;
! 985: {
! 986: bus_space_tag_t iot = sc->sc_iot;
! 987: bus_space_handle_t ioh = sc->sc_ioh;
! 988: int i;
! 989: u_char x;
! 990:
! 991: for (i = SBDSP_NPOLL; --i >= 0; ) {
! 992: x = bus_space_read_1(iot, ioh, SBP_DSP_RSTAT);
! 993: delay(10);
! 994: if (x & SB_DSP_READY) {
! 995: x = bus_space_read_1(iot, ioh, SBP_DSP_READ);
! 996: delay(10);
! 997: return x;
! 998: }
! 999: }
! 1000: ++sberr.rdsp;
! 1001: return -1;
! 1002: }
! 1003:
! 1004: /*
! 1005: * Doing certain things (like toggling the speaker) make
! 1006: * the SB hardware go away for a while, so pause a little.
! 1007: */
! 1008: void
! 1009: sbdsp_to(arg)
! 1010: void *arg;
! 1011: {
! 1012: wakeup(arg);
! 1013: }
! 1014:
! 1015: void
! 1016: sbdsp_pause(sc)
! 1017: struct sbdsp_softc *sc;
! 1018: {
! 1019: extern int hz;
! 1020:
! 1021: timeout_add(&sc->sc_tmo, hz/8);
! 1022: (void)tsleep(sbdsp_to, PWAIT, "sbpause", 0);
! 1023: }
! 1024:
! 1025: /*
! 1026: * Turn on the speaker. The SBK documention says this operation
! 1027: * can take up to 1/10 of a second. Higher level layers should
! 1028: * probably let the task sleep for this amount of time after
! 1029: * calling here. Otherwise, things might not work (because
! 1030: * sbdsp_wdsp() and sbdsp_rdsp() will probably timeout.)
! 1031: *
! 1032: * These engineers had their heads up their ass when
! 1033: * they designed this card.
! 1034: */
! 1035: void
! 1036: sbdsp_spkron(sc)
! 1037: struct sbdsp_softc *sc;
! 1038: {
! 1039: (void)sbdsp_wdsp(sc, SB_DSP_SPKR_ON);
! 1040: sbdsp_pause(sc);
! 1041: }
! 1042:
! 1043: /*
! 1044: * Turn off the speaker; see comment above.
! 1045: */
! 1046: void
! 1047: sbdsp_spkroff(sc)
! 1048: struct sbdsp_softc *sc;
! 1049: {
! 1050: (void)sbdsp_wdsp(sc, SB_DSP_SPKR_OFF);
! 1051: sbdsp_pause(sc);
! 1052: }
! 1053:
! 1054: /*
! 1055: * Read the version number out of the card.
! 1056: * Store version information in the softc.
! 1057: */
! 1058: void
! 1059: sbversion(sc)
! 1060: struct sbdsp_softc *sc;
! 1061: {
! 1062: int v;
! 1063:
! 1064: sc->sc_model = SB_UNK;
! 1065: sc->sc_version = 0;
! 1066: if (sbdsp_wdsp(sc, SB_DSP_VERSION) < 0)
! 1067: return;
! 1068: v = sbdsp_rdsp(sc) << 8;
! 1069: v |= sbdsp_rdsp(sc);
! 1070: if (v < 0)
! 1071: return;
! 1072: sc->sc_version = v;
! 1073: switch(SBVER_MAJOR(v)) {
! 1074: case 1:
! 1075: sc->sc_mixer_model = SBM_NONE;
! 1076: sc->sc_model = SB_1;
! 1077: break;
! 1078: case 2:
! 1079: /* Some SB2 have a mixer, some don't. */
! 1080: sbdsp_mix_write(sc, SBP_1335_MASTER_VOL, 0x04);
! 1081: sbdsp_mix_write(sc, SBP_1335_MIDI_VOL, 0x06);
! 1082: /* Check if we can read back the mixer values. */
! 1083: if ((sbdsp_mix_read(sc, SBP_1335_MASTER_VOL) & 0x0e) == 0x04 &&
! 1084: (sbdsp_mix_read(sc, SBP_1335_MIDI_VOL) & 0x0e) == 0x06)
! 1085: sc->sc_mixer_model = SBM_CT1335;
! 1086: else
! 1087: sc->sc_mixer_model = SBM_NONE;
! 1088: if (SBVER_MINOR(v) == 0)
! 1089: sc->sc_model = SB_20;
! 1090: else
! 1091: sc->sc_model = SB_2x;
! 1092: break;
! 1093: case 3:
! 1094: sc->sc_mixer_model = SBM_CT1345;
! 1095: sc->sc_model = SB_PRO;
! 1096: break;
! 1097: case 4:
! 1098: #if 0
! 1099: /* XXX This does not work */
! 1100: /* Most SB16 have a tone controls, but some don't. */
! 1101: sbdsp_mix_write(sc, SB16P_TREBLE_L, 0x80);
! 1102: /* Check if we can read back the mixer value. */
! 1103: if ((sbdsp_mix_read(sc, SB16P_TREBLE_L) & 0xf0) == 0x80)
! 1104: sc->sc_mixer_model = SBM_CT1745;
! 1105: else
! 1106: sc->sc_mixer_model = SBM_CT1XX5;
! 1107: #else
! 1108: sc->sc_mixer_model = SBM_CT1745;
! 1109: #endif
! 1110: #if 0
! 1111: /* XXX figure out a good way of determining the model */
! 1112: /* XXX what about SB_32 */
! 1113: if (SBVER_MINOR(v) == 16)
! 1114: sc->sc_model = SB_64;
! 1115: else
! 1116: #endif
! 1117: sc->sc_model = SB_16;
! 1118: break;
! 1119: }
! 1120: }
! 1121:
! 1122: /*
! 1123: * Halt a DMA in progress.
! 1124: */
! 1125: int
! 1126: sbdsp_haltdma(addr)
! 1127: void *addr;
! 1128: {
! 1129: struct sbdsp_softc *sc = addr;
! 1130:
! 1131: DPRINTF(("sbdsp_haltdma: sc=%p\n", sc));
! 1132:
! 1133: sbdsp_reset(sc);
! 1134: return 0;
! 1135: }
! 1136:
! 1137: int
! 1138: sbdsp_set_timeconst(sc, tc)
! 1139: struct sbdsp_softc *sc;
! 1140: int tc;
! 1141: {
! 1142: DPRINTF(("sbdsp_set_timeconst: sc=%p tc=%d\n", sc, tc));
! 1143:
! 1144: if (sbdsp_wdsp(sc, SB_DSP_TIMECONST) < 0 ||
! 1145: sbdsp_wdsp(sc, tc) < 0)
! 1146: return EIO;
! 1147:
! 1148: return 0;
! 1149: }
! 1150:
! 1151: int
! 1152: sbdsp16_set_rate(sc, cmd, rate)
! 1153: struct sbdsp_softc *sc;
! 1154: int cmd, rate;
! 1155: {
! 1156: DPRINTF(("sbdsp16_set_rate: sc=%p cmd=0x%02x rate=%d\n", sc, cmd, rate));
! 1157:
! 1158: if (sbdsp_wdsp(sc, cmd) < 0 ||
! 1159: sbdsp_wdsp(sc, rate >> 8) < 0 ||
! 1160: sbdsp_wdsp(sc, rate) < 0)
! 1161: return EIO;
! 1162: return 0;
! 1163: }
! 1164:
! 1165: int
! 1166: sbdsp_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1167: void *addr;
! 1168: void *start, *end;
! 1169: int blksize;
! 1170: void (*intr)(void *);
! 1171: void *arg;
! 1172: struct audio_params *param;
! 1173: {
! 1174: struct sbdsp_softc *sc = addr;
! 1175: int stereo = param->channels == 2;
! 1176: int width = param->precision * param->factor;
! 1177: int filter;
! 1178:
! 1179: #ifdef DIAGNOSTIC
! 1180: if (stereo && (blksize & 1)) {
! 1181: DPRINTF(("stereo record odd bytes (%d)\n", blksize));
! 1182: return (EIO);
! 1183: }
! 1184: #endif
! 1185:
! 1186: sc->sc_intrr = intr;
! 1187: sc->sc_argr = arg;
! 1188:
! 1189: if (width == 8) {
! 1190: #ifdef DIAGNOSTIC
! 1191: if (sc->sc_i.dmachan != sc->sc_drq8) {
! 1192: printf("sbdsp_trigger_input: width=%d bad chan %d\n",
! 1193: width, sc->sc_i.dmachan);
! 1194: return (EIO);
! 1195: }
! 1196: #endif
! 1197: sc->sc_intr8 = sbdsp_block_input;
! 1198: sc->sc_arg8 = addr;
! 1199: } else {
! 1200: #ifdef DIAGNOSTIC
! 1201: if (sc->sc_i.dmachan != sc->sc_drq16) {
! 1202: printf("sbdsp_trigger_input: width=%d bad chan %d\n",
! 1203: width, sc->sc_i.dmachan);
! 1204: return (EIO);
! 1205: }
! 1206: #endif
! 1207: sc->sc_intr16 = sbdsp_block_input;
! 1208: sc->sc_arg16 = addr;
! 1209: }
! 1210:
! 1211: if ((sc->sc_model == SB_JAZZ) ? (sc->sc_i.dmachan > 3) : (width == 16))
! 1212: blksize >>= 1;
! 1213: --blksize;
! 1214: sc->sc_i.blksize = blksize;
! 1215:
! 1216: if (ISSBPRO(sc)) {
! 1217: if (sbdsp_wdsp(sc, sc->sc_i.modep->cmdchan) < 0)
! 1218: return (EIO);
! 1219: filter = stereo ? SBP_FILTER_OFF : sc->in_filter;
! 1220: sbdsp_mix_write(sc, SBP_INFILTER,
! 1221: (sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK) |
! 1222: filter);
! 1223: }
! 1224:
! 1225: if (ISSB16CLASS(sc)) {
! 1226: if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, sc->sc_i.rate)) {
! 1227: DPRINTF(("sbdsp_trigger_input: rate=%d set failed\n",
! 1228: sc->sc_i.rate));
! 1229: return (EIO);
! 1230: }
! 1231: } else {
! 1232: if (sbdsp_set_timeconst(sc, sc->sc_i.tc)) {
! 1233: DPRINTF(("sbdsp_trigger_input: tc=%d set failed\n",
! 1234: sc->sc_i.rate));
! 1235: return (EIO);
! 1236: }
! 1237: }
! 1238:
! 1239: DPRINTF(("sbdsp: dma start loop input start=%p end=%p chan=%d\n",
! 1240: start, end, sc->sc_i.dmachan));
! 1241: isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, start, (char *)end -
! 1242: (char *)start, NULL, DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT);
! 1243:
! 1244: return sbdsp_block_input(addr);
! 1245: }
! 1246:
! 1247: int
! 1248: sbdsp_block_input(addr)
! 1249: void *addr;
! 1250: {
! 1251: struct sbdsp_softc *sc = addr;
! 1252: int cc = sc->sc_i.blksize;
! 1253:
! 1254: DPRINTFN(2, ("sbdsp_block_input: sc=%p cc=%d\n", addr, cc));
! 1255:
! 1256: if (sc->sc_i.run != SB_NOTRUNNING)
! 1257: sc->sc_intrr(sc->sc_argr);
! 1258:
! 1259: if (sc->sc_model == SB_1) {
! 1260: /* Non-looping mode, start DMA */
! 1261: if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 ||
! 1262: sbdsp_wdsp(sc, cc) < 0 ||
! 1263: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1264: DPRINTF(("sbdsp_block_input: SB1 DMA start failed\n"));
! 1265: return (EIO);
! 1266: }
! 1267: sc->sc_i.run = SB_RUNNING;
! 1268: } else if (sc->sc_i.run == SB_NOTRUNNING) {
! 1269: /* Initialize looping PCM */
! 1270: if (ISSB16CLASS(sc)) {
! 1271: DPRINTFN(3, ("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n",
! 1272: sc->sc_i.modep->cmd, sc->sc_i.bmode, cc));
! 1273: if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 ||
! 1274: sbdsp_wdsp(sc, sc->sc_i.bmode) < 0 ||
! 1275: sbdsp_wdsp(sc, cc) < 0 ||
! 1276: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1277: DPRINTF(("sbdsp_block_input: SB16 DMA start failed\n"));
! 1278: return (EIO);
! 1279: }
! 1280: } else {
! 1281: DPRINTF(("sbdsp_block_input: set blocksize=%d\n", cc));
! 1282: if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 ||
! 1283: sbdsp_wdsp(sc, cc) < 0 ||
! 1284: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1285: DPRINTF(("sbdsp_block_input: SB2 DMA blocksize failed\n"));
! 1286: return (EIO);
! 1287: }
! 1288: if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0) {
! 1289: DPRINTF(("sbdsp_block_input: SB2 DMA start failed\n"));
! 1290: return (EIO);
! 1291: }
! 1292: }
! 1293: sc->sc_i.run = SB_LOOPING;
! 1294: }
! 1295:
! 1296: return (0);
! 1297: }
! 1298:
! 1299: int
! 1300: sbdsp_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1301: void *addr;
! 1302: void *start, *end;
! 1303: int blksize;
! 1304: void (*intr)(void *);
! 1305: void *arg;
! 1306: struct audio_params *param;
! 1307: {
! 1308: struct sbdsp_softc *sc = addr;
! 1309: int stereo = param->channels == 2;
! 1310: int width = param->precision * param->factor;
! 1311: int cmd;
! 1312:
! 1313: #ifdef DIAGNOSTIC
! 1314: if (stereo && (blksize & 1)) {
! 1315: DPRINTF(("stereo playback odd bytes (%d)\n", blksize));
! 1316: return (EIO);
! 1317: }
! 1318: #endif
! 1319:
! 1320: sc->sc_intrp = intr;
! 1321: sc->sc_argp = arg;
! 1322:
! 1323: if (width == 8) {
! 1324: #ifdef DIAGNOSTIC
! 1325: if (sc->sc_o.dmachan != sc->sc_drq8) {
! 1326: printf("sbdsp_trigger_output: width=%d bad chan %d\n",
! 1327: width, sc->sc_o.dmachan);
! 1328: return (EIO);
! 1329: }
! 1330: #endif
! 1331: sc->sc_intr8 = sbdsp_block_output;
! 1332: sc->sc_arg8 = addr;
! 1333: } else {
! 1334: #ifdef DIAGNOSTIC
! 1335: if (sc->sc_o.dmachan != sc->sc_drq16) {
! 1336: printf("sbdsp_trigger_output: width=%d bad chan %d\n",
! 1337: width, sc->sc_o.dmachan);
! 1338: return (EIO);
! 1339: }
! 1340: #endif
! 1341: sc->sc_intr16 = sbdsp_block_output;
! 1342: sc->sc_arg16 = addr;
! 1343: }
! 1344:
! 1345: if ((sc->sc_model == SB_JAZZ) ? (sc->sc_o.dmachan > 3) : (width == 16))
! 1346: blksize >>= 1;
! 1347: --blksize;
! 1348: sc->sc_o.blksize = blksize;
! 1349:
! 1350: if (ISSBPRO(sc)) {
! 1351: /* make sure we re-set stereo mixer bit when we start output. */
! 1352: sbdsp_mix_write(sc, SBP_STEREO,
! 1353: (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) |
! 1354: (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
! 1355: cmd = sc->sc_o.modep->cmdchan;
! 1356: if (cmd && sbdsp_wdsp(sc, cmd) < 0)
! 1357: return (EIO);
! 1358: }
! 1359:
! 1360: if (ISSB16CLASS(sc)) {
! 1361: if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, sc->sc_o.rate)) {
! 1362: DPRINTF(("sbdsp_trigger_output: rate=%d set failed\n",
! 1363: sc->sc_o.rate));
! 1364: return (EIO);
! 1365: }
! 1366: } else {
! 1367: if (sbdsp_set_timeconst(sc, sc->sc_o.tc)) {
! 1368: DPRINTF(("sbdsp_trigger_output: tc=%d set failed\n",
! 1369: sc->sc_o.rate));
! 1370: return (EIO);
! 1371: }
! 1372: }
! 1373:
! 1374: DPRINTF(("sbdsp: dma start loop output start=%p end=%p chan=%d\n",
! 1375: start, end, sc->sc_o.dmachan));
! 1376: isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, start, (char *)end -
! 1377: (char *)start, NULL, DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
! 1378:
! 1379: return sbdsp_block_output(addr);
! 1380: }
! 1381:
! 1382: int
! 1383: sbdsp_block_output(addr)
! 1384: void *addr;
! 1385: {
! 1386: struct sbdsp_softc *sc = addr;
! 1387: int cc = sc->sc_o.blksize;
! 1388:
! 1389: DPRINTFN(2, ("sbdsp_block_output: sc=%p cc=%d\n", addr, cc));
! 1390:
! 1391: if (sc->sc_o.run != SB_NOTRUNNING)
! 1392: sc->sc_intrp(sc->sc_argp);
! 1393:
! 1394: if (sc->sc_model == SB_1) {
! 1395: /* Non-looping mode, initialized. Start DMA and PCM */
! 1396: if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 ||
! 1397: sbdsp_wdsp(sc, cc) < 0 ||
! 1398: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1399: DPRINTF(("sbdsp_block_output: SB1 DMA start failed\n"));
! 1400: return (EIO);
! 1401: }
! 1402: sc->sc_o.run = SB_RUNNING;
! 1403: } else if (sc->sc_o.run == SB_NOTRUNNING) {
! 1404: /* Initialize looping PCM */
! 1405: if (ISSB16CLASS(sc)) {
! 1406: DPRINTF(("sbdsp_block_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n",
! 1407: sc->sc_o.modep->cmd,sc->sc_o.bmode, cc));
! 1408: if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 ||
! 1409: sbdsp_wdsp(sc, sc->sc_o.bmode) < 0 ||
! 1410: sbdsp_wdsp(sc, cc) < 0 ||
! 1411: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1412: DPRINTF(("sbdsp_block_output: SB16 DMA start failed\n"));
! 1413: return (EIO);
! 1414: }
! 1415: } else {
! 1416: DPRINTF(("sbdsp_block_output: set blocksize=%d\n", cc));
! 1417: if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 ||
! 1418: sbdsp_wdsp(sc, cc) < 0 ||
! 1419: sbdsp_wdsp(sc, cc >> 8) < 0) {
! 1420: DPRINTF(("sbdsp_block_output: SB2 DMA blocksize failed\n"));
! 1421: return (EIO);
! 1422: }
! 1423: if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0) {
! 1424: DPRINTF(("sbdsp_block_output: SB2 DMA start failed\n"));
! 1425: return (EIO);
! 1426: }
! 1427: }
! 1428: sc->sc_o.run = SB_LOOPING;
! 1429: }
! 1430:
! 1431: return (0);
! 1432: }
! 1433:
! 1434: /*
! 1435: * Only the DSP unit on the sound blaster generates interrupts.
! 1436: * There are three cases of interrupt: reception of a midi byte
! 1437: * (when mode is enabled), completion of dma transmission, or
! 1438: * completion of a dma reception.
! 1439: *
! 1440: * If there is interrupt sharing or a spurious interrupt occurs
! 1441: * there is no way to distinguish this on an SB2. So if you have
! 1442: * an SB2 and experience problems, buy an SB16 (it's only $40).
! 1443: */
! 1444: int
! 1445: sbdsp_intr(arg)
! 1446: void *arg;
! 1447: {
! 1448: struct sbdsp_softc *sc = arg;
! 1449: u_char irq;
! 1450:
! 1451: DPRINTFN(2, ("sbdsp_intr: intr8=%p, intr16=%p\n",
! 1452: sc->sc_intr8, sc->sc_intr16));
! 1453: if (ISSB16CLASS(sc)) {
! 1454: irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS);
! 1455: if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16 | SBP_IRQ_MPU401)) == 0) {
! 1456: DPRINTF(("sbdsp_intr: Spurious interrupt 0x%x\n", irq));
! 1457: return 0;
! 1458: }
! 1459: } else {
! 1460: /* XXXX CHECK FOR INTERRUPT */
! 1461: irq = SBP_IRQ_DMA8;
! 1462: }
! 1463:
! 1464: sc->sc_interrupts++;
! 1465: delay(10); /* XXX why? */
! 1466:
! 1467: /* clear interrupt */
! 1468: if (irq & SBP_IRQ_DMA8) {
! 1469: bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK8);
! 1470: if (sc->sc_intr8)
! 1471: sc->sc_intr8(sc->sc_arg8);
! 1472: }
! 1473: if (irq & SBP_IRQ_DMA16) {
! 1474: bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK16);
! 1475: if (sc->sc_intr16)
! 1476: sc->sc_intr16(sc->sc_arg16);
! 1477: }
! 1478: #if NMIDI > 0
! 1479: if ((irq & SBP_IRQ_MPU401) && sc->sc_hasmpu) {
! 1480: mpu_intr(&sc->sc_mpu_sc);
! 1481: }
! 1482: #endif
! 1483: return 1;
! 1484: }
! 1485:
! 1486: /* Like val & mask, but make sure the result is correctly rounded. */
! 1487: #define MAXVAL 256
! 1488: static int
! 1489: sbdsp_adjust(val, mask)
! 1490: int val, mask;
! 1491: {
! 1492: val += (MAXVAL - mask) >> 1;
! 1493: if (val >= MAXVAL)
! 1494: val = MAXVAL-1;
! 1495: return val & mask;
! 1496: }
! 1497:
! 1498: void
! 1499: sbdsp_set_mixer_gain(sc, port)
! 1500: struct sbdsp_softc *sc;
! 1501: int port;
! 1502: {
! 1503: int src, gain;
! 1504:
! 1505: switch(sc->sc_mixer_model) {
! 1506: case SBM_NONE:
! 1507: return;
! 1508: case SBM_CT1335:
! 1509: gain = SB_1335_GAIN(sc->gain[port][SB_LEFT]);
! 1510: switch(port) {
! 1511: case SB_MASTER_VOL:
! 1512: src = SBP_1335_MASTER_VOL;
! 1513: break;
! 1514: case SB_MIDI_VOL:
! 1515: src = SBP_1335_MIDI_VOL;
! 1516: break;
! 1517: case SB_CD_VOL:
! 1518: src = SBP_1335_CD_VOL;
! 1519: break;
! 1520: case SB_VOICE_VOL:
! 1521: src = SBP_1335_VOICE_VOL;
! 1522: gain = SB_1335_MASTER_GAIN(sc->gain[port][SB_LEFT]);
! 1523: break;
! 1524: default:
! 1525: return;
! 1526: }
! 1527: sbdsp_mix_write(sc, src, gain);
! 1528: break;
! 1529: case SBM_CT1345:
! 1530: gain = SB_STEREO_GAIN(sc->gain[port][SB_LEFT],
! 1531: sc->gain[port][SB_RIGHT]);
! 1532: switch (port) {
! 1533: case SB_MIC_VOL:
! 1534: src = SBP_MIC_VOL;
! 1535: gain = SB_MIC_GAIN(sc->gain[port][SB_LEFT]);
! 1536: break;
! 1537: case SB_MASTER_VOL:
! 1538: src = SBP_MASTER_VOL;
! 1539: break;
! 1540: case SB_LINE_IN_VOL:
! 1541: src = SBP_LINE_VOL;
! 1542: break;
! 1543: case SB_VOICE_VOL:
! 1544: src = SBP_VOICE_VOL;
! 1545: break;
! 1546: case SB_MIDI_VOL:
! 1547: src = SBP_MIDI_VOL;
! 1548: break;
! 1549: case SB_CD_VOL:
! 1550: src = SBP_CD_VOL;
! 1551: break;
! 1552: default:
! 1553: return;
! 1554: }
! 1555: sbdsp_mix_write(sc, src, gain);
! 1556: break;
! 1557: case SBM_CT1XX5:
! 1558: case SBM_CT1745:
! 1559: switch (port) {
! 1560: case SB_MIC_VOL:
! 1561: src = SB16P_MIC_L;
! 1562: break;
! 1563: case SB_MASTER_VOL:
! 1564: src = SB16P_MASTER_L;
! 1565: break;
! 1566: case SB_LINE_IN_VOL:
! 1567: src = SB16P_LINE_L;
! 1568: break;
! 1569: case SB_VOICE_VOL:
! 1570: src = SB16P_VOICE_L;
! 1571: break;
! 1572: case SB_MIDI_VOL:
! 1573: src = SB16P_MIDI_L;
! 1574: break;
! 1575: case SB_CD_VOL:
! 1576: src = SB16P_CD_L;
! 1577: break;
! 1578: case SB_INPUT_GAIN:
! 1579: src = SB16P_INPUT_GAIN_L;
! 1580: break;
! 1581: case SB_OUTPUT_GAIN:
! 1582: src = SB16P_OUTPUT_GAIN_L;
! 1583: break;
! 1584: case SB_TREBLE:
! 1585: src = SB16P_TREBLE_L;
! 1586: break;
! 1587: case SB_BASS:
! 1588: src = SB16P_BASS_L;
! 1589: break;
! 1590: case SB_PCSPEAKER:
! 1591: sbdsp_mix_write(sc, SB16P_PCSPEAKER, sc->gain[port][SB_LEFT]);
! 1592: return;
! 1593: default:
! 1594: return;
! 1595: }
! 1596: sbdsp_mix_write(sc, src, sc->gain[port][SB_LEFT]);
! 1597: sbdsp_mix_write(sc, SB16P_L_TO_R(src), sc->gain[port][SB_RIGHT]);
! 1598: break;
! 1599: }
! 1600: }
! 1601:
! 1602: int
! 1603: sbdsp_mixer_set_port(addr, cp)
! 1604: void *addr;
! 1605: mixer_ctrl_t *cp;
! 1606: {
! 1607: struct sbdsp_softc *sc = addr;
! 1608: int lgain, rgain;
! 1609: int mask, bits;
! 1610: int lmask, rmask, lbits, rbits;
! 1611: int mute, swap;
! 1612:
! 1613: if (sc->sc_open == SB_OPEN_MIDI)
! 1614: return EBUSY;
! 1615:
! 1616: DPRINTF(("sbdsp_mixer_set_port: port=%d num_channels=%d\n", cp->dev,
! 1617: cp->un.value.num_channels));
! 1618:
! 1619: if (sc->sc_mixer_model == SBM_NONE)
! 1620: return EINVAL;
! 1621:
! 1622: switch (cp->dev) {
! 1623: case SB_TREBLE:
! 1624: case SB_BASS:
! 1625: if (sc->sc_mixer_model == SBM_CT1345 ||
! 1626: sc->sc_mixer_model == SBM_CT1XX5) {
! 1627: if (cp->type != AUDIO_MIXER_ENUM)
! 1628: return EINVAL;
! 1629: switch (cp->dev) {
! 1630: case SB_TREBLE:
! 1631: sbdsp_set_ifilter(addr, cp->un.ord ? SB_TREBLE : 0);
! 1632: return 0;
! 1633: case SB_BASS:
! 1634: sbdsp_set_ifilter(addr, cp->un.ord ? SB_BASS : 0);
! 1635: return 0;
! 1636: }
! 1637: }
! 1638: case SB_PCSPEAKER:
! 1639: case SB_INPUT_GAIN:
! 1640: case SB_OUTPUT_GAIN:
! 1641: if (!ISSBM1745(sc))
! 1642: return EINVAL;
! 1643: case SB_MIC_VOL:
! 1644: case SB_LINE_IN_VOL:
! 1645: if (sc->sc_mixer_model == SBM_CT1335)
! 1646: return EINVAL;
! 1647: case SB_VOICE_VOL:
! 1648: case SB_MIDI_VOL:
! 1649: case SB_CD_VOL:
! 1650: case SB_MASTER_VOL:
! 1651: if (cp->type != AUDIO_MIXER_VALUE)
! 1652: return EINVAL;
! 1653:
! 1654: /*
! 1655: * All the mixer ports are stereo except for the microphone.
! 1656: * If we get a single-channel gain value passed in, then we
! 1657: * duplicate it to both left and right channels.
! 1658: */
! 1659:
! 1660: switch (cp->dev) {
! 1661: case SB_MIC_VOL:
! 1662: if (cp->un.value.num_channels != 1)
! 1663: return EINVAL;
! 1664:
! 1665: lgain = rgain = SB_ADJUST_MIC_GAIN(sc,
! 1666: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1667: break;
! 1668: case SB_PCSPEAKER:
! 1669: if (cp->un.value.num_channels != 1)
! 1670: return EINVAL;
! 1671: /* fall into */
! 1672: case SB_INPUT_GAIN:
! 1673: case SB_OUTPUT_GAIN:
! 1674: lgain = rgain = SB_ADJUST_2_GAIN(sc,
! 1675: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1676: break;
! 1677: default:
! 1678: switch (cp->un.value.num_channels) {
! 1679: case 1:
! 1680: lgain = rgain = SB_ADJUST_GAIN(sc,
! 1681: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1682: break;
! 1683: case 2:
! 1684: if (sc->sc_mixer_model == SBM_CT1335)
! 1685: return EINVAL;
! 1686: lgain = SB_ADJUST_GAIN(sc,
! 1687: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
! 1688: rgain = SB_ADJUST_GAIN(sc,
! 1689: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
! 1690: break;
! 1691: default:
! 1692: return EINVAL;
! 1693: }
! 1694: break;
! 1695: }
! 1696: sc->gain[cp->dev][SB_LEFT] = lgain;
! 1697: sc->gain[cp->dev][SB_RIGHT] = rgain;
! 1698:
! 1699: sbdsp_set_mixer_gain(sc, cp->dev);
! 1700: break;
! 1701:
! 1702: case SB_RECORD_SOURCE:
! 1703: if (ISSBM1745(sc)) {
! 1704: if (cp->type != AUDIO_MIXER_SET)
! 1705: return EINVAL;
! 1706: return sbdsp_set_in_ports(sc, cp->un.mask);
! 1707: } else {
! 1708: if (cp->type != AUDIO_MIXER_ENUM)
! 1709: return EINVAL;
! 1710: sc->in_port = cp->un.ord;
! 1711: return sbdsp_set_in_ports(sc, 1 << cp->un.ord);
! 1712: }
! 1713: break;
! 1714:
! 1715: case SB_AGC:
! 1716: if (!ISSBM1745(sc) || cp->type != AUDIO_MIXER_ENUM)
! 1717: return EINVAL;
! 1718: sbdsp_mix_write(sc, SB16P_AGC, cp->un.ord & 1);
! 1719: break;
! 1720:
! 1721: case SB_CD_OUT_MUTE:
! 1722: mask = SB16P_SW_CD;
! 1723: goto omute;
! 1724: case SB_MIC_OUT_MUTE:
! 1725: mask = SB16P_SW_MIC;
! 1726: goto omute;
! 1727: case SB_LINE_OUT_MUTE:
! 1728: mask = SB16P_SW_LINE;
! 1729: omute:
! 1730: if (cp->type != AUDIO_MIXER_ENUM)
! 1731: return EINVAL;
! 1732: bits = sbdsp_mix_read(sc, SB16P_OSWITCH);
! 1733: sc->gain[cp->dev][SB_LR] = cp->un.ord != 0;
! 1734: if (cp->un.ord)
! 1735: bits = bits & ~mask;
! 1736: else
! 1737: bits = bits | mask;
! 1738: sbdsp_mix_write(sc, SB16P_OSWITCH, bits);
! 1739: break;
! 1740:
! 1741: case SB_MIC_IN_MUTE:
! 1742: case SB_MIC_SWAP:
! 1743: lmask = rmask = SB16P_SW_MIC;
! 1744: goto imute;
! 1745: case SB_CD_IN_MUTE:
! 1746: case SB_CD_SWAP:
! 1747: lmask = SB16P_SW_CD_L;
! 1748: rmask = SB16P_SW_CD_R;
! 1749: goto imute;
! 1750: case SB_LINE_IN_MUTE:
! 1751: case SB_LINE_SWAP:
! 1752: lmask = SB16P_SW_LINE_L;
! 1753: rmask = SB16P_SW_LINE_R;
! 1754: goto imute;
! 1755: case SB_MIDI_IN_MUTE:
! 1756: case SB_MIDI_SWAP:
! 1757: lmask = SB16P_SW_MIDI_L;
! 1758: rmask = SB16P_SW_MIDI_R;
! 1759: imute:
! 1760: if (cp->type != AUDIO_MIXER_ENUM)
! 1761: return EINVAL;
! 1762: mask = lmask | rmask;
! 1763: lbits = sbdsp_mix_read(sc, SB16P_ISWITCH_L) & ~mask;
! 1764: rbits = sbdsp_mix_read(sc, SB16P_ISWITCH_R) & ~mask;
! 1765: sc->gain[cp->dev][SB_LR] = cp->un.ord != 0;
! 1766: if (SB_IS_IN_MUTE(cp->dev)) {
! 1767: mute = cp->dev;
! 1768: swap = mute - SB_CD_IN_MUTE + SB_CD_SWAP;
! 1769: } else {
! 1770: swap = cp->dev;
! 1771: mute = swap + SB_CD_IN_MUTE - SB_CD_SWAP;
! 1772: }
! 1773: if (sc->gain[swap][SB_LR]) {
! 1774: mask = lmask;
! 1775: lmask = rmask;
! 1776: rmask = mask;
! 1777: }
! 1778: if (!sc->gain[mute][SB_LR]) {
! 1779: lbits = lbits | lmask;
! 1780: rbits = rbits | rmask;
! 1781: }
! 1782: sbdsp_mix_write(sc, SB16P_ISWITCH_L, lbits);
! 1783: sbdsp_mix_write(sc, SB16P_ISWITCH_L, rbits);
! 1784: break;
! 1785:
! 1786: default:
! 1787: return EINVAL;
! 1788: }
! 1789:
! 1790: return 0;
! 1791: }
! 1792:
! 1793: int
! 1794: sbdsp_mixer_get_port(addr, cp)
! 1795: void *addr;
! 1796: mixer_ctrl_t *cp;
! 1797: {
! 1798: struct sbdsp_softc *sc = addr;
! 1799:
! 1800: if (sc->sc_open == SB_OPEN_MIDI)
! 1801: return EBUSY;
! 1802:
! 1803: DPRINTF(("sbdsp_mixer_get_port: port=%d\n", cp->dev));
! 1804:
! 1805: if (sc->sc_mixer_model == SBM_NONE)
! 1806: return EINVAL;
! 1807:
! 1808: switch (cp->dev) {
! 1809: case SB_TREBLE:
! 1810: case SB_BASS:
! 1811: if (sc->sc_mixer_model == SBM_CT1345 ||
! 1812: sc->sc_mixer_model == SBM_CT1XX5) {
! 1813: switch (cp->dev) {
! 1814: case SB_TREBLE:
! 1815: cp->un.ord = sbdsp_get_ifilter(addr) == SB_TREBLE;
! 1816: return 0;
! 1817: case SB_BASS:
! 1818: cp->un.ord = sbdsp_get_ifilter(addr) == SB_BASS;
! 1819: return 0;
! 1820: }
! 1821: }
! 1822: case SB_PCSPEAKER:
! 1823: case SB_INPUT_GAIN:
! 1824: case SB_OUTPUT_GAIN:
! 1825: if (!ISSBM1745(sc))
! 1826: return EINVAL;
! 1827: case SB_MIC_VOL:
! 1828: case SB_LINE_IN_VOL:
! 1829: if (sc->sc_mixer_model == SBM_CT1335)
! 1830: return EINVAL;
! 1831: case SB_VOICE_VOL:
! 1832: case SB_MIDI_VOL:
! 1833: case SB_CD_VOL:
! 1834: case SB_MASTER_VOL:
! 1835: switch (cp->dev) {
! 1836: case SB_MIC_VOL:
! 1837: case SB_PCSPEAKER:
! 1838: if (cp->un.value.num_channels != 1)
! 1839: return EINVAL;
! 1840: /* fall into */
! 1841: default:
! 1842: switch (cp->un.value.num_channels) {
! 1843: case 1:
! 1844: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
! 1845: sc->gain[cp->dev][SB_LEFT];
! 1846: break;
! 1847: case 2:
! 1848: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 1849: sc->gain[cp->dev][SB_LEFT];
! 1850: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
! 1851: sc->gain[cp->dev][SB_RIGHT];
! 1852: break;
! 1853: default:
! 1854: return EINVAL;
! 1855: }
! 1856: break;
! 1857: }
! 1858: break;
! 1859:
! 1860: case SB_RECORD_SOURCE:
! 1861: if (ISSBM1745(sc))
! 1862: cp->un.mask = sc->in_mask;
! 1863: else
! 1864: cp->un.ord = sc->in_port;
! 1865: break;
! 1866:
! 1867: case SB_AGC:
! 1868: if (!ISSBM1745(sc))
! 1869: return EINVAL;
! 1870: cp->un.ord = sbdsp_mix_read(sc, SB16P_AGC);
! 1871: break;
! 1872:
! 1873: case SB_CD_IN_MUTE:
! 1874: case SB_MIC_IN_MUTE:
! 1875: case SB_LINE_IN_MUTE:
! 1876: case SB_MIDI_IN_MUTE:
! 1877: case SB_CD_SWAP:
! 1878: case SB_MIC_SWAP:
! 1879: case SB_LINE_SWAP:
! 1880: case SB_MIDI_SWAP:
! 1881: case SB_CD_OUT_MUTE:
! 1882: case SB_MIC_OUT_MUTE:
! 1883: case SB_LINE_OUT_MUTE:
! 1884: cp->un.ord = sc->gain[cp->dev][SB_LR];
! 1885: break;
! 1886:
! 1887: default:
! 1888: return EINVAL;
! 1889: }
! 1890:
! 1891: return 0;
! 1892: }
! 1893:
! 1894: int
! 1895: sbdsp_mixer_query_devinfo(addr, dip)
! 1896: void *addr;
! 1897: mixer_devinfo_t *dip;
! 1898: {
! 1899: struct sbdsp_softc *sc = addr;
! 1900: int chan, class, is1745;
! 1901:
! 1902: DPRINTF(("sbdsp_mixer_query_devinfo: model=%d index=%d\n",
! 1903: sc->sc_mixer_model, dip->index));
! 1904:
! 1905: if (sc->sc_mixer_model == SBM_NONE)
! 1906: return ENXIO;
! 1907:
! 1908: chan = sc->sc_mixer_model == SBM_CT1335 ? 1 : 2;
! 1909: is1745 = ISSBM1745(sc);
! 1910: class = is1745 ? SB_INPUT_CLASS : SB_OUTPUT_CLASS;
! 1911:
! 1912: switch (dip->index) {
! 1913: case SB_MASTER_VOL:
! 1914: dip->type = AUDIO_MIXER_VALUE;
! 1915: dip->mixer_class = SB_OUTPUT_CLASS;
! 1916: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 1917: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
! 1918: dip->un.v.num_channels = chan;
! 1919: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1920: return 0;
! 1921: case SB_MIDI_VOL:
! 1922: dip->type = AUDIO_MIXER_VALUE;
! 1923: dip->mixer_class = class;
! 1924: dip->prev = AUDIO_MIXER_LAST;
! 1925: dip->next = is1745 ? SB_MIDI_IN_MUTE : AUDIO_MIXER_LAST;
! 1926: strlcpy(dip->label.name, AudioNfmsynth, sizeof dip->label.name);
! 1927: dip->un.v.num_channels = chan;
! 1928: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1929: return 0;
! 1930: case SB_CD_VOL:
! 1931: dip->type = AUDIO_MIXER_VALUE;
! 1932: dip->mixer_class = class;
! 1933: dip->prev = AUDIO_MIXER_LAST;
! 1934: dip->next = is1745 ? SB_CD_IN_MUTE : AUDIO_MIXER_LAST;
! 1935: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
! 1936: dip->un.v.num_channels = chan;
! 1937: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1938: return 0;
! 1939: case SB_VOICE_VOL:
! 1940: dip->type = AUDIO_MIXER_VALUE;
! 1941: dip->mixer_class = class;
! 1942: dip->prev = AUDIO_MIXER_LAST;
! 1943: dip->next = AUDIO_MIXER_LAST;
! 1944: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
! 1945: dip->un.v.num_channels = chan;
! 1946: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1947: return 0;
! 1948: case SB_OUTPUT_CLASS:
! 1949: dip->type = AUDIO_MIXER_CLASS;
! 1950: dip->mixer_class = SB_OUTPUT_CLASS;
! 1951: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1952: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
! 1953: return 0;
! 1954: }
! 1955:
! 1956: if (sc->sc_mixer_model == SBM_CT1335)
! 1957: return ENXIO;
! 1958:
! 1959: switch (dip->index) {
! 1960: case SB_MIC_VOL:
! 1961: dip->type = AUDIO_MIXER_VALUE;
! 1962: dip->mixer_class = class;
! 1963: dip->prev = AUDIO_MIXER_LAST;
! 1964: dip->next = is1745 ? SB_MIC_IN_MUTE : AUDIO_MIXER_LAST;
! 1965: strlcpy(dip->label.name, AudioNmicrophone,
! 1966: sizeof dip->label.name);
! 1967: dip->un.v.num_channels = 1;
! 1968: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1969: return 0;
! 1970:
! 1971: case SB_LINE_IN_VOL:
! 1972: dip->type = AUDIO_MIXER_VALUE;
! 1973: dip->mixer_class = class;
! 1974: dip->prev = AUDIO_MIXER_LAST;
! 1975: dip->next = is1745 ? SB_LINE_IN_MUTE : AUDIO_MIXER_LAST;
! 1976: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
! 1977: dip->un.v.num_channels = 2;
! 1978: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 1979: return 0;
! 1980:
! 1981: case SB_RECORD_SOURCE:
! 1982: dip->mixer_class = SB_RECORD_CLASS;
! 1983: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 1984: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
! 1985: if (ISSBM1745(sc)) {
! 1986: dip->type = AUDIO_MIXER_SET;
! 1987: dip->un.s.num_mem = 4;
! 1988: strlcpy(dip->un.s.member[0].label.name,
! 1989: AudioNmicrophone,
! 1990: sizeof dip->un.s.member[0].label.name);
! 1991: dip->un.s.member[0].mask = 1 << SB_MIC_VOL;
! 1992: strlcpy(dip->un.s.member[1].label.name,
! 1993: AudioNcd, sizeof dip->un.s.member[1].label.name);
! 1994: dip->un.s.member[1].mask = 1 << SB_CD_VOL;
! 1995: strlcpy(dip->un.s.member[2].label.name,
! 1996: AudioNline, sizeof dip->un.s.member[2].label.name);
! 1997: dip->un.s.member[2].mask = 1 << SB_LINE_IN_VOL;
! 1998: strlcpy(dip->un.s.member[3].label.name,
! 1999: AudioNfmsynth,
! 2000: sizeof dip->un.s.member[3].label.name);
! 2001: dip->un.s.member[3].mask = 1 << SB_MIDI_VOL;
! 2002: } else {
! 2003: dip->type = AUDIO_MIXER_ENUM;
! 2004: dip->un.e.num_mem = 3;
! 2005: strlcpy(dip->un.e.member[0].label.name,
! 2006: AudioNmicrophone,
! 2007: sizeof dip->un.e.member[0].label.name);
! 2008: dip->un.e.member[0].ord = SB_MIC_VOL;
! 2009: strlcpy(dip->un.e.member[1].label.name, AudioNcd,
! 2010: sizeof dip->un.e.member[1].label.name);
! 2011: dip->un.e.member[1].ord = SB_CD_VOL;
! 2012: strlcpy(dip->un.e.member[2].label.name, AudioNline,
! 2013: sizeof dip->un.e.member[2].label.name);
! 2014: dip->un.e.member[2].ord = SB_LINE_IN_VOL;
! 2015: }
! 2016: return 0;
! 2017:
! 2018: case SB_BASS:
! 2019: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2020: strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name);
! 2021: if (sc->sc_mixer_model == SBM_CT1745) {
! 2022: dip->type = AUDIO_MIXER_VALUE;
! 2023: dip->mixer_class = SB_EQUALIZATION_CLASS;
! 2024: dip->un.v.num_channels = 2;
! 2025: strlcpy(dip->un.v.units.name, AudioNbass, sizeof dip->un.v.units.name);
! 2026: } else {
! 2027: dip->type = AUDIO_MIXER_ENUM;
! 2028: dip->mixer_class = SB_INPUT_CLASS;
! 2029: dip->un.e.num_mem = 2;
! 2030: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2031: sizeof dip->un.e.member[0].label.name);
! 2032: dip->un.e.member[0].ord = 0;
! 2033: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2034: sizeof dip->un.e.member[1].label.name);
! 2035: dip->un.e.member[1].ord = 1;
! 2036: }
! 2037: return 0;
! 2038:
! 2039: case SB_TREBLE:
! 2040: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2041: strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name);
! 2042: if (sc->sc_mixer_model == SBM_CT1745) {
! 2043: dip->type = AUDIO_MIXER_VALUE;
! 2044: dip->mixer_class = SB_EQUALIZATION_CLASS;
! 2045: dip->un.v.num_channels = 2;
! 2046: strlcpy(dip->un.v.units.name, AudioNtreble, sizeof dip->un.v.units.name);
! 2047: } else {
! 2048: dip->type = AUDIO_MIXER_ENUM;
! 2049: dip->mixer_class = SB_INPUT_CLASS;
! 2050: dip->un.e.num_mem = 2;
! 2051: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2052: sizeof dip->un.e.member[0].label.name);
! 2053: dip->un.e.member[0].ord = 0;
! 2054: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2055: sizeof dip->un.e.member[1].label.name);
! 2056: dip->un.e.member[1].ord = 1;
! 2057: }
! 2058: return 0;
! 2059:
! 2060: case SB_RECORD_CLASS: /* record source class */
! 2061: dip->type = AUDIO_MIXER_CLASS;
! 2062: dip->mixer_class = SB_RECORD_CLASS;
! 2063: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2064: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
! 2065: return 0;
! 2066:
! 2067: case SB_INPUT_CLASS:
! 2068: dip->type = AUDIO_MIXER_CLASS;
! 2069: dip->mixer_class = SB_INPUT_CLASS;
! 2070: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2071: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
! 2072: return 0;
! 2073:
! 2074: }
! 2075:
! 2076: if (sc->sc_mixer_model == SBM_CT1345)
! 2077: return ENXIO;
! 2078:
! 2079: switch(dip->index) {
! 2080: case SB_PCSPEAKER:
! 2081: dip->type = AUDIO_MIXER_VALUE;
! 2082: dip->mixer_class = SB_INPUT_CLASS;
! 2083: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2084: strlcpy(dip->label.name, "pc_speaker", sizeof dip->label.name);
! 2085: dip->un.v.num_channels = 1;
! 2086: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 2087: return 0;
! 2088:
! 2089: case SB_INPUT_GAIN:
! 2090: dip->type = AUDIO_MIXER_VALUE;
! 2091: dip->mixer_class = SB_INPUT_CLASS;
! 2092: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2093: strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
! 2094: dip->un.v.num_channels = 2;
! 2095: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 2096: return 0;
! 2097:
! 2098: case SB_OUTPUT_GAIN:
! 2099: dip->type = AUDIO_MIXER_VALUE;
! 2100: dip->mixer_class = SB_OUTPUT_CLASS;
! 2101: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2102: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
! 2103: dip->un.v.num_channels = 2;
! 2104: strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
! 2105: return 0;
! 2106:
! 2107: case SB_AGC:
! 2108: dip->type = AUDIO_MIXER_ENUM;
! 2109: dip->mixer_class = SB_INPUT_CLASS;
! 2110: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 2111: strlcpy(dip->label.name, "agc", sizeof dip->label.name);
! 2112: dip->un.e.num_mem = 2;
! 2113: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2114: sizeof dip->un.e.member[0].label.name);
! 2115: dip->un.e.member[0].ord = 0;
! 2116: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2117: sizeof dip->un.e.member[1].label.name);
! 2118: dip->un.e.member[1].ord = 1;
! 2119: return 0;
! 2120:
! 2121: case SB_EQUALIZATION_CLASS:
! 2122: dip->type = AUDIO_MIXER_CLASS;
! 2123: dip->mixer_class = SB_EQUALIZATION_CLASS;
! 2124: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 2125: strlcpy(dip->label.name, AudioCequalization, sizeof dip->label.name);
! 2126: return 0;
! 2127:
! 2128: case SB_CD_IN_MUTE:
! 2129: dip->prev = SB_CD_VOL;
! 2130: dip->next = SB_CD_SWAP;
! 2131: dip->mixer_class = SB_INPUT_CLASS;
! 2132: goto mute;
! 2133:
! 2134: case SB_MIC_IN_MUTE:
! 2135: dip->prev = SB_MIC_VOL;
! 2136: dip->next = SB_MIC_SWAP;
! 2137: dip->mixer_class = SB_INPUT_CLASS;
! 2138: goto mute;
! 2139:
! 2140: case SB_LINE_IN_MUTE:
! 2141: dip->prev = SB_LINE_IN_VOL;
! 2142: dip->next = SB_LINE_SWAP;
! 2143: dip->mixer_class = SB_INPUT_CLASS;
! 2144: goto mute;
! 2145:
! 2146: case SB_MIDI_IN_MUTE:
! 2147: dip->prev = SB_MIDI_VOL;
! 2148: dip->next = SB_MIDI_SWAP;
! 2149: dip->mixer_class = SB_INPUT_CLASS;
! 2150: goto mute;
! 2151:
! 2152: case SB_CD_SWAP:
! 2153: dip->prev = SB_CD_IN_MUTE;
! 2154: dip->next = SB_CD_OUT_MUTE;
! 2155: goto swap;
! 2156:
! 2157: case SB_MIC_SWAP:
! 2158: dip->prev = SB_MIC_IN_MUTE;
! 2159: dip->next = SB_MIC_OUT_MUTE;
! 2160: goto swap;
! 2161:
! 2162: case SB_LINE_SWAP:
! 2163: dip->prev = SB_LINE_IN_MUTE;
! 2164: dip->next = SB_LINE_OUT_MUTE;
! 2165: goto swap;
! 2166:
! 2167: case SB_MIDI_SWAP:
! 2168: dip->prev = SB_MIDI_IN_MUTE;
! 2169: dip->next = AUDIO_MIXER_LAST;
! 2170: swap:
! 2171: dip->mixer_class = SB_INPUT_CLASS;
! 2172: strlcpy(dip->label.name, AudioNswap, sizeof dip->label.name);
! 2173: goto mute1;
! 2174:
! 2175: case SB_CD_OUT_MUTE:
! 2176: dip->prev = SB_CD_SWAP;
! 2177: dip->next = AUDIO_MIXER_LAST;
! 2178: dip->mixer_class = SB_OUTPUT_CLASS;
! 2179: goto mute;
! 2180:
! 2181: case SB_MIC_OUT_MUTE:
! 2182: dip->prev = SB_MIC_SWAP;
! 2183: dip->next = AUDIO_MIXER_LAST;
! 2184: dip->mixer_class = SB_OUTPUT_CLASS;
! 2185: goto mute;
! 2186:
! 2187: case SB_LINE_OUT_MUTE:
! 2188: dip->prev = SB_LINE_SWAP;
! 2189: dip->next = AUDIO_MIXER_LAST;
! 2190: dip->mixer_class = SB_OUTPUT_CLASS;
! 2191: mute:
! 2192: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
! 2193: mute1:
! 2194: dip->type = AUDIO_MIXER_ENUM;
! 2195: dip->un.e.num_mem = 2;
! 2196: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 2197: sizeof dip->un.e.member[0].label.name);
! 2198: dip->un.e.member[0].ord = 0;
! 2199: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 2200: sizeof dip->un.e.member[1].label.name);
! 2201: dip->un.e.member[1].ord = 1;
! 2202: return 0;
! 2203:
! 2204: }
! 2205:
! 2206: return ENXIO;
! 2207: }
! 2208:
! 2209: void *
! 2210: sb_malloc(addr, direction, size, pool, flags)
! 2211: void *addr;
! 2212: int direction;
! 2213: size_t size;
! 2214: int pool;
! 2215: int flags;
! 2216: {
! 2217: struct sbdsp_softc *sc = addr;
! 2218: int drq;
! 2219:
! 2220: /* 8-bit has more restrictive alignment */
! 2221: if (sc->sc_drq8 != -1)
! 2222: drq = sc->sc_drq8;
! 2223: else
! 2224: drq = sc->sc_drq16;
! 2225:
! 2226: return isa_malloc(sc->sc_isa, drq, size, pool, flags);
! 2227: }
! 2228:
! 2229: void
! 2230: sb_free(addr, ptr, pool)
! 2231: void *addr;
! 2232: void *ptr;
! 2233: int pool;
! 2234: {
! 2235: isa_free(ptr, pool);
! 2236: }
! 2237:
! 2238: size_t
! 2239: sb_round(addr, direction, size)
! 2240: void *addr;
! 2241: int direction;
! 2242: size_t size;
! 2243: {
! 2244: if (size > MAX_ISADMA)
! 2245: size = MAX_ISADMA;
! 2246: return size;
! 2247: }
! 2248:
! 2249: paddr_t
! 2250: sb_mappage(addr, mem, off, prot)
! 2251: void *addr;
! 2252: void *mem;
! 2253: off_t off;
! 2254: int prot;
! 2255: {
! 2256: return isa_mappage(mem, off, prot);
! 2257: }
! 2258:
! 2259: int
! 2260: sbdsp_get_props(addr)
! 2261: void *addr;
! 2262: {
! 2263: struct sbdsp_softc *sc = addr;
! 2264: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
! 2265: (sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0);
! 2266: }
! 2267:
! 2268: #if NMIDI > 0
! 2269: /*
! 2270: * MIDI related routines.
! 2271: */
! 2272:
! 2273: int
! 2274: sbdsp_midi_open(addr, flags, iintr, ointr, arg)
! 2275: void *addr;
! 2276: int flags;
! 2277: void (*iintr)(void *, int);
! 2278: void (*ointr)(void *);
! 2279: void *arg;
! 2280: {
! 2281: struct sbdsp_softc *sc = addr;
! 2282:
! 2283: DPRINTF(("sbdsp_midi_open: sc=%p\n", sc));
! 2284:
! 2285: if (sc->sc_open != SB_CLOSED)
! 2286: return EBUSY;
! 2287: if (sbdsp_reset(sc) != 0)
! 2288: return EIO;
! 2289:
! 2290: if (sc->sc_model >= SB_20)
! 2291: if (sbdsp_wdsp(sc, SB_MIDI_UART_INTR)) /* enter UART mode */
! 2292: return EIO;
! 2293: sc->sc_open = SB_OPEN_MIDI;
! 2294: sc->sc_openflags = flags;
! 2295: sc->sc_intr8 = sbdsp_midi_intr;
! 2296: sc->sc_arg8 = addr;
! 2297: sc->sc_intrm = iintr;
! 2298: sc->sc_argm = arg;
! 2299: return 0;
! 2300: }
! 2301:
! 2302: void
! 2303: sbdsp_midi_close(addr)
! 2304: void *addr;
! 2305: {
! 2306: struct sbdsp_softc *sc = addr;
! 2307:
! 2308: DPRINTF(("sbdsp_midi_close: sc=%p\n", sc));
! 2309:
! 2310: if (sc->sc_model >= SB_20)
! 2311: sbdsp_reset(sc); /* exit UART mode */
! 2312: sc->sc_open = SB_CLOSED;
! 2313: sc->sc_intrm = 0;
! 2314: }
! 2315:
! 2316: int
! 2317: sbdsp_midi_output(addr, d)
! 2318: void *addr;
! 2319: int d;
! 2320: {
! 2321: struct sbdsp_softc *sc = addr;
! 2322:
! 2323: if (sc->sc_model < SB_20 && sbdsp_wdsp(sc, SB_MIDI_WRITE))
! 2324: return EIO;
! 2325: if (sbdsp_wdsp(sc, d))
! 2326: return EIO;
! 2327: return 0;
! 2328: }
! 2329:
! 2330: void
! 2331: sbdsp_midi_getinfo(addr, mi)
! 2332: void *addr;
! 2333: struct midi_info *mi;
! 2334: {
! 2335: struct sbdsp_softc *sc = addr;
! 2336:
! 2337: mi->name = sc->sc_model < SB_20 ? "SB MIDI cmd" : "SB MIDI UART";
! 2338: mi->props = MIDI_PROP_CAN_INPUT;
! 2339: }
! 2340:
! 2341: int
! 2342: sbdsp_midi_intr(addr)
! 2343: void *addr;
! 2344: {
! 2345: struct sbdsp_softc *sc = addr;
! 2346:
! 2347: sc->sc_intrm(sc->sc_argm, sbdsp_rdsp(sc));
! 2348: return (0);
! 2349: }
! 2350:
! 2351: #endif
CVSweb