Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.92
      1 /*      $NetBSD: ac97.c,v 1.92 2011/11/23 23:07:31 jmcneill 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.92 2011/11/23 23:07:31 jmcneill 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 #include <sys/sysctl.h>
     74 
     75 #include <sys/audioio.h>
     76 #include <dev/audio_if.h>
     77 
     78 #include <dev/ic/ac97reg.h>
     79 #include <dev/ic/ac97var.h>
     80 
     81 struct ac97_softc;
     82 struct ac97_source_info;
     83 static int	ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
     84 static int	ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
     85 static void	ac97_detach(struct ac97_codec_if *);
     86 static void	ac97_lock(struct ac97_codec_if *);
     87 static void	ac97_unlock(struct ac97_codec_if *);
     88 static int	ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
     89 static int	ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
     90 					 const char *, const char *);
     91 static void	ac97_restore_shadow(struct ac97_codec_if *);
     92 static int	ac97_set_rate(struct ac97_codec_if *, int, u_int *);
     93 static void	ac97_set_clock(struct ac97_codec_if *, unsigned int);
     94 static uint16_t ac97_get_extcaps(struct ac97_codec_if *);
     95 static int	ac97_add_port(struct ac97_softc *,
     96 			      const struct ac97_source_info *);
     97 static int	ac97_str_equal(const char *, const char *);
     98 static int	ac97_check_capability(struct ac97_softc *, int);
     99 static void	ac97_setup_source_info(struct ac97_softc *);
    100 static void	ac97_read(struct ac97_softc *, uint8_t, uint16_t *);
    101 static void	ac97_setup_defaults(struct ac97_softc *);
    102 static int	ac97_write(struct ac97_softc *, uint8_t, uint16_t);
    103 
    104 static void	ac97_ad198x_init(struct ac97_softc *);
    105 static void	ac97_alc650_init(struct ac97_softc *);
    106 static void	ac97_ucb1400_init(struct ac97_softc *);
    107 static void	ac97_vt1616_init(struct ac97_softc *);
    108 
    109 static int	ac97_modem_offhook_set(struct ac97_softc *, int, int);
    110 static int	ac97_sysctl_verify(SYSCTLFN_ARGS);
    111 
    112 #define Ac97Nphone	"phone"
    113 #define Ac97Nline1	"line1"
    114 #define Ac97Nline2	"line2"
    115 #define Ac97Nhandset	"handset"
    116 
    117 static const struct audio_mixer_enum
    118 ac97_on_off = { 2, { { { AudioNoff, 0 } , 0 },
    119 		     { { AudioNon, 0 }  , 1 },
    120 		     { { "", 0 }	, 0 },
    121 		     { { "", 0 }	, 0 },
    122 		     { { "", 0 }	, 0 },
    123 		     { { "", 0 }	, 0 },
    124 		     { { "", 0 }	, 0 },
    125 		     { { "", 0 }	, 0 },
    126 		     { { "", 0 }	, 0 },
    127 		     { { "", 0 }	, 0 },
    128 		     { { "", 0 }	, 0 },
    129 		     { { "", 0 }	, 0 },
    130 		     { { "", 0 }	, 0 },
    131 		     { { "", 0 }	, 0 },
    132 		     { { "", 0 }	, 0 },
    133 		     { { "", 0 }	, 0 },
    134 		     { { "", 0 }	, 0 },
    135 		     { { "", 0 }	, 0 },
    136 		     { { "", 0 }	, 0 },
    137 		     { { "", 0 }	, 0 },
    138 		     { { "", 0 }	, 0 },
    139 		     { { "", 0 }	, 0 },
    140 		     { { "", 0 }	, 0 },
    141 		     { { "", 0 }	, 0 },
    142 		     { { "", 0 }	, 0 },
    143 		     { { "", 0 }	, 0 },
    144 		     { { "", 0 }	, 0 },
    145 		     { { "", 0 }	, 0 },
    146 		     { { "", 0 }	, 0 },
    147 		     { { "", 0 }	, 0 },
    148 		     { { "", 0 }	, 0 },
    149 		     { { "", 0 }	, 0 }, } };
    150 
    151 static const struct audio_mixer_enum
    152 ac97_mic_select = { 2, { { { AudioNmicrophone "0", 0  }, 0 },
    153 			 { { AudioNmicrophone "1", 0  }, 1 },
    154 			 { { "", 0 }	, 0 },
    155 			 { { "", 0 }	, 0 },
    156 			 { { "", 0 }	, 0 },
    157 			 { { "", 0 }	, 0 },
    158 			 { { "", 0 }	, 0 },
    159 			 { { "", 0 }	, 0 },
    160 			 { { "", 0 }	, 0 },
    161 			 { { "", 0 }	, 0 },
    162 			 { { "", 0 }	, 0 },
    163 			 { { "", 0 }	, 0 },
    164 			 { { "", 0 }	, 0 },
    165 			 { { "", 0 }	, 0 },
    166 			 { { "", 0 }	, 0 },
    167 			 { { "", 0 }	, 0 },
    168 			 { { "", 0 }	, 0 },
    169 			 { { "", 0 }	, 0 },
    170 			 { { "", 0 }	, 0 },
    171 			 { { "", 0 }	, 0 },
    172 			 { { "", 0 }	, 0 },
    173 			 { { "", 0 }	, 0 },
    174 			 { { "", 0 }	, 0 },
    175 			 { { "", 0 }	, 0 },
    176 			 { { "", 0 }	, 0 },
    177 			 { { "", 0 }	, 0 },
    178 			 { { "", 0 }	, 0 },
    179 			 { { "", 0 }	, 0 },
    180 			 { { "", 0 }	, 0 },
    181 			 { { "", 0 }	, 0 },
    182 			 { { "", 0 }	, 0 },
    183 			 { { "", 0 }	, 0 }, } };
    184 
    185 static const struct audio_mixer_enum
    186 ac97_mono_select = { 2, { { { AudioNmixerout, 0  }, 0 },
    187 			  { { AudioNmicrophone, 0  }, 1 },
    188 			  { { "", 0 }	, 0 },
    189 			  { { "", 0 }	, 0 },
    190 			  { { "", 0 }	, 0 },
    191 			  { { "", 0 }	, 0 },
    192 			  { { "", 0 }	, 0 },
    193 			  { { "", 0 }	, 0 },
    194 			  { { "", 0 }	, 0 },
    195 			  { { "", 0 }	, 0 },
    196 			  { { "", 0 }	, 0 },
    197 			  { { "", 0 }	, 0 },
    198 			  { { "", 0 }	, 0 },
    199 			  { { "", 0 }	, 0 },
    200 			  { { "", 0 }	, 0 },
    201 			  { { "", 0 }	, 0 },
    202 			  { { "", 0 }	, 0 },
    203 			  { { "", 0 }	, 0 },
    204 			  { { "", 0 }	, 0 },
    205 			  { { "", 0 }	, 0 },
    206 			  { { "", 0 }	, 0 },
    207 			  { { "", 0 }	, 0 },
    208 			  { { "", 0 }	, 0 },
    209 			  { { "", 0 }	, 0 },
    210 			  { { "", 0 }	, 0 },
    211 			  { { "", 0 }	, 0 },
    212 			  { { "", 0 }	, 0 },
    213 			  { { "", 0 }	, 0 },
    214 			  { { "", 0 }	, 0 },
    215 			  { { "", 0 }	, 0 },
    216 			  { { "", 0 }	, 0 },
    217 			  { { "", 0 }	, 0 }, } };
    218 
    219 static const struct audio_mixer_enum
    220 ac97_source = { 8, { { { AudioNmicrophone, 0  } , 0 },
    221 		     { { AudioNcd, 0 }, 1 },
    222 		     { { AudioNvideo, 0 }, 2 },
    223 		     { { AudioNaux, 0 }, 3 },
    224 		     { { AudioNline, 0 }, 4 },
    225 		     { { AudioNmixerout, 0 }, 5 },
    226 		     { { AudioNmixerout AudioNmono, 0 }, 6 },
    227 		     { { Ac97Nphone, 0 }, 7 },
    228 		     { { "", 0 }	, 0 },
    229 		     { { "", 0 }	, 0 },
    230 		     { { "", 0 }	, 0 },
    231 		     { { "", 0 }	, 0 },
    232 		     { { "", 0 }	, 0 },
    233 		     { { "", 0 }	, 0 },
    234 		     { { "", 0 }	, 0 },
    235 		     { { "", 0 }	, 0 },
    236 		     { { "", 0 }	, 0 },
    237 		     { { "", 0 }	, 0 },
    238 		     { { "", 0 }	, 0 },
    239 		     { { "", 0 }	, 0 },
    240 		     { { "", 0 }	, 0 },
    241 		     { { "", 0 }	, 0 },
    242 		     { { "", 0 }	, 0 },
    243 		     { { "", 0 }	, 0 },
    244 		     { { "", 0 }	, 0 },
    245 		     { { "", 0 }	, 0 },
    246 		     { { "", 0 }	, 0 },
    247 		     { { "", 0 }	, 0 },
    248 		     { { "", 0 }	, 0 },
    249 		     { { "", 0 }	, 0 },
    250 		     { { "", 0 }	, 0 },
    251 		     { { "", 0 }	, 0 }, } };
    252 
    253 /*
    254  * Due to different values for each source that uses these structures,
    255  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
    256  * ac97_source_info.bits.
    257  */
    258 static const struct audio_mixer_value
    259 ac97_volume_stereo = { { AudioNvolume, 0 }, 2, 0 };
    260 
    261 static const struct audio_mixer_value
    262 ac97_volume_mono = { { AudioNvolume, 0 }, 1, 0 };
    263 
    264 #define WRAP(a)  &a, sizeof(a)
    265 
    266 struct ac97_source_info {
    267 	const char *class;
    268 	const char *device;
    269 	const char *qualifier;
    270 
    271 	int  type;
    272 	const void *info;
    273 	int  info_size;
    274 
    275 	uint8_t  reg;
    276 	int32_t	 default_value;
    277 	unsigned bits:3;
    278 	unsigned ofs:4;
    279 	unsigned mute:1;
    280 	unsigned polarity:1;   /* Does 0 == MAX or MIN */
    281 	unsigned checkbits:1;
    282 	enum {
    283 		CHECK_NONE = 0,
    284 		CHECK_SURROUND,
    285 		CHECK_CENTER,
    286 		CHECK_LFE,
    287 		CHECK_HEADPHONES,
    288 		CHECK_TONE,
    289 		CHECK_MIC,
    290 		CHECK_LOUDNESS,
    291 		CHECK_3D,
    292 		CHECK_LINE1,
    293 		CHECK_LINE2,
    294 		CHECK_HANDSET,
    295 		CHECK_SPDIF
    296 	} req_feature;
    297 
    298 	int  prev;
    299 	int  next;
    300 	int  mixer_class;
    301 };
    302 
    303 static const struct ac97_source_info audio_source_info[] = {
    304 	{ AudioCinputs,		NULL,		NULL,
    305 	  AUDIO_MIXER_CLASS,    NULL,		0,
    306 	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    307 	{ AudioCoutputs,	NULL,		0,
    308 	  AUDIO_MIXER_CLASS,    NULL,		0,
    309 	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    310 	{ AudioCrecord,		NULL,		0,
    311 	  AUDIO_MIXER_CLASS,    NULL,		0,
    312 	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    313 	/* Stereo master volume*/
    314 	{ AudioCoutputs,	AudioNmaster,	0,
    315 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    316 	  AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 0, 1, 0, 0, 0, 0,
    317 	},
    318 	/* Mono volume */
    319 	{ AudioCoutputs,	AudioNmono,	NULL,
    320 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    321 	  AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 0, 1, 0, 0, 0, 0,
    322 	},
    323 	{ AudioCoutputs,	AudioNmono,	AudioNsource,
    324 	  AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
    325 	  AC97_REG_GP, 0x0000, 1, 9, 0, 0, 0, 0, 0, 0, 0,
    326 	},
    327 	/* Headphone volume */
    328 	{ AudioCoutputs,	AudioNheadphone, NULL,
    329 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    330 	  AC97_REG_HEADPHONE_VOLUME, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES, 0, 0, 0,
    331 	},
    332 	/* Surround volume - logic hard coded for mute */
    333 	{ AudioCoutputs,	AudioNsurround,	NULL,
    334 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    335 	  AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND, 0, 0, 0
    336 	},
    337 	/* Center volume*/
    338 	{ AudioCoutputs,	AudioNcenter,	NULL,
    339 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    340 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER, 0, 0, 0
    341 	},
    342 	{ AudioCoutputs,	AudioNcenter,	AudioNmute,
    343 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    344 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER, 0, 0, 0
    345 	},
    346 	/* LFE volume*/
    347 	{ AudioCoutputs,	AudioNlfe,	NULL,
    348 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    349 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE, 0, 0, 0
    350 	},
    351 	{ AudioCoutputs,	AudioNlfe,	AudioNmute,
    352 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    353 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE, 0, 0, 0
    354 	},
    355 	/* Tone - bass */
    356 	{ AudioCoutputs,	AudioNbass,	NULL,
    357 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    358 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE, 0, 0, 0
    359 	},
    360 	/* Tone - treble */
    361 	{ AudioCoutputs,	AudioNtreble,	NULL,
    362 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    363 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE, 0, 0, 0
    364 	},
    365 	/* PC Beep Volume */
    366 	{ AudioCinputs,		AudioNspeaker,	NULL,
    367 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    368 	  AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 0, 0, 0, 0, 0, 0,
    369 	},
    370 
    371 	/* Phone */
    372 	{ AudioCinputs,		Ac97Nphone,	NULL,
    373 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    374 	  AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    375 	},
    376 	/* Mic Volume */
    377 	{ AudioCinputs,		AudioNmicrophone, NULL,
    378 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    379 	  AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    380 	},
    381 	{ AudioCinputs,		AudioNmicrophone, AudioNpreamp,
    382 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    383 	  AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 0, 0, 0, 0, 0, 0,
    384 	},
    385 	{ AudioCinputs,		AudioNmicrophone, AudioNsource,
    386 	  AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
    387 	  AC97_REG_GP, 0x0000, 1, 8, 0, 0, 0, 0, 0, 0, 0,
    388 	},
    389 	/* Line in Volume */
    390 	{ AudioCinputs,		AudioNline,	NULL,
    391 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    392 	  AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    393 	},
    394 	/* CD Volume */
    395 	{ AudioCinputs,		AudioNcd,	NULL,
    396 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    397 	  AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    398 	},
    399 	/* Video Volume */
    400 	{ AudioCinputs,		AudioNvideo,	NULL,
    401 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    402 	  AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    403 	},
    404 	/* AUX volume */
    405 	{ AudioCinputs,		AudioNaux,	NULL,
    406 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    407 	  AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    408 	},
    409 	/* PCM out volume */
    410 	{ AudioCinputs,		AudioNdac,	NULL,
    411 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    412 	  AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
    413 	},
    414 	/* Record Source - some logic for this is hard coded - see below */
    415 	{ AudioCrecord,		AudioNsource,	NULL,
    416 	  AUDIO_MIXER_ENUM, WRAP(ac97_source),
    417 	  AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 0, 0, 0, 0, 0, 0,
    418 	},
    419 	/* Record Gain */
    420 	{ AudioCrecord,		AudioNvolume,	NULL,
    421 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
    422 	  AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 0, 0, 0, 0, 0,
    423 	},
    424 	/* Record Gain mic */
    425 	{ AudioCrecord,		AudioNmicrophone, NULL,
    426 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    427 	  AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC, 0, 0, 0
    428 	},
    429 	/* */
    430 	{ AudioCoutputs,	AudioNloudness,	NULL,
    431 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    432 	  AC97_REG_GP, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS, 0, 0, 0
    433 	},
    434 	{ AudioCoutputs,	AudioNspatial,	NULL,
    435 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    436 	  AC97_REG_GP, 0x0000, 1, 13, 0, 1, 0, CHECK_3D, 0, 0, 0
    437 	},
    438 	{ AudioCoutputs,	AudioNspatial,	"center",
    439 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    440 	  AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 0, CHECK_3D, 0, 0, 0
    441 	},
    442 	{ AudioCoutputs,	AudioNspatial,	"depth",
    443 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    444 	  AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 0, CHECK_3D, 0, 0, 0
    445 	},
    446 
    447 	/* SPDIF */
    448 	{ "spdif", NULL, NULL,
    449 	  AUDIO_MIXER_CLASS, NULL, 0,
    450 	  0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
    451 	},
    452 	{ "spdif", "enable", NULL,
    453 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    454 	  AC97_REG_EXT_AUDIO_CTRL, -1, 1, 2, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
    455 	},
    456 
    457 	/* Missing features: Simulated Stereo, POP, Loopback mode */
    458 };
    459 
    460 static const struct ac97_source_info modem_source_info[] = {
    461 	/* Classes */
    462 	{ AudioCinputs,		NULL,		NULL,
    463 	  AUDIO_MIXER_CLASS,    NULL,		0,
    464 	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    465 	{ AudioCoutputs,	NULL,		NULL,
    466 	  AUDIO_MIXER_CLASS,    NULL,		0,
    467 	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    468 	{ AudioCinputs,		Ac97Nline1,	NULL,
    469 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    470 	  AC97_REG_LINE1_LEVEL, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1, 0, 0, 0
    471 	},
    472 	{ AudioCoutputs,	Ac97Nline1,	NULL,
    473 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
    474 	  AC97_REG_LINE1_LEVEL, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1, 0, 0, 0
    475 	},
    476 	{ AudioCinputs,		Ac97Nline1,	AudioNmute,
    477 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    478 	  AC97_REG_LINE1_LEVEL, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1, 0, 0, 0
    479 	},
    480 	{ AudioCoutputs,	Ac97Nline1,	AudioNmute,
    481 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
    482 	  AC97_REG_LINE1_LEVEL, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1, 0, 0, 0
    483 	},
    484 };
    485 
    486 #define AUDIO_SOURCE_INFO_SIZE \
    487 		(sizeof(audio_source_info)/sizeof(audio_source_info[0]))
    488 #define MODEM_SOURCE_INFO_SIZE \
    489 		(sizeof(modem_source_info)/sizeof(modem_source_info[0]))
    490 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \
    491 		MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE)
    492 
    493 /*
    494  * Check out http://www.intel.com/support/motherboards/desktop/sb/cs-025406.htm for
    495  * AC'97 Component Specification
    496  */
    497 
    498 struct ac97_softc {
    499 	/* ac97_codec_if must be at the first of ac97_softc. */
    500 	struct ac97_codec_if codec_if;
    501 
    502 	struct ac97_host_if *host_if;
    503 
    504 	kmutex_t *lock;
    505 
    506 #define AUDIO_MAX_SOURCES	(2 * AUDIO_SOURCE_INFO_SIZE)
    507 #define MODEM_MAX_SOURCES	(2 * MODEM_SOURCE_INFO_SIZE)
    508 	struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES];
    509 	struct ac97_source_info modem_source_info[MODEM_MAX_SOURCES];
    510 	struct ac97_source_info *source_info;
    511 	int num_source_info;
    512 
    513 	enum ac97_host_flags host_flags;
    514 	unsigned int ac97_clock; /* usually 48000 */
    515 #define AC97_STANDARD_CLOCK	48000U
    516 	uint16_t power_all;
    517 	uint16_t power_reg;	/* -> AC97_REG_POWER */
    518 	uint16_t caps;		/* -> AC97_REG_RESET */
    519 	uint16_t ext_id;	/* -> AC97_REG_EXT_AUDIO_ID */
    520 	uint16_t ext_mid;	/* -> AC97_REG_EXT_MODEM_ID */
    521 	uint16_t shadow_reg[128];
    522 
    523 	int lock_counter;
    524 	int type;
    525 
    526 	/* sysctl */
    527 	struct sysctllog *log;
    528 	int offhook_line1_mib;
    529 	int offhook_line2_mib;
    530 	int offhook_line1;
    531 	int offhook_line2;
    532 };
    533 
    534 static struct ac97_codec_if_vtbl ac97civ = {
    535 	ac97_mixer_get_port,
    536 	ac97_mixer_set_port,
    537 	ac97_query_devinfo,
    538 	ac97_get_portnum_by_name,
    539 	ac97_restore_shadow,
    540 	ac97_get_extcaps,
    541 	ac97_set_rate,
    542 	ac97_set_clock,
    543 	ac97_detach,
    544 	ac97_lock,
    545 	ac97_unlock,
    546 };
    547 
    548 static const struct ac97_codecid {
    549 	uint32_t id;
    550 	uint32_t mask;
    551 	const char *name;
    552 	void (*init)(struct ac97_softc *);
    553 } ac97codecid[] = {
    554 	/*
    555 	 * Analog Devices SoundMAX
    556 	 * http://www.soundmax.com/products/information/codecs.html
    557 	 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
    558 	 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
    559 	 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
    560 	 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
    561 	 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
    562 	 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
    563 	 */
    564 	{ AC97_CODEC_ID('A', 'D', 'S', 3),
    565 	  0xffffffff,			"Analog Devices AD1819B", NULL, },
    566 	{ AC97_CODEC_ID('A', 'D', 'S', 0x40),
    567 	  0xffffffff,			"Analog Devices AD1881", NULL, },
    568 	{ AC97_CODEC_ID('A', 'D', 'S', 0x48),
    569 	  0xffffffff,			"Analog Devices AD1881A", NULL, },
    570 	{ AC97_CODEC_ID('A', 'D', 'S', 0x60),
    571 	  0xffffffff,			"Analog Devices AD1885", NULL, },
    572 	{ AC97_CODEC_ID('A', 'D', 'S', 0x61),
    573 	  0xffffffff,			"Analog Devices AD1886", NULL, },
    574 	{ AC97_CODEC_ID('A', 'D', 'S', 0x63),
    575 	  0xffffffff,			"Analog Devices AD1886A", NULL, },
    576 	{ AC97_CODEC_ID('A', 'D', 'S', 0x68),
    577 	  0xffffffff,			"Analog Devices AD1888", ac97_ad198x_init },
    578 	{ AC97_CODEC_ID('A', 'D', 'S', 0x70),
    579 	  0xffffffff,			"Analog Devices AD1980", ac97_ad198x_init },
    580 	{ AC97_CODEC_ID('A', 'D', 'S', 0x72),
    581 	  0xffffffff,			"Analog Devices AD1981A", NULL, },
    582 	{ AC97_CODEC_ID('A', 'D', 'S', 0x74),
    583 	  0xffffffff,			"Analog Devices AD1981B", NULL, },
    584 	{ AC97_CODEC_ID('A', 'D', 'S', 0x75),
    585 	  0xffffffff,			"Analog Devices AD1985", ac97_ad198x_init },
    586 	{ AC97_CODEC_ID('A', 'D', 'S', 0),
    587 	  AC97_VENDOR_ID_MASK,		"Analog Devices unknown", NULL, },
    588 
    589 	/*
    590 	 * Datasheets:
    591 	 *	http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf
    592 	 *	http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf
    593 	 *	http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf
    594 	 */
    595 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    596 	  0xffffffff,			"Asahi Kasei AK4540", NULL,	},
    597 	{ AC97_CODEC_ID('A', 'K', 'M', 1),
    598 	  0xffffffff,			"Asahi Kasei AK4542", NULL,	},
    599 	{ AC97_CODEC_ID('A', 'K', 'M', 2),
    600 	  0xffffffff,			"Asahi Kasei AK4541/AK4543", NULL, },
    601 	{ AC97_CODEC_ID('A', 'K', 'M', 5),
    602 	  0xffffffff,			"Asahi Kasei AK4544", NULL, },
    603 	{ AC97_CODEC_ID('A', 'K', 'M', 6),
    604 	  0xffffffff,			"Asahi Kasei AK4544A", NULL, },
    605 	{ AC97_CODEC_ID('A', 'K', 'M', 7),
    606 	  0xffffffff,			"Asahi Kasei AK4545", NULL, },
    607 	{ AC97_CODEC_ID('A', 'K', 'M', 0),
    608 	  AC97_VENDOR_ID_MASK,		"Asahi Kasei unknown", NULL, },
    609 
    610 	/*
    611 	 * Realtek & Avance Logic
    612 	 *	http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
    613 	 *
    614 	 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
    615 	 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
    616 	 */
    617 	{ AC97_CODEC_ID('A', 'L', 'C', 0x00),
    618 	  0xfffffff0,			"Realtek RL5306", NULL,	},
    619 	{ AC97_CODEC_ID('A', 'L', 'C', 0x10),
    620 	  0xfffffff0,			"Realtek RL5382", NULL,	},
    621 	{ AC97_CODEC_ID('A', 'L', 'C', 0x20),
    622 	  0xfffffff0,			"Realtek RL5383/RL5522/ALC100", NULL,	},
    623 	{ AC97_CODEC_ID('A', 'L', 'G', 0x10),
    624 	  0xffffffff,			"Avance Logic ALC200/ALC201", NULL,	},
    625 	{ AC97_CODEC_ID('A', 'L', 'G', 0x20),
    626 	  0xfffffff0,			"Avance Logic ALC650", ac97_alc650_init },
    627 	{ AC97_CODEC_ID('A', 'L', 'G', 0x30),
    628 	  0xffffffff,			"Avance Logic ALC101", NULL,	},
    629 	{ AC97_CODEC_ID('A', 'L', 'G', 0x40),
    630 	  0xffffffff,			"Avance Logic ALC202", NULL,	},
    631 	{ AC97_CODEC_ID('A', 'L', 'G', 0x50),
    632 	  0xffffffff,			"Avance Logic ALC250", NULL,	},
    633 	{ AC97_CODEC_ID('A', 'L', 'G', 0x60),
    634 	  0xfffffff0,			"Avance Logic ALC655", NULL,	},
    635 	{ AC97_CODEC_ID('A', 'L', 'G', 0x80),
    636 	  0xfffffff0,			"Avance Logic ALC658", NULL,	},
    637 	{ AC97_CODEC_ID('A', 'L', 'G', 0x90),
    638 	  0xfffffff0,			"Avance Logic ALC850", NULL,	},
    639 	{ AC97_CODEC_ID('A', 'L', 'C', 0),
    640 	  AC97_VENDOR_ID_MASK,		"Realtek unknown", NULL,	},
    641 	{ AC97_CODEC_ID('A', 'L', 'G', 0),
    642 	  AC97_VENDOR_ID_MASK,		"Avance Logic unknown", NULL,	},
    643 
    644 	/**
    645 	 * C-Media Electronics Inc.
    646 	 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
    647 	 */
    648 	{ AC97_CODEC_ID('C', 'M', 'I', 0x61),
    649 	  0xffffffff,			"C-Media CMI9739", NULL,	},
    650 	{ AC97_CODEC_ID('C', 'M', 'I', 0),
    651 	  AC97_VENDOR_ID_MASK,		"C-Media unknown", NULL,	},
    652 
    653 	/* Cirrus Logic, Crystal series:
    654 	 *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
    655 	 *              0x1[0-7]  - CS4297A
    656 	 *              0x2[0-7]  - CS4298
    657 	 *              0x2[8-f]  - CS4294
    658 	 *              0x3[0-7]  - CS4299
    659 	 *              0x4[8-f]  - CS4201
    660 	 *              0x5[8-f]  - CS4205
    661 	 *              0x6[0-7]  - CS4291
    662 	 *              0x7[0-7]  - CS4202
    663 	 * Datasheets:
    664 	 *	http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
    665 	 *	http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
    666 	 *	http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
    667 	 *	http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
    668 	 *	http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
    669 	 *	http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
    670 	 */
    671 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x00),
    672 	  0xfffffff8,			"Crystal CS4297", NULL,	},
    673 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x10),
    674 	  0xfffffff8,			"Crystal CS4297A", NULL,	},
    675 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x20),
    676 	  0xfffffff8,			"Crystal CS4298", NULL,	},
    677 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x28),
    678 	  0xfffffff8,			"Crystal CS4294", NULL,	},
    679 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x30),
    680 	  0xfffffff8,			"Crystal CS4299", NULL,	},
    681 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x48),
    682 	  0xfffffff8,			"Crystal CS4201", NULL,	},
    683 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x58),
    684 	  0xfffffff8,			"Crystal CS4205", NULL,	},
    685 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x60),
    686 	  0xfffffff8,			"Crystal CS4291", NULL,	},
    687 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x70),
    688 	  0xfffffff8,			"Crystal CS4202", NULL,	},
    689 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),
    690 	  AC97_VENDOR_ID_MASK,		"Cirrus Logic unknown", NULL,	},
    691 
    692 	{ 0x45838308, 0xffffffff,	"ESS Technology ES1921", NULL, },
    693 	{ 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", NULL, },
    694 
    695 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    696 	  0xffffffff,			"Intersil HMP9701", NULL,	},
    697 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    698 	  AC97_VENDOR_ID_MASK,		"Intersil unknown", NULL,	},
    699 
    700 	/*
    701 	 * IC Ensemble (VIA)
    702 	 *	http://www.viatech.com/en/datasheet/DS1616.pdf
    703 	 */
    704 	{ AC97_CODEC_ID('I', 'C', 'E', 0x01),
    705 	  0xffffffff,			"ICEnsemble ICE1230/VT1611", NULL,	},
    706 	{ AC97_CODEC_ID('I', 'C', 'E', 0x11),
    707 	  0xffffffff,			"ICEnsemble ICE1232/VT1611A", NULL,	},
    708 	{ AC97_CODEC_ID('I', 'C', 'E', 0x14),
    709 	  0xffffffff,			"ICEnsemble ICE1232A", NULL,	},
    710 	{ AC97_CODEC_ID('I', 'C', 'E', 0x51),
    711 	  0xffffffff,			"VIA Technologies VT1616", ac97_vt1616_init },
    712 	{ AC97_CODEC_ID('I', 'C', 'E', 0x52),
    713 	  0xffffffff,			"VIA Technologies VT1616i", ac97_vt1616_init },
    714 	{ AC97_CODEC_ID('I', 'C', 'E', 0),
    715 	  AC97_VENDOR_ID_MASK,		"ICEnsemble/VIA unknown", NULL,	},
    716 
    717 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    718 	  0xffffffff,			"National Semiconductor LM454[03568]", NULL, },
    719 	{ AC97_CODEC_ID('N', 'S', 'C', 49),
    720 	  0xffffffff,			"National Semiconductor LM4549", NULL, },
    721 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    722 	  AC97_VENDOR_ID_MASK,		"National Semiconductor unknown", NULL, },
    723 
    724 	{ AC97_CODEC_ID('P', 'S', 'C', 4),
    725 	  0xffffffff,			"Philips Semiconductor UCB1400", ac97_ucb1400_init, },
    726 	{ AC97_CODEC_ID('P', 'S', 'C', 0),
    727 	  AC97_VENDOR_ID_MASK,		"Philips Semiconductor unknown", NULL, },
    728 
    729 	{ AC97_CODEC_ID('S', 'I', 'L', 34),
    730 	  0xffffffff,			"Silicon Laboratory Si3036", NULL, },
    731 	{ AC97_CODEC_ID('S', 'I', 'L', 35),
    732 	  0xffffffff,			"Silicon Laboratory Si3038", NULL, },
    733 	{ AC97_CODEC_ID('S', 'I', 'L', 0),
    734 	  AC97_VENDOR_ID_MASK,		"Silicon Laboratory unknown", NULL, },
    735 
    736 	{ AC97_CODEC_ID('T', 'R', 'A', 2),
    737 	  0xffffffff,			"TriTech TR28022", NULL,	},
    738 	{ AC97_CODEC_ID('T', 'R', 'A', 3),
    739 	  0xffffffff,			"TriTech TR28023", NULL,	},
    740 	{ AC97_CODEC_ID('T', 'R', 'A', 6),
    741 	  0xffffffff,			"TriTech TR28026", NULL,	},
    742 	{ AC97_CODEC_ID('T', 'R', 'A', 8),
    743 	  0xffffffff,			"TriTech TR28028", NULL,	},
    744 	{ AC97_CODEC_ID('T', 'R', 'A', 35),
    745 	  0xffffffff,			"TriTech TR28602", NULL,	},
    746 	{ AC97_CODEC_ID('T', 'R', 'A', 0),
    747 	  AC97_VENDOR_ID_MASK,		"TriTech unknown", NULL,	},
    748 
    749 	{ AC97_CODEC_ID('T', 'X', 'N', 0x20),
    750 	  0xffffffff,			"Texas Instruments TLC320AD9xC", NULL, },
    751 	{ AC97_CODEC_ID('T', 'X', 'N', 0),
    752 	  AC97_VENDOR_ID_MASK,		"Texas Instruments unknown", NULL, },
    753 
    754 	/*
    755 	 * VIA
    756 	 * http://www.viatech.com/en/multimedia/audio.jsp
    757 	 */
    758 	{ AC97_CODEC_ID('V', 'I', 'A', 0x61),
    759 	  0xffffffff,			"VIA Technologies VT1612A", NULL, },
    760 	{ AC97_CODEC_ID('V', 'I', 'A', 0),
    761 	  AC97_VENDOR_ID_MASK,		"VIA Technologies unknown", NULL, },
    762 
    763 	{ AC97_CODEC_ID('W', 'E', 'C', 1),
    764 	  0xffffffff,			"Winbond W83971D", NULL,	},
    765 	{ AC97_CODEC_ID('W', 'E', 'C', 0),
    766 	  AC97_VENDOR_ID_MASK,		"Winbond unknown", NULL,	},
    767 
    768 	/*
    769 	 * http://www.wolfsonmicro.com/product_list.asp?cid=64
    770 	 *	http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
    771 	 *	http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
    772 	 *	http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
    773 	 *	http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
    774 	 *	http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
    775 	 *	http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
    776 	 *	http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
    777 	 *	http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
    778 	 */
    779 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    780 	  0xffffffff,			"Wolfson WM9701A", NULL,	},
    781 	{ AC97_CODEC_ID('W', 'M', 'L', 3),
    782 	  0xffffffff,			"Wolfson WM9703/WM9707/WM9708", NULL,	},
    783 	{ AC97_CODEC_ID('W', 'M', 'L', 4),
    784 	  0xffffffff,			"Wolfson WM9704", NULL,	},
    785 	{ AC97_CODEC_ID('W', 'M', 'L', 5),
    786 	  0xffffffff,			"Wolfson WM9705/WM9710", NULL, },
    787 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    788 	  AC97_VENDOR_ID_MASK,		"Wolfson unknown", NULL,	},
    789 
    790 	/*
    791 	 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
    792 	 * Datasheets:
    793 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
    794 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
    795 	 */
    796 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    797 	  0xffffffff,			"Yamaha YMF743-S", NULL,	},
    798 	{ AC97_CODEC_ID('Y', 'M', 'H', 3),
    799 	  0xffffffff,			"Yamaha YMF753-S", NULL,	},
    800 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    801 	  AC97_VENDOR_ID_MASK,		"Yamaha unknown", NULL,	},
    802 
    803 	/*
    804 	 * http://www.sigmatel.com/products/technical_docs.htm
    805 	 * and
    806 	 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
    807 	 */
    808 	{ 0x83847600, 0xffffffff,	"SigmaTel STAC9700",	NULL, },
    809 	{ 0x83847604, 0xffffffff,	"SigmaTel STAC9701/3/4/5", NULL, },
    810 	{ 0x83847605, 0xffffffff,	"SigmaTel STAC9704",	NULL, },
    811 	{ 0x83847608, 0xffffffff,	"SigmaTel STAC9708",	NULL, },
    812 	{ 0x83847609, 0xffffffff,	"SigmaTel STAC9721/23",	NULL, },
    813 	{ 0x83847644, 0xffffffff,	"SigmaTel STAC9744/45",	NULL, },
    814 	{ 0x83847650, 0xffffffff,	"SigmaTel STAC9750/51",	NULL, },
    815 	{ 0x83847652, 0xffffffff,	"SigmaTel STAC9752/53",	NULL, },
    816 	{ 0x83847656, 0xffffffff,	"SigmaTel STAC9756/57",	NULL, },
    817 	{ 0x83847658, 0xffffffff,	"SigmaTel STAC9758/59",	NULL, },
    818 	{ 0x83847666, 0xffffffff,	"SigmaTel STAC9766/67",	NULL, },
    819 	{ 0x83847684, 0xffffffff,	"SigmaTel STAC9783/84",	NULL, },
    820 	{ 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",	NULL, },
    821 
    822 	/* Conexant AC'97 modems -- good luck finding datasheets! */
    823 	{ AC97_CODEC_ID('C', 'X', 'T', 33),
    824 	  0xffffffff,			"Conexant HSD11246", NULL, },
    825 	{ AC97_CODEC_ID('C', 'X', 'T', 34),
    826 	  0xffffffff,			"Conexant D480 MDC V.92 Modem", NULL, },
    827 	{ AC97_CODEC_ID('C', 'X', 'T', 48),
    828 	  0xffffffff,			"Conexant CXT48", NULL, },
    829 	{ AC97_CODEC_ID('C', 'X', 'T', 0),
    830 	  AC97_VENDOR_ID_MASK,		"Conexant unknown", NULL, },
    831 
    832 	{ 0,
    833 	  0,			NULL,	NULL, 		},
    834 };
    835 
    836 static const char * const ac97enhancement[] = {
    837 	"no 3D stereo",
    838 	"Analog Devices Phat Stereo",
    839 	"Creative",
    840 	"National Semi 3D",
    841 	"Yamaha Ymersion",
    842 	"BBE 3D",
    843 	"Crystal Semi 3D",
    844 	"Qsound QXpander",
    845 	"Spatializer 3D",
    846 	"SRS 3D",
    847 	"Platform Tech 3D",
    848 	"AKM 3D",
    849 	"Aureal",
    850 	"AZTECH 3D",
    851 	"Binaura 3D",
    852 	"ESS Technology",
    853 	"Harman International VMAx",
    854 	"Nvidea 3D",
    855 	"Philips Incredible Sound",
    856 	"Texas Instruments' 3D",
    857 	"VLSI Technology 3D",
    858 	"TriTech 3D",
    859 	"Realtek 3D",
    860 	"Samsung 3D",
    861 	"Wolfson Microelectronics 3D",
    862 	"Delta Integration 3D",
    863 	"SigmaTel 3D",
    864 	"KS Waves 3D",
    865 	"Rockwell 3D",
    866 	"Unknown 3D",
    867 	"Unknown 3D",
    868 	"Unknown 3D",
    869 };
    870 
    871 static const char * const ac97feature[] = {
    872 	"dedicated mic channel",
    873 	"reserved",
    874 	"tone",
    875 	"simulated stereo",
    876 	"headphone",
    877 	"bass boost",
    878 	"18 bit DAC",
    879 	"20 bit DAC",
    880 	"18 bit ADC",
    881 	"20 bit ADC"
    882 };
    883 
    884 
    885 /* #define AC97_DEBUG 10 */
    886 /* #define AC97_IO_DEBUG */
    887 
    888 #ifdef AUDIO_DEBUG
    889 #define DPRINTF(x)	if (ac97debug) printf x
    890 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    891 #ifdef AC97_DEBUG
    892 int	ac97debug = AC97_DEBUG;
    893 #else
    894 int	ac97debug = 0;
    895 #endif
    896 #else
    897 #define DPRINTF(x)
    898 #define DPRINTFN(n,x)
    899 #endif
    900 
    901 #ifdef AC97_IO_DEBUG
    902 static const char *ac97_register_names[0x80 / 2] = {
    903 	"RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
    904 	"MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
    905 	"LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
    906 	"PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
    907 	"GP", "3D_CONTROL", "AUDIO_INT", "POWER",
    908 	"EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
    909 	"PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
    910 	"SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
    911 	"LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
    912 	"LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
    913 	"GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
    914 	"0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
    915 	"0x60", "0x62", "0x64", "0x66",
    916 	"0x68", "0x6a", "0x6c", "0x6e",
    917 	"VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
    918 	"VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
    919 };
    920 #endif
    921 
    922 /*
    923  * XXX Some cards have an inverted AC97_POWER_EAMP bit.
    924  * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
    925  */
    926 
    927 #define POWER_EAMP_ON(as)  ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
    928 			    ? AC97_POWER_EAMP : 0)
    929 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
    930 			    ? 0 : AC97_POWER_EAMP)
    931 
    932 static void
    933 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
    934 {
    935 	KASSERT(mutex_owned(as->lock));
    936 
    937 	if (as->host_flags & AC97_HOST_DONT_READ &&
    938 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    939 	     reg != AC97_REG_RESET)) {
    940 		*val = as->shadow_reg[reg >> 1];
    941 		return;
    942 	}
    943 
    944 	if (as->host_if->read(as->host_if->arg, reg, val)) {
    945 		*val = as->shadow_reg[reg >> 1];
    946 	}
    947 }
    948 
    949 static int
    950 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
    951 {
    952 	KASSERT(mutex_owned(as->lock));
    953 
    954 #ifndef AC97_IO_DEBUG
    955 	as->shadow_reg[reg >> 1] = val;
    956 	return as->host_if->write(as->host_if->arg, reg, val);
    957 #else
    958 	int ret;
    959 	uint16_t actual;
    960 
    961 	as->shadow_reg[reg >> 1] = val;
    962 	ret = as->host_if->write(as->host_if->arg, reg, val);
    963 	as->host_if->read(as->host_if->arg, reg, &actual);
    964 	if (val != actual && reg < 0x80) {
    965 		printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
    966 		       ac97_register_names[reg / 2], val, actual);
    967 	}
    968 	return ret;
    969 #endif
    970 }
    971 
    972 static void
    973 ac97_setup_defaults(struct ac97_softc *as)
    974 {
    975 	int idx;
    976 	const struct ac97_source_info *si;
    977 
    978 	KASSERT(mutex_owned(as->lock));
    979 
    980 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    981 
    982 	for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
    983 		si = &audio_source_info[idx];
    984 		if (si->default_value >= 0)
    985 			ac97_write(as, si->reg, si->default_value);
    986 	}
    987 	for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) {
    988 		si = &modem_source_info[idx];
    989 		if (si->default_value >= 0)
    990 			ac97_write(as, si->reg, si->default_value);
    991 	}
    992 }
    993 
    994 static void
    995 ac97_restore_shadow(struct ac97_codec_if *self)
    996 {
    997 	struct ac97_softc *as;
    998 	const struct ac97_source_info *si;
    999 	int idx;
   1000 	uint16_t val;
   1001 
   1002 	as = (struct ac97_softc *) self;
   1003 
   1004 	KASSERT(mutex_owned(as->lock));
   1005 
   1006 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1007 		/* restore AC97_REG_POWER */
   1008 		ac97_write(as, AC97_REG_POWER, as->power_reg);
   1009 		/* make sure chip is fully operational */
   1010 		for (idx = 50000; idx >= 0; idx--) {
   1011 			ac97_read(as, AC97_REG_POWER, &val);
   1012 			if ((val & as->power_all) == as->power_all)
   1013 				break;
   1014 			DELAY(10);
   1015 		}
   1016 
   1017 		/*
   1018 		 * actually try changing a value!
   1019 		 * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
   1020 		 */
   1021 		for (idx = 50000; idx >= 0; idx--) {
   1022 			ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
   1023 			ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
   1024 			if (val == 0x1010)
   1025 				break;
   1026 			DELAY(10);
   1027 		}
   1028 	}
   1029 
   1030        for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
   1031 		if (as->type == AC97_CODEC_TYPE_MODEM)
   1032 			si = &modem_source_info[idx];
   1033 		else
   1034 			si = &audio_source_info[idx];
   1035 		/* don't "restore" to the reset reg! */
   1036 		if (si->reg != AC97_REG_RESET)
   1037 			ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
   1038 	}
   1039 
   1040 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
   1041 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
   1042 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
   1043 			  | AC97_EXT_AUDIO_LDAC)) {
   1044 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
   1045 		    as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
   1046 	}
   1047 	if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2
   1048 			  | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1
   1049 			  | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0
   1050 			  | AC97_EXT_MODEM_ID1)) {
   1051 		ac97_write(as, AC97_REG_EXT_MODEM_CTRL,
   1052 		    as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]);
   1053 	}
   1054 }
   1055 
   1056 static int
   1057 ac97_str_equal(const char *a, const char *b)
   1058 {
   1059 	return (a == b) || (a && b && (!strcmp(a, b)));
   1060 }
   1061 
   1062 static int
   1063 ac97_check_capability(struct ac97_softc *as, int check)
   1064 {
   1065 	switch (check) {
   1066 	case CHECK_NONE:
   1067 		return 1;
   1068 	case CHECK_SURROUND:
   1069 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
   1070 	case CHECK_CENTER:
   1071 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
   1072 	case CHECK_LFE:
   1073 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
   1074 	case CHECK_SPDIF:
   1075 		return as->ext_id & AC97_EXT_AUDIO_SPDIF;
   1076 	case CHECK_HEADPHONES:
   1077 		return as->caps & AC97_CAPS_HEADPHONES;
   1078 	case CHECK_TONE:
   1079 		return as->caps & AC97_CAPS_TONECTRL;
   1080 	case CHECK_MIC:
   1081 		return as->caps & AC97_CAPS_MICIN;
   1082 	case CHECK_LOUDNESS:
   1083 		return as->caps & AC97_CAPS_LOUDNESS;
   1084 	case CHECK_3D:
   1085 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
   1086 	case CHECK_LINE1:
   1087 		return as->ext_mid & AC97_EXT_MODEM_LINE1;
   1088 	case CHECK_LINE2:
   1089 		return as->ext_mid & AC97_EXT_MODEM_LINE2;
   1090 	case CHECK_HANDSET:
   1091 		return as->ext_mid & AC97_EXT_MODEM_HANDSET;
   1092 	default:
   1093 		printf("%s: internal error: feature=%d\n", __func__, check);
   1094 		return 0;
   1095 	}
   1096 }
   1097 
   1098 static void
   1099 ac97_setup_source_info(struct ac97_softc *as)
   1100 {
   1101 	int idx, ouridx;
   1102 	struct ac97_source_info *si, *si2;
   1103 	uint16_t value1, value2, value3;
   1104 
   1105 	KASSERT(mutex_owned(as->lock));
   1106 
   1107 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
   1108 		si = &as->source_info[ouridx];
   1109 		if (as->type == AC97_CODEC_TYPE_MODEM) {
   1110 			memcpy(si, &modem_source_info[idx], sizeof(*si));
   1111 		} else {
   1112 			memcpy(si, &audio_source_info[idx], sizeof(*si));
   1113 		}
   1114 		if (!ac97_check_capability(as, si->req_feature))
   1115 			continue;
   1116 		if (si->checkbits) {
   1117 			/* read the register value */
   1118 			ac97_read(as, si->reg, &value1);
   1119 			/* write 0b100000 */
   1120 			value2 = value1 & 0xffc0;
   1121 			value2 |= 0x20;
   1122 			ac97_write(as, si->reg, value2);
   1123 			/* verify */
   1124 			ac97_read(as, si->reg, &value3);
   1125 			if (value2 == value3) {
   1126 				si->bits = 6;
   1127 			} else {
   1128 				si->bits = 5;
   1129 			}
   1130 			DPRINTF(("%s: register=%02x bits=%d\n",
   1131 			    __func__, si->reg, si->bits));
   1132 			ac97_write(as, si->reg, value1);
   1133 		}
   1134 
   1135 		switch (si->type) {
   1136 		case AUDIO_MIXER_CLASS:
   1137 			si->mixer_class = ouridx;
   1138 			ouridx++;
   1139 			break;
   1140 		case AUDIO_MIXER_VALUE:
   1141 			/* Todo - Test to see if it works */
   1142 			ouridx++;
   1143 
   1144 			/* Add an entry for mute, if necessary */
   1145 			if (si->mute) {
   1146 				si = &as->source_info[ouridx];
   1147 				if (as->type == AC97_CODEC_TYPE_MODEM)
   1148 					memcpy(si, &modem_source_info[idx],
   1149 					    sizeof(*si));
   1150 				else
   1151 					memcpy(si, &audio_source_info[idx],
   1152 					    sizeof(*si));
   1153 				si->qualifier = AudioNmute;
   1154 				si->type = AUDIO_MIXER_ENUM;
   1155 				si->info = &ac97_on_off;
   1156 				si->info_size = sizeof(ac97_on_off);
   1157 				si->bits = 1;
   1158 				si->ofs = 15;
   1159 				si->mute = 0;
   1160 				si->polarity = 0;
   1161 				ouridx++;
   1162 			}
   1163 			break;
   1164 		case AUDIO_MIXER_ENUM:
   1165 			/* Todo - Test to see if it works */
   1166 			ouridx++;
   1167 			break;
   1168 		default:
   1169 			aprint_error ("ac97: shouldn't get here\n");
   1170 			break;
   1171 		}
   1172 	}
   1173 
   1174 	as->num_source_info = ouridx;
   1175 
   1176 	for (idx = 0; idx < as->num_source_info; idx++) {
   1177 		int idx2, previdx;
   1178 
   1179 		si = &as->source_info[idx];
   1180 
   1181 		/* Find mixer class */
   1182 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
   1183 			si2 = &as->source_info[idx2];
   1184 
   1185 			if (si2->type == AUDIO_MIXER_CLASS &&
   1186 			    ac97_str_equal(si->class,
   1187 					   si2->class)) {
   1188 				si->mixer_class = idx2;
   1189 			}
   1190 		}
   1191 
   1192 
   1193 		/* Setup prev and next pointers */
   1194 		if (si->prev != 0)
   1195 			continue;
   1196 
   1197 		if (si->qualifier)
   1198 			continue;
   1199 
   1200 		si->prev = AUDIO_MIXER_LAST;
   1201 		previdx = idx;
   1202 
   1203 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
   1204 			if (idx2 == idx)
   1205 				continue;
   1206 
   1207 			si2 = &as->source_info[idx2];
   1208 
   1209 			if (!si2->prev &&
   1210 			    ac97_str_equal(si->class, si2->class) &&
   1211 			    ac97_str_equal(si->device, si2->device)) {
   1212 				as->source_info[previdx].next = idx2;
   1213 				as->source_info[idx2].prev = previdx;
   1214 
   1215 				previdx = idx2;
   1216 			}
   1217 		}
   1218 
   1219 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
   1220 	}
   1221 }
   1222 
   1223 /* backward compatibility */
   1224 int
   1225 ac97_attach(struct ac97_host_if *host_if, device_t sc_dev, kmutex_t *lk)
   1226 {
   1227 	return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO, lk);
   1228 }
   1229 
   1230 int
   1231 ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type, kmutex_t *lk)
   1232 {
   1233 	struct ac97_softc *as;
   1234 	int error, i, j;
   1235 	uint32_t id;
   1236 	uint16_t id1, id2;
   1237 	uint16_t extstat, rate;
   1238 	uint16_t val;
   1239 	mixer_ctrl_t ctl;
   1240 	void (*initfunc)(struct ac97_softc *);
   1241 #define FLAGBUFLEN	140
   1242 	char flagbuf[FLAGBUFLEN];
   1243 
   1244 	initfunc = NULL;
   1245 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
   1246 
   1247 	if (as == NULL)
   1248 		return ENOMEM;
   1249 
   1250 	as->codec_if.vtbl = &ac97civ;
   1251 	as->host_if = host_if;
   1252 	as->type = type;
   1253 	as->lock = lk;
   1254 
   1255 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
   1256 		free(as, M_DEVBUF);
   1257 		return error;
   1258 	}
   1259 
   1260 	mutex_enter(as->lock);
   1261 
   1262 	if (host_if->reset != NULL) {
   1263 		if ((error = host_if->reset(host_if->arg))) {
   1264 			mutex_exit(as->lock);
   1265 			free(as, M_DEVBUF);
   1266 			return error;
   1267 		}
   1268 	}
   1269 
   1270 	if (host_if->flags)
   1271 		as->host_flags = host_if->flags(host_if->arg);
   1272 
   1273 	/*
   1274 	 * Assume codec has all four power bits.
   1275 	 * XXXSCW: what to do for modems?
   1276 	 */
   1277 	as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
   1278 	    AC97_POWER_ADC;
   1279 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1280 		host_if->write(host_if->arg, AC97_REG_RESET, 0);
   1281 
   1282 		/*
   1283 		 * Power-up everything except the analogue mixer.
   1284 		 * If this codec doesn't support analogue mixer power-down,
   1285 		 * AC97_POWER_MIXER will read back as zero.
   1286 		 */
   1287 		host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
   1288 		ac97_read(as, AC97_REG_POWER, &val);
   1289 		if ((val & AC97_POWER_MIXER) == 0) {
   1290 			/* Codec doesn't support analogue mixer power-down */
   1291 			as->power_all &= ~AC97_POWER_ANL;
   1292 		}
   1293 		host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as));
   1294 
   1295 		for (i = 500000; i >= 0; i--) {
   1296 			ac97_read(as, AC97_REG_POWER, &val);
   1297 			if ((val & as->power_all) == as->power_all)
   1298 			       break;
   1299 			DELAY(1);
   1300 		}
   1301 
   1302 		/* save AC97_REG_POWER so that we can restore it later */
   1303 		ac97_read(as, AC97_REG_POWER, &as->power_reg);
   1304 	} else if (as->type == AC97_CODEC_TYPE_MODEM) {
   1305 		host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
   1306 	}
   1307 
   1308 	ac97_setup_defaults(as);
   1309 	if (as->type == AC97_CODEC_TYPE_AUDIO)
   1310 		ac97_read(as, AC97_REG_RESET, &as->caps);
   1311 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
   1312 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
   1313 
   1314 	mutex_exit(as->lock);
   1315 
   1316 	id = (id1 << 16) | id2;
   1317 	aprint_normal_dev(sc_dev, "ac97: ");
   1318 
   1319 	for (i = 0; ; i++) {
   1320 		if (ac97codecid[i].id == 0) {
   1321 			char pnp[4];
   1322 
   1323 			AC97_GET_CODEC_ID(id, pnp);
   1324 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
   1325 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
   1326 			    ISASCII(pnp[2]))
   1327 				aprint_normal("%c%c%c%d",
   1328 				    pnp[0], pnp[1], pnp[2], pnp[3]);
   1329 			else
   1330 				aprint_normal("unknown (0x%08x)", id);
   1331 			break;
   1332 		}
   1333 		if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
   1334 			aprint_normal("%s", ac97codecid[i].name);
   1335 			if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
   1336 				aprint_normal(" (0x%08x)", id);
   1337 			}
   1338 			initfunc = ac97codecid[i].init;
   1339 			break;
   1340 		}
   1341 	}
   1342 	aprint_normal(" codec; ");
   1343 	for (i = j = 0; i < 10; i++) {
   1344 		if (as->caps & (1 << i)) {
   1345 			aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
   1346 			j++;
   1347 		}
   1348 	}
   1349 	aprint_normal("%s%s\n", j ? ", " : "",
   1350 	       ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
   1351 
   1352 	as->ac97_clock = AC97_STANDARD_CLOCK;
   1353 
   1354 	mutex_enter(as->lock);
   1355 
   1356 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1357 		ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
   1358 		if (as->ext_id != 0) {
   1359 			mutex_exit(as->lock);
   1360 
   1361 			/* Print capabilities */
   1362 			snprintb(flagbuf, sizeof(flagbuf),
   1363 			     "\20\20SECONDARY10\17SECONDARY01"
   1364 			     "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
   1365 			     "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", as->ext_id);
   1366 			aprint_normal_dev(sc_dev, "ac97: ext id %s\n",
   1367 				      flagbuf);
   1368 
   1369 			/* Print unusual settings */
   1370 			if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
   1371 				aprint_normal_dev(sc_dev, "ac97: Slot assignment: ");
   1372 				switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
   1373 				case AC97_EXT_AUDIO_DSA01:
   1374 					aprint_normal("7&8, 6&9, 10&11.\n");
   1375 					break;
   1376 				case AC97_EXT_AUDIO_DSA10:
   1377 					aprint_normal("6&9, 10&11, 3&4.\n");
   1378 					break;
   1379 				case AC97_EXT_AUDIO_DSA11:
   1380 					aprint_normal("10&11, 3&4, 7&8.\n");
   1381 					break;
   1382 				}
   1383 			}
   1384 			if (as->host_flags & AC97_HOST_INVERTED_EAMP) {
   1385 				aprint_normal_dev(sc_dev, "ac97: using inverted "
   1386 					      "AC97_POWER_EAMP bit\n");
   1387 			}
   1388 
   1389 			mutex_enter(as->lock);
   1390 
   1391 			/* Enable and disable features */
   1392 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
   1393 			extstat &= ~AC97_EXT_AUDIO_DRA;
   1394 			if (as->ext_id & AC97_EXT_AUDIO_LDAC)
   1395 				extstat |= AC97_EXT_AUDIO_LDAC;
   1396 			if (as->ext_id & AC97_EXT_AUDIO_SDAC)
   1397 				extstat |= AC97_EXT_AUDIO_SDAC;
   1398 			if (as->ext_id & AC97_EXT_AUDIO_CDAC)
   1399 				extstat |= AC97_EXT_AUDIO_CDAC;
   1400 			if (as->ext_id & AC97_EXT_AUDIO_VRM)
   1401 				extstat |= AC97_EXT_AUDIO_VRM;
   1402 			if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
   1403 				/* Output the same data as DAC to SPDIF output */
   1404 				extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
   1405 				extstat |= AC97_EXT_AUDIO_SPSA34;
   1406 				ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
   1407 				val = (val & ~AC97_SPDIF_SPSR_MASK)
   1408 				    | AC97_SPDIF_SPSR_48K;
   1409 				ac97_write(as, AC97_REG_SPDIF_CTRL, val);
   1410 			}
   1411 			if (as->ext_id & AC97_EXT_AUDIO_VRA)
   1412 				extstat |= AC97_EXT_AUDIO_VRA;
   1413 			ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
   1414 			if (as->ext_id & AC97_EXT_AUDIO_VRA) {
   1415 				/* VRA should be enabled. */
   1416 				/* so it claims to do variable rate, let's make sure */
   1417 				ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1418 					   44100);
   1419 				ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1420 					  &rate);
   1421 				if (rate != 44100) {
   1422 					/* We can't believe ext_id */
   1423 					as->ext_id = 0;
   1424 					aprint_normal_dev(sc_dev,
   1425 					    "Ignore these capabilities.\n");
   1426 				}
   1427 				/* restore the default value */
   1428 				ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1429 					   AC97_SINGLE_RATE);
   1430 			}
   1431 		}
   1432 	} else if (as->type == AC97_CODEC_TYPE_MODEM) {
   1433 		const struct sysctlnode *node;
   1434 		const struct sysctlnode *node_line1;
   1435 		const struct sysctlnode *node_line2;
   1436 		uint16_t xrate = 8000;
   1437 		uint16_t xval, reg;
   1438 		int err;
   1439 
   1440 		ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
   1441 		mutex_exit(as->lock);
   1442 
   1443 		if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
   1444 			aprint_normal_dev(sc_dev, "no modem codec found\n");
   1445 			return ENXIO;
   1446 		}
   1447 		as->type = AC97_CODEC_TYPE_MODEM;
   1448 
   1449 		/* Print capabilities */
   1450 		snprintb(flagbuf, sizeof(flagbuf),
   1451 		    "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as->ext_mid);
   1452 		aprint_normal_dev(sc_dev, "ac97: ext mid %s",
   1453 			      flagbuf);
   1454 		aprint_normal(", %s codec\n",
   1455 			      (as->ext_mid & 0xc000) == 0 ?
   1456 			      "primary" : "secondary");
   1457 
   1458 		/* Setup modem and sysctls */
   1459 		err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
   1460 				     "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
   1461 				     CTL_EOL);
   1462 		if (err != 0)
   1463 			goto setup_modem;
   1464 		err = sysctl_createv(&as->log, 0, NULL, &node, 0,
   1465 				     CTLTYPE_NODE, device_xname(sc_dev), NULL,
   1466 				     NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
   1467 				     CTL_EOL);
   1468 		if (err != 0)
   1469 			goto setup_modem;
   1470 setup_modem:
   1471 		mutex_enter(as->lock);
   1472 
   1473 		/* reset */
   1474 		ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
   1475 
   1476 		/* program rates */
   1477 		xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
   1478 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1479 			ac97_write(as, AC97_REG_LINE1_RATE, xrate);
   1480 			xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
   1481 			       AC97_EXT_MODEM_CTRL_PRD);
   1482 		}
   1483 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1484 			ac97_write(as, AC97_REG_LINE2_RATE, xrate);
   1485 			xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
   1486 			       AC97_EXT_MODEM_CTRL_PRF);
   1487 		}
   1488 		if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
   1489 			ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
   1490 			xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
   1491 			       AC97_EXT_MODEM_CTRL_PRH);
   1492 		}
   1493 
   1494 		/* power-up everything */
   1495 		ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
   1496 		for (i = 5000; i >= 0; i--) {
   1497 			ac97_read(as, AC97_REG_EXT_MODEM_CTRL, &reg);
   1498 			if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
   1499 			       break;
   1500 			DELAY(1);
   1501 		}
   1502 		if (i <= 0) {
   1503 			mutex_exit(as->lock);
   1504 			printf("%s: codec not responding, status=0x%x\n",
   1505 			    device_xname(sc_dev), reg);
   1506 			return ENXIO;
   1507 		}
   1508 
   1509 		/* setup sysctls */
   1510 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1511 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1512 			reg &= ~AC97_GPIO_LINE1_OH;
   1513 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1514 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1515 			reg &= ~AC97_GPIO_LINE1_OH;
   1516 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1517 
   1518 			mutex_exit(as->lock);
   1519 			err = sysctl_createv(&as->log, 0, NULL, &node_line1,
   1520 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1521 					     "line1",
   1522 					     SYSCTL_DESCR("off-hook line1"),
   1523 					     ac97_sysctl_verify, 0, as, 0,
   1524 					     CTL_HW, node->sysctl_num,
   1525 					     CTL_CREATE, CTL_EOL);
   1526 			mutex_enter(as->lock);
   1527 
   1528 			if (err != 0)
   1529 				goto sysctl_err;
   1530 			as->offhook_line1_mib = node_line1->sysctl_num;
   1531 		}
   1532 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1533 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1534 			reg &= ~AC97_GPIO_LINE2_OH;
   1535 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1536 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1537 			reg &= ~AC97_GPIO_LINE2_OH;
   1538 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1539 
   1540 			mutex_exit(as->lock);
   1541 			err = sysctl_createv(&as->log, 0, NULL, &node_line2,
   1542 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1543 					     "line2",
   1544 					     SYSCTL_DESCR("off-hook line2"),
   1545 					     ac97_sysctl_verify, 0, as, 0,
   1546 					     CTL_HW, node->sysctl_num,
   1547 					     CTL_CREATE, CTL_EOL);
   1548 			mutex_enter(as->lock);
   1549 
   1550 			if (err != 0)
   1551 				goto sysctl_err;
   1552 			as->offhook_line2_mib = node_line2->sysctl_num;
   1553 		}
   1554 sysctl_err:
   1555 
   1556 		ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
   1557 		ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
   1558 		ac97_write(as, AC97_REG_MISC_AFE, 0x0);
   1559 	}
   1560 
   1561 	as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
   1562 			   as->modem_source_info : as->audio_source_info);
   1563 	ac97_setup_source_info(as);
   1564 
   1565 	memset(&ctl, 0, sizeof(ctl));
   1566 	/* disable mutes */
   1567 	for (i = 0; i < 11; i++) {
   1568 		static struct {
   1569 			const char *class, *device;
   1570 		} d[11] = {
   1571 			{ AudioCoutputs, AudioNmaster},
   1572 			{ AudioCoutputs, AudioNheadphone},
   1573 			{ AudioCoutputs, AudioNsurround},
   1574 			{ AudioCoutputs, AudioNcenter},
   1575 			{ AudioCoutputs, AudioNlfe},
   1576 			{ AudioCinputs, AudioNdac},
   1577 			{ AudioCinputs, AudioNcd},
   1578 			{ AudioCinputs, AudioNline},
   1579 			{ AudioCinputs, AudioNaux},
   1580 			{ AudioCinputs, AudioNvideo},
   1581 			{ AudioCrecord, AudioNvolume},
   1582 		};
   1583 
   1584 		ctl.type = AUDIO_MIXER_ENUM;
   1585 		ctl.un.ord = 0;
   1586 
   1587 		ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
   1588 			d[i].class, d[i].device, AudioNmute);
   1589 		ac97_mixer_set_port(&as->codec_if, &ctl);
   1590 	}
   1591 	ctl.type = AUDIO_MIXER_ENUM;
   1592 	ctl.un.ord = 0;
   1593 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
   1594 					   AudioNsource, NULL);
   1595 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1596 
   1597 	/* set a reasonable default volume */
   1598 	ctl.type = AUDIO_MIXER_VALUE;
   1599 	ctl.un.value.num_channels = 2;
   1600 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
   1601 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
   1602 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1603 					   AudioNmaster, NULL);
   1604 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1605 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1606 					   AudioNsurround, NULL);
   1607 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1608 	ctl.un.value.num_channels = 1;
   1609 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1610 					   AudioNcenter, NULL);
   1611 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1612 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1613 					   AudioNlfe, NULL);
   1614 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1615 
   1616 	if (initfunc != NULL)
   1617 		initfunc(as);
   1618 
   1619 	/* restore AC97_REG_POWER */
   1620 	if (as->type == AC97_CODEC_TYPE_AUDIO)
   1621 		ac97_write(as, AC97_REG_POWER, as->power_reg);
   1622 
   1623 	mutex_exit(as->lock);
   1624 
   1625 	return 0;
   1626 }
   1627 
   1628 static void
   1629 ac97_detach(struct ac97_codec_if *codec_if)
   1630 {
   1631 	struct ac97_softc *as;
   1632 
   1633 	as = (struct ac97_softc *)codec_if;
   1634 
   1635 	mutex_enter(as->lock);
   1636 	ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
   1637 		   | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
   1638 		   | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
   1639 		   | POWER_EAMP_OFF(as));
   1640 	mutex_exit(as->lock);
   1641 
   1642 	free(as, M_DEVBUF);
   1643 }
   1644 
   1645 static void
   1646 ac97_lock(struct ac97_codec_if *codec_if)
   1647 {
   1648 	struct ac97_softc *as;
   1649 
   1650 	as = (struct ac97_softc *)codec_if;
   1651 
   1652 	KASSERT(mutex_owned(as->lock));
   1653 
   1654 	as->lock_counter++;
   1655 }
   1656 
   1657 static void
   1658 ac97_unlock(struct ac97_codec_if *codec_if)
   1659 {
   1660 	struct ac97_softc *as;
   1661 
   1662 	as = (struct ac97_softc *)codec_if;
   1663 
   1664 	KASSERT(mutex_owned(as->lock));
   1665 
   1666 	as->lock_counter--;
   1667 }
   1668 
   1669 static int
   1670 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
   1671 {
   1672 	struct ac97_softc *as;
   1673 	struct ac97_source_info *si;
   1674 	const char *name;
   1675 
   1676 	as = (struct ac97_softc *)codec_if;
   1677 	if (dip->index < as->num_source_info) {
   1678 		si = &as->source_info[dip->index];
   1679 		dip->type = si->type;
   1680 		dip->mixer_class = si->mixer_class;
   1681 		dip->prev = si->prev;
   1682 		dip->next = si->next;
   1683 
   1684 		if (si->qualifier)
   1685 			name = si->qualifier;
   1686 		else if (si->device)
   1687 			name = si->device;
   1688 		else if (si->class)
   1689 			name = si->class;
   1690 		else
   1691 			name = 0;
   1692 
   1693 		if (name)
   1694 			strcpy(dip->label.name, name);
   1695 
   1696 		memcpy(&dip->un, si->info, si->info_size);
   1697 
   1698 		/* Set the delta for volume sources */
   1699 		if (dip->type == AUDIO_MIXER_VALUE)
   1700 			dip->un.v.delta = 1 << (8 - si->bits);
   1701 
   1702 		return 0;
   1703 	}
   1704 
   1705 	return ENXIO;
   1706 }
   1707 
   1708 static int
   1709 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1710 {
   1711 	struct ac97_softc *as;
   1712 	struct ac97_source_info *si;
   1713 	uint16_t mask;
   1714 	uint16_t val, newval;
   1715 	int error;
   1716 	bool spdif;
   1717 
   1718 	as = (struct ac97_softc *)codec_if;
   1719 
   1720 	KASSERT(mutex_owned(as->lock));
   1721 
   1722 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1723 		return EINVAL;
   1724 	si = &as->source_info[cp->dev];
   1725 
   1726 	if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
   1727 		return EINVAL;
   1728 	spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
   1729 	if (spdif && as->lock_counter >= 0) {
   1730 		/* When the value of lock_counter is the default 0,
   1731 		 * it is not allowed to change the SPDIF mode. */
   1732 		return EBUSY;
   1733 	}
   1734 
   1735 	ac97_read(as, si->reg, &val);
   1736 
   1737 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1738 
   1739 	mask = (1 << si->bits) - 1;
   1740 
   1741 	switch (cp->type) {
   1742 	case AUDIO_MIXER_ENUM:
   1743 		if (cp->un.ord > mask || cp->un.ord < 0)
   1744 			return EINVAL;
   1745 
   1746 		newval = (cp->un.ord << si->ofs);
   1747 		if (si->reg == AC97_REG_RECORD_SELECT) {
   1748 			newval |= (newval << (8 + si->ofs));
   1749 			mask |= (mask << 8);
   1750 			mask = mask << si->ofs;
   1751 		} else if (si->reg == AC97_REG_SURR_MASTER) {
   1752 			newval = cp->un.ord ? 0x8080 : 0x0000;
   1753 			mask = 0x8080;
   1754 		} else
   1755 			mask = mask << si->ofs;
   1756 		break;
   1757 	case AUDIO_MIXER_VALUE:
   1758 	{
   1759 		const struct audio_mixer_value *value = si->info;
   1760 		uint16_t  l, r, ol, or;
   1761 		int deltal, deltar;
   1762 
   1763 		if ((cp->un.value.num_channels <= 0) ||
   1764 		    (cp->un.value.num_channels > value->num_channels))
   1765 			return EINVAL;
   1766 
   1767 		if (cp->un.value.num_channels == 1) {
   1768 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
   1769 		} else {
   1770 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1771 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1772 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1773 			} else {	/* left/right is reversed here */
   1774 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1775 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1776 			}
   1777 
   1778 		}
   1779 
   1780 		if (!si->polarity) {
   1781 			l = 255 - l;
   1782 			r = 255 - r;
   1783 		}
   1784 
   1785 		ol = (val >> (8+si->ofs)) & mask;
   1786 		or = (val >> si->ofs) & mask;
   1787 
   1788 		deltal = (ol << (8 - si->bits)) - l;
   1789 		deltar = (or << (8 - si->bits)) - r;
   1790 
   1791 		l = l >> (8 - si->bits);
   1792 		r = r >> (8 - si->bits);
   1793 
   1794 		if (deltal && ol == l)
   1795 			l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
   1796 		if (deltar && or == r)
   1797 			r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
   1798 
   1799 		newval = ((r & mask) << si->ofs);
   1800 		if (value->num_channels == 2) {
   1801 			newval = newval | ((l & mask) << (si->ofs+8));
   1802 			mask |= (mask << 8);
   1803 		}
   1804 		mask = mask << si->ofs;
   1805 		break;
   1806 	}
   1807 	default:
   1808 		return EINVAL;
   1809 	}
   1810 
   1811 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
   1812 	if (error)
   1813 		return error;
   1814 
   1815 	if (spdif && as->host_if->spdif_event != NULL) {
   1816 		DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
   1817 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
   1818 	}
   1819 	return 0;
   1820 }
   1821 
   1822 static int
   1823 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
   1824 			 const char *device, const char *qualifier)
   1825 {
   1826 	struct ac97_softc *as;
   1827 	int idx;
   1828 
   1829 	as = (struct ac97_softc *)codec_if;
   1830 
   1831 	KASSERT(mutex_owned(as->lock));
   1832 
   1833 	for (idx = 0; idx < as->num_source_info; idx++) {
   1834 		struct ac97_source_info *si = &as->source_info[idx];
   1835 		if (ac97_str_equal(class, si->class) &&
   1836 		    ac97_str_equal(device, si->device) &&
   1837 		    ac97_str_equal(qualifier, si->qualifier))
   1838 			return idx;
   1839 	}
   1840 
   1841 	return -1;
   1842 }
   1843 
   1844 static int
   1845 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1846 {
   1847 	struct ac97_softc *as;
   1848 	struct ac97_source_info *si;
   1849 	uint16_t mask;
   1850 	uint16_t val;
   1851 
   1852 	as = (struct ac97_softc *)codec_if;
   1853 
   1854 	KASSERT(mutex_owned(as->lock));
   1855 
   1856 	si = &as->source_info[cp->dev];
   1857 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1858 		return EINVAL;
   1859 
   1860 	if (cp->type != si->type)
   1861 		return EINVAL;
   1862 
   1863 	ac97_read(as, si->reg, &val);
   1864 
   1865 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1866 
   1867 	mask = (1 << si->bits) - 1;
   1868 
   1869 	switch (cp->type) {
   1870 	case AUDIO_MIXER_ENUM:
   1871 		cp->un.ord = (val >> si->ofs) & mask;
   1872 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
   1873 			     val, si->ofs, mask, cp->un.ord));
   1874 		break;
   1875 	case AUDIO_MIXER_VALUE:
   1876 	{
   1877 		const struct audio_mixer_value *value = si->info;
   1878 		uint16_t  l, r;
   1879 
   1880 		if ((cp->un.value.num_channels <= 0) ||
   1881 		    (cp->un.value.num_channels > value->num_channels))
   1882 			return EINVAL;
   1883 
   1884 		if (value->num_channels == 1) {
   1885 			l = r = (val >> si->ofs) & mask;
   1886 		} else {
   1887 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1888 				l = (val >> (si->ofs + 8)) & mask;
   1889 				r = (val >> si->ofs) & mask;
   1890 			} else {	/* host has reversed channels */
   1891 				r = (val >> (si->ofs + 8)) & mask;
   1892 				l = (val >> si->ofs) & mask;
   1893 			}
   1894 		}
   1895 
   1896 		l = (l << (8 - si->bits));
   1897 		r = (r << (8 - si->bits));
   1898 		if (!si->polarity) {
   1899 			l = 255 - l;
   1900 			r = 255 - r;
   1901 		}
   1902 
   1903 		/* The EAP driver averages l and r for stereo
   1904 		   channels that are requested in MONO mode. Does this
   1905 		   make sense? */
   1906 		if (cp->un.value.num_channels == 1) {
   1907 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
   1908 		} else if (cp->un.value.num_channels == 2) {
   1909 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
   1910 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
   1911 		}
   1912 
   1913 		break;
   1914 	}
   1915 	default:
   1916 		return EINVAL;
   1917 	}
   1918 
   1919 	return 0;
   1920 }
   1921 
   1922 
   1923 static int
   1924 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
   1925 {
   1926 	struct ac97_softc *as;
   1927 	u_int value;
   1928 	uint16_t ext_stat;
   1929 	uint16_t actual;
   1930 	uint16_t power;
   1931 	uint16_t power_bit;
   1932 
   1933 	as = (struct ac97_softc *)codec_if;
   1934 
   1935 	KASSERT(mutex_owned(as->lock));
   1936 
   1937 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
   1938 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1939 			*rate = AC97_SINGLE_RATE;
   1940 			return 0;
   1941 		}
   1942 	} else {
   1943 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1944 			*rate = AC97_SINGLE_RATE;
   1945 			return 0;
   1946 		}
   1947 	}
   1948 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
   1949 	ext_stat = 0;
   1950 	/*
   1951 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
   1952 	 *	Check VRA, DRA
   1953 	 * PCM_LR_ADC_RATE
   1954 	 *	Check VRA
   1955 	 * PCM_MIC_ADC_RATE
   1956 	 *	Check VRM
   1957 	 */
   1958 	switch (target) {
   1959 	case AC97_REG_PCM_FRONT_DAC_RATE:
   1960 	case AC97_REG_PCM_SURR_DAC_RATE:
   1961 	case AC97_REG_PCM_LFE_DAC_RATE:
   1962 		power_bit = AC97_POWER_OUT;
   1963 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1964 			*rate = AC97_SINGLE_RATE;
   1965 			return 0;
   1966 		}
   1967 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1968 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1969 			if (value > 0x1ffff) {
   1970 				return EINVAL;
   1971 			} else if (value > 0xffff) {
   1972 				/* Enable DRA */
   1973 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1974 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1975 				value /= 2;
   1976 			} else {
   1977 				/* Disable DRA */
   1978 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1979 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1980 			}
   1981 		} else {
   1982 			if (value > 0xffff)
   1983 				return EINVAL;
   1984 		}
   1985 		break;
   1986 	case AC97_REG_PCM_LR_ADC_RATE:
   1987 		power_bit = AC97_POWER_IN;
   1988 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1989 			*rate = AC97_SINGLE_RATE;
   1990 			return 0;
   1991 		}
   1992 		if (value > 0xffff)
   1993 			return EINVAL;
   1994 		break;
   1995 	case AC97_REG_PCM_MIC_ADC_RATE:
   1996 		power_bit = AC97_POWER_IN;
   1997 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1998 			*rate = AC97_SINGLE_RATE;
   1999 			return 0;
   2000 		}
   2001 		if (value > 0xffff)
   2002 			return EINVAL;
   2003 		break;
   2004 	default:
   2005 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   2006 		return EINVAL;
   2007 	}
   2008 
   2009 	ac97_read(as, AC97_REG_POWER, &power);
   2010 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   2011 
   2012 	ac97_write(as, target, (uint16_t)value);
   2013 	ac97_read(as, target, &actual);
   2014 	actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   2015 
   2016 	ac97_write(as, AC97_REG_POWER, power);
   2017 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   2018 		*rate = actual * 2;
   2019 	} else {
   2020 		*rate = actual;
   2021 	}
   2022 	return 0;
   2023 }
   2024 
   2025 static void
   2026 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   2027 {
   2028 	struct ac97_softc *as;
   2029 
   2030 	as = (struct ac97_softc *)codec_if;
   2031 
   2032 	KASSERT(mutex_owned(as->lock));
   2033 
   2034 	as->ac97_clock = clock;
   2035 }
   2036 
   2037 static uint16_t
   2038 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   2039 {
   2040 	struct ac97_softc *as;
   2041 
   2042 	as = (struct ac97_softc *)codec_if;
   2043 
   2044 	KASSERT(mutex_owned(as->lock));
   2045 
   2046 	return as->ext_id;
   2047 }
   2048 
   2049 static int
   2050 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
   2051 {
   2052 	struct ac97_source_info *si;
   2053 	int ouridx, idx;
   2054 
   2055 	KASSERT(mutex_owned(as->lock));
   2056 
   2057 	if ((as->type == AC97_CODEC_TYPE_AUDIO &&
   2058 	     as->num_source_info >= AUDIO_MAX_SOURCES) ||
   2059 	    (as->type == AC97_CODEC_TYPE_MODEM &&
   2060 	     as->num_source_info >= MODEM_MAX_SOURCES)) {
   2061 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
   2062 		       __func__, __FILE__);
   2063 		return -1;
   2064 	}
   2065 	if (!ac97_check_capability(as, src->req_feature))
   2066 		return -1;
   2067 	ouridx = as->num_source_info;
   2068 	si = &as->source_info[ouridx];
   2069 	memcpy(si, src, sizeof(*si));
   2070 
   2071 	switch (si->type) {
   2072 	case AUDIO_MIXER_CLASS:
   2073 	case AUDIO_MIXER_VALUE:
   2074 		printf("%s: adding class/value is not supported yet.\n",
   2075 		       __func__);
   2076 		return -1;
   2077 	case AUDIO_MIXER_ENUM:
   2078 		break;
   2079 	default:
   2080 		printf("%s: unknown type: %d\n", __func__, si->type);
   2081 		return -1;
   2082 	}
   2083 	as->num_source_info++;
   2084 
   2085 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2086 						   NULL, NULL);
   2087 	/* Find the root of the device */
   2088 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2089 				       si->device, NULL);
   2090 	/* Find the last item */
   2091 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
   2092 		idx = as->source_info[idx].next;
   2093 	/* Append */
   2094 	as->source_info[idx].next = ouridx;
   2095 	si->prev = idx;
   2096 	si->next = AUDIO_MIXER_LAST;
   2097 
   2098 	return 0;
   2099 }
   2100 
   2101 /**
   2102  * Codec-dependent initialization
   2103  */
   2104 
   2105 #define	AD1980_REG_MISC	0x76
   2106 #define		AD1980_MISC_MBG0	0x0001	/* 0 1888/1980/1981 /1985 */
   2107 #define		AD1980_MISC_MBG1	0x0002	/* 1 1888/1980/1981 /1985 */
   2108 #define		AD1980_MISC_VREFD	0x0004	/* 2 1888/1980/1981 /1985 */
   2109 #define		AD1980_MISC_VREFH	0x0008	/* 3 1888/1980/1981 /1985 */
   2110 #define		AD1980_MISC_SRU		0x0010	/* 4 1888/1980      /1985 */
   2111 #define		AD1980_MISC_LOSEL	0x0020	/* 5 1888/1980/1981 /1985 */
   2112 #define		AD1980_MISC_2CMIC	0x0040	/* 6      1980/1981B/1985 */
   2113 #define		AD1980_MISC_SPRD	0x0080	/* 7 1888/1980      /1985 */
   2114 #define		AD1980_MISC_DMIX0	0x0100	/* 8 1888/1980      /1985 */
   2115 #define		AD1980_MISC_DMIX1	0x0200	/* 9 1888/1980      /1985 */
   2116 #define		AD1980_MISC_HPSEL	0x0400	/*10 1888/1980      /1985 */
   2117 #define		AD1980_MISC_CLDIS	0x0800	/*11 1888/1980      /1985 */
   2118 #define		AD1980_MISC_LODIS	0x1000	/*12 1888/1980/1981 /1985 */
   2119 #define		AD1980_MISC_MSPLT	0x2000	/*13 1888/1980/1981 /1985 */
   2120 #define		AD1980_MISC_AC97NC	0x4000	/*14 1888/1980      /1985 */
   2121 #define		AD1980_MISC_DACZ	0x8000	/*15 1888/1980/1981 /1985 */
   2122 #define	AD1981_REG_MISC	0x76
   2123 #define		AD1981_MISC_MADST	0x0010  /* 4 */
   2124 #define		AD1981A_MISC_MADPD	0x0040  /* 6 */
   2125 #define		AD1981B_MISC_MADPD	0x0080  /* 7 */
   2126 #define		AD1981_MISC_FMXE	0x0200  /* 9 */
   2127 #define		AD1981_MISC_DAM		0x0800  /*11 */
   2128 static void
   2129 ac97_ad198x_init(struct ac97_softc *as)
   2130 {
   2131 	int i;
   2132 	uint16_t misc;
   2133 
   2134 	KASSERT(mutex_owned(as->lock));
   2135 
   2136 	ac97_read(as, AD1980_REG_MISC, &misc);
   2137 	ac97_write(as, AD1980_REG_MISC,
   2138 		   misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
   2139 
   2140 	for (i = 0; i < as->num_source_info; i++) {
   2141 		if (as->source_info[i].type != AUDIO_MIXER_VALUE)
   2142 			continue;
   2143 
   2144 		if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
   2145 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
   2146 		else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
   2147 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
   2148 	}
   2149 }
   2150 
   2151 #define ALC650_REG_MULTI_CHANNEL_CONTROL	0x6a
   2152 #define		ALC650_MCC_SLOT_MODIFY_MASK		0xc000
   2153 #define		ALC650_MCC_FRONTDAC_FROM_SPDIFIN	0x2000 /* 13 */
   2154 #define		ALC650_MCC_SPDIFOUT_FROM_ADC		0x1000 /* 12 */
   2155 #define		ALC650_MCC_PCM_FROM_SPDIFIN		0x0800 /* 11 */
   2156 #define		ALC650_MCC_MIC_OR_CENTERLFE		0x0400 /* 10 */
   2157 #define		ALC650_MCC_LINEIN_OR_SURROUND		0x0200 /* 9 */
   2158 #define		ALC650_MCC_INDEPENDENT_MASTER_L		0x0080 /* 7 */
   2159 #define		ALC650_MCC_INDEPENDENT_MASTER_R		0x0040 /* 6 */
   2160 #define		ALC650_MCC_ANALOG_TO_CENTERLFE		0x0020 /* 5 */
   2161 #define		ALC650_MCC_ANALOG_TO_SURROUND		0x0010 /* 4 */
   2162 #define		ALC650_MCC_EXCHANGE_CENTERLFE		0x0008 /* 3 */
   2163 #define		ALC650_MCC_CENTERLFE_DOWNMIX		0x0004 /* 2 */
   2164 #define		ALC650_MCC_SURROUND_DOWNMIX		0x0002 /* 1 */
   2165 #define		ALC650_MCC_LINEOUT_TO_SURROUND		0x0001 /* 0 */
   2166 static void
   2167 ac97_alc650_init(struct ac97_softc *as)
   2168 {
   2169 	static const struct ac97_source_info sources[6] = {
   2170 		{ AudioCoutputs, AudioNsurround, "lineinjack",
   2171 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2172 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2173 		  0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2174 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2175 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2176 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2177 		  0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2178 		{ AudioCoutputs, AudioNcenter, "micjack",
   2179 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2180 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2181 		  0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2182 		{ AudioCoutputs, AudioNlfe, "micjack",
   2183 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2184 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2185 		  0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2186 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2187 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2188 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2189 		  0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2190 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2191 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2192 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2193 		  0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2194 	};
   2195 
   2196 	ac97_add_port(as, &sources[0]);
   2197 	ac97_add_port(as, &sources[1]);
   2198 	ac97_add_port(as, &sources[2]);
   2199 	ac97_add_port(as, &sources[3]);
   2200 	ac97_add_port(as, &sources[4]);
   2201 	ac97_add_port(as, &sources[5]);
   2202 }
   2203 
   2204 #define UCB1400_REG_FEATURE_CSR1	0x6a
   2205 #define		UCB1400_BB(bb)			(((bb) & 0xf) << 11)
   2206 #define		UCB1400_TR(tr)			(((tr) & 0x3) << 9)
   2207 #define		UCB1400_M_MAXIMUM		(3 << 7)
   2208 #define		UCB1400_M_MINIMUM		(1 << 7)
   2209 #define		UCB1400_M_FLAT			(0 << 7)
   2210 #define		UCB1400_HPEN			(1 << 6)
   2211 #define		UCB1400_DE			(1 << 5)
   2212 #define		UCB1400_DC			(1 << 4)
   2213 #define		UCB1400_HIPS			(1 << 3)
   2214 #define		UCB1400_GIEN			(1 << 2)
   2215 #define		UCB1400_OVFL			(1 << 0)
   2216 #define UCB1400_REG_FEATURE_CSR2	0x6c
   2217 #define		UCB1400_SMT			(1 << 15)	/* Must be 0 */
   2218 #define		UCB1400_SUEV1			(1 << 14)	/* Must be 0 */
   2219 #define		UCB1400_SUEV0			(1 << 13)	/* Must be 0 */
   2220 #define		UCB1400_AVE			(1 << 12)
   2221 #define		UCB1400_AVEN1			(1 << 11)	/* Must be 0 */
   2222 #define		UCB1400_AVEN0			(1 << 10)	/* Must be 0 */
   2223 #define		UCB1400_SLP_ON			\
   2224 					(UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
   2225 #define		UCB1400_SLP_PLL			(2 << 4)
   2226 #define		UCB1400_SLP_CODEC		(1 << 4)
   2227 #define		UCB1400_SLP_NO			(0 << 4)
   2228 #define		UCB1400_EV2			(1 << 2)	/* Must be 0 */
   2229 #define		UCB1400_EV1			(1 << 1)	/* Must be 0 */
   2230 #define		UCB1400_EV0			(1 << 0)	/* Must be 0 */
   2231 static void
   2232 ac97_ucb1400_init(struct ac97_softc *as)
   2233 {
   2234 
   2235 	ac97_write(as, UCB1400_REG_FEATURE_CSR1,
   2236 	    UCB1400_HPEN | UCB1400_DC | UCB1400_HIPS | UCB1400_OVFL);
   2237 	ac97_write(as, UCB1400_REG_FEATURE_CSR2, UCB1400_AVE | UCB1400_SLP_ON);
   2238 }
   2239 
   2240 #define VT1616_REG_IO_CONTROL	0x5a
   2241 #define		VT1616_IC_LVL			(1 << 15)
   2242 #define		VT1616_IC_LFECENTER_TO_FRONT	(1 << 12)
   2243 #define		VT1616_IC_SURROUND_TO_FRONT	(1 << 11)
   2244 #define		VT1616_IC_BPDC			(1 << 10)
   2245 #define		VT1616_IC_DC			(1 << 9)
   2246 #define		VT1616_IC_IB_MASK		0x000c
   2247 static void
   2248 ac97_vt1616_init(struct ac97_softc *as)
   2249 {
   2250 	static const struct ac97_source_info sources[3] = {
   2251 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2252 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2253 		  VT1616_REG_IO_CONTROL,
   2254 		  0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2255 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2256 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2257 		  VT1616_REG_IO_CONTROL,
   2258 		  0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2259 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2260 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2261 		  VT1616_REG_IO_CONTROL,
   2262 		  0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2263 	};
   2264 
   2265 	KASSERT(mutex_owned(as->lock));
   2266 
   2267 	ac97_add_port(as, &sources[0]);
   2268 	ac97_add_port(as, &sources[1]);
   2269 	ac97_add_port(as, &sources[2]);
   2270 }
   2271 
   2272 static int
   2273 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
   2274 {
   2275 	uint16_t val;
   2276 
   2277 	KASSERT(mutex_owned(as->lock));
   2278 
   2279 	val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
   2280 	switch (newval) {
   2281 	case 0:
   2282 		val &= ~line;
   2283 		break;
   2284 	case 1:
   2285 		val |= line;
   2286 		break;
   2287 	}
   2288 	ac97_write(as, AC97_REG_GPIO_STATUS, val);
   2289 
   2290 	return 0;
   2291 }
   2292 
   2293 static int
   2294 ac97_sysctl_verify(SYSCTLFN_ARGS)
   2295 {
   2296 	int error, tmp;
   2297 	struct sysctlnode node;
   2298 	struct ac97_softc *as;
   2299 
   2300 	node = *rnode;
   2301 	as = rnode->sysctl_data;
   2302 	if (node.sysctl_num == as->offhook_line1_mib) {
   2303 		tmp = as->offhook_line1;
   2304 		node.sysctl_data = &tmp;
   2305 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2306 		if (error || newp == NULL)
   2307 			return error;
   2308 
   2309 		if (tmp < 0 || tmp > 1)
   2310 			return EINVAL;
   2311 
   2312 		as->offhook_line1 = tmp;
   2313 		mutex_enter(as->lock);
   2314 		ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
   2315 		mutex_exit(as->lock);
   2316 	} else if (node.sysctl_num == as->offhook_line2_mib) {
   2317 		tmp = as->offhook_line2;
   2318 		node.sysctl_data = &tmp;
   2319 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2320 		if (error || newp == NULL)
   2321 			return error;
   2322 
   2323 		if (tmp < 0 || tmp > 1)
   2324 			return EINVAL;
   2325 
   2326 		as->offhook_line2 = tmp;
   2327 		mutex_enter(as->lock);
   2328 		ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
   2329 		mutex_exit(as->lock);
   2330 	}
   2331 
   2332 	return 0;
   2333 }
   2334