Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.29
      1 /*      $NetBSD: ac97.c,v 1.29 2002/10/08 12:33:34 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.29 2002/10/08 12:33:34 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 static const struct audio_mixer_enum ac97_on_off = { 2,
     81 					       { { { AudioNoff } , 0 },
     82 					         { { AudioNon }  , 1 } }};
     83 
     84 
     85 static const struct audio_mixer_enum ac97_mic_select = { 2,
     86 					       { { { AudioNmicrophone "0" },
     87 						   0 },
     88 					         { { AudioNmicrophone "1" },
     89 						   1 } }};
     90 
     91 static const struct audio_mixer_enum ac97_mono_select = { 2,
     92 					       { { { AudioNmixerout },
     93 						   0 },
     94 					         { { AudioNmicrophone },
     95 						   1 } }};
     96 
     97 static const struct audio_mixer_enum ac97_source = { 8,
     98 					       { { { AudioNmicrophone } , 0 },
     99 						 { { AudioNcd }, 1 },
    100 						 { { "video" }, 2 },
    101 						 { { AudioNaux }, 3 },
    102 						 { { AudioNline }, 4 },
    103 						 { { AudioNmixerout }, 5 },
    104 						 { { AudioNmixerout AudioNmono }, 6 },
    105 						 { { "phone" }, 7 }}};
    106 
    107 /*
    108  * Due to different values for each source that uses these structures,
    109  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
    110  * ac97_source_info.bits.
    111  */
    112 static const struct audio_mixer_value ac97_volume_stereo = { { AudioNvolume },
    113 						       2 };
    114 
    115 static const struct audio_mixer_value ac97_volume_mono = { { AudioNvolume },
    116 						     1 };
    117 
    118 #define WRAP(a)  &a, sizeof(a)
    119 
    120 const struct ac97_source_info {
    121 	const char *class;
    122 	const char *device;
    123 	const char *qualifier;
    124 	int  type;
    125 
    126 	const void *info;
    127 	int  info_size;
    128 
    129 	u_int8_t  reg;
    130 	u_int16_t default_value;
    131 	u_int8_t  bits:3;
    132 	u_int8_t  ofs:4;
    133 	u_int8_t  mute:1;
    134 	u_int8_t  polarity:1;   /* Does 0 == MAX or MIN */
    135 
    136 	int  prev;
    137 	int  next;
    138 	int  mixer_class;
    139 } source_info[] = {
    140 	{ AudioCinputs ,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    141 	},
    142 	{ AudioCoutputs,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    143 	},
    144 	{ AudioCrecord ,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    145 	},
    146 	/* Stereo master volume*/
    147 	{ AudioCoutputs,     AudioNmaster,        NULL,    AUDIO_MIXER_VALUE,
    148 	  WRAP(ac97_volume_stereo),
    149 	  AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
    150 	},
    151 	/* Mono volume */
    152 	{ AudioCoutputs,       AudioNmono,        NULL,    AUDIO_MIXER_VALUE,
    153 	  WRAP(ac97_volume_mono),
    154 	  AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
    155 	},
    156 	{ AudioCoutputs,       AudioNmono,AudioNsource,   AUDIO_MIXER_ENUM,
    157 	  WRAP(ac97_mono_select),
    158 	  AC97_REG_GP, 0x0000, 1, 9, 0,
    159 	},
    160 	/* Headphone volume */
    161 	{ AudioCoutputs,  AudioNheadphone,        NULL,    AUDIO_MIXER_VALUE,
    162 	  WRAP(ac97_volume_stereo),
    163 	  AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1,
    164 	},
    165 	/* Tone */
    166 	{ AudioCoutputs,           "tone",        NULL,    AUDIO_MIXER_VALUE,
    167 	  WRAP(ac97_volume_stereo),
    168 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0,
    169 	},
    170 	/* PC Beep Volume */
    171 	{ AudioCinputs,     AudioNspeaker,        NULL,    AUDIO_MIXER_VALUE,
    172 	  WRAP(ac97_volume_mono),
    173 	  AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
    174 	},
    175 	/* Phone */
    176 	{ AudioCinputs,           "phone",        NULL,    AUDIO_MIXER_VALUE,
    177 	  WRAP(ac97_volume_mono),
    178 	  AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
    179 	},
    180 	/* Mic Volume */
    181 	{ AudioCinputs,  AudioNmicrophone,        NULL,    AUDIO_MIXER_VALUE,
    182 	  WRAP(ac97_volume_mono),
    183 	  AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
    184 	},
    185 	{ AudioCinputs,  AudioNmicrophone, AudioNpreamp,   AUDIO_MIXER_ENUM,
    186 	  WRAP(ac97_on_off),
    187 	  AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
    188 	},
    189 	{ AudioCinputs,  AudioNmicrophone, AudioNsource,   AUDIO_MIXER_ENUM,
    190 	  WRAP(ac97_mic_select),
    191 	  AC97_REG_GP, 0x0000, 1, 8, 0,
    192 	},
    193 	/* Line in Volume */
    194 	{ AudioCinputs,        AudioNline,        NULL,    AUDIO_MIXER_VALUE,
    195 	  WRAP(ac97_volume_stereo),
    196 	  AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
    197 	},
    198 	/* CD Volume */
    199 	{ AudioCinputs,          AudioNcd,        NULL,    AUDIO_MIXER_VALUE,
    200 	  WRAP(ac97_volume_stereo),
    201 	  AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
    202 	},
    203 	/* Video Volume */
    204 	{ AudioCinputs,           "video",        NULL,    AUDIO_MIXER_VALUE,
    205 	  WRAP(ac97_volume_stereo),
    206 	  AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
    207 	},
    208 	/* AUX volume */
    209 	{ AudioCinputs,         AudioNaux,        NULL,    AUDIO_MIXER_VALUE,
    210 	  WRAP(ac97_volume_stereo),
    211 	  AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
    212 	},
    213 	/* PCM out volume */
    214 	{ AudioCinputs,         AudioNdac,        NULL,    AUDIO_MIXER_VALUE,
    215 	  WRAP(ac97_volume_stereo),
    216 	  AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
    217 	},
    218 	/* Record Source - some logic for this is hard coded - see below */
    219 	{ AudioCrecord,      AudioNsource,        NULL,    AUDIO_MIXER_ENUM,
    220 	  WRAP(ac97_source),
    221 	  AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
    222 	},
    223 	/* Record Gain */
    224 	{ AudioCrecord,      AudioNvolume,        NULL,    AUDIO_MIXER_VALUE,
    225 	  WRAP(ac97_volume_stereo),
    226 	  AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
    227 	},
    228 	/* Record Gain mic */
    229 	{ AudioCrecord,  AudioNmicrophone,        NULL,    AUDIO_MIXER_VALUE,
    230 	  WRAP(ac97_volume_mono),
    231 	  AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1,
    232 	},
    233 	/* */
    234 	{ AudioCoutputs,   AudioNloudness,        NULL,    AUDIO_MIXER_ENUM,
    235 	  WRAP(ac97_on_off),
    236 	  AC97_REG_GP, 0x0000, 1, 12, 0,
    237 	},
    238 	{ AudioCoutputs,    AudioNspatial,        NULL,    AUDIO_MIXER_ENUM,
    239 	  WRAP(ac97_on_off),
    240 	  AC97_REG_GP, 0x0000, 1, 13, 0,
    241 	},
    242 	{ AudioCoutputs,    AudioNspatial,    "center",    AUDIO_MIXER_VALUE,
    243 	  WRAP(ac97_volume_mono),
    244 	  AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1,
    245 	},
    246 	{ AudioCoutputs,    AudioNspatial,     "depth",    AUDIO_MIXER_VALUE,
    247 	  WRAP(ac97_volume_mono),
    248 	  AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1,
    249 	},
    250 
    251 	/* Missing features: Simulated Stereo, POP, Loopback mode */
    252 } ;
    253 
    254 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
    255 
    256 /*
    257  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
    258  * information on AC-97
    259  */
    260 
    261 struct ac97_softc {
    262 	/* ac97_codec_if must be at the first of ac97_softc. */
    263 	struct ac97_codec_if codec_if;
    264 
    265 	struct ac97_host_if *host_if;
    266 
    267 	struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
    268 	int num_source_info;
    269 
    270 	enum ac97_host_flags host_flags;
    271 	unsigned int ac97_clock; /* usually 48000 */
    272 #define AC97_STANDARD_CLOCK	48000U
    273 	u_int16_t caps;		/* -> AC97_REG_RESET */
    274 	u_int16_t ext_id;	/* -> AC97_REG_EXT_AUDIO_ID */
    275 	u_int16_t shadow_reg[128];
    276 };
    277 
    278 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
    279 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
    280 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
    281 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
    282 				  char *));
    283 void ac97_restore_shadow __P((struct ac97_codec_if *self));
    284 int ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
    285 void ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
    286 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
    287 
    288 struct ac97_codec_if_vtbl ac97civ = {
    289 	ac97_mixer_get_port,
    290 	ac97_mixer_set_port,
    291 	ac97_query_devinfo,
    292 	ac97_get_portnum_by_name,
    293 	ac97_restore_shadow,
    294 	ac97_get_extcaps,
    295 	ac97_set_rate,
    296 	ac97_set_clock,
    297 };
    298 
    299 static const struct ac97_codecid {
    300 	u_int32_t id;
    301 	const char *name;
    302 } ac97codecid[] = {
    303 	{ AC97_CODEC_ID('A', 'D', 'S', 3),	"Analog Devices AD1819B" },
    304 	{ AC97_CODEC_ID('A', 'D', 'S', 64),	"Analog Devices AD1881" },
    305 	{ AC97_CODEC_ID('A', 'D', 'S', 72),	"Analog Devices AD1881A" },
    306 	{ AC97_CODEC_ID('A', 'D', 'S', 96),	"Analog Devices AD1885" },
    307 	{ AC97_CODEC_ID('A', 'D', 'S', 99),	"Analog Devices AD1886A" },
    308 	{ AC97_CODEC_ID('A', 'K', 'M', 0),	"Asahi Kasei AK4540"	},
    309 	{ AC97_CODEC_ID('A', 'K', 'M', 2),	"Asahi Kasei AK4543"	},
    310 	{ AC97_CODEC_ID('A', 'L', 'G', 16),	"Advance Logic ALC200"	},
    311 	{ AC97_CODEC_ID('A', 'L', 'G', 32),	"Advance Logic ALC650"	},
    312 	{ AC97_CODEC_ID('A', 'L', 'G', 48),	"Advance Logic ALC101"	},
    313 	{ AC97_CODEC_ID('A', 'L', 'G', 64),	"Advance Logic ALC202"	},
    314 	{ AC97_CODEC_ID('A', 'L', 'G', 80),	"Advance Logic ALC250"	},
    315 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),	"Crystal CS4297"	},
    316 	{ AC97_CODEC_ID('C', 'R', 'Y', 3),	"Crystal CS4297"	},
    317 	{ AC97_CODEC_ID('C', 'R', 'Y', 19),	"Crystal CS4297A"	},
    318 	{ AC97_CODEC_ID('C', 'R', 'Y', 35),	"Crystal CS4298",	},
    319 	{ AC97_CODEC_ID('C', 'R', 'Y', 43),	"Crystal CS4294",	},
    320 	{ AC97_CODEC_ID('C', 'R', 'Y', 49),	"Crystal CS4299",	},
    321 	{ AC97_CODEC_ID('C', 'R', 'Y', 51),	"Crystal CS4298A",	},
    322 	{ AC97_CODEC_ID('C', 'R', 'Y', 52),	"Crystal CS4299",	},
    323 	{ AC97_CODEC_ID('N', 'S', 'C', 49), "National Semiconductor LM4549", },
    324 	{ AC97_CODEC_ID('S', 'I', 'L', 34),	"Silicon Laboratory Si3036", },
    325 	{ AC97_CODEC_ID('S', 'I', 'L', 35),	"Silicon Laboratory Si3038", },
    326 	{ AC97_CODEC_ID('T', 'R', 'A', 2),	"TriTech TR28022",	},
    327 	{ AC97_CODEC_ID('T', 'R', 'A', 3),	"TriTech TR28023",	},
    328 	{ AC97_CODEC_ID('T', 'R', 'A', 6),	"TriTech TR28026",	},
    329 	{ AC97_CODEC_ID('T', 'R', 'A', 8),	"TriTech TR28028",	},
    330 	{ AC97_CODEC_ID('T', 'R', 'A', 35),	"TriTech unknown",	},
    331 	{ AC97_CODEC_ID('W', 'M', 'L', 0),	"Wolfson WM9704",	},
    332 	{ AC97_CODEC_ID('W', 'M', 'L', 3),	"Wolfson WM9707",	},
    333 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),	"Yamaha YMF743-S",	},
    334 	{ AC97_CODEC_ID('Y', 'M', 'H', 3),	"Yamaha YMF753-S",	},
    335 	{ 0x45838308,				"ESS Technology ES1921", },
    336 	{ 0x83847600,				"SigmaTel STAC9700",	},
    337 	{ 0x83847604,				"SigmaTel STAC9701/3/4/5", },
    338 	{ 0x83847605,				"SigmaTel STAC9704", 	},
    339 	{ 0x83847608,				"SigmaTel STAC9708", 	},
    340 	{ 0x83847609,				"SigmaTel STAC9721/23",	},
    341 	{ 0x83847644,				"SigmaTel STAC9744/45",	},
    342 	{ 0x83847684,				"SigmaTel STAC9783/84",	},
    343 	{ 0,					NULL,			}
    344 };
    345 
    346 static const char * const ac97enhancement[] = {
    347 	"no 3D stereo",
    348 	"Analog Devices Phat Stereo",
    349 	"Creative",
    350 	"National Semi 3D",
    351 	"Yamaha Ymersion",
    352 	"BBE 3D",
    353 	"Crystal Semi 3D",
    354 	"Qsound QXpander",
    355 	"Spatializer 3D",
    356 	"SRS 3D",
    357 	"Platform Tech 3D",
    358 	"AKM 3D",
    359 	"Aureal",
    360 	"AZTECH 3D",
    361 	"Binaura 3D",
    362 	"ESS Technology",
    363 	"Harman International VMAx",
    364 	"Nvidea 3D",
    365 	"Philips Incredible Sound",
    366 	"Texas Instruments' 3D",
    367 	"VLSI Technology 3D",
    368 	"TriTech 3D",
    369 	"Realtek 3D",
    370 	"Samsung 3D",
    371 	"Wolfson Microelectronics 3D",
    372 	"Delta Integration 3D",
    373 	"SigmaTel 3D",
    374 	"Unknown 3D",
    375 	"Rockwell 3D",
    376 	"Unknown 3D",
    377 	"Unknown 3D",
    378 	"Unknown 3D",
    379 };
    380 
    381 static const char * const ac97feature[] = {
    382 	"dedicated mic channel",
    383 	"reserved",
    384 	"tone",
    385 	"simulated stereo",
    386 	"headphone",
    387 	"bass boost",
    388 	"18 bit DAC",
    389 	"20 bit DAC",
    390 	"18 bit ADC",
    391 	"20 bit ADC"
    392 };
    393 
    394 
    395 int ac97_str_equal __P((const char *, const char *));
    396 void ac97_setup_source_info __P((struct ac97_softc *));
    397 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    398 void ac97_setup_defaults __P((struct ac97_softc *));
    399 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    400 
    401 /* #define AC97_DEBUG 10 */
    402 
    403 #ifdef AUDIO_DEBUG
    404 #define DPRINTF(x)	if (ac97debug) printf x
    405 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    406 #ifdef AC97_DEBUG
    407 int	ac97debug = AC97_DEBUG;
    408 #else
    409 int	ac97debug = 0;
    410 #endif
    411 #else
    412 #define DPRINTF(x)
    413 #define DPRINTFN(n,x)
    414 #endif
    415 
    416 void
    417 ac97_read(as, reg, val)
    418 	struct ac97_softc *as;
    419 	u_int8_t reg;
    420 	u_int16_t *val;
    421 {
    422 	int error;
    423 
    424 	if (as->host_flags & AC97_HOST_DONT_READ &&
    425 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    426 	     reg != AC97_REG_RESET)) {
    427 		*val = as->shadow_reg[reg >> 1];
    428 		return;
    429 	}
    430 
    431 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    432 		*val = as->shadow_reg[reg >> 1];
    433 	}
    434 }
    435 
    436 int
    437 ac97_write(as, reg, val)
    438 	struct ac97_softc *as;
    439 	u_int8_t reg;
    440 	u_int16_t val;
    441 {
    442 
    443 	as->shadow_reg[reg >> 1] = val;
    444 
    445 	return (as->host_if->write(as->host_if->arg, reg, val));
    446 }
    447 
    448 void
    449 ac97_setup_defaults(as)
    450 	struct ac97_softc *as;
    451 {
    452 	int idx;
    453 	const struct ac97_source_info *si;
    454 
    455 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    456 
    457 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    458 		si = &source_info[idx];
    459 		ac97_write(as, si->reg, si->default_value);
    460 	}
    461 }
    462 
    463 void
    464 ac97_restore_shadow(self)
    465 	struct ac97_codec_if *self;
    466 {
    467 	struct ac97_softc *as = (struct ac97_softc *) self;
    468 	int idx;
    469 	const struct ac97_source_info *si;
    470 
    471 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    472 		si = &source_info[idx];
    473 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    474 	}
    475 }
    476 
    477 int
    478 ac97_str_equal(a, b)
    479 	const char *a, *b;
    480 {
    481 	return ((a == b) || (a && b && (!strcmp(a, b))));
    482 }
    483 
    484 void
    485 ac97_setup_source_info(as)
    486 	struct ac97_softc *as;
    487 {
    488 	int idx, ouridx;
    489 	struct ac97_source_info *si, *si2;
    490 
    491 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    492 		si = &as->source_info[ouridx];
    493 
    494 		memcpy(si, &source_info[idx], sizeof(*si));
    495 
    496 		switch (si->type) {
    497 		case AUDIO_MIXER_CLASS:
    498 		        si->mixer_class = ouridx;
    499 			ouridx++;
    500 			break;
    501 		case AUDIO_MIXER_VALUE:
    502 			/* Todo - Test to see if it works */
    503 			ouridx++;
    504 
    505 			/* Add an entry for mute, if necessary */
    506 			if (si->mute) {
    507 				si = &as->source_info[ouridx];
    508 				memcpy(si, &source_info[idx], sizeof(*si));
    509 				si->qualifier = AudioNmute;
    510 				si->type = AUDIO_MIXER_ENUM;
    511 				si->info = &ac97_on_off;
    512 				si->info_size = sizeof(ac97_on_off);
    513 				si->bits = 1;
    514 				si->ofs = 15;
    515 				si->mute = 0;
    516 				si->polarity = 0;
    517 				ouridx++;
    518 			}
    519 			break;
    520 		case AUDIO_MIXER_ENUM:
    521 			/* Todo - Test to see if it works */
    522 			ouridx++;
    523 			break;
    524 		default:
    525 			printf ("ac97: shouldn't get here\n");
    526 			break;
    527 		}
    528 	}
    529 
    530 	as->num_source_info = ouridx;
    531 
    532 	for (idx = 0; idx < as->num_source_info; idx++) {
    533 		int idx2, previdx;
    534 
    535 		si = &as->source_info[idx];
    536 
    537 		/* Find mixer class */
    538 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    539 			si2 = &as->source_info[idx2];
    540 
    541 			if (si2->type == AUDIO_MIXER_CLASS &&
    542 			    ac97_str_equal(si->class,
    543 					   si2->class)) {
    544 				si->mixer_class = idx2;
    545 			}
    546 		}
    547 
    548 
    549 		/* Setup prev and next pointers */
    550 		if (si->prev != 0)
    551 			continue;
    552 
    553 		if (si->qualifier)
    554 			continue;
    555 
    556 		si->prev = AUDIO_MIXER_LAST;
    557 		previdx = idx;
    558 
    559 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    560 			if (idx2 == idx)
    561 				continue;
    562 
    563 			si2 = &as->source_info[idx2];
    564 
    565 			if (!si2->prev &&
    566 			    ac97_str_equal(si->class, si2->class) &&
    567 			    ac97_str_equal(si->device, si2->device)) {
    568 				as->source_info[previdx].next = idx2;
    569 				as->source_info[idx2].prev = previdx;
    570 
    571 				previdx = idx2;
    572 			}
    573 		}
    574 
    575 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    576 	}
    577 }
    578 
    579 int
    580 ac97_attach(host_if)
    581 	struct ac97_host_if *host_if;
    582 {
    583 	struct ac97_softc *as;
    584 	struct device *sc_dev = (struct device *)host_if->arg;
    585 	int error, i, j;
    586 	u_int32_t id;
    587 	u_int16_t id1, id2;
    588 	u_int16_t extstat, rate;
    589 	mixer_ctrl_t ctl;
    590 	const char *delim;
    591 
    592 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    593 
    594 	if (as == NULL)
    595 		return (ENOMEM);
    596 
    597 	as->codec_if.vtbl = &ac97civ;
    598 	as->host_if = host_if;
    599 
    600 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    601 		free (as, M_DEVBUF);
    602 		return (error);
    603 	}
    604 
    605 	host_if->reset(host_if->arg);
    606 
    607 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    608 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    609 
    610 	if (host_if->flags)
    611 		as->host_flags = host_if->flags(host_if->arg);
    612 
    613 	ac97_setup_defaults(as);
    614 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    615 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    616 	ac97_read(as, AC97_REG_RESET, &as->caps);
    617 
    618 	id = (id1 << 16) | id2;
    619 
    620 	printf("%s: ", sc_dev->dv_xname);
    621 
    622 	for (i = 0; ; i++) {
    623 		if (ac97codecid[i].id == 0) {
    624 			char pnp[4];
    625 
    626 			AC97_GET_CODEC_ID(id, pnp);
    627 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    628 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    629 			    ISASCII(pnp[2]))
    630 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    631 				    pnp[3]);
    632 			else
    633 				printf("unknown (0x%08x)", id);
    634 			break;
    635 		}
    636 		if (ac97codecid[i].id == id) {
    637 			printf("%s", ac97codecid[i].name);
    638 			break;
    639 		}
    640 	}
    641 	printf(" codec; ");
    642 	for (i = j = 0; i < 10; i++) {
    643 		if (as->caps & (1 << i)) {
    644 			printf("%s%s", j? ", " : "", ac97feature[i]);
    645 			j++;
    646 		}
    647 	}
    648 	printf("%s%s\n", j ? ", " : "",
    649 	       ac97enhancement[(as->caps >> 10) & 0x1f]);
    650 
    651 	as->ac97_clock = AC97_STANDARD_CLOCK;
    652 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
    653 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
    654 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
    655 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
    656 			  | AC97_EXT_AUDIO_LDAC)) {
    657 		printf("%s:", sc_dev->dv_xname);
    658 		delim = "";
    659 
    660 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    661 			printf("%s variable rate audio", delim);
    662 			delim = ",";
    663 		}
    664 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
    665 			printf("%s double rate output", delim);
    666 			delim = ",";
    667 		}
    668 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
    669 			printf("%s S/PDIF", delim);
    670 			delim = ",";
    671 		}
    672 		if (as->ext_id & AC97_EXT_AUDIO_VRM) {
    673 			printf("%s variable rate dedicated mic", delim);
    674 			delim = ",";
    675 		}
    676 		if (as->ext_id & AC97_EXT_AUDIO_CDAC) {
    677 			printf("%s center DAC", delim);
    678 			delim = ",";
    679 		}
    680 		if (as->ext_id & AC97_EXT_AUDIO_SDAC) {
    681 			printf("%s surround DAC", delim);
    682 			delim = ",";
    683 		}
    684 		if (as->ext_id & AC97_EXT_AUDIO_LDAC) {
    685 			printf("%s LFE DAC", delim);
    686 		}
    687 		printf("\n");
    688 
    689 		/* If VRA and/or VRM capablities, enable them. */
    690 		if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM)) {
    691 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
    692 			if (as->ext_id & AC97_EXT_AUDIO_VRA) {
    693 				extstat |= AC97_EXT_AUDIO_VRA;
    694 			}
    695 			if (as->ext_id & AC97_EXT_AUDIO_VRM) {
    696 				extstat |= AC97_EXT_AUDIO_VRM;
    697 			}
    698 			ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
    699 
    700 			/* so it claims to do variable rate, let's make sure */
    701 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
    702 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
    703 			if (rate != 44100) {
    704 				/* We can't believe ext_id */
    705 				as->ext_id = 0;
    706 				printf("%s: Ignore these capabilities.\n",
    707 				       sc_dev->dv_xname);
    708 			}
    709 		}
    710 	}
    711 
    712 	ac97_setup_source_info(as);
    713 
    714 	/* Just enable the DAC and master volumes by default */
    715 	memset(&ctl, 0, sizeof(ctl));
    716 
    717 	ctl.type = AUDIO_MIXER_ENUM;
    718 	ctl.un.ord = 0;  /* off */
    719 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
    720 					   AudioNmaster, AudioNmute);
    721 	ac97_mixer_set_port(&as->codec_if, &ctl);
    722 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
    723 					   AudioNdac, AudioNmute);
    724 
    725 	ac97_mixer_set_port(&as->codec_if, &ctl);
    726 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    727 					   AudioNvolume, AudioNmute);
    728 	ac97_mixer_set_port(&as->codec_if, &ctl);
    729 
    730 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    731 					   AudioNsource, NULL);
    732 	ctl.type = AUDIO_MIXER_ENUM;
    733 	ctl.un.ord = 0;
    734 	ac97_mixer_set_port(&as->codec_if, &ctl);
    735 
    736 	return (0);
    737 }
    738 
    739 
    740 int
    741 ac97_query_devinfo(codec_if, dip)
    742 	struct ac97_codec_if *codec_if;
    743 	mixer_devinfo_t *dip;
    744 {
    745 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    746 
    747 	if (dip->index < as->num_source_info) {
    748 		struct ac97_source_info *si = &as->source_info[dip->index];
    749 		const char *name;
    750 
    751 		dip->type = si->type;
    752 		dip->mixer_class = si->mixer_class;
    753 		dip->prev = si->prev;
    754 		dip->next = si->next;
    755 
    756 		if (si->qualifier)
    757 			name = si->qualifier;
    758 		else if (si->device)
    759 			name = si->device;
    760 		else if (si->class)
    761 			name = si->class;
    762 		else
    763 			name = 0;
    764 
    765 		if (name)
    766 			strcpy(dip->label.name, name);
    767 
    768 		memcpy(&dip->un, si->info, si->info_size);
    769 
    770 		/* Set the delta for volume sources */
    771 		if (dip->type == AUDIO_MIXER_VALUE)
    772 			dip->un.v.delta = 1 << (8 - si->bits);
    773 
    774 		return (0);
    775 	}
    776 
    777 	return (ENXIO);
    778 }
    779 
    780 
    781 
    782 int
    783 ac97_mixer_set_port(codec_if, cp)
    784 	struct ac97_codec_if *codec_if;
    785 	mixer_ctrl_t *cp;
    786 {
    787 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    788 	struct ac97_source_info *si = &as->source_info[cp->dev];
    789 	u_int16_t mask;
    790 	u_int16_t val, newval;
    791 	int error;
    792 
    793 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    794 		return (EINVAL);
    795 
    796 	if (cp->type != si->type)
    797 		return (EINVAL);
    798 
    799 	ac97_read(as, si->reg, &val);
    800 
    801 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    802 
    803 	mask = (1 << si->bits) - 1;
    804 
    805 	switch (cp->type) {
    806 	case AUDIO_MIXER_ENUM:
    807 		if (cp->un.ord > mask || cp->un.ord < 0)
    808 			return (EINVAL);
    809 
    810 		newval = (cp->un.ord << si->ofs);
    811 		if (si->reg == AC97_REG_RECORD_SELECT) {
    812 			newval |= (newval << (8 + si->ofs));
    813 			mask |= (mask << 8);
    814 		}
    815 		break;
    816 	case AUDIO_MIXER_VALUE:
    817 	{
    818 		const struct audio_mixer_value *value = si->info;
    819 		u_int16_t  l, r;
    820 
    821 		if ((cp->un.value.num_channels <= 0) ||
    822 		    (cp->un.value.num_channels > value->num_channels))
    823 			return (EINVAL);
    824 
    825 		if (cp->un.value.num_channels == 1) {
    826 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    827 		} else {
    828 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    829 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    830 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    831 			} else {	/* left/right is reversed here */
    832 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    833 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    834 			}
    835 
    836 		}
    837 
    838 		if (!si->polarity) {
    839 			l = 255 - l;
    840 			r = 255 - r;
    841 		}
    842 
    843 		l = l >> (8 - si->bits);
    844 		r = r >> (8 - si->bits);
    845 
    846 		newval = ((l & mask) << si->ofs);
    847 		if (value->num_channels == 2) {
    848 			newval |= ((r & mask) << (si->ofs + 8));
    849 			mask |= (mask << 8);
    850 		}
    851 
    852 		break;
    853 	}
    854 	default:
    855 		return (EINVAL);
    856 	}
    857 
    858 	mask = mask << si->ofs;
    859 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
    860 	if (error)
    861 		return (error);
    862 
    863 	return (0);
    864 }
    865 
    866 int
    867 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
    868 	struct ac97_codec_if *codec_if;
    869 	char *class, *device, *qualifier;
    870 {
    871 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    872 	int idx;
    873 
    874 	for (idx = 0; idx < as->num_source_info; idx++) {
    875 		struct ac97_source_info *si = &as->source_info[idx];
    876 		if (ac97_str_equal(class, si->class) &&
    877 		    ac97_str_equal(device, si->device) &&
    878 		    ac97_str_equal(qualifier, si->qualifier))
    879 			return (idx);
    880 	}
    881 
    882 	return (-1);
    883 }
    884 
    885 int
    886 ac97_mixer_get_port(codec_if, cp)
    887 	struct ac97_codec_if *codec_if;
    888 	mixer_ctrl_t *cp;
    889 {
    890 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    891 	struct ac97_source_info *si = &as->source_info[cp->dev];
    892 	u_int16_t mask;
    893 	u_int16_t val;
    894 
    895 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    896 		return (EINVAL);
    897 
    898 	if (cp->type != si->type)
    899 		return (EINVAL);
    900 
    901 	ac97_read(as, si->reg, &val);
    902 
    903 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    904 
    905 	mask = (1 << si->bits) - 1;
    906 
    907 	switch (cp->type) {
    908 	case AUDIO_MIXER_ENUM:
    909 		cp->un.ord = (val >> si->ofs) & mask;
    910 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
    911 		break;
    912 	case AUDIO_MIXER_VALUE:
    913 	{
    914 		const struct audio_mixer_value *value = si->info;
    915 		u_int16_t  l, r;
    916 
    917 		if ((cp->un.value.num_channels <= 0) ||
    918 		    (cp->un.value.num_channels > value->num_channels))
    919 			return (EINVAL);
    920 
    921 		if (value->num_channels == 1) {
    922 			l = r = (val >> si->ofs) & mask;
    923 		} else {
    924 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    925 				l = (val >> si->ofs) & mask;
    926 				r = (val >> (si->ofs + 8)) & mask;
    927 			} else {	/* host has reversed channels */
    928 				r = (val >> si->ofs) & mask;
    929 				l = (val >> (si->ofs + 8)) & mask;
    930 			}
    931 		}
    932 
    933 		l = (l << (8 - si->bits));
    934 		r = (r << (8 - si->bits));
    935 		if (!si->polarity) {
    936 			l = 255 - l;
    937 			r = 255 - r;
    938 		}
    939 
    940 		/* The EAP driver averages l and r for stereo
    941 		   channels that are requested in MONO mode. Does this
    942 		   make sense? */
    943 		if (cp->un.value.num_channels == 1) {
    944 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
    945 		} else if (cp->un.value.num_channels == 2) {
    946 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    947 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    948 		}
    949 
    950 		break;
    951 	}
    952 	default:
    953 		return (EINVAL);
    954 	}
    955 
    956 	return (0);
    957 }
    958 
    959 
    960 int
    961 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
    962 {
    963 	struct ac97_softc *as;
    964 	u_long value;
    965 	u_int16_t ext_stat;
    966 	u_int16_t actual;
    967 	u_int16_t power;
    968 	u_int16_t power_bit;
    969 
    970 	as = (struct ac97_softc *)codec_if;
    971 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
    972 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
    973 			*rate = AC97_SINGLE_RATE;
    974 			return 0;
    975 		}
    976 	} else {
    977 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
    978 			*rate = AC97_SINGLE_RATE;
    979 			return 0;
    980 		}
    981 	}
    982 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
    983 	ext_stat = 0;
    984 	/*
    985 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
    986 	 *	Check VRA, DRA
    987 	 * PCM_LR_ADC_RATE
    988 	 *	Check VRA
    989 	 * PCM_MIC_ADC_RATE
    990 	 *	Check VRM
    991 	 */
    992 	switch (target) {
    993 	case AC97_REG_PCM_FRONT_DAC_RATE:
    994 	case AC97_REG_PCM_SURR_DAC_RATE:
    995 	case AC97_REG_PCM_LFE_DAC_RATE:
    996 		power_bit = AC97_POWER_OUT;
    997 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
    998 			*rate = AC97_SINGLE_RATE;
    999 			return 0;
   1000 		}
   1001 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1002 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1003 			if (value > 0x1ffff) {
   1004 				return EINVAL;
   1005 			} else if (value > 0xffff) {
   1006 				/* Enable DRA */
   1007 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1008 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1009 				value /= 2;
   1010 			} else {
   1011 				/* Disable DRA */
   1012 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1013 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1014 			}
   1015 		} else {
   1016 			if (value > 0xffff)
   1017 				return EINVAL;
   1018 		}
   1019 		break;
   1020 	case AC97_REG_PCM_LR_ADC_RATE:
   1021 		power_bit = AC97_POWER_IN;
   1022 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1023 			*rate = AC97_SINGLE_RATE;
   1024 			return 0;
   1025 		}
   1026 		if (value > 0xffff)
   1027 			return EINVAL;
   1028 		break;
   1029 	case AC97_REG_PCM_MIC_ADC_RATE:
   1030 		power_bit = AC97_POWER_IN;
   1031 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1032 			*rate = AC97_SINGLE_RATE;
   1033 			return 0;
   1034 		}
   1035 		if (value > 0xffff)
   1036 			return EINVAL;
   1037 		break;
   1038 	default:
   1039 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   1040 		return EINVAL;
   1041 	}
   1042 
   1043 	ac97_read(as, AC97_REG_POWER, &power);
   1044 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   1045 
   1046 	ac97_write(as, target, (u_int16_t)value);
   1047 	ac97_read(as, target, &actual);
   1048 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   1049 
   1050 	ac97_write(as, AC97_REG_POWER, power);
   1051 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   1052 		*rate = actual * 2;
   1053 	} else {
   1054 		*rate = actual;
   1055 	}
   1056 	return 0;
   1057 }
   1058 
   1059 void
   1060 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   1061 {
   1062 	struct ac97_softc *as;
   1063 
   1064 	as = (struct ac97_softc *)codec_if;
   1065 	as->ac97_clock = clock;
   1066 }
   1067 
   1068 u_int16_t
   1069 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   1070 {
   1071 	struct ac97_softc *as;
   1072 
   1073 	as = (struct ac97_softc *)codec_if;
   1074 	return as->ext_id;
   1075 }
   1076