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