wss.c revision 1.42 1 /* $NetBSD: wss.c,v 1.42 1998/01/19 22:18:23 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/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/syslog.h>
43 #include <sys/device.h>
44 #include <sys/proc.h>
45 #include <sys/buf.h>
46
47 #include <machine/cpu.h>
48 #include <machine/intr.h>
49 #include <machine/bus.h>
50 #include <machine/pio.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 __P((void *, struct audio_device *));
78
79 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
80 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
81 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
82
83 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
84 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
85
86 /*
87 * Define our interface to the higher level audio driver.
88 */
89
90 struct audio_hw_if wss_hw_if = {
91 ad1848_open,
92 ad1848_close,
93 NULL,
94 ad1848_query_encoding,
95 ad1848_set_params,
96 ad1848_round_blocksize,
97 ad1848_commit_settings,
98 ad1848_dma_init_output,
99 ad1848_dma_init_input,
100 ad1848_dma_output,
101 ad1848_dma_input,
102 ad1848_halt_out_dma,
103 ad1848_halt_in_dma,
104 NULL,
105 wss_getdev,
106 NULL,
107 wss_mixer_set_port,
108 wss_mixer_get_port,
109 wss_query_devinfo,
110 ad1848_malloc,
111 ad1848_free,
112 ad1848_round,
113 ad1848_mappage,
114 ad1848_get_props,
115 };
116
117 /*
118 * Attach hardware to driver, attach hardware driver to audio
119 * pseudo-device driver .
120 */
121 void
122 wssattach(sc)
123 struct wss_softc *sc;
124 {
125 int version;
126
127 madattach(sc);
128
129 sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->wss_irq, IST_EDGE, IPL_AUDIO,
130 ad1848_intr, &sc->sc_ad1848);
131
132 ad1848_attach(&sc->sc_ad1848);
133
134 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK;
135 printf(" (vers %d)", version);
136 switch(sc->mad_chip_type) {
137 case MAD_82C928:
138 printf(", 82C928");
139 break;
140 case MAD_OTI601D:
141 printf(", OTI-601D");
142 break;
143 case MAD_82C929:
144 printf(", 82C929");
145 break;
146 case MAD_82C931:
147 printf(", 82C931");
148 break;
149 default:
150 break;
151 }
152 printf("\n");
153
154 sc->sc_ad1848.parent = sc;
155
156 audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev);
157 }
158
159 static int
160 wss_to_vol(cp, vol)
161 mixer_ctrl_t *cp;
162 struct ad1848_volume *vol;
163 {
164 if (cp->un.value.num_channels == 1) {
165 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
166 return(1);
167 }
168 else if (cp->un.value.num_channels == 2) {
169 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
170 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
171 return(1);
172 }
173 return(0);
174 }
175
176 static int
177 wss_from_vol(cp, vol)
178 mixer_ctrl_t *cp;
179 struct ad1848_volume *vol;
180 {
181 if (cp->un.value.num_channels == 1) {
182 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
183 return(1);
184 }
185 else if (cp->un.value.num_channels == 2) {
186 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
187 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
188 return(1);
189 }
190 return(0);
191 }
192
193 int
194 wss_getdev(addr, retp)
195 void *addr;
196 struct audio_device *retp;
197 {
198 *retp = wss_device;
199 return 0;
200 }
201
202 int
203 wss_mixer_set_port(addr, cp)
204 void *addr;
205 mixer_ctrl_t *cp;
206 {
207 struct ad1848_softc *ac = addr;
208 struct wss_softc *sc = ac->parent;
209 struct ad1848_volume vol;
210 int error = EINVAL;
211
212 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
213
214 switch (cp->dev) {
215 case WSS_MIC_IN_LVL: /* Microphone */
216 if (cp->type == AUDIO_MIXER_VALUE) {
217 if (wss_to_vol(cp, &vol))
218 error = ad1848_set_aux2_gain(ac, &vol);
219 }
220 break;
221
222 case WSS_MIC_IN_MUTE: /* Microphone */
223 if (cp->type == AUDIO_MIXER_ENUM) {
224 sc->mic_mute = cp->un.ord;
225 DPRINTF(("mic mute %d\n", cp->un.ord));
226 error = 0;
227 }
228 break;
229
230 case WSS_LINE_IN_LVL: /* linein/CD */
231 if (cp->type == AUDIO_MIXER_VALUE) {
232 if (wss_to_vol(cp, &vol))
233 error = ad1848_set_aux1_gain(ac, &vol);
234 }
235 break;
236
237 case WSS_LINE_IN_MUTE: /* linein/CD */
238 if (cp->type == AUDIO_MIXER_ENUM) {
239 sc->cd_mute = cp->un.ord;
240 DPRINTF(("CD mute %d\n", cp->un.ord));
241 error = 0;
242 }
243 break;
244
245 case WSS_DAC_LVL: /* dac out */
246 if (cp->type == AUDIO_MIXER_VALUE) {
247 if (wss_to_vol(cp, &vol))
248 error = ad1848_set_out_gain(ac, &vol);
249 }
250 break;
251
252 case WSS_DAC_MUTE: /* dac out */
253 if (cp->type == AUDIO_MIXER_ENUM) {
254 sc->dac_mute = cp->un.ord;
255 DPRINTF(("DAC mute %d\n", cp->un.ord));
256 error = 0;
257 }
258 break;
259
260 case WSS_REC_LVL: /* record level */
261 if (cp->type == AUDIO_MIXER_VALUE) {
262 if (wss_to_vol(cp, &vol))
263 error = ad1848_set_rec_gain(ac, &vol);
264 }
265 break;
266
267 case WSS_RECORD_SOURCE:
268 if (cp->type == AUDIO_MIXER_ENUM) {
269 error = ad1848_set_rec_port(ac, cp->un.ord);
270 }
271 break;
272
273 case WSS_MON_LVL:
274 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
275 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
276 error = ad1848_set_mon_gain(ac, &vol);
277 }
278 break;
279
280 default:
281 return ENXIO;
282 /*NOTREACHED*/
283 }
284
285 return 0;
286 }
287
288 int
289 wss_mixer_get_port(addr, cp)
290 void *addr;
291 mixer_ctrl_t *cp;
292 {
293 struct ad1848_softc *ac = addr;
294 struct wss_softc *sc = ac->parent;
295 struct ad1848_volume vol;
296 int error = EINVAL;
297
298 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
299
300 switch (cp->dev) {
301 case WSS_MIC_IN_LVL: /* Microphone */
302 if (cp->type == AUDIO_MIXER_VALUE) {
303 error = ad1848_get_aux2_gain(ac, &vol);
304 if (!error)
305 wss_from_vol(cp, &vol);
306 }
307 break;
308
309 case WSS_MIC_IN_MUTE:
310 if (cp->type == AUDIO_MIXER_ENUM) {
311 cp->un.ord = sc->mic_mute;
312 error = 0;
313 }
314 break;
315
316 case WSS_LINE_IN_LVL: /* linein/CD */
317 if (cp->type == AUDIO_MIXER_VALUE) {
318 error = ad1848_get_aux1_gain(ac, &vol);
319 if (!error)
320 wss_from_vol(cp, &vol);
321 }
322 break;
323
324 case WSS_LINE_IN_MUTE:
325 if (cp->type == AUDIO_MIXER_ENUM) {
326 cp->un.ord = sc->cd_mute;
327 error = 0;
328 }
329 break;
330
331 case WSS_DAC_LVL: /* dac out */
332 if (cp->type == AUDIO_MIXER_VALUE) {
333 error = ad1848_get_out_gain(ac, &vol);
334 if (!error)
335 wss_from_vol(cp, &vol);
336 }
337 break;
338
339 case WSS_DAC_MUTE:
340 if (cp->type == AUDIO_MIXER_ENUM) {
341 cp->un.ord = sc->dac_mute;
342 error = 0;
343 }
344 break;
345
346 case WSS_REC_LVL: /* record level */
347 if (cp->type == AUDIO_MIXER_VALUE) {
348 error = ad1848_get_rec_gain(ac, &vol);
349 if (!error)
350 wss_from_vol(cp, &vol);
351 }
352 break;
353
354 case WSS_RECORD_SOURCE:
355 if (cp->type == AUDIO_MIXER_ENUM) {
356 cp->un.ord = ad1848_get_rec_port(ac);
357 error = 0;
358 }
359 break;
360
361 case WSS_MON_LVL: /* monitor level */
362 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
363 error = ad1848_get_mon_gain(ac, &vol);
364 if (!error)
365 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
366 }
367 break;
368
369 default:
370 error = ENXIO;
371 break;
372 }
373
374 return(error);
375 }
376
377 int
378 wss_query_devinfo(addr, dip)
379 void *addr;
380 mixer_devinfo_t *dip;
381 {
382 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
383
384 switch(dip->index) {
385 case WSS_MIC_IN_LVL: /* Microphone */
386 dip->type = AUDIO_MIXER_VALUE;
387 dip->mixer_class = WSS_INPUT_CLASS;
388 dip->prev = AUDIO_MIXER_LAST;
389 dip->next = WSS_MIC_IN_MUTE;
390 strcpy(dip->label.name, AudioNmicrophone);
391 dip->un.v.num_channels = 2;
392 strcpy(dip->un.v.units.name, AudioNvolume);
393 break;
394
395 case WSS_LINE_IN_LVL: /* line/CD */
396 dip->type = AUDIO_MIXER_VALUE;
397 dip->mixer_class = WSS_INPUT_CLASS;
398 dip->prev = AUDIO_MIXER_LAST;
399 dip->next = WSS_LINE_IN_MUTE;
400 strcpy(dip->label.name, AudioNcd);
401 dip->un.v.num_channels = 2;
402 strcpy(dip->un.v.units.name, AudioNvolume);
403 break;
404
405 case WSS_DAC_LVL: /* dacout */
406 dip->type = AUDIO_MIXER_VALUE;
407 dip->mixer_class = WSS_INPUT_CLASS;
408 dip->prev = AUDIO_MIXER_LAST;
409 dip->next = WSS_DAC_MUTE;
410 strcpy(dip->label.name, AudioNdac);
411 dip->un.v.num_channels = 2;
412 strcpy(dip->un.v.units.name, AudioNvolume);
413 break;
414
415 case WSS_REC_LVL: /* record level */
416 dip->type = AUDIO_MIXER_VALUE;
417 dip->mixer_class = WSS_RECORD_CLASS;
418 dip->prev = AUDIO_MIXER_LAST;
419 dip->next = WSS_RECORD_SOURCE;
420 strcpy(dip->label.name, AudioNrecord);
421 dip->un.v.num_channels = 2;
422 strcpy(dip->un.v.units.name, AudioNvolume);
423 break;
424
425 case WSS_MON_LVL: /* monitor level */
426 dip->type = AUDIO_MIXER_VALUE;
427 dip->mixer_class = WSS_MONITOR_CLASS;
428 dip->next = dip->prev = AUDIO_MIXER_LAST;
429 strcpy(dip->label.name, AudioNmonitor);
430 dip->un.v.num_channels = 1;
431 strcpy(dip->un.v.units.name, AudioNvolume);
432 break;
433
434 case WSS_INPUT_CLASS: /* input class descriptor */
435 dip->type = AUDIO_MIXER_CLASS;
436 dip->mixer_class = WSS_INPUT_CLASS;
437 dip->next = dip->prev = AUDIO_MIXER_LAST;
438 strcpy(dip->label.name, AudioCinputs);
439 break;
440
441 case WSS_MONITOR_CLASS: /* monitor class descriptor */
442 dip->type = AUDIO_MIXER_CLASS;
443 dip->mixer_class = WSS_MONITOR_CLASS;
444 dip->next = dip->prev = AUDIO_MIXER_LAST;
445 strcpy(dip->label.name, AudioCmonitor);
446 break;
447
448 case WSS_RECORD_CLASS: /* record source class */
449 dip->type = AUDIO_MIXER_CLASS;
450 dip->mixer_class = WSS_RECORD_CLASS;
451 dip->next = dip->prev = AUDIO_MIXER_LAST;
452 strcpy(dip->label.name, AudioCrecord);
453 break;
454
455 case WSS_MIC_IN_MUTE:
456 dip->mixer_class = WSS_INPUT_CLASS;
457 dip->type = AUDIO_MIXER_ENUM;
458 dip->prev = WSS_MIC_IN_LVL;
459 dip->next = AUDIO_MIXER_LAST;
460 goto mute;
461
462 case WSS_LINE_IN_MUTE:
463 dip->mixer_class = WSS_INPUT_CLASS;
464 dip->type = AUDIO_MIXER_ENUM;
465 dip->prev = WSS_LINE_IN_LVL;
466 dip->next = AUDIO_MIXER_LAST;
467 goto mute;
468
469 case WSS_DAC_MUTE:
470 dip->mixer_class = WSS_INPUT_CLASS;
471 dip->type = AUDIO_MIXER_ENUM;
472 dip->prev = WSS_DAC_LVL;
473 dip->next = AUDIO_MIXER_LAST;
474 mute:
475 strcpy(dip->label.name, AudioNmute);
476 dip->un.e.num_mem = 2;
477 strcpy(dip->un.e.member[0].label.name, AudioNoff);
478 dip->un.e.member[0].ord = 0;
479 strcpy(dip->un.e.member[1].label.name, AudioNon);
480 dip->un.e.member[1].ord = 1;
481 break;
482
483 case WSS_RECORD_SOURCE:
484 dip->mixer_class = WSS_RECORD_CLASS;
485 dip->type = AUDIO_MIXER_ENUM;
486 dip->prev = WSS_REC_LVL;
487 dip->next = AUDIO_MIXER_LAST;
488 strcpy(dip->label.name, AudioNsource);
489 dip->un.e.num_mem = 3;
490 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
491 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
492 strcpy(dip->un.e.member[1].label.name, AudioNcd);
493 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
494 strcpy(dip->un.e.member[2].label.name, AudioNdac);
495 dip->un.e.member[2].ord = WSS_DAC_LVL;
496 break;
497
498 default:
499 return ENXIO;
500 /*NOTREACHED*/
501 }
502 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
503
504 return 0;
505 }
506
507
508 /*
509 * Copyright by Hannu Savolainen 1994
510 *
511 * Redistribution and use in source and binary forms, with or without
512 * modification, are permitted provided that the following conditions are
513 * met: 1. Redistributions of source code must retain the above copyright
514 * notice, this list of conditions and the following disclaimer. 2.
515 * Redistributions in binary form must reproduce the above copyright notice,
516 * this list of conditions and the following disclaimer in the documentation
517 * and/or other materials provided with the distribution.
518 *
519 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
520 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
521 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
522 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
523 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
524 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
525 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
526 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
527 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
528 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
529 * SUCH DAMAGE.
530 *
531 */
532 /*
533 * Initialization code for OPTi MAD16 compatible audio chips. Including
534 *
535 * OPTi 82C928 MAD16 (replaced by C929)
536 * OAK OTI-601D Mozart
537 * OPTi 82C929 MAD16 Pro
538 *
539 */
540
541 u_int
542 mad_read(sc, port)
543 struct wss_softc *sc;
544 int port;
545 {
546 u_int tmp;
547 int pwd;
548 int s;
549
550 switch (sc->mad_chip_type) { /* Output password */
551 case MAD_82C928:
552 case MAD_OTI601D:
553 pwd = M_PASSWD_928;
554 break;
555 case MAD_82C929:
556 pwd = M_PASSWD_929;
557 break;
558 case MAD_82C931:
559 pwd = M_PASSWD_931;
560 break;
561 default:
562 panic("mad_read: Bad chip type=%d\n", sc->mad_chip_type);
563 }
564 s = splaudio(); /* don't want an interrupt between outb&inb */
565 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
566 tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port);
567 splx(s);
568 return tmp;
569 }
570
571 void
572 mad_write(sc, port, value)
573 struct wss_softc *sc;
574 int port;
575 int value;
576 {
577 int pwd;
578 int s;
579
580 switch (sc->mad_chip_type) { /* Output password */
581 case MAD_82C928:
582 case MAD_OTI601D:
583 pwd = M_PASSWD_928;
584 break;
585 case MAD_82C929:
586 pwd = M_PASSWD_929;
587 break;
588 case MAD_82C931:
589 pwd = M_PASSWD_931;
590 break;
591 default:
592 panic("mad_write: Bad chip type=%d\n", sc->mad_chip_type);
593 }
594 s = splaudio();
595 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
596 bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff);
597 splx(s);
598 }
599
600 void
601 madattach(sc)
602 struct wss_softc *sc;
603 {
604 unsigned char cs4231_mode;
605 int joy;
606
607 if (sc->mad_chip_type == MAD_NONE)
608 return;
609
610 /* Do we want the joystick disabled? */
611 joy = sc->sc_dev.dv_cfdata->cf_flags & 2 ? MC1_JOYDISABLE : 0;
612
613 /* enable WSS emulation at the I/O port */
614 mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(sc->mad_ioindex) | joy);
615 mad_write(sc, MC2_PORT, 0x03); /* ? */
616 mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */
617
618 cs4231_mode =
619 strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 ||
620 strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0;
621
622 if (sc->mad_chip_type == MAD_82C929) {
623 mad_write(sc, MC4_PORT, 0x92);
624 mad_write(sc, MC5_PORT, 0xA5 | cs4231_mode);
625 mad_write(sc, MC6_PORT, 0x03); /* Disable MPU401 */
626 } else {
627 mad_write(sc, MC4_PORT, 0x02);
628 mad_write(sc, MC5_PORT, 0x30 | cs4231_mode);
629 }
630
631 #ifdef AUDIO_DEBUG
632 if (wssdebug) {
633 int i;
634 for (i = MC1_PORT; i <= MC7_PORT; i++)
635 DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, i)));
636 }
637 #endif
638 }
639