wss.c revision 1.25 1 /* $NetBSD: wss.c,v 1.25 1997/05/09 22:16:43 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 * 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/pio.h>
79
80 #include <sys/audioio.h>
81 #include <dev/audio_if.h>
82
83 #include <dev/isa/isavar.h>
84 #include <dev/isa/isadmavar.h>
85
86 #include <dev/ic/ad1848reg.h>
87 #include <dev/isa/ad1848var.h>
88 #include <dev/isa/wssreg.h>
89 #include <dev/isa/madreg.h>
90
91 /*
92 * Mixer devices
93 */
94 #define WSS_MIC_IN_LVL 0
95 #define WSS_LINE_IN_LVL 1
96 #define WSS_DAC_LVL 2
97 #define WSS_REC_LVL 3
98 #define WSS_MON_LVL 4
99 #define WSS_MIC_IN_MUTE 5
100 #define WSS_LINE_IN_MUTE 6
101 #define WSS_DAC_MUTE 7
102
103 #define WSS_RECORD_SOURCE 8
104
105 /* Classes */
106 #define WSS_INPUT_CLASS 9
107 #define WSS_RECORD_CLASS 10
108 #define WSS_MONITOR_CLASS 11
109
110 #ifdef AUDIO_DEBUG
111 #define DPRINTF(x) if (wssdebug) printf x
112 int wssdebug = 0;
113 #else
114 #define DPRINTF(x)
115 #endif
116
117 struct wss_softc {
118 struct device sc_dev; /* base device */
119 struct isadev sc_id; /* ISA device */
120 void *sc_ih; /* interrupt vectoring */
121 bus_space_tag_t sc_iot; /* tag */
122 bus_space_handle_t sc_ioh; /* handle */
123
124 struct ad1848_softc sc_ad1848;
125 #define wss_irq sc_ad1848.sc_irq
126 #define wss_drq sc_ad1848.sc_drq
127
128 int mic_mute, cd_mute, dac_mute;
129 int mad_chip_type; /* chip type if MAD emulation of WSS */
130 bus_space_handle_t sc_mad_ioh; /* handle */
131 };
132
133 struct audio_device wss_device = {
134 "wss,ad1848",
135 "",
136 "WSS"
137 };
138
139 int wssopen __P((dev_t, int));
140 int wss_getdev __P((void *, struct audio_device *));
141 int wss_setfd __P((void *, int));
142
143 int wss_set_out_port __P((void *, int));
144 int wss_get_out_port __P((void *));
145 int wss_set_in_port __P((void *, int));
146 int wss_get_in_port __P((void *));
147 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
148 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
149 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
150
151 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
152 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
153
154 static int madprobe __P((struct wss_softc *, int));
155 static void madprobedone __P((struct wss_softc *));
156
157 /*
158 * Define our interface to the higher level audio driver.
159 */
160
161 struct audio_hw_if wss_hw_if = {
162 wssopen,
163 ad1848_close,
164 NULL,
165 ad1848_query_encoding,
166 ad1848_set_params,
167 ad1848_round_blocksize,
168 wss_set_out_port,
169 wss_get_out_port,
170 wss_set_in_port,
171 wss_get_in_port,
172 ad1848_commit_settings,
173 ad1848_dma_output,
174 ad1848_dma_input,
175 ad1848_halt_out_dma,
176 ad1848_halt_in_dma,
177 ad1848_cont_out_dma,
178 ad1848_cont_in_dma,
179 NULL,
180 wss_getdev,
181 wss_setfd,
182 wss_mixer_set_port,
183 wss_mixer_get_port,
184 wss_query_devinfo,
185 0, /* not full-duplex */
186 0
187 };
188
189 int wssprobe __P((struct device *, void *, void *));
190 void wssattach __P((struct device *, struct device *, void *));
191
192 struct cfattach wss_ca = {
193 sizeof(struct wss_softc), wssprobe, wssattach
194 };
195
196 struct cfdriver wss_cd = {
197 NULL, "wss", DV_DULL
198 };
199
200 /*
201 * Probe for the Microsoft Sound System hardware.
202 */
203 int
204 wssprobe(parent, match, aux)
205 struct device *parent;
206 void *match, *aux;
207 {
208 register struct wss_softc *sc = match;
209 register struct isa_attach_args *ia = aux;
210 static u_char interrupt_bits[12] = {
211 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
212 };
213 static u_char dma_bits[4] = {1, 2, 0, 3};
214
215 sc->sc_iot = ia->ia_iot;
216 if (sc->sc_dev.dv_cfdata->cf_flags & 1)
217 sc->mad_chip_type = madprobe(sc, ia->ia_iobase);
218 else
219 sc->mad_chip_type = MAD_NONE;
220
221 if (!WSS_BASE_VALID(ia->ia_iobase)) {
222 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase));
223 return 0;
224 }
225
226 /* map the ports upto the AD1488 port */
227 if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh))
228 return 0;
229
230 sc->sc_ad1848.sc_iot = sc->sc_iot;
231 sc->sc_ad1848.sc_iobase = ia->ia_iobase + WSS_CODEC;
232
233 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */
234 if (ad1848_probe(&sc->sc_ad1848) == 0)
235 goto bad;
236
237 ia->ia_iosize = WSS_NPORT;
238
239 /* Setup WSS interrupt and DMA */
240 if (!WSS_DRQ_VALID(ia->ia_drq)) {
241 DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq));
242 goto bad;
243 }
244 sc->wss_drq = ia->ia_drq;
245
246 #ifdef NEWCONFIG
247 /*
248 * If the IRQ wasn't compiled in, auto-detect it.
249 */
250 if (ia->ia_irq == IRQUNK) {
251 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848);
252 if (!WSS_IRQ_VALID(ia->ia_irq)) {
253 printf("wss: couldn't auto-detect interrupt\n");
254 goto bad;
255 }
256 }
257 else
258 #endif
259 if (!WSS_IRQ_VALID(ia->ia_irq)) {
260 DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq));
261 goto bad;
262 }
263
264 sc->wss_irq = ia->ia_irq;
265
266 bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG,
267 (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq]));
268
269 if (sc->mad_chip_type != MAD_NONE)
270 madprobedone(sc);
271
272 return 1;
273
274 bad:
275 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC);
276 if (sc->mad_chip_type != MAD_NONE)
277 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT);
278 return 0;
279 }
280
281 /*
282 * Attach hardware to driver, attach hardware driver to audio
283 * pseudo-device driver .
284 */
285 void
286 wssattach(parent, self, aux)
287 struct device *parent, *self;
288 void *aux;
289 {
290 register struct wss_softc *sc = (struct wss_softc *)self;
291 struct isa_attach_args *ia = (struct isa_attach_args *)aux;
292 int version;
293 int err;
294
295 sc->sc_ad1848.sc_recdrq = ia->ia_drq;
296
297 #ifdef NEWCONFIG
298 isa_establish(&sc->sc_id, &sc->sc_dev);
299 #endif
300 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
301 ad1848_intr, &sc->sc_ad1848);
302
303 ad1848_attach(&sc->sc_ad1848);
304
305 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK;
306 printf(" (vers %d)", version);
307 if (sc->mad_chip_type != MAD_NONE)
308 printf(", %s",
309 sc->mad_chip_type == MAD_82C929 ? "82C929" :
310 sc->mad_chip_type == MAD_82C928 ? "82C928" :
311 "OTI-601D");
312 printf("\n");
313
314 sc->sc_ad1848.parent = sc;
315
316 if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0)
317 printf("wss: could not attach to audio pseudo-device driver (%d)\n", err);
318 }
319
320 static int
321 wss_to_vol(cp, vol)
322 mixer_ctrl_t *cp;
323 struct ad1848_volume *vol;
324 {
325 if (cp->un.value.num_channels == 1) {
326 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
327 return(1);
328 }
329 else if (cp->un.value.num_channels == 2) {
330 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
331 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
332 return(1);
333 }
334 return(0);
335 }
336
337 static int
338 wss_from_vol(cp, vol)
339 mixer_ctrl_t *cp;
340 struct ad1848_volume *vol;
341 {
342 if (cp->un.value.num_channels == 1) {
343 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
344 return(1);
345 }
346 else if (cp->un.value.num_channels == 2) {
347 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
348 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
349 return(1);
350 }
351 return(0);
352 }
353
354 int
355 wssopen(dev, flags)
356 dev_t dev;
357 int flags;
358 {
359 struct wss_softc *sc;
360 int unit = AUDIOUNIT(dev);
361
362 if (unit >= wss_cd.cd_ndevs)
363 return ENODEV;
364
365 sc = wss_cd.cd_devs[unit];
366 if (!sc)
367 return ENXIO;
368
369 return ad1848_open(&sc->sc_ad1848, dev, flags);
370 }
371
372 int
373 wss_getdev(addr, retp)
374 void *addr;
375 struct audio_device *retp;
376 {
377 *retp = wss_device;
378 return 0;
379 }
380
381 int
382 wss_setfd(addr, flag)
383 void *addr;
384 int flag;
385 {
386 /* Can't do full-duplex */
387 return(ENOTTY);
388 }
389
390
391 int
392 wss_set_out_port(addr, port)
393 void *addr;
394 int port;
395 {
396 DPRINTF(("wss_set_out_port:\n"));
397 return(EINVAL);
398 }
399
400 int
401 wss_get_out_port(addr)
402 void *addr;
403 {
404 DPRINTF(("wss_get_out_port:\n"));
405 return(WSS_DAC_LVL);
406 }
407
408 int
409 wss_set_in_port(addr, port)
410 void *addr;
411 int port;
412 {
413 register struct ad1848_softc *ac = addr;
414
415 DPRINTF(("wss_set_in_port: %d\n", port));
416
417 switch(port) {
418 case WSS_MIC_IN_LVL:
419 port = MIC_IN_PORT;
420 break;
421 case WSS_LINE_IN_LVL:
422 port = LINE_IN_PORT;
423 break;
424 case WSS_DAC_LVL:
425 port = DAC_IN_PORT;
426 break;
427 default:
428 return(EINVAL);
429 /*NOTREACHED*/
430 }
431
432 return(ad1848_set_rec_port(ac, port));
433 }
434
435 int
436 wss_get_in_port(addr)
437 void *addr;
438 {
439 register struct ad1848_softc *ac = addr;
440 int port = WSS_MIC_IN_LVL;
441
442 switch(ad1848_get_rec_port(ac)) {
443 case MIC_IN_PORT:
444 port = WSS_MIC_IN_LVL;
445 break;
446 case LINE_IN_PORT:
447 port = WSS_LINE_IN_LVL;
448 break;
449 case DAC_IN_PORT:
450 port = WSS_DAC_LVL;
451 break;
452 }
453
454 DPRINTF(("wss_get_in_port: %d\n", port));
455
456 return(port);
457 }
458
459 int
460 wss_mixer_set_port(addr, cp)
461 void *addr;
462 mixer_ctrl_t *cp;
463 {
464 register struct ad1848_softc *ac = addr;
465 register struct wss_softc *sc = ac->parent;
466 struct ad1848_volume vol;
467 int error = EINVAL;
468
469 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
470
471 switch (cp->dev) {
472 case WSS_MIC_IN_LVL: /* Microphone */
473 if (cp->type == AUDIO_MIXER_VALUE) {
474 if (wss_to_vol(cp, &vol))
475 error = ad1848_set_aux2_gain(ac, &vol);
476 }
477 break;
478
479 case WSS_MIC_IN_MUTE: /* Microphone */
480 if (cp->type == AUDIO_MIXER_ENUM) {
481 sc->mic_mute = cp->un.ord;
482 DPRINTF(("mic mute %d\n", cp->un.ord));
483 error = 0;
484 }
485 break;
486
487 case WSS_LINE_IN_LVL: /* linein/CD */
488 if (cp->type == AUDIO_MIXER_VALUE) {
489 if (wss_to_vol(cp, &vol))
490 error = ad1848_set_aux1_gain(ac, &vol);
491 }
492 break;
493
494 case WSS_LINE_IN_MUTE: /* linein/CD */
495 if (cp->type == AUDIO_MIXER_ENUM) {
496 sc->cd_mute = cp->un.ord;
497 DPRINTF(("CD mute %d\n", cp->un.ord));
498 error = 0;
499 }
500 break;
501
502 case WSS_DAC_LVL: /* dac out */
503 if (cp->type == AUDIO_MIXER_VALUE) {
504 if (wss_to_vol(cp, &vol))
505 error = ad1848_set_out_gain(ac, &vol);
506 }
507 break;
508
509 case WSS_DAC_MUTE: /* dac out */
510 if (cp->type == AUDIO_MIXER_ENUM) {
511 sc->dac_mute = cp->un.ord;
512 DPRINTF(("DAC mute %d\n", cp->un.ord));
513 error = 0;
514 }
515 break;
516
517 case WSS_REC_LVL: /* record level */
518 if (cp->type == AUDIO_MIXER_VALUE) {
519 if (wss_to_vol(cp, &vol))
520 error = ad1848_set_rec_gain(ac, &vol);
521 }
522 break;
523
524 case WSS_RECORD_SOURCE:
525 if (cp->type == AUDIO_MIXER_ENUM) {
526 error = ad1848_set_rec_port(ac, cp->un.ord);
527 }
528 break;
529
530 case WSS_MON_LVL:
531 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
532 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
533 error = ad1848_set_mon_gain(ac, &vol);
534 }
535 break;
536
537 default:
538 return ENXIO;
539 /*NOTREACHED*/
540 }
541
542 return 0;
543 }
544
545 int
546 wss_mixer_get_port(addr, cp)
547 void *addr;
548 mixer_ctrl_t *cp;
549 {
550 register struct ad1848_softc *ac = addr;
551 register struct wss_softc *sc = ac->parent;
552 struct ad1848_volume vol;
553 int error = EINVAL;
554
555 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
556
557 switch (cp->dev) {
558 case WSS_MIC_IN_LVL: /* Microphone */
559 if (cp->type == AUDIO_MIXER_VALUE) {
560 error = ad1848_get_aux2_gain(ac, &vol);
561 if (!error)
562 wss_from_vol(cp, &vol);
563 }
564 break;
565
566 case WSS_MIC_IN_MUTE:
567 if (cp->type == AUDIO_MIXER_ENUM) {
568 cp->un.ord = sc->mic_mute;
569 error = 0;
570 }
571 break;
572
573 case WSS_LINE_IN_LVL: /* linein/CD */
574 if (cp->type == AUDIO_MIXER_VALUE) {
575 error = ad1848_get_aux1_gain(ac, &vol);
576 if (!error)
577 wss_from_vol(cp, &vol);
578 }
579 break;
580
581 case WSS_LINE_IN_MUTE:
582 if (cp->type == AUDIO_MIXER_ENUM) {
583 cp->un.ord = sc->cd_mute;
584 error = 0;
585 }
586 break;
587
588 case WSS_DAC_LVL: /* dac out */
589 if (cp->type == AUDIO_MIXER_VALUE) {
590 error = ad1848_get_out_gain(ac, &vol);
591 if (!error)
592 wss_from_vol(cp, &vol);
593 }
594 break;
595
596 case WSS_DAC_MUTE:
597 if (cp->type == AUDIO_MIXER_ENUM) {
598 cp->un.ord = sc->dac_mute;
599 error = 0;
600 }
601 break;
602
603 case WSS_REC_LVL: /* record level */
604 if (cp->type == AUDIO_MIXER_VALUE) {
605 error = ad1848_get_rec_gain(ac, &vol);
606 if (!error)
607 wss_from_vol(cp, &vol);
608 }
609 break;
610
611 case WSS_RECORD_SOURCE:
612 if (cp->type == AUDIO_MIXER_ENUM) {
613 cp->un.ord = ad1848_get_rec_port(ac);
614 error = 0;
615 }
616 break;
617
618 case WSS_MON_LVL: /* monitor level */
619 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
620 error = ad1848_get_mon_gain(ac, &vol);
621 if (!error)
622 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
623 }
624 break;
625
626 default:
627 error = ENXIO;
628 break;
629 }
630
631 return(error);
632 }
633
634 int
635 wss_query_devinfo(addr, dip)
636 void *addr;
637 register mixer_devinfo_t *dip;
638 {
639 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
640
641 switch(dip->index) {
642 case WSS_MIC_IN_LVL: /* Microphone */
643 dip->type = AUDIO_MIXER_VALUE;
644 dip->mixer_class = WSS_INPUT_CLASS;
645 dip->prev = AUDIO_MIXER_LAST;
646 dip->next = WSS_MIC_IN_MUTE;
647 strcpy(dip->label.name, AudioNmicrophone);
648 dip->un.v.num_channels = 2;
649 strcpy(dip->un.v.units.name, AudioNvolume);
650 break;
651
652 case WSS_LINE_IN_LVL: /* line/CD */
653 dip->type = AUDIO_MIXER_VALUE;
654 dip->mixer_class = WSS_INPUT_CLASS;
655 dip->prev = AUDIO_MIXER_LAST;
656 dip->next = WSS_LINE_IN_MUTE;
657 strcpy(dip->label.name, AudioNcd);
658 dip->un.v.num_channels = 2;
659 strcpy(dip->un.v.units.name, AudioNvolume);
660 break;
661
662 case WSS_DAC_LVL: /* dacout */
663 dip->type = AUDIO_MIXER_VALUE;
664 dip->mixer_class = WSS_INPUT_CLASS;
665 dip->prev = AUDIO_MIXER_LAST;
666 dip->next = WSS_DAC_MUTE;
667 strcpy(dip->label.name, AudioNdac);
668 dip->un.v.num_channels = 2;
669 strcpy(dip->un.v.units.name, AudioNvolume);
670 break;
671
672 case WSS_REC_LVL: /* record level */
673 dip->type = AUDIO_MIXER_VALUE;
674 dip->mixer_class = WSS_RECORD_CLASS;
675 dip->prev = AUDIO_MIXER_LAST;
676 dip->next = WSS_RECORD_SOURCE;
677 strcpy(dip->label.name, AudioNrecord);
678 dip->un.v.num_channels = 2;
679 strcpy(dip->un.v.units.name, AudioNvolume);
680 break;
681
682 case WSS_MON_LVL: /* monitor level */
683 dip->type = AUDIO_MIXER_VALUE;
684 dip->mixer_class = WSS_MONITOR_CLASS;
685 dip->next = dip->prev = AUDIO_MIXER_LAST;
686 strcpy(dip->label.name, AudioNmonitor);
687 dip->un.v.num_channels = 1;
688 strcpy(dip->un.v.units.name, AudioNvolume);
689 break;
690
691 case WSS_INPUT_CLASS: /* input class descriptor */
692 dip->type = AUDIO_MIXER_CLASS;
693 dip->mixer_class = WSS_INPUT_CLASS;
694 dip->next = dip->prev = AUDIO_MIXER_LAST;
695 strcpy(dip->label.name, AudioCInputs);
696 break;
697
698 case WSS_MONITOR_CLASS: /* monitor class descriptor */
699 dip->type = AUDIO_MIXER_CLASS;
700 dip->mixer_class = WSS_MONITOR_CLASS;
701 dip->next = dip->prev = AUDIO_MIXER_LAST;
702 strcpy(dip->label.name, AudioCMonitor);
703 break;
704
705 case WSS_RECORD_CLASS: /* record source class */
706 dip->type = AUDIO_MIXER_CLASS;
707 dip->mixer_class = WSS_RECORD_CLASS;
708 dip->next = dip->prev = AUDIO_MIXER_LAST;
709 strcpy(dip->label.name, AudioCRecord);
710 break;
711
712 case WSS_MIC_IN_MUTE:
713 dip->mixer_class = WSS_INPUT_CLASS;
714 dip->type = AUDIO_MIXER_ENUM;
715 dip->prev = WSS_MIC_IN_LVL;
716 dip->next = AUDIO_MIXER_LAST;
717 goto mute;
718
719 case WSS_LINE_IN_MUTE:
720 dip->mixer_class = WSS_INPUT_CLASS;
721 dip->type = AUDIO_MIXER_ENUM;
722 dip->prev = WSS_LINE_IN_LVL;
723 dip->next = AUDIO_MIXER_LAST;
724 goto mute;
725
726 case WSS_DAC_MUTE:
727 dip->mixer_class = WSS_INPUT_CLASS;
728 dip->type = AUDIO_MIXER_ENUM;
729 dip->prev = WSS_DAC_LVL;
730 dip->next = AUDIO_MIXER_LAST;
731 mute:
732 strcpy(dip->label.name, AudioNmute);
733 dip->un.e.num_mem = 2;
734 strcpy(dip->un.e.member[0].label.name, AudioNoff);
735 dip->un.e.member[0].ord = 0;
736 strcpy(dip->un.e.member[1].label.name, AudioNon);
737 dip->un.e.member[1].ord = 1;
738 break;
739
740 case WSS_RECORD_SOURCE:
741 dip->mixer_class = WSS_RECORD_CLASS;
742 dip->type = AUDIO_MIXER_ENUM;
743 dip->prev = WSS_REC_LVL;
744 dip->next = AUDIO_MIXER_LAST;
745 strcpy(dip->label.name, AudioNsource);
746 dip->un.e.num_mem = 3;
747 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
748 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
749 strcpy(dip->un.e.member[1].label.name, AudioNcd);
750 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
751 strcpy(dip->un.e.member[2].label.name, AudioNdac);
752 dip->un.e.member[2].ord = WSS_DAC_LVL;
753 break;
754
755 default:
756 return ENXIO;
757 /*NOTREACHED*/
758 }
759 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
760
761 return 0;
762 }
763
764 /*
765 * Initialization code for OPTi MAD16 compatible audio chips. Including
766 *
767 * OPTi 82C928 MAD16 (replaced by C929)
768 * OAK OTI-601D Mozart
769 * OPTi 82C929 MAD16 Pro
770 *
771 */
772 static unsigned int mad_read __P((struct wss_softc *, int, int));
773 static void mad_write __P((struct wss_softc *, int, int, int));
774 static int detect_mad16 __P((struct wss_softc *, int));
775
776 static unsigned int
777 mad_read(sc, chip_type, port)
778 struct wss_softc *sc;
779 int chip_type;
780 int port;
781 {
782 unsigned int tmp;
783 int s = splaudio(); /* don't want an interrupt between outb&inb */
784
785 switch (chip_type) { /* Output password */
786 case MAD_82C928:
787 case MAD_OTI601D:
788 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928);
789 break;
790 case MAD_82C929:
791 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929);
792 break;
793 }
794 tmp = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, port);
795 splx(s);
796 return tmp;
797 }
798
799 static void
800 mad_write(sc, chip_type, port, value)
801 struct wss_softc *sc;
802 int chip_type;
803 int port;
804 int value;
805 {
806 int s = splaudio(); /* don't want an interrupt between outb&outb */
807
808 switch (chip_type) { /* Output password */
809 case MAD_82C928:
810 case MAD_OTI601D:
811 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928);
812 break;
813 case MAD_82C929:
814 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929);
815 break;
816 }
817 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, port, value & 0xff);
818 splx(s);
819 }
820
821 static int
822 detect_mad16(sc, chip_type)
823 struct wss_softc *sc;
824 int chip_type;
825 {
826 unsigned char tmp, tmp2;
827
828 /*
829 * Check that reading a register doesn't return bus float (0xff)
830 * when the card is accessed using password. This may fail in case
831 * the card is in low power mode. Normally at least the power saving mode
832 * bit should be 0.
833 */
834 if ((tmp = mad_read(sc, chip_type, MC1_PORT)) == 0xff) {
835 DPRINTF(("MC1_PORT returned 0xff\n"));
836 return 0;
837 }
838
839 /*
840 * Now check that the gate is closed on first I/O after writing
841 * the password. (This is how a MAD16 compatible card works).
842 */
843 if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, MC1_PORT)) == tmp) { /* It didn't close */
844 DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
845 return 0;
846 }
847
848 mad_write(sc, chip_type, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */
849
850 /* Compare the bit */
851 if ((tmp2 = mad_read(sc, chip_type, MC1_PORT)) != (tmp ^ 0x80)) {
852 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */
853 DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
854 return 0;
855 }
856
857 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */
858 return 1;
859 }
860
861 static int
862 madprobe(sc, iobase)
863 struct wss_softc *sc;
864 int iobase;
865 {
866 static int valid_ports[M_WSS_NPORTS] =
867 { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 };
868 int i;
869 int chip_type;
870
871 if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->sc_mad_ioh))
872 return MAD_NONE;
873
874 DPRINTF(("mad: Detect using password = 0xE2\n"));
875 if (!detect_mad16(sc, MAD_82C928)) {
876 /* No luck. Try different model */
877 DPRINTF(("mad: Detect using password = 0xE3\n"));
878 if (!detect_mad16(sc, MAD_82C929))
879 goto bad;
880 chip_type = MAD_82C929;
881 DPRINTF(("mad: 82C929 detected\n"));
882 } else {
883 if ((mad_read(sc, MAD_82C928, MC3_PORT) & 0x03) == 0x03) {
884 DPRINTF(("mad: Mozart detected\n"));
885 chip_type = MAD_OTI601D;
886 } else {
887 DPRINTF(("mad: 82C928 detected?\n"));
888 chip_type = MAD_82C928;
889 }
890 }
891
892 #ifdef AUDIO_DEBUG
893 if (wssdebug)
894 for (i = MC1_PORT; i <= MC7_PORT; i++)
895 printf("mad: port %03x = %02x\n", i, mad_read(sc, chip_type, i));
896 #endif
897
898 /* Set the WSS address. */
899 for (i = 0; i < 4; i++)
900 if (valid_ports[i] == iobase)
901 break;
902 if (i > 3) { /* Not a valid port */
903 printf("mad: Bad WSS base address 0x%x\n", iobase);
904 goto bad;
905 }
906 /* enable WSS emulation at the I/O port, keep joystck */
907 mad_write(sc, chip_type, MC1_PORT, M_WSS_PORT_SELECT(i));
908
909 mad_write(sc, chip_type, MC2_PORT, 0x03); /* ? */
910 mad_write(sc, chip_type, MC3_PORT, 0xf0); /* Disable SB */
911
912 return chip_type;
913 bad:
914 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT);
915 return MAD_NONE;
916 }
917
918 static void
919 madprobedone(sc)
920 struct wss_softc *sc;
921 {
922 int chip_type = sc->mad_chip_type;
923 unsigned char cs4231_mode;
924
925 cs4231_mode =
926 strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 ||
927 strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0;
928
929 if (chip_type == MAD_82C929) {
930 mad_write(sc, chip_type, MC4_PORT, 0xa2);
931 mad_write(sc, chip_type, MC5_PORT, 0xA5 | cs4231_mode);
932 mad_write(sc, chip_type, MC6_PORT, 0x03); /* Disable MPU401 */
933 } else {
934 mad_write(sc, chip_type, MC4_PORT, 0x02);
935 mad_write(sc, chip_type, MC5_PORT, 0x30 | cs4231_mode);
936 }
937
938 #ifdef AUDIO_DEBUG
939 if (wssdebug) {
940 int i;
941 for (i = MC1_PORT; i <= MC7_PORT; i++)
942 DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, chip_type, i)));
943 }
944 #endif
945 }
946