1 /* $NetBSD: sb.c,v 1.87 2007/10/19 12:00:22 ad Exp $ */
4 * Copyright (c) 1991-1993 Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the Computer Systems
18 * Engineering Group at Lawrence Berkeley Laboratory.
19 * 4. Neither the name of the University nor of the Laboratory may be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: sb.c,v 1.87 2007/10/19 12:00:22 ad Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/ioctl.h>
46 #include <sys/syslog.h>
47 #include <sys/device.h>
54 #include <sys/audioio.h>
55 #include <dev/audio_if.h>
56 #include <dev/midi_if.h>
58 #include <dev/isa/isavar.h>
59 #include <dev/isa/isadmavar.h>
61 #include <dev/isa/sbreg.h>
62 #include <dev/isa/sbvar.h>
63 #include <dev/isa/sbdspvar.h>
66 const struct midi_hw_if sb_midi_hw_if
= {
75 int sb_getdev(void *, struct audio_device
*);
78 * Define our interface to the higher level audio driver.
81 const struct audio_hw_if sb_hw_if
= {
87 sbdsp_round_blocksize
,
100 sbdsp_mixer_query_devinfo
,
106 sbdsp_trigger_output
,
113 * Probe / attach routines.
118 sbmatch(struct sbdsp_softc
*sc
, int probing
, cfdata_t match
)
120 static const u_char drq_conf
[8] = {
121 0x01, 0x02, -1, 0x08, -1, 0x20, 0x40, 0x80
124 static const u_char irq_conf
[11] = {
125 -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08
128 if (sbdsp_probe(sc
, match
) == 0)
132 * Cannot auto-discover DMA channel.
134 if (ISSBPROCLASS(sc
)) {
135 if (!SBP_DRQ_VALID(sc
->sc_drq8
)) {
136 aprint_error("%s: configured DMA chan %d invalid\n",
137 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
142 if (!SB_DRQ_VALID(sc
->sc_drq8
)) {
143 aprint_error("%s: configured DMA chan %d invalid\n",
144 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
150 if (0 <= sc
->sc_drq16
&& sc
->sc_drq16
<= 3)
152 * XXX Some ViBRA16 cards seem to have two 8 bit DMA
153 * channels. I've no clue how to use them, so ignore
154 * one of them for now. -- augustss@NetBSD.org
158 if (ISSB16CLASS(sc
)) {
159 if (sc
->sc_drq16
== -1)
160 sc
->sc_drq16
= sc
->sc_drq8
;
161 if (!SB16_DRQ_VALID(sc
->sc_drq16
)) {
162 aprint_error("%s: configured DMA chan %d invalid\n",
163 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
168 sc
->sc_drq16
= sc
->sc_drq8
;
170 if (ISSBPROCLASS(sc
)) {
171 if (!SBP_IRQ_VALID(sc
->sc_irq
)) {
172 aprint_error("%s: configured irq %d invalid\n",
173 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
178 if (!SB_IRQ_VALID(sc
->sc_irq
)) {
179 aprint_error("%s: configured irq %d invalid\n",
180 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
186 if (ISSB16CLASS(sc
) && !(sc
->sc_quirks
& SB_QUIRK_NO_INIT_DRQ
)) {
188 if (sc
->sc_irq
>= __arraycount(irq_conf
)) {
189 aprint_error("%s: Cannot handle irq %d\n",
190 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
194 if (sc
->sc_drq16
>= __arraycount(drq_conf
)) {
195 aprint_error("%s: Cannot handle drq16 %d\n",
196 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
200 if (sc
->sc_drq8
>= __arraycount(drq_conf
)) {
201 aprint_error("%s: Cannot handle drq8 %d\n",
202 probing
? "sbmatch" : device_xname(sc
->sc_dev
),
207 printf("%s: old drq conf %02x\n", device_xname(sc
->sc_dev
),
208 sbdsp_mix_read(sc
, SBP_SET_DRQ
));
209 printf("%s: try drq conf %02x\n", device_xname(sc
->sc_dev
),
210 drq_conf
[sc
->sc_drq16
] | drq_conf
[sc
->sc_drq8
]);
212 w
= drq_conf
[sc
->sc_drq16
] | drq_conf
[sc
->sc_drq8
];
213 sbdsp_mix_write(sc
, SBP_SET_DRQ
, w
);
214 r
= sbdsp_mix_read(sc
, SBP_SET_DRQ
) & 0xeb;
216 aprint_error("%s: setting drq mask %02x failed, "
218 probing
? "sbmatch" : device_xname(sc
->sc_dev
), w
,
223 printf("%s: new drq conf %02x\n", device_xname(sc
->sc_dev
),
224 sbdsp_mix_read(sc
, SBP_SET_DRQ
));
228 printf("%s: old irq conf %02x\n", device_xname(sc
->sc_dev
),
229 sbdsp_mix_read(sc
, SBP_SET_IRQ
));
230 printf("%s: try irq conf %02x\n", device_xname(sc
->sc_dev
),
231 irq_conf
[sc
->sc_irq
]);
233 w
= irq_conf
[sc
->sc_irq
];
234 sbdsp_mix_write(sc
, SBP_SET_IRQ
, w
);
235 r
= sbdsp_mix_read(sc
, SBP_SET_IRQ
) & 0x0f;
237 aprint_error("%s: setting irq mask %02x failed, "
239 probing
? "sbmatch" : device_xname(sc
->sc_dev
), w
,
244 printf("%s: new irq conf %02x\n", device_xname(sc
->sc_dev
),
245 sbdsp_mix_read(sc
, SBP_SET_IRQ
));
254 sbattach(struct sbdsp_softc
*sc
)
256 struct audio_attach_args arg
;
260 audio_attach_mi(&sb_hw_if
, sc
, sc
->sc_dev
);
263 switch(sc
->sc_hasmpu
) {
265 case SBMPU_NONE
: /* no mpu */
267 case SBMPU_INTERNAL
: /* try to attach midi directly */
268 midi_attach_mi(&sb_midi_hw_if
, sc
, sc
->sc_dev
);
270 case SBMPU_EXTERNAL
: /* search for mpu */
271 arg
.type
= AUDIODEV_TYPE_MPU
;
274 sc
->sc_mpudev
= config_found_ia(sc
->sc_dev
, "sbdsp", &arg
, audioprint
);
278 if (sc
->sc_model
>= SB_20
) {
279 arg
.type
= AUDIODEV_TYPE_OPL
;
282 (void)config_found_ia(sc
->sc_dev
, "sbdsp", &arg
, audioprint
);
287 * Various routines to interface to higher level audio driver
291 sb_getdev(void *addr
, struct audio_device
*retp
)
293 static const char * const names
[] = SB_NAMES
;
294 struct sbdsp_softc
*sc
;
298 if (sc
->sc_model
== SB_JAZZ
)
299 strlcpy(retp
->name
, "MV Jazz16", sizeof(retp
->name
));
301 strlcpy(retp
->name
, "SoundBlaster", sizeof(retp
->name
));
302 snprintf(retp
->version
, sizeof(retp
->version
), "%d.%02d",
303 SBVER_MAJOR(sc
->sc_version
), SBVER_MINOR(sc
->sc_version
));
304 if (sc
->sc_model
< sizeof names
/ sizeof names
[0])
305 config
= names
[sc
->sc_model
];
308 strlcpy(retp
->config
, config
, sizeof(retp
->config
));