wss.c revision 1.18 1 /* $NetBSD: wss.c,v 1.18 1997/03/19 06:47:37 mikel 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/pio.h>
50
51 #include <sys/audioio.h>
52 #include <dev/audio_if.h>
53
54 #include <dev/isa/isavar.h>
55 #include <dev/isa/isadmavar.h>
56
57 #include <dev/ic/ad1848reg.h>
58 #include <dev/isa/ad1848var.h>
59 #include <dev/isa/wssreg.h>
60
61 /*
62 * Mixer devices
63 */
64 #define WSS_MIC_IN_LVL 0
65 #define WSS_LINE_IN_LVL 1
66 #define WSS_DAC_LVL 2
67 #define WSS_REC_LVL 3
68 #define WSS_MON_LVL 4
69 #define WSS_MIC_IN_MUTE 5
70 #define WSS_LINE_IN_MUTE 6
71 #define WSS_DAC_MUTE 7
72
73 #define WSS_RECORD_SOURCE 8
74
75 /* Classes */
76 #define WSS_INPUT_CLASS 9
77 #define WSS_RECORD_CLASS 10
78 #define WSS_MONITOR_CLASS 11
79
80 #ifdef AUDIO_DEBUG
81 #define DPRINTF(x) if (wssdebug) printf x
82 int wssdebug = 0;
83 #else
84 #define DPRINTF(x)
85 #endif
86
87 struct wss_softc {
88 struct device sc_dev; /* base device */
89 struct isadev sc_id; /* ISA device */
90 void *sc_ih; /* interrupt vectoring */
91
92 struct ad1848_softc sc_ad1848;
93 #define wss_irq sc_ad1848.sc_irq
94 #define wss_drq sc_ad1848.sc_drq
95
96 int mic_mute, cd_mute, dac_mute;
97 };
98
99 struct audio_device wss_device = {
100 "wss,ad1848",
101 "",
102 "WSS"
103 };
104
105 int wssopen __P((dev_t, int));
106 int wss_getdev __P((void *, struct audio_device *));
107 int wss_setfd __P((void *, int));
108
109 int wss_set_out_port __P((void *, int));
110 int wss_get_out_port __P((void *));
111 int wss_set_in_port __P((void *, int));
112 int wss_get_in_port __P((void *));
113 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
114 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
115 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
116
117 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
118 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *));
119 /*
120 * Define our interface to the higher level audio driver.
121 */
122
123 struct audio_hw_if wss_hw_if = {
124 wssopen,
125 ad1848_close,
126 NULL,
127 ad1848_set_in_sr,
128 ad1848_get_in_sr,
129 ad1848_set_out_sr,
130 ad1848_get_out_sr,
131 ad1848_query_encoding,
132 ad1848_set_encoding,
133 ad1848_get_encoding,
134 ad1848_set_precision,
135 ad1848_get_precision,
136 ad1848_set_channels,
137 ad1848_get_channels,
138 ad1848_round_blocksize,
139 wss_set_out_port,
140 wss_get_out_port,
141 wss_set_in_port,
142 wss_get_in_port,
143 ad1848_commit_settings,
144 NULL,
145 NULL,
146 ad1848_dma_output,
147 ad1848_dma_input,
148 ad1848_halt_out_dma,
149 ad1848_halt_in_dma,
150 ad1848_cont_out_dma,
151 ad1848_cont_in_dma,
152 NULL,
153 wss_getdev,
154 wss_setfd,
155 wss_mixer_set_port,
156 wss_mixer_get_port,
157 wss_query_devinfo,
158 0, /* not full-duplex */
159 0
160 };
161
162 int wssprobe __P((struct device *, void *, void *));
163 void wssattach __P((struct device *, struct device *, void *));
164
165 struct cfattach wss_ca = {
166 sizeof(struct wss_softc), wssprobe, wssattach
167 };
168
169 struct cfdriver wss_cd = {
170 NULL, "wss", DV_DULL
171 };
172
173 /*
174 * Probe for the Microsoft Sound System hardware.
175 */
176 int
177 wssprobe(parent, match, aux)
178 struct device *parent;
179 void *match, *aux;
180 {
181 register struct wss_softc *sc = match;
182 register struct isa_attach_args *ia = aux;
183 register int iobase = ia->ia_iobase;
184 static u_char interrupt_bits[12] = {
185 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
186 };
187 static u_char dma_bits[4] = {1, 2, 0, 3};
188
189 if (!WSS_BASE_VALID(ia->ia_iobase)) {
190 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase));
191 return 0;
192 }
193
194 sc->sc_ad1848.sc_iobase = iobase + WSS_CODEC;
195
196 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */
197 if (ad1848_probe(&sc->sc_ad1848) == 0)
198 return 0;
199
200 ia->ia_iosize = WSS_NPORT;
201
202 /* Setup WSS interrupt and DMA */
203 if (!WSS_DRQ_VALID(ia->ia_drq)) {
204 DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq));
205 return 0;
206 }
207 sc->wss_drq = ia->ia_drq;
208
209 #ifdef NEWCONFIG
210 /*
211 * If the IRQ wasn't compiled in, auto-detect it.
212 */
213 if (ia->ia_irq == IRQUNK) {
214 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848);
215 if (!WSS_IRQ_VALID(ia->ia_irq)) {
216 printf("wss: couldn't auto-detect interrupt\n");
217 return 0;
218 }
219 }
220 else
221 #endif
222 if (!WSS_IRQ_VALID(ia->ia_irq)) {
223 DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq));
224 return 0;
225 }
226
227 sc->wss_irq = ia->ia_irq;
228
229 outb(iobase+WSS_CONFIG,
230 (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq]));
231
232 return 1;
233 }
234
235 /*
236 * Attach hardware to driver, attach hardware driver to audio
237 * pseudo-device driver .
238 */
239 void
240 wssattach(parent, self, aux)
241 struct device *parent, *self;
242 void *aux;
243 {
244 register struct wss_softc *sc = (struct wss_softc *)self;
245 struct isa_attach_args *ia = (struct isa_attach_args *)aux;
246 register int iobase = ia->ia_iobase;
247 int err;
248
249 sc->sc_ad1848.sc_recdrq = ia->ia_drq;
250
251 #ifdef NEWCONFIG
252 isa_establish(&sc->sc_id, &sc->sc_dev);
253 #endif
254 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
255 ad1848_intr, &sc->sc_ad1848);
256
257 ad1848_attach(&sc->sc_ad1848);
258
259 printf(" (vers %d)", inb(iobase+WSS_STATUS) & WSS_VERSMASK);
260 printf("\n");
261
262 sc->sc_ad1848.parent = sc;
263
264 if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0)
265 printf("wss: could not attach to audio pseudo-device driver (%d)\n", err);
266 }
267
268 static int
269 wss_to_vol(cp, vol)
270 mixer_ctrl_t *cp;
271 struct ad1848_volume *vol;
272 {
273 if (cp->un.value.num_channels == 1) {
274 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
275 return(1);
276 }
277 else if (cp->un.value.num_channels == 2) {
278 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
279 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
280 return(1);
281 }
282 return(0);
283 }
284
285 static int
286 wss_from_vol(cp, vol)
287 mixer_ctrl_t *cp;
288 struct ad1848_volume *vol;
289 {
290 if (cp->un.value.num_channels == 1) {
291 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
292 return(1);
293 }
294 else if (cp->un.value.num_channels == 2) {
295 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
296 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
297 return(1);
298 }
299 return(0);
300 }
301
302 int
303 wssopen(dev, flags)
304 dev_t dev;
305 int flags;
306 {
307 struct wss_softc *sc;
308 int unit = AUDIOUNIT(dev);
309
310 if (unit >= wss_cd.cd_ndevs)
311 return ENODEV;
312
313 sc = wss_cd.cd_devs[unit];
314 if (!sc)
315 return ENXIO;
316
317 return ad1848_open(&sc->sc_ad1848, dev, flags);
318 }
319
320 int
321 wss_getdev(addr, retp)
322 void *addr;
323 struct audio_device *retp;
324 {
325 *retp = wss_device;
326 return 0;
327 }
328
329 int
330 wss_setfd(addr, flag)
331 void *addr;
332 int flag;
333 {
334 /* Can't do full-duplex */
335 return(ENOTTY);
336 }
337
338
339 int
340 wss_set_out_port(addr, port)
341 void *addr;
342 int port;
343 {
344 DPRINTF(("wss_set_out_port:\n"));
345 return(EINVAL);
346 }
347
348 int
349 wss_get_out_port(addr)
350 void *addr;
351 {
352 DPRINTF(("wss_get_out_port:\n"));
353 return(WSS_DAC_LVL);
354 }
355
356 int
357 wss_set_in_port(addr, port)
358 void *addr;
359 int port;
360 {
361 register struct ad1848_softc *ac = addr;
362
363 DPRINTF(("wss_set_in_port: %d\n", port));
364
365 switch(port) {
366 case WSS_MIC_IN_LVL:
367 port = MIC_IN_PORT;
368 break;
369 case WSS_LINE_IN_LVL:
370 port = LINE_IN_PORT;
371 break;
372 case WSS_DAC_LVL:
373 port = DAC_IN_PORT;
374 break;
375 default:
376 return(EINVAL);
377 /*NOTREACHED*/
378 }
379
380 return(ad1848_set_rec_port(ac, port));
381 }
382
383 int
384 wss_get_in_port(addr)
385 void *addr;
386 {
387 register struct ad1848_softc *ac = addr;
388 int port = WSS_MIC_IN_LVL;
389
390 switch(ad1848_get_rec_port(ac)) {
391 case MIC_IN_PORT:
392 port = WSS_MIC_IN_LVL;
393 break;
394 case LINE_IN_PORT:
395 port = WSS_LINE_IN_LVL;
396 break;
397 case DAC_IN_PORT:
398 port = WSS_DAC_LVL;
399 break;
400 }
401
402 DPRINTF(("wss_get_in_port: %d\n", port));
403
404 return(port);
405 }
406
407 int
408 wss_mixer_set_port(addr, cp)
409 void *addr;
410 mixer_ctrl_t *cp;
411 {
412 register struct ad1848_softc *ac = addr;
413 register struct wss_softc *sc = ac->parent;
414 struct ad1848_volume vol;
415 int error = EINVAL;
416
417 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
418
419 switch (cp->dev) {
420 case WSS_MIC_IN_LVL: /* Microphone */
421 if (cp->type == AUDIO_MIXER_VALUE) {
422 if (wss_to_vol(cp, &vol))
423 error = ad1848_set_aux2_gain(ac, &vol);
424 }
425 break;
426
427 case WSS_MIC_IN_MUTE: /* Microphone */
428 if (cp->type == AUDIO_MIXER_ENUM) {
429 sc->mic_mute = cp->un.ord;
430 DPRINTF(("mic mute %d\n", cp->un.ord));
431 error = 0;
432 }
433 break;
434
435 case WSS_LINE_IN_LVL: /* linein/CD */
436 if (cp->type == AUDIO_MIXER_VALUE) {
437 if (wss_to_vol(cp, &vol))
438 error = ad1848_set_aux1_gain(ac, &vol);
439 }
440 break;
441
442 case WSS_LINE_IN_MUTE: /* linein/CD */
443 if (cp->type == AUDIO_MIXER_ENUM) {
444 sc->cd_mute = cp->un.ord;
445 DPRINTF(("CD mute %d\n", cp->un.ord));
446 error = 0;
447 }
448 break;
449
450 case WSS_DAC_LVL: /* dac out */
451 if (cp->type == AUDIO_MIXER_VALUE) {
452 if (wss_to_vol(cp, &vol))
453 error = ad1848_set_out_gain(ac, &vol);
454 }
455 break;
456
457 case WSS_DAC_MUTE: /* dac out */
458 if (cp->type == AUDIO_MIXER_ENUM) {
459 sc->dac_mute = cp->un.ord;
460 DPRINTF(("DAC mute %d\n", cp->un.ord));
461 error = 0;
462 }
463 break;
464
465 case WSS_REC_LVL: /* record level */
466 if (cp->type == AUDIO_MIXER_VALUE) {
467 if (wss_to_vol(cp, &vol))
468 error = ad1848_set_rec_gain(ac, &vol);
469 }
470 break;
471
472 case WSS_RECORD_SOURCE:
473 if (cp->type == AUDIO_MIXER_ENUM) {
474 error = ad1848_set_rec_port(ac, cp->un.ord);
475 }
476 break;
477
478 case WSS_MON_LVL:
479 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
480 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
481 error = ad1848_set_mon_gain(ac, &vol);
482 }
483 break;
484
485 default:
486 return ENXIO;
487 /*NOTREACHED*/
488 }
489
490 return 0;
491 }
492
493 int
494 wss_mixer_get_port(addr, cp)
495 void *addr;
496 mixer_ctrl_t *cp;
497 {
498 register struct ad1848_softc *ac = addr;
499 register struct wss_softc *sc = ac->parent;
500 struct ad1848_volume vol;
501 int error = EINVAL;
502
503 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
504
505 switch (cp->dev) {
506 case WSS_MIC_IN_LVL: /* Microphone */
507 if (cp->type == AUDIO_MIXER_VALUE) {
508 error = ad1848_get_aux2_gain(ac, &vol);
509 if (!error)
510 wss_from_vol(cp, &vol);
511 }
512 break;
513
514 case WSS_MIC_IN_MUTE:
515 if (cp->type == AUDIO_MIXER_ENUM) {
516 cp->un.ord = sc->mic_mute;
517 error = 0;
518 }
519 break;
520
521 case WSS_LINE_IN_LVL: /* linein/CD */
522 if (cp->type == AUDIO_MIXER_VALUE) {
523 error = ad1848_get_aux1_gain(ac, &vol);
524 if (!error)
525 wss_from_vol(cp, &vol);
526 }
527 break;
528
529 case WSS_LINE_IN_MUTE:
530 if (cp->type == AUDIO_MIXER_ENUM) {
531 cp->un.ord = sc->cd_mute;
532 error = 0;
533 }
534 break;
535
536 case WSS_DAC_LVL: /* dac out */
537 if (cp->type == AUDIO_MIXER_VALUE) {
538 error = ad1848_get_out_gain(ac, &vol);
539 if (!error)
540 wss_from_vol(cp, &vol);
541 }
542 break;
543
544 case WSS_DAC_MUTE:
545 if (cp->type == AUDIO_MIXER_ENUM) {
546 cp->un.ord = sc->dac_mute;
547 error = 0;
548 }
549 break;
550
551 case WSS_REC_LVL: /* record level */
552 if (cp->type == AUDIO_MIXER_VALUE) {
553 error = ad1848_get_rec_gain(ac, &vol);
554 if (!error)
555 wss_from_vol(cp, &vol);
556 }
557 break;
558
559 case WSS_RECORD_SOURCE:
560 if (cp->type == AUDIO_MIXER_ENUM) {
561 cp->un.ord = ad1848_get_rec_port(ac);
562 error = 0;
563 }
564 break;
565
566 case WSS_MON_LVL: /* monitor level */
567 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
568 error = ad1848_get_mon_gain(ac, &vol);
569 if (!error)
570 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
571 }
572 break;
573
574 default:
575 error = ENXIO;
576 break;
577 }
578
579 return(error);
580 }
581
582 int
583 wss_query_devinfo(addr, dip)
584 void *addr;
585 register mixer_devinfo_t *dip;
586 {
587 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
588
589 switch(dip->index) {
590 case WSS_MIC_IN_LVL: /* Microphone */
591 dip->type = AUDIO_MIXER_VALUE;
592 dip->mixer_class = WSS_INPUT_CLASS;
593 dip->prev = AUDIO_MIXER_LAST;
594 dip->next = WSS_MIC_IN_MUTE;
595 strcpy(dip->label.name, AudioNmicrophone);
596 dip->un.v.num_channels = 2;
597 strcpy(dip->un.v.units.name, AudioNvolume);
598 break;
599
600 case WSS_LINE_IN_LVL: /* line/CD */
601 dip->type = AUDIO_MIXER_VALUE;
602 dip->mixer_class = WSS_INPUT_CLASS;
603 dip->prev = AUDIO_MIXER_LAST;
604 dip->next = WSS_LINE_IN_MUTE;
605 strcpy(dip->label.name, AudioNcd);
606 dip->un.v.num_channels = 2;
607 strcpy(dip->un.v.units.name, AudioNvolume);
608 break;
609
610 case WSS_DAC_LVL: /* dacout */
611 dip->type = AUDIO_MIXER_VALUE;
612 dip->mixer_class = WSS_INPUT_CLASS;
613 dip->prev = AUDIO_MIXER_LAST;
614 dip->next = WSS_DAC_MUTE;
615 strcpy(dip->label.name, AudioNdac);
616 dip->un.v.num_channels = 2;
617 strcpy(dip->un.v.units.name, AudioNvolume);
618 break;
619
620 case WSS_REC_LVL: /* record level */
621 dip->type = AUDIO_MIXER_VALUE;
622 dip->mixer_class = WSS_RECORD_CLASS;
623 dip->prev = AUDIO_MIXER_LAST;
624 dip->next = WSS_RECORD_SOURCE;
625 strcpy(dip->label.name, AudioNrecord);
626 dip->un.v.num_channels = 2;
627 strcpy(dip->un.v.units.name, AudioNvolume);
628 break;
629
630 case WSS_MON_LVL: /* monitor level */
631 dip->type = AUDIO_MIXER_VALUE;
632 dip->mixer_class = WSS_MONITOR_CLASS;
633 dip->next = dip->prev = AUDIO_MIXER_LAST;
634 strcpy(dip->label.name, AudioNmonitor);
635 dip->un.v.num_channels = 1;
636 strcpy(dip->un.v.units.name, AudioNvolume);
637 break;
638
639 case WSS_INPUT_CLASS: /* input class descriptor */
640 dip->type = AUDIO_MIXER_CLASS;
641 dip->mixer_class = WSS_INPUT_CLASS;
642 dip->next = dip->prev = AUDIO_MIXER_LAST;
643 strcpy(dip->label.name, AudioCInputs);
644 break;
645
646 case WSS_MONITOR_CLASS: /* monitor class descriptor */
647 dip->type = AUDIO_MIXER_CLASS;
648 dip->mixer_class = WSS_MONITOR_CLASS;
649 dip->next = dip->prev = AUDIO_MIXER_LAST;
650 strcpy(dip->label.name, AudioNmonitor);
651 break;
652
653 case WSS_RECORD_CLASS: /* record source class */
654 dip->type = AUDIO_MIXER_CLASS;
655 dip->mixer_class = WSS_RECORD_CLASS;
656 dip->next = dip->prev = AUDIO_MIXER_LAST;
657 strcpy(dip->label.name, AudioNrecord);
658 break;
659
660 case WSS_MIC_IN_MUTE:
661 dip->mixer_class = WSS_INPUT_CLASS;
662 dip->type = AUDIO_MIXER_ENUM;
663 dip->prev = WSS_MIC_IN_LVL;
664 dip->next = AUDIO_MIXER_LAST;
665 goto mute;
666
667 case WSS_LINE_IN_MUTE:
668 dip->mixer_class = WSS_INPUT_CLASS;
669 dip->type = AUDIO_MIXER_ENUM;
670 dip->prev = WSS_LINE_IN_LVL;
671 dip->next = AUDIO_MIXER_LAST;
672 goto mute;
673
674 case WSS_DAC_MUTE:
675 dip->mixer_class = WSS_INPUT_CLASS;
676 dip->type = AUDIO_MIXER_ENUM;
677 dip->prev = WSS_DAC_LVL;
678 dip->next = AUDIO_MIXER_LAST;
679 mute:
680 strcpy(dip->label.name, AudioNmute);
681 dip->un.e.num_mem = 2;
682 strcpy(dip->un.e.member[0].label.name, AudioNoff);
683 dip->un.e.member[0].ord = 0;
684 strcpy(dip->un.e.member[1].label.name, AudioNon);
685 dip->un.e.member[1].ord = 1;
686 break;
687
688 case WSS_RECORD_SOURCE:
689 dip->mixer_class = WSS_RECORD_CLASS;
690 dip->type = AUDIO_MIXER_ENUM;
691 dip->prev = WSS_REC_LVL;
692 dip->next = AUDIO_MIXER_LAST;
693 strcpy(dip->label.name, AudioNsource);
694 dip->un.e.num_mem = 3;
695 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
696 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
697 strcpy(dip->un.e.member[1].label.name, AudioNcd);
698 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
699 strcpy(dip->un.e.member[2].label.name, AudioNdac);
700 dip->un.e.member[2].ord = WSS_DAC_LVL;
701 break;
702
703 default:
704 return ENXIO;
705 /*NOTREACHED*/
706 }
707 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
708
709 return 0;
710 }
711