wss.c revision 1.4 1 /* $NetBSD: wss.c,v 1.4 1995/04/17 15:48:37 cgd 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 * $Id: wss.c,v 1.4 1995/04/17 15:48:37 cgd Exp $
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/syslog.h>
44 #include <sys/device.h>
45 #include <sys/proc.h>
46 #include <sys/buf.h>
47
48 #include <machine/cpu.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 #include <i386/isa/icu.h> /* XXX BROKEN; WHY? */
57
58 #include <dev/isa/ad1848var.h>
59 #include <dev/isa/ad1848reg.h>
60 #include <dev/isa/wssreg.h>
61
62 /*
63 * Mixer devices
64 */
65 #define WSS_MIC_IN_LVL 0
66 #define WSS_LINE_IN_LVL 1
67 #define WSS_DAC_LVL 2
68 #define WSS_REC_LVL 3
69 #define WSS_MON_LVL 4
70 #define WSS_MIC_IN_MUTE 5
71 #define WSS_LINE_IN_MUTE 6
72 #define WSS_DAC_MUTE 7
73
74 #define WSS_RECORD_SOURCE 8
75
76 /* Classes */
77 #define WSS_INPUT_CLASS 9
78 #define WSS_RECORD_CLASS 10
79 #define WSS_MONITOR_CLASS 11
80
81 #define DEBUG /*XXX*/
82 #ifdef DEBUG
83 #define DPRINTF(x) if (wssdebug) printf x
84 int wssdebug = 0;
85 #else
86 #define DPRINTF(x)
87 #endif
88
89 struct wss_softc {
90 struct device sc_dev; /* base device */
91 struct isadev sc_id; /* ISA device */
92 void *sc_ih; /* interrupt vectoring */
93
94 struct ad1848_softc sc_ad1848;
95 #define wss_iobase sc_ad1848.sc_iobase
96 #define wss_irq sc_ad1848.sc_irq
97 #define wss_drq sc_ad1848.sc_drq
98
99 int mic_mute, cd_mute, dac_mute;
100 };
101
102 struct audio_device wss_device = {
103 "wss,ad1848",
104 "",
105 "WSS"
106 };
107
108 int wssprobe();
109 void wssattach();
110 int wssopen __P((dev_t, int));
111
112 int wss_getdev __P((void *, struct audio_device *));
113 int wss_setfd __P((void *, int));
114
115 int wss_set_out_port __P((void *, int));
116 int wss_get_out_port __P((void *));
117 int wss_set_in_port __P((void *, int));
118 int wss_get_in_port __P((void *));
119 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
120 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
121 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
122
123 /*
124 * Define our interface to the higher level audio driver.
125 */
126
127 struct audio_hw_if wss_hw_if = {
128 wssopen,
129 ad1848_close,
130 NULL,
131 ad1848_set_in_sr,
132 ad1848_get_in_sr,
133 ad1848_set_out_sr,
134 ad1848_get_out_sr,
135 ad1848_query_encoding,
136 ad1848_set_encoding,
137 ad1848_get_encoding,
138 ad1848_set_precision,
139 ad1848_get_precision,
140 ad1848_set_channels,
141 ad1848_get_channels,
142 ad1848_round_blocksize,
143 wss_set_out_port,
144 wss_get_out_port,
145 wss_set_in_port,
146 wss_get_in_port,
147 ad1848_commit_settings,
148 ad1848_get_silence,
149 NULL,
150 NULL,
151 ad1848_dma_output,
152 ad1848_dma_input,
153 ad1848_halt_out_dma,
154 ad1848_halt_in_dma,
155 ad1848_cont_out_dma,
156 ad1848_cont_in_dma,
157 NULL,
158 wss_getdev,
159 wss_setfd,
160 wss_mixer_set_port,
161 wss_mixer_get_port,
162 wss_query_devinfo,
163 0, /* not full-duplex */
164 0
165 };
166
167 #ifndef NEWCONFIG
168 #define at_dma(flags, ptr, cc, chan) isa_dmastart(flags, ptr, cc, chan)
169 #endif
170
171 struct cfdriver wsscd = {
172 NULL, "wss", wssprobe, wssattach, DV_DULL, sizeof(struct wss_softc)
173 };
174
175 /*
176 * Probe for the Microsoft Sound System hardware.
177 */
178 int
179 wssprobe(parent, self, aux)
180 struct device *parent, *self;
181 void *aux;
182 {
183 register struct wss_softc *sc = (void *)self;
184 register struct isa_attach_args *ia = aux;
185 register u_short iobase = ia->ia_iobase;
186 static u_char interrupt_bits[12] = {
187 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
188 };
189 static u_char dma_bits[4] = {1, 2, 0, 3};
190 char bits;
191
192 if (!WSS_BASE_VALID(ia->ia_iobase)) {
193 printf("wss: configured iobase %d invalid\n", ia->ia_iobase);
194 return 0;
195 }
196
197 sc->wss_iobase = iobase;
198
199 /* Is there an ad1848 chip at the WSS iobase ? */
200 if (ad1848_probe(&sc->sc_ad1848) == 0)
201 return 0;
202
203 #ifdef NEWCONFIG
204 /*
205 * If the IRQ wasn't compiled in, auto-detect it.
206 */
207 if (ia->ia_irq == IRQUNK) {
208 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848);
209 if (!WSS_IRQ_VALID(ia->ia_irq)) {
210 printf("wss: couldn't auto-detect interrupt");
211 return 0;
212 }
213 }
214 else
215 #endif
216 ia->ia_iosize = WSS_NPORT;
217
218 /* Setup WSS interrupt and DMA */
219 if ((bits = interrupt_bits[sc->wss_irq]) == -1) {
220 printf("wss: invalid interrupt configuration (irq=%d)\n", sc->wss_irq);
221 return 0;
222 }
223
224 #if 0
225 /* XXX Dual-DMA */
226 outb(sc->wss_iobase+WSS_CONFIG, (bits | 0x40));
227 if ((inb(sc->wss_iobase+WSS_STATUS) & 0x40) == 0)
228 printf("wss: IRQ?\n");
229 #endif
230 outb(sc->wss_iobase+WSS_CONFIG, (bits | dma_bits[sc->wss_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 u_short iobase = ia->ia_iobase;
247
248 sc->wss_iobase = iobase;
249 sc->wss_drq = 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_irq, ISA_IST_EDGE, ISA_IPL_BIO,
255 ad1848_intr, &sc->sc_ad1848);
256
257 ad1848_attach(&sc->sc_ad1848);
258
259 printf(" (vers %d)", inb(sc->wss_iobase+WSS_STATUS) & 0x1f);
260 printf("\n");
261
262 sc->sc_ad1848.parent = sc;
263
264 if (audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848) != 0)
265 printf("wss: could not attach to audio pseudo-device driver\n");
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 >= wsscd.cd_ndevs)
311 return ENODEV;
312
313 sc = wsscd.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(EINVAL);
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 register struct wss_softc *sc = ac->parent;
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 register struct wss_softc *sc = ac->parent;
390 int port = WSS_MIC_IN_LVL;
391
392 switch(ad1848_get_rec_port(ac)) {
393 case MIC_IN_PORT:
394 port = WSS_MIC_IN_LVL;
395 break;
396 case LINE_IN_PORT:
397 port = WSS_LINE_IN_LVL;
398 break;
399 case DAC_IN_PORT:
400 port = WSS_DAC_LVL;
401 break;
402 }
403
404 DPRINTF(("wss_get_in_port: %d\n", port));
405
406 return(port);
407 }
408
409 int
410 wss_mixer_set_port(addr, cp)
411 void *addr;
412 mixer_ctrl_t *cp;
413 {
414 register struct ad1848_softc *ac = addr;
415 register struct wss_softc *sc = ac->parent;
416 struct ad1848_volume vol;
417 u_char eq;
418 int error = EINVAL;
419
420 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
421
422 switch (cp->dev) {
423 case WSS_MIC_IN_LVL: /* Microphone */
424 if (cp->type == AUDIO_MIXER_VALUE) {
425 if (wss_to_vol(cp, &vol))
426 error = ad1848_set_aux2_gain(ac, &vol);
427 }
428 break;
429
430 case WSS_MIC_IN_MUTE: /* Microphone */
431 if (cp->type == AUDIO_MIXER_ENUM) {
432 sc->mic_mute = cp->un.ord;
433 DPRINTF(("mic mute %d\n", cp->un.ord));
434 error = 0;
435 }
436 break;
437
438 case WSS_LINE_IN_LVL: /* linein/CD */
439 if (cp->type == AUDIO_MIXER_VALUE) {
440 if (wss_to_vol(cp, &vol))
441 error = ad1848_set_aux1_gain(ac, &vol);
442 }
443 break;
444
445 case WSS_LINE_IN_MUTE: /* linein/CD */
446 if (cp->type == AUDIO_MIXER_ENUM) {
447 sc->cd_mute = cp->un.ord;
448 DPRINTF(("CD mute %d\n", cp->un.ord));
449 error = 0;
450 }
451 break;
452
453 case WSS_DAC_LVL: /* dac out */
454 if (cp->type == AUDIO_MIXER_VALUE) {
455 if (wss_to_vol(cp, &vol))
456 error = ad1848_set_out_gain(ac, &vol);
457 }
458 break;
459
460 case WSS_DAC_MUTE: /* dac out */
461 if (cp->type == AUDIO_MIXER_ENUM) {
462 sc->dac_mute = cp->un.ord;
463 DPRINTF(("DAC mute %d\n", cp->un.ord));
464 error = 0;
465 }
466 break;
467
468 case WSS_REC_LVL: /* record level */
469 if (cp->type == AUDIO_MIXER_VALUE) {
470 if (wss_to_vol(cp, &vol))
471 error = ad1848_set_rec_gain(ac, &vol);
472 }
473 break;
474
475 case WSS_RECORD_SOURCE:
476 if (cp->type == AUDIO_MIXER_ENUM) {
477 error = ad1848_set_rec_port(ac, cp->un.ord);
478 }
479 break;
480
481 case WSS_MON_LVL:
482 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
483 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
484 error = ad1848_set_mon_gain(ac, &vol);
485 }
486 break;
487
488 default:
489 return ENXIO;
490 /*NOTREACHED*/
491 }
492
493 return 0;
494 }
495
496 int
497 wss_mixer_get_port(addr, cp)
498 void *addr;
499 mixer_ctrl_t *cp;
500 {
501 register struct ad1848_softc *ac = addr;
502 register struct wss_softc *sc = ac->parent;
503 struct ad1848_volume vol;
504 u_char eq;
505 int error = EINVAL;
506
507 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
508
509 switch (cp->dev) {
510 case WSS_MIC_IN_LVL: /* Microphone */
511 if (cp->type == AUDIO_MIXER_VALUE) {
512 error = ad1848_get_aux2_gain(ac, &vol);
513 if (!error)
514 wss_from_vol(cp, &vol);
515 }
516 break;
517
518 case WSS_MIC_IN_MUTE:
519 if (cp->type == AUDIO_MIXER_ENUM) {
520 cp->un.ord = sc->mic_mute;
521 error = 0;
522 }
523 break;
524
525 case WSS_LINE_IN_LVL: /* linein/CD */
526 if (cp->type == AUDIO_MIXER_VALUE) {
527 error = ad1848_get_aux1_gain(ac, &vol);
528 if (!error)
529 wss_from_vol(cp, &vol);
530 }
531 break;
532
533 case WSS_LINE_IN_MUTE:
534 if (cp->type == AUDIO_MIXER_ENUM) {
535 cp->un.ord = sc->cd_mute;
536 error = 0;
537 }
538 break;
539
540 case WSS_DAC_LVL: /* dac out */
541 if (cp->type == AUDIO_MIXER_VALUE) {
542 error = ad1848_get_out_gain(ac, &vol);
543 if (!error)
544 wss_from_vol(cp, &vol);
545 }
546 break;
547
548 case WSS_DAC_MUTE:
549 if (cp->type == AUDIO_MIXER_ENUM) {
550 cp->un.ord = sc->dac_mute;
551 error = 0;
552 }
553 break;
554
555 case WSS_REC_LVL: /* record level */
556 if (cp->type == AUDIO_MIXER_VALUE) {
557 error = ad1848_get_rec_gain(ac, &vol);
558 if (!error)
559 wss_from_vol(cp, &vol);
560 }
561 break;
562
563 case WSS_RECORD_SOURCE:
564 if (cp->type == AUDIO_MIXER_ENUM) {
565 cp->un.ord = ad1848_get_rec_port(ac);
566 error = 0;
567 }
568 break;
569
570 case WSS_MON_LVL: /* monitor level */
571 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
572 error = ad1848_get_mon_gain(ac, &vol);
573 if (!error)
574 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
575 }
576 break;
577
578 default:
579 error = ENXIO;
580 break;
581 }
582
583 return(error);
584 }
585
586 int
587 wss_query_devinfo(addr, dip)
588 void *addr;
589 register mixer_devinfo_t *dip;
590 {
591 register struct ad1848_softc *ac = addr;
592 register struct wss_softc *sc = ac->parent;
593
594 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
595
596 switch(dip->index) {
597 case WSS_MIC_IN_LVL: /* Microphone */
598 dip->type = AUDIO_MIXER_VALUE;
599 dip->mixer_class = WSS_INPUT_CLASS;
600 dip->prev = AUDIO_MIXER_LAST;
601 dip->next = WSS_MIC_IN_MUTE;
602 strcpy(dip->label.name, AudioNmicrophone);
603 dip->un.v.num_channels = 2;
604 strcpy(dip->un.v.units.name, AudioNvolume);
605 break;
606
607 case WSS_LINE_IN_LVL: /* line/CD */
608 dip->type = AUDIO_MIXER_VALUE;
609 dip->mixer_class = WSS_INPUT_CLASS;
610 dip->prev = AUDIO_MIXER_LAST;
611 dip->next = WSS_LINE_IN_MUTE;
612 strcpy(dip->label.name, AudioNcd);
613 dip->un.v.num_channels = 2;
614 strcpy(dip->un.v.units.name, AudioNvolume);
615 break;
616
617 case WSS_DAC_LVL: /* dacout */
618 dip->type = AUDIO_MIXER_VALUE;
619 dip->mixer_class = WSS_INPUT_CLASS;
620 dip->prev = AUDIO_MIXER_LAST;
621 dip->next = WSS_DAC_MUTE;
622 strcpy(dip->label.name, AudioNdac);
623 dip->un.v.num_channels = 2;
624 strcpy(dip->un.v.units.name, AudioNvolume);
625 break;
626
627 case WSS_REC_LVL: /* record level */
628 dip->type = AUDIO_MIXER_VALUE;
629 dip->mixer_class = WSS_RECORD_CLASS;
630 dip->prev = AUDIO_MIXER_LAST;
631 dip->next = WSS_RECORD_SOURCE;
632 strcpy(dip->label.name, AudioNrecord);
633 dip->un.v.num_channels = 2;
634 strcpy(dip->un.v.units.name, AudioNvolume);
635 break;
636
637 case WSS_MON_LVL: /* monitor level */
638 dip->type = AUDIO_MIXER_VALUE;
639 dip->mixer_class = WSS_MONITOR_CLASS;
640 dip->next = dip->prev = AUDIO_MIXER_LAST;
641 strcpy(dip->label.name, AudioNmonitor);
642 dip->un.v.num_channels = 1;
643 strcpy(dip->un.v.units.name, AudioNvolume);
644 break;
645
646 case WSS_INPUT_CLASS: /* input class descriptor */
647 dip->type = AUDIO_MIXER_CLASS;
648 dip->mixer_class = WSS_INPUT_CLASS;
649 dip->next = dip->prev = AUDIO_MIXER_LAST;
650 strcpy(dip->label.name, AudioCInputs);
651 break;
652
653 case WSS_MONITOR_CLASS: /* monitor class descriptor */
654 dip->type = AUDIO_MIXER_CLASS;
655 dip->mixer_class = WSS_MONITOR_CLASS;
656 dip->next = dip->prev = AUDIO_MIXER_LAST;
657 strcpy(dip->label.name, AudioNmonitor);
658 break;
659
660 case WSS_RECORD_CLASS: /* record source class */
661 dip->type = AUDIO_MIXER_CLASS;
662 dip->mixer_class = WSS_RECORD_CLASS;
663 dip->next = dip->prev = AUDIO_MIXER_LAST;
664 strcpy(dip->label.name, AudioNrecord);
665 break;
666
667 case WSS_MIC_IN_MUTE:
668 dip->mixer_class = WSS_INPUT_CLASS;
669 dip->type = AUDIO_MIXER_ENUM;
670 dip->prev = WSS_MIC_IN_LVL;
671 dip->next = AUDIO_MIXER_LAST;
672 goto mute;
673
674 case WSS_LINE_IN_MUTE:
675 dip->mixer_class = WSS_INPUT_CLASS;
676 dip->type = AUDIO_MIXER_ENUM;
677 dip->prev = WSS_LINE_IN_LVL;
678 dip->next = AUDIO_MIXER_LAST;
679 goto mute;
680
681 case WSS_DAC_MUTE:
682 dip->mixer_class = WSS_INPUT_CLASS;
683 dip->type = AUDIO_MIXER_ENUM;
684 dip->prev = WSS_DAC_LVL;
685 dip->next = AUDIO_MIXER_LAST;
686 mute:
687 strcpy(dip->label.name, AudioNmute);
688 dip->un.e.num_mem = 2;
689 strcpy(dip->un.e.member[0].label.name, AudioNoff);
690 dip->un.e.member[0].ord = 0;
691 strcpy(dip->un.e.member[1].label.name, AudioNon);
692 dip->un.e.member[1].ord = 1;
693 break;
694
695 case WSS_RECORD_SOURCE:
696 dip->mixer_class = WSS_RECORD_CLASS;
697 dip->type = AUDIO_MIXER_ENUM;
698 dip->prev = WSS_REC_LVL;
699 dip->next = AUDIO_MIXER_LAST;
700 strcpy(dip->label.name, AudioNsource);
701 dip->un.e.num_mem = 3;
702 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
703 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
704 strcpy(dip->un.e.member[1].label.name, AudioNcd);
705 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
706 strcpy(dip->un.e.member[2].label.name, AudioNdac);
707 dip->un.e.member[2].ord = WSS_DAC_LVL;
708 break;
709
710 default:
711 return ENXIO;
712 /*NOTREACHED*/
713 }
714 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
715
716 return 0;
717 }
718