wss.c revision 1.11 1 /* $NetBSD: wss.c,v 1.11 1996/04/11 22:30:46 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 */
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_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
257 ad1848_intr, &sc->sc_ad1848);
258
259 ad1848_attach(&sc->sc_ad1848);
260
261 printf(" (vers %d)", inb(iobase+WSS_STATUS) & WSS_VERSMASK);
262 printf("\n");
263
264 sc->sc_ad1848.parent = sc;
265
266 if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0)
267 printf("wss: could not attach to audio pseudo-device driver (%d)\n", err);
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 >= wss_cd.cd_ndevs)
313 return ENODEV;
314
315 sc = wss_cd.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