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