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