Home | History | Annotate | Line # | Download | only in ic
am7930.c revision 1.50.56.1
      1 /*	$NetBSD: am7930.c,v 1.50.56.1 2011/11/20 10:56:18 mrg 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.56.1 2011/11/20 10:56:18 mrg 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 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    194 	/* We used to take splaudio() in commit_settings */
    195 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
    196 }
    197 
    198 int
    199 am7930_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 
    210 void
    211 am7930_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  */
    224 int
    225 am7930_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->precision != 8 ||
    236 			p->channels != 1)
    237 				return EINVAL;
    238 		p->sample_rate = 8000;
    239 		if (sc->sc_glue->output_conv != NULL) {
    240 			hw = *p;
    241 			hw.encoding = AUDIO_ENCODING_NONE;
    242 			hw.precision *= sc->sc_glue->factor;
    243 			pfil->append(pfil, sc->sc_glue->output_conv, &hw);
    244 		}
    245 	}
    246 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
    247 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
    248 			r->encoding != AUDIO_ENCODING_ULAW ||
    249 			r->precision != 8 ||
    250 			r->channels != 1)
    251 				return EINVAL;
    252 		r->sample_rate = 8000;
    253 		if (sc->sc_glue->input_conv != NULL) {
    254 			hw = *r;
    255 			hw.encoding = AUDIO_ENCODING_NONE;
    256 			hw.precision *= sc->sc_glue->factor;
    257 			pfil->append(rfil, sc->sc_glue->input_conv, &hw);
    258 		}
    259 	}
    260 
    261 	return 0;
    262 }
    263 
    264 int
    265 am7930_query_encoding(void *addr, struct audio_encoding *fp)
    266 {
    267 	switch (fp->index) {
    268 	case 0:
    269 		strcpy(fp->name, AudioEmulaw);
    270 		fp->encoding = AUDIO_ENCODING_ULAW;
    271 		fp->precision = 8;
    272 		fp->flags = 0;
    273 		break;
    274 	default:
    275 		return EINVAL;
    276 		    /*NOTREACHED*/
    277 	}
    278 	return 0;
    279 }
    280 
    281 int
    282 am7930_round_blocksize(void *addr, int blk,
    283     int mode, const audio_params_t *param)
    284 {
    285 	return blk;
    286 }
    287 
    288 int
    289 am7930_commit_settings(void *addr)
    290 {
    291 	struct am7930_softc *sc;
    292 	uint16_t ger, gr, gx, stgr;
    293 	uint8_t mmr2, mmr3;
    294 	int level;
    295 
    296 	DPRINTF(("sa_commit.\n"));
    297 	sc = addr;
    298 	gx = gx_coeff[sc->sc_rlevel];
    299 	stgr = gx_coeff[sc->sc_mlevel];
    300 
    301 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
    302 	if (level >= 256) {
    303 		ger = ger_coeff[level - 256];
    304 		gr = gx_coeff[255];
    305 	} else {
    306 		ger = ger_coeff[0];
    307 		gr = gx_coeff[level];
    308 	}
    309 
    310 	mutex_enter(&sc->sc_intr_lock);
    311 
    312 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
    313 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
    314 		mmr2 |= AM7930_MMR2_LS;
    315 	else
    316 		mmr2 &= ~AM7930_MMR2_LS;
    317 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
    318 
    319 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
    320 	if (sc->sc_mic_mute)
    321 		mmr3 |= AM7930_MMR3_MUTE;
    322 	else
    323 		mmr3 &= ~AM7930_MMR3_MUTE;
    324 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
    325 
    326 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
    327 		AM7930_MMR1_GX | AM7930_MMR1_GER |
    328 		AM7930_MMR1_GR | AM7930_MMR1_STG);
    329 
    330 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
    331 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
    332 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
    333 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
    334 
    335 	mutex_exit(&sc->sc_intr_lock);
    336 
    337 	return 0;
    338 }
    339 
    340 int
    341 am7930_halt_output(void *addr)
    342 {
    343 	struct am7930_softc *sc;
    344 
    345 	sc = addr;
    346 	/* XXX only halt, if input is also halted ?? */
    347 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    348 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    349 	return 0;
    350 }
    351 
    352 int
    353 am7930_halt_input(void *addr)
    354 {
    355 	struct am7930_softc *sc;
    356 
    357 	sc = addr;
    358 	/* XXX only halt, if output is also halted ?? */
    359 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    360 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    361 	return 0;
    362 }
    363 
    364 /*
    365  * XXX chip is full-duplex, but really attach-dependent.
    366  * For now we know of no half-duplex attachments.
    367  */
    368 int
    369 am7930_get_props(void *addr)
    370 {
    371 	return AUDIO_PROP_FULLDUPLEX;
    372 }
    373 
    374 /*
    375  * Attach-dependent channel set/query
    376  */
    377 int
    378 am7930_set_port(void *addr, mixer_ctrl_t *cp)
    379 {
    380 	struct am7930_softc *sc;
    381 
    382 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
    383 	sc = addr;
    384 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    385 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    386 		cp->dev == AUDIOAMD_MIC_MUTE) {
    387 		if (cp->type != AUDIO_MIXER_ENUM)
    388 			return EINVAL;
    389 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    390 	    cp->un.value.num_channels != 1) {
    391 		return EINVAL;
    392 	}
    393 
    394 	switch(cp->dev) {
    395 	    case AUDIOAMD_MIC_VOL:
    396 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    397 		    break;
    398 	    case AUDIOAMD_SPEAKER_VOL:
    399 	    case AUDIOAMD_HEADPHONES_VOL:
    400 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    401 		    break;
    402 	    case AUDIOAMD_MONITOR_VOL:
    403 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    404 		    break;
    405 	    case AUDIOAMD_RECORD_SOURCE:
    406 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
    407 			    return EINVAL;
    408 		    break;
    409 	    case AUDIOAMD_MIC_MUTE:
    410 		    sc->sc_mic_mute = cp->un.ord;
    411 		    break;
    412 	    case AUDIOAMD_MONITOR_OUTPUT:
    413 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
    414 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
    415 			    return EINVAL;
    416 			sc->sc_out_port = cp->un.ord;
    417 		    break;
    418 	    default:
    419 		    return EINVAL;
    420 		    /* NOTREACHED */
    421 	}
    422 	return 0;
    423 }
    424 
    425 int
    426 am7930_get_port(void *addr, mixer_ctrl_t *cp)
    427 {
    428 	struct am7930_softc *sc;
    429 
    430 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
    431 	sc = addr;
    432 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    433 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    434 		cp->dev == AUDIOAMD_MIC_MUTE) {
    435 		if (cp->type != AUDIO_MIXER_ENUM)
    436 			return EINVAL;
    437 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    438 		cp->un.value.num_channels != 1) {
    439 		return EINVAL;
    440 	}
    441 
    442 	switch(cp->dev) {
    443 	    case AUDIOAMD_MIC_VOL:
    444 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
    445 		    break;
    446 	    case AUDIOAMD_SPEAKER_VOL:
    447 	    case AUDIOAMD_HEADPHONES_VOL:
    448 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
    449 		    break;
    450 	    case AUDIOAMD_MONITOR_VOL:
    451 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
    452 		    break;
    453 	    case AUDIOAMD_RECORD_SOURCE:
    454 		    cp->un.ord = AUDIOAMD_MIC_VOL;
    455 		    break;
    456 	    case AUDIOAMD_MIC_MUTE:
    457 		    cp->un.ord = sc->sc_mic_mute;
    458 		    break;
    459 	    case AUDIOAMD_MONITOR_OUTPUT:
    460 		    cp->un.ord = sc->sc_out_port;
    461 		    break;
    462 	    default:
    463 		    return EINVAL;
    464 		    /* NOTREACHED */
    465 	}
    466 	return 0;
    467 }
    468 
    469 
    470 /*
    471  * Define mixer control facilities.
    472  */
    473 int
    474 am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
    475 {
    476 
    477 	DPRINTF(("am7930_query_devinfo()\n"));
    478 
    479 	switch(dip->index) {
    480 	case AUDIOAMD_MIC_VOL:
    481 		dip->type = AUDIO_MIXER_VALUE;
    482 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    483 		dip->prev =  AUDIO_MIXER_LAST;
    484 		dip->next = AUDIOAMD_MIC_MUTE;
    485 		strcpy(dip->label.name, AudioNmicrophone);
    486 		dip->un.v.num_channels = 1;
    487 		strcpy(dip->un.v.units.name, AudioNvolume);
    488 		break;
    489 	case AUDIOAMD_SPEAKER_VOL:
    490 		dip->type = AUDIO_MIXER_VALUE;
    491 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    492 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    493 		strcpy(dip->label.name, AudioNspeaker);
    494 		dip->un.v.num_channels = 1;
    495 		strcpy(dip->un.v.units.name, AudioNvolume);
    496 		break;
    497 	case AUDIOAMD_HEADPHONES_VOL:
    498 		dip->type = AUDIO_MIXER_VALUE;
    499 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    500 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    501 		strcpy(dip->label.name, AudioNheadphone);
    502 		dip->un.v.num_channels = 1;
    503 		strcpy(dip->un.v.units.name, AudioNvolume);
    504 		break;
    505 	case AUDIOAMD_MONITOR_VOL:
    506 		dip->type = AUDIO_MIXER_VALUE;
    507 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    508 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    509 		strcpy(dip->label.name, AudioNmonitor);
    510 		dip->un.v.num_channels = 1;
    511 		strcpy(dip->un.v.units.name, AudioNvolume);
    512 		break;
    513 	case AUDIOAMD_RECORD_SOURCE:
    514 		dip->type = AUDIO_MIXER_ENUM;
    515 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    516 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    517 		strcpy(dip->label.name, AudioNsource);
    518 		dip->un.e.num_mem = 1;
    519 		strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    520 		dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
    521 		break;
    522 	case AUDIOAMD_MONITOR_OUTPUT:
    523 		dip->type = AUDIO_MIXER_ENUM;
    524 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    525 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    526 		strcpy(dip->label.name, AudioNoutput);
    527 		dip->un.e.num_mem = 2;
    528 		strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
    529 		dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
    530 		strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
    531 		dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
    532 		break;
    533 	case AUDIOAMD_MIC_MUTE:
    534 		dip->type = AUDIO_MIXER_ENUM;
    535 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    536 		dip->prev =  AUDIOAMD_MIC_VOL;
    537 		dip->next = AUDIO_MIXER_LAST;
    538 		strcpy(dip->label.name, AudioNmute);
    539 		dip->un.e.num_mem = 2;
    540 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
    541 		dip->un.e.member[0].ord = 0;
    542 		strcpy(dip->un.e.member[1].label.name, AudioNon);
    543 		dip->un.e.member[1].ord = 1;
    544 		break;
    545 	case AUDIOAMD_INPUT_CLASS:
    546 		dip->type = AUDIO_MIXER_CLASS;
    547 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    548 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    549 		strcpy(dip->label.name, AudioCinputs);
    550 		break;
    551 	case AUDIOAMD_OUTPUT_CLASS:
    552 		dip->type = AUDIO_MIXER_CLASS;
    553 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    554 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    555 		strcpy(dip->label.name, AudioCoutputs);
    556 		break;
    557 	case AUDIOAMD_RECORD_CLASS:
    558 		dip->type = AUDIO_MIXER_CLASS;
    559 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    560 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    561 		strcpy(dip->label.name, AudioCrecord);
    562 		break;
    563 	case AUDIOAMD_MONITOR_CLASS:
    564 		dip->type = AUDIO_MIXER_CLASS;
    565 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    566 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    567 		strcpy(dip->label.name, AudioCmonitor);
    568 		break;
    569 	default:
    570 		return ENXIO;
    571 		/*NOTREACHED*/
    572 	}
    573 
    574 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
    575 
    576 	return 0;
    577 }
    578 
    579 #endif	/* NAUDIO */
    580