Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.95
      1 /*      $NetBSD: ac97.c,v 1.94 2012/06/02 21:36:44 dsl 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.94 2012/06/02 21:36:44 dsl 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', 0x70),
    636 	  0xffffffff,			"Avance Logic ALC203", NULL,	},
    637 	{ AC97_CODEC_ID('A', 'L', 'G', 0x80),
    638 	  0xfffffff0,			"Avance Logic ALC658", NULL,	},
    639 	{ AC97_CODEC_ID('A', 'L', 'G', 0x90),
    640 	  0xfffffff0,			"Avance Logic ALC850", NULL,	},
    641 	{ AC97_CODEC_ID('A', 'L', 'C', 0),
    642 	  AC97_VENDOR_ID_MASK,		"Realtek unknown", NULL,	},
    643 	{ AC97_CODEC_ID('A', 'L', 'G', 0),
    644 	  AC97_VENDOR_ID_MASK,		"Avance Logic unknown", NULL,	},
    645 
    646 	/**
    647 	 * C-Media Electronics Inc.
    648 	 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
    649 	 */
    650 	{ AC97_CODEC_ID('C', 'M', 'I', 0x61),
    651 	  0xffffffff,			"C-Media CMI9739", NULL,	},
    652 	{ AC97_CODEC_ID('C', 'M', 'I', 0),
    653 	  AC97_VENDOR_ID_MASK,		"C-Media unknown", NULL,	},
    654 
    655 	/* Cirrus Logic, Crystal series:
    656 	 *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
    657 	 *              0x1[0-7]  - CS4297A
    658 	 *              0x2[0-7]  - CS4298
    659 	 *              0x2[8-f]  - CS4294
    660 	 *              0x3[0-7]  - CS4299
    661 	 *              0x4[8-f]  - CS4201
    662 	 *              0x5[8-f]  - CS4205
    663 	 *              0x6[0-7]  - CS4291
    664 	 *              0x7[0-7]  - CS4202
    665 	 * Datasheets:
    666 	 *	http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
    667 	 *	http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
    668 	 *	http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
    669 	 *	http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
    670 	 *	http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
    671 	 *	http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
    672 	 */
    673 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x00),
    674 	  0xfffffff8,			"Crystal CS4297", NULL,	},
    675 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x10),
    676 	  0xfffffff8,			"Crystal CS4297A", NULL,	},
    677 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x20),
    678 	  0xfffffff8,			"Crystal CS4298", NULL,	},
    679 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x28),
    680 	  0xfffffff8,			"Crystal CS4294", NULL,	},
    681 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x30),
    682 	  0xfffffff8,			"Crystal CS4299", NULL,	},
    683 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x48),
    684 	  0xfffffff8,			"Crystal CS4201", NULL,	},
    685 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x58),
    686 	  0xfffffff8,			"Crystal CS4205", NULL,	},
    687 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x60),
    688 	  0xfffffff8,			"Crystal CS4291", NULL,	},
    689 	{ AC97_CODEC_ID('C', 'R', 'Y', 0x70),
    690 	  0xfffffff8,			"Crystal CS4202", NULL,	},
    691 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),
    692 	  AC97_VENDOR_ID_MASK,		"Cirrus Logic unknown", NULL,	},
    693 
    694 	{ 0x45838308, 0xffffffff,	"ESS Technology ES1921", NULL, },
    695 	{ 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", NULL, },
    696 
    697 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    698 	  0xffffffff,			"Intersil HMP9701", NULL,	},
    699 	{ AC97_CODEC_ID('H', 'R', 'S', 0),
    700 	  AC97_VENDOR_ID_MASK,		"Intersil unknown", NULL,	},
    701 
    702 	/*
    703 	 * IC Ensemble (VIA)
    704 	 *	http://www.viatech.com/en/datasheet/DS1616.pdf
    705 	 */
    706 	{ AC97_CODEC_ID('I', 'C', 'E', 0x01),
    707 	  0xffffffff,			"ICEnsemble ICE1230/VT1611", NULL,	},
    708 	{ AC97_CODEC_ID('I', 'C', 'E', 0x11),
    709 	  0xffffffff,			"ICEnsemble ICE1232/VT1611A", NULL,	},
    710 	{ AC97_CODEC_ID('I', 'C', 'E', 0x14),
    711 	  0xffffffff,			"ICEnsemble ICE1232A", NULL,	},
    712 	{ AC97_CODEC_ID('I', 'C', 'E', 0x51),
    713 	  0xffffffff,			"VIA Technologies VT1616", ac97_vt1616_init },
    714 	{ AC97_CODEC_ID('I', 'C', 'E', 0x52),
    715 	  0xffffffff,			"VIA Technologies VT1616i", ac97_vt1616_init },
    716 	{ AC97_CODEC_ID('I', 'C', 'E', 0),
    717 	  AC97_VENDOR_ID_MASK,		"ICEnsemble/VIA unknown", NULL,	},
    718 
    719 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    720 	  0xffffffff,			"National Semiconductor LM454[03568]", NULL, },
    721 	{ AC97_CODEC_ID('N', 'S', 'C', 49),
    722 	  0xffffffff,			"National Semiconductor LM4549", NULL, },
    723 	{ AC97_CODEC_ID('N', 'S', 'C', 0),
    724 	  AC97_VENDOR_ID_MASK,		"National Semiconductor unknown", NULL, },
    725 
    726 	{ AC97_CODEC_ID('P', 'S', 'C', 4),
    727 	  0xffffffff,			"Philips Semiconductor UCB1400", ac97_ucb1400_init, },
    728 	{ AC97_CODEC_ID('P', 'S', 'C', 0),
    729 	  AC97_VENDOR_ID_MASK,		"Philips Semiconductor unknown", NULL, },
    730 
    731 	{ AC97_CODEC_ID('S', 'I', 'L', 34),
    732 	  0xffffffff,			"Silicon Laboratory Si3036", NULL, },
    733 	{ AC97_CODEC_ID('S', 'I', 'L', 35),
    734 	  0xffffffff,			"Silicon Laboratory Si3038", NULL, },
    735 	{ AC97_CODEC_ID('S', 'I', 'L', 0),
    736 	  AC97_VENDOR_ID_MASK,		"Silicon Laboratory unknown", NULL, },
    737 
    738 	{ AC97_CODEC_ID('T', 'R', 'A', 2),
    739 	  0xffffffff,			"TriTech TR28022", NULL,	},
    740 	{ AC97_CODEC_ID('T', 'R', 'A', 3),
    741 	  0xffffffff,			"TriTech TR28023", NULL,	},
    742 	{ AC97_CODEC_ID('T', 'R', 'A', 6),
    743 	  0xffffffff,			"TriTech TR28026", NULL,	},
    744 	{ AC97_CODEC_ID('T', 'R', 'A', 8),
    745 	  0xffffffff,			"TriTech TR28028", NULL,	},
    746 	{ AC97_CODEC_ID('T', 'R', 'A', 35),
    747 	  0xffffffff,			"TriTech TR28602", NULL,	},
    748 	{ AC97_CODEC_ID('T', 'R', 'A', 0),
    749 	  AC97_VENDOR_ID_MASK,		"TriTech unknown", NULL,	},
    750 
    751 	{ AC97_CODEC_ID('T', 'X', 'N', 0x20),
    752 	  0xffffffff,			"Texas Instruments TLC320AD9xC", NULL, },
    753 	{ AC97_CODEC_ID('T', 'X', 'N', 0),
    754 	  AC97_VENDOR_ID_MASK,		"Texas Instruments unknown", NULL, },
    755 
    756 	/*
    757 	 * VIA
    758 	 * http://www.viatech.com/en/multimedia/audio.jsp
    759 	 */
    760 	{ AC97_CODEC_ID('V', 'I', 'A', 0x61),
    761 	  0xffffffff,			"VIA Technologies VT1612A", NULL, },
    762 	{ AC97_CODEC_ID('V', 'I', 'A', 0),
    763 	  AC97_VENDOR_ID_MASK,		"VIA Technologies unknown", NULL, },
    764 
    765 	{ AC97_CODEC_ID('W', 'E', 'C', 1),
    766 	  0xffffffff,			"Winbond W83971D", NULL,	},
    767 	{ AC97_CODEC_ID('W', 'E', 'C', 0),
    768 	  AC97_VENDOR_ID_MASK,		"Winbond unknown", NULL,	},
    769 
    770 	/*
    771 	 * http://www.wolfsonmicro.com/product_list.asp?cid=64
    772 	 *	http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
    773 	 *	http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
    774 	 *	http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
    775 	 *	http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
    776 	 *	http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
    777 	 *	http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
    778 	 *	http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
    779 	 *	http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
    780 	 */
    781 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    782 	  0xffffffff,			"Wolfson WM9701A", NULL,	},
    783 	{ AC97_CODEC_ID('W', 'M', 'L', 3),
    784 	  0xffffffff,			"Wolfson WM9703/WM9707/WM9708", NULL,	},
    785 	{ AC97_CODEC_ID('W', 'M', 'L', 4),
    786 	  0xffffffff,			"Wolfson WM9704", NULL,	},
    787 	{ AC97_CODEC_ID('W', 'M', 'L', 5),
    788 	  0xffffffff,			"Wolfson WM9705/WM9710", NULL, },
    789 	{ AC97_CODEC_ID('W', 'M', 'L', 0),
    790 	  AC97_VENDOR_ID_MASK,		"Wolfson unknown", NULL,	},
    791 
    792 	/*
    793 	 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
    794 	 * Datasheets:
    795 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
    796 	 *	http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
    797 	 */
    798 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    799 	  0xffffffff,			"Yamaha YMF743-S", NULL,	},
    800 	{ AC97_CODEC_ID('Y', 'M', 'H', 3),
    801 	  0xffffffff,			"Yamaha YMF753-S", NULL,	},
    802 	{ AC97_CODEC_ID('Y', 'M', 'H', 0),
    803 	  AC97_VENDOR_ID_MASK,		"Yamaha unknown", NULL,	},
    804 
    805 	/*
    806 	 * http://www.sigmatel.com/products/technical_docs.htm
    807 	 * and
    808 	 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
    809 	 */
    810 	{ 0x83847600, 0xffffffff,	"SigmaTel STAC9700",	NULL, },
    811 	{ 0x83847604, 0xffffffff,	"SigmaTel STAC9701/3/4/5", NULL, },
    812 	{ 0x83847605, 0xffffffff,	"SigmaTel STAC9704",	NULL, },
    813 	{ 0x83847608, 0xffffffff,	"SigmaTel STAC9708",	NULL, },
    814 	{ 0x83847609, 0xffffffff,	"SigmaTel STAC9721/23",	NULL, },
    815 	{ 0x83847644, 0xffffffff,	"SigmaTel STAC9744/45",	NULL, },
    816 	{ 0x83847650, 0xffffffff,	"SigmaTel STAC9750/51",	NULL, },
    817 	{ 0x83847652, 0xffffffff,	"SigmaTel STAC9752/53",	NULL, },
    818 	{ 0x83847656, 0xffffffff,	"SigmaTel STAC9756/57",	NULL, },
    819 	{ 0x83847658, 0xffffffff,	"SigmaTel STAC9758/59",	NULL, },
    820 	{ 0x83847666, 0xffffffff,	"SigmaTel STAC9766/67",	NULL, },
    821 	{ 0x83847684, 0xffffffff,	"SigmaTel STAC9783/84",	NULL, },
    822 	{ 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",	NULL, },
    823 
    824 	/* Conexant AC'97 modems -- good luck finding datasheets! */
    825 	{ AC97_CODEC_ID('C', 'X', 'T', 33),
    826 	  0xffffffff,			"Conexant HSD11246", NULL, },
    827 	{ AC97_CODEC_ID('C', 'X', 'T', 34),
    828 	  0xffffffff,			"Conexant D480 MDC V.92 Modem", NULL, },
    829 	{ AC97_CODEC_ID('C', 'X', 'T', 48),
    830 	  0xffffffff,			"Conexant CXT48", NULL, },
    831 	{ AC97_CODEC_ID('C', 'X', 'T', 0),
    832 	  AC97_VENDOR_ID_MASK,		"Conexant unknown", NULL, },
    833 
    834 	{ 0,
    835 	  0,			NULL,	NULL, 		},
    836 };
    837 
    838 static const char * const ac97enhancement[] = {
    839 	"no 3D stereo",
    840 	"Analog Devices Phat Stereo",
    841 	"Creative",
    842 	"National Semi 3D",
    843 	"Yamaha Ymersion",
    844 	"BBE 3D",
    845 	"Crystal Semi 3D",
    846 	"Qsound QXpander",
    847 	"Spatializer 3D",
    848 	"SRS 3D",
    849 	"Platform Tech 3D",
    850 	"AKM 3D",
    851 	"Aureal",
    852 	"AZTECH 3D",
    853 	"Binaura 3D",
    854 	"ESS Technology",
    855 	"Harman International VMAx",
    856 	"Nvidea 3D",
    857 	"Philips Incredible Sound",
    858 	"Texas Instruments' 3D",
    859 	"VLSI Technology 3D",
    860 	"TriTech 3D",
    861 	"Realtek 3D",
    862 	"Samsung 3D",
    863 	"Wolfson Microelectronics 3D",
    864 	"Delta Integration 3D",
    865 	"SigmaTel 3D",
    866 	"KS Waves 3D",
    867 	"Rockwell 3D",
    868 	"Unknown 3D",
    869 	"Unknown 3D",
    870 	"Unknown 3D",
    871 };
    872 
    873 static const char * const ac97feature[] = {
    874 	"dedicated mic channel",
    875 	"reserved",
    876 	"tone",
    877 	"simulated stereo",
    878 	"headphone",
    879 	"bass boost",
    880 	"18 bit DAC",
    881 	"20 bit DAC",
    882 	"18 bit ADC",
    883 	"20 bit ADC"
    884 };
    885 
    886 
    887 /* #define AC97_DEBUG 10 */
    888 /* #define AC97_IO_DEBUG */
    889 
    890 #ifdef AUDIO_DEBUG
    891 #define DPRINTF(x)	if (ac97debug) printf x
    892 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    893 #ifdef AC97_DEBUG
    894 int	ac97debug = AC97_DEBUG;
    895 #else
    896 int	ac97debug = 0;
    897 #endif
    898 #else
    899 #define DPRINTF(x)
    900 #define DPRINTFN(n,x)
    901 #endif
    902 
    903 #ifdef AC97_IO_DEBUG
    904 static const char *ac97_register_names[0x80 / 2] = {
    905 	"RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
    906 	"MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
    907 	"LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
    908 	"PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
    909 	"GP", "3D_CONTROL", "AUDIO_INT", "POWER",
    910 	"EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
    911 	"PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
    912 	"SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
    913 	"LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
    914 	"LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
    915 	"GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
    916 	"0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
    917 	"0x60", "0x62", "0x64", "0x66",
    918 	"0x68", "0x6a", "0x6c", "0x6e",
    919 	"VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
    920 	"VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
    921 };
    922 #endif
    923 
    924 /*
    925  * XXX Some cards have an inverted AC97_POWER_EAMP bit.
    926  * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
    927  */
    928 
    929 #define POWER_EAMP_ON(as)  ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
    930 			    ? AC97_POWER_EAMP : 0)
    931 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
    932 			    ? 0 : AC97_POWER_EAMP)
    933 
    934 static void
    935 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
    936 {
    937 	KASSERT(mutex_owned(as->lock));
    938 
    939 	if (as->host_flags & AC97_HOST_DONT_READ &&
    940 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    941 	     reg != AC97_REG_RESET)) {
    942 		*val = as->shadow_reg[reg >> 1];
    943 		return;
    944 	}
    945 
    946 	if (as->host_if->read(as->host_if->arg, reg, val)) {
    947 		*val = as->shadow_reg[reg >> 1];
    948 	}
    949 }
    950 
    951 static int
    952 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
    953 {
    954 	KASSERT(mutex_owned(as->lock));
    955 
    956 #ifndef AC97_IO_DEBUG
    957 	as->shadow_reg[reg >> 1] = val;
    958 	return as->host_if->write(as->host_if->arg, reg, val);
    959 #else
    960 	int ret;
    961 	uint16_t actual;
    962 
    963 	as->shadow_reg[reg >> 1] = val;
    964 	ret = as->host_if->write(as->host_if->arg, reg, val);
    965 	as->host_if->read(as->host_if->arg, reg, &actual);
    966 	if (val != actual && reg < 0x80) {
    967 		printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
    968 		       ac97_register_names[reg / 2], val, actual);
    969 	}
    970 	return ret;
    971 #endif
    972 }
    973 
    974 static void
    975 ac97_setup_defaults(struct ac97_softc *as)
    976 {
    977 	int idx;
    978 	const struct ac97_source_info *si;
    979 
    980 	KASSERT(mutex_owned(as->lock));
    981 
    982 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    983 
    984 	for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
    985 		si = &audio_source_info[idx];
    986 		if (si->default_value >= 0)
    987 			ac97_write(as, si->reg, si->default_value);
    988 	}
    989 	for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) {
    990 		si = &modem_source_info[idx];
    991 		if (si->default_value >= 0)
    992 			ac97_write(as, si->reg, si->default_value);
    993 	}
    994 }
    995 
    996 static void
    997 ac97_restore_shadow(struct ac97_codec_if *codec_if)
    998 {
    999 	struct ac97_softc *as;
   1000 	const struct ac97_source_info *si;
   1001 	int idx;
   1002 	uint16_t val;
   1003 
   1004 	as = (struct ac97_softc *)codec_if;
   1005 
   1006 	KASSERT(mutex_owned(as->lock));
   1007 
   1008 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1009 		/* restore AC97_REG_POWER */
   1010 		ac97_write(as, AC97_REG_POWER, as->power_reg);
   1011 		/* make sure chip is fully operational */
   1012 		for (idx = 50000; idx >= 0; idx--) {
   1013 			ac97_read(as, AC97_REG_POWER, &val);
   1014 			if ((val & as->power_all) == as->power_all)
   1015 				break;
   1016 			DELAY(10);
   1017 		}
   1018 
   1019 		/*
   1020 		 * actually try changing a value!
   1021 		 * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
   1022 		 */
   1023 		for (idx = 50000; idx >= 0; idx--) {
   1024 			ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
   1025 			ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
   1026 			if (val == 0x1010)
   1027 				break;
   1028 			DELAY(10);
   1029 		}
   1030 	}
   1031 
   1032        for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
   1033 		if (as->type == AC97_CODEC_TYPE_MODEM)
   1034 			si = &modem_source_info[idx];
   1035 		else
   1036 			si = &audio_source_info[idx];
   1037 		/* don't "restore" to the reset reg! */
   1038 		if (si->reg != AC97_REG_RESET)
   1039 			ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
   1040 	}
   1041 
   1042 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
   1043 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
   1044 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
   1045 			  | AC97_EXT_AUDIO_LDAC)) {
   1046 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
   1047 		    as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
   1048 	}
   1049 	if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2
   1050 			  | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1
   1051 			  | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0
   1052 			  | AC97_EXT_MODEM_ID1)) {
   1053 		ac97_write(as, AC97_REG_EXT_MODEM_CTRL,
   1054 		    as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]);
   1055 	}
   1056 }
   1057 
   1058 static int
   1059 ac97_str_equal(const char *a, const char *b)
   1060 {
   1061 	return (a == b) || (a && b && (!strcmp(a, b)));
   1062 }
   1063 
   1064 static int
   1065 ac97_check_capability(struct ac97_softc *as, int check)
   1066 {
   1067 	switch (check) {
   1068 	case CHECK_NONE:
   1069 		return 1;
   1070 	case CHECK_SURROUND:
   1071 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
   1072 	case CHECK_CENTER:
   1073 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
   1074 	case CHECK_LFE:
   1075 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
   1076 	case CHECK_SPDIF:
   1077 		return as->ext_id & AC97_EXT_AUDIO_SPDIF;
   1078 	case CHECK_HEADPHONES:
   1079 		return as->caps & AC97_CAPS_HEADPHONES;
   1080 	case CHECK_TONE:
   1081 		return as->caps & AC97_CAPS_TONECTRL;
   1082 	case CHECK_MIC:
   1083 		return as->caps & AC97_CAPS_MICIN;
   1084 	case CHECK_LOUDNESS:
   1085 		return as->caps & AC97_CAPS_LOUDNESS;
   1086 	case CHECK_3D:
   1087 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
   1088 	case CHECK_LINE1:
   1089 		return as->ext_mid & AC97_EXT_MODEM_LINE1;
   1090 	case CHECK_LINE2:
   1091 		return as->ext_mid & AC97_EXT_MODEM_LINE2;
   1092 	case CHECK_HANDSET:
   1093 		return as->ext_mid & AC97_EXT_MODEM_HANDSET;
   1094 	default:
   1095 		printf("%s: internal error: feature=%d\n", __func__, check);
   1096 		return 0;
   1097 	}
   1098 }
   1099 
   1100 static void
   1101 ac97_setup_source_info(struct ac97_softc *as)
   1102 {
   1103 	int idx, ouridx;
   1104 	struct ac97_source_info *si, *si2;
   1105 	uint16_t value1, value2, value3;
   1106 
   1107 	KASSERT(mutex_owned(as->lock));
   1108 
   1109 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
   1110 		si = &as->source_info[ouridx];
   1111 		if (as->type == AC97_CODEC_TYPE_MODEM) {
   1112 			memcpy(si, &modem_source_info[idx], sizeof(*si));
   1113 		} else {
   1114 			memcpy(si, &audio_source_info[idx], sizeof(*si));
   1115 		}
   1116 		if (!ac97_check_capability(as, si->req_feature))
   1117 			continue;
   1118 		if (si->checkbits) {
   1119 			/* read the register value */
   1120 			ac97_read(as, si->reg, &value1);
   1121 			/* write 0b100000 */
   1122 			value2 = value1 & 0xffc0;
   1123 			value2 |= 0x20;
   1124 			ac97_write(as, si->reg, value2);
   1125 			/* verify */
   1126 			ac97_read(as, si->reg, &value3);
   1127 			if (value2 == value3) {
   1128 				si->bits = 6;
   1129 			} else {
   1130 				si->bits = 5;
   1131 			}
   1132 			DPRINTF(("%s: register=%02x bits=%d\n",
   1133 			    __func__, si->reg, si->bits));
   1134 			ac97_write(as, si->reg, value1);
   1135 		}
   1136 
   1137 		switch (si->type) {
   1138 		case AUDIO_MIXER_CLASS:
   1139 			si->mixer_class = ouridx;
   1140 			ouridx++;
   1141 			break;
   1142 		case AUDIO_MIXER_VALUE:
   1143 			/* Todo - Test to see if it works */
   1144 			ouridx++;
   1145 
   1146 			/* Add an entry for mute, if necessary */
   1147 			if (si->mute) {
   1148 				si = &as->source_info[ouridx];
   1149 				if (as->type == AC97_CODEC_TYPE_MODEM)
   1150 					memcpy(si, &modem_source_info[idx],
   1151 					    sizeof(*si));
   1152 				else
   1153 					memcpy(si, &audio_source_info[idx],
   1154 					    sizeof(*si));
   1155 				si->qualifier = AudioNmute;
   1156 				si->type = AUDIO_MIXER_ENUM;
   1157 				si->info = &ac97_on_off;
   1158 				si->info_size = sizeof(ac97_on_off);
   1159 				si->bits = 1;
   1160 				si->ofs = 15;
   1161 				si->mute = 0;
   1162 				si->polarity = 0;
   1163 				ouridx++;
   1164 			}
   1165 			break;
   1166 		case AUDIO_MIXER_ENUM:
   1167 			/* Todo - Test to see if it works */
   1168 			ouridx++;
   1169 			break;
   1170 		default:
   1171 			aprint_error ("ac97: shouldn't get here\n");
   1172 			break;
   1173 		}
   1174 	}
   1175 
   1176 	as->num_source_info = ouridx;
   1177 
   1178 	for (idx = 0; idx < as->num_source_info; idx++) {
   1179 		int idx2, previdx;
   1180 
   1181 		si = &as->source_info[idx];
   1182 
   1183 		/* Find mixer class */
   1184 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
   1185 			si2 = &as->source_info[idx2];
   1186 
   1187 			if (si2->type == AUDIO_MIXER_CLASS &&
   1188 			    ac97_str_equal(si->class,
   1189 					   si2->class)) {
   1190 				si->mixer_class = idx2;
   1191 			}
   1192 		}
   1193 
   1194 
   1195 		/* Setup prev and next pointers */
   1196 		if (si->prev != 0)
   1197 			continue;
   1198 
   1199 		if (si->qualifier)
   1200 			continue;
   1201 
   1202 		si->prev = AUDIO_MIXER_LAST;
   1203 		previdx = idx;
   1204 
   1205 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
   1206 			if (idx2 == idx)
   1207 				continue;
   1208 
   1209 			si2 = &as->source_info[idx2];
   1210 
   1211 			if (!si2->prev &&
   1212 			    ac97_str_equal(si->class, si2->class) &&
   1213 			    ac97_str_equal(si->device, si2->device)) {
   1214 				as->source_info[previdx].next = idx2;
   1215 				as->source_info[idx2].prev = previdx;
   1216 
   1217 				previdx = idx2;
   1218 			}
   1219 		}
   1220 
   1221 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
   1222 	}
   1223 }
   1224 
   1225 /* backward compatibility */
   1226 int
   1227 ac97_attach(struct ac97_host_if *host_if, device_t sc_dev, kmutex_t *lk)
   1228 {
   1229 	return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO, lk);
   1230 }
   1231 
   1232 int
   1233 ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type, kmutex_t *lk)
   1234 {
   1235 	struct ac97_softc *as;
   1236 	int error, i, j;
   1237 	uint32_t id;
   1238 	uint16_t id1, id2;
   1239 	uint16_t extstat, rate;
   1240 	uint16_t val;
   1241 	mixer_ctrl_t ctl;
   1242 	void (*initfunc)(struct ac97_softc *);
   1243 #define FLAGBUFLEN	140
   1244 	char flagbuf[FLAGBUFLEN];
   1245 
   1246 	initfunc = NULL;
   1247 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
   1248 
   1249 	if (as == NULL)
   1250 		return ENOMEM;
   1251 
   1252 	as->codec_if.vtbl = &ac97civ;
   1253 	as->host_if = host_if;
   1254 	as->type = type;
   1255 	as->lock = lk;
   1256 
   1257 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
   1258 		free(as, M_DEVBUF);
   1259 		return error;
   1260 	}
   1261 
   1262 	mutex_enter(as->lock);
   1263 
   1264 	if (host_if->reset != NULL) {
   1265 		if ((error = host_if->reset(host_if->arg))) {
   1266 			mutex_exit(as->lock);
   1267 			free(as, M_DEVBUF);
   1268 			return error;
   1269 		}
   1270 	}
   1271 
   1272 	if (host_if->flags)
   1273 		as->host_flags = host_if->flags(host_if->arg);
   1274 
   1275 	/*
   1276 	 * Assume codec has all four power bits.
   1277 	 * XXXSCW: what to do for modems?
   1278 	 */
   1279 	as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
   1280 	    AC97_POWER_ADC;
   1281 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1282 		host_if->write(host_if->arg, AC97_REG_RESET, 0);
   1283 
   1284 		/*
   1285 		 * Power-up everything except the analogue mixer.
   1286 		 * If this codec doesn't support analogue mixer power-down,
   1287 		 * AC97_POWER_MIXER will read back as zero.
   1288 		 */
   1289 		host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
   1290 		ac97_read(as, AC97_REG_POWER, &val);
   1291 		if ((val & AC97_POWER_MIXER) == 0) {
   1292 			/* Codec doesn't support analogue mixer power-down */
   1293 			as->power_all &= ~AC97_POWER_ANL;
   1294 		}
   1295 		host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as));
   1296 
   1297 		for (i = 500000; i >= 0; i--) {
   1298 			ac97_read(as, AC97_REG_POWER, &val);
   1299 			if ((val & as->power_all) == as->power_all)
   1300 			       break;
   1301 			DELAY(1);
   1302 		}
   1303 
   1304 		/* save AC97_REG_POWER so that we can restore it later */
   1305 		ac97_read(as, AC97_REG_POWER, &as->power_reg);
   1306 	} else if (as->type == AC97_CODEC_TYPE_MODEM) {
   1307 		host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
   1308 	}
   1309 
   1310 	ac97_setup_defaults(as);
   1311 	if (as->type == AC97_CODEC_TYPE_AUDIO)
   1312 		ac97_read(as, AC97_REG_RESET, &as->caps);
   1313 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
   1314 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
   1315 
   1316 	mutex_exit(as->lock);
   1317 
   1318 	id = (id1 << 16) | id2;
   1319 	aprint_normal_dev(sc_dev, "ac97: ");
   1320 
   1321 	for (i = 0; ; i++) {
   1322 		if (ac97codecid[i].id == 0) {
   1323 			char pnp[4];
   1324 
   1325 			AC97_GET_CODEC_ID(id, pnp);
   1326 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
   1327 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
   1328 			    ISASCII(pnp[2]))
   1329 				aprint_normal("%c%c%c%d",
   1330 				    pnp[0], pnp[1], pnp[2], pnp[3]);
   1331 			else
   1332 				aprint_normal("unknown (0x%08x)", id);
   1333 			break;
   1334 		}
   1335 		if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
   1336 			aprint_normal("%s", ac97codecid[i].name);
   1337 			if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
   1338 				aprint_normal(" (0x%08x)", id);
   1339 			}
   1340 			initfunc = ac97codecid[i].init;
   1341 			break;
   1342 		}
   1343 	}
   1344 	aprint_normal(" codec; ");
   1345 	for (i = j = 0; i < 10; i++) {
   1346 		if (as->caps & (1 << i)) {
   1347 			aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
   1348 			j++;
   1349 		}
   1350 	}
   1351 	aprint_normal("%s%s\n", j ? ", " : "",
   1352 	       ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
   1353 
   1354 	as->ac97_clock = AC97_STANDARD_CLOCK;
   1355 
   1356 	mutex_enter(as->lock);
   1357 
   1358 	if (as->type == AC97_CODEC_TYPE_AUDIO) {
   1359 		ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
   1360 		if (as->ext_id != 0) {
   1361 			mutex_exit(as->lock);
   1362 
   1363 			/* Print capabilities */
   1364 			snprintb(flagbuf, sizeof(flagbuf),
   1365 			     "\20\20SECONDARY10\17SECONDARY01"
   1366 			     "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
   1367 			     "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", as->ext_id);
   1368 			aprint_normal_dev(sc_dev, "ac97: ext id %s\n",
   1369 				      flagbuf);
   1370 
   1371 			/* Print unusual settings */
   1372 			if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
   1373 				aprint_normal_dev(sc_dev, "ac97: Slot assignment: ");
   1374 				switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
   1375 				case AC97_EXT_AUDIO_DSA01:
   1376 					aprint_normal("7&8, 6&9, 10&11.\n");
   1377 					break;
   1378 				case AC97_EXT_AUDIO_DSA10:
   1379 					aprint_normal("6&9, 10&11, 3&4.\n");
   1380 					break;
   1381 				case AC97_EXT_AUDIO_DSA11:
   1382 					aprint_normal("10&11, 3&4, 7&8.\n");
   1383 					break;
   1384 				}
   1385 			}
   1386 			if (as->host_flags & AC97_HOST_INVERTED_EAMP) {
   1387 				aprint_normal_dev(sc_dev, "ac97: using inverted "
   1388 					      "AC97_POWER_EAMP bit\n");
   1389 			}
   1390 
   1391 			mutex_enter(as->lock);
   1392 
   1393 			/* Enable and disable features */
   1394 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
   1395 			extstat &= ~AC97_EXT_AUDIO_DRA;
   1396 			if (as->ext_id & AC97_EXT_AUDIO_LDAC)
   1397 				extstat |= AC97_EXT_AUDIO_LDAC;
   1398 			if (as->ext_id & AC97_EXT_AUDIO_SDAC)
   1399 				extstat |= AC97_EXT_AUDIO_SDAC;
   1400 			if (as->ext_id & AC97_EXT_AUDIO_CDAC)
   1401 				extstat |= AC97_EXT_AUDIO_CDAC;
   1402 			if (as->ext_id & AC97_EXT_AUDIO_VRM)
   1403 				extstat |= AC97_EXT_AUDIO_VRM;
   1404 			if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
   1405 				/* Output the same data as DAC to SPDIF output */
   1406 				extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
   1407 				extstat |= AC97_EXT_AUDIO_SPSA34;
   1408 				ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
   1409 				val = (val & ~AC97_SPDIF_SPSR_MASK)
   1410 				    | AC97_SPDIF_SPSR_48K;
   1411 				ac97_write(as, AC97_REG_SPDIF_CTRL, val);
   1412 			}
   1413 			if (as->ext_id & AC97_EXT_AUDIO_VRA)
   1414 				extstat |= AC97_EXT_AUDIO_VRA;
   1415 			ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
   1416 			if (as->ext_id & AC97_EXT_AUDIO_VRA) {
   1417 				/* VRA should be enabled. */
   1418 				/* so it claims to do variable rate, let's make sure */
   1419 				ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1420 					   44100);
   1421 				ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1422 					  &rate);
   1423 				if (rate != 44100) {
   1424 					/* We can't believe ext_id */
   1425 					as->ext_id = 0;
   1426 					aprint_normal_dev(sc_dev,
   1427 					    "Ignore these capabilities.\n");
   1428 				}
   1429 				/* restore the default value */
   1430 				ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
   1431 					   AC97_SINGLE_RATE);
   1432 			}
   1433 		}
   1434 	} else if (as->type == AC97_CODEC_TYPE_MODEM) {
   1435 		const struct sysctlnode *node;
   1436 		const struct sysctlnode *node_line1;
   1437 		const struct sysctlnode *node_line2;
   1438 		uint16_t xrate = 8000;
   1439 		uint16_t xval, reg;
   1440 		int err;
   1441 
   1442 		ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
   1443 		mutex_exit(as->lock);
   1444 
   1445 		if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
   1446 			aprint_normal_dev(sc_dev, "no modem codec found\n");
   1447 			return ENXIO;
   1448 		}
   1449 		as->type = AC97_CODEC_TYPE_MODEM;
   1450 
   1451 		/* Print capabilities */
   1452 		snprintb(flagbuf, sizeof(flagbuf),
   1453 		    "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as->ext_mid);
   1454 		aprint_normal_dev(sc_dev, "ac97: ext mid %s",
   1455 			      flagbuf);
   1456 		aprint_normal(", %s codec\n",
   1457 			      (as->ext_mid & 0xc000) == 0 ?
   1458 			      "primary" : "secondary");
   1459 
   1460 		/* Setup modem and sysctls */
   1461 		err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
   1462 				     "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
   1463 				     CTL_EOL);
   1464 		if (err != 0)
   1465 			goto setup_modem;
   1466 		err = sysctl_createv(&as->log, 0, NULL, &node, 0,
   1467 				     CTLTYPE_NODE, device_xname(sc_dev), NULL,
   1468 				     NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
   1469 				     CTL_EOL);
   1470 		if (err != 0)
   1471 			goto setup_modem;
   1472 setup_modem:
   1473 		mutex_enter(as->lock);
   1474 
   1475 		/* reset */
   1476 		ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
   1477 
   1478 		/* program rates */
   1479 		xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
   1480 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1481 			ac97_write(as, AC97_REG_LINE1_RATE, xrate);
   1482 			xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
   1483 			       AC97_EXT_MODEM_CTRL_PRD);
   1484 		}
   1485 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1486 			ac97_write(as, AC97_REG_LINE2_RATE, xrate);
   1487 			xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
   1488 			       AC97_EXT_MODEM_CTRL_PRF);
   1489 		}
   1490 		if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
   1491 			ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
   1492 			xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
   1493 			       AC97_EXT_MODEM_CTRL_PRH);
   1494 		}
   1495 
   1496 		/* power-up everything */
   1497 		ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
   1498 		for (i = 5000; i >= 0; i--) {
   1499 			ac97_read(as, AC97_REG_EXT_MODEM_CTRL, &reg);
   1500 			if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
   1501 			       break;
   1502 			DELAY(1);
   1503 		}
   1504 		if (i <= 0) {
   1505 			mutex_exit(as->lock);
   1506 			printf("%s: codec not responding, status=0x%x\n",
   1507 			    device_xname(sc_dev), reg);
   1508 			return ENXIO;
   1509 		}
   1510 
   1511 		/* setup sysctls */
   1512 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1513 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1514 			reg &= ~AC97_GPIO_LINE1_OH;
   1515 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1516 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1517 			reg &= ~AC97_GPIO_LINE1_OH;
   1518 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1519 
   1520 			mutex_exit(as->lock);
   1521 			err = sysctl_createv(&as->log, 0, NULL, &node_line1,
   1522 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1523 					     "line1",
   1524 					     SYSCTL_DESCR("off-hook line1"),
   1525 					     ac97_sysctl_verify, 0, (void *)as, 0,
   1526 					     CTL_HW, node->sysctl_num,
   1527 					     CTL_CREATE, CTL_EOL);
   1528 			mutex_enter(as->lock);
   1529 
   1530 			if (err != 0)
   1531 				goto sysctl_err;
   1532 			as->offhook_line1_mib = node_line1->sysctl_num;
   1533 		}
   1534 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1535 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1536 			reg &= ~AC97_GPIO_LINE2_OH;
   1537 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1538 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1539 			reg &= ~AC97_GPIO_LINE2_OH;
   1540 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1541 
   1542 			mutex_exit(as->lock);
   1543 			err = sysctl_createv(&as->log, 0, NULL, &node_line2,
   1544 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1545 					     "line2",
   1546 					     SYSCTL_DESCR("off-hook line2"),
   1547 					     ac97_sysctl_verify, 0, (void *)as, 0,
   1548 					     CTL_HW, node->sysctl_num,
   1549 					     CTL_CREATE, CTL_EOL);
   1550 			mutex_enter(as->lock);
   1551 
   1552 			if (err != 0)
   1553 				goto sysctl_err;
   1554 			as->offhook_line2_mib = node_line2->sysctl_num;
   1555 		}
   1556 sysctl_err:
   1557 
   1558 		ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
   1559 		ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
   1560 		ac97_write(as, AC97_REG_MISC_AFE, 0x0);
   1561 	}
   1562 
   1563 	as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
   1564 			   as->modem_source_info : as->audio_source_info);
   1565 	ac97_setup_source_info(as);
   1566 
   1567 	memset(&ctl, 0, sizeof(ctl));
   1568 	/* disable mutes */
   1569 	for (i = 0; i < 11; i++) {
   1570 		static struct {
   1571 			const char *class, *device;
   1572 		} d[11] = {
   1573 			{ AudioCoutputs, AudioNmaster},
   1574 			{ AudioCoutputs, AudioNheadphone},
   1575 			{ AudioCoutputs, AudioNsurround},
   1576 			{ AudioCoutputs, AudioNcenter},
   1577 			{ AudioCoutputs, AudioNlfe},
   1578 			{ AudioCinputs, AudioNdac},
   1579 			{ AudioCinputs, AudioNcd},
   1580 			{ AudioCinputs, AudioNline},
   1581 			{ AudioCinputs, AudioNaux},
   1582 			{ AudioCinputs, AudioNvideo},
   1583 			{ AudioCrecord, AudioNvolume},
   1584 		};
   1585 
   1586 		ctl.type = AUDIO_MIXER_ENUM;
   1587 		ctl.un.ord = 0;
   1588 
   1589 		ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
   1590 			d[i].class, d[i].device, AudioNmute);
   1591 		ac97_mixer_set_port(&as->codec_if, &ctl);
   1592 	}
   1593 	ctl.type = AUDIO_MIXER_ENUM;
   1594 	ctl.un.ord = 0;
   1595 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
   1596 					   AudioNsource, NULL);
   1597 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1598 
   1599 	/* set a reasonable default volume */
   1600 	ctl.type = AUDIO_MIXER_VALUE;
   1601 	ctl.un.value.num_channels = 2;
   1602 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
   1603 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
   1604 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1605 					   AudioNmaster, NULL);
   1606 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1607 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1608 					   AudioNsurround, NULL);
   1609 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1610 	ctl.un.value.num_channels = 1;
   1611 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1612 					   AudioNcenter, NULL);
   1613 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1614 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1615 					   AudioNlfe, NULL);
   1616 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1617 
   1618 	if (initfunc != NULL)
   1619 		initfunc(as);
   1620 
   1621 	/* restore AC97_REG_POWER */
   1622 	if (as->type == AC97_CODEC_TYPE_AUDIO)
   1623 		ac97_write(as, AC97_REG_POWER, as->power_reg);
   1624 
   1625 	mutex_exit(as->lock);
   1626 
   1627 	return 0;
   1628 }
   1629 
   1630 static void
   1631 ac97_detach(struct ac97_codec_if *codec_if)
   1632 {
   1633 	struct ac97_softc *as;
   1634 
   1635 	as = (struct ac97_softc *)codec_if;
   1636 
   1637 	mutex_enter(as->lock);
   1638 	ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
   1639 		   | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
   1640 		   | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
   1641 		   | POWER_EAMP_OFF(as));
   1642 	mutex_exit(as->lock);
   1643 
   1644 	free(as, M_DEVBUF);
   1645 }
   1646 
   1647 static void
   1648 ac97_lock(struct ac97_codec_if *codec_if)
   1649 {
   1650 	struct ac97_softc *as;
   1651 
   1652 	as = (struct ac97_softc *)codec_if;
   1653 
   1654 	KASSERT(mutex_owned(as->lock));
   1655 
   1656 	as->lock_counter++;
   1657 }
   1658 
   1659 static void
   1660 ac97_unlock(struct ac97_codec_if *codec_if)
   1661 {
   1662 	struct ac97_softc *as;
   1663 
   1664 	as = (struct ac97_softc *)codec_if;
   1665 
   1666 	KASSERT(mutex_owned(as->lock));
   1667 
   1668 	as->lock_counter--;
   1669 }
   1670 
   1671 static int
   1672 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
   1673 {
   1674 	struct ac97_softc *as;
   1675 	struct ac97_source_info *si;
   1676 	const char *name;
   1677 
   1678 	as = (struct ac97_softc *)codec_if;
   1679 	if (dip->index < as->num_source_info) {
   1680 		si = &as->source_info[dip->index];
   1681 		dip->type = si->type;
   1682 		dip->mixer_class = si->mixer_class;
   1683 		dip->prev = si->prev;
   1684 		dip->next = si->next;
   1685 
   1686 		if (si->qualifier)
   1687 			name = si->qualifier;
   1688 		else if (si->device)
   1689 			name = si->device;
   1690 		else if (si->class)
   1691 			name = si->class;
   1692 		else
   1693 			name = 0;
   1694 
   1695 		if (name)
   1696 			strcpy(dip->label.name, name);
   1697 
   1698 		memcpy(&dip->un, si->info, si->info_size);
   1699 
   1700 		/* Set the delta for volume sources */
   1701 		if (dip->type == AUDIO_MIXER_VALUE)
   1702 			dip->un.v.delta = 1 << (8 - si->bits);
   1703 
   1704 		return 0;
   1705 	}
   1706 
   1707 	return ENXIO;
   1708 }
   1709 
   1710 static int
   1711 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1712 {
   1713 	struct ac97_softc *as;
   1714 	struct ac97_source_info *si;
   1715 	uint16_t mask;
   1716 	uint16_t val, newval;
   1717 	int error;
   1718 	bool spdif;
   1719 
   1720 	as = (struct ac97_softc *)codec_if;
   1721 
   1722 	KASSERT(mutex_owned(as->lock));
   1723 
   1724 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1725 		return EINVAL;
   1726 	si = &as->source_info[cp->dev];
   1727 
   1728 	if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
   1729 		return EINVAL;
   1730 	spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
   1731 	if (spdif && as->lock_counter >= 0) {
   1732 		/* When the value of lock_counter is the default 0,
   1733 		 * it is not allowed to change the SPDIF mode. */
   1734 		return EBUSY;
   1735 	}
   1736 
   1737 	ac97_read(as, si->reg, &val);
   1738 
   1739 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1740 
   1741 	mask = (1 << si->bits) - 1;
   1742 
   1743 	switch (cp->type) {
   1744 	case AUDIO_MIXER_ENUM:
   1745 		if (cp->un.ord > mask || cp->un.ord < 0)
   1746 			return EINVAL;
   1747 
   1748 		newval = (cp->un.ord << si->ofs);
   1749 		if (si->reg == AC97_REG_RECORD_SELECT) {
   1750 			newval |= (newval << (8 + si->ofs));
   1751 			mask |= (mask << 8);
   1752 			mask = mask << si->ofs;
   1753 		} else if (si->reg == AC97_REG_SURR_MASTER) {
   1754 			newval = cp->un.ord ? 0x8080 : 0x0000;
   1755 			mask = 0x8080;
   1756 		} else
   1757 			mask = mask << si->ofs;
   1758 		break;
   1759 	case AUDIO_MIXER_VALUE:
   1760 	{
   1761 		const struct audio_mixer_value *value = si->info;
   1762 		uint16_t  l, r, ol, or;
   1763 		int deltal, deltar;
   1764 
   1765 		if ((cp->un.value.num_channels <= 0) ||
   1766 		    (cp->un.value.num_channels > value->num_channels))
   1767 			return EINVAL;
   1768 
   1769 		if (cp->un.value.num_channels == 1) {
   1770 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
   1771 		} else {
   1772 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1773 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1774 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1775 			} else {	/* left/right is reversed here */
   1776 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1777 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1778 			}
   1779 
   1780 		}
   1781 
   1782 		if (!si->polarity) {
   1783 			l = 255 - l;
   1784 			r = 255 - r;
   1785 		}
   1786 
   1787 		ol = (val >> (8+si->ofs)) & mask;
   1788 		or = (val >> si->ofs) & mask;
   1789 
   1790 		deltal = (ol << (8 - si->bits)) - l;
   1791 		deltar = (or << (8 - si->bits)) - r;
   1792 
   1793 		l = l >> (8 - si->bits);
   1794 		r = r >> (8 - si->bits);
   1795 
   1796 		if (deltal && ol == l)
   1797 			l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
   1798 		if (deltar && or == r)
   1799 			r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
   1800 
   1801 		newval = ((r & mask) << si->ofs);
   1802 		if (value->num_channels == 2) {
   1803 			newval = newval | ((l & mask) << (si->ofs+8));
   1804 			mask |= (mask << 8);
   1805 		}
   1806 		mask = mask << si->ofs;
   1807 		break;
   1808 	}
   1809 	default:
   1810 		return EINVAL;
   1811 	}
   1812 
   1813 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
   1814 	if (error)
   1815 		return error;
   1816 
   1817 	if (spdif && as->host_if->spdif_event != NULL) {
   1818 		DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
   1819 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
   1820 	}
   1821 	return 0;
   1822 }
   1823 
   1824 static int
   1825 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
   1826 			 const char *device, const char *qualifier)
   1827 {
   1828 	struct ac97_softc *as;
   1829 	int idx;
   1830 
   1831 	as = (struct ac97_softc *)codec_if;
   1832 
   1833 	KASSERT(mutex_owned(as->lock));
   1834 
   1835 	for (idx = 0; idx < as->num_source_info; idx++) {
   1836 		struct ac97_source_info *si = &as->source_info[idx];
   1837 		if (ac97_str_equal(class, si->class) &&
   1838 		    ac97_str_equal(device, si->device) &&
   1839 		    ac97_str_equal(qualifier, si->qualifier))
   1840 			return idx;
   1841 	}
   1842 
   1843 	return -1;
   1844 }
   1845 
   1846 static int
   1847 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1848 {
   1849 	struct ac97_softc *as;
   1850 	struct ac97_source_info *si;
   1851 	uint16_t mask;
   1852 	uint16_t val;
   1853 
   1854 	as = (struct ac97_softc *)codec_if;
   1855 
   1856 	KASSERT(mutex_owned(as->lock));
   1857 
   1858 	si = &as->source_info[cp->dev];
   1859 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1860 		return EINVAL;
   1861 
   1862 	if (cp->type != si->type)
   1863 		return EINVAL;
   1864 
   1865 	ac97_read(as, si->reg, &val);
   1866 
   1867 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1868 
   1869 	mask = (1 << si->bits) - 1;
   1870 
   1871 	switch (cp->type) {
   1872 	case AUDIO_MIXER_ENUM:
   1873 		cp->un.ord = (val >> si->ofs) & mask;
   1874 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
   1875 			     val, si->ofs, mask, cp->un.ord));
   1876 		break;
   1877 	case AUDIO_MIXER_VALUE:
   1878 	{
   1879 		const struct audio_mixer_value *value = si->info;
   1880 		uint16_t  l, r;
   1881 
   1882 		if ((cp->un.value.num_channels <= 0) ||
   1883 		    (cp->un.value.num_channels > value->num_channels))
   1884 			return EINVAL;
   1885 
   1886 		if (value->num_channels == 1) {
   1887 			l = r = (val >> si->ofs) & mask;
   1888 		} else {
   1889 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1890 				l = (val >> (si->ofs + 8)) & mask;
   1891 				r = (val >> si->ofs) & mask;
   1892 			} else {	/* host has reversed channels */
   1893 				r = (val >> (si->ofs + 8)) & mask;
   1894 				l = (val >> si->ofs) & mask;
   1895 			}
   1896 		}
   1897 
   1898 		l = (l << (8 - si->bits));
   1899 		r = (r << (8 - si->bits));
   1900 		if (!si->polarity) {
   1901 			l = 255 - l;
   1902 			r = 255 - r;
   1903 		}
   1904 
   1905 		/* The EAP driver averages l and r for stereo
   1906 		   channels that are requested in MONO mode. Does this
   1907 		   make sense? */
   1908 		if (cp->un.value.num_channels == 1) {
   1909 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
   1910 		} else if (cp->un.value.num_channels == 2) {
   1911 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
   1912 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
   1913 		}
   1914 
   1915 		break;
   1916 	}
   1917 	default:
   1918 		return EINVAL;
   1919 	}
   1920 
   1921 	return 0;
   1922 }
   1923 
   1924 
   1925 static int
   1926 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
   1927 {
   1928 	struct ac97_softc *as;
   1929 	u_int value;
   1930 	uint16_t ext_stat;
   1931 	uint16_t actual;
   1932 	uint16_t power;
   1933 	uint16_t power_bit;
   1934 
   1935 	as = (struct ac97_softc *)codec_if;
   1936 
   1937 	KASSERT(mutex_owned(as->lock));
   1938 
   1939 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
   1940 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1941 			*rate = AC97_SINGLE_RATE;
   1942 			return 0;
   1943 		}
   1944 	} else {
   1945 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1946 			*rate = AC97_SINGLE_RATE;
   1947 			return 0;
   1948 		}
   1949 	}
   1950 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
   1951 	ext_stat = 0;
   1952 	/*
   1953 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
   1954 	 *	Check VRA, DRA
   1955 	 * PCM_LR_ADC_RATE
   1956 	 *	Check VRA
   1957 	 * PCM_MIC_ADC_RATE
   1958 	 *	Check VRM
   1959 	 */
   1960 	switch (target) {
   1961 	case AC97_REG_PCM_FRONT_DAC_RATE:
   1962 	case AC97_REG_PCM_SURR_DAC_RATE:
   1963 	case AC97_REG_PCM_LFE_DAC_RATE:
   1964 		power_bit = AC97_POWER_OUT;
   1965 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1966 			*rate = AC97_SINGLE_RATE;
   1967 			return 0;
   1968 		}
   1969 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1970 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1971 			if (value > 0x1ffff) {
   1972 				return EINVAL;
   1973 			} else if (value > 0xffff) {
   1974 				/* Enable DRA */
   1975 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1976 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1977 				value /= 2;
   1978 			} else {
   1979 				/* Disable DRA */
   1980 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1981 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1982 			}
   1983 		} else {
   1984 			if (value > 0xffff)
   1985 				return EINVAL;
   1986 		}
   1987 		break;
   1988 	case AC97_REG_PCM_LR_ADC_RATE:
   1989 		power_bit = AC97_POWER_IN;
   1990 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1991 			*rate = AC97_SINGLE_RATE;
   1992 			return 0;
   1993 		}
   1994 		if (value > 0xffff)
   1995 			return EINVAL;
   1996 		break;
   1997 	case AC97_REG_PCM_MIC_ADC_RATE:
   1998 		power_bit = AC97_POWER_IN;
   1999 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   2000 			*rate = AC97_SINGLE_RATE;
   2001 			return 0;
   2002 		}
   2003 		if (value > 0xffff)
   2004 			return EINVAL;
   2005 		break;
   2006 	default:
   2007 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   2008 		return EINVAL;
   2009 	}
   2010 
   2011 	ac97_read(as, AC97_REG_POWER, &power);
   2012 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   2013 
   2014 	ac97_write(as, target, (uint16_t)value);
   2015 	ac97_read(as, target, &actual);
   2016 	actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   2017 
   2018 	ac97_write(as, AC97_REG_POWER, power);
   2019 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   2020 		*rate = actual * 2;
   2021 	} else {
   2022 		*rate = actual;
   2023 	}
   2024 	return 0;
   2025 }
   2026 
   2027 static void
   2028 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   2029 {
   2030 	struct ac97_softc *as;
   2031 
   2032 	as = (struct ac97_softc *)codec_if;
   2033 
   2034 	KASSERT(mutex_owned(as->lock));
   2035 
   2036 	as->ac97_clock = clock;
   2037 }
   2038 
   2039 static uint16_t
   2040 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   2041 {
   2042 	struct ac97_softc *as;
   2043 
   2044 	as = (struct ac97_softc *)codec_if;
   2045 
   2046 	KASSERT(mutex_owned(as->lock));
   2047 
   2048 	return as->ext_id;
   2049 }
   2050 
   2051 static int
   2052 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
   2053 {
   2054 	struct ac97_source_info *si;
   2055 	int ouridx, idx;
   2056 
   2057 	KASSERT(mutex_owned(as->lock));
   2058 
   2059 	if ((as->type == AC97_CODEC_TYPE_AUDIO &&
   2060 	     as->num_source_info >= AUDIO_MAX_SOURCES) ||
   2061 	    (as->type == AC97_CODEC_TYPE_MODEM &&
   2062 	     as->num_source_info >= MODEM_MAX_SOURCES)) {
   2063 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
   2064 		       __func__, __FILE__);
   2065 		return -1;
   2066 	}
   2067 	if (!ac97_check_capability(as, src->req_feature))
   2068 		return -1;
   2069 	ouridx = as->num_source_info;
   2070 	si = &as->source_info[ouridx];
   2071 	memcpy(si, src, sizeof(*si));
   2072 
   2073 	switch (si->type) {
   2074 	case AUDIO_MIXER_CLASS:
   2075 	case AUDIO_MIXER_VALUE:
   2076 		printf("%s: adding class/value is not supported yet.\n",
   2077 		       __func__);
   2078 		return -1;
   2079 	case AUDIO_MIXER_ENUM:
   2080 		break;
   2081 	default:
   2082 		printf("%s: unknown type: %d\n", __func__, si->type);
   2083 		return -1;
   2084 	}
   2085 	as->num_source_info++;
   2086 
   2087 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2088 						   NULL, NULL);
   2089 	/* Find the root of the device */
   2090 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2091 				       si->device, NULL);
   2092 	/* Find the last item */
   2093 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
   2094 		idx = as->source_info[idx].next;
   2095 	/* Append */
   2096 	as->source_info[idx].next = ouridx;
   2097 	si->prev = idx;
   2098 	si->next = AUDIO_MIXER_LAST;
   2099 
   2100 	return 0;
   2101 }
   2102 
   2103 /**
   2104  * Codec-dependent initialization
   2105  */
   2106 
   2107 #define	AD1980_REG_MISC	0x76
   2108 #define		AD1980_MISC_MBG0	0x0001	/* 0 1888/1980/1981 /1985 */
   2109 #define		AD1980_MISC_MBG1	0x0002	/* 1 1888/1980/1981 /1985 */
   2110 #define		AD1980_MISC_VREFD	0x0004	/* 2 1888/1980/1981 /1985 */
   2111 #define		AD1980_MISC_VREFH	0x0008	/* 3 1888/1980/1981 /1985 */
   2112 #define		AD1980_MISC_SRU		0x0010	/* 4 1888/1980      /1985 */
   2113 #define		AD1980_MISC_LOSEL	0x0020	/* 5 1888/1980/1981 /1985 */
   2114 #define		AD1980_MISC_2CMIC	0x0040	/* 6      1980/1981B/1985 */
   2115 #define		AD1980_MISC_SPRD	0x0080	/* 7 1888/1980      /1985 */
   2116 #define		AD1980_MISC_DMIX0	0x0100	/* 8 1888/1980      /1985 */
   2117 #define		AD1980_MISC_DMIX1	0x0200	/* 9 1888/1980      /1985 */
   2118 #define		AD1980_MISC_HPSEL	0x0400	/*10 1888/1980      /1985 */
   2119 #define		AD1980_MISC_CLDIS	0x0800	/*11 1888/1980      /1985 */
   2120 #define		AD1980_MISC_LODIS	0x1000	/*12 1888/1980/1981 /1985 */
   2121 #define		AD1980_MISC_MSPLT	0x2000	/*13 1888/1980/1981 /1985 */
   2122 #define		AD1980_MISC_AC97NC	0x4000	/*14 1888/1980      /1985 */
   2123 #define		AD1980_MISC_DACZ	0x8000	/*15 1888/1980/1981 /1985 */
   2124 #define	AD1981_REG_MISC	0x76
   2125 #define		AD1981_MISC_MADST	0x0010  /* 4 */
   2126 #define		AD1981A_MISC_MADPD	0x0040  /* 6 */
   2127 #define		AD1981B_MISC_MADPD	0x0080  /* 7 */
   2128 #define		AD1981_MISC_FMXE	0x0200  /* 9 */
   2129 #define		AD1981_MISC_DAM		0x0800  /*11 */
   2130 static void
   2131 ac97_ad198x_init(struct ac97_softc *as)
   2132 {
   2133 	int i;
   2134 	uint16_t misc;
   2135 
   2136 	KASSERT(mutex_owned(as->lock));
   2137 
   2138 	ac97_read(as, AD1980_REG_MISC, &misc);
   2139 	ac97_write(as, AD1980_REG_MISC,
   2140 		   misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
   2141 
   2142 	for (i = 0; i < as->num_source_info; i++) {
   2143 		if (as->source_info[i].type != AUDIO_MIXER_VALUE)
   2144 			continue;
   2145 
   2146 		if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
   2147 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
   2148 		else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
   2149 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
   2150 	}
   2151 }
   2152 
   2153 #define ALC650_REG_MULTI_CHANNEL_CONTROL	0x6a
   2154 #define		ALC650_MCC_SLOT_MODIFY_MASK		0xc000
   2155 #define		ALC650_MCC_FRONTDAC_FROM_SPDIFIN	0x2000 /* 13 */
   2156 #define		ALC650_MCC_SPDIFOUT_FROM_ADC		0x1000 /* 12 */
   2157 #define		ALC650_MCC_PCM_FROM_SPDIFIN		0x0800 /* 11 */
   2158 #define		ALC650_MCC_MIC_OR_CENTERLFE		0x0400 /* 10 */
   2159 #define		ALC650_MCC_LINEIN_OR_SURROUND		0x0200 /* 9 */
   2160 #define		ALC650_MCC_INDEPENDENT_MASTER_L		0x0080 /* 7 */
   2161 #define		ALC650_MCC_INDEPENDENT_MASTER_R		0x0040 /* 6 */
   2162 #define		ALC650_MCC_ANALOG_TO_CENTERLFE		0x0020 /* 5 */
   2163 #define		ALC650_MCC_ANALOG_TO_SURROUND		0x0010 /* 4 */
   2164 #define		ALC650_MCC_EXCHANGE_CENTERLFE		0x0008 /* 3 */
   2165 #define		ALC650_MCC_CENTERLFE_DOWNMIX		0x0004 /* 2 */
   2166 #define		ALC650_MCC_SURROUND_DOWNMIX		0x0002 /* 1 */
   2167 #define		ALC650_MCC_LINEOUT_TO_SURROUND		0x0001 /* 0 */
   2168 static void
   2169 ac97_alc650_init(struct ac97_softc *as)
   2170 {
   2171 	static const struct ac97_source_info sources[6] = {
   2172 		{ AudioCoutputs, AudioNsurround, "lineinjack",
   2173 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2174 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2175 		  0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2176 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2177 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2178 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2179 		  0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2180 		{ AudioCoutputs, AudioNcenter, "micjack",
   2181 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2182 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2183 		  0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2184 		{ AudioCoutputs, AudioNlfe, "micjack",
   2185 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2186 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2187 		  0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2188 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2189 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2190 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2191 		  0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2192 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2193 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2194 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2195 		  0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2196 	};
   2197 
   2198 	ac97_add_port(as, &sources[0]);
   2199 	ac97_add_port(as, &sources[1]);
   2200 	ac97_add_port(as, &sources[2]);
   2201 	ac97_add_port(as, &sources[3]);
   2202 	ac97_add_port(as, &sources[4]);
   2203 	ac97_add_port(as, &sources[5]);
   2204 }
   2205 
   2206 #define UCB1400_REG_FEATURE_CSR1	0x6a
   2207 #define		UCB1400_BB(bb)			(((bb) & 0xf) << 11)
   2208 #define		UCB1400_TR(tr)			(((tr) & 0x3) << 9)
   2209 #define		UCB1400_M_MAXIMUM		(3 << 7)
   2210 #define		UCB1400_M_MINIMUM		(1 << 7)
   2211 #define		UCB1400_M_FLAT			(0 << 7)
   2212 #define		UCB1400_HPEN			(1 << 6)
   2213 #define		UCB1400_DE			(1 << 5)
   2214 #define		UCB1400_DC			(1 << 4)
   2215 #define		UCB1400_HIPS			(1 << 3)
   2216 #define		UCB1400_GIEN			(1 << 2)
   2217 #define		UCB1400_OVFL			(1 << 0)
   2218 #define UCB1400_REG_FEATURE_CSR2	0x6c
   2219 #define		UCB1400_SMT			(1 << 15)	/* Must be 0 */
   2220 #define		UCB1400_SUEV1			(1 << 14)	/* Must be 0 */
   2221 #define		UCB1400_SUEV0			(1 << 13)	/* Must be 0 */
   2222 #define		UCB1400_AVE			(1 << 12)
   2223 #define		UCB1400_AVEN1			(1 << 11)	/* Must be 0 */
   2224 #define		UCB1400_AVEN0			(1 << 10)	/* Must be 0 */
   2225 #define		UCB1400_SLP_ON			\
   2226 					(UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
   2227 #define		UCB1400_SLP_PLL			(2 << 4)
   2228 #define		UCB1400_SLP_CODEC		(1 << 4)
   2229 #define		UCB1400_SLP_NO			(0 << 4)
   2230 #define		UCB1400_EV2			(1 << 2)	/* Must be 0 */
   2231 #define		UCB1400_EV1			(1 << 1)	/* Must be 0 */
   2232 #define		UCB1400_EV0			(1 << 0)	/* Must be 0 */
   2233 static void
   2234 ac97_ucb1400_init(struct ac97_softc *as)
   2235 {
   2236 
   2237 	ac97_write(as, UCB1400_REG_FEATURE_CSR1,
   2238 	    UCB1400_HPEN | UCB1400_DC | UCB1400_HIPS | UCB1400_OVFL);
   2239 	ac97_write(as, UCB1400_REG_FEATURE_CSR2, UCB1400_AVE | UCB1400_SLP_ON);
   2240 }
   2241 
   2242 #define VT1616_REG_IO_CONTROL	0x5a
   2243 #define		VT1616_IC_LVL			(1 << 15)
   2244 #define		VT1616_IC_LFECENTER_TO_FRONT	(1 << 12)
   2245 #define		VT1616_IC_SURROUND_TO_FRONT	(1 << 11)
   2246 #define		VT1616_IC_BPDC			(1 << 10)
   2247 #define		VT1616_IC_DC			(1 << 9)
   2248 #define		VT1616_IC_IB_MASK		0x000c
   2249 static void
   2250 ac97_vt1616_init(struct ac97_softc *as)
   2251 {
   2252 	static const struct ac97_source_info sources[3] = {
   2253 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2254 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2255 		  VT1616_REG_IO_CONTROL,
   2256 		  0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2257 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2258 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2259 		  VT1616_REG_IO_CONTROL,
   2260 		  0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2261 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2262 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2263 		  VT1616_REG_IO_CONTROL,
   2264 		  0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2265 	};
   2266 
   2267 	KASSERT(mutex_owned(as->lock));
   2268 
   2269 	ac97_add_port(as, &sources[0]);
   2270 	ac97_add_port(as, &sources[1]);
   2271 	ac97_add_port(as, &sources[2]);
   2272 }
   2273 
   2274 static int
   2275 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
   2276 {
   2277 	uint16_t val;
   2278 
   2279 	KASSERT(mutex_owned(as->lock));
   2280 
   2281 	val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
   2282 	switch (newval) {
   2283 	case 0:
   2284 		val &= ~line;
   2285 		break;
   2286 	case 1:
   2287 		val |= line;
   2288 		break;
   2289 	}
   2290 	ac97_write(as, AC97_REG_GPIO_STATUS, val);
   2291 
   2292 	return 0;
   2293 }
   2294 
   2295 static int
   2296 ac97_sysctl_verify(SYSCTLFN_ARGS)
   2297 {
   2298 	int error, tmp;
   2299 	struct sysctlnode node;
   2300 	struct ac97_softc *as;
   2301 
   2302 	node = *rnode;
   2303 	as = rnode->sysctl_data;
   2304 	if (node.sysctl_num == as->offhook_line1_mib) {
   2305 		tmp = as->offhook_line1;
   2306 		node.sysctl_data = &tmp;
   2307 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2308 		if (error || newp == NULL)
   2309 			return error;
   2310 
   2311 		if (tmp < 0 || tmp > 1)
   2312 			return EINVAL;
   2313 
   2314 		as->offhook_line1 = tmp;
   2315 		mutex_enter(as->lock);
   2316 		ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
   2317 		mutex_exit(as->lock);
   2318 	} else if (node.sysctl_num == as->offhook_line2_mib) {
   2319 		tmp = as->offhook_line2;
   2320 		node.sysctl_data = &tmp;
   2321 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2322 		if (error || newp == NULL)
   2323 			return error;
   2324 
   2325 		if (tmp < 0 || tmp > 1)
   2326 			return EINVAL;
   2327 
   2328 		as->offhook_line2 = tmp;
   2329 		mutex_enter(as->lock);
   2330 		ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
   2331 		mutex_exit(as->lock);
   2332 	}
   2333 
   2334 	return 0;
   2335 }
   2336