Annotation of sys/dev/isa/sb.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sb.c,v 1.24 2006/04/07 22:41:33 jsg Exp $ */
2: /* $NetBSD: sb.c,v 1.57 1998/01/12 09:43:46 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1991-1993 Regents of the University of California.
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the Computer Systems
19: * Engineering Group at Lawrence Berkeley Laboratory.
20: * 4. Neither the name of the University nor of the Laboratory may be used
21: * to endorse or promote products derived from this software without
22: * specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: */
37:
38: #include "midi.h"
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/errno.h>
43: #include <sys/ioctl.h>
44: #include <sys/syslog.h>
45: #include <sys/device.h>
46: #include <sys/proc.h>
47:
48: #include <machine/cpu.h>
49: #include <machine/intr.h>
50: #include <machine/bus.h>
51:
52: #include <sys/audioio.h>
53: #include <dev/audio_if.h>
54: #include <dev/midi_if.h>
55:
56: #include <dev/isa/isavar.h>
57: #include <dev/isa/isadmavar.h>
58:
59: #include <dev/isa/sbreg.h>
60: #include <dev/isa/sbvar.h>
61: #include <dev/isa/sbdspvar.h>
62:
63: struct cfdriver sb_cd = {
64: NULL, "sb", DV_DULL
65: };
66:
67: #if NMIDI > 0
68: int sb_mpu401_open(void *, int, void (*iintr)(void *, int),
69: void (*ointr)(void *), void *arg);
70: void sb_mpu401_close(void *);
71: int sb_mpu401_output(void *, int);
72: void sb_mpu401_getinfo(void *, struct midi_info *);
73:
74: struct midi_hw_if sb_midi_hw_if = {
75: sbdsp_midi_open,
76: sbdsp_midi_close,
77: sbdsp_midi_output,
78: 0, /* flush */
79: sbdsp_midi_getinfo,
80: 0, /* ioctl */
81: };
82:
83: struct midi_hw_if sb_mpu401_hw_if = {
84: sb_mpu401_open,
85: sb_mpu401_close,
86: sb_mpu401_output,
87: 0, /* flush */
88: sb_mpu401_getinfo,
89: 0, /* ioctl */
90: };
91: #endif
92:
93: struct audio_device sb_device = {
94: "SoundBlaster",
95: "x",
96: "sb"
97: };
98:
99: int sb_getdev(void *, struct audio_device *);
100:
101: /*
102: * Define our interface to the higher level audio driver.
103: */
104:
105: struct audio_hw_if sb_hw_if = {
106: sbdsp_open,
107: sbdsp_close,
108: 0,
109: sbdsp_query_encoding,
110: sbdsp_set_params,
111: sbdsp_round_blocksize,
112: 0,
113: 0,
114: 0,
115: 0,
116: 0,
117: sbdsp_haltdma,
118: sbdsp_haltdma,
119: sbdsp_speaker_ctl,
120: sb_getdev,
121: 0,
122: sbdsp_mixer_set_port,
123: sbdsp_mixer_get_port,
124: sbdsp_mixer_query_devinfo,
125: sb_malloc,
126: sb_free,
127: sb_round,
128: sb_mappage,
129: sbdsp_get_props,
130: sbdsp_trigger_output,
131: sbdsp_trigger_input
132: };
133:
134: #ifdef AUDIO_DEBUG
135: #define DPRINTF(x) if (sbdebug) printf x
136: int sbdebug = 0;
137: #else
138: #define DPRINTF(x)
139: #endif
140:
141: /*
142: * Probe / attach routines.
143: */
144:
145:
146: int
147: sbmatch(sc)
148: struct sbdsp_softc *sc;
149: {
150: static u_char drq_conf[8] = {
151: 0x01, 0x02, -1, 0x08, -1, 0x20, 0x40, 0x80
152: };
153:
154: static u_char irq_conf[11] = {
155: -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08
156: };
157:
158: if (sbdsp_probe(sc) == 0)
159: return 0;
160:
161: /*
162: * Cannot auto-discover DMA channel.
163: */
164: if (ISSBPROCLASS(sc)) {
165: if (!SBP_DRQ_VALID(sc->sc_drq8)) {
166: DPRINTF(("%s: configured dma chan %d invalid\n",
167: sc->sc_dev.dv_xname, sc->sc_drq8));
168: return 0;
169: }
170: } else {
171: if (!SB_DRQ_VALID(sc->sc_drq8)) {
172: DPRINTF(("%s: configured dma chan %d invalid\n",
173: sc->sc_dev.dv_xname, sc->sc_drq8));
174: return 0;
175: }
176: }
177:
178: if (0 <= sc->sc_drq16 && sc->sc_drq16 <= 3)
179: /*
180: * XXX Some ViBRA16 cards seem to have two 8 bit DMA
181: * channels. I've no clue how to use them, so ignore
182: * one of them for now. -- augustss@netbsd.org
183: */
184: sc->sc_drq16 = -1;
185:
186: if (ISSB16CLASS(sc)) {
187: if (sc->sc_drq16 == -1)
188: sc->sc_drq16 = sc->sc_drq8;
189: if (!SB16_DRQ_VALID(sc->sc_drq16)) {
190: DPRINTF(("%s: configured dma chan %d invalid\n",
191: sc->sc_dev.dv_xname, sc->sc_drq16));
192: return 0;
193: }
194: } else
195: sc->sc_drq16 = sc->sc_drq8;
196:
197: if (ISSBPROCLASS(sc)) {
198: if (!SBP_IRQ_VALID(sc->sc_irq)) {
199: DPRINTF(("%s: configured irq %d invalid\n",
200: sc->sc_dev.dv_xname, sc->sc_irq));
201: return 0;
202: }
203: } else {
204: if (!SB_IRQ_VALID(sc->sc_irq)) {
205: DPRINTF(("%s: configured irq %d invalid\n",
206: sc->sc_dev.dv_xname, sc->sc_irq));
207: return 0;
208: }
209: }
210:
211: if (ISSB16CLASS(sc)) {
212: int w, r;
213: #if 0
214: DPRINTF(("%s: old drq conf %02x\n", sc->sc_dev.dv_xname,
215: sbdsp_mix_read(sc, SBP_SET_DRQ)));
216: DPRINTF(("%s: try drq conf %02x\n", sc->sc_dev.dv_xname,
217: drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]));
218: #endif
219: w = drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8];
220: sbdsp_mix_write(sc, SBP_SET_DRQ, w);
221: r = sbdsp_mix_read(sc, SBP_SET_DRQ) & 0xeb;
222: if (r != w) {
223: DPRINTF(("%s: setting drq mask %02x failed, got %02x\n", sc->sc_dev.dv_xname, w, r));
224: return 0;
225: }
226: #if 0
227: DPRINTF(("%s: new drq conf %02x\n", sc->sc_dev.dv_xname,
228: sbdsp_mix_read(sc, SBP_SET_DRQ)));
229: #endif
230:
231: #if 0
232: DPRINTF(("%s: old irq conf %02x\n", sc->sc_dev.dv_xname,
233: sbdsp_mix_read(sc, SBP_SET_IRQ)));
234: DPRINTF(("%s: try irq conf %02x\n", sc->sc_dev.dv_xname,
235: irq_conf[sc->sc_irq]));
236: #endif
237: w = irq_conf[sc->sc_irq];
238: sbdsp_mix_write(sc, SBP_SET_IRQ, w);
239: r = sbdsp_mix_read(sc, SBP_SET_IRQ) & 0x0f;
240: if (r != w) {
241: DPRINTF(("%s: setting irq mask %02x failed, got %02x\n",
242: sc->sc_dev.dv_xname, w, r));
243: return 0;
244: }
245: #if 0
246: DPRINTF(("%s: new irq conf %02x\n", sc->sc_dev.dv_xname,
247: sbdsp_mix_read(sc, SBP_SET_IRQ)));
248: #endif
249: }
250:
251: return 1;
252: }
253:
254:
255: void
256: sbattach(sc)
257: struct sbdsp_softc *sc;
258: {
259: struct audio_attach_args arg;
260: #if NMIDI > 0
261: struct midi_hw_if *mhw = &sb_midi_hw_if;
262: #endif
263:
264: sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq, IST_EDGE,
265: IPL_AUDIO, sbdsp_intr, sc, sc->sc_dev.dv_xname);
266:
267: sbdsp_attach(sc);
268:
269: #if NMIDI > 0
270: sc->sc_hasmpu = 0;
271: if (ISSB16CLASS(sc) && sc->sc_mpu_sc.iobase != 0) {
272: sc->sc_mpu_sc.iot = sc->sc_iot;
273: if (mpu_find(&sc->sc_mpu_sc)) {
274: sc->sc_hasmpu = 1;
275: mhw = &sb_mpu401_hw_if;
276: }
277: }
278: midi_attach_mi(mhw, sc, &sc->sc_dev);
279: #endif
280:
281: audio_attach_mi(&sb_hw_if, sc, &sc->sc_dev);
282:
283: arg.type = AUDIODEV_TYPE_OPL;
284: arg.hwif = 0;
285: arg.hdl = 0;
286: (void)config_found(&sc->sc_dev, &arg, audioprint);
287: }
288:
289: /*
290: * Various routines to interface to higher level audio driver
291: */
292:
293: int
294: sb_getdev(addr, retp)
295: void *addr;
296: struct audio_device *retp;
297: {
298: struct sbdsp_softc *sc = addr;
299: static char *names[] = SB_NAMES;
300: char *config;
301:
302: if (sc->sc_model == SB_JAZZ)
303: strlcpy(retp->name, "MV Jazz16", sizeof retp->name);
304: else
305: strlcpy(retp->name, "SoundBlaster", sizeof retp->name);
306: snprintf(retp->version, sizeof retp->version, "%d.%02d",
307: SBVER_MAJOR(sc->sc_version),
308: SBVER_MINOR(sc->sc_version));
309: if (0 <= sc->sc_model && sc->sc_model < sizeof names / sizeof names[0])
310: config = names[sc->sc_model];
311: else
312: config = "??";
313: strlcpy(retp->config, config, sizeof retp->config);
314:
315: return 0;
316: }
317:
318: #if NMIDI > 0
319:
320: #define SBMPU(a) (&((struct sbdsp_softc *)addr)->sc_mpu_sc)
321:
322: int
323: sb_mpu401_open(addr, flags, iintr, ointr, arg)
324: void *addr;
325: int flags;
326: void (*iintr)(void *, int);
327: void (*ointr)(void *);
328: void *arg;
329: {
330: return mpu_open(SBMPU(addr), flags, iintr, ointr, arg);
331: }
332:
333: int
334: sb_mpu401_output(addr, d)
335: void *addr;
336: int d;
337: {
338: return mpu_output(SBMPU(addr), d);
339: }
340:
341: void
342: sb_mpu401_close(addr)
343: void *addr;
344: {
345: mpu_close(SBMPU(addr));
346: }
347:
348: void
349: sb_mpu401_getinfo(addr, mi)
350: void *addr;
351: struct midi_info *mi;
352: {
353: mi->name = "SB MPU-401 UART";
354: mi->props = 0;
355: }
356: #endif
CVSweb