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