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