Annotation of sys/dev/isa/sbdsp.c, Revision 1.1.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