jcs's openbsd hax
openbsd
1/* $OpenBSD: sb.c,v 1.35 2022/11/02 10:41:34 kn 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
47#include <machine/cpu.h>
48#include <machine/intr.h>
49#include <machine/bus.h>
50
51#include <sys/audioio.h>
52#include <dev/audio_if.h>
53#include <dev/midi_if.h>
54
55#include <dev/isa/isavar.h>
56#include <dev/isa/isadmavar.h>
57
58#include <dev/isa/sbreg.h>
59#include <dev/isa/sbvar.h>
60#include <dev/isa/sbdspvar.h>
61
62struct cfdriver sb_cd = {
63 NULL, "sb", DV_DULL
64};
65
66#if NMIDI > 0
67int sb_mpu401_open(void *, int, void (*iintr)(void *, int),
68 void (*ointr)(void *), void *arg);
69void sb_mpu401_close(void *);
70int sb_mpu401_output(void *, int);
71void sb_mpu401_getinfo(void *, struct midi_info *);
72
73const struct midi_hw_if sb_midi_hw_if = {
74 sbdsp_midi_open,
75 sbdsp_midi_close,
76 sbdsp_midi_output,
77 0, /* flush */
78 sbdsp_midi_getinfo,
79 0, /* ioctl */
80};
81
82const struct midi_hw_if sb_mpu401_hw_if = {
83 sb_mpu401_open,
84 sb_mpu401_close,
85 sb_mpu401_output,
86 0, /* flush */
87 sb_mpu401_getinfo,
88 0, /* ioctl */
89};
90#endif
91
92/*
93 * Define our interface to the higher level audio driver.
94 */
95
96const struct audio_hw_if sb_hw_if = {
97 .open = sbdsp_open,
98 .close = sbdsp_close,
99 .set_params = sbdsp_set_params,
100 .round_blocksize = sbdsp_round_blocksize,
101 .halt_output = sbdsp_haltdma,
102 .halt_input = sbdsp_haltdma,
103 .set_port = sbdsp_mixer_set_port,
104 .get_port = sbdsp_mixer_get_port,
105 .query_devinfo = sbdsp_mixer_query_devinfo,
106 .allocm = sb_malloc,
107 .freem = sb_free,
108 .round_buffersize = sb_round,
109 .trigger_output = sbdsp_trigger_output,
110 .trigger_input = sbdsp_trigger_input,
111};
112
113#ifdef AUDIO_DEBUG
114#define DPRINTF(x) if (sbdebug) printf x
115int sbdebug = 0;
116#else
117#define DPRINTF(x)
118#endif
119
120/*
121 * Probe / attach routines.
122 */
123
124
125int
126sbmatch(struct sbdsp_softc *sc)
127{
128 static u_char drq_conf[8] = {
129 0x01, 0x02, -1, 0x08, -1, 0x20, 0x40, 0x80
130 };
131
132 static u_char irq_conf[11] = {
133 -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08
134 };
135
136 if (sbdsp_probe(sc) == 0)
137 return 0;
138
139 /*
140 * Cannot auto-discover DMA channel.
141 */
142 if (ISSBPROCLASS(sc)) {
143 if (!SBP_DRQ_VALID(sc->sc_drq8)) {
144 DPRINTF(("%s: configured dma chan %d invalid\n",
145 sc->sc_dev.dv_xname, sc->sc_drq8));
146 return 0;
147 }
148 } else {
149 if (!SB_DRQ_VALID(sc->sc_drq8)) {
150 DPRINTF(("%s: configured dma chan %d invalid\n",
151 sc->sc_dev.dv_xname, sc->sc_drq8));
152 return 0;
153 }
154 }
155
156 if (0 <= sc->sc_drq16 && sc->sc_drq16 <= 3)
157 /*
158 * XXX Some ViBRA16 cards seem to have two 8 bit DMA
159 * channels. I've no clue how to use them, so ignore
160 * one of them for now. -- augustss@netbsd.org
161 */
162 sc->sc_drq16 = -1;
163
164 if (ISSB16CLASS(sc)) {
165 if (sc->sc_drq16 == -1)
166 sc->sc_drq16 = sc->sc_drq8;
167 if (!SB16_DRQ_VALID(sc->sc_drq16)) {
168 DPRINTF(("%s: configured dma chan %d invalid\n",
169 sc->sc_dev.dv_xname, sc->sc_drq16));
170 return 0;
171 }
172 } else
173 sc->sc_drq16 = sc->sc_drq8;
174
175 if (ISSBPROCLASS(sc)) {
176 if (!SBP_IRQ_VALID(sc->sc_irq)) {
177 DPRINTF(("%s: configured irq %d invalid\n",
178 sc->sc_dev.dv_xname, sc->sc_irq));
179 return 0;
180 }
181 } else {
182 if (!SB_IRQ_VALID(sc->sc_irq)) {
183 DPRINTF(("%s: configured irq %d invalid\n",
184 sc->sc_dev.dv_xname, sc->sc_irq));
185 return 0;
186 }
187 }
188
189 if (ISSB16CLASS(sc)) {
190 int w, r;
191#if 0
192 DPRINTF(("%s: old drq conf %02x\n", sc->sc_dev.dv_xname,
193 sbdsp_mix_read(sc, SBP_SET_DRQ)));
194 DPRINTF(("%s: try drq conf %02x\n", sc->sc_dev.dv_xname,
195 drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]));
196#endif
197 w = drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8];
198 sbdsp_mix_write(sc, SBP_SET_DRQ, w);
199 r = sbdsp_mix_read(sc, SBP_SET_DRQ) & 0xeb;
200 if (r != w) {
201 DPRINTF(("%s: setting drq mask %02x failed, got %02x\n", sc->sc_dev.dv_xname, w, r));
202 return 0;
203 }
204#if 0
205 DPRINTF(("%s: new drq conf %02x\n", sc->sc_dev.dv_xname,
206 sbdsp_mix_read(sc, SBP_SET_DRQ)));
207#endif
208
209#if 0
210 DPRINTF(("%s: old irq conf %02x\n", sc->sc_dev.dv_xname,
211 sbdsp_mix_read(sc, SBP_SET_IRQ)));
212 DPRINTF(("%s: try irq conf %02x\n", sc->sc_dev.dv_xname,
213 irq_conf[sc->sc_irq]));
214#endif
215 w = irq_conf[sc->sc_irq];
216 sbdsp_mix_write(sc, SBP_SET_IRQ, w);
217 r = sbdsp_mix_read(sc, SBP_SET_IRQ) & 0x0f;
218 if (r != w) {
219 DPRINTF(("%s: setting irq mask %02x failed, got %02x\n",
220 sc->sc_dev.dv_xname, w, r));
221 return 0;
222 }
223#if 0
224 DPRINTF(("%s: new irq conf %02x\n", sc->sc_dev.dv_xname,
225 sbdsp_mix_read(sc, SBP_SET_IRQ)));
226#endif
227 }
228
229 return 1;
230}
231
232
233void
234sbattach(struct sbdsp_softc *sc)
235{
236 struct audio_attach_args arg;
237#if NMIDI > 0
238 const struct midi_hw_if *mhw = &sb_midi_hw_if;
239#endif
240
241 sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq,
242 IST_EDGE, IPL_AUDIO | IPL_MPSAFE,
243 sbdsp_intr, sc, sc->sc_dev.dv_xname);
244
245 sbdsp_attach(sc);
246
247#if NMIDI > 0
248 sc->sc_hasmpu = 0;
249 if (ISSB16CLASS(sc) && sc->sc_mpu_sc.iobase != 0) {
250 sc->sc_mpu_sc.iot = sc->sc_iot;
251 if (mpu_find(&sc->sc_mpu_sc)) {
252 sc->sc_hasmpu = 1;
253 mhw = &sb_mpu401_hw_if;
254 }
255 }
256 midi_attach_mi(mhw, sc, &sc->sc_dev);
257#endif
258
259 audio_attach_mi(&sb_hw_if, sc, NULL, &sc->sc_dev);
260
261 arg.type = AUDIODEV_TYPE_OPL;
262 arg.hwif = 0;
263 arg.hdl = 0;
264 (void)config_found(&sc->sc_dev, &arg, audioprint);
265}
266
267/*
268 * Various routines to interface to higher level audio driver
269 */
270
271#if NMIDI > 0
272
273#define SBMPU(a) (&((struct sbdsp_softc *)addr)->sc_mpu_sc)
274
275int
276sb_mpu401_open(void *addr, int flags, void (*iintr)(void *, int),
277 void (*ointr)(void *), void *arg)
278{
279 return mpu_open(SBMPU(addr), flags, iintr, ointr, arg);
280}
281
282int
283sb_mpu401_output(void *addr, int d)
284{
285 return mpu_output(SBMPU(addr), d);
286}
287
288void
289sb_mpu401_close(void *addr)
290{
291 mpu_close(SBMPU(addr));
292}
293
294void
295sb_mpu401_getinfo(void *addr, struct midi_info *mi)
296{
297 mi->name = "SB MPU-401 UART";
298 mi->props = 0;
299}
300#endif