Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.96
      1 /*      $NetBSD: ac97.c,v 1.96 2015/04/04 15:09:45 christos 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.96 2015/04/04 15:09:45 christos 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 			free(as, M_DEVBUF);
   1448 			return ENXIO;
   1449 		}
   1450 		as->type = AC97_CODEC_TYPE_MODEM;
   1451 
   1452 		/* Print capabilities */
   1453 		snprintb(flagbuf, sizeof(flagbuf),
   1454 		    "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as->ext_mid);
   1455 		aprint_normal_dev(sc_dev, "ac97: ext mid %s",
   1456 			      flagbuf);
   1457 		aprint_normal(", %s codec\n",
   1458 			      (as->ext_mid & 0xc000) == 0 ?
   1459 			      "primary" : "secondary");
   1460 
   1461 		/* Setup modem and sysctls */
   1462 		err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
   1463 				     "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
   1464 				     CTL_EOL);
   1465 		if (err != 0)
   1466 			goto setup_modem;
   1467 		err = sysctl_createv(&as->log, 0, NULL, &node, 0,
   1468 				     CTLTYPE_NODE, device_xname(sc_dev), NULL,
   1469 				     NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
   1470 				     CTL_EOL);
   1471 		if (err != 0)
   1472 			goto setup_modem;
   1473 setup_modem:
   1474 		mutex_enter(as->lock);
   1475 
   1476 		/* reset */
   1477 		ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
   1478 
   1479 		/* program rates */
   1480 		xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
   1481 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1482 			ac97_write(as, AC97_REG_LINE1_RATE, xrate);
   1483 			xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
   1484 			       AC97_EXT_MODEM_CTRL_PRD);
   1485 		}
   1486 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1487 			ac97_write(as, AC97_REG_LINE2_RATE, xrate);
   1488 			xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
   1489 			       AC97_EXT_MODEM_CTRL_PRF);
   1490 		}
   1491 		if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
   1492 			ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
   1493 			xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
   1494 			       AC97_EXT_MODEM_CTRL_PRH);
   1495 		}
   1496 
   1497 		/* power-up everything */
   1498 		ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
   1499 		for (i = 5000; i >= 0; i--) {
   1500 			ac97_read(as, AC97_REG_EXT_MODEM_CTRL, &reg);
   1501 			if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
   1502 			       break;
   1503 			DELAY(1);
   1504 		}
   1505 		if (i <= 0) {
   1506 			mutex_exit(as->lock);
   1507 			printf("%s: codec not responding, status=0x%x\n",
   1508 			    device_xname(sc_dev), reg);
   1509 			return ENXIO;
   1510 		}
   1511 
   1512 		/* setup sysctls */
   1513 		if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
   1514 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1515 			reg &= ~AC97_GPIO_LINE1_OH;
   1516 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1517 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1518 			reg &= ~AC97_GPIO_LINE1_OH;
   1519 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1520 
   1521 			mutex_exit(as->lock);
   1522 			err = sysctl_createv(&as->log, 0, NULL, &node_line1,
   1523 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1524 					     "line1",
   1525 					     SYSCTL_DESCR("off-hook line1"),
   1526 					     ac97_sysctl_verify, 0, (void *)as, 0,
   1527 					     CTL_HW, node->sysctl_num,
   1528 					     CTL_CREATE, CTL_EOL);
   1529 			mutex_enter(as->lock);
   1530 
   1531 			if (err != 0)
   1532 				goto sysctl_err;
   1533 			as->offhook_line1_mib = node_line1->sysctl_num;
   1534 		}
   1535 		if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
   1536 			ac97_read(as, AC97_REG_GPIO_CFG, &reg);
   1537 			reg &= ~AC97_GPIO_LINE2_OH;
   1538 			ac97_write(as, AC97_REG_GPIO_CFG, reg);
   1539 			ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
   1540 			reg &= ~AC97_GPIO_LINE2_OH;
   1541 			ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
   1542 
   1543 			mutex_exit(as->lock);
   1544 			err = sysctl_createv(&as->log, 0, NULL, &node_line2,
   1545 					     CTLFLAG_READWRITE, CTLTYPE_INT,
   1546 					     "line2",
   1547 					     SYSCTL_DESCR("off-hook line2"),
   1548 					     ac97_sysctl_verify, 0, (void *)as, 0,
   1549 					     CTL_HW, node->sysctl_num,
   1550 					     CTL_CREATE, CTL_EOL);
   1551 			mutex_enter(as->lock);
   1552 
   1553 			if (err != 0)
   1554 				goto sysctl_err;
   1555 			as->offhook_line2_mib = node_line2->sysctl_num;
   1556 		}
   1557 sysctl_err:
   1558 
   1559 		ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
   1560 		ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
   1561 		ac97_write(as, AC97_REG_MISC_AFE, 0x0);
   1562 	}
   1563 
   1564 	as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
   1565 			   as->modem_source_info : as->audio_source_info);
   1566 	ac97_setup_source_info(as);
   1567 
   1568 	memset(&ctl, 0, sizeof(ctl));
   1569 	/* disable mutes */
   1570 	for (i = 0; i < 11; i++) {
   1571 		static struct {
   1572 			const char *class, *device;
   1573 		} d[11] = {
   1574 			{ AudioCoutputs, AudioNmaster},
   1575 			{ AudioCoutputs, AudioNheadphone},
   1576 			{ AudioCoutputs, AudioNsurround},
   1577 			{ AudioCoutputs, AudioNcenter},
   1578 			{ AudioCoutputs, AudioNlfe},
   1579 			{ AudioCinputs, AudioNdac},
   1580 			{ AudioCinputs, AudioNcd},
   1581 			{ AudioCinputs, AudioNline},
   1582 			{ AudioCinputs, AudioNaux},
   1583 			{ AudioCinputs, AudioNvideo},
   1584 			{ AudioCrecord, AudioNvolume},
   1585 		};
   1586 
   1587 		ctl.type = AUDIO_MIXER_ENUM;
   1588 		ctl.un.ord = 0;
   1589 
   1590 		ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
   1591 			d[i].class, d[i].device, AudioNmute);
   1592 		ac97_mixer_set_port(&as->codec_if, &ctl);
   1593 	}
   1594 	ctl.type = AUDIO_MIXER_ENUM;
   1595 	ctl.un.ord = 0;
   1596 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
   1597 					   AudioNsource, NULL);
   1598 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1599 
   1600 	/* set a reasonable default volume */
   1601 	ctl.type = AUDIO_MIXER_VALUE;
   1602 	ctl.un.value.num_channels = 2;
   1603 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
   1604 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
   1605 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1606 					   AudioNmaster, NULL);
   1607 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1608 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1609 					   AudioNsurround, NULL);
   1610 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1611 	ctl.un.value.num_channels = 1;
   1612 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1613 					   AudioNcenter, NULL);
   1614 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1615 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
   1616 					   AudioNlfe, NULL);
   1617 	ac97_mixer_set_port(&as->codec_if, &ctl);
   1618 
   1619 	if (initfunc != NULL)
   1620 		initfunc(as);
   1621 
   1622 	/* restore AC97_REG_POWER */
   1623 	if (as->type == AC97_CODEC_TYPE_AUDIO)
   1624 		ac97_write(as, AC97_REG_POWER, as->power_reg);
   1625 
   1626 	mutex_exit(as->lock);
   1627 
   1628 	return 0;
   1629 }
   1630 
   1631 static void
   1632 ac97_detach(struct ac97_codec_if *codec_if)
   1633 {
   1634 	struct ac97_softc *as;
   1635 
   1636 	as = (struct ac97_softc *)codec_if;
   1637 
   1638 	mutex_enter(as->lock);
   1639 	ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
   1640 		   | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
   1641 		   | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
   1642 		   | POWER_EAMP_OFF(as));
   1643 	mutex_exit(as->lock);
   1644 
   1645 	free(as, M_DEVBUF);
   1646 }
   1647 
   1648 static void
   1649 ac97_lock(struct ac97_codec_if *codec_if)
   1650 {
   1651 	struct ac97_softc *as;
   1652 
   1653 	as = (struct ac97_softc *)codec_if;
   1654 
   1655 	KASSERT(mutex_owned(as->lock));
   1656 
   1657 	as->lock_counter++;
   1658 }
   1659 
   1660 static void
   1661 ac97_unlock(struct ac97_codec_if *codec_if)
   1662 {
   1663 	struct ac97_softc *as;
   1664 
   1665 	as = (struct ac97_softc *)codec_if;
   1666 
   1667 	KASSERT(mutex_owned(as->lock));
   1668 
   1669 	as->lock_counter--;
   1670 }
   1671 
   1672 static int
   1673 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
   1674 {
   1675 	struct ac97_softc *as;
   1676 	struct ac97_source_info *si;
   1677 	const char *name;
   1678 
   1679 	as = (struct ac97_softc *)codec_if;
   1680 	if (dip->index < as->num_source_info) {
   1681 		si = &as->source_info[dip->index];
   1682 		dip->type = si->type;
   1683 		dip->mixer_class = si->mixer_class;
   1684 		dip->prev = si->prev;
   1685 		dip->next = si->next;
   1686 
   1687 		if (si->qualifier)
   1688 			name = si->qualifier;
   1689 		else if (si->device)
   1690 			name = si->device;
   1691 		else if (si->class)
   1692 			name = si->class;
   1693 		else
   1694 			name = 0;
   1695 
   1696 		if (name)
   1697 			strcpy(dip->label.name, name);
   1698 
   1699 		memcpy(&dip->un, si->info, si->info_size);
   1700 
   1701 		/* Set the delta for volume sources */
   1702 		if (dip->type == AUDIO_MIXER_VALUE)
   1703 			dip->un.v.delta = 1 << (8 - si->bits);
   1704 
   1705 		return 0;
   1706 	}
   1707 
   1708 	return ENXIO;
   1709 }
   1710 
   1711 static int
   1712 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1713 {
   1714 	struct ac97_softc *as;
   1715 	struct ac97_source_info *si;
   1716 	uint16_t mask;
   1717 	uint16_t val, newval;
   1718 	int error;
   1719 	bool spdif;
   1720 
   1721 	as = (struct ac97_softc *)codec_if;
   1722 
   1723 	KASSERT(mutex_owned(as->lock));
   1724 
   1725 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1726 		return EINVAL;
   1727 	si = &as->source_info[cp->dev];
   1728 
   1729 	if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
   1730 		return EINVAL;
   1731 	spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
   1732 	if (spdif && as->lock_counter >= 0) {
   1733 		/* When the value of lock_counter is the default 0,
   1734 		 * it is not allowed to change the SPDIF mode. */
   1735 		return EBUSY;
   1736 	}
   1737 
   1738 	ac97_read(as, si->reg, &val);
   1739 
   1740 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1741 
   1742 	mask = (1 << si->bits) - 1;
   1743 
   1744 	switch (cp->type) {
   1745 	case AUDIO_MIXER_ENUM:
   1746 		if (cp->un.ord > mask || cp->un.ord < 0)
   1747 			return EINVAL;
   1748 
   1749 		newval = (cp->un.ord << si->ofs);
   1750 		if (si->reg == AC97_REG_RECORD_SELECT) {
   1751 			newval |= (newval << (8 + si->ofs));
   1752 			mask |= (mask << 8);
   1753 			mask = mask << si->ofs;
   1754 		} else if (si->reg == AC97_REG_SURR_MASTER) {
   1755 			newval = cp->un.ord ? 0x8080 : 0x0000;
   1756 			mask = 0x8080;
   1757 		} else
   1758 			mask = mask << si->ofs;
   1759 		break;
   1760 	case AUDIO_MIXER_VALUE:
   1761 	{
   1762 		const struct audio_mixer_value *value = si->info;
   1763 		uint16_t  l, r, ol, or;
   1764 		int deltal, deltar;
   1765 
   1766 		if ((cp->un.value.num_channels <= 0) ||
   1767 		    (cp->un.value.num_channels > value->num_channels))
   1768 			return EINVAL;
   1769 
   1770 		if (cp->un.value.num_channels == 1) {
   1771 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
   1772 		} else {
   1773 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1774 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1775 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1776 			} else {	/* left/right is reversed here */
   1777 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   1778 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
   1779 			}
   1780 
   1781 		}
   1782 
   1783 		if (!si->polarity) {
   1784 			l = 255 - l;
   1785 			r = 255 - r;
   1786 		}
   1787 
   1788 		ol = (val >> (8+si->ofs)) & mask;
   1789 		or = (val >> si->ofs) & mask;
   1790 
   1791 		deltal = (ol << (8 - si->bits)) - l;
   1792 		deltar = (or << (8 - si->bits)) - r;
   1793 
   1794 		l = l >> (8 - si->bits);
   1795 		r = r >> (8 - si->bits);
   1796 
   1797 		if (deltal && ol == l)
   1798 			l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
   1799 		if (deltar && or == r)
   1800 			r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
   1801 
   1802 		newval = ((r & mask) << si->ofs);
   1803 		if (value->num_channels == 2) {
   1804 			newval = newval | ((l & mask) << (si->ofs+8));
   1805 			mask |= (mask << 8);
   1806 		}
   1807 		mask = mask << si->ofs;
   1808 		break;
   1809 	}
   1810 	default:
   1811 		return EINVAL;
   1812 	}
   1813 
   1814 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
   1815 	if (error)
   1816 		return error;
   1817 
   1818 	if (spdif && as->host_if->spdif_event != NULL) {
   1819 		DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
   1820 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
   1821 	}
   1822 	return 0;
   1823 }
   1824 
   1825 static int
   1826 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
   1827 			 const char *device, const char *qualifier)
   1828 {
   1829 	struct ac97_softc *as;
   1830 	int idx;
   1831 
   1832 	as = (struct ac97_softc *)codec_if;
   1833 
   1834 	KASSERT(mutex_owned(as->lock));
   1835 
   1836 	for (idx = 0; idx < as->num_source_info; idx++) {
   1837 		struct ac97_source_info *si = &as->source_info[idx];
   1838 		if (ac97_str_equal(class, si->class) &&
   1839 		    ac97_str_equal(device, si->device) &&
   1840 		    ac97_str_equal(qualifier, si->qualifier))
   1841 			return idx;
   1842 	}
   1843 
   1844 	return -1;
   1845 }
   1846 
   1847 static int
   1848 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
   1849 {
   1850 	struct ac97_softc *as;
   1851 	struct ac97_source_info *si;
   1852 	uint16_t mask;
   1853 	uint16_t val;
   1854 
   1855 	as = (struct ac97_softc *)codec_if;
   1856 
   1857 	KASSERT(mutex_owned(as->lock));
   1858 
   1859 	si = &as->source_info[cp->dev];
   1860 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
   1861 		return EINVAL;
   1862 
   1863 	if (cp->type != si->type)
   1864 		return EINVAL;
   1865 
   1866 	ac97_read(as, si->reg, &val);
   1867 
   1868 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
   1869 
   1870 	mask = (1 << si->bits) - 1;
   1871 
   1872 	switch (cp->type) {
   1873 	case AUDIO_MIXER_ENUM:
   1874 		cp->un.ord = (val >> si->ofs) & mask;
   1875 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
   1876 			     val, si->ofs, mask, cp->un.ord));
   1877 		break;
   1878 	case AUDIO_MIXER_VALUE:
   1879 	{
   1880 		const struct audio_mixer_value *value = si->info;
   1881 		uint16_t  l, r;
   1882 
   1883 		if ((cp->un.value.num_channels <= 0) ||
   1884 		    (cp->un.value.num_channels > value->num_channels))
   1885 			return EINVAL;
   1886 
   1887 		if (value->num_channels == 1) {
   1888 			l = r = (val >> si->ofs) & mask;
   1889 		} else {
   1890 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
   1891 				l = (val >> (si->ofs + 8)) & mask;
   1892 				r = (val >> si->ofs) & mask;
   1893 			} else {	/* host has reversed channels */
   1894 				r = (val >> (si->ofs + 8)) & mask;
   1895 				l = (val >> si->ofs) & mask;
   1896 			}
   1897 		}
   1898 
   1899 		l = (l << (8 - si->bits));
   1900 		r = (r << (8 - si->bits));
   1901 		if (!si->polarity) {
   1902 			l = 255 - l;
   1903 			r = 255 - r;
   1904 		}
   1905 
   1906 		/* The EAP driver averages l and r for stereo
   1907 		   channels that are requested in MONO mode. Does this
   1908 		   make sense? */
   1909 		if (cp->un.value.num_channels == 1) {
   1910 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
   1911 		} else if (cp->un.value.num_channels == 2) {
   1912 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
   1913 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
   1914 		}
   1915 
   1916 		break;
   1917 	}
   1918 	default:
   1919 		return EINVAL;
   1920 	}
   1921 
   1922 	return 0;
   1923 }
   1924 
   1925 
   1926 static int
   1927 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
   1928 {
   1929 	struct ac97_softc *as;
   1930 	u_int value;
   1931 	uint16_t ext_stat;
   1932 	uint16_t actual;
   1933 	uint16_t power;
   1934 	uint16_t power_bit;
   1935 
   1936 	as = (struct ac97_softc *)codec_if;
   1937 
   1938 	KASSERT(mutex_owned(as->lock));
   1939 
   1940 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
   1941 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   1942 			*rate = AC97_SINGLE_RATE;
   1943 			return 0;
   1944 		}
   1945 	} else {
   1946 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1947 			*rate = AC97_SINGLE_RATE;
   1948 			return 0;
   1949 		}
   1950 	}
   1951 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
   1952 	ext_stat = 0;
   1953 	/*
   1954 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
   1955 	 *	Check VRA, DRA
   1956 	 * PCM_LR_ADC_RATE
   1957 	 *	Check VRA
   1958 	 * PCM_MIC_ADC_RATE
   1959 	 *	Check VRM
   1960 	 */
   1961 	switch (target) {
   1962 	case AC97_REG_PCM_FRONT_DAC_RATE:
   1963 	case AC97_REG_PCM_SURR_DAC_RATE:
   1964 	case AC97_REG_PCM_LFE_DAC_RATE:
   1965 		power_bit = AC97_POWER_OUT;
   1966 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1967 			*rate = AC97_SINGLE_RATE;
   1968 			return 0;
   1969 		}
   1970 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
   1971 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
   1972 			if (value > 0x1ffff) {
   1973 				return EINVAL;
   1974 			} else if (value > 0xffff) {
   1975 				/* Enable DRA */
   1976 				ext_stat |= AC97_EXT_AUDIO_DRA;
   1977 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1978 				value /= 2;
   1979 			} else {
   1980 				/* Disable DRA */
   1981 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
   1982 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
   1983 			}
   1984 		} else {
   1985 			if (value > 0xffff)
   1986 				return EINVAL;
   1987 		}
   1988 		break;
   1989 	case AC97_REG_PCM_LR_ADC_RATE:
   1990 		power_bit = AC97_POWER_IN;
   1991 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
   1992 			*rate = AC97_SINGLE_RATE;
   1993 			return 0;
   1994 		}
   1995 		if (value > 0xffff)
   1996 			return EINVAL;
   1997 		break;
   1998 	case AC97_REG_PCM_MIC_ADC_RATE:
   1999 		power_bit = AC97_POWER_IN;
   2000 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
   2001 			*rate = AC97_SINGLE_RATE;
   2002 			return 0;
   2003 		}
   2004 		if (value > 0xffff)
   2005 			return EINVAL;
   2006 		break;
   2007 	default:
   2008 		printf("%s: Unknown register: 0x%x\n", __func__, target);
   2009 		return EINVAL;
   2010 	}
   2011 
   2012 	ac97_read(as, AC97_REG_POWER, &power);
   2013 	ac97_write(as, AC97_REG_POWER, power | power_bit);
   2014 
   2015 	ac97_write(as, target, (uint16_t)value);
   2016 	ac97_read(as, target, &actual);
   2017 	actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
   2018 
   2019 	ac97_write(as, AC97_REG_POWER, power);
   2020 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
   2021 		*rate = actual * 2;
   2022 	} else {
   2023 		*rate = actual;
   2024 	}
   2025 	return 0;
   2026 }
   2027 
   2028 static void
   2029 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
   2030 {
   2031 	struct ac97_softc *as;
   2032 
   2033 	as = (struct ac97_softc *)codec_if;
   2034 
   2035 	KASSERT(mutex_owned(as->lock));
   2036 
   2037 	as->ac97_clock = clock;
   2038 }
   2039 
   2040 static uint16_t
   2041 ac97_get_extcaps(struct ac97_codec_if *codec_if)
   2042 {
   2043 	struct ac97_softc *as;
   2044 
   2045 	as = (struct ac97_softc *)codec_if;
   2046 
   2047 	KASSERT(mutex_owned(as->lock));
   2048 
   2049 	return as->ext_id;
   2050 }
   2051 
   2052 static int
   2053 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
   2054 {
   2055 	struct ac97_source_info *si;
   2056 	int ouridx, idx;
   2057 
   2058 	KASSERT(mutex_owned(as->lock));
   2059 
   2060 	if ((as->type == AC97_CODEC_TYPE_AUDIO &&
   2061 	     as->num_source_info >= AUDIO_MAX_SOURCES) ||
   2062 	    (as->type == AC97_CODEC_TYPE_MODEM &&
   2063 	     as->num_source_info >= MODEM_MAX_SOURCES)) {
   2064 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
   2065 		       __func__, __FILE__);
   2066 		return -1;
   2067 	}
   2068 	if (!ac97_check_capability(as, src->req_feature))
   2069 		return -1;
   2070 	ouridx = as->num_source_info;
   2071 	si = &as->source_info[ouridx];
   2072 	memcpy(si, src, sizeof(*si));
   2073 
   2074 	switch (si->type) {
   2075 	case AUDIO_MIXER_CLASS:
   2076 	case AUDIO_MIXER_VALUE:
   2077 		printf("%s: adding class/value is not supported yet.\n",
   2078 		       __func__);
   2079 		return -1;
   2080 	case AUDIO_MIXER_ENUM:
   2081 		break;
   2082 	default:
   2083 		printf("%s: unknown type: %d\n", __func__, si->type);
   2084 		return -1;
   2085 	}
   2086 	as->num_source_info++;
   2087 
   2088 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2089 						   NULL, NULL);
   2090 	/* Find the root of the device */
   2091 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
   2092 				       si->device, NULL);
   2093 	/* Find the last item */
   2094 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
   2095 		idx = as->source_info[idx].next;
   2096 	/* Append */
   2097 	as->source_info[idx].next = ouridx;
   2098 	si->prev = idx;
   2099 	si->next = AUDIO_MIXER_LAST;
   2100 
   2101 	return 0;
   2102 }
   2103 
   2104 /**
   2105  * Codec-dependent initialization
   2106  */
   2107 
   2108 #define	AD1980_REG_MISC	0x76
   2109 #define		AD1980_MISC_MBG0	0x0001	/* 0 1888/1980/1981 /1985 */
   2110 #define		AD1980_MISC_MBG1	0x0002	/* 1 1888/1980/1981 /1985 */
   2111 #define		AD1980_MISC_VREFD	0x0004	/* 2 1888/1980/1981 /1985 */
   2112 #define		AD1980_MISC_VREFH	0x0008	/* 3 1888/1980/1981 /1985 */
   2113 #define		AD1980_MISC_SRU		0x0010	/* 4 1888/1980      /1985 */
   2114 #define		AD1980_MISC_LOSEL	0x0020	/* 5 1888/1980/1981 /1985 */
   2115 #define		AD1980_MISC_2CMIC	0x0040	/* 6      1980/1981B/1985 */
   2116 #define		AD1980_MISC_SPRD	0x0080	/* 7 1888/1980      /1985 */
   2117 #define		AD1980_MISC_DMIX0	0x0100	/* 8 1888/1980      /1985 */
   2118 #define		AD1980_MISC_DMIX1	0x0200	/* 9 1888/1980      /1985 */
   2119 #define		AD1980_MISC_HPSEL	0x0400	/*10 1888/1980      /1985 */
   2120 #define		AD1980_MISC_CLDIS	0x0800	/*11 1888/1980      /1985 */
   2121 #define		AD1980_MISC_LODIS	0x1000	/*12 1888/1980/1981 /1985 */
   2122 #define		AD1980_MISC_MSPLT	0x2000	/*13 1888/1980/1981 /1985 */
   2123 #define		AD1980_MISC_AC97NC	0x4000	/*14 1888/1980      /1985 */
   2124 #define		AD1980_MISC_DACZ	0x8000	/*15 1888/1980/1981 /1985 */
   2125 #define	AD1981_REG_MISC	0x76
   2126 #define		AD1981_MISC_MADST	0x0010  /* 4 */
   2127 #define		AD1981A_MISC_MADPD	0x0040  /* 6 */
   2128 #define		AD1981B_MISC_MADPD	0x0080  /* 7 */
   2129 #define		AD1981_MISC_FMXE	0x0200  /* 9 */
   2130 #define		AD1981_MISC_DAM		0x0800  /*11 */
   2131 static void
   2132 ac97_ad198x_init(struct ac97_softc *as)
   2133 {
   2134 	int i;
   2135 	uint16_t misc;
   2136 
   2137 	KASSERT(mutex_owned(as->lock));
   2138 
   2139 	ac97_read(as, AD1980_REG_MISC, &misc);
   2140 	ac97_write(as, AD1980_REG_MISC,
   2141 		   misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
   2142 
   2143 	for (i = 0; i < as->num_source_info; i++) {
   2144 		if (as->source_info[i].type != AUDIO_MIXER_VALUE)
   2145 			continue;
   2146 
   2147 		if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
   2148 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
   2149 		else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
   2150 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
   2151 	}
   2152 }
   2153 
   2154 #define ALC650_REG_MULTI_CHANNEL_CONTROL	0x6a
   2155 #define		ALC650_MCC_SLOT_MODIFY_MASK		0xc000
   2156 #define		ALC650_MCC_FRONTDAC_FROM_SPDIFIN	0x2000 /* 13 */
   2157 #define		ALC650_MCC_SPDIFOUT_FROM_ADC		0x1000 /* 12 */
   2158 #define		ALC650_MCC_PCM_FROM_SPDIFIN		0x0800 /* 11 */
   2159 #define		ALC650_MCC_MIC_OR_CENTERLFE		0x0400 /* 10 */
   2160 #define		ALC650_MCC_LINEIN_OR_SURROUND		0x0200 /* 9 */
   2161 #define		ALC650_MCC_INDEPENDENT_MASTER_L		0x0080 /* 7 */
   2162 #define		ALC650_MCC_INDEPENDENT_MASTER_R		0x0040 /* 6 */
   2163 #define		ALC650_MCC_ANALOG_TO_CENTERLFE		0x0020 /* 5 */
   2164 #define		ALC650_MCC_ANALOG_TO_SURROUND		0x0010 /* 4 */
   2165 #define		ALC650_MCC_EXCHANGE_CENTERLFE		0x0008 /* 3 */
   2166 #define		ALC650_MCC_CENTERLFE_DOWNMIX		0x0004 /* 2 */
   2167 #define		ALC650_MCC_SURROUND_DOWNMIX		0x0002 /* 1 */
   2168 #define		ALC650_MCC_LINEOUT_TO_SURROUND		0x0001 /* 0 */
   2169 static void
   2170 ac97_alc650_init(struct ac97_softc *as)
   2171 {
   2172 	static const struct ac97_source_info sources[6] = {
   2173 		{ AudioCoutputs, AudioNsurround, "lineinjack",
   2174 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2175 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2176 		  0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2177 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2178 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2179 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2180 		  0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2181 		{ AudioCoutputs, AudioNcenter, "micjack",
   2182 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2183 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2184 		  0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2185 		{ AudioCoutputs, AudioNlfe, "micjack",
   2186 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2187 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2188 		  0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2189 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2190 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2191 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2192 		  0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2193 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2194 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2195 		  ALC650_REG_MULTI_CHANNEL_CONTROL,
   2196 		  0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2197 	};
   2198 
   2199 	ac97_add_port(as, &sources[0]);
   2200 	ac97_add_port(as, &sources[1]);
   2201 	ac97_add_port(as, &sources[2]);
   2202 	ac97_add_port(as, &sources[3]);
   2203 	ac97_add_port(as, &sources[4]);
   2204 	ac97_add_port(as, &sources[5]);
   2205 }
   2206 
   2207 #define UCB1400_REG_FEATURE_CSR1	0x6a
   2208 #define		UCB1400_BB(bb)			(((bb) & 0xf) << 11)
   2209 #define		UCB1400_TR(tr)			(((tr) & 0x3) << 9)
   2210 #define		UCB1400_M_MAXIMUM		(3 << 7)
   2211 #define		UCB1400_M_MINIMUM		(1 << 7)
   2212 #define		UCB1400_M_FLAT			(0 << 7)
   2213 #define		UCB1400_HPEN			(1 << 6)
   2214 #define		UCB1400_DE			(1 << 5)
   2215 #define		UCB1400_DC			(1 << 4)
   2216 #define		UCB1400_HIPS			(1 << 3)
   2217 #define		UCB1400_GIEN			(1 << 2)
   2218 #define		UCB1400_OVFL			(1 << 0)
   2219 #define UCB1400_REG_FEATURE_CSR2	0x6c
   2220 #define		UCB1400_SMT			(1 << 15)	/* Must be 0 */
   2221 #define		UCB1400_SUEV1			(1 << 14)	/* Must be 0 */
   2222 #define		UCB1400_SUEV0			(1 << 13)	/* Must be 0 */
   2223 #define		UCB1400_AVE			(1 << 12)
   2224 #define		UCB1400_AVEN1			(1 << 11)	/* Must be 0 */
   2225 #define		UCB1400_AVEN0			(1 << 10)	/* Must be 0 */
   2226 #define		UCB1400_SLP_ON			\
   2227 					(UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
   2228 #define		UCB1400_SLP_PLL			(2 << 4)
   2229 #define		UCB1400_SLP_CODEC		(1 << 4)
   2230 #define		UCB1400_SLP_NO			(0 << 4)
   2231 #define		UCB1400_EV2			(1 << 2)	/* Must be 0 */
   2232 #define		UCB1400_EV1			(1 << 1)	/* Must be 0 */
   2233 #define		UCB1400_EV0			(1 << 0)	/* Must be 0 */
   2234 static void
   2235 ac97_ucb1400_init(struct ac97_softc *as)
   2236 {
   2237 
   2238 	ac97_write(as, UCB1400_REG_FEATURE_CSR1,
   2239 	    UCB1400_HPEN | UCB1400_DC | UCB1400_HIPS | UCB1400_OVFL);
   2240 	ac97_write(as, UCB1400_REG_FEATURE_CSR2, UCB1400_AVE | UCB1400_SLP_ON);
   2241 }
   2242 
   2243 #define VT1616_REG_IO_CONTROL	0x5a
   2244 #define		VT1616_IC_LVL			(1 << 15)
   2245 #define		VT1616_IC_LFECENTER_TO_FRONT	(1 << 12)
   2246 #define		VT1616_IC_SURROUND_TO_FRONT	(1 << 11)
   2247 #define		VT1616_IC_BPDC			(1 << 10)
   2248 #define		VT1616_IC_DC			(1 << 9)
   2249 #define		VT1616_IC_IB_MASK		0x000c
   2250 static void
   2251 ac97_vt1616_init(struct ac97_softc *as)
   2252 {
   2253 	static const struct ac97_source_info sources[3] = {
   2254 		{ AudioCoutputs, AudioNsurround, "mixtofront",
   2255 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2256 		  VT1616_REG_IO_CONTROL,
   2257 		  0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
   2258 		{ AudioCoutputs, AudioNcenter, "mixtofront",
   2259 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2260 		  VT1616_REG_IO_CONTROL,
   2261 		  0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
   2262 		{ AudioCoutputs, AudioNlfe, "mixtofront",
   2263 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
   2264 		  VT1616_REG_IO_CONTROL,
   2265 		  0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
   2266 	};
   2267 
   2268 	KASSERT(mutex_owned(as->lock));
   2269 
   2270 	ac97_add_port(as, &sources[0]);
   2271 	ac97_add_port(as, &sources[1]);
   2272 	ac97_add_port(as, &sources[2]);
   2273 }
   2274 
   2275 static int
   2276 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
   2277 {
   2278 	uint16_t val;
   2279 
   2280 	KASSERT(mutex_owned(as->lock));
   2281 
   2282 	val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
   2283 	switch (newval) {
   2284 	case 0:
   2285 		val &= ~line;
   2286 		break;
   2287 	case 1:
   2288 		val |= line;
   2289 		break;
   2290 	}
   2291 	ac97_write(as, AC97_REG_GPIO_STATUS, val);
   2292 
   2293 	return 0;
   2294 }
   2295 
   2296 static int
   2297 ac97_sysctl_verify(SYSCTLFN_ARGS)
   2298 {
   2299 	int error, tmp;
   2300 	struct sysctlnode node;
   2301 	struct ac97_softc *as;
   2302 
   2303 	node = *rnode;
   2304 	as = rnode->sysctl_data;
   2305 	if (node.sysctl_num == as->offhook_line1_mib) {
   2306 		tmp = as->offhook_line1;
   2307 		node.sysctl_data = &tmp;
   2308 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2309 		if (error || newp == NULL)
   2310 			return error;
   2311 
   2312 		if (tmp < 0 || tmp > 1)
   2313 			return EINVAL;
   2314 
   2315 		as->offhook_line1 = tmp;
   2316 		mutex_enter(as->lock);
   2317 		ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
   2318 		mutex_exit(as->lock);
   2319 	} else if (node.sysctl_num == as->offhook_line2_mib) {
   2320 		tmp = as->offhook_line2;
   2321 		node.sysctl_data = &tmp;
   2322 		error = sysctl_lookup(SYSCTLFN_CALL(&node));
   2323 		if (error || newp == NULL)
   2324 			return error;
   2325 
   2326 		if (tmp < 0 || tmp > 1)
   2327 			return EINVAL;
   2328 
   2329 		as->offhook_line2 = tmp;
   2330 		mutex_enter(as->lock);
   2331 		ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
   2332 		mutex_exit(as->lock);
   2333 	}
   2334 
   2335 	return 0;
   2336 }
   2337