xref: /netbsd-src/sys/dev/ic/am7930.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: am7930.c,v 1.45 2004/07/09 02:07:01 mycroft 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.45 2004/07/09 02:07:01 mycroft 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 <machine/bus.h>
52 #include <machine/autoconf.h>
53 #include <machine/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 u_short 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 u_short 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(sc, flag)
146 	struct am7930_softc *sc;
147 	int flag;
148 {
149 
150 	DPRINTF(("am7930_init()\n"));
151 
152 	/* set boot defaults */
153 	sc->sc_rlevel = 128;
154 	sc->sc_plevel = 128;
155 	sc->sc_mlevel = 0;
156 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
157 	sc->sc_mic_mute = 0;
158 
159 	/* disable sample interrupts */
160 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
161 
162 	/* initialise voice and data, and disable interrupts */
163 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
164 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
165 
166 	if (flag == AUDIOAMD_DMA_MODE) {
167 
168 		/* configure PP for serial (SBP) mode */
169 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
170 
171 		/*
172 		 * Initialise the MUX unit - route the MAP to the PP
173 		 */
174 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
175 			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
176 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
177 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
178 
179 	} else {
180 
181 		/*
182 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
183 		 * through channel Bb.  MCR1 and MCR2 are unused.
184 		 * Setting the INT enable bit in MCR4 will generate an
185 		 * interrupt on each converted audio sample.
186 		 */
187 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
188 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
189 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
190 			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
191 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
192 			AM7930_MCR4_INT_ENABLE);
193 	}
194 
195 }
196 
197 
198 int
199 am7930_open(addr, flags)
200 	void *addr;
201 	int flags;
202 {
203 	struct am7930_softc *sc = addr;
204 
205 	DPRINTF(("sa_open: unit %p\n", sc));
206 
207 	sc->sc_glue->onopen(sc);
208 
209 	DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
210 
211 	return (0);
212 }
213 
214 void
215 am7930_close(addr)
216 	void *addr;
217 {
218 	struct am7930_softc *sc = addr;
219 
220 	DPRINTF(("sa_close: sc=%p\n", sc));
221 
222 	sc->sc_glue->onclose(sc);
223 
224 	DPRINTF(("sa_close: closed.\n"));
225 }
226 
227 
228 /*
229  * XXX should be extended to handle a few of the more common formats.
230  */
231 int
232 am7930_set_params(addr, setmode, usemode, p, r)
233 	void *addr;
234 	int setmode, usemode;
235 	struct audio_params *p, *r;
236 {
237 	struct am7930_softc *sc = addr;
238 
239 	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
240 		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
241 			p->encoding != AUDIO_ENCODING_ULAW ||
242 			p->precision != 8 ||
243 			p->channels != 1)
244 				return EINVAL;
245 		p->sample_rate = 8000;
246 		if (sc->sc_glue->factor > 1) {
247 			p->factor = sc->sc_glue->factor;
248 			p->sw_code = sc->sc_glue->output_conv;
249 		}
250 	}
251 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
252 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
253 			r->encoding != AUDIO_ENCODING_ULAW ||
254 			r->precision != 8 ||
255 			r->channels != 1)
256 				return EINVAL;
257 		r->sample_rate = 8000;
258 		if (sc->sc_glue->factor > 1) {
259 			r->factor = sc->sc_glue->factor;
260 			r->sw_code = sc->sc_glue->input_conv;
261 		}
262 	}
263 
264 	return 0;
265 }
266 
267 int
268 am7930_query_encoding(addr, fp)
269 	void *addr;
270 	struct audio_encoding *fp;
271 {
272 	switch (fp->index) {	/* ??? */
273 	    case 0:
274 		    strcpy(fp->name, AudioEmulaw);
275 		    fp->encoding = AUDIO_ENCODING_ULAW;
276 		    fp->precision = 8;
277 		    fp->flags = 0;
278 		    break;
279 	    default:
280 		    return(EINVAL);
281 		    /*NOTREACHED*/
282 	}
283 	return(0);
284 }
285 
286 
287 int
288 am7930_round_blocksize(addr, blk)
289 	void *addr;
290 	int blk;
291 {
292 	return(blk);
293 }
294 
295 
296 int
297 am7930_commit_settings(addr)
298 	void *addr;
299 {
300 	struct am7930_softc *sc = addr;
301 	u_int16_t ger, gr, gx, stgr;
302 	u_int8_t mmr2, mmr3;
303 	int s, level;
304 
305 	DPRINTF(("sa_commit.\n"));
306 
307 	gx = gx_coeff[sc->sc_rlevel];
308 	stgr = gx_coeff[sc->sc_mlevel];
309 
310 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
311 	if (level >= 256) {
312 		ger = ger_coeff[level - 256];
313 		gr = gx_coeff[255];
314 	} else {
315 		ger = ger_coeff[0];
316 		gr = gx_coeff[level];
317 	}
318 
319 	s = splaudio();
320 
321 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
322 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
323 		mmr2 |= AM7930_MMR2_LS;
324 	else
325 		mmr2 &= ~AM7930_MMR2_LS;
326 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
327 
328 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
329 	if (sc->sc_mic_mute)
330 		mmr3 |= AM7930_MMR3_MUTE;
331 	else
332 		mmr3 &= ~AM7930_MMR3_MUTE;
333 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
334 
335 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
336 		AM7930_MMR1_GX | AM7930_MMR1_GER |
337 		AM7930_MMR1_GR | AM7930_MMR1_STG);
338 
339 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
340 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
341 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
342 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
343 
344 	splx(s);
345 
346 	return(0);
347 }
348 
349 
350 int
351 am7930_halt_output(addr)
352 	void *addr;
353 {
354 	struct am7930_softc *sc = addr;
355 
356 	/* XXX only halt, if input is also halted ?? */
357 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
358 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
359 
360 	return(0);
361 }
362 
363 
364 int
365 am7930_halt_input(addr)
366 	void *addr;
367 {
368 	struct am7930_softc *sc = addr;
369 
370 	/* XXX only halt, if output is also halted ?? */
371 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
372 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
373 
374 	return(0);
375 }
376 
377 
378 /*
379  * XXX chip is full-duplex, but really attach-dependent.
380  * For now we know of no half-duplex attachments.
381  */
382 int
383 am7930_get_props(addr)
384 	void *addr;
385 {
386 	return AUDIO_PROP_FULLDUPLEX;
387 }
388 
389 /*
390  * Attach-dependent channel set/query
391  */
392 int
393 am7930_set_port(addr, cp)
394 	void *addr;
395 	mixer_ctrl_t *cp;
396 {
397 	struct am7930_softc *sc = addr;
398 
399 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
400 
401 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
402 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
403 		cp->dev == AUDIOAMD_MIC_MUTE) {
404 		if (cp->type != AUDIO_MIXER_ENUM)
405 			return(EINVAL);
406 	} else if (cp->type != AUDIO_MIXER_VALUE ||
407 					cp->un.value.num_channels != 1) {
408 		return(EINVAL);
409 	}
410 
411 	switch(cp->dev) {
412 	    case AUDIOAMD_MIC_VOL:
413 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
414 		    break;
415 	    case AUDIOAMD_SPEAKER_VOL:
416 	    case AUDIOAMD_HEADPHONES_VOL:
417 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
418 		    break;
419 	    case AUDIOAMD_MONITOR_VOL:
420 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
421 		    break;
422 	    case AUDIOAMD_RECORD_SOURCE:
423 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
424 			    return EINVAL;
425 		    break;
426 	    case AUDIOAMD_MIC_MUTE:
427 		    sc->sc_mic_mute = cp->un.ord;
428 		    break;
429 	    case AUDIOAMD_MONITOR_OUTPUT:
430 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
431 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
432 			    return EINVAL;
433 			sc->sc_out_port = cp->un.ord;
434 		    break;
435 	    default:
436 		    return(EINVAL);
437 		    /* NOTREACHED */
438 	}
439 	return 0;
440 }
441 
442 int
443 am7930_get_port(addr, cp)
444 	void *addr;
445 	mixer_ctrl_t *cp;
446 {
447 	struct am7930_softc *sc = addr;
448 
449 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
450 
451 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
452 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
453 		cp->dev == AUDIOAMD_MIC_MUTE) {
454 		if (cp->type != AUDIO_MIXER_ENUM)
455 			return(EINVAL);
456 	} else if (cp->type != AUDIO_MIXER_VALUE ||
457 		cp->un.value.num_channels != 1) {
458 		return(EINVAL);
459 	}
460 
461 	switch(cp->dev) {
462 	    case AUDIOAMD_MIC_VOL:
463 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
464 		    break;
465 	    case AUDIOAMD_SPEAKER_VOL:
466 	    case AUDIOAMD_HEADPHONES_VOL:
467 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
468 		    break;
469 	    case AUDIOAMD_MONITOR_VOL:
470 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
471 		    break;
472 	    case AUDIOAMD_RECORD_SOURCE:
473 		    cp->un.ord = AUDIOAMD_MIC_VOL;
474 		    break;
475 	    case AUDIOAMD_MIC_MUTE:
476 		    cp->un.ord = sc->sc_mic_mute;
477 		    break;
478 	    case AUDIOAMD_MONITOR_OUTPUT:
479 		    cp->un.ord = sc->sc_out_port;
480 		    break;
481 	    default:
482 		    return(EINVAL);
483 		    /* NOTREACHED */
484 	}
485 	return 0;
486 }
487 
488 
489 /*
490  * Define mixer control facilities.
491  */
492 int
493 am7930_query_devinfo(addr, dip)
494 	void *addr;
495 	mixer_devinfo_t *dip;
496 {
497 
498 	DPRINTF(("am7930_query_devinfo()\n"));
499 
500 	switch(dip->index) {
501 	    case AUDIOAMD_MIC_VOL:
502 		    dip->type = AUDIO_MIXER_VALUE;
503 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
504 		    dip->prev =  AUDIO_MIXER_LAST;
505 		    dip->next = AUDIOAMD_MIC_MUTE;
506 		    strcpy(dip->label.name, AudioNmicrophone);
507 		    dip->un.v.num_channels = 1;
508 		    strcpy(dip->un.v.units.name, AudioNvolume);
509 		    break;
510 	    case AUDIOAMD_SPEAKER_VOL:
511 		    dip->type = AUDIO_MIXER_VALUE;
512 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
513 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
514 		    strcpy(dip->label.name, AudioNspeaker);
515 		    dip->un.v.num_channels = 1;
516 		    strcpy(dip->un.v.units.name, AudioNvolume);
517 		    break;
518 	    case AUDIOAMD_HEADPHONES_VOL:
519 		    dip->type = AUDIO_MIXER_VALUE;
520 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
521 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
522 		    strcpy(dip->label.name, AudioNheadphone);
523 		    dip->un.v.num_channels = 1;
524 		    strcpy(dip->un.v.units.name, AudioNvolume);
525 		    break;
526 	    case AUDIOAMD_MONITOR_VOL:
527 		    dip->type = AUDIO_MIXER_VALUE;
528 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
529 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
530 		    strcpy(dip->label.name, AudioNmonitor);
531 		    dip->un.v.num_channels = 1;
532 		    strcpy(dip->un.v.units.name, AudioNvolume);
533 		    break;
534 	    case AUDIOAMD_RECORD_SOURCE:
535 		    dip->type = AUDIO_MIXER_ENUM;
536 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
537 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
538 		    strcpy(dip->label.name, AudioNsource);
539 		    dip->un.e.num_mem = 1;
540 		    strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
541 		    dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
542 		    break;
543 	    case AUDIOAMD_MONITOR_OUTPUT:
544 		    dip->type = AUDIO_MIXER_ENUM;
545 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
546 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
547 		    strcpy(dip->label.name, AudioNoutput);
548 		    dip->un.e.num_mem = 2;
549 		    strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
550 		    dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
551 		    strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
552 		    dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
553 		    break;
554 	    case AUDIOAMD_MIC_MUTE:
555 		    dip->type = AUDIO_MIXER_ENUM;
556 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
557 		    dip->prev =  AUDIOAMD_MIC_VOL;
558 		    dip->next = AUDIO_MIXER_LAST;
559 		    strcpy(dip->label.name, AudioNmute);
560 		    dip->un.e.num_mem = 2;
561 		    strcpy(dip->un.e.member[0].label.name, AudioNoff);
562 		    dip->un.e.member[0].ord = 0;
563 		    strcpy(dip->un.e.member[1].label.name, AudioNon);
564 		    dip->un.e.member[1].ord = 1;
565 		    break;
566 	    case AUDIOAMD_INPUT_CLASS:
567 		    dip->type = AUDIO_MIXER_CLASS;
568 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
569 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
570 		    strcpy(dip->label.name, AudioCinputs);
571 		    break;
572 	    case AUDIOAMD_OUTPUT_CLASS:
573 		    dip->type = AUDIO_MIXER_CLASS;
574 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
575 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
576 		    strcpy(dip->label.name, AudioCoutputs);
577 		    break;
578 	    case AUDIOAMD_RECORD_CLASS:
579 		    dip->type = AUDIO_MIXER_CLASS;
580 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
581 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
582 		    strcpy(dip->label.name, AudioCrecord);
583 		    break;
584 	    case AUDIOAMD_MONITOR_CLASS:
585 		    dip->type = AUDIO_MIXER_CLASS;
586 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
587 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
588 		    strcpy(dip->label.name, AudioCmonitor);
589 		    break;
590 	    default:
591 		    return ENXIO;
592 		    /*NOTREACHED*/
593 	}
594 
595 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
596 
597 	return(0);
598 }
599 
600 #endif	/* NAUDIO */
601