wss.c revision 1.2 1 /* $NetBSD: wss.c,v 1.2 1995/03/25 00:01:07 mycroft 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.2 1995/03/25 00:01:07 mycroft 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 <i386/isa/isavar.h>
55 #include <i386/isa/dmavar.h>
56 #include <i386/isa/icu.h>
57
58 #include <i386/isa/ad1848var.h>
59 #include <i386/isa/ad1848reg.h>
60 #include <i386/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 struct intrhand 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.ih_fun = ad1848_intr;
255 sc->sc_ih.ih_arg = &sc->sc_ad1848;
256 sc->sc_ih.ih_level = IPL_BIO;
257 intr_establish(ia->ia_irq, IST_EDGE, &sc->sc_ih);
258
259 ad1848_attach(&sc->sc_ad1848);
260
261 printf(" (vers %d)", inb(sc->wss_iobase+WSS_STATUS) & 0x1f);
262 printf("\n");
263
264 sc->sc_ad1848.parent = sc;
265
266 if (audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848) != 0)
267 printf("wss: could not attach to audio pseudo-device driver\n");
268 }
269
270 static int
271 wss_to_vol(cp, vol)
272 mixer_ctrl_t *cp;
273 struct ad1848_volume *vol;
274 {
275 if (cp->un.value.num_channels == 1) {
276 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
277 return(1);
278 }
279 else if (cp->un.value.num_channels == 2) {
280 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
281 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
282 return(1);
283 }
284 return(0);
285 }
286
287 static int
288 wss_from_vol(cp, vol)
289 mixer_ctrl_t *cp;
290 struct ad1848_volume *vol;
291 {
292 if (cp->un.value.num_channels == 1) {
293 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
294 return(1);
295 }
296 else if (cp->un.value.num_channels == 2) {
297 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
298 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
299 return(1);
300 }
301 return(0);
302 }
303
304 int
305 wssopen(dev, flags)
306 dev_t dev;
307 int flags;
308 {
309 struct wss_softc *sc;
310 int unit = AUDIOUNIT(dev);
311
312 if (unit >= wsscd.cd_ndevs)
313 return ENODEV;
314
315 sc = wsscd.cd_devs[unit];
316 if (!sc)
317 return ENXIO;
318
319 return ad1848_open(&sc->sc_ad1848, dev, flags);
320 }
321
322 int
323 wss_getdev(addr, retp)
324 void *addr;
325 struct audio_device *retp;
326 {
327 *retp = wss_device;
328 return 0;
329 }
330
331 int
332 wss_setfd(addr, flag)
333 void *addr;
334 int flag;
335 {
336 /* Can't do full-duplex */
337 return(ENOTTY);
338 }
339
340
341 int
342 wss_set_out_port(addr, port)
343 void *addr;
344 int port;
345 {
346 DPRINTF(("wss_set_out_port:\n"));
347 return(EINVAL);
348 }
349
350 int
351 wss_get_out_port(addr)
352 void *addr;
353 {
354 DPRINTF(("wss_get_out_port:\n"));
355 return(EINVAL);
356 }
357
358 int
359 wss_set_in_port(addr, port)
360 void *addr;
361 int port;
362 {
363 register struct ad1848_softc *ac = addr;
364 register struct wss_softc *sc = ac->parent;
365
366 DPRINTF(("wss_set_in_port: %d\n", port));
367
368 switch(port) {
369 case WSS_MIC_IN_LVL:
370 port = MIC_IN_PORT;
371 break;
372 case WSS_LINE_IN_LVL:
373 port = LINE_IN_PORT;
374 break;
375 case WSS_DAC_LVL:
376 port = DAC_IN_PORT;
377 break;
378 default:
379 return(EINVAL);
380 /*NOTREACHED*/
381 }
382
383 return(ad1848_set_rec_port(ac, port));
384 }
385
386 int
387 wss_get_in_port(addr)
388 void *addr;
389 {
390 register struct ad1848_softc *ac = addr;
391 register struct wss_softc *sc = ac->parent;
392 int port = WSS_MIC_IN_LVL;
393
394 switch(ad1848_get_rec_port(ac)) {
395 case MIC_IN_PORT:
396 port = WSS_MIC_IN_LVL;
397 break;
398 case LINE_IN_PORT:
399 port = WSS_LINE_IN_LVL;
400 break;
401 case DAC_IN_PORT:
402 port = WSS_DAC_LVL;
403 break;
404 }
405
406 DPRINTF(("wss_get_in_port: %d\n", port));
407
408 return(port);
409 }
410
411 int
412 wss_mixer_set_port(addr, cp)
413 void *addr;
414 mixer_ctrl_t *cp;
415 {
416 register struct ad1848_softc *ac = addr;
417 register struct wss_softc *sc = ac->parent;
418 struct ad1848_volume vol;
419 u_char eq;
420 int error = EINVAL;
421
422 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
423
424 switch (cp->dev) {
425 case WSS_MIC_IN_LVL: /* Microphone */
426 if (cp->type == AUDIO_MIXER_VALUE) {
427 if (wss_to_vol(cp, &vol))
428 error = ad1848_set_aux2_gain(ac, &vol);
429 }
430 break;
431
432 case WSS_MIC_IN_MUTE: /* Microphone */
433 if (cp->type == AUDIO_MIXER_ENUM) {
434 sc->mic_mute = cp->un.ord;
435 DPRINTF(("mic mute %d\n", cp->un.ord));
436 error = 0;
437 }
438 break;
439
440 case WSS_LINE_IN_LVL: /* linein/CD */
441 if (cp->type == AUDIO_MIXER_VALUE) {
442 if (wss_to_vol(cp, &vol))
443 error = ad1848_set_aux1_gain(ac, &vol);
444 }
445 break;
446
447 case WSS_LINE_IN_MUTE: /* linein/CD */
448 if (cp->type == AUDIO_MIXER_ENUM) {
449 sc->cd_mute = cp->un.ord;
450 DPRINTF(("CD mute %d\n", cp->un.ord));
451 error = 0;
452 }
453 break;
454
455 case WSS_DAC_LVL: /* dac out */
456 if (cp->type == AUDIO_MIXER_VALUE) {
457 if (wss_to_vol(cp, &vol))
458 error = ad1848_set_out_gain(ac, &vol);
459 }
460 break;
461
462 case WSS_DAC_MUTE: /* dac out */
463 if (cp->type == AUDIO_MIXER_ENUM) {
464 sc->dac_mute = cp->un.ord;
465 DPRINTF(("DAC mute %d\n", cp->un.ord));
466 error = 0;
467 }
468 break;
469
470 case WSS_REC_LVL: /* record level */
471 if (cp->type == AUDIO_MIXER_VALUE) {
472 if (wss_to_vol(cp, &vol))
473 error = ad1848_set_rec_gain(ac, &vol);
474 }
475 break;
476
477 case WSS_RECORD_SOURCE:
478 if (cp->type == AUDIO_MIXER_ENUM) {
479 error = ad1848_set_rec_port(ac, cp->un.ord);
480 }
481 break;
482
483 case WSS_MON_LVL:
484 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
485 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
486 error = ad1848_set_mon_gain(ac, &vol);
487 }
488 break;
489
490 default:
491 return ENXIO;
492 /*NOTREACHED*/
493 }
494
495 return 0;
496 }
497
498 int
499 wss_mixer_get_port(addr, cp)
500 void *addr;
501 mixer_ctrl_t *cp;
502 {
503 register struct ad1848_softc *ac = addr;
504 register struct wss_softc *sc = ac->parent;
505 struct ad1848_volume vol;
506 u_char eq;
507 int error = EINVAL;
508
509 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
510
511 switch (cp->dev) {
512 case WSS_MIC_IN_LVL: /* Microphone */
513 if (cp->type == AUDIO_MIXER_VALUE) {
514 error = ad1848_get_aux2_gain(ac, &vol);
515 if (!error)
516 wss_from_vol(cp, &vol);
517 }
518 break;
519
520 case WSS_MIC_IN_MUTE:
521 if (cp->type == AUDIO_MIXER_ENUM) {
522 cp->un.ord = sc->mic_mute;
523 error = 0;
524 }
525 break;
526
527 case WSS_LINE_IN_LVL: /* linein/CD */
528 if (cp->type == AUDIO_MIXER_VALUE) {
529 error = ad1848_get_aux1_gain(ac, &vol);
530 if (!error)
531 wss_from_vol(cp, &vol);
532 }
533 break;
534
535 case WSS_LINE_IN_MUTE:
536 if (cp->type == AUDIO_MIXER_ENUM) {
537 cp->un.ord = sc->cd_mute;
538 error = 0;
539 }
540 break;
541
542 case WSS_DAC_LVL: /* dac out */
543 if (cp->type == AUDIO_MIXER_VALUE) {
544 error = ad1848_get_out_gain(ac, &vol);
545 if (!error)
546 wss_from_vol(cp, &vol);
547 }
548 break;
549
550 case WSS_DAC_MUTE:
551 if (cp->type == AUDIO_MIXER_ENUM) {
552 cp->un.ord = sc->dac_mute;
553 error = 0;
554 }
555 break;
556
557 case WSS_REC_LVL: /* record level */
558 if (cp->type == AUDIO_MIXER_VALUE) {
559 error = ad1848_get_rec_gain(ac, &vol);
560 if (!error)
561 wss_from_vol(cp, &vol);
562 }
563 break;
564
565 case WSS_RECORD_SOURCE:
566 if (cp->type == AUDIO_MIXER_ENUM) {
567 cp->un.ord = ad1848_get_rec_port(ac);
568 error = 0;
569 }
570 break;
571
572 case WSS_MON_LVL: /* monitor level */
573 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
574 error = ad1848_get_mon_gain(ac, &vol);
575 if (!error)
576 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
577 }
578 break;
579
580 default:
581 error = ENXIO;
582 break;
583 }
584
585 return(error);
586 }
587
588 int
589 wss_query_devinfo(addr, dip)
590 void *addr;
591 register mixer_devinfo_t *dip;
592 {
593 register struct ad1848_softc *ac = addr;
594 register struct wss_softc *sc = ac->parent;
595
596 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
597
598 switch(dip->index) {
599 case WSS_MIC_IN_LVL: /* Microphone */
600 dip->type = AUDIO_MIXER_VALUE;
601 dip->mixer_class = WSS_INPUT_CLASS;
602 dip->prev = AUDIO_MIXER_LAST;
603 dip->next = WSS_MIC_IN_MUTE;
604 strcpy(dip->label.name, AudioNmicrophone);
605 dip->un.v.num_channels = 2;
606 strcpy(dip->un.v.units.name, AudioNvolume);
607 break;
608
609 case WSS_LINE_IN_LVL: /* line/CD */
610 dip->type = AUDIO_MIXER_VALUE;
611 dip->mixer_class = WSS_INPUT_CLASS;
612 dip->prev = AUDIO_MIXER_LAST;
613 dip->next = WSS_LINE_IN_MUTE;
614 strcpy(dip->label.name, AudioNcd);
615 dip->un.v.num_channels = 2;
616 strcpy(dip->un.v.units.name, AudioNvolume);
617 break;
618
619 case WSS_DAC_LVL: /* dacout */
620 dip->type = AUDIO_MIXER_VALUE;
621 dip->mixer_class = WSS_INPUT_CLASS;
622 dip->prev = AUDIO_MIXER_LAST;
623 dip->next = WSS_DAC_MUTE;
624 strcpy(dip->label.name, AudioNdac);
625 dip->un.v.num_channels = 2;
626 strcpy(dip->un.v.units.name, AudioNvolume);
627 break;
628
629 case WSS_REC_LVL: /* record level */
630 dip->type = AUDIO_MIXER_VALUE;
631 dip->mixer_class = WSS_RECORD_CLASS;
632 dip->prev = AUDIO_MIXER_LAST;
633 dip->next = WSS_RECORD_SOURCE;
634 strcpy(dip->label.name, AudioNrecord);
635 dip->un.v.num_channels = 2;
636 strcpy(dip->un.v.units.name, AudioNvolume);
637 break;
638
639 case WSS_MON_LVL: /* monitor level */
640 dip->type = AUDIO_MIXER_VALUE;
641 dip->mixer_class = WSS_MONITOR_CLASS;
642 dip->next = dip->prev = AUDIO_MIXER_LAST;
643 strcpy(dip->label.name, AudioNmonitor);
644 dip->un.v.num_channels = 1;
645 strcpy(dip->un.v.units.name, AudioNvolume);
646 break;
647
648 case WSS_INPUT_CLASS: /* input class descriptor */
649 dip->type = AUDIO_MIXER_CLASS;
650 dip->mixer_class = WSS_INPUT_CLASS;
651 dip->next = dip->prev = AUDIO_MIXER_LAST;
652 strcpy(dip->label.name, AudioCInputs);
653 break;
654
655 case WSS_MONITOR_CLASS: /* monitor class descriptor */
656 dip->type = AUDIO_MIXER_CLASS;
657 dip->mixer_class = WSS_MONITOR_CLASS;
658 dip->next = dip->prev = AUDIO_MIXER_LAST;
659 strcpy(dip->label.name, AudioNmonitor);
660 break;
661
662 case WSS_RECORD_CLASS: /* record source class */
663 dip->type = AUDIO_MIXER_CLASS;
664 dip->mixer_class = WSS_RECORD_CLASS;
665 dip->next = dip->prev = AUDIO_MIXER_LAST;
666 strcpy(dip->label.name, AudioNrecord);
667 break;
668
669 case WSS_MIC_IN_MUTE:
670 dip->mixer_class = WSS_INPUT_CLASS;
671 dip->type = AUDIO_MIXER_ENUM;
672 dip->prev = WSS_MIC_IN_LVL;
673 dip->next = AUDIO_MIXER_LAST;
674 goto mute;
675
676 case WSS_LINE_IN_MUTE:
677 dip->mixer_class = WSS_INPUT_CLASS;
678 dip->type = AUDIO_MIXER_ENUM;
679 dip->prev = WSS_LINE_IN_LVL;
680 dip->next = AUDIO_MIXER_LAST;
681 goto mute;
682
683 case WSS_DAC_MUTE:
684 dip->mixer_class = WSS_INPUT_CLASS;
685 dip->type = AUDIO_MIXER_ENUM;
686 dip->prev = WSS_DAC_LVL;
687 dip->next = AUDIO_MIXER_LAST;
688 mute:
689 strcpy(dip->label.name, AudioNmute);
690 dip->un.e.num_mem = 2;
691 strcpy(dip->un.e.member[0].label.name, AudioNoff);
692 dip->un.e.member[0].ord = 0;
693 strcpy(dip->un.e.member[1].label.name, AudioNon);
694 dip->un.e.member[1].ord = 1;
695 break;
696
697 case WSS_RECORD_SOURCE:
698 dip->mixer_class = WSS_RECORD_CLASS;
699 dip->type = AUDIO_MIXER_ENUM;
700 dip->prev = WSS_REC_LVL;
701 dip->next = AUDIO_MIXER_LAST;
702 strcpy(dip->label.name, AudioNsource);
703 dip->un.e.num_mem = 3;
704 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
705 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
706 strcpy(dip->un.e.member[1].label.name, AudioNcd);
707 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
708 strcpy(dip->un.e.member[2].label.name, AudioNdac);
709 dip->un.e.member[2].ord = WSS_DAC_LVL;
710 break;
711
712 default:
713 return ENXIO;
714 /*NOTREACHED*/
715 }
716 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
717
718 return 0;
719 }
720