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