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