wss.c revision 1.41 1 /* $NetBSD: wss.c,v 1.41 1998/01/12 09:43:52 thorpej 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 * MAD support:
9 * Copyright (c) 1996 Lennart Augustsson
10 * Based on code which is
11 * Copyright (c) 1995 Hannu Savolainen
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the Computer Systems
24 * Engineering Group at Lawrence Berkeley Laboratory.
25 * 4. Neither the name of the University nor of the Laboratory may be used
26 * to endorse or promote products derived from this software without
27 * specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 */
42 /*
43 * Copyright by Hannu Savolainen 1994
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions are
47 * met: 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer. 2.
49 * Redistributions in binary form must reproduce the above copyright notice,
50 * this list of conditions and the following disclaimer in the documentation
51 * and/or other materials provided with the distribution.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
54 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
55 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
56 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
57 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
59 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
60 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 */
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/ioctl.h>
71 #include <sys/syslog.h>
72 #include <sys/device.h>
73 #include <sys/proc.h>
74 #include <sys/buf.h>
75
76 #include <machine/cpu.h>
77 #include <machine/intr.h>
78 #include <machine/bus.h>
79 #include <machine/pio.h>
80
81 #include <sys/audioio.h>
82 #include <dev/audio_if.h>
83
84 #include <dev/isa/isavar.h>
85 #include <dev/isa/isadmavar.h>
86
87 #include <dev/ic/ad1848reg.h>
88 #include <dev/isa/ad1848var.h>
89 #include <dev/isa/wssreg.h>
90 #include <dev/isa/madreg.h>
91
92 /*
93 * Mixer devices
94 */
95 #define WSS_MIC_IN_LVL 0
96 #define WSS_LINE_IN_LVL 1
97 #define WSS_DAC_LVL 2
98 #define WSS_REC_LVL 3
99 #define WSS_MON_LVL 4
100 #define WSS_MIC_IN_MUTE 5
101 #define WSS_LINE_IN_MUTE 6
102 #define WSS_DAC_MUTE 7
103
104 #define WSS_RECORD_SOURCE 8
105
106 /* Classes */
107 #define WSS_INPUT_CLASS 9
108 #define WSS_RECORD_CLASS 10
109 #define WSS_MONITOR_CLASS 11
110
111 #ifdef AUDIO_DEBUG
112 #define DPRINTF(x) if (wssdebug) printf x
113 int wssdebug = 0;
114 #else
115 #define DPRINTF(x)
116 #endif
117
118 struct wss_softc {
119 struct device sc_dev; /* base device */
120 struct isadev sc_id; /* ISA device */
121 void *sc_ih; /* interrupt vectoring */
122 bus_space_tag_t sc_iot; /* tag */
123 bus_space_handle_t sc_ioh; /* handle */
124
125 struct ad1848_softc sc_ad1848;
126 #define wss_irq sc_ad1848.sc_irq
127 #define wss_drq sc_ad1848.sc_drq
128
129 int mic_mute, cd_mute, dac_mute;
130 int mad_chip_type; /* chip type if MAD emulation of WSS */
131 bus_space_handle_t sc_mad_ioh; /* MAD handle */
132 bus_space_handle_t sc_mad_ioh1, sc_mad_ioh2, sc_mad_ioh3;
133 };
134
135 struct audio_device wss_device = {
136 "wss,ad1848",
137 "",
138 "WSS"
139 };
140
141 int wss_getdev __P((void *, struct audio_device *));
142
143 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
144 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
145 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
146
147 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
148 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
149
150 static int wssfind __P((struct device *, struct wss_softc *, struct isa_attach_args *));
151
152 static int madprobe __P((struct wss_softc *, int));
153 static void madattach __P((struct wss_softc *));
154 static void madunmap __P((struct wss_softc *));
155
156 /*
157 * Define our interface to the higher level audio driver.
158 */
159
160 struct audio_hw_if wss_hw_if = {
161 ad1848_open,
162 ad1848_close,
163 NULL,
164 ad1848_query_encoding,
165 ad1848_set_params,
166 ad1848_round_blocksize,
167 ad1848_commit_settings,
168 ad1848_dma_init_output,
169 ad1848_dma_init_input,
170 ad1848_dma_output,
171 ad1848_dma_input,
172 ad1848_halt_out_dma,
173 ad1848_halt_in_dma,
174 NULL,
175 wss_getdev,
176 NULL,
177 wss_mixer_set_port,
178 wss_mixer_get_port,
179 wss_query_devinfo,
180 ad1848_malloc,
181 ad1848_free,
182 ad1848_round,
183 ad1848_mappage,
184 ad1848_get_props,
185 };
186
187 #ifdef __BROKEN_INDIRECT_CONFIG
188 int wssprobe __P((struct device *, void *, void *));
189 #else
190 int wssprobe __P((struct device *, struct cfdata *, void *));
191 #endif
192 void wssattach __P((struct device *, struct device *, void *));
193
194 struct cfattach wss_ca = {
195 sizeof(struct wss_softc), wssprobe, wssattach
196 };
197
198 /*
199 * Probe for the Microsoft Sound System hardware.
200 */
201 int
202 wssprobe(parent, match, aux)
203 struct device *parent;
204 #ifdef __BROKEN_INDIRECT_CONFIG
205 void *match;
206 #else
207 struct cfdata *match;
208 #endif
209 void *aux;
210 {
211 struct wss_softc probesc, *sc = &probesc;
212
213 bzero(sc, sizeof *sc);
214 #ifdef __BROKEN_INDIRECT_CONFIG
215 sc->sc_dev.dv_cfdata = ((struct device *)match)->dv_cfdata;
216 #else
217 sc->sc_dev.dv_cfdata = match;
218 #endif
219 if (wssfind(parent, sc, aux)) {
220 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC);
221 ad1848_unmap(&sc->sc_ad1848);
222 madunmap(sc);
223 return 1;
224 } else
225 /* Everything is already unmapped */
226 return 0;
227 }
228
229 static int
230 wssfind(parent, sc, ia)
231 struct device *parent;
232 struct wss_softc *sc;
233 struct isa_attach_args *ia;
234 {
235 static u_char interrupt_bits[12] = {
236 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
237 };
238 static u_char dma_bits[4] = {1, 2, 0, 3};
239
240 sc->sc_iot = ia->ia_iot;
241 if (sc->sc_dev.dv_cfdata->cf_flags & 1)
242 sc->mad_chip_type = madprobe(sc, ia->ia_iobase);
243 else
244 sc->mad_chip_type = MAD_NONE;
245
246 if (!WSS_BASE_VALID(ia->ia_iobase)) {
247 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase));
248 goto bad1;
249 }
250
251 /* Map the ports upto the AD1848 port */
252 if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh))
253 goto bad1;
254
255 sc->sc_ad1848.sc_iot = sc->sc_iot;
256 sc->sc_ad1848.sc_iobase = ia->ia_iobase + WSS_CODEC;
257
258 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */
259 if (ad1848_probe(&sc->sc_ad1848) == 0)
260 goto bad;
261
262 ia->ia_iosize = WSS_NPORT;
263
264 /* Setup WSS interrupt and DMA */
265 if (!WSS_DRQ_VALID(ia->ia_drq)) {
266 DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq));
267 goto bad;
268 }
269 sc->wss_drq = ia->ia_drq;
270
271 /* XXX reqdrq? */
272 if (sc->wss_drq != -1 && isa_drq_isfree(parent, sc->wss_drq) == 0)
273 goto bad;
274
275 #ifdef NEWCONFIG
276 /*
277 * If the IRQ wasn't compiled in, auto-detect it.
278 */
279 if (ia->ia_irq == IRQUNK) {
280 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848);
281 if (!WSS_IRQ_VALID(ia->ia_irq)) {
282 printf("wss: couldn't auto-detect interrupt\n");
283 goto bad;
284 }
285 }
286 else
287 #endif
288 if (!WSS_IRQ_VALID(ia->ia_irq)) {
289 DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq));
290 goto bad;
291 }
292
293 sc->wss_irq = ia->ia_irq;
294
295 bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG,
296 (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq]));
297
298 if (sc->sc_ad1848.mode <= 1)
299 ia->ia_drq2 = -1;
300 return 1;
301
302 bad:
303 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC);
304 bad1:
305 madunmap(sc);
306 return 0;
307 }
308
309 /*
310 * Attach hardware to driver, attach hardware driver to audio
311 * pseudo-device driver .
312 */
313 void
314 wssattach(parent, self, aux)
315 struct device *parent, *self;
316 void *aux;
317 {
318 struct wss_softc *sc = (struct wss_softc *)self;
319 struct isa_attach_args *ia = (struct isa_attach_args *)aux;
320 int version;
321
322 if (!wssfind(parent, sc, ia)) {
323 printf("%s: wssfind failed\n", sc->sc_dev.dv_xname);
324 return;
325 }
326
327 madattach(sc);
328
329 sc->sc_ad1848.sc_recdrq = sc->sc_ad1848.mode > 1 && ia->ia_drq2 != -1 ? ia->ia_drq2 : ia->ia_drq;
330 sc->sc_ad1848.sc_isa = parent;
331
332 #ifdef NEWCONFIG
333 isa_establish(&sc->sc_id, &sc->sc_dev);
334 #endif
335 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
336 ad1848_intr, &sc->sc_ad1848);
337
338 ad1848_attach(&sc->sc_ad1848);
339
340 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK;
341 printf(" (vers %d)", version);
342 if (sc->mad_chip_type != MAD_NONE)
343 printf(", %s",
344 sc->mad_chip_type == MAD_82C929 ? "82C929" :
345 sc->mad_chip_type == MAD_82C928 ? "82C928" :
346 "OTI-601D");
347 printf("\n");
348
349 sc->sc_ad1848.parent = sc;
350
351 audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev);
352 }
353
354 static int
355 wss_to_vol(cp, vol)
356 mixer_ctrl_t *cp;
357 struct ad1848_volume *vol;
358 {
359 if (cp->un.value.num_channels == 1) {
360 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
361 return(1);
362 }
363 else if (cp->un.value.num_channels == 2) {
364 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
365 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
366 return(1);
367 }
368 return(0);
369 }
370
371 static int
372 wss_from_vol(cp, vol)
373 mixer_ctrl_t *cp;
374 struct ad1848_volume *vol;
375 {
376 if (cp->un.value.num_channels == 1) {
377 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
378 return(1);
379 }
380 else if (cp->un.value.num_channels == 2) {
381 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
382 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
383 return(1);
384 }
385 return(0);
386 }
387
388 int
389 wss_getdev(addr, retp)
390 void *addr;
391 struct audio_device *retp;
392 {
393 *retp = wss_device;
394 return 0;
395 }
396
397 int
398 wss_mixer_set_port(addr, cp)
399 void *addr;
400 mixer_ctrl_t *cp;
401 {
402 struct ad1848_softc *ac = addr;
403 struct wss_softc *sc = ac->parent;
404 struct ad1848_volume vol;
405 int error = EINVAL;
406
407 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
408
409 switch (cp->dev) {
410 case WSS_MIC_IN_LVL: /* Microphone */
411 if (cp->type == AUDIO_MIXER_VALUE) {
412 if (wss_to_vol(cp, &vol))
413 error = ad1848_set_aux2_gain(ac, &vol);
414 }
415 break;
416
417 case WSS_MIC_IN_MUTE: /* Microphone */
418 if (cp->type == AUDIO_MIXER_ENUM) {
419 sc->mic_mute = cp->un.ord;
420 DPRINTF(("mic mute %d\n", cp->un.ord));
421 error = 0;
422 }
423 break;
424
425 case WSS_LINE_IN_LVL: /* linein/CD */
426 if (cp->type == AUDIO_MIXER_VALUE) {
427 if (wss_to_vol(cp, &vol))
428 error = ad1848_set_aux1_gain(ac, &vol);
429 }
430 break;
431
432 case WSS_LINE_IN_MUTE: /* linein/CD */
433 if (cp->type == AUDIO_MIXER_ENUM) {
434 sc->cd_mute = cp->un.ord;
435 DPRINTF(("CD mute %d\n", cp->un.ord));
436 error = 0;
437 }
438 break;
439
440 case WSS_DAC_LVL: /* dac out */
441 if (cp->type == AUDIO_MIXER_VALUE) {
442 if (wss_to_vol(cp, &vol))
443 error = ad1848_set_out_gain(ac, &vol);
444 }
445 break;
446
447 case WSS_DAC_MUTE: /* dac out */
448 if (cp->type == AUDIO_MIXER_ENUM) {
449 sc->dac_mute = cp->un.ord;
450 DPRINTF(("DAC mute %d\n", cp->un.ord));
451 error = 0;
452 }
453 break;
454
455 case WSS_REC_LVL: /* record level */
456 if (cp->type == AUDIO_MIXER_VALUE) {
457 if (wss_to_vol(cp, &vol))
458 error = ad1848_set_rec_gain(ac, &vol);
459 }
460 break;
461
462 case WSS_RECORD_SOURCE:
463 if (cp->type == AUDIO_MIXER_ENUM) {
464 error = ad1848_set_rec_port(ac, cp->un.ord);
465 }
466 break;
467
468 case WSS_MON_LVL:
469 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
470 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
471 error = ad1848_set_mon_gain(ac, &vol);
472 }
473 break;
474
475 default:
476 return ENXIO;
477 /*NOTREACHED*/
478 }
479
480 return 0;
481 }
482
483 int
484 wss_mixer_get_port(addr, cp)
485 void *addr;
486 mixer_ctrl_t *cp;
487 {
488 struct ad1848_softc *ac = addr;
489 struct wss_softc *sc = ac->parent;
490 struct ad1848_volume vol;
491 int error = EINVAL;
492
493 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
494
495 switch (cp->dev) {
496 case WSS_MIC_IN_LVL: /* Microphone */
497 if (cp->type == AUDIO_MIXER_VALUE) {
498 error = ad1848_get_aux2_gain(ac, &vol);
499 if (!error)
500 wss_from_vol(cp, &vol);
501 }
502 break;
503
504 case WSS_MIC_IN_MUTE:
505 if (cp->type == AUDIO_MIXER_ENUM) {
506 cp->un.ord = sc->mic_mute;
507 error = 0;
508 }
509 break;
510
511 case WSS_LINE_IN_LVL: /* linein/CD */
512 if (cp->type == AUDIO_MIXER_VALUE) {
513 error = ad1848_get_aux1_gain(ac, &vol);
514 if (!error)
515 wss_from_vol(cp, &vol);
516 }
517 break;
518
519 case WSS_LINE_IN_MUTE:
520 if (cp->type == AUDIO_MIXER_ENUM) {
521 cp->un.ord = sc->cd_mute;
522 error = 0;
523 }
524 break;
525
526 case WSS_DAC_LVL: /* dac out */
527 if (cp->type == AUDIO_MIXER_VALUE) {
528 error = ad1848_get_out_gain(ac, &vol);
529 if (!error)
530 wss_from_vol(cp, &vol);
531 }
532 break;
533
534 case WSS_DAC_MUTE:
535 if (cp->type == AUDIO_MIXER_ENUM) {
536 cp->un.ord = sc->dac_mute;
537 error = 0;
538 }
539 break;
540
541 case WSS_REC_LVL: /* record level */
542 if (cp->type == AUDIO_MIXER_VALUE) {
543 error = ad1848_get_rec_gain(ac, &vol);
544 if (!error)
545 wss_from_vol(cp, &vol);
546 }
547 break;
548
549 case WSS_RECORD_SOURCE:
550 if (cp->type == AUDIO_MIXER_ENUM) {
551 cp->un.ord = ad1848_get_rec_port(ac);
552 error = 0;
553 }
554 break;
555
556 case WSS_MON_LVL: /* monitor level */
557 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
558 error = ad1848_get_mon_gain(ac, &vol);
559 if (!error)
560 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
561 }
562 break;
563
564 default:
565 error = ENXIO;
566 break;
567 }
568
569 return(error);
570 }
571
572 int
573 wss_query_devinfo(addr, dip)
574 void *addr;
575 mixer_devinfo_t *dip;
576 {
577 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
578
579 switch(dip->index) {
580 case WSS_MIC_IN_LVL: /* Microphone */
581 dip->type = AUDIO_MIXER_VALUE;
582 dip->mixer_class = WSS_INPUT_CLASS;
583 dip->prev = AUDIO_MIXER_LAST;
584 dip->next = WSS_MIC_IN_MUTE;
585 strcpy(dip->label.name, AudioNmicrophone);
586 dip->un.v.num_channels = 2;
587 strcpy(dip->un.v.units.name, AudioNvolume);
588 break;
589
590 case WSS_LINE_IN_LVL: /* line/CD */
591 dip->type = AUDIO_MIXER_VALUE;
592 dip->mixer_class = WSS_INPUT_CLASS;
593 dip->prev = AUDIO_MIXER_LAST;
594 dip->next = WSS_LINE_IN_MUTE;
595 strcpy(dip->label.name, AudioNcd);
596 dip->un.v.num_channels = 2;
597 strcpy(dip->un.v.units.name, AudioNvolume);
598 break;
599
600 case WSS_DAC_LVL: /* dacout */
601 dip->type = AUDIO_MIXER_VALUE;
602 dip->mixer_class = WSS_INPUT_CLASS;
603 dip->prev = AUDIO_MIXER_LAST;
604 dip->next = WSS_DAC_MUTE;
605 strcpy(dip->label.name, AudioNdac);
606 dip->un.v.num_channels = 2;
607 strcpy(dip->un.v.units.name, AudioNvolume);
608 break;
609
610 case WSS_REC_LVL: /* record level */
611 dip->type = AUDIO_MIXER_VALUE;
612 dip->mixer_class = WSS_RECORD_CLASS;
613 dip->prev = AUDIO_MIXER_LAST;
614 dip->next = WSS_RECORD_SOURCE;
615 strcpy(dip->label.name, AudioNrecord);
616 dip->un.v.num_channels = 2;
617 strcpy(dip->un.v.units.name, AudioNvolume);
618 break;
619
620 case WSS_MON_LVL: /* monitor level */
621 dip->type = AUDIO_MIXER_VALUE;
622 dip->mixer_class = WSS_MONITOR_CLASS;
623 dip->next = dip->prev = AUDIO_MIXER_LAST;
624 strcpy(dip->label.name, AudioNmonitor);
625 dip->un.v.num_channels = 1;
626 strcpy(dip->un.v.units.name, AudioNvolume);
627 break;
628
629 case WSS_INPUT_CLASS: /* input class descriptor */
630 dip->type = AUDIO_MIXER_CLASS;
631 dip->mixer_class = WSS_INPUT_CLASS;
632 dip->next = dip->prev = AUDIO_MIXER_LAST;
633 strcpy(dip->label.name, AudioCinputs);
634 break;
635
636 case WSS_MONITOR_CLASS: /* monitor class descriptor */
637 dip->type = AUDIO_MIXER_CLASS;
638 dip->mixer_class = WSS_MONITOR_CLASS;
639 dip->next = dip->prev = AUDIO_MIXER_LAST;
640 strcpy(dip->label.name, AudioCmonitor);
641 break;
642
643 case WSS_RECORD_CLASS: /* record source class */
644 dip->type = AUDIO_MIXER_CLASS;
645 dip->mixer_class = WSS_RECORD_CLASS;
646 dip->next = dip->prev = AUDIO_MIXER_LAST;
647 strcpy(dip->label.name, AudioCrecord);
648 break;
649
650 case WSS_MIC_IN_MUTE:
651 dip->mixer_class = WSS_INPUT_CLASS;
652 dip->type = AUDIO_MIXER_ENUM;
653 dip->prev = WSS_MIC_IN_LVL;
654 dip->next = AUDIO_MIXER_LAST;
655 goto mute;
656
657 case WSS_LINE_IN_MUTE:
658 dip->mixer_class = WSS_INPUT_CLASS;
659 dip->type = AUDIO_MIXER_ENUM;
660 dip->prev = WSS_LINE_IN_LVL;
661 dip->next = AUDIO_MIXER_LAST;
662 goto mute;
663
664 case WSS_DAC_MUTE:
665 dip->mixer_class = WSS_INPUT_CLASS;
666 dip->type = AUDIO_MIXER_ENUM;
667 dip->prev = WSS_DAC_LVL;
668 dip->next = AUDIO_MIXER_LAST;
669 mute:
670 strcpy(dip->label.name, AudioNmute);
671 dip->un.e.num_mem = 2;
672 strcpy(dip->un.e.member[0].label.name, AudioNoff);
673 dip->un.e.member[0].ord = 0;
674 strcpy(dip->un.e.member[1].label.name, AudioNon);
675 dip->un.e.member[1].ord = 1;
676 break;
677
678 case WSS_RECORD_SOURCE:
679 dip->mixer_class = WSS_RECORD_CLASS;
680 dip->type = AUDIO_MIXER_ENUM;
681 dip->prev = WSS_REC_LVL;
682 dip->next = AUDIO_MIXER_LAST;
683 strcpy(dip->label.name, AudioNsource);
684 dip->un.e.num_mem = 3;
685 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
686 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
687 strcpy(dip->un.e.member[1].label.name, AudioNcd);
688 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
689 strcpy(dip->un.e.member[2].label.name, AudioNdac);
690 dip->un.e.member[2].ord = WSS_DAC_LVL;
691 break;
692
693 default:
694 return ENXIO;
695 /*NOTREACHED*/
696 }
697 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
698
699 return 0;
700 }
701
702 /*
703 * Initialization code for OPTi MAD16 compatible audio chips. Including
704 *
705 * OPTi 82C928 MAD16 (replaced by C929)
706 * OAK OTI-601D Mozart
707 * OPTi 82C929 MAD16 Pro
708 *
709 */
710 static unsigned int mad_read __P((struct wss_softc *, int, int));
711 static void mad_write __P((struct wss_softc *, int, int, int));
712 static int detect_mad16 __P((struct wss_softc *, int));
713
714 static unsigned int
715 mad_read(sc, chip_type, port)
716 struct wss_softc *sc;
717 int chip_type;
718 int port;
719 {
720 unsigned int tmp;
721 int s = splaudio(); /* don't want an interrupt between outb&inb */
722
723 switch (chip_type) { /* Output password */
724 case MAD_82C928:
725 case MAD_OTI601D:
726 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928);
727 break;
728 case MAD_82C929:
729 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929);
730 break;
731 }
732 tmp = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, port);
733 splx(s);
734 return tmp;
735 }
736
737 static void
738 mad_write(sc, chip_type, port, value)
739 struct wss_softc *sc;
740 int chip_type;
741 int port;
742 int value;
743 {
744 int s = splaudio(); /* don't want an interrupt between outb&outb */
745
746 switch (chip_type) { /* Output password */
747 case MAD_82C928:
748 case MAD_OTI601D:
749 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928);
750 break;
751 case MAD_82C929:
752 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929);
753 break;
754 }
755 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, port, value & 0xff);
756 splx(s);
757 }
758
759 static int
760 detect_mad16(sc, chip_type)
761 struct wss_softc *sc;
762 int chip_type;
763 {
764 unsigned char tmp, tmp2;
765
766 /*
767 * Check that reading a register doesn't return bus float (0xff)
768 * when the card is accessed using password. This may fail in case
769 * the card is in low power mode. Normally at least the power saving mode
770 * bit should be 0.
771 */
772 if ((tmp = mad_read(sc, chip_type, MC1_PORT)) == 0xff) {
773 DPRINTF(("MC1_PORT returned 0xff\n"));
774 return 0;
775 }
776
777 /*
778 * Now check that the gate is closed on first I/O after writing
779 * the password. (This is how a MAD16 compatible card works).
780 */
781 if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, MC1_PORT)) == tmp) { /* It didn't close */
782 DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
783 return 0;
784 }
785
786 mad_write(sc, chip_type, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */
787
788 /* Compare the bit */
789 if ((tmp2 = mad_read(sc, chip_type, MC1_PORT)) != (tmp ^ 0x80)) {
790 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */
791 DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
792 return 0;
793 }
794
795 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */
796 return 1;
797 }
798
799 static int
800 madprobe(sc, iobase)
801 struct wss_softc *sc;
802 int iobase;
803 {
804 static int valid_ports[M_WSS_NPORTS] =
805 { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 };
806 int i;
807 int chip_type;
808
809 if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->sc_mad_ioh))
810 return MAD_NONE;
811
812 /* Allocate bus space that the MAD chip wants */
813 if (bus_space_map(sc->sc_iot, MAD_REG1, MAD_LEN1, 0, &sc->sc_mad_ioh1))
814 goto bad1;
815 if (bus_space_map(sc->sc_iot, MAD_REG2, MAD_LEN2, 0, &sc->sc_mad_ioh2))
816 goto bad2;
817 if (bus_space_map(sc->sc_iot, MAD_REG3, MAD_LEN3, 0, &sc->sc_mad_ioh3))
818 goto bad3;
819
820 DPRINTF(("mad: Detect using password = 0xE2\n"));
821 if (!detect_mad16(sc, MAD_82C928)) {
822 /* No luck. Try different model */
823 DPRINTF(("mad: Detect using password = 0xE3\n"));
824 if (!detect_mad16(sc, MAD_82C929))
825 goto bad;
826 chip_type = MAD_82C929;
827 DPRINTF(("mad: 82C929 detected\n"));
828 } else {
829 if ((mad_read(sc, MAD_82C928, MC3_PORT) & 0x03) == 0x03) {
830 DPRINTF(("mad: Mozart detected\n"));
831 chip_type = MAD_OTI601D;
832 } else {
833 DPRINTF(("mad: 82C928 detected?\n"));
834 chip_type = MAD_82C928;
835 }
836 }
837
838 #ifdef AUDIO_DEBUG
839 if (wssdebug)
840 for (i = MC1_PORT; i <= MC7_PORT; i++)
841 printf("mad: port %03x = %02x\n", i, mad_read(sc, chip_type, i));
842 #endif
843
844 /* Set the WSS address. */
845 for (i = 0; i < M_WSS_NPORTS; i++)
846 if (valid_ports[i] == iobase)
847 break;
848 if (i >= M_WSS_NPORTS) { /* Not a valid port */
849 printf("mad: Bad WSS base address 0x%x\n", iobase);
850 goto bad;
851 }
852 /* enable WSS emulation at the I/O port, no joystick */
853 mad_write(sc, chip_type, MC1_PORT, M_WSS_PORT_SELECT(i) | MC1_JOYDISABLE);
854
855 mad_write(sc, chip_type, MC2_PORT, 0x03); /* ? */
856 mad_write(sc, chip_type, MC3_PORT, 0xf0); /* Disable SB */
857
858 return chip_type;
859 bad:
860 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh3, MAD_LEN3);
861 bad3:
862 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh2, MAD_LEN2);
863 bad2:
864 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh1, MAD_LEN1);
865 bad1:
866 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT);
867 return MAD_NONE;
868 }
869
870 static void
871 madunmap(sc)
872 struct wss_softc *sc;
873 {
874 if (sc->mad_chip_type == MAD_NONE)
875 return;
876 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT);
877 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh1, MAD_LEN1);
878 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh2, MAD_LEN2);
879 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh3, MAD_LEN3);
880 }
881
882 static void
883 madattach(sc)
884 struct wss_softc *sc;
885 {
886 int chip_type = sc->mad_chip_type;
887 unsigned char cs4231_mode;
888
889 if (chip_type == MAD_NONE)
890 return;
891
892 cs4231_mode =
893 strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 ||
894 strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0;
895
896 if (chip_type == MAD_82C929) {
897 mad_write(sc, chip_type, MC4_PORT, 0xa2);
898 mad_write(sc, chip_type, MC5_PORT, 0xA5 | cs4231_mode);
899 mad_write(sc, chip_type, MC6_PORT, 0x03); /* Disable MPU401 */
900 } else {
901 mad_write(sc, chip_type, MC4_PORT, 0x02);
902 mad_write(sc, chip_type, MC5_PORT, 0x30 | cs4231_mode);
903 }
904
905 #ifdef AUDIO_DEBUG
906 if (wssdebug) {
907 int i;
908 for (i = MC1_PORT; i <= MC7_PORT; i++)
909 DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, chip_type, i)));
910 }
911 #endif
912 }
913