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