Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.35
      1 /*      $NetBSD: ac97.c,v 1.35 2002/10/22 13:48:30 kent Exp $ */
      2 /*	$OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
      6  *
      7  * Author:        Constantine Sapuntzakis <csapuntz (at) stanford.edu>
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote
     18  *    products derived from this software without specific prior written
     19  *    permission.
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
     21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
     24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     30  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     31  * DAMAGE
     32  */
     33 
     34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
     35    the following copyright */
     36 
     37 /*
     38  * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
     39  * All rights reserved.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     60  * SUCH DAMAGE.
     61  *
     62  * $FreeBSD$
     63  */
     64 
     65 #include <sys/cdefs.h>
     66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.35 2002/10/22 13:48:30 kent Exp $");
     67 
     68 #include <sys/param.h>
     69 #include <sys/systm.h>
     70 #include <sys/kernel.h>
     71 #include <sys/malloc.h>
     72 #include <sys/device.h>
     73 
     74 #include <sys/audioio.h>
     75 #include <dev/audio_if.h>
     76 
     77 #include <dev/ic/ac97reg.h>
     78 #include <dev/ic/ac97var.h>
     79 
     80 #define Ac97Ntone	"tone"
     81 #define Ac97Nphone	"phone"
     82 
     83 static const struct audio_mixer_enum ac97_on_off = { 2,
     84 					       { { { AudioNoff } , 0 },
     85 						 { { AudioNon }  , 1 } }};
     86 
     87 static const struct audio_mixer_enum ac97_mic_select = { 2,
     88 					       { { { AudioNmicrophone "0" },
     89 						   0 },
     90 						 { { AudioNmicrophone "1" },
     91 						   1 } }};
     92 
     93 static const struct audio_mixer_enum ac97_mono_select = { 2,
     94 					       { { { AudioNmixerout },
     95 						   0 },
     96 						 { { AudioNmicrophone },
     97 						   1 } }};
     98 
     99 static const struct audio_mixer_enum ac97_source = { 8,
    100 					       { { { AudioNmicrophone } , 0 },
    101 						 { { AudioNcd }, 1 },
    102 						 { { AudioNvideo }, 2 },
    103 						 { { AudioNaux }, 3 },
    104 						 { { AudioNline }, 4 },
    105 						 { { AudioNmixerout }, 5 },
    106 						 { { AudioNmixerout AudioNmono }, 6 },
    107 						 { { Ac97Nphone }, 7 }}};
    108 
    109 /*
    110  * Due to different values for each source that uses these structures,
    111  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
    112  * ac97_source_info.bits.
    113  */
    114 static const struct audio_mixer_value ac97_volume_stereo = { { AudioNvolume },
    115 						       2 };
    116 
    117 static const struct audio_mixer_value ac97_volume_mono = { { AudioNvolume },
    118 						     1 };
    119 
    120 #define WRAP(a)  &a, sizeof(a)
    121 
    122 const struct ac97_source_info {
    123 	const char *class;
    124 	const char *device;
    125 	const char *qualifier;
    126 
    127 	int  type;
    128 	const void *info;
    129 	int  info_size;
    130 
    131 	u_int8_t  reg;
    132 	u_int16_t default_value;
    133 	u_int8_t  bits:3;
    134 	u_int8_t  ofs:4;
    135 	u_int8_t  mute:1;
    136 	u_int8_t  polarity:1;   /* Does 0 == MAX or MIN */
    137 	enum {
    138 		CHECK_NONE = 0,
    139 		CHECK_SURROUND,
    140 		CHECK_CENTER,
    141 		CHECK_LFE,
    142 		CHECK_HEADPHONES,
    143 		CHECK_TONE,
    144 		CHECK_MIC,
    145 		CHECK_LOUDNESS,
    146 		CHECK_3D
    147 	} req_feature;
    148 
    149 	int  prev;
    150 	int  next;
    151 	int  mixer_class;
    152 } source_info[] = {
    153 	{ AudioCinputs,		NULL,		NULL,
    154 	  AUDIO_MIXER_CLASS, },
    155 	{ AudioCoutputs,	NULL,		NULL,
    156 	  AUDIO_MIXER_CLASS, },
    157 	{ AudioCrecord,		NULL,		NULL,
    158 	  AUDIO_MIXER_CLASS, },
    159 	/* Stereo master volume*/
    160 	{ AudioCoutputs,	AudioNmaster,	NULL,
    161 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    162 	  AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
    163 	},
    164 	/* Mono volume */
    165 	{ AudioCoutputs,	AudioNmono,	NULL,
    166 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    167 	  AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
    168 	},
    169 	{ AudioCoutputs,	AudioNmono,	AudioNsource,
    170 	  AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
    171 	  AC97_REG_GP, 0x0000, 1, 9, 0,
    172 	},
    173 	/* Headphone volume */
    174 	{ AudioCoutputs,	AudioNheadphone, NULL,
    175 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    176 	  AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
    177 	},
    178 	/* Surround volume - logic hard coded for mute */
    179 	{ AudioCoutputs,	AudioNsurround,	NULL,
    180 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    181 	  AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
    182 	},
    183 	/* Center volume*/
    184 	{ AudioCoutputs,	AudioNcenter,	NULL,
    185 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    186 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
    187 	},
    188 	{ AudioCoutputs,	AudioNcenter,	AudioNmute,
    189 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    190 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
    191 	},
    192 	/* LFE volume*/
    193 	{ AudioCoutputs,	AudioNlfe,	NULL,
    194 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    195 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
    196 	},
    197 	{ AudioCoutputs,	AudioNlfe,	AudioNmute,
    198 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    199 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
    200 	},
    201 	/* Tone */
    202 	{ AudioCoutputs,	Ac97Ntone,	NULL,
    203 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    204 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
    205 	},
    206 	/* PC Beep Volume */
    207 	{ AudioCinputs,		AudioNspeaker,	NULL,
    208 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    209 	  AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
    210 	},
    211 
    212 	/* Phone */
    213 	{ AudioCinputs,		Ac97Nphone,	NULL,
    214 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    215 	  AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
    216 	},
    217 	/* Mic Volume */
    218 	{ AudioCinputs,		AudioNmicrophone, NULL,
    219 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    220 	  AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
    221 	},
    222 	{ AudioCinputs,		AudioNmicrophone, AudioNpreamp,
    223 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    224 	  AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
    225 	},
    226 	{ AudioCinputs,		AudioNmicrophone, AudioNsource,
    227 	  AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
    228 	  AC97_REG_GP, 0x0000, 1, 8, 0,
    229 	},
    230 	/* Line in Volume */
    231 	{ AudioCinputs,		AudioNline,	NULL,
    232 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    233 	  AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
    234 	},
    235 	/* CD Volume */
    236 	{ AudioCinputs,		AudioNcd,	NULL,
    237 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    238 	  AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
    239 	},
    240 	/* Video Volume */
    241 	{ AudioCinputs,		AudioNvideo,	NULL,
    242 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    243 	  AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
    244 	},
    245 	/* AUX volume */
    246 	{ AudioCinputs,		AudioNaux,	NULL,
    247 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    248 	  AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
    249 	},
    250 	/* PCM out volume */
    251 	{ AudioCinputs,		AudioNdac,	NULL,
    252 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    253 	  AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
    254 	},
    255 	/* Record Source - some logic for this is hard coded - see below */
    256 	{ AudioCrecord,		AudioNsource,	NULL,
    257 	  AUDIO_MIXER_ENUM, WRAP(ac97_source),
    258 	  AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
    259 	},
    260 	/* Record Gain */
    261 	{ AudioCrecord,		AudioNvolume,	NULL,
    262 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    263 	  AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
    264 	},
    265 	/* Record Gain mic */
    266 	{ AudioCrecord,		AudioNmicrophone, NULL,
    267 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    268 	  AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
    269 	},
    270 	/* */
    271 	{ AudioCoutputs,	AudioNloudness,	NULL,
    272 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    273 	  AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
    274 	},
    275 	{ AudioCoutputs,	AudioNspatial,	NULL,
    276 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    277 	  AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
    278 	},
    279 	{ AudioCoutputs,	AudioNspatial,	"center",
    280 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    281 	  AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
    282 	},
    283 	{ AudioCoutputs,	AudioNspatial,	"depth",
    284 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    285 	  AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
    286 	},
    287 
    288 	/* Missing features: Simulated Stereo, POP, Loopback mode */
    289 } ;
    290 
    291 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
    292 
    293 /*
    294  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
    295  * information on AC-97
    296  */
    297 
    298 struct ac97_softc {
    299 	/* ac97_codec_if must be at the first of ac97_softc. */
    300 	struct ac97_codec_if codec_if;
    301 
    302 	struct ac97_host_if *host_if;
    303 
    304 #define MAX_SOURCES	(2 * SOURCE_INFO_SIZE)
    305 	struct ac97_source_info source_info[MAX_SOURCES];
    306 	int num_source_info;
    307 
    308 	enum ac97_host_flags host_flags;
    309 	unsigned int ac97_clock; /* usually 48000 */
    310 #define AC97_STANDARD_CLOCK	48000U
    311 	u_int16_t caps;		/* -> AC97_REG_RESET */
    312 	u_int16_t ext_id;	/* -> AC97_REG_EXT_AUDIO_ID */
    313 	u_int16_t shadow_reg[128];
    314 };
    315 
    316 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
    317 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
    318 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
    319 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, const char *,
    320 				  const char *, const char *));
    321 void ac97_restore_shadow __P((struct ac97_codec_if *self));
    322 int ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
    323 void ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
    324 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
    325 int ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src);
    326 
    327 static void ac97_alc650_init(struct ac97_softc *);
    328 static void ac97_vt1616_init(struct ac97_softc *);
    329 
    330 struct ac97_codec_if_vtbl ac97civ = {
    331 	ac97_mixer_get_port,
    332 	ac97_mixer_set_port,
    333 	ac97_query_devinfo,
    334 	ac97_get_portnum_by_name,
    335 	ac97_restore_shadow,
    336 	ac97_get_extcaps,
    337 	ac97_set_rate,
    338 	ac97_set_clock,
    339 };
    340 
    341 static const struct ac97_codecid {
    342 	u_int32_t id;
    343 	u_int32_t mask;
    344 	const char *name;
    345 	void (*init)(struct ac97_softc *);
    346 } ac97codecid[] = {
    347 	{ AC97_CODEC_ID('A', 'D', 'S', 3),
    348 	  0xffffffff,			"Analog Devices AD1819B" },
    349 	{ AC97_CODEC_ID('A', 'D', 'S', 0x40),
    350 	  0xffffffff,			"Analog Devices AD1881" },
    351 	{ AC97_CODEC_ID('A', 'D', 'S', 0x48),
    352 	  0xffffffff,			"Analog Devices AD1881A" },
    353 	{ AC97_CODEC_ID('A', 'D', 'S', 0x60),
    354 	  0xffffffff,			"Analog Devices AD1885" },
    355 	{ AC97_CODEC_ID('A', 'D', 'S', 0x61),
    356 	  0xffffffff,			"Analog Devices AD1886" },
    357 	{ AC97_CODEC_ID('A', 'D', 'S', 0x63),
    358 	  0xffffffff,			"Analog Devices AD1886A" },
    359 	{ AC97_CODEC_ID('A', 'D', 'S', 0x72),
    360 	  0xffffffff,			"Analog Devices AD1981A" },
    361 	{ AC97_CODEC_ID('A', 'D', 'S', 0),
    362 	  AC97_VENDOR_ID_MASK,		"Analog Devices unknown" },
    363 
    364 	/*
    365 	 * Datasheets:
    366 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4541/ek4541.pdf
    367 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4543/ek4543.pdf
    368 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4544a/ek4544a.pdf
    369 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4545/ek4545.pdf
    370 	 */
    371 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    372 	  0xffffffff,			"Asahi Kasei AK4540"	},
    373 	{ AC97_CODEC_ID('A', 'K', 'M', 1),
    374 	  0xffffffff,			"Asahi Kasei AK4542"	},
    375 	{ AC97_CODEC_ID('A', 'K', 'M', 2),
    376 	  0xffffffff,			"Asahi Kasei AK4541/AK4543" },
    377 	{ AC97_CODEC_ID('A', 'K', 'M', 5),
    378 	  0xffffffff,			"Asahi Kasei AK4544" },
    379 	{ AC97_CODEC_ID('A', 'K', 'M', 6),
    380 	  0xffffffff,			"Asahi Kasei AK4544A" },
    381 	{ AC97_CODEC_ID('A', 'K', 'M', 7),
    382 	  0xffffffff,			"Asahi Kasei AK4545" },
    383 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    384 	  AC97_VENDOR_ID_MASK,		"Asahi Kasei unknown" },
    385 
    386 	/*
    387 	 * Realtek & Avance Logic
    388 	 *	http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
    389 	 */
    390 	{ AC97_CODEC_ID('A', 'L', 'C', 0x00),
    391 	  0xfffffff0,			"Realtek RL5306"	},
    392 	{ AC97_CODEC_ID('A', 'L', 'C', 0x10),
    393 	  0xfffffff0,			"Realtek RL5382"	},
    394 	{ AC97_CODEC_ID('A', 'L', 'C', 0x20),
    395 	  0xfffffff0,			"Realtek RL5383/RL5522/ALC100"	},
    396 	{ AC97_CODEC_ID('A', 'L', 'G', 0x10),
    397 	  0xffffffff,			"Avance Logic ALC200/ALC201"	},
    398 	{ AC97_CODEC_ID('A', 'L', 'G', 0x20),
    399 	  0xffffffff,			"Avance Logic ALC650", ac97_alc650_init },
    400 	{ AC97_CODEC_ID('A', 'L', 'G', 0x30),
    401 	  0xffffffff,			"Avance Logic ALC101"	},
    402 	{ AC97_CODEC_ID('A', 'L', 'G', 0x40),
    403 	  0xffffffff,			"Avance Logic ALC202"	},
    404 	{ AC97_CODEC_ID('A', 'L', 'G', 0x50),
    405 	  0xffffffff,			"Avance Logic ALC250"	},
    406 	{ AC97_CODEC_ID('A', 'L', 'C', 0),
    407 	  AC97_VENDOR_ID_MASK,		"Realtek unknown"	},
    408 	{ AC97_CODEC_ID('A', 'L', 'G', 0),
    409 	  AC97_VENDOR_ID_MASK,		"Avance Logic unknown"	},
    410 
    411 	/* Cirrus Logic, Crystal series:
    412 	 *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
    413 	 *              0x1[0-7]  - CS4297A
    414 	 *              0x2[0-7]  - CS4298
    415 	 *              0x2[8-f]  - CS4294
    416 	 *              0x3[0-7]  - CS4299
    417 	 *              0x4[8-f]  - CS4201
    418 	 *              0x5[8-f]  - CS4205
    419 	 *              0x6[0-7]  - CS4291
    420 	 *              0x7[0-7]  - CS4202
    421 	 * Datasheets:
    422 	 *	http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
    423 	 *	http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
    424 	 *	http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
    425 	 *	http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
    426 	 *	http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
    427 	 *	http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
    428 	 */
    429 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x00),
    430 	  0xfffffff8,			"Crystal CS4297",	},
    431 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x10),
    432 	  0xfffffff8,			"Crystal CS4297A",	},
    433 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x20),
    434 	  0xfffffff8,			"Crystal CS4298",	},
    435 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x28),
    436 	  0xfffffff8,			"Crystal CS4294",	},
    437 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x30),
    438 	  0xfffffff8,			"Crystal CS4299",	},
    439 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x48),
    440 	  0xfffffff8,			"Crystal CS4201",	},
    441 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x58),
    442 	  0xfffffff8,			"Crystal CS4205",	},
    443 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x60),
    444 	  0xfffffff8,			"Crystal CS4291",	},
    445 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x70),
    446 	  0xfffffff8,			"Crystal CS4202",	},
    447 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),
    448 	  AC97_VENDOR_ID_MASK,		"Cirrus Logic unknown",	},
    449 
    450 	{ 0x45838308, 0xffffffff,	"ESS Technology ES1921", },
    451 	{ 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", },
    452 
    453 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    454 	  0xffffffff,			"Intersil HMP9701",	},
    455 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    456 	  AC97_VENDOR_ID_MASK,		"Intersil unknown",	},
    457 
    458 	/*
    459 	 * IC Ensemble (VIA)
    460 	 *	http://www.viatech.com/en/datasheet/DS1616.pdf
    461 	 */
    462 	{ AC97_CODEC_ID('I', 'C', 'E', 0x01),
    463 	  0xffffffff,			"ICEnsemble ICE1230/VT1611",	},
    464 	{ AC97_CODEC_ID('I', 'C', 'E', 0x11),
    465 	  0xffffffff,			"ICEnsemble ICE1232/VT1611A",	},
    466 	{ AC97_CODEC_ID('I', 'C', 'E', 0x14),
    467 	  0xffffffff,			"ICEnsemble ICE1232A",	},
    468 	{ AC97_CODEC_ID('I', 'C', 'E', 0x51),
    469 	  0xffffffff,			"VIA Technologies VT1616", ac97_vt1616_init },
    470 	{ AC97_CODEC_ID('I', 'C', 'E', 0),
    471 	  AC97_VENDOR_ID_MASK,		"ICEnsemble unknown",	},
    472 
    473 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    474 	  0xffffffff,			"National Semiconductor LM454[03568]", },
    475 	{ AC97_CODEC_ID('N', 'S', 'C', 49),
    476 	  0xffffffff,			"National Semiconductor LM4549", },
    477 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    478 	  AC97_VENDOR_ID_MASK,		"National Semiconductor unknown", },
    479 
    480 	{ AC97_CODEC_ID('S', 'I', 'L', 34),
    481 	  0xffffffff,			"Silicon Laboratory Si3036", },
    482 	{ AC97_CODEC_ID('S', 'I', 'L', 35),
    483 	  0xffffffff,			"Silicon Laboratory Si3038", },
    484 	{ AC97_CODEC_ID('S', 'I', 'L', 0),
    485 	  AC97_VENDOR_ID_MASK,		"Silicon Laboratory unknown", },
    486 
    487 	{ AC97_CODEC_ID('T', 'R', 'A', 2),
    488 	  0xffffffff,			"TriTech TR28022",	},
    489 	{ AC97_CODEC_ID('T', 'R', 'A', 3),
    490 	  0xffffffff,			"TriTech TR28023",	},
    491 	{ AC97_CODEC_ID('T', 'R', 'A', 6),
    492 	  0xffffffff,			"TriTech TR28026",	},
    493 	{ AC97_CODEC_ID('T', 'R', 'A', 8),
    494 	  0xffffffff,			"TriTech TR28028",	},
    495 	{ AC97_CODEC_ID('T', 'R', 'A', 35),
    496 	  0xffffffff,			"TriTech TR28602",	},
    497 	{ AC97_CODEC_ID('T', 'R', 'A', 0),
    498 	  AC97_VENDOR_ID_MASK,		"TriTech unknown",	},
    499 
    500 	{ AC97_CODEC_ID('T', 'X', 'N', 0x20),
    501 	  0xffffffff,			"Texas Instruments TLC320AD9xC", },
    502 	{ AC97_CODEC_ID('T', 'X', 'N', 0),
    503 	  AC97_VENDOR_ID_MASK,		"Texas Instruments unknown", },
    504 
    505 	/*
    506 	 * VIA
    507 	 * http://www.viatech.com/en/multimedia/audio.jsp
    508 	 */
    509 	{ AC97_CODEC_ID('V', 'I', 'A', 0x61),
    510 	  0xffffffff,			"VIA Technologies VT1612A", },
    511 	{ AC97_CODEC_ID('V', 'I', 'A', 0),
    512 	  AC97_VENDOR_ID_MASK,		"VIA Technologies unknown", },
    513 
    514 	{ AC97_CODEC_ID('W', 'E', 'C', 1),
    515 	  0xffffffff,			"Winbond W83971D",	},
    516 	{ AC97_CODEC_ID('W', 'E', 'C', 0),
    517 	  AC97_VENDOR_ID_MASK,		"Winbond unknown",	},
    518 
    519 	/*
    520 	 * http://www.wolfsonmicro.com/product_list.asp?cid=64
    521 	 *	http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
    522 	 *	http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
    523 	 *	http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
    524 	 *	http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
    525 	 *	http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
    526 	 *	http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
    527 	 *	http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
    528 	 *	http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
    529 	 */
    530 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    531 	  0xffffffff,			"Wolfson WM9701A",	},
    532 	{ AC97_CODEC_ID('W', 'M', 'L', 3),
    533 	  0xffffffff,			"Wolfson WM9703/WM9707/WM9708",	},
    534 	{ AC97_CODEC_ID('W', 'M', 'L', 4),
    535 	  0xffffffff,			"Wolfson WM9704",	},
    536 	{ AC97_CODEC_ID('W', 'M', 'L', 5),
    537 	  0xffffffff,			"Wolfson WM9705/WM9710", },
    538 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    539 	  AC97_VENDOR_ID_MASK,		"Wolfson unknown",	},
    540 
    541 	/*
    542 	 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
    543 	 * Datasheets:
    544 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
    545 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
    546 	 */
    547 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    548 	  0xffffffff,			"Yamaha YMF743-S",	},
    549 	{ AC97_CODEC_ID('Y', 'M', 'H', 3),
    550 	  0xffffffff,			"Yamaha YMF753-S",	},
    551 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    552 	  AC97_VENDOR_ID_MASK,		"Yamaha unknown",	},
    553 
    554 	/*
    555 	 * http://www.sigmatel.com/products.htm
    556 	 */
    557 	{ 0x83847600, 0xffffffff,	"SigmaTel STAC9700",	},
    558 	{ 0x83847604, 0xffffffff,	"SigmaTel STAC9701/3/4/5", },
    559 	{ 0x83847605, 0xffffffff,	"SigmaTel STAC9704",	},
    560 	{ 0x83847608, 0xffffffff,	"SigmaTel STAC9708",	},
    561 	{ 0x83847609, 0xffffffff,	"SigmaTel STAC9721/23",	},
    562 	{ 0x83847644, 0xffffffff,	"SigmaTel STAC9744/45",	},
    563 	{ 0x83847656, 0xffffffff,	"SigmaTel STAC9756/57",	},
    564 	{ 0x83847684, 0xffffffff,	"SigmaTel STAC9783/84",	},
    565 	{ 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",	},
    566 
    567 	{ 0,
    568 	  0,			NULL,			}
    569 };
    570 
    571 static const char * const ac97enhancement[] = {
    572 	"no 3D stereo",
    573 	"Analog Devices Phat Stereo",
    574 	"Creative",
    575 	"National Semi 3D",
    576 	"Yamaha Ymersion",
    577 	"BBE 3D",
    578 	"Crystal Semi 3D",
    579 	"Qsound QXpander",
    580 	"Spatializer 3D",
    581 	"SRS 3D",
    582 	"Platform Tech 3D",
    583 	"AKM 3D",
    584 	"Aureal",
    585 	"AZTECH 3D",
    586 	"Binaura 3D",
    587 	"ESS Technology",
    588 	"Harman International VMAx",
    589 	"Nvidea 3D",
    590 	"Philips Incredible Sound",
    591 	"Texas Instruments' 3D",
    592 	"VLSI Technology 3D",
    593 	"TriTech 3D",
    594 	"Realtek 3D",
    595 	"Samsung 3D",
    596 	"Wolfson Microelectronics 3D",
    597 	"Delta Integration 3D",
    598 	"SigmaTel 3D",
    599 	"KS Waves 3D",
    600 	"Rockwell 3D",
    601 	"Unknown 3D",
    602 	"Unknown 3D",
    603 	"Unknown 3D",
    604 };
    605 
    606 static const char * const ac97feature[] = {
    607 	"dedicated mic channel",
    608 	"reserved",
    609 	"tone",
    610 	"simulated stereo",
    611 	"headphone",
    612 	"bass boost",
    613 	"18 bit DAC",
    614 	"20 bit DAC",
    615 	"18 bit ADC",
    616 	"20 bit ADC"
    617 };
    618 
    619 
    620 int ac97_str_equal __P((const char *, const char *));
    621 int ac97_check_capability(struct ac97_softc *, int);
    622 void ac97_setup_source_info __P((struct ac97_softc *));
    623 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    624 void ac97_setup_defaults __P((struct ac97_softc *));
    625 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    626 
    627 /* #define AC97_DEBUG 10 */
    628 
    629 #ifdef AUDIO_DEBUG
    630 #define DPRINTF(x)	if (ac97debug) printf x
    631 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    632 #ifdef AC97_DEBUG
    633 int	ac97debug = AC97_DEBUG;
    634 #else
    635 int	ac97debug = 0;
    636 #endif
    637 #else
    638 #define DPRINTF(x)
    639 #define DPRINTFN(n,x)
    640 #endif
    641 
    642 void
    643 ac97_read(as, reg, val)
    644 	struct ac97_softc *as;
    645 	u_int8_t reg;
    646 	u_int16_t *val;
    647 {
    648 	int error;
    649 
    650 	if (as->host_flags & AC97_HOST_DONT_READ &&
    651 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    652 	     reg != AC97_REG_RESET)) {
    653 		*val = as->shadow_reg[reg >> 1];
    654 		return;
    655 	}
    656 
    657 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    658 		*val = as->shadow_reg[reg >> 1];
    659 	}
    660 }
    661 
    662 int
    663 ac97_write(as, reg, val)
    664 	struct ac97_softc *as;
    665 	u_int8_t reg;
    666 	u_int16_t val;
    667 {
    668 
    669 	as->shadow_reg[reg >> 1] = val;
    670 
    671 	return (as->host_if->write(as->host_if->arg, reg, val));
    672 }
    673 
    674 void
    675 ac97_setup_defaults(as)
    676 	struct ac97_softc *as;
    677 {
    678 	int idx;
    679 	const struct ac97_source_info *si;
    680 
    681 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    682 
    683 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    684 		si = &source_info[idx];
    685 		ac97_write(as, si->reg, si->default_value);
    686 	}
    687 }
    688 
    689 void
    690 ac97_restore_shadow(self)
    691 	struct ac97_codec_if *self;
    692 {
    693 	struct ac97_softc *as = (struct ac97_softc *) self;
    694 	int idx;
    695 	const struct ac97_source_info *si;
    696 
    697 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    698 		si = &source_info[idx];
    699 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    700 	}
    701 }
    702 
    703 int
    704 ac97_str_equal(a, b)
    705 	const char *a, *b;
    706 {
    707 	return ((a == b) || (a && b && (!strcmp(a, b))));
    708 }
    709 
    710 int
    711 ac97_check_capability(struct ac97_softc *as, int check)
    712 {
    713 	switch (check) {
    714 	case CHECK_NONE:
    715 		return 1;
    716 	case CHECK_SURROUND:
    717 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
    718 	case CHECK_CENTER:
    719 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
    720 	case CHECK_LFE:
    721 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
    722 	case CHECK_HEADPHONES:
    723 		return as->caps & AC97_CAPS_HEADPHONES;
    724 	case CHECK_TONE:
    725 		return as->caps & AC97_CAPS_TONECTRL;
    726 	case CHECK_MIC:
    727 		return as->caps & AC97_CAPS_MICIN;
    728 	case CHECK_LOUDNESS:
    729 		return as->caps & AC97_CAPS_LOUDNESS;
    730 	case CHECK_3D:
    731 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
    732 	default:
    733 		printf("%s: internal error: feature=%d\n", __func__, check);
    734 		return 0;
    735 	}
    736 }
    737 
    738 void
    739 ac97_setup_source_info(as)
    740 	struct ac97_softc *as;
    741 {
    742 	int idx, ouridx;
    743 	struct ac97_source_info *si, *si2;
    744 
    745 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    746 		si = &as->source_info[ouridx];
    747 
    748 		if (!ac97_check_capability(as, source_info[idx].req_feature))
    749 			continue;
    750 
    751 		memcpy(si, &source_info[idx], sizeof(*si));
    752 
    753 		switch (si->type) {
    754 		case AUDIO_MIXER_CLASS:
    755 		        si->mixer_class = ouridx;
    756 			ouridx++;
    757 			break;
    758 		case AUDIO_MIXER_VALUE:
    759 			/* Todo - Test to see if it works */
    760 			ouridx++;
    761 
    762 			/* Add an entry for mute, if necessary */
    763 			if (si->mute) {
    764 				si = &as->source_info[ouridx];
    765 				memcpy(si, &source_info[idx], sizeof(*si));
    766 				si->qualifier = AudioNmute;
    767 				si->type = AUDIO_MIXER_ENUM;
    768 				si->info = &ac97_on_off;
    769 				si->info_size = sizeof(ac97_on_off);
    770 				si->bits = 1;
    771 				si->ofs = 15;
    772 				si->mute = 0;
    773 				si->polarity = 0;
    774 				ouridx++;
    775 			}
    776 			break;
    777 		case AUDIO_MIXER_ENUM:
    778 			/* Todo - Test to see if it works */
    779 			ouridx++;
    780 			break;
    781 		default:
    782 			printf ("ac97: shouldn't get here\n");
    783 			break;
    784 		}
    785 	}
    786 
    787 	as->num_source_info = ouridx;
    788 
    789 	for (idx = 0; idx < as->num_source_info; idx++) {
    790 		int idx2, previdx;
    791 
    792 		si = &as->source_info[idx];
    793 
    794 		/* Find mixer class */
    795 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    796 			si2 = &as->source_info[idx2];
    797 
    798 			if (si2->type == AUDIO_MIXER_CLASS &&
    799 			    ac97_str_equal(si->class,
    800 					   si2->class)) {
    801 				si->mixer_class = idx2;
    802 			}
    803 		}
    804 
    805 
    806 		/* Setup prev and next pointers */
    807 		if (si->prev != 0)
    808 			continue;
    809 
    810 		if (si->qualifier)
    811 			continue;
    812 
    813 		si->prev = AUDIO_MIXER_LAST;
    814 		previdx = idx;
    815 
    816 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    817 			if (idx2 == idx)
    818 				continue;
    819 
    820 			si2 = &as->source_info[idx2];
    821 
    822 			if (!si2->prev &&
    823 			    ac97_str_equal(si->class, si2->class) &&
    824 			    ac97_str_equal(si->device, si2->device)) {
    825 				as->source_info[previdx].next = idx2;
    826 				as->source_info[idx2].prev = previdx;
    827 
    828 				previdx = idx2;
    829 			}
    830 		}
    831 
    832 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    833 	}
    834 }
    835 
    836 int
    837 ac97_attach(host_if)
    838 	struct ac97_host_if *host_if;
    839 {
    840 	struct ac97_softc *as;
    841 	struct device *sc_dev = (struct device *)host_if->arg;
    842 	int error, i, j;
    843 	u_int32_t id;
    844 	u_int16_t id1, id2;
    845 	u_int16_t extstat, rate;
    846 	mixer_ctrl_t ctl;
    847 	const char *delim;
    848 	void (*initfunc)(struct ac97_softc *);
    849 
    850 	initfunc = NULL;
    851 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    852 
    853 	if (as == NULL)
    854 		return (ENOMEM);
    855 
    856 	as->codec_if.vtbl = &ac97civ;
    857 	as->host_if = host_if;
    858 
    859 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    860 		free(as, M_DEVBUF);
    861 		return (error);
    862 	}
    863 
    864 	host_if->reset(host_if->arg);
    865 
    866 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    867 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    868 
    869 	if (host_if->flags)
    870 		as->host_flags = host_if->flags(host_if->arg);
    871 
    872 	ac97_setup_defaults(as);
    873 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    874 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    875 	ac97_read(as, AC97_REG_RESET, &as->caps);
    876 
    877 	id = (id1 << 16) | id2;
    878 
    879 	printf("%s: ", sc_dev->dv_xname);
    880 
    881 	for (i = 0; ; i++) {
    882 		if (ac97codecid[i].id == 0) {
    883 			char pnp[4];
    884 
    885 			AC97_GET_CODEC_ID(id, pnp);
    886 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    887 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    888 			    ISASCII(pnp[2]))
    889 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    890 				    pnp[3]);
    891 			else
    892 				printf("unknown (0x%08x)", id);
    893 			break;
    894 		}
    895 		if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
    896 			printf("%s", ac97codecid[i].name);
    897 			if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
    898 				printf(" (0x%08x)", id);
    899 			}
    900 			initfunc = ac97codecid[i].init;
    901 			break;
    902 		}
    903 	}
    904 	printf(" codec; ");
    905 	for (i = j = 0; i < 10; i++) {
    906 		if (as->caps & (1 << i)) {
    907 			printf("%s%s", j? ", " : "", ac97feature[i]);
    908 			j++;
    909 		}
    910 	}
    911 	printf("%s%s\n", j ? ", " : "",
    912 	       ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
    913 
    914 	as->ac97_clock = AC97_STANDARD_CLOCK;
    915 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
    916 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
    917 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
    918 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
    919 			  | AC97_EXT_AUDIO_LDAC)) {
    920 		printf("%s:", sc_dev->dv_xname);
    921 		delim = "";
    922 
    923 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
    924 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    925 			printf("%s variable rate audio", delim);
    926 			delim = ",";
    927 			extstat |= AC97_EXT_AUDIO_VRA;
    928 		}
    929 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
    930 			printf("%s double rate output", delim);
    931 			delim = ",";
    932 		}
    933 		extstat &= ~AC97_EXT_AUDIO_DRA;
    934 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
    935 			printf("%s S/PDIF", delim);
    936 			delim = ",";
    937 		}
    938 		if (as->ext_id & AC97_EXT_AUDIO_VRM) {
    939 			printf("%s variable rate dedicated mic", delim);
    940 			delim = ",";
    941 			extstat |= AC97_EXT_AUDIO_VRM;
    942 		}
    943 		if (as->ext_id & AC97_EXT_AUDIO_CDAC) {
    944 			printf("%s center DAC", delim);
    945 			delim = ",";
    946 			extstat |= AC97_EXT_AUDIO_CDAC;
    947 		}
    948 		if (as->ext_id & AC97_EXT_AUDIO_SDAC) {
    949 			printf("%s surround DAC", delim);
    950 			delim = ",";
    951 			extstat |= AC97_EXT_AUDIO_SDAC;
    952 		}
    953 		if (as->ext_id & AC97_EXT_AUDIO_LDAC) {
    954 			printf("%s LFE DAC", delim);
    955 			extstat |= AC97_EXT_AUDIO_LDAC;
    956 		}
    957 		printf("\n");
    958 
    959 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
    960 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    961 			/* VRA should be enabled. */
    962 			/* so it claims to do variable rate, let's make sure */
    963 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
    964 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
    965 			if (rate != 44100) {
    966 				/* We can't believe ext_id */
    967 				as->ext_id = 0;
    968 				printf("%s: Ignore these capabilities.\n",
    969 				       sc_dev->dv_xname);
    970 			}
    971 			/* restore the default value */
    972 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
    973 				   AC97_SINGLE_RATE);
    974 		}
    975 	}
    976 
    977 	ac97_setup_source_info(as);
    978 
    979 	DELAY(900 * 1000);
    980 	memset(&ctl, 0, sizeof(ctl));
    981 
    982 	/* disable mutes */
    983 	for (i = 0; i < 11; i++) {
    984 		static struct {
    985 			char *class, *device;
    986 		} d[11] = {
    987 			{ AudioCoutputs, AudioNmaster},
    988 			{ AudioCoutputs, AudioNheadphone},
    989 			{ AudioCoutputs, AudioNsurround},
    990 			{ AudioCoutputs, AudioNcenter},
    991 			{ AudioCoutputs, AudioNlfe},
    992 			{ AudioCinputs, AudioNdac},
    993 			{ AudioCinputs, AudioNcd},
    994 			{ AudioCinputs, AudioNline},
    995 			{ AudioCinputs, AudioNaux},
    996 			{ AudioCinputs, AudioNvideo},
    997 			{ AudioCrecord, AudioNvolume},
    998 		};
    999 
   1000 		ctl.type = AUDIO_MIXER_ENUM;
   1001 		ctl.un.ord = 0;
   1002 
   1003 		ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
   1004 			d[i].class, d[i].device, AudioNmute);
   1005 		ac97_mixer_set_port(&as->codec_if, &ctl);
   1006 	}
   1007 	ctl.type = AUDIO_MIXER_ENUM;
   1008 	ctl.un.ord = 0;
   1009 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
   1010 					   AudioNsource, NULL);
   1011 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1012 
   1013 	/* set a reasonable default volume */
   1014 	ctl.type = AUDIO_MIXER_VALUE;
   1015 	ctl.un.value.num_channels = 2;
   1016 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
   1017 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
   1018 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1019 					   AudioNmaster, NULL);
   1020 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1021 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1022 					   AudioNsurround, NULL);
   1023 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1024 	ctl.un.value.num_channels = 1;
   1025 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1026 					   AudioNcenter, NULL);
   1027 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1028 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1029 					   AudioNlfe, NULL);
   1030 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1031 
   1032 	if (initfunc != NULL)
   1033 		initfunc(as);
   1034 	return (0);
   1035 }
   1036 
   1037 
   1038 int
   1039 ac97_query_devinfo(codec_if, dip)
   1040 	struct ac97_codec_if *codec_if;
   1041 	mixer_devinfo_t *dip;
   1042 {
   1043 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1044 
   1045 	if (dip->index < as->num_source_info) {
   1046 		struct ac97_source_info *si = &as->source_info[dip->index];
   1047 		const char *name;
   1048 
   1049 		dip->type = si->type;
   1050 		dip->mixer_class = si->mixer_class;
   1051 		dip->prev = si->prev;
   1052 		dip->next = si->next;
   1053 
   1054 		if (si->qualifier)
   1055 			name = si->qualifier;
   1056 		else if (si->device)
   1057 			name = si->device;
   1058 		else if (si->class)
   1059 			name = si->class;
   1060 		else
   1061 			name = 0;
   1062 
   1063 		if (name)
   1064 			strcpy(dip->label.name, name);
   1065 
   1066 		memcpy(&dip->un, si->info, si->info_size);
   1067 
   1068 		/* Set the delta for volume sources */
   1069 		if (dip->type == AUDIO_MIXER_VALUE)
   1070 			dip->un.v.delta = 1 << (8 - si->bits);
   1071 
   1072 		return (0);
   1073 	}
   1074 
   1075 	return (ENXIO);
   1076 }
   1077 
   1078 
   1079 
   1080 int
   1081 ac97_mixer_set_port(codec_if, cp)
   1082 	struct ac97_codec_if *codec_if;
   1083 	mixer_ctrl_t *cp;
   1084 {
   1085 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1086 	struct ac97_source_info *si = &as->source_info[cp->dev];
   1087 	u_int16_t mask;
   1088 	u_int16_t val, newval;
   1089 	int error;
   1090 
   1091 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1092 		return (EINVAL);
   1093 
   1094 	if (cp->type != si->type)
   1095 		return (EINVAL);
   1096 
   1097 	ac97_read(as, si->reg, &val);
   1098 
   1099 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1100 
   1101 	mask = (1 << si->bits) - 1;
   1102 
   1103 	switch (cp->type) {
   1104 	case AUDIO_MIXER_ENUM:
   1105 		if (cp->un.ord > mask || cp->un.ord < 0)
   1106 			return (EINVAL);
   1107 
   1108 		newval = (cp->un.ord << si->ofs);
   1109 		if (si->reg == AC97_REG_RECORD_SELECT) {
   1110 			newval |= (newval << (8 + si->ofs));
   1111 			mask |= (mask << 8);
   1112 			mask = mask << si->ofs;
   1113 		} else if (si->reg == AC97_REG_SURR_MASTER) {
   1114 			newval = cp->un.ord ? 0x8080 : 0x0000;
   1115 			mask = 0x8080;
   1116 		} else
   1117 			mask = mask << si->ofs;
   1118 		break;
   1119 	case AUDIO_MIXER_VALUE:
   1120 	{
   1121 		const struct audio_mixer_value *value = si->info;
   1122 		u_int16_t  l, r;
   1123 
   1124 		if ((cp->un.value.num_channels <= 0) ||
   1125 		    (cp->un.value.num_channels > value->num_channels))
   1126 			return (EINVAL);
   1127 
   1128 		if (cp->un.value.num_channels == 1) {
   1129 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
   1130 		} else {
   1131 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1132 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1133 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1134 			} else {	/* left/right is reversed here */
   1135 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1136 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1137 			}
   1138 
   1139 		}
   1140 
   1141 		if (!si->polarity) {
   1142 			l = 255 - l;
   1143 			r = 255 - r;
   1144 		}
   1145 
   1146 		l = l >> (8 - si->bits);
   1147 		r = r >> (8 - si->bits);
   1148 
   1149 		newval = ((l & mask) << si->ofs);
   1150 		if (value->num_channels == 2) {
   1151 			newval |= ((r & mask) << (si->ofs + 8));
   1152 			mask |= (mask << 8);
   1153 		}
   1154 		mask = mask << si->ofs;
   1155 		break;
   1156 	}
   1157 	default:
   1158 		return (EINVAL);
   1159 	}
   1160 
   1161 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
   1162 	if (error)
   1163 		return (error);
   1164 
   1165 	return (0);
   1166 }
   1167 
   1168 int
   1169 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
   1170 	struct ac97_codec_if *codec_if;
   1171 	const char *class, *device, *qualifier;
   1172 {
   1173 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1174 	int idx;
   1175 
   1176 	for (idx = 0; idx < as->num_source_info; idx++) {
   1177 		struct ac97_source_info *si = &as->source_info[idx];
   1178 		if (ac97_str_equal(class, si->class) &&
   1179 		    ac97_str_equal(device, si->device) &&
   1180 		    ac97_str_equal(qualifier, si->qualifier))
   1181 			return (idx);
   1182 	}
   1183 
   1184 	return (-1);
   1185 }
   1186 
   1187 int
   1188 ac97_mixer_get_port(codec_if, cp)
   1189 	struct ac97_codec_if *codec_if;
   1190 	mixer_ctrl_t *cp;
   1191 {
   1192 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1193 	struct ac97_source_info *si = &as->source_info[cp->dev];
   1194 	u_int16_t mask;
   1195 	u_int16_t val;
   1196 
   1197 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1198 		return (EINVAL);
   1199 
   1200 	if (cp->type != si->type)
   1201 		return (EINVAL);
   1202 
   1203 	ac97_read(as, si->reg, &val);
   1204 
   1205 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1206 
   1207 	mask = (1 << si->bits) - 1;
   1208 
   1209 	switch (cp->type) {
   1210 	case AUDIO_MIXER_ENUM:
   1211 		cp->un.ord = (val >> si->ofs) & mask;
   1212 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
   1213 		break;
   1214 	case AUDIO_MIXER_VALUE:
   1215 	{
   1216 		const struct audio_mixer_value *value = si->info;
   1217 		u_int16_t  l, r;
   1218 
   1219 		if ((cp->un.value.num_channels <= 0) ||
   1220 		    (cp->un.value.num_channels > value->num_channels))
   1221 			return (EINVAL);
   1222 
   1223 		if (value->num_channels == 1) {
   1224 			l = r = (val >> si->ofs) & mask;
   1225 		} else {
   1226 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1227 				l = (val >> si->ofs) & mask;
   1228 				r = (val >> (si->ofs + 8)) & mask;
   1229 			} else {	/* host has reversed channels */
   1230 				r = (val >> si->ofs) & mask;
   1231 				l = (val >> (si->ofs + 8)) & mask;
   1232 			}
   1233 		}
   1234 
   1235 		l = (l << (8 - si->bits));
   1236 		r = (r << (8 - si->bits));
   1237 		if (!si->polarity) {
   1238 			l = 255 - l;
   1239 			r = 255 - r;
   1240 		}
   1241 
   1242 		/* The EAP driver averages l and r for stereo
   1243 		   channels that are requested in MONO mode. Does this
   1244 		   make sense? */
   1245 		if (cp->un.value.num_channels == 1) {
   1246 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
   1247 		} else if (cp->un.value.num_channels == 2) {
   1248 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
   1249 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
   1250 		}
   1251 
   1252 		break;
   1253 	}
   1254 	default:
   1255 		return (EINVAL);
   1256 	}
   1257 
   1258 	return (0);
   1259 }
   1260 
   1261 
   1262 int
   1263 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
   1264 {
   1265 	struct ac97_softc *as;
   1266 	u_long value;
   1267 	u_int16_t ext_stat;
   1268 	u_int16_t actual;
   1269 	u_int16_t power;
   1270 	u_int16_t power_bit;
   1271 
   1272 	as = (struct ac97_softc *)codec_if;
   1273 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
   1274 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1275 			*rate = AC97_SINGLE_RATE;
   1276 			return 0;
   1277 		}
   1278 	} else {
   1279 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1280 			*rate = AC97_SINGLE_RATE;
   1281 			return 0;
   1282 		}
   1283 	}
   1284 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
   1285 	ext_stat = 0;
   1286 	/*
   1287 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
   1288 	 *	Check VRA, DRA
   1289 	 * PCM_LR_ADC_RATE
   1290 	 *	Check VRA
   1291 	 * PCM_MIC_ADC_RATE
   1292 	 *	Check VRM
   1293 	 */
   1294 	switch (target) {
   1295 	case AC97_REG_PCM_FRONT_DAC_RATE:
   1296 	case AC97_REG_PCM_SURR_DAC_RATE:
   1297 	case AC97_REG_PCM_LFE_DAC_RATE:
   1298 		power_bit = AC97_POWER_OUT;
   1299 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1300 			*rate = AC97_SINGLE_RATE;
   1301 			return 0;
   1302 		}
   1303 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1304 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1305 			if (value > 0x1ffff) {
   1306 				return EINVAL;
   1307 			} else if (value > 0xffff) {
   1308 				/* Enable DRA */
   1309 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1310 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1311 				value /= 2;
   1312 			} else {
   1313 				/* Disable DRA */
   1314 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1315 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1316 			}
   1317 		} else {
   1318 			if (value > 0xffff)
   1319 				return EINVAL;
   1320 		}
   1321 		break;
   1322 	case AC97_REG_PCM_LR_ADC_RATE:
   1323 		power_bit = AC97_POWER_IN;
   1324 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1325 			*rate = AC97_SINGLE_RATE;
   1326 			return 0;
   1327 		}
   1328 		if (value > 0xffff)
   1329 			return EINVAL;
   1330 		break;
   1331 	case AC97_REG_PCM_MIC_ADC_RATE:
   1332 		power_bit = AC97_POWER_IN;
   1333 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1334 			*rate = AC97_SINGLE_RATE;
   1335 			return 0;
   1336 		}
   1337 		if (value > 0xffff)
   1338 			return EINVAL;
   1339 		break;
   1340 	default:
   1341 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   1342 		return EINVAL;
   1343 	}
   1344 
   1345 	ac97_read(as, AC97_REG_POWER, &power);
   1346 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   1347 
   1348 	ac97_write(as, target, (u_int16_t)value);
   1349 	ac97_read(as, target, &actual);
   1350 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   1351 
   1352 	ac97_write(as, AC97_REG_POWER, power);
   1353 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   1354 		*rate = actual * 2;
   1355 	} else {
   1356 		*rate = actual;
   1357 	}
   1358 	return 0;
   1359 }
   1360 
   1361 void
   1362 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   1363 {
   1364 	struct ac97_softc *as;
   1365 
   1366 	as = (struct ac97_softc *)codec_if;
   1367 	as->ac97_clock = clock;
   1368 }
   1369 
   1370 u_int16_t
   1371 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   1372 {
   1373 	struct ac97_softc *as;
   1374 
   1375 	as = (struct ac97_softc *)codec_if;
   1376 	return as->ext_id;
   1377 }
   1378 
   1379 int
   1380 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
   1381 {
   1382 	struct ac97_source_info *si;
   1383 	int ouridx, idx;
   1384 
   1385 	if (as->num_source_info >= MAX_SOURCES) {
   1386 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
   1387 		       __func__, __FILE__);
   1388 		return -1;
   1389 	}
   1390 	if (!ac97_check_capability(as, src->req_feature))
   1391 		return -1;
   1392 	ouridx = as->num_source_info;
   1393 	si = &as->source_info[ouridx];
   1394 	memcpy(si, src, sizeof(*si));
   1395 
   1396 	switch (si->type) {
   1397 	case AUDIO_MIXER_CLASS:
   1398 	case AUDIO_MIXER_VALUE:
   1399 		printf("%s: adding class/value is not supported yet.\n",
   1400 		       __func__);
   1401 		return -1;
   1402 	case AUDIO_MIXER_ENUM:
   1403 		break;
   1404 	default:
   1405 		printf("%s: unknown type: %d\n", __func__, si->type);
   1406 		return -1;
   1407 	}
   1408 	as->num_source_info++;
   1409 
   1410 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
   1411 						   NULL, NULL);
   1412 	/* Find the root of the device */
   1413 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
   1414 				       si->device, NULL);
   1415 	/* Find the last item */
   1416 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
   1417 		idx = as->source_info[idx].next;
   1418 	/* Append */
   1419 	as->source_info[idx].next = ouridx;
   1420 	si->prev = idx;
   1421 	si->next = AUDIO_MIXER_LAST;
   1422 
   1423 	return 0;
   1424 }
   1425 
   1426 #define ALC650_REG_MULTI_CHANNEL_CONTROL	0x6a
   1427 #define		ALC650_MCC_SLOT_MODIFY_MASK		0xc000
   1428 #define		ALC650_MCC_FRONTDAC_FROM_SPDIFIN	0x2000 /* 13 */
   1429 #define		ALC650_MCC_SPDIFOUT_FROM_ADC		0x1000 /* 12 */
   1430 #define		ALC650_MCC_PCM_FROM_SPDIFIN		0x0800 /* 11 */
   1431 #define		ALC650_MCC_MIC_OR_CENTERLFE		0x0400 /* 10 */
   1432 #define		ALC650_MCC_LINEIN_OR_SURROUND		0x0200 /* 9 */
   1433 #define		ALC650_MCC_INDEPENDENT_MASTER_L		0x0080 /* 7 */
   1434 #define		ALC650_MCC_INDEPENDENT_MASTER_R		0x0040 /* 6 */
   1435 #define		ALC650_MCC_ANALOG_TO_CENTERLFE		0x0020 /* 5 */
   1436 #define		ALC650_MCC_ANALOG_TO_SURROUND		0x0010 /* 4 */
   1437 #define		ALC650_MCC_EXCHANGE_CENTERLFE		0x0008 /* 3 */
   1438 #define		ALC650_MCC_CENTERLFE_DOWNMIX		0x0004 /* 2 */
   1439 #define		ALC650_MCC_SURROUND_DOWNMIX		0x0002 /* 1 */
   1440 #define		ALC650_MCC_LINEOUT_TO_SURROUND		0x0001 /* 0 */
   1441 static void
   1442 ac97_alc650_init(struct ac97_softc *as)
   1443 {
   1444 	static const struct ac97_source_info sources[6] = {
   1445 		{ AudioCoutputs, AudioNsurround, "lineinjack",
   1446 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1447 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1448 		  0x0000, 1, 9, 0, 0, CHECK_SURROUND },
   1449 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   1450 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1451 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1452 		  0x0000, 1, 1, 0, 0, CHECK_SURROUND },
   1453 		{ AudioCoutputs, AudioNcenter, "micjack",
   1454 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1455 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1456 		  0x0000, 1, 10, 0, 0, CHECK_CENTER },
   1457 		{ AudioCoutputs, AudioNlfe, "micjack",
   1458 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1459 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1460 		  0x0000, 1, 10, 0, 0, CHECK_LFE },
   1461 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   1462 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1463 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1464 		  0x0000, 1, 2, 0, 0, CHECK_CENTER },
   1465 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   1466 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1467 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1468 		  0x0000, 1, 2, 0, 0, CHECK_LFE },
   1469 	};
   1470 
   1471 	ac97_add_port(as, &sources[0]);
   1472 	ac97_add_port(as, &sources[1]);
   1473 	ac97_add_port(as, &sources[2]);
   1474 	ac97_add_port(as, &sources[3]);
   1475 	ac97_add_port(as, &sources[4]);
   1476 	ac97_add_port(as, &sources[5]);
   1477 }
   1478 
   1479 #define VT1616_REG_IO_CONTROL	0x5a
   1480 #define		VT1616_IC_LVL			(1 << 15)
   1481 #define		VT1616_IC_LFECENTER_TO_FRONT	(1 << 12)
   1482 #define		VT1616_IC_SURROUND_TO_FRONT	(1 << 11)
   1483 #define		VT1616_IC_BPDC			(1 << 10)
   1484 #define		VT1616_IC_DC			(1 << 9)
   1485 #define		VT1616_IC_IB_MASK		0x000c
   1486 static void
   1487 ac97_vt1616_init(struct ac97_softc *as)
   1488 {
   1489 	static const struct ac97_source_info sources[3] = {
   1490 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   1491 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1492 		  VT1616_REG_IO_CONTROL,
   1493 		  0x0000, 1, 11, 0, 0, CHECK_SURROUND },
   1494 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   1495 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1496 		  VT1616_REG_IO_CONTROL,
   1497 		  0x0000, 1, 12, 0, 0, CHECK_CENTER },
   1498 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   1499 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1500 		  VT1616_REG_IO_CONTROL,
   1501 		  0x0000, 1, 12, 0, 0, CHECK_LFE },
   1502 	};
   1503 
   1504 	ac97_add_port(as, &sources[0]);
   1505 	ac97_add_port(as, &sources[1]);
   1506 	ac97_add_port(as, &sources[2]);
   1507 }
   1508 
   1509