xref: /netbsd/sys/dev/ic/am7930.c (revision bf9ec67e)
1 /*	$NetBSD: am7930.c,v 1.44 2001/11/13 13:14:34 lukem 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.44 2001/11/13 13:14:34 lukem 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 	if (sc->sc_open)
208 		return (EBUSY);
209 	sc->sc_open = 1;
210 	sc->sc_locked = 0;
211 
212 	sc->sc_glue->onopen(sc);
213 
214 	DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
215 
216 	return (0);
217 }
218 
219 void
220 am7930_close(addr)
221 	void *addr;
222 {
223 	struct am7930_softc *sc = addr;
224 
225 	DPRINTF(("sa_close: sc=%p\n", sc));
226 
227 	sc->sc_glue->onclose(sc);
228 	sc->sc_open = 0;
229 
230 	DPRINTF(("sa_close: closed.\n"));
231 }
232 
233 
234 /*
235  * XXX should be extended to handle a few of the more common formats.
236  */
237 int
238 am7930_set_params(addr, setmode, usemode, p, r)
239 	void *addr;
240 	int setmode, usemode;
241 	struct audio_params *p, *r;
242 {
243 	struct am7930_softc *sc = addr;
244 
245 	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
246 		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
247 			p->encoding != AUDIO_ENCODING_ULAW ||
248 			p->precision != 8 ||
249 			p->channels != 1)
250 				return EINVAL;
251 		p->sample_rate = 8000;
252 		if (sc->sc_glue->factor > 1) {
253 			p->factor = sc->sc_glue->factor;
254 			p->sw_code = sc->sc_glue->output_conv;
255 		}
256 	}
257 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
258 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
259 			r->encoding != AUDIO_ENCODING_ULAW ||
260 			r->precision != 8 ||
261 			r->channels != 1)
262 				return EINVAL;
263 		r->sample_rate = 8000;
264 		if (sc->sc_glue->factor > 1) {
265 			r->factor = sc->sc_glue->factor;
266 			r->sw_code = sc->sc_glue->input_conv;
267 		}
268 	}
269 
270 	return 0;
271 }
272 
273 int
274 am7930_query_encoding(addr, fp)
275 	void *addr;
276 	struct audio_encoding *fp;
277 {
278 	switch (fp->index) {	/* ??? */
279 	    case 0:
280 		    strcpy(fp->name, AudioEmulaw);
281 		    fp->encoding = AUDIO_ENCODING_ULAW;
282 		    fp->precision = 8;
283 		    fp->flags = 0;
284 		    break;
285 	    default:
286 		    return(EINVAL);
287 		    /*NOTREACHED*/
288 	}
289 	return(0);
290 }
291 
292 
293 int
294 am7930_round_blocksize(addr, blk)
295 	void *addr;
296 	int blk;
297 {
298 	return(blk);
299 }
300 
301 
302 int
303 am7930_commit_settings(addr)
304 	void *addr;
305 {
306 	struct am7930_softc *sc = addr;
307 	u_int16_t ger, gr, gx, stgr;
308 	u_int8_t mmr2, mmr3;
309 	int s, level;
310 
311 	DPRINTF(("sa_commit.\n"));
312 
313 	gx = gx_coeff[sc->sc_rlevel];
314 	stgr = gx_coeff[sc->sc_mlevel];
315 
316 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
317 	if (level >= 256) {
318 		ger = ger_coeff[level - 256];
319 		gr = gx_coeff[255];
320 	} else {
321 		ger = ger_coeff[0];
322 		gr = gx_coeff[level];
323 	}
324 
325 	s = splaudio();
326 
327 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
328 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
329 		mmr2 |= AM7930_MMR2_LS;
330 	else
331 		mmr2 &= ~AM7930_MMR2_LS;
332 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
333 
334 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
335 	if (sc->sc_mic_mute)
336 		mmr3 |= AM7930_MMR3_MUTE;
337 	else
338 		mmr3 &= ~AM7930_MMR3_MUTE;
339 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
340 
341 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
342 		AM7930_MMR1_GX | AM7930_MMR1_GER |
343 		AM7930_MMR1_GR | AM7930_MMR1_STG);
344 
345 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
346 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
347 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
348 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
349 
350 	splx(s);
351 
352 	return(0);
353 }
354 
355 
356 int
357 am7930_halt_output(addr)
358 	void *addr;
359 {
360 	struct am7930_softc *sc = addr;
361 
362 	/* XXX only halt, if input is also halted ?? */
363 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
364 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
365 	sc->sc_locked = 0;
366 
367 	return(0);
368 }
369 
370 
371 int
372 am7930_halt_input(addr)
373 	void *addr;
374 {
375 	struct am7930_softc *sc = addr;
376 
377 	/* XXX only halt, if output is also halted ?? */
378 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
379 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
380 	sc->sc_locked = 0;
381 
382 	return(0);
383 }
384 
385 
386 /*
387  * XXX chip is full-duplex, but really attach-dependent.
388  * For now we know of no half-duplex attachments.
389  */
390 int
391 am7930_get_props(addr)
392 	void *addr;
393 {
394 	return AUDIO_PROP_FULLDUPLEX;
395 }
396 
397 /*
398  * Attach-dependent channel set/query
399  */
400 int
401 am7930_set_port(addr, cp)
402 	void *addr;
403 	mixer_ctrl_t *cp;
404 {
405 	struct am7930_softc *sc = addr;
406 
407 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
408 
409 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
410 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
411 		cp->dev == AUDIOAMD_MIC_MUTE) {
412 		if (cp->type != AUDIO_MIXER_ENUM)
413 			return(EINVAL);
414 	} else if (cp->type != AUDIO_MIXER_VALUE ||
415 					cp->un.value.num_channels != 1) {
416 		return(EINVAL);
417 	}
418 
419 	switch(cp->dev) {
420 	    case AUDIOAMD_MIC_VOL:
421 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
422 		    break;
423 	    case AUDIOAMD_SPEAKER_VOL:
424 	    case AUDIOAMD_HEADPHONES_VOL:
425 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
426 		    break;
427 	    case AUDIOAMD_MONITOR_VOL:
428 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
429 		    break;
430 	    case AUDIOAMD_RECORD_SOURCE:
431 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
432 			    return EINVAL;
433 		    break;
434 	    case AUDIOAMD_MIC_MUTE:
435 		    sc->sc_mic_mute = cp->un.ord;
436 		    break;
437 	    case AUDIOAMD_MONITOR_OUTPUT:
438 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
439 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
440 			    return EINVAL;
441 			sc->sc_out_port = cp->un.ord;
442 		    break;
443 	    default:
444 		    return(EINVAL);
445 		    /* NOTREACHED */
446 	}
447 	return 0;
448 }
449 
450 int
451 am7930_get_port(addr, cp)
452 	void *addr;
453 	mixer_ctrl_t *cp;
454 {
455 	struct am7930_softc *sc = addr;
456 
457 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
458 
459 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
460 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
461 		cp->dev == AUDIOAMD_MIC_MUTE) {
462 		if (cp->type != AUDIO_MIXER_ENUM)
463 			return(EINVAL);
464 	} else if (cp->type != AUDIO_MIXER_VALUE ||
465 		cp->un.value.num_channels != 1) {
466 		return(EINVAL);
467 	}
468 
469 	switch(cp->dev) {
470 	    case AUDIOAMD_MIC_VOL:
471 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
472 		    break;
473 	    case AUDIOAMD_SPEAKER_VOL:
474 	    case AUDIOAMD_HEADPHONES_VOL:
475 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
476 		    break;
477 	    case AUDIOAMD_MONITOR_VOL:
478 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
479 		    break;
480 	    case AUDIOAMD_RECORD_SOURCE:
481 		    cp->un.ord = AUDIOAMD_MIC_VOL;
482 		    break;
483 	    case AUDIOAMD_MIC_MUTE:
484 		    cp->un.ord = sc->sc_mic_mute;
485 		    break;
486 	    case AUDIOAMD_MONITOR_OUTPUT:
487 		    cp->un.ord = sc->sc_out_port;
488 		    break;
489 	    default:
490 		    return(EINVAL);
491 		    /* NOTREACHED */
492 	}
493 	return 0;
494 }
495 
496 
497 /*
498  * Define mixer control facilities.
499  */
500 int
501 am7930_query_devinfo(addr, dip)
502 	void *addr;
503 	mixer_devinfo_t *dip;
504 {
505 
506 	DPRINTF(("am7930_query_devinfo()\n"));
507 
508 	switch(dip->index) {
509 	    case AUDIOAMD_MIC_VOL:
510 		    dip->type = AUDIO_MIXER_VALUE;
511 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
512 		    dip->prev =  AUDIO_MIXER_LAST;
513 		    dip->next = AUDIOAMD_MIC_MUTE;
514 		    strcpy(dip->label.name, AudioNmicrophone);
515 		    dip->un.v.num_channels = 1;
516 		    strcpy(dip->un.v.units.name, AudioNvolume);
517 		    break;
518 	    case AUDIOAMD_SPEAKER_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, AudioNspeaker);
523 		    dip->un.v.num_channels = 1;
524 		    strcpy(dip->un.v.units.name, AudioNvolume);
525 		    break;
526 	    case AUDIOAMD_HEADPHONES_VOL:
527 		    dip->type = AUDIO_MIXER_VALUE;
528 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
529 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
530 		    strcpy(dip->label.name, AudioNheadphone);
531 		    dip->un.v.num_channels = 1;
532 		    strcpy(dip->un.v.units.name, AudioNvolume);
533 		    break;
534 	    case AUDIOAMD_MONITOR_VOL:
535 		    dip->type = AUDIO_MIXER_VALUE;
536 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
537 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
538 		    strcpy(dip->label.name, AudioNmonitor);
539 		    dip->un.v.num_channels = 1;
540 		    strcpy(dip->un.v.units.name, AudioNvolume);
541 		    break;
542 	    case AUDIOAMD_RECORD_SOURCE:
543 		    dip->type = AUDIO_MIXER_ENUM;
544 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
545 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
546 		    strcpy(dip->label.name, AudioNsource);
547 		    dip->un.e.num_mem = 1;
548 		    strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
549 		    dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
550 		    break;
551 	    case AUDIOAMD_MONITOR_OUTPUT:
552 		    dip->type = AUDIO_MIXER_ENUM;
553 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
554 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
555 		    strcpy(dip->label.name, AudioNoutput);
556 		    dip->un.e.num_mem = 2;
557 		    strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
558 		    dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
559 		    strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
560 		    dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
561 		    break;
562 	    case AUDIOAMD_MIC_MUTE:
563 		    dip->type = AUDIO_MIXER_ENUM;
564 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
565 		    dip->prev =  AUDIOAMD_MIC_VOL;
566 		    dip->next = AUDIO_MIXER_LAST;
567 		    strcpy(dip->label.name, AudioNmute);
568 		    dip->un.e.num_mem = 2;
569 		    strcpy(dip->un.e.member[0].label.name, AudioNoff);
570 		    dip->un.e.member[0].ord = 0;
571 		    strcpy(dip->un.e.member[1].label.name, AudioNon);
572 		    dip->un.e.member[1].ord = 1;
573 		    break;
574 	    case AUDIOAMD_INPUT_CLASS:
575 		    dip->type = AUDIO_MIXER_CLASS;
576 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
577 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
578 		    strcpy(dip->label.name, AudioCinputs);
579 		    break;
580 	    case AUDIOAMD_OUTPUT_CLASS:
581 		    dip->type = AUDIO_MIXER_CLASS;
582 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
583 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
584 		    strcpy(dip->label.name, AudioCoutputs);
585 		    break;
586 	    case AUDIOAMD_RECORD_CLASS:
587 		    dip->type = AUDIO_MIXER_CLASS;
588 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
589 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
590 		    strcpy(dip->label.name, AudioCrecord);
591 		    break;
592 	    case AUDIOAMD_MONITOR_CLASS:
593 		    dip->type = AUDIO_MIXER_CLASS;
594 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
595 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
596 		    strcpy(dip->label.name, AudioCmonitor);
597 		    break;
598 	    default:
599 		    return ENXIO;
600 		    /*NOTREACHED*/
601 	}
602 
603 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
604 
605 	return(0);
606 }
607 
608 #endif	/* NAUDIO */
609