Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.34
      1 /*      $NetBSD: ac97.c,v 1.34 2002/10/16 16:38:25 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.34 2002/10/16 16:38:25 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 
    329 struct ac97_codec_if_vtbl ac97civ = {
    330 	ac97_mixer_get_port,
    331 	ac97_mixer_set_port,
    332 	ac97_query_devinfo,
    333 	ac97_get_portnum_by_name,
    334 	ac97_restore_shadow,
    335 	ac97_get_extcaps,
    336 	ac97_set_rate,
    337 	ac97_set_clock,
    338 };
    339 
    340 static const struct ac97_codecid {
    341 	u_int32_t id;
    342 	u_int32_t mask;
    343 	const char *name;
    344 	void (*init)(struct ac97_softc *);
    345 } ac97codecid[] = {
    346 	{ AC97_CODEC_ID('A', 'D', 'S', 3),
    347 	  0xffffffff,			"Analog Devices AD1819B" },
    348 	{ AC97_CODEC_ID('A', 'D', 'S', 0x40),
    349 	  0xffffffff,			"Analog Devices AD1881" },
    350 	{ AC97_CODEC_ID('A', 'D', 'S', 0x48),
    351 	  0xffffffff,			"Analog Devices AD1881A" },
    352 	{ AC97_CODEC_ID('A', 'D', 'S', 0x60),
    353 	  0xffffffff,			"Analog Devices AD1885" },
    354 	{ AC97_CODEC_ID('A', 'D', 'S', 0x61),
    355 	  0xffffffff,			"Analog Devices AD1886" },
    356 	{ AC97_CODEC_ID('A', 'D', 'S', 0x63),
    357 	  0xffffffff,			"Analog Devices AD1886A" },
    358 	{ AC97_CODEC_ID('A', 'D', 'S', 0x72),
    359 	  0xffffffff,			"Analog Devices AD1981A" },
    360 	{ AC97_CODEC_ID('A', 'D', 'S', 0),
    361 	  AC97_VENDOR_ID_MASK,		"Analog Devices unknown" },
    362 
    363 	/*
    364 	 * Datasheets:
    365 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4541/ek4541.pdf
    366 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4543/ek4543.pdf
    367 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4544a/ek4544a.pdf
    368 	 *	http://www.asahi-kasei.co.jp/akm/usa/product/ak4545/ek4545.pdf
    369 	 */
    370 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    371 	  0xffffffff,			"Asahi Kasei AK4540"	},
    372 	{ AC97_CODEC_ID('A', 'K', 'M', 1),
    373 	  0xffffffff,			"Asahi Kasei AK4542"	},
    374 	{ AC97_CODEC_ID('A', 'K', 'M', 2),
    375 	  0xffffffff,			"Asahi Kasei AK4541/AK4543" },
    376 	{ AC97_CODEC_ID('A', 'K', 'M', 5),
    377 	  0xffffffff,			"Asahi Kasei AK4544" },
    378 	{ AC97_CODEC_ID('A', 'K', 'M', 6),
    379 	  0xffffffff,			"Asahi Kasei AK4544A" },
    380 	{ AC97_CODEC_ID('A', 'K', 'M', 7),
    381 	  0xffffffff,			"Asahi Kasei AK4545" },
    382 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    383 	  AC97_VENDOR_ID_MASK,		"Asahi Kasei unknown" },
    384 
    385 	/*
    386 	 * Realtek & Avance Logic
    387 	 *	http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
    388 	 */
    389 	{ AC97_CODEC_ID('A', 'L', 'C', 0x00),
    390 	  0xfffffff0,			"Realtek RL5306"	},
    391 	{ AC97_CODEC_ID('A', 'L', 'C', 0x10),
    392 	  0xfffffff0,			"Realtek RL5382"	},
    393 	{ AC97_CODEC_ID('A', 'L', 'C', 0x20),
    394 	  0xfffffff0,			"Realtek RL5383/RL5522/ALC100"	},
    395 	{ AC97_CODEC_ID('A', 'L', 'G', 0x10),
    396 	  0xffffffff,			"Avance Logic ALC200/ALC201"	},
    397 	{ AC97_CODEC_ID('A', 'L', 'G', 0x20),
    398 	  0xffffffff,			"Avance Logic ALC650", ac97_alc650_init },
    399 	{ AC97_CODEC_ID('A', 'L', 'G', 0x30),
    400 	  0xffffffff,			"Avance Logic ALC101"	},
    401 	{ AC97_CODEC_ID('A', 'L', 'G', 0x40),
    402 	  0xffffffff,			"Avance Logic ALC202"	},
    403 	{ AC97_CODEC_ID('A', 'L', 'G', 0x50),
    404 	  0xffffffff,			"Avance Logic ALC250"	},
    405 	{ AC97_CODEC_ID('A', 'L', 'C', 0),
    406 	  AC97_VENDOR_ID_MASK,		"Realtek unknown"	},
    407 	{ AC97_CODEC_ID('A', 'L', 'G', 0),
    408 	  AC97_VENDOR_ID_MASK,		"Avance Logic unknown"	},
    409 
    410 	/* Cirrus Logic, Crystal series:
    411 	 *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
    412 	 *              0x1[0-7]  - CS4297A
    413 	 *              0x2[0-7]  - CS4298
    414 	 *              0x2[8-f]  - CS4294
    415 	 *              0x3[0-7]  - CS4299
    416 	 *              0x4[8-f]  - CS4201
    417 	 *              0x5[8-f]  - CS4205
    418 	 *              0x6[0-7]  - CS4291
    419 	 *              0x7[0-7]  - CS4202
    420 	 * Datasheets:
    421 	 *	http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
    422 	 *	http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
    423 	 *	http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
    424 	 *	http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
    425 	 *	http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
    426 	 *	http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
    427 	 */
    428 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x00),
    429 	  0xfffffff8,			"Crystal CS4297",	},
    430 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x10),
    431 	  0xfffffff8,			"Crystal CS4297A",	},
    432 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x20),
    433 	  0xfffffff8,			"Crystal CS4298",	},
    434 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x28),
    435 	  0xfffffff8,			"Crystal CS4294",	},
    436 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x30),
    437 	  0xfffffff8,			"Crystal CS4299",	},
    438 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x48),
    439 	  0xfffffff8,			"Crystal CS4201",	},
    440 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x58),
    441 	  0xfffffff8,			"Crystal CS4205",	},
    442 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x60),
    443 	  0xfffffff8,			"Crystal CS4291",	},
    444 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x70),
    445 	  0xfffffff8,			"Crystal CS4202",	},
    446 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),
    447 	  AC97_VENDOR_ID_MASK,		"Cirrus Logic unknown",	},
    448 
    449 	{ 0x45838308, 0xffffffff,	"ESS Technology ES1921", },
    450 	{ 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", },
    451 
    452 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    453 	  0xffffffff,			"Intersil HMP9701",	},
    454 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    455 	  AC97_VENDOR_ID_MASK,		"Intersil unknown",	},
    456 
    457 	{ AC97_CODEC_ID('I', 'C', 'E', 0x01),
    458 	  0xffffffff,			"ICEnsemble ICE1230",	},
    459 	{ AC97_CODEC_ID('I', 'C', 'E', 0x11),
    460 	  0xffffffff,			"ICEnsemble ICE1232",	},
    461 	{ AC97_CODEC_ID('I', 'C', 'E', 0),
    462 	  AC97_VENDOR_ID_MASK,		"ICEnsemble unknown",	},
    463 
    464 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    465 	  0xffffffff,			"National Semiconductor LM454[03568]", },
    466 	{ AC97_CODEC_ID('N', 'S', 'C', 49),
    467 	  0xffffffff,			"National Semiconductor LM4549", },
    468 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    469 	  AC97_VENDOR_ID_MASK,		"National Semiconductor unknown", },
    470 
    471 	{ AC97_CODEC_ID('S', 'I', 'L', 34),
    472 	  0xffffffff,			"Silicon Laboratory Si3036", },
    473 	{ AC97_CODEC_ID('S', 'I', 'L', 35),
    474 	  0xffffffff,			"Silicon Laboratory Si3038", },
    475 	{ AC97_CODEC_ID('S', 'I', 'L', 0),
    476 	  AC97_VENDOR_ID_MASK,		"Silicon Laboratory unknown", },
    477 
    478 	{ AC97_CODEC_ID('T', 'R', 'A', 2),
    479 	  0xffffffff,			"TriTech TR28022",	},
    480 	{ AC97_CODEC_ID('T', 'R', 'A', 3),
    481 	  0xffffffff,			"TriTech TR28023",	},
    482 	{ AC97_CODEC_ID('T', 'R', 'A', 6),
    483 	  0xffffffff,			"TriTech TR28026",	},
    484 	{ AC97_CODEC_ID('T', 'R', 'A', 8),
    485 	  0xffffffff,			"TriTech TR28028",	},
    486 	{ AC97_CODEC_ID('T', 'R', 'A', 35),
    487 	  0xffffffff,			"TriTech TR28602",	},
    488 	{ AC97_CODEC_ID('T', 'R', 'A', 0),
    489 	  AC97_VENDOR_ID_MASK,		"TriTech unknown",	},
    490 
    491 	{ AC97_CODEC_ID('T', 'X', 'N', 0x20),
    492 	  0xffffffff,			"Texas Instruments TLC320AD9xC", },
    493 	{ AC97_CODEC_ID('T', 'X', 'N', 0),
    494 	  AC97_VENDOR_ID_MASK,		"Texas Instruments unknown", },
    495 
    496 	/*
    497 	 * VIA
    498 	 * No datasheets are available.
    499 	 * http://www.viatech.com/en/multimedia/audio.jsp
    500 	 *
    501 	 * What about VT1616?
    502 	 */
    503 	{ AC97_CODEC_ID('V', 'I', 'A', 0x43),
    504 	  0xffffffff,			"VIA Technologies VT1611A", },
    505 	{ AC97_CODEC_ID('V', 'I', 'A', 0x61),
    506 	  0xffffffff,			"VIA Technologies VT1612A", },
    507 	{ AC97_CODEC_ID('V', 'I', 'A', 0),
    508 	  AC97_VENDOR_ID_MASK,		"VIA Technologies unknown", },
    509 
    510 	{ AC97_CODEC_ID('W', 'E', 'C', 1),
    511 	  0xffffffff,			"Winbond W83971D",	},
    512 	{ AC97_CODEC_ID('W', 'E', 'C', 0),
    513 	  AC97_VENDOR_ID_MASK,		"Winbond unknown",	},
    514 
    515 	/*
    516 	 * http://www.wolfsonmicro.com/product_list.asp?cid=64
    517 	 *	http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
    518 	 *	http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
    519 	 *	http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
    520 	 *	http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
    521 	 *	http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
    522 	 *	http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
    523 	 *	http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
    524 	 *	http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
    525 	 */
    526 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    527 	  0xffffffff,			"Wolfson WM9701A",	},
    528 	{ AC97_CODEC_ID('W', 'M', 'L', 3),
    529 	  0xffffffff,			"Wolfson WM9703/WM9707/WM9708",	},
    530 	{ AC97_CODEC_ID('W', 'M', 'L', 4),
    531 	  0xffffffff,			"Wolfson WM9704",	},
    532 	{ AC97_CODEC_ID('W', 'M', 'L', 5),
    533 	  0xffffffff,			"Wolfson WM9705/WM9710", },
    534 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    535 	  AC97_VENDOR_ID_MASK,		"Wolfson unknown",	},
    536 
    537 	/*
    538 	 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
    539 	 * Datasheets:
    540 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
    541 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
    542 	 */
    543 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    544 	  0xffffffff,			"Yamaha YMF743-S",	},
    545 	{ AC97_CODEC_ID('Y', 'M', 'H', 3),
    546 	  0xffffffff,			"Yamaha YMF753-S",	},
    547 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    548 	  AC97_VENDOR_ID_MASK,		"Yamaha unknown",	},
    549 
    550 	/*
    551 	 * http://www.sigmatel.com/products.htm
    552 	 */
    553 	{ 0x83847600, 0xffffffff,	"SigmaTel STAC9700",	},
    554 	{ 0x83847604, 0xffffffff,	"SigmaTel STAC9701/3/4/5", },
    555 	{ 0x83847605, 0xffffffff,	"SigmaTel STAC9704",	},
    556 	{ 0x83847608, 0xffffffff,	"SigmaTel STAC9708",	},
    557 	{ 0x83847609, 0xffffffff,	"SigmaTel STAC9721/23",	},
    558 	{ 0x83847644, 0xffffffff,	"SigmaTel STAC9744/45",	},
    559 	{ 0x83847656, 0xffffffff,	"SigmaTel STAC9756/57",	},
    560 	{ 0x83847684, 0xffffffff,	"SigmaTel STAC9783/84",	},
    561 	{ 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",	},
    562 
    563 	{ 0,
    564 	  0,			NULL,			}
    565 };
    566 
    567 static const char * const ac97enhancement[] = {
    568 	"no 3D stereo",
    569 	"Analog Devices Phat Stereo",
    570 	"Creative",
    571 	"National Semi 3D",
    572 	"Yamaha Ymersion",
    573 	"BBE 3D",
    574 	"Crystal Semi 3D",
    575 	"Qsound QXpander",
    576 	"Spatializer 3D",
    577 	"SRS 3D",
    578 	"Platform Tech 3D",
    579 	"AKM 3D",
    580 	"Aureal",
    581 	"AZTECH 3D",
    582 	"Binaura 3D",
    583 	"ESS Technology",
    584 	"Harman International VMAx",
    585 	"Nvidea 3D",
    586 	"Philips Incredible Sound",
    587 	"Texas Instruments' 3D",
    588 	"VLSI Technology 3D",
    589 	"TriTech 3D",
    590 	"Realtek 3D",
    591 	"Samsung 3D",
    592 	"Wolfson Microelectronics 3D",
    593 	"Delta Integration 3D",
    594 	"SigmaTel 3D",
    595 	"KS Waves 3D",
    596 	"Rockwell 3D",
    597 	"Unknown 3D",
    598 	"Unknown 3D",
    599 	"Unknown 3D",
    600 };
    601 
    602 static const char * const ac97feature[] = {
    603 	"dedicated mic channel",
    604 	"reserved",
    605 	"tone",
    606 	"simulated stereo",
    607 	"headphone",
    608 	"bass boost",
    609 	"18 bit DAC",
    610 	"20 bit DAC",
    611 	"18 bit ADC",
    612 	"20 bit ADC"
    613 };
    614 
    615 
    616 int ac97_str_equal __P((const char *, const char *));
    617 int ac97_check_capability(struct ac97_softc *, int);
    618 void ac97_setup_source_info __P((struct ac97_softc *));
    619 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    620 void ac97_setup_defaults __P((struct ac97_softc *));
    621 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    622 
    623 /* #define AC97_DEBUG 10 */
    624 
    625 #ifdef AUDIO_DEBUG
    626 #define DPRINTF(x)	if (ac97debug) printf x
    627 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    628 #ifdef AC97_DEBUG
    629 int	ac97debug = AC97_DEBUG;
    630 #else
    631 int	ac97debug = 0;
    632 #endif
    633 #else
    634 #define DPRINTF(x)
    635 #define DPRINTFN(n,x)
    636 #endif
    637 
    638 void
    639 ac97_read(as, reg, val)
    640 	struct ac97_softc *as;
    641 	u_int8_t reg;
    642 	u_int16_t *val;
    643 {
    644 	int error;
    645 
    646 	if (as->host_flags & AC97_HOST_DONT_READ &&
    647 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    648 	     reg != AC97_REG_RESET)) {
    649 		*val = as->shadow_reg[reg >> 1];
    650 		return;
    651 	}
    652 
    653 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    654 		*val = as->shadow_reg[reg >> 1];
    655 	}
    656 }
    657 
    658 int
    659 ac97_write(as, reg, val)
    660 	struct ac97_softc *as;
    661 	u_int8_t reg;
    662 	u_int16_t val;
    663 {
    664 
    665 	as->shadow_reg[reg >> 1] = val;
    666 
    667 	return (as->host_if->write(as->host_if->arg, reg, val));
    668 }
    669 
    670 void
    671 ac97_setup_defaults(as)
    672 	struct ac97_softc *as;
    673 {
    674 	int idx;
    675 	const struct ac97_source_info *si;
    676 
    677 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    678 
    679 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    680 		si = &source_info[idx];
    681 		ac97_write(as, si->reg, si->default_value);
    682 	}
    683 }
    684 
    685 void
    686 ac97_restore_shadow(self)
    687 	struct ac97_codec_if *self;
    688 {
    689 	struct ac97_softc *as = (struct ac97_softc *) self;
    690 	int idx;
    691 	const struct ac97_source_info *si;
    692 
    693 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    694 		si = &source_info[idx];
    695 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    696 	}
    697 }
    698 
    699 int
    700 ac97_str_equal(a, b)
    701 	const char *a, *b;
    702 {
    703 	return ((a == b) || (a && b && (!strcmp(a, b))));
    704 }
    705 
    706 int
    707 ac97_check_capability(struct ac97_softc *as, int check)
    708 {
    709 	switch (check) {
    710 	case CHECK_NONE:
    711 		return 1;
    712 	case CHECK_SURROUND:
    713 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
    714 	case CHECK_CENTER:
    715 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
    716 	case CHECK_LFE:
    717 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
    718 	case CHECK_HEADPHONES:
    719 		return as->caps & AC97_CAPS_HEADPHONES;
    720 	case CHECK_TONE:
    721 		return as->caps & AC97_CAPS_TONECTRL;
    722 	case CHECK_MIC:
    723 		return as->caps & AC97_CAPS_MICIN;
    724 	case CHECK_LOUDNESS:
    725 		return as->caps & AC97_CAPS_LOUDNESS;
    726 	case CHECK_3D:
    727 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
    728 	default:
    729 		printf("%s: internal error: feature=%d\n", __func__, check);
    730 		return 0;
    731 	}
    732 }
    733 
    734 void
    735 ac97_setup_source_info(as)
    736 	struct ac97_softc *as;
    737 {
    738 	int idx, ouridx;
    739 	struct ac97_source_info *si, *si2;
    740 
    741 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    742 		si = &as->source_info[ouridx];
    743 
    744 		if (!ac97_check_capability(as, source_info[idx].req_feature))
    745 			continue;
    746 
    747 		memcpy(si, &source_info[idx], sizeof(*si));
    748 
    749 		switch (si->type) {
    750 		case AUDIO_MIXER_CLASS:
    751 		        si->mixer_class = ouridx;
    752 			ouridx++;
    753 			break;
    754 		case AUDIO_MIXER_VALUE:
    755 			/* Todo - Test to see if it works */
    756 			ouridx++;
    757 
    758 			/* Add an entry for mute, if necessary */
    759 			if (si->mute) {
    760 				si = &as->source_info[ouridx];
    761 				memcpy(si, &source_info[idx], sizeof(*si));
    762 				si->qualifier = AudioNmute;
    763 				si->type = AUDIO_MIXER_ENUM;
    764 				si->info = &ac97_on_off;
    765 				si->info_size = sizeof(ac97_on_off);
    766 				si->bits = 1;
    767 				si->ofs = 15;
    768 				si->mute = 0;
    769 				si->polarity = 0;
    770 				ouridx++;
    771 			}
    772 			break;
    773 		case AUDIO_MIXER_ENUM:
    774 			/* Todo - Test to see if it works */
    775 			ouridx++;
    776 			break;
    777 		default:
    778 			printf ("ac97: shouldn't get here\n");
    779 			break;
    780 		}
    781 	}
    782 
    783 	as->num_source_info = ouridx;
    784 
    785 	for (idx = 0; idx < as->num_source_info; idx++) {
    786 		int idx2, previdx;
    787 
    788 		si = &as->source_info[idx];
    789 
    790 		/* Find mixer class */
    791 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    792 			si2 = &as->source_info[idx2];
    793 
    794 			if (si2->type == AUDIO_MIXER_CLASS &&
    795 			    ac97_str_equal(si->class,
    796 					   si2->class)) {
    797 				si->mixer_class = idx2;
    798 			}
    799 		}
    800 
    801 
    802 		/* Setup prev and next pointers */
    803 		if (si->prev != 0)
    804 			continue;
    805 
    806 		if (si->qualifier)
    807 			continue;
    808 
    809 		si->prev = AUDIO_MIXER_LAST;
    810 		previdx = idx;
    811 
    812 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    813 			if (idx2 == idx)
    814 				continue;
    815 
    816 			si2 = &as->source_info[idx2];
    817 
    818 			if (!si2->prev &&
    819 			    ac97_str_equal(si->class, si2->class) &&
    820 			    ac97_str_equal(si->device, si2->device)) {
    821 				as->source_info[previdx].next = idx2;
    822 				as->source_info[idx2].prev = previdx;
    823 
    824 				previdx = idx2;
    825 			}
    826 		}
    827 
    828 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    829 	}
    830 }
    831 
    832 int
    833 ac97_attach(host_if)
    834 	struct ac97_host_if *host_if;
    835 {
    836 	struct ac97_softc *as;
    837 	struct device *sc_dev = (struct device *)host_if->arg;
    838 	int error, i, j;
    839 	u_int32_t id;
    840 	u_int16_t id1, id2;
    841 	u_int16_t extstat, rate;
    842 	mixer_ctrl_t ctl;
    843 	const char *delim;
    844 	void (*initfunc)(struct ac97_softc *);
    845 
    846 	initfunc = NULL;
    847 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    848 
    849 	if (as == NULL)
    850 		return (ENOMEM);
    851 
    852 	as->codec_if.vtbl = &ac97civ;
    853 	as->host_if = host_if;
    854 
    855 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    856 		free(as, M_DEVBUF);
    857 		return (error);
    858 	}
    859 
    860 	host_if->reset(host_if->arg);
    861 
    862 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    863 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    864 
    865 	if (host_if->flags)
    866 		as->host_flags = host_if->flags(host_if->arg);
    867 
    868 	ac97_setup_defaults(as);
    869 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    870 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    871 	ac97_read(as, AC97_REG_RESET, &as->caps);
    872 
    873 	id = (id1 << 16) | id2;
    874 
    875 	printf("%s: ", sc_dev->dv_xname);
    876 
    877 	for (i = 0; ; i++) {
    878 		if (ac97codecid[i].id == 0) {
    879 			char pnp[4];
    880 
    881 			AC97_GET_CODEC_ID(id, pnp);
    882 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    883 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    884 			    ISASCII(pnp[2]))
    885 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    886 				    pnp[3]);
    887 			else
    888 				printf("unknown (0x%08x)", id);
    889 			break;
    890 		}
    891 		if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
    892 			printf("%s", ac97codecid[i].name);
    893 			if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
    894 				printf(" (0x%08x)", id);
    895 			}
    896 			initfunc = ac97codecid[i].init;
    897 			break;
    898 		}
    899 	}
    900 	printf(" codec; ");
    901 	for (i = j = 0; i < 10; i++) {
    902 		if (as->caps & (1 << i)) {
    903 			printf("%s%s", j? ", " : "", ac97feature[i]);
    904 			j++;
    905 		}
    906 	}
    907 	printf("%s%s\n", j ? ", " : "",
    908 	       ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
    909 
    910 	as->ac97_clock = AC97_STANDARD_CLOCK;
    911 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
    912 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
    913 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
    914 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
    915 			  | AC97_EXT_AUDIO_LDAC)) {
    916 		printf("%s:", sc_dev->dv_xname);
    917 		delim = "";
    918 
    919 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
    920 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    921 			printf("%s variable rate audio", delim);
    922 			delim = ",";
    923 			extstat |= AC97_EXT_AUDIO_VRA;
    924 		}
    925 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
    926 			printf("%s double rate output", delim);
    927 			delim = ",";
    928 		}
    929 		extstat &= ~AC97_EXT_AUDIO_DRA;
    930 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
    931 			printf("%s S/PDIF", delim);
    932 			delim = ",";
    933 		}
    934 		if (as->ext_id & AC97_EXT_AUDIO_VRM) {
    935 			printf("%s variable rate dedicated mic", delim);
    936 			delim = ",";
    937 			extstat |= AC97_EXT_AUDIO_VRM;
    938 		}
    939 		if (as->ext_id & AC97_EXT_AUDIO_CDAC) {
    940 			printf("%s center DAC", delim);
    941 			delim = ",";
    942 			extstat |= AC97_EXT_AUDIO_CDAC;
    943 		}
    944 		if (as->ext_id & AC97_EXT_AUDIO_SDAC) {
    945 			printf("%s surround DAC", delim);
    946 			delim = ",";
    947 			extstat |= AC97_EXT_AUDIO_SDAC;
    948 		}
    949 		if (as->ext_id & AC97_EXT_AUDIO_LDAC) {
    950 			printf("%s LFE DAC", delim);
    951 			extstat |= AC97_EXT_AUDIO_LDAC;
    952 		}
    953 		printf("\n");
    954 
    955 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
    956 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    957 			/* VRA should be enabled. */
    958 			/* so it claims to do variable rate, let's make sure */
    959 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
    960 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
    961 			if (rate != 44100) {
    962 				/* We can't believe ext_id */
    963 				as->ext_id = 0;
    964 				printf("%s: Ignore these capabilities.\n",
    965 				       sc_dev->dv_xname);
    966 			}
    967 			/* restore the default value */
    968 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
    969 				   AC97_SINGLE_RATE);
    970 		}
    971 	}
    972 
    973 	ac97_setup_source_info(as);
    974 
    975 	DELAY(900 * 1000);
    976 	memset(&ctl, 0, sizeof(ctl));
    977 
    978 	/* disable mutes */
    979 	for (i = 0; i < 11; i++) {
    980 		static struct {
    981 			char *class, *device;
    982 		} d[11] = {
    983 			{ AudioCoutputs, AudioNmaster},
    984 			{ AudioCoutputs, AudioNheadphone},
    985 			{ AudioCoutputs, AudioNsurround},
    986 			{ AudioCoutputs, AudioNcenter},
    987 			{ AudioCoutputs, AudioNlfe},
    988 			{ AudioCinputs, AudioNdac},
    989 			{ AudioCinputs, AudioNcd},
    990 			{ AudioCinputs, AudioNline},
    991 			{ AudioCinputs, AudioNaux},
    992 			{ AudioCinputs, AudioNvideo},
    993 			{ AudioCrecord, AudioNvolume},
    994 		};
    995 
    996 		ctl.type = AUDIO_MIXER_ENUM;
    997 		ctl.un.ord = 0;
    998 
    999 		ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
   1000 			d[i].class, d[i].device, AudioNmute);
   1001 		ac97_mixer_set_port(&as->codec_if, &ctl);
   1002 	}
   1003 	ctl.type = AUDIO_MIXER_ENUM;
   1004 	ctl.un.ord = 0;
   1005 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
   1006 					   AudioNsource, NULL);
   1007 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1008 
   1009 	/* set a reasonable default volume */
   1010 	ctl.type = AUDIO_MIXER_VALUE;
   1011 	ctl.un.value.num_channels = 2;
   1012 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
   1013 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
   1014 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1015 					   AudioNmaster, NULL);
   1016 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1017 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1018 					   AudioNsurround, NULL);
   1019 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1020 	ctl.un.value.num_channels = 1;
   1021 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1022 					   AudioNcenter, NULL);
   1023 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1024 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1025 					   AudioNlfe, NULL);
   1026 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1027 
   1028 	if (initfunc != NULL)
   1029 		initfunc(as);
   1030 	return (0);
   1031 }
   1032 
   1033 
   1034 int
   1035 ac97_query_devinfo(codec_if, dip)
   1036 	struct ac97_codec_if *codec_if;
   1037 	mixer_devinfo_t *dip;
   1038 {
   1039 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1040 
   1041 	if (dip->index < as->num_source_info) {
   1042 		struct ac97_source_info *si = &as->source_info[dip->index];
   1043 		const char *name;
   1044 
   1045 		dip->type = si->type;
   1046 		dip->mixer_class = si->mixer_class;
   1047 		dip->prev = si->prev;
   1048 		dip->next = si->next;
   1049 
   1050 		if (si->qualifier)
   1051 			name = si->qualifier;
   1052 		else if (si->device)
   1053 			name = si->device;
   1054 		else if (si->class)
   1055 			name = si->class;
   1056 		else
   1057 			name = 0;
   1058 
   1059 		if (name)
   1060 			strcpy(dip->label.name, name);
   1061 
   1062 		memcpy(&dip->un, si->info, si->info_size);
   1063 
   1064 		/* Set the delta for volume sources */
   1065 		if (dip->type == AUDIO_MIXER_VALUE)
   1066 			dip->un.v.delta = 1 << (8 - si->bits);
   1067 
   1068 		return (0);
   1069 	}
   1070 
   1071 	return (ENXIO);
   1072 }
   1073 
   1074 
   1075 
   1076 int
   1077 ac97_mixer_set_port(codec_if, cp)
   1078 	struct ac97_codec_if *codec_if;
   1079 	mixer_ctrl_t *cp;
   1080 {
   1081 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1082 	struct ac97_source_info *si = &as->source_info[cp->dev];
   1083 	u_int16_t mask;
   1084 	u_int16_t val, newval;
   1085 	int error;
   1086 
   1087 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1088 		return (EINVAL);
   1089 
   1090 	if (cp->type != si->type)
   1091 		return (EINVAL);
   1092 
   1093 	ac97_read(as, si->reg, &val);
   1094 
   1095 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1096 
   1097 	mask = (1 << si->bits) - 1;
   1098 
   1099 	switch (cp->type) {
   1100 	case AUDIO_MIXER_ENUM:
   1101 		if (cp->un.ord > mask || cp->un.ord < 0)
   1102 			return (EINVAL);
   1103 
   1104 		newval = (cp->un.ord << si->ofs);
   1105 		if (si->reg == AC97_REG_RECORD_SELECT) {
   1106 			newval |= (newval << (8 + si->ofs));
   1107 			mask |= (mask << 8);
   1108 			mask = mask << si->ofs;
   1109 		} else if (si->reg == AC97_REG_SURR_MASTER) {
   1110 			newval = cp->un.ord ? 0x8080 : 0x0000;
   1111 			mask = 0x8080;
   1112 		} else
   1113 			mask = mask << si->ofs;
   1114 		break;
   1115 	case AUDIO_MIXER_VALUE:
   1116 	{
   1117 		const struct audio_mixer_value *value = si->info;
   1118 		u_int16_t  l, r;
   1119 
   1120 		if ((cp->un.value.num_channels <= 0) ||
   1121 		    (cp->un.value.num_channels > value->num_channels))
   1122 			return (EINVAL);
   1123 
   1124 		if (cp->un.value.num_channels == 1) {
   1125 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
   1126 		} else {
   1127 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1128 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1129 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1130 			} else {	/* left/right is reversed here */
   1131 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1132 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1133 			}
   1134 
   1135 		}
   1136 
   1137 		if (!si->polarity) {
   1138 			l = 255 - l;
   1139 			r = 255 - r;
   1140 		}
   1141 
   1142 		l = l >> (8 - si->bits);
   1143 		r = r >> (8 - si->bits);
   1144 
   1145 		newval = ((l & mask) << si->ofs);
   1146 		if (value->num_channels == 2) {
   1147 			newval |= ((r & mask) << (si->ofs + 8));
   1148 			mask |= (mask << 8);
   1149 		}
   1150 		mask = mask << si->ofs;
   1151 		break;
   1152 	}
   1153 	default:
   1154 		return (EINVAL);
   1155 	}
   1156 
   1157 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
   1158 	if (error)
   1159 		return (error);
   1160 
   1161 	return (0);
   1162 }
   1163 
   1164 int
   1165 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
   1166 	struct ac97_codec_if *codec_if;
   1167 	const char *class, *device, *qualifier;
   1168 {
   1169 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1170 	int idx;
   1171 
   1172 	for (idx = 0; idx < as->num_source_info; idx++) {
   1173 		struct ac97_source_info *si = &as->source_info[idx];
   1174 		if (ac97_str_equal(class, si->class) &&
   1175 		    ac97_str_equal(device, si->device) &&
   1176 		    ac97_str_equal(qualifier, si->qualifier))
   1177 			return (idx);
   1178 	}
   1179 
   1180 	return (-1);
   1181 }
   1182 
   1183 int
   1184 ac97_mixer_get_port(codec_if, cp)
   1185 	struct ac97_codec_if *codec_if;
   1186 	mixer_ctrl_t *cp;
   1187 {
   1188 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
   1189 	struct ac97_source_info *si = &as->source_info[cp->dev];
   1190 	u_int16_t mask;
   1191 	u_int16_t val;
   1192 
   1193 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1194 		return (EINVAL);
   1195 
   1196 	if (cp->type != si->type)
   1197 		return (EINVAL);
   1198 
   1199 	ac97_read(as, si->reg, &val);
   1200 
   1201 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1202 
   1203 	mask = (1 << si->bits) - 1;
   1204 
   1205 	switch (cp->type) {
   1206 	case AUDIO_MIXER_ENUM:
   1207 		cp->un.ord = (val >> si->ofs) & mask;
   1208 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
   1209 		break;
   1210 	case AUDIO_MIXER_VALUE:
   1211 	{
   1212 		const struct audio_mixer_value *value = si->info;
   1213 		u_int16_t  l, r;
   1214 
   1215 		if ((cp->un.value.num_channels <= 0) ||
   1216 		    (cp->un.value.num_channels > value->num_channels))
   1217 			return (EINVAL);
   1218 
   1219 		if (value->num_channels == 1) {
   1220 			l = r = (val >> si->ofs) & mask;
   1221 		} else {
   1222 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1223 				l = (val >> si->ofs) & mask;
   1224 				r = (val >> (si->ofs + 8)) & mask;
   1225 			} else {	/* host has reversed channels */
   1226 				r = (val >> si->ofs) & mask;
   1227 				l = (val >> (si->ofs + 8)) & mask;
   1228 			}
   1229 		}
   1230 
   1231 		l = (l << (8 - si->bits));
   1232 		r = (r << (8 - si->bits));
   1233 		if (!si->polarity) {
   1234 			l = 255 - l;
   1235 			r = 255 - r;
   1236 		}
   1237 
   1238 		/* The EAP driver averages l and r for stereo
   1239 		   channels that are requested in MONO mode. Does this
   1240 		   make sense? */
   1241 		if (cp->un.value.num_channels == 1) {
   1242 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
   1243 		} else if (cp->un.value.num_channels == 2) {
   1244 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
   1245 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
   1246 		}
   1247 
   1248 		break;
   1249 	}
   1250 	default:
   1251 		return (EINVAL);
   1252 	}
   1253 
   1254 	return (0);
   1255 }
   1256 
   1257 
   1258 int
   1259 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
   1260 {
   1261 	struct ac97_softc *as;
   1262 	u_long value;
   1263 	u_int16_t ext_stat;
   1264 	u_int16_t actual;
   1265 	u_int16_t power;
   1266 	u_int16_t power_bit;
   1267 
   1268 	as = (struct ac97_softc *)codec_if;
   1269 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
   1270 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1271 			*rate = AC97_SINGLE_RATE;
   1272 			return 0;
   1273 		}
   1274 	} else {
   1275 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1276 			*rate = AC97_SINGLE_RATE;
   1277 			return 0;
   1278 		}
   1279 	}
   1280 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
   1281 	ext_stat = 0;
   1282 	/*
   1283 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
   1284 	 *	Check VRA, DRA
   1285 	 * PCM_LR_ADC_RATE
   1286 	 *	Check VRA
   1287 	 * PCM_MIC_ADC_RATE
   1288 	 *	Check VRM
   1289 	 */
   1290 	switch (target) {
   1291 	case AC97_REG_PCM_FRONT_DAC_RATE:
   1292 	case AC97_REG_PCM_SURR_DAC_RATE:
   1293 	case AC97_REG_PCM_LFE_DAC_RATE:
   1294 		power_bit = AC97_POWER_OUT;
   1295 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1296 			*rate = AC97_SINGLE_RATE;
   1297 			return 0;
   1298 		}
   1299 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1300 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1301 			if (value > 0x1ffff) {
   1302 				return EINVAL;
   1303 			} else if (value > 0xffff) {
   1304 				/* Enable DRA */
   1305 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1306 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1307 				value /= 2;
   1308 			} else {
   1309 				/* Disable DRA */
   1310 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1311 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1312 			}
   1313 		} else {
   1314 			if (value > 0xffff)
   1315 				return EINVAL;
   1316 		}
   1317 		break;
   1318 	case AC97_REG_PCM_LR_ADC_RATE:
   1319 		power_bit = AC97_POWER_IN;
   1320 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1321 			*rate = AC97_SINGLE_RATE;
   1322 			return 0;
   1323 		}
   1324 		if (value > 0xffff)
   1325 			return EINVAL;
   1326 		break;
   1327 	case AC97_REG_PCM_MIC_ADC_RATE:
   1328 		power_bit = AC97_POWER_IN;
   1329 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1330 			*rate = AC97_SINGLE_RATE;
   1331 			return 0;
   1332 		}
   1333 		if (value > 0xffff)
   1334 			return EINVAL;
   1335 		break;
   1336 	default:
   1337 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   1338 		return EINVAL;
   1339 	}
   1340 
   1341 	ac97_read(as, AC97_REG_POWER, &power);
   1342 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   1343 
   1344 	ac97_write(as, target, (u_int16_t)value);
   1345 	ac97_read(as, target, &actual);
   1346 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   1347 
   1348 	ac97_write(as, AC97_REG_POWER, power);
   1349 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   1350 		*rate = actual * 2;
   1351 	} else {
   1352 		*rate = actual;
   1353 	}
   1354 	return 0;
   1355 }
   1356 
   1357 void
   1358 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   1359 {
   1360 	struct ac97_softc *as;
   1361 
   1362 	as = (struct ac97_softc *)codec_if;
   1363 	as->ac97_clock = clock;
   1364 }
   1365 
   1366 u_int16_t
   1367 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   1368 {
   1369 	struct ac97_softc *as;
   1370 
   1371 	as = (struct ac97_softc *)codec_if;
   1372 	return as->ext_id;
   1373 }
   1374 
   1375 int
   1376 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
   1377 {
   1378 	struct ac97_source_info *si;
   1379 	int ouridx, idx;
   1380 
   1381 	if (as->num_source_info >= MAX_SOURCES) {
   1382 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
   1383 		       __func__, __FILE__);
   1384 		return -1;
   1385 	}
   1386 	if (!ac97_check_capability(as, src->req_feature))
   1387 		return -1;
   1388 	ouridx = as->num_source_info;
   1389 	si = &as->source_info[ouridx];
   1390 	memcpy(si, src, sizeof(*si));
   1391 
   1392 	switch (si->type) {
   1393 	case AUDIO_MIXER_CLASS:
   1394 	case AUDIO_MIXER_VALUE:
   1395 		printf("%s: adding class/value is not supported yet.\n",
   1396 		       __func__);
   1397 		return -1;
   1398 	case AUDIO_MIXER_ENUM:
   1399 		break;
   1400 	default:
   1401 		printf("%s: unknown type: %d\n", __func__, si->type);
   1402 		return -1;
   1403 	}
   1404 	as->num_source_info++;
   1405 
   1406 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
   1407 						   NULL, NULL);
   1408 	/* Find the root of the device */
   1409 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
   1410 				       si->device, NULL);
   1411 	/* Find the last item */
   1412 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
   1413 		idx = as->source_info[idx].next;
   1414 	/* Append */
   1415 	as->source_info[idx].next = ouridx;
   1416 	si->prev = idx;
   1417 	si->next = AUDIO_MIXER_LAST;
   1418 
   1419 	return 0;
   1420 }
   1421 
   1422 #define ALC650_REG_MULTI_CHANNEL_CONTROL	0x6a
   1423 #define		ALC650_MCC_SLOT_MODIFY_MASK		0xc000
   1424 #define		ALC650_MCC_FRONTDAC_FROM_SPDIFIN	0x2000
   1425 #define		ALC650_MCC_SPDIFOUT_FROM_ADC		0x1000
   1426 #define		ALC650_MCC_PCM_FROM_SPDIFIN		0x0800
   1427 #define		ALC650_MCC_MIC_OR_CENTERLFE		0x0400
   1428 #define		ALC650_MCC_LINEIN_OR_SURROUND		0x0200
   1429 #define		ALC650_MCC_INDEPENDENT_MASTER_L		0x0080
   1430 #define		ALC650_MCC_INDEPENDENT_MASTER_R		0x0040
   1431 #define		ALC650_MCC_ANALOG_TO_CENTERLFE		0x0020
   1432 #define		ALC650_MCC_ANALOG_TO_SURROUND		0x0010
   1433 #define		ALC650_MCC_EXCHANGE_CENTERLFE		0x0008
   1434 #define		ALC650_MCC_CENTERLFE_DOWNMIX		0x0004
   1435 #define		ALC650_MCC_SURROUND_DOWNMIX		0x0002
   1436 #define		ALC650_MCC_LINEOUT_TO_SURROUND		0x0001
   1437 static void
   1438 ac97_alc650_init(struct ac97_softc *as)
   1439 {
   1440 	static const struct ac97_source_info sources[3] = {
   1441 		{ AudioCoutputs, AudioNsurround, "lineinjack",
   1442 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1443 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1444 		  0x0000, 1, 9, 0, 0, CHECK_SURROUND },
   1445 		{ AudioCoutputs, AudioNcenter, "micjack",
   1446 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1447 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1448 		  0x0000, 1, 10, 0, 0, CHECK_CENTER },
   1449 		{ AudioCoutputs, AudioNlfe, "micjack",
   1450 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   1451 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   1452 		  0x0000, 1, 10, 0, 0, CHECK_LFE }};
   1453 
   1454 	ac97_add_port(as, &sources[0]);
   1455 	ac97_add_port(as, &sources[1]);
   1456 	ac97_add_port(as, &sources[2]);
   1457 }
   1458