wss.c revision 1.5 1 /* $NetBSD: wss.c,v 1.5 1995/05/08 22:02:32 brezak 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 #include <i386/isa/icu.h> /* XXX BROKEN; WHY? */
56
57 #include <dev/isa/ad1848var.h>
58 #include <dev/isa/ad1848reg.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 #define DEBUG /*XXX*/
81 #ifdef DEBUG
82 #define DPRINTF(x) if (wssdebug) printf x
83 int wssdebug = 0;
84 #else
85 #define DPRINTF(x)
86 #endif
87
88 struct wss_softc {
89 struct device sc_dev; /* base device */
90 struct isadev sc_id; /* ISA device */
91 void *sc_ih; /* interrupt vectoring */
92
93 struct ad1848_softc sc_ad1848;
94 #define wss_iobase sc_ad1848.sc_iobase
95 #define wss_irq sc_ad1848.sc_irq
96 #define wss_drq sc_ad1848.sc_drq
97
98 int mic_mute, cd_mute, dac_mute;
99 };
100
101 struct audio_device wss_device = {
102 "wss,ad1848",
103 "",
104 "WSS"
105 };
106
107 int wssprobe();
108 void wssattach();
109 int wssopen __P((dev_t, int));
110
111 int wss_getdev __P((void *, struct audio_device *));
112 int wss_setfd __P((void *, int));
113
114 int wss_set_out_port __P((void *, int));
115 int wss_get_out_port __P((void *));
116 int wss_set_in_port __P((void *, int));
117 int wss_get_in_port __P((void *));
118 int wss_mixer_set_port __P((void *, mixer_ctrl_t *));
119 int wss_mixer_get_port __P((void *, mixer_ctrl_t *));
120 int wss_query_devinfo __P((void *, mixer_devinfo_t *));
121
122 /*
123 * Define our interface to the higher level audio driver.
124 */
125
126 struct audio_hw_if wss_hw_if = {
127 wssopen,
128 ad1848_close,
129 NULL,
130 ad1848_set_in_sr,
131 ad1848_get_in_sr,
132 ad1848_set_out_sr,
133 ad1848_get_out_sr,
134 ad1848_query_encoding,
135 ad1848_set_encoding,
136 ad1848_get_encoding,
137 ad1848_set_precision,
138 ad1848_get_precision,
139 ad1848_set_channels,
140 ad1848_get_channels,
141 ad1848_round_blocksize,
142 wss_set_out_port,
143 wss_get_out_port,
144 wss_set_in_port,
145 wss_get_in_port,
146 ad1848_commit_settings,
147 ad1848_get_silence,
148 NULL,
149 NULL,
150 ad1848_dma_output,
151 ad1848_dma_input,
152 ad1848_halt_out_dma,
153 ad1848_halt_in_dma,
154 ad1848_cont_out_dma,
155 ad1848_cont_in_dma,
156 NULL,
157 wss_getdev,
158 wss_setfd,
159 wss_mixer_set_port,
160 wss_mixer_get_port,
161 wss_query_devinfo,
162 0, /* not full-duplex */
163 0
164 };
165
166 #ifndef NEWCONFIG
167 #define at_dma(flags, ptr, cc, chan) isa_dmastart(flags, ptr, cc, chan)
168 #endif
169
170 struct cfdriver wsscd = {
171 NULL, "wss", wssprobe, wssattach, DV_DULL, sizeof(struct wss_softc)
172 };
173
174 /*
175 * Probe for the Microsoft Sound System hardware.
176 */
177 int
178 wssprobe(parent, self, aux)
179 struct device *parent, *self;
180 void *aux;
181 {
182 register struct wss_softc *sc = (void *)self;
183 register struct isa_attach_args *ia = aux;
184 register u_short 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 char bits;
190
191 if (!WSS_BASE_VALID(ia->ia_iobase)) {
192 printf("wss: configured iobase %d invalid\n", ia->ia_iobase);
193 return 0;
194 }
195
196 sc->wss_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 #ifdef NEWCONFIG
203 /*
204 * If the IRQ wasn't compiled in, auto-detect it.
205 */
206 if (ia->ia_irq == IRQUNK) {
207 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848);
208 if (!WSS_IRQ_VALID(ia->ia_irq)) {
209 printf("wss: couldn't auto-detect interrupt");
210 return 0;
211 }
212 }
213 else
214 #endif
215 ia->ia_iosize = WSS_NPORT;
216
217 /* Setup WSS interrupt and DMA */
218 if ((bits = interrupt_bits[sc->wss_irq]) == -1) {
219 printf("wss: invalid interrupt configuration (irq=%d)\n", sc->wss_irq);
220 return 0;
221 }
222
223 #if 0
224 /* XXX Dual-DMA */
225 outb(sc->wss_iobase+WSS_CONFIG, (bits | 0x40));
226 if ((inb(sc->wss_iobase+WSS_STATUS) & 0x40) == 0)
227 printf("wss: IRQ?\n");
228 #endif
229 outb(sc->wss_iobase+WSS_CONFIG, (bits | dma_bits[sc->wss_drq]));
230
231 return 1;
232 }
233
234 /*
235 * Attach hardware to driver, attach hardware driver to audio
236 * pseudo-device driver .
237 */
238 void
239 wssattach(parent, self, aux)
240 struct device *parent, *self;
241 void *aux;
242 {
243 register struct wss_softc *sc = (struct wss_softc *)self;
244 struct isa_attach_args *ia = (struct isa_attach_args *)aux;
245 register u_short iobase = ia->ia_iobase;
246
247 sc->wss_iobase = iobase;
248 sc->wss_drq = ia->ia_drq;
249
250 #ifdef NEWCONFIG
251 isa_establish(&sc->sc_id, &sc->sc_dev);
252 #endif
253 sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE, ISA_IPL_BIO,
254 ad1848_intr, &sc->sc_ad1848);
255
256 ad1848_attach(&sc->sc_ad1848);
257
258 printf(" (vers %d)", inb(sc->wss_iobase+WSS_STATUS) & 0x1f);
259 printf("\n");
260
261 sc->sc_ad1848.parent = sc;
262
263 if (audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848) != 0)
264 printf("wss: could not attach to audio pseudo-device driver\n");
265 }
266
267 static int
268 wss_to_vol(cp, vol)
269 mixer_ctrl_t *cp;
270 struct ad1848_volume *vol;
271 {
272 if (cp->un.value.num_channels == 1) {
273 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
274 return(1);
275 }
276 else if (cp->un.value.num_channels == 2) {
277 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
278 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
279 return(1);
280 }
281 return(0);
282 }
283
284 static int
285 wss_from_vol(cp, vol)
286 mixer_ctrl_t *cp;
287 struct ad1848_volume *vol;
288 {
289 if (cp->un.value.num_channels == 1) {
290 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
291 return(1);
292 }
293 else if (cp->un.value.num_channels == 2) {
294 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
295 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
296 return(1);
297 }
298 return(0);
299 }
300
301 int
302 wssopen(dev, flags)
303 dev_t dev;
304 int flags;
305 {
306 struct wss_softc *sc;
307 int unit = AUDIOUNIT(dev);
308
309 if (unit >= wsscd.cd_ndevs)
310 return ENODEV;
311
312 sc = wsscd.cd_devs[unit];
313 if (!sc)
314 return ENXIO;
315
316 return ad1848_open(&sc->sc_ad1848, dev, flags);
317 }
318
319 int
320 wss_getdev(addr, retp)
321 void *addr;
322 struct audio_device *retp;
323 {
324 *retp = wss_device;
325 return 0;
326 }
327
328 int
329 wss_setfd(addr, flag)
330 void *addr;
331 int flag;
332 {
333 /* Can't do full-duplex */
334 return(ENOTTY);
335 }
336
337
338 int
339 wss_set_out_port(addr, port)
340 void *addr;
341 int port;
342 {
343 DPRINTF(("wss_set_out_port:\n"));
344 return(EINVAL);
345 }
346
347 int
348 wss_get_out_port(addr)
349 void *addr;
350 {
351 DPRINTF(("wss_get_out_port:\n"));
352 return(EINVAL);
353 }
354
355 int
356 wss_set_in_port(addr, port)
357 void *addr;
358 int port;
359 {
360 register struct ad1848_softc *ac = addr;
361 register struct wss_softc *sc = ac->parent;
362
363 DPRINTF(("wss_set_in_port: %d\n", port));
364
365 switch(port) {
366 case WSS_MIC_IN_LVL:
367 port = MIC_IN_PORT;
368 break;
369 case WSS_LINE_IN_LVL:
370 port = LINE_IN_PORT;
371 break;
372 case WSS_DAC_LVL:
373 port = DAC_IN_PORT;
374 break;
375 default:
376 return(EINVAL);
377 /*NOTREACHED*/
378 }
379
380 return(ad1848_set_rec_port(ac, port));
381 }
382
383 int
384 wss_get_in_port(addr)
385 void *addr;
386 {
387 register struct ad1848_softc *ac = addr;
388 register struct wss_softc *sc = ac->parent;
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 u_char eq;
417 int error = EINVAL;
418
419 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
420
421 switch (cp->dev) {
422 case WSS_MIC_IN_LVL: /* Microphone */
423 if (cp->type == AUDIO_MIXER_VALUE) {
424 if (wss_to_vol(cp, &vol))
425 error = ad1848_set_aux2_gain(ac, &vol);
426 }
427 break;
428
429 case WSS_MIC_IN_MUTE: /* Microphone */
430 if (cp->type == AUDIO_MIXER_ENUM) {
431 sc->mic_mute = cp->un.ord;
432 DPRINTF(("mic mute %d\n", cp->un.ord));
433 error = 0;
434 }
435 break;
436
437 case WSS_LINE_IN_LVL: /* linein/CD */
438 if (cp->type == AUDIO_MIXER_VALUE) {
439 if (wss_to_vol(cp, &vol))
440 error = ad1848_set_aux1_gain(ac, &vol);
441 }
442 break;
443
444 case WSS_LINE_IN_MUTE: /* linein/CD */
445 if (cp->type == AUDIO_MIXER_ENUM) {
446 sc->cd_mute = cp->un.ord;
447 DPRINTF(("CD mute %d\n", cp->un.ord));
448 error = 0;
449 }
450 break;
451
452 case WSS_DAC_LVL: /* dac out */
453 if (cp->type == AUDIO_MIXER_VALUE) {
454 if (wss_to_vol(cp, &vol))
455 error = ad1848_set_out_gain(ac, &vol);
456 }
457 break;
458
459 case WSS_DAC_MUTE: /* dac out */
460 if (cp->type == AUDIO_MIXER_ENUM) {
461 sc->dac_mute = cp->un.ord;
462 DPRINTF(("DAC mute %d\n", cp->un.ord));
463 error = 0;
464 }
465 break;
466
467 case WSS_REC_LVL: /* record level */
468 if (cp->type == AUDIO_MIXER_VALUE) {
469 if (wss_to_vol(cp, &vol))
470 error = ad1848_set_rec_gain(ac, &vol);
471 }
472 break;
473
474 case WSS_RECORD_SOURCE:
475 if (cp->type == AUDIO_MIXER_ENUM) {
476 error = ad1848_set_rec_port(ac, cp->un.ord);
477 }
478 break;
479
480 case WSS_MON_LVL:
481 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
482 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
483 error = ad1848_set_mon_gain(ac, &vol);
484 }
485 break;
486
487 default:
488 return ENXIO;
489 /*NOTREACHED*/
490 }
491
492 return 0;
493 }
494
495 int
496 wss_mixer_get_port(addr, cp)
497 void *addr;
498 mixer_ctrl_t *cp;
499 {
500 register struct ad1848_softc *ac = addr;
501 register struct wss_softc *sc = ac->parent;
502 struct ad1848_volume vol;
503 u_char eq;
504 int error = EINVAL;
505
506 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev));
507
508 switch (cp->dev) {
509 case WSS_MIC_IN_LVL: /* Microphone */
510 if (cp->type == AUDIO_MIXER_VALUE) {
511 error = ad1848_get_aux2_gain(ac, &vol);
512 if (!error)
513 wss_from_vol(cp, &vol);
514 }
515 break;
516
517 case WSS_MIC_IN_MUTE:
518 if (cp->type == AUDIO_MIXER_ENUM) {
519 cp->un.ord = sc->mic_mute;
520 error = 0;
521 }
522 break;
523
524 case WSS_LINE_IN_LVL: /* linein/CD */
525 if (cp->type == AUDIO_MIXER_VALUE) {
526 error = ad1848_get_aux1_gain(ac, &vol);
527 if (!error)
528 wss_from_vol(cp, &vol);
529 }
530 break;
531
532 case WSS_LINE_IN_MUTE:
533 if (cp->type == AUDIO_MIXER_ENUM) {
534 cp->un.ord = sc->cd_mute;
535 error = 0;
536 }
537 break;
538
539 case WSS_DAC_LVL: /* dac out */
540 if (cp->type == AUDIO_MIXER_VALUE) {
541 error = ad1848_get_out_gain(ac, &vol);
542 if (!error)
543 wss_from_vol(cp, &vol);
544 }
545 break;
546
547 case WSS_DAC_MUTE:
548 if (cp->type == AUDIO_MIXER_ENUM) {
549 cp->un.ord = sc->dac_mute;
550 error = 0;
551 }
552 break;
553
554 case WSS_REC_LVL: /* record level */
555 if (cp->type == AUDIO_MIXER_VALUE) {
556 error = ad1848_get_rec_gain(ac, &vol);
557 if (!error)
558 wss_from_vol(cp, &vol);
559 }
560 break;
561
562 case WSS_RECORD_SOURCE:
563 if (cp->type == AUDIO_MIXER_ENUM) {
564 cp->un.ord = ad1848_get_rec_port(ac);
565 error = 0;
566 }
567 break;
568
569 case WSS_MON_LVL: /* monitor level */
570 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
571 error = ad1848_get_mon_gain(ac, &vol);
572 if (!error)
573 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left;
574 }
575 break;
576
577 default:
578 error = ENXIO;
579 break;
580 }
581
582 return(error);
583 }
584
585 int
586 wss_query_devinfo(addr, dip)
587 void *addr;
588 register mixer_devinfo_t *dip;
589 {
590 register struct ad1848_softc *ac = addr;
591 register struct wss_softc *sc = ac->parent;
592
593 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index));
594
595 switch(dip->index) {
596 case WSS_MIC_IN_LVL: /* Microphone */
597 dip->type = AUDIO_MIXER_VALUE;
598 dip->mixer_class = WSS_INPUT_CLASS;
599 dip->prev = AUDIO_MIXER_LAST;
600 dip->next = WSS_MIC_IN_MUTE;
601 strcpy(dip->label.name, AudioNmicrophone);
602 dip->un.v.num_channels = 2;
603 strcpy(dip->un.v.units.name, AudioNvolume);
604 break;
605
606 case WSS_LINE_IN_LVL: /* line/CD */
607 dip->type = AUDIO_MIXER_VALUE;
608 dip->mixer_class = WSS_INPUT_CLASS;
609 dip->prev = AUDIO_MIXER_LAST;
610 dip->next = WSS_LINE_IN_MUTE;
611 strcpy(dip->label.name, AudioNcd);
612 dip->un.v.num_channels = 2;
613 strcpy(dip->un.v.units.name, AudioNvolume);
614 break;
615
616 case WSS_DAC_LVL: /* dacout */
617 dip->type = AUDIO_MIXER_VALUE;
618 dip->mixer_class = WSS_INPUT_CLASS;
619 dip->prev = AUDIO_MIXER_LAST;
620 dip->next = WSS_DAC_MUTE;
621 strcpy(dip->label.name, AudioNdac);
622 dip->un.v.num_channels = 2;
623 strcpy(dip->un.v.units.name, AudioNvolume);
624 break;
625
626 case WSS_REC_LVL: /* record level */
627 dip->type = AUDIO_MIXER_VALUE;
628 dip->mixer_class = WSS_RECORD_CLASS;
629 dip->prev = AUDIO_MIXER_LAST;
630 dip->next = WSS_RECORD_SOURCE;
631 strcpy(dip->label.name, AudioNrecord);
632 dip->un.v.num_channels = 2;
633 strcpy(dip->un.v.units.name, AudioNvolume);
634 break;
635
636 case WSS_MON_LVL: /* monitor level */
637 dip->type = AUDIO_MIXER_VALUE;
638 dip->mixer_class = WSS_MONITOR_CLASS;
639 dip->next = dip->prev = AUDIO_MIXER_LAST;
640 strcpy(dip->label.name, AudioNmonitor);
641 dip->un.v.num_channels = 1;
642 strcpy(dip->un.v.units.name, AudioNvolume);
643 break;
644
645 case WSS_INPUT_CLASS: /* input class descriptor */
646 dip->type = AUDIO_MIXER_CLASS;
647 dip->mixer_class = WSS_INPUT_CLASS;
648 dip->next = dip->prev = AUDIO_MIXER_LAST;
649 strcpy(dip->label.name, AudioCInputs);
650 break;
651
652 case WSS_MONITOR_CLASS: /* monitor class descriptor */
653 dip->type = AUDIO_MIXER_CLASS;
654 dip->mixer_class = WSS_MONITOR_CLASS;
655 dip->next = dip->prev = AUDIO_MIXER_LAST;
656 strcpy(dip->label.name, AudioNmonitor);
657 break;
658
659 case WSS_RECORD_CLASS: /* record source class */
660 dip->type = AUDIO_MIXER_CLASS;
661 dip->mixer_class = WSS_RECORD_CLASS;
662 dip->next = dip->prev = AUDIO_MIXER_LAST;
663 strcpy(dip->label.name, AudioNrecord);
664 break;
665
666 case WSS_MIC_IN_MUTE:
667 dip->mixer_class = WSS_INPUT_CLASS;
668 dip->type = AUDIO_MIXER_ENUM;
669 dip->prev = WSS_MIC_IN_LVL;
670 dip->next = AUDIO_MIXER_LAST;
671 goto mute;
672
673 case WSS_LINE_IN_MUTE:
674 dip->mixer_class = WSS_INPUT_CLASS;
675 dip->type = AUDIO_MIXER_ENUM;
676 dip->prev = WSS_LINE_IN_LVL;
677 dip->next = AUDIO_MIXER_LAST;
678 goto mute;
679
680 case WSS_DAC_MUTE:
681 dip->mixer_class = WSS_INPUT_CLASS;
682 dip->type = AUDIO_MIXER_ENUM;
683 dip->prev = WSS_DAC_LVL;
684 dip->next = AUDIO_MIXER_LAST;
685 mute:
686 strcpy(dip->label.name, AudioNmute);
687 dip->un.e.num_mem = 2;
688 strcpy(dip->un.e.member[0].label.name, AudioNoff);
689 dip->un.e.member[0].ord = 0;
690 strcpy(dip->un.e.member[1].label.name, AudioNon);
691 dip->un.e.member[1].ord = 1;
692 break;
693
694 case WSS_RECORD_SOURCE:
695 dip->mixer_class = WSS_RECORD_CLASS;
696 dip->type = AUDIO_MIXER_ENUM;
697 dip->prev = WSS_REC_LVL;
698 dip->next = AUDIO_MIXER_LAST;
699 strcpy(dip->label.name, AudioNsource);
700 dip->un.e.num_mem = 3;
701 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
702 dip->un.e.member[0].ord = WSS_MIC_IN_LVL;
703 strcpy(dip->un.e.member[1].label.name, AudioNcd);
704 dip->un.e.member[1].ord = WSS_LINE_IN_LVL;
705 strcpy(dip->un.e.member[2].label.name, AudioNdac);
706 dip->un.e.member[2].ord = WSS_DAC_LVL;
707 break;
708
709 default:
710 return ENXIO;
711 /*NOTREACHED*/
712 }
713 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
714
715 return 0;
716 }
717