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