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