xref: /netbsd-src/sys/dev/ic/am7930.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: am7930.c,v 1.50 2007/10/19 11:59:46 ad Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Rolf Grossmann
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Rolf Grossmann.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Front-end attachment independent layer for AMD 79c30
35  * audio driver.  No ISDN support.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.50 2007/10/19 11:59:46 ad Exp $");
40 
41 #include "audio.h"
42 #if NAUDIO > 0
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/device.h>
49 #include <sys/proc.h>
50 
51 #include <sys/bus.h>
52 #include <machine/autoconf.h>
53 #include <sys/cpu.h>
54 
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
57 
58 #include <dev/ic/am7930reg.h>
59 #include <dev/ic/am7930var.h>
60 
61 #ifdef AUDIO_DEBUG
62 int     am7930debug = 0;
63 #define DPRINTF(x)      if (am7930debug) printf x
64 #else
65 #define DPRINTF(x)
66 #endif
67 
68 
69 /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
70 
71 /*
72  * gx, gr & stg gains.  this table must contain 256 elements with
73  * the 0th being "infinity" (the magic value 9008).  The remaining
74  * elements match sun's gain curve (but with higher resolution):
75  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
76  */
77 static const uint16_t gx_coeff[256] = {
78 	0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
79 	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
80 	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
81 	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
82 	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
83 	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
84 	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
85 	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
86 	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
87 	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
88 	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
89 	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
90 	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
91 	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
92 	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
93 	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
94 	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
95 	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
96 	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
97 	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
98 	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
99 	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
100 	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
101 	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
102 	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
103 	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
104 	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
105 	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
106 	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
107 	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
108 	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
109 	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
110 };
111 
112 /*
113  * second stage play gain.
114  */
115 static const uint16_t ger_coeff[] = {
116 	0x431f, /* 5. dB */
117 	0x331f, /* 5.5 dB */
118 	0x40dd, /* 6. dB */
119 	0x11dd, /* 6.5 dB */
120 	0x440f, /* 7. dB */
121 	0x411f, /* 7.5 dB */
122 	0x311f, /* 8. dB */
123 	0x5520, /* 8.5 dB */
124 	0x10dd, /* 9. dB */
125 	0x4211, /* 9.5 dB */
126 	0x410f, /* 10. dB */
127 	0x111f, /* 10.5 dB */
128 	0x600b, /* 11. dB */
129 	0x00dd, /* 11.5 dB */
130 	0x4210, /* 12. dB */
131 	0x110f, /* 13. dB */
132 	0x7200, /* 14. dB */
133 	0x2110, /* 15. dB */
134 	0x2200, /* 15.9 dB */
135 	0x000b, /* 16.9 dB */
136 	0x000f  /* 18. dB */
137 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
138 };
139 
140 
141 /*
142  * Reset chip and set boot-time softc defaults.
143  */
144 void
145 am7930_init(struct am7930_softc *sc, int flag)
146 {
147 
148 	DPRINTF(("am7930_init()\n"));
149 
150 	/* set boot defaults */
151 	sc->sc_rlevel = 128;
152 	sc->sc_plevel = 128;
153 	sc->sc_mlevel = 0;
154 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
155 	sc->sc_mic_mute = 0;
156 
157 	/* disable sample interrupts */
158 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
159 
160 	/* initialise voice and data, and disable interrupts */
161 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
162 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
163 
164 	if (flag == AUDIOAMD_DMA_MODE) {
165 
166 		/* configure PP for serial (SBP) mode */
167 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
168 
169 		/*
170 		 * Initialise the MUX unit - route the MAP to the PP
171 		 */
172 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
173 			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
174 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
175 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
176 
177 	} else {
178 
179 		/*
180 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
181 		 * through channel Bb.  MCR1 and MCR2 are unused.
182 		 * Setting the INT enable bit in MCR4 will generate an
183 		 * interrupt on each converted audio sample.
184 		 */
185 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
186 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
187 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
188 			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
189 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
190 			AM7930_MCR4_INT_ENABLE);
191 	}
192 
193 }
194 
195 int
196 am7930_open(void *addr, int flags)
197 {
198 	struct am7930_softc *sc;
199 
200 	sc = addr;
201 	DPRINTF(("sa_open: unit %p\n", sc));
202 	sc->sc_glue->onopen(sc);
203 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
204 	return 0;
205 }
206 
207 void
208 am7930_close(void *addr)
209 {
210 	struct am7930_softc *sc;
211 
212 	sc = addr;
213 	DPRINTF(("sa_close: sc=%p\n", sc));
214 	sc->sc_glue->onclose(sc);
215 	DPRINTF(("sa_close: closed.\n"));
216 }
217 
218 /*
219  * XXX should be extended to handle a few of the more common formats.
220  */
221 int
222 am7930_set_params(void *addr, int setmode, int usemode, audio_params_t *p,
223     audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
224 {
225 	audio_params_t hw;
226 	struct am7930_softc *sc;
227 
228 	sc = addr;
229 	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
230 		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
231 			p->encoding != AUDIO_ENCODING_ULAW ||
232 			p->precision != 8 ||
233 			p->channels != 1)
234 				return EINVAL;
235 		p->sample_rate = 8000;
236 		if (sc->sc_glue->output_conv != NULL) {
237 			hw = *p;
238 			hw.encoding = AUDIO_ENCODING_NONE;
239 			hw.precision *= sc->sc_glue->factor;
240 			pfil->append(pfil, sc->sc_glue->output_conv, &hw);
241 		}
242 	}
243 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
244 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
245 			r->encoding != AUDIO_ENCODING_ULAW ||
246 			r->precision != 8 ||
247 			r->channels != 1)
248 				return EINVAL;
249 		r->sample_rate = 8000;
250 		if (sc->sc_glue->input_conv != NULL) {
251 			hw = *r;
252 			hw.encoding = AUDIO_ENCODING_NONE;
253 			hw.precision *= sc->sc_glue->factor;
254 			pfil->append(rfil, sc->sc_glue->input_conv, &hw);
255 		}
256 	}
257 
258 	return 0;
259 }
260 
261 int
262 am7930_query_encoding(void *addr, struct audio_encoding *fp)
263 {
264 	switch (fp->index) {
265 	case 0:
266 		strcpy(fp->name, AudioEmulaw);
267 		fp->encoding = AUDIO_ENCODING_ULAW;
268 		fp->precision = 8;
269 		fp->flags = 0;
270 		break;
271 	default:
272 		return EINVAL;
273 		    /*NOTREACHED*/
274 	}
275 	return 0;
276 }
277 
278 int
279 am7930_round_blocksize(void *addr, int blk,
280     int mode, const audio_params_t *param)
281 {
282 	return blk;
283 }
284 
285 int
286 am7930_commit_settings(void *addr)
287 {
288 	struct am7930_softc *sc;
289 	uint16_t ger, gr, gx, stgr;
290 	uint8_t mmr2, mmr3;
291 	int s, level;
292 
293 	DPRINTF(("sa_commit.\n"));
294 	sc = addr;
295 	gx = gx_coeff[sc->sc_rlevel];
296 	stgr = gx_coeff[sc->sc_mlevel];
297 
298 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
299 	if (level >= 256) {
300 		ger = ger_coeff[level - 256];
301 		gr = gx_coeff[255];
302 	} else {
303 		ger = ger_coeff[0];
304 		gr = gx_coeff[level];
305 	}
306 
307 	s = splaudio();
308 
309 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
310 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
311 		mmr2 |= AM7930_MMR2_LS;
312 	else
313 		mmr2 &= ~AM7930_MMR2_LS;
314 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
315 
316 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
317 	if (sc->sc_mic_mute)
318 		mmr3 |= AM7930_MMR3_MUTE;
319 	else
320 		mmr3 &= ~AM7930_MMR3_MUTE;
321 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
322 
323 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
324 		AM7930_MMR1_GX | AM7930_MMR1_GER |
325 		AM7930_MMR1_GR | AM7930_MMR1_STG);
326 
327 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
328 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
329 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
330 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
331 
332 	splx(s);
333 
334 	return 0;
335 }
336 
337 int
338 am7930_halt_output(void *addr)
339 {
340 	struct am7930_softc *sc;
341 
342 	sc = addr;
343 	/* XXX only halt, if input is also halted ?? */
344 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
345 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
346 	return 0;
347 }
348 
349 int
350 am7930_halt_input(void *addr)
351 {
352 	struct am7930_softc *sc;
353 
354 	sc = addr;
355 	/* XXX only halt, if output is also halted ?? */
356 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
357 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
358 	return 0;
359 }
360 
361 /*
362  * XXX chip is full-duplex, but really attach-dependent.
363  * For now we know of no half-duplex attachments.
364  */
365 int
366 am7930_get_props(void *addr)
367 {
368 	return AUDIO_PROP_FULLDUPLEX;
369 }
370 
371 /*
372  * Attach-dependent channel set/query
373  */
374 int
375 am7930_set_port(void *addr, mixer_ctrl_t *cp)
376 {
377 	struct am7930_softc *sc;
378 
379 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
380 	sc = addr;
381 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
382 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
383 		cp->dev == AUDIOAMD_MIC_MUTE) {
384 		if (cp->type != AUDIO_MIXER_ENUM)
385 			return EINVAL;
386 	} else if (cp->type != AUDIO_MIXER_VALUE ||
387 	    cp->un.value.num_channels != 1) {
388 		return EINVAL;
389 	}
390 
391 	switch(cp->dev) {
392 	    case AUDIOAMD_MIC_VOL:
393 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
394 		    break;
395 	    case AUDIOAMD_SPEAKER_VOL:
396 	    case AUDIOAMD_HEADPHONES_VOL:
397 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
398 		    break;
399 	    case AUDIOAMD_MONITOR_VOL:
400 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
401 		    break;
402 	    case AUDIOAMD_RECORD_SOURCE:
403 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
404 			    return EINVAL;
405 		    break;
406 	    case AUDIOAMD_MIC_MUTE:
407 		    sc->sc_mic_mute = cp->un.ord;
408 		    break;
409 	    case AUDIOAMD_MONITOR_OUTPUT:
410 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
411 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
412 			    return EINVAL;
413 			sc->sc_out_port = cp->un.ord;
414 		    break;
415 	    default:
416 		    return EINVAL;
417 		    /* NOTREACHED */
418 	}
419 	return 0;
420 }
421 
422 int
423 am7930_get_port(void *addr, mixer_ctrl_t *cp)
424 {
425 	struct am7930_softc *sc;
426 
427 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
428 	sc = addr;
429 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
430 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
431 		cp->dev == AUDIOAMD_MIC_MUTE) {
432 		if (cp->type != AUDIO_MIXER_ENUM)
433 			return EINVAL;
434 	} else if (cp->type != AUDIO_MIXER_VALUE ||
435 		cp->un.value.num_channels != 1) {
436 		return EINVAL;
437 	}
438 
439 	switch(cp->dev) {
440 	    case AUDIOAMD_MIC_VOL:
441 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
442 		    break;
443 	    case AUDIOAMD_SPEAKER_VOL:
444 	    case AUDIOAMD_HEADPHONES_VOL:
445 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
446 		    break;
447 	    case AUDIOAMD_MONITOR_VOL:
448 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
449 		    break;
450 	    case AUDIOAMD_RECORD_SOURCE:
451 		    cp->un.ord = AUDIOAMD_MIC_VOL;
452 		    break;
453 	    case AUDIOAMD_MIC_MUTE:
454 		    cp->un.ord = sc->sc_mic_mute;
455 		    break;
456 	    case AUDIOAMD_MONITOR_OUTPUT:
457 		    cp->un.ord = sc->sc_out_port;
458 		    break;
459 	    default:
460 		    return EINVAL;
461 		    /* NOTREACHED */
462 	}
463 	return 0;
464 }
465 
466 
467 /*
468  * Define mixer control facilities.
469  */
470 int
471 am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
472 {
473 
474 	DPRINTF(("am7930_query_devinfo()\n"));
475 
476 	switch(dip->index) {
477 	case AUDIOAMD_MIC_VOL:
478 		dip->type = AUDIO_MIXER_VALUE;
479 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
480 		dip->prev =  AUDIO_MIXER_LAST;
481 		dip->next = AUDIOAMD_MIC_MUTE;
482 		strcpy(dip->label.name, AudioNmicrophone);
483 		dip->un.v.num_channels = 1;
484 		strcpy(dip->un.v.units.name, AudioNvolume);
485 		break;
486 	case AUDIOAMD_SPEAKER_VOL:
487 		dip->type = AUDIO_MIXER_VALUE;
488 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
489 		dip->prev = dip->next = AUDIO_MIXER_LAST;
490 		strcpy(dip->label.name, AudioNspeaker);
491 		dip->un.v.num_channels = 1;
492 		strcpy(dip->un.v.units.name, AudioNvolume);
493 		break;
494 	case AUDIOAMD_HEADPHONES_VOL:
495 		dip->type = AUDIO_MIXER_VALUE;
496 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
497 		dip->prev = dip->next = AUDIO_MIXER_LAST;
498 		strcpy(dip->label.name, AudioNheadphone);
499 		dip->un.v.num_channels = 1;
500 		strcpy(dip->un.v.units.name, AudioNvolume);
501 		break;
502 	case AUDIOAMD_MONITOR_VOL:
503 		dip->type = AUDIO_MIXER_VALUE;
504 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
505 		dip->prev = dip->next = AUDIO_MIXER_LAST;
506 		strcpy(dip->label.name, AudioNmonitor);
507 		dip->un.v.num_channels = 1;
508 		strcpy(dip->un.v.units.name, AudioNvolume);
509 		break;
510 	case AUDIOAMD_RECORD_SOURCE:
511 		dip->type = AUDIO_MIXER_ENUM;
512 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
513 		dip->next = dip->prev = AUDIO_MIXER_LAST;
514 		strcpy(dip->label.name, AudioNsource);
515 		dip->un.e.num_mem = 1;
516 		strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
517 		dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
518 		break;
519 	case AUDIOAMD_MONITOR_OUTPUT:
520 		dip->type = AUDIO_MIXER_ENUM;
521 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
522 		dip->next = dip->prev = AUDIO_MIXER_LAST;
523 		strcpy(dip->label.name, AudioNoutput);
524 		dip->un.e.num_mem = 2;
525 		strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
526 		dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
527 		strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
528 		dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
529 		break;
530 	case AUDIOAMD_MIC_MUTE:
531 		dip->type = AUDIO_MIXER_ENUM;
532 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
533 		dip->prev =  AUDIOAMD_MIC_VOL;
534 		dip->next = AUDIO_MIXER_LAST;
535 		strcpy(dip->label.name, AudioNmute);
536 		dip->un.e.num_mem = 2;
537 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
538 		dip->un.e.member[0].ord = 0;
539 		strcpy(dip->un.e.member[1].label.name, AudioNon);
540 		dip->un.e.member[1].ord = 1;
541 		break;
542 	case AUDIOAMD_INPUT_CLASS:
543 		dip->type = AUDIO_MIXER_CLASS;
544 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
545 		dip->next = dip->prev = AUDIO_MIXER_LAST;
546 		strcpy(dip->label.name, AudioCinputs);
547 		break;
548 	case AUDIOAMD_OUTPUT_CLASS:
549 		dip->type = AUDIO_MIXER_CLASS;
550 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
551 		dip->next = dip->prev = AUDIO_MIXER_LAST;
552 		strcpy(dip->label.name, AudioCoutputs);
553 		break;
554 	case AUDIOAMD_RECORD_CLASS:
555 		dip->type = AUDIO_MIXER_CLASS;
556 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
557 		dip->next = dip->prev = AUDIO_MIXER_LAST;
558 		strcpy(dip->label.name, AudioCrecord);
559 		break;
560 	case AUDIOAMD_MONITOR_CLASS:
561 		dip->type = AUDIO_MIXER_CLASS;
562 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
563 		dip->next = dip->prev = AUDIO_MIXER_LAST;
564 		strcpy(dip->label.name, AudioCmonitor);
565 		break;
566 	default:
567 		return ENXIO;
568 		/*NOTREACHED*/
569 	}
570 
571 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
572 
573 	return 0;
574 }
575 
576 #endif	/* NAUDIO */
577