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