wss.c revision 1.58 1 /* $NetBSD: wss.c,v 1.58 2001/10/03 00:04:51 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1994 John Brezak
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 <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/errno.h>
42
43 #include <machine/cpu.h>
44 #include <machine/intr.h>
45 #include <machine/bus.h>
46
47 #include <sys/audioio.h>
48 #include <dev/audio_if.h>
49
50 #include <dev/isa/isavar.h>
51 #include <dev/isa/isadmavar.h>
52
53 #include <dev/ic/ad1848reg.h>
54 #include <dev/ic/cs4231reg.h>
55 #include <dev/isa/ad1848var.h>
56 #include <dev/isa/cs4231var.h>
57 #include <dev/isa/wssreg.h>
58 #include <dev/isa/wssvar.h>
59 #include <dev/isa/madreg.h>
60
61 #ifdef AUDIO_DEBUG
62 #define DPRINTF(x) if (wssdebug) printf x
63 int wssdebug = 0;
64 #else
65 #define DPRINTF(x)
66 #endif
67
68 struct audio_device wss_device = {
69 "wss,ad1848",
70 "",
71 "WSS"
72 };
73
74 int wss_getdev __P((void *, struct audio_device *));
75
76 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
77 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
78 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
79
80 /*
81 * Define our interface to the higher level audio driver.
82 */
83
84 struct audio_hw_if wss_hw_if = {
85 ad1848_isa_open,
86 ad1848_isa_close,
87 NULL,
88 ad1848_query_encoding,
89 ad1848_set_params,
90 ad1848_round_blocksize,
91 ad1848_commit_settings,
92 NULL,
93 NULL,
94 NULL,
95 NULL,
96 ad1848_isa_halt_output,
97 ad1848_isa_halt_input,
98 NULL,
99 wss_getdev,
100 NULL,
101 wss_mixer_set_port,
102 wss_mixer_get_port,
103 wss_query_devinfo,
104 ad1848_isa_malloc,
105 ad1848_isa_free,
106 ad1848_isa_round_buffersize,
107 ad1848_isa_mappage,
108 ad1848_isa_get_props,
109 ad1848_isa_trigger_output,
110 ad1848_isa_trigger_input,
111 NULL,
112 };
113
114 /*
115 * Attach hardware to driver, attach hardware driver to audio
116 * pseudo-device driver .
117 */
118 void
119 wssattach(sc)
120 struct wss_softc *sc;
121 {
122 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
123
124 #if 0 /* loses on CS423X chips */
125 int version;
126 #endif
127
128 madattach(sc);
129
130 sc->sc_ad1848.sc_ih = isa_intr_establish(sc->wss_ic, sc->wss_irq,
131 IST_EDGE,
132 IPL_AUDIO, ad1848_isa_intr,
133 &sc->sc_ad1848);
134
135 ad1848_isa_attach(&sc->sc_ad1848);
136
137 #if 0 /* loses on CS423X chips */
138 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS)
139 & WSS_VERSMASK;
140 printf(" (vers %d)", version);
141 #endif
142
143 switch(sc->mad_chip_type) {
144 case MAD_82C928:
145 printf(", 82C928");
146 break;
147 case MAD_OTI601D:
148 printf(", OTI-601D");
149 break;
150 case MAD_82C929:
151 printf(", 82C929");
152 break;
153 case MAD_82C931:
154 printf(", 82C931");
155 break;
156 default:
157 break;
158 }
159 printf("\n");
160
161 ac->parent = sc;
162
163 audio_attach_mi(&wss_hw_if, &sc->sc_ad1848, &ac->sc_dev);
164
165 if (sc->mad_chip_type != MAD_NONE) {
166 struct audio_attach_args arg;
167 arg.type = AUDIODEV_TYPE_OPL;
168 arg.hwif = 0;
169 arg.hdl = 0;
170 (void)config_found(&ac->sc_dev, &arg, audioprint);
171 }
172 }
173
174 int
175 wss_getdev(addr, retp)
176 void *addr;
177 struct audio_device *retp;
178 {
179 *retp = wss_device;
180 return 0;
181 }
182
183 static ad1848_devmap_t mappings[] = {
184 { WSS_MIC_IN_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
185 { WSS_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
186 { WSS_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
187 { WSS_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
188 { WSS_MIC_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
189 { WSS_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
190 { WSS_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
191 { WSS_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
192 { WSS_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
193 { WSS_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
194 };
195
196 static int nummap = sizeof(mappings) / sizeof(mappings[0]);
197
198 int
199 wss_mixer_set_port(addr, cp)
200 void *addr;
201 mixer_ctrl_t *cp;
202 {
203 struct ad1848_softc *ac = addr;
204
205 return (ad1848_mixer_set_port(ac, mappings, nummap, cp));
206 }
207
208 int
209 wss_mixer_get_port(addr, cp)
210 void *addr;
211 mixer_ctrl_t *cp;
212 {
213 struct ad1848_softc *ac = addr;
214
215 return (ad1848_mixer_get_port(ac, mappings, nummap, cp));
216 }
217
218 int
219 wss_query_devinfo(addr, dip)
220 void *addr;
221 mixer_devinfo_t *dip;
222 {
223 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
224
225 switch(dip->index) {
226 case WSS_MIC_IN_LVL: /* Microphone */
227 dip->type = AUDIO_MIXER_VALUE;
228 dip->mixer_class = WSS_INPUT_CLASS;
229 dip->prev = AUDIO_MIXER_LAST;
230 dip->next = WSS_MIC_IN_MUTE;
231 strcpy(dip->label.name, AudioNmicrophone);
232 dip->un.v.num_channels = 2;
233 strcpy(dip->un.v.units.name, AudioNvolume);
234 break;
235
236 case WSS_LINE_IN_LVL: /* line/CD */
237 dip->type = AUDIO_MIXER_VALUE;
238 dip->mixer_class = WSS_INPUT_CLASS;
239 dip->prev = AUDIO_MIXER_LAST;
240 dip->next = WSS_LINE_IN_MUTE;
241 strcpy(dip->label.name, AudioNcd);
242 dip->un.v.num_channels = 2;
243 strcpy(dip->un.v.units.name, AudioNvolume);
244 break;
245
246 case WSS_DAC_LVL: /* dacout */
247 dip->type = AUDIO_MIXER_VALUE;
248 dip->mixer_class = WSS_INPUT_CLASS;
249 dip->prev = AUDIO_MIXER_LAST;
250 dip->next = WSS_DAC_MUTE;
251 strcpy(dip->label.name, AudioNdac);
252 dip->un.v.num_channels = 2;
253 strcpy(dip->un.v.units.name, AudioNvolume);
254 break;
255
256 case WSS_REC_LVL: /* record level */
257 dip->type = AUDIO_MIXER_VALUE;
258 dip->mixer_class = WSS_RECORD_CLASS;
259 dip->prev = AUDIO_MIXER_LAST;
260 dip->next = WSS_RECORD_SOURCE;
261 strcpy(dip->label.name, AudioNrecord);
262 dip->un.v.num_channels = 2;
263 strcpy(dip->un.v.units.name, AudioNvolume);
264 break;
265
266 case WSS_MONITOR_LVL: /* monitor level */
267 dip->type = AUDIO_MIXER_VALUE;
268 dip->mixer_class = WSS_MONITOR_CLASS;
269 dip->prev = AUDIO_MIXER_LAST;
270 dip->next = WSS_MONITOR_MUTE;
271 strcpy(dip->label.name, AudioNmonitor);
272 dip->un.v.num_channels = 1;
273 strcpy(dip->un.v.units.name, AudioNvolume);
274 break;
275
276 case WSS_INPUT_CLASS: /* input class descriptor */
277 dip->type = AUDIO_MIXER_CLASS;
278 dip->mixer_class = WSS_INPUT_CLASS;
279 dip->next = dip->prev = AUDIO_MIXER_LAST;
280 strcpy(dip->label.name, AudioCinputs);
281 break;
282
283 case WSS_MONITOR_CLASS: /* monitor class descriptor */
284 dip->type = AUDIO_MIXER_CLASS;
285 dip->mixer_class = WSS_MONITOR_CLASS;
286 dip->next = dip->prev = AUDIO_MIXER_LAST;
287 strcpy(dip->label.name, AudioCmonitor);
288 break;
289
290 case WSS_RECORD_CLASS: /* record source class */
291 dip->type = AUDIO_MIXER_CLASS;
292 dip->mixer_class = WSS_RECORD_CLASS;
293 dip->next = dip->prev = AUDIO_MIXER_LAST;
294 strcpy(dip->label.name, AudioCrecord);
295 break;
296
297 case WSS_MIC_IN_MUTE:
298 dip->mixer_class = WSS_INPUT_CLASS;
299 dip->type = AUDIO_MIXER_ENUM;
300 dip->prev = WSS_MIC_IN_LVL;
301 dip->next = AUDIO_MIXER_LAST;
302 goto mute;
303
304 case WSS_LINE_IN_MUTE:
305 dip->mixer_class = WSS_INPUT_CLASS;
306 dip->type = AUDIO_MIXER_ENUM;
307 dip->prev = WSS_LINE_IN_LVL;
308 dip->next = AUDIO_MIXER_LAST;
309 goto mute;
310
311 case WSS_DAC_MUTE:
312 dip->mixer_class = WSS_INPUT_CLASS;
313 dip->type = AUDIO_MIXER_ENUM;
314 dip->prev = WSS_DAC_LVL;
315 dip->next = AUDIO_MIXER_LAST;
316 goto mute;
317
318 case WSS_MONITOR_MUTE:
319 dip->mixer_class = WSS_MONITOR_CLASS;
320 dip->type = AUDIO_MIXER_ENUM;
321 dip->prev = WSS_MONITOR_LVL;
322 dip->next = AUDIO_MIXER_LAST;
323 mute:
324 strcpy(dip->label.name, AudioNmute);
325 dip->un.e.num_mem = 2;
326 strcpy(dip->un.e.member[0].label.name, AudioNoff);
327 dip->un.e.member[0].ord = 0;
328 strcpy(dip->un.e.member[1].label.name, AudioNon);
329 dip->un.e.member[1].ord = 1;
330 break;
331
332 case WSS_RECORD_SOURCE:
333 dip->mixer_class = WSS_RECORD_CLASS;
334 dip->type = AUDIO_MIXER_ENUM;
335 dip->prev = WSS_REC_LVL;
336 dip->next = AUDIO_MIXER_LAST;
337 strcpy(dip->label.name, AudioNsource);
338 dip->un.e.num_mem = 3;
339 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
340 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
341 strcpy(dip->un.e.member[1].label.name, AudioNcd);
342 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
343 strcpy(dip->un.e.member[2].label.name, AudioNdac);
344 dip->un.e.member[2].ord = WSS_DAC_LVL;
345 break;
346
347 default:
348 return ENXIO;
349 /*NOTREACHED*/
350 }
351 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
352
353 return 0;
354 }
355
356
357 /*
358 * Copyright by Hannu Savolainen 1994
359 *
360 * Redistribution and use in source and binary forms, with or without
361 * modification, are permitted provided that the following conditions are
362 * met: 1. Redistributions of source code must retain the above copyright
363 * notice, this list of conditions and the following disclaimer. 2.
364 * Redistributions in binary form must reproduce the above copyright notice,
365 * this list of conditions and the following disclaimer in the documentation
366 * and/or other materials provided with the distribution.
367 *
368 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
369 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
370 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
371 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
372 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
373 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
374 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
375 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
376 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
377 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
378 * SUCH DAMAGE.
379 *
380 */
381 /*
382 * Initialization code for OPTi MAD16 compatible audio chips. Including
383 *
384 * OPTi 82C928 MAD16 (replaced by C929)
385 * OAK OTI-601D Mozart
386 * OPTi 82C929 MAD16 Pro
387 *
388 */
389
390 u_int
391 mad_read(sc, port)
392 struct wss_softc *sc;
393 int port;
394 {
395 u_int tmp;
396 int pwd;
397 int s;
398
399 switch (sc->mad_chip_type) { /* Output password */
400 case MAD_82C928:
401 case MAD_OTI601D:
402 pwd = M_PASSWD_928;
403 break;
404 case MAD_82C929:
405 pwd = M_PASSWD_929;
406 break;
407 case MAD_82C931:
408 pwd = M_PASSWD_931;
409 break;
410 default:
411 panic("mad_read: Bad chip type=%d\n", sc->mad_chip_type);
412 }
413 s = splaudio(); /* don't want an interrupt between outb&inb */
414 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
415 tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port);
416 splx(s);
417 return tmp;
418 }
419
420 void
421 mad_write(sc, port, value)
422 struct wss_softc *sc;
423 int port;
424 int value;
425 {
426 int pwd;
427 int s;
428
429 switch (sc->mad_chip_type) { /* Output password */
430 case MAD_82C928:
431 case MAD_OTI601D:
432 pwd = M_PASSWD_928;
433 break;
434 case MAD_82C929:
435 pwd = M_PASSWD_929;
436 break;
437 case MAD_82C931:
438 pwd = M_PASSWD_931;
439 break;
440 default:
441 panic("mad_write: Bad chip type=%d\n", sc->mad_chip_type);
442 }
443 s = splaudio();
444 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
445 bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff);
446 splx(s);
447 }
448
449 void
450 madattach(sc)
451 struct wss_softc *sc;
452 {
453 struct ad1848_softc *ac = (struct ad1848_softc *)&sc->sc_ad1848;
454 unsigned char cs4231_mode;
455 int joy;
456
457 if (sc->mad_chip_type == MAD_NONE)
458 return;
459
460 /* Do we want the joystick disabled? */
461 joy = ac->sc_dev.dv_cfdata->cf_flags & 2 ? MC1_JOYDISABLE : 0;
462
463 /* enable WSS emulation at the I/O port */
464 mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(sc->mad_ioindex) | joy);
465 mad_write(sc, MC2_PORT, MC2_NO_CD_DRQ); /* disable CD */
466 mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */
467
468 cs4231_mode =
469 strncmp(ac->chip_name, "CS4248", 6) == 0 ||
470 strncmp(ac->chip_name, "CS4231", 6) == 0 ? 0x02 : 0;
471
472 if (sc->mad_chip_type == MAD_82C929) {
473 mad_write(sc, MC4_PORT, 0x92);
474 mad_write(sc, MC5_PORT, 0xA5 | cs4231_mode);
475 mad_write(sc, MC6_PORT, 0x03); /* Disable MPU401 */
476 } else {
477 mad_write(sc, MC4_PORT, 0x02);
478 mad_write(sc, MC5_PORT, 0x30 | cs4231_mode);
479 }
480
481 #ifdef AUDIO_DEBUG
482 if (wssdebug) {
483 int i;
484 for (i = MC1_PORT; i <= MC7_PORT; i++)
485 DPRINTF(("port %03x after init = %02x\n",
486 i, mad_read(sc, i)));
487 }
488 #endif
489 }
490