xref: /openbsd/sys/dev/ic/ac97.c (revision 9b7c3dbb)
1 /*	$OpenBSD: ac97.c,v 1.81 2015/08/28 00:03:53 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
5  *
6  * Author:	Constantine Sapuntzakis <csapuntz@stanford.edu>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote
17  *    products derived from this software without specific prior written
18  *    permission.
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
29  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.  */
31 
32 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
33    the following copyright */
34 
35 /*
36  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  * $FreeBSD$
61  */
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 
68 #include <sys/audioio.h>
69 #include <dev/audio_if.h>
70 #include <dev/ic/ac97.h>
71 
72 
73 /* default parameters; supported by all ac97 codecs */
74 const struct audio_params ac97_audio_default = {
75 	48000,		/* sample_rate */
76 	AUDIO_ENCODING_SLINEAR_LE, /* encoding */
77 	16,		/* precision */
78 	2,		/* bps */
79 	1,		/* msb */
80 	2		/* channels */
81 };
82 
83 const struct audio_mixer_enum ac97_on_off = {
84 	2,
85 	{ { { AudioNoff } , 0 },
86 	{ { AudioNon }  , 1 } }
87 };
88 
89 const struct audio_mixer_enum ac97_mic_select = {
90 	2,
91 	{ { { AudioNmicrophone "0" }, 0 },
92 	{ { AudioNmicrophone "1" }, 1 } }
93 };
94 
95 const struct audio_mixer_enum ac97_mono_select = {
96 	2,
97 	{ { { AudioNmixerout }, 0 },
98 	{ { AudioNmicrophone }, 1 } }
99 };
100 
101 const struct audio_mixer_enum ac97_source = {
102 	8,
103 	{ { { AudioNmicrophone } , 0 },
104 	{ { AudioNcd }, 1 },
105 	{ { "video" }, 2 },
106 	{ { AudioNaux }, 3 },
107 	{ { AudioNline }, 4 },
108 	{ { AudioNmixerout }, 5 },
109 	{ { AudioNmixerout AudioNmono }, 6 },
110 	{ { "phone" }, 7 }}
111 };
112 
113 /*
114  * Due to different values for each source that uses these structures,
115  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
116  * ac97_source_info.bits.
117  */
118 const struct audio_mixer_value ac97_volume_stereo = {
119 	{ AudioNvolume },
120 	2
121 };
122 
123 const struct audio_mixer_value ac97_volume_mono = {
124 	{ AudioNvolume },
125 	1
126 };
127 
128 #define AudioNspdif	"spdif"
129 
130 #define WRAP(a)  &a, sizeof(a)
131 
132 const struct ac97_source_info {
133 	char *class;
134 	char *device;
135 	char *qualifier;
136 	int  type;
137 
138 	const void *info;
139 	int16_t info_size;
140 
141 	u_int8_t  reg;
142 	u_int16_t default_value;
143 	u_int8_t  bits:3;
144 	u_int8_t  ofs:4;
145 	u_int8_t  mute:1;
146 	u_int8_t  polarity:1;		/* Does 0 == MAX or MIN */
147 	enum {
148 		CHECK_NONE = 0,
149 		CHECK_SURROUND,
150 		CHECK_CENTER,
151 		CHECK_LFE,
152 		CHECK_HEADPHONES,
153 		CHECK_TONE,
154 		CHECK_MIC,
155 		CHECK_LOUDNESS,
156 		CHECK_3D,
157 		CHECK_SPDIF
158 	} req_feature;
159 
160 	int16_t  prev;
161 	int16_t  next;
162 	int16_t  mixer_class;
163 } source_info[] = {
164 	{ AudioCinputs,		NULL,		NULL,
165 	  AUDIO_MIXER_CLASS, },
166 	{ AudioCoutputs,	NULL,		NULL,
167 	  AUDIO_MIXER_CLASS, },
168 	{ AudioCrecord,		NULL,		NULL,
169 	  AUDIO_MIXER_CLASS, },
170 	/* Stereo master volume*/
171 	{ AudioCoutputs,	AudioNmaster,	NULL,
172 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
173 	  AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
174 	},
175 	/* Mono volume */
176 	{ AudioCoutputs,	AudioNmono,	NULL,
177 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
178 	  AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
179 	},
180 	{ AudioCoutputs,	AudioNmono,	AudioNsource,
181 	  AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
182 	  AC97_REG_GP, 0x0000, 1, 9, 0,
183 	},
184 	/* Headphone volume */
185 	{ AudioCoutputs,	AudioNheadphone, NULL,
186 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
187 	  AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
188 	},
189 	/* Surround volume - logic hard coded for mute */
190 	{ AudioCoutputs,	AudioNsurround,	NULL,
191 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
192 	  AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
193 	},
194 	/* Center volume*/
195 	{ AudioCoutputs,	AudioNcenter,	NULL,
196 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
197 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
198 	},
199 	{ AudioCoutputs,	AudioNcenter,	AudioNmute,
200 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
201 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
202 	},
203 	/* LFE volume*/
204 	{ AudioCoutputs,	AudioNlfe,	NULL,
205 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
206 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
207 	},
208 	{ AudioCoutputs,	AudioNlfe,	AudioNmute,
209 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
210 	  AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
211 	},
212 	/* Tone */
213 	{ AudioCoutputs,	"tone",	NULL,
214 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
215 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
216 	},
217 	/* PC Beep Volume */
218 	{ AudioCinputs,		AudioNspeaker,	NULL,
219 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
220 	  AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
221 	},
222 
223 	/* Phone */
224 	{ AudioCinputs,		"phone",	NULL,
225 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
226 	  AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
227 	},
228 	/* Mic Volume */
229 	{ AudioCinputs,		AudioNmicrophone, NULL,
230 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
231 	  AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
232 	},
233 	{ AudioCinputs,		AudioNmicrophone, AudioNpreamp,
234 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
235 	  AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
236 	},
237 	{ AudioCinputs,		AudioNmicrophone, AudioNsource,
238 	  AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
239 	  AC97_REG_GP, 0x0000, 1, 8, 0,
240 	},
241 	/* Line in Volume */
242 	{ AudioCinputs,		AudioNline,	NULL,
243 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
244 	  AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
245 	},
246 	/* CD Volume */
247 	{ AudioCinputs,		AudioNcd,	NULL,
248 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
249 	  AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
250 	},
251 	/* Video Volume */
252 	{ AudioCinputs,		AudioNvideo,	NULL,
253 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
254 	  AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
255 	},
256 	/* AUX volume */
257 	{ AudioCinputs,		AudioNaux,	NULL,
258 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
259 	  AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
260 	},
261 	/* PCM out volume */
262 	{ AudioCinputs,		AudioNdac,	NULL,
263 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
264 	  AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
265 	},
266 	/* Record Source - some logic for this is hard coded - see below */
267 	{ AudioCrecord,		AudioNsource,	NULL,
268 	  AUDIO_MIXER_ENUM, WRAP(ac97_source),
269 	  AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
270 	},
271 	/* Record Gain */
272 	{ AudioCrecord,		AudioNvolume,	NULL,
273 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
274 	  AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
275 	},
276 	/* Record Gain mic */
277 	{ AudioCrecord,		AudioNmicrophone, NULL,
278 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
279 	  AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
280 	},
281 	/* */
282 	{ AudioCoutputs,	AudioNloudness,	NULL,
283 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
284 	  AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
285 	},
286 	{ AudioCoutputs,	AudioNspatial,	NULL,
287 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
288 	  AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
289 	},
290 	{ AudioCoutputs,	AudioNspatial,	"center",
291 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
292 	  AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
293 	},
294 	{ AudioCoutputs,	AudioNspatial,	"depth",
295 	  AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
296 	  AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
297 	},
298 	/* External Amp */
299 	{ AudioCoutputs,	AudioNextamp,	NULL,
300 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
301 	  AC97_REG_POWER, 0x0000, 1, 15, 0, 0
302 	},
303 	/* S/PDIF output enable */
304 	{ AudioCoutputs,	AudioNspdif,	NULL,
305 	  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
306 	  AC97_REG_EXT_AUDIO_CTRL, 0x0000, 1, 2, 0, 0, CHECK_SPDIF
307 	}
308 
309 	/* Missing features: Simulated Stereo, POP, Loopback mode */
310 };
311 
312 /*
313  * Check out http://www.intel.com/technology/computing/audio/index.htm
314  * for information on AC-97
315  */
316 
317 struct ac97_softc {
318 	/* ac97_codec_if must be at the first of ac97_softc. */
319 	struct ac97_codec_if codec_if;
320 	struct ac97_host_if *host_if;
321 #define MAX_SOURCES	(2 * nitems(source_info))
322 	struct ac97_source_info source_info[MAX_SOURCES];
323 	int num_source_info;
324 	enum ac97_host_flags host_flags;
325 	unsigned int ac97_clock; /* usually 48000 */
326 #define AC97_STANDARD_CLOCK	48000U
327 	u_int16_t caps;		/* -> AC97_REG_RESET */
328 	u_int16_t ext_id;	/* -> AC97_REG_EXT_AUDIO_ID */
329 	u_int16_t shadow_reg[128];
330 	int lock_counter;
331 };
332 
333 int	ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
334 int	ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
335 void	ac97_lock(struct ac97_codec_if *);
336 void	ac97_unlock(struct ac97_codec_if *);
337 int	ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
338 int	ac97_get_portnum_by_name(struct ac97_codec_if *, char *, char *,
339 	    char *);
340 void	ac97_restore_shadow(struct ac97_codec_if *);
341 int	ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
342 void	ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
343 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
344 int	ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src);
345 
346 void	ac97_ad1885_init(struct ac97_softc *, int);
347 void	ac97_ad1886_init(struct ac97_softc *, int);
348 void	ac97_ad198x_init(struct ac97_softc *, int);
349 void	ac97_alc650_init(struct ac97_softc *, int);
350 void	ac97_cx20468_init(struct ac97_softc *, int);
351 void	ac97_vt1616_init(struct ac97_softc *, int);
352 
353 struct ac97_codec_if_vtbl ac97civ = {
354 	ac97_mixer_get_port,
355 	ac97_mixer_set_port,
356 	ac97_query_devinfo,
357 	ac97_get_portnum_by_name,
358 	ac97_restore_shadow,
359 	ac97_get_extcaps,
360 	ac97_set_rate,
361 	ac97_set_clock,
362 	ac97_lock,
363 	ac97_unlock
364 };
365 
366 const struct ac97_codecid {
367 	u_int8_t id;
368 	u_int8_t mask;
369 	u_int8_t rev;
370 	u_int8_t shift;	/* no use yet */
371 	char * const name;
372 	void (*init)(struct ac97_softc *, int);
373 }  ac97_ad[] = {
374 	{ 0x03, 0xff, 0, 0,	"AD1819" },
375 	{ 0x40, 0xff, 0, 0,	"AD1881" },
376 	{ 0x48, 0xff, 0, 0,	"AD1881A" },
377 	{ 0x60, 0xff, 0, 0,	"AD1885", 	ac97_ad1885_init },
378 	{ 0x61, 0xff, 0, 0,	"AD1886",	ac97_ad1886_init },
379 	{ 0x63, 0xff, 0, 0,	"AD1886A" },
380 	{ 0x68, 0xff, 0, 0,	"AD1888",	ac97_ad198x_init },
381 	{ 0x70, 0xff, 0, 0,	"AD1980",	ac97_ad198x_init },
382 	{ 0x72, 0xff, 0, 0,	"AD1981A" },
383 	{ 0x74, 0xff, 0, 0,	"AD1981B" },
384 	{ 0x75, 0xff, 0, 0,	"AD1985",	ac97_ad198x_init },
385 }, ac97_ak[] = {
386 	{ 0x00,	0xfe, 1, 0,	"AK4540" },
387 	{ 0x01,	0xfe, 1, 0,	"AK4540" },
388 	{ 0x02,	0xff, 0, 0,	"AK4543" },
389 	{ 0x05,	0xff, 0, 0,	"AK4544" },
390 	{ 0x06,	0xff, 0, 0,	"AK4544A" },
391 	{ 0x07,	0xff, 0, 0,	"AK4545" },
392 }, ac97_av[] = {
393 	{ 0x10, 0xff, 0, 0,	"ALC200" },
394 	{ 0x20, 0xff, 0, 0,	"ALC650" },
395 	{ 0x21, 0xff, 0, 0,	"ALC650D" },
396 	{ 0x22, 0xff, 0, 0,	"ALC650E" },
397 	{ 0x23, 0xff, 0, 0,	"ALC650F" },
398 	{ 0x30, 0xff, 0, 0,	"ALC101" },
399 	{ 0x40, 0xff, 0, 0,	"ALC202" },
400 	{ 0x50, 0xff, 0, 0,	"ALC250" },
401 	{ 0x52, 0xff, 0, 0,	"ALC250A?" },
402 	{ 0x60, 0xf0, 0xf, 0,	"ALC655",	ac97_alc650_init },
403 	{ 0x70, 0xf0, 0xf, 0,	"ALC203" },
404 	{ 0x80, 0xf0, 0xf, 0,	"ALC658",	ac97_alc650_init },
405 	{ 0x90, 0xf0, 0xf, 0,	"ALC850" },
406 }, ac97_rl[] = {
407 	{ 0x00, 0xf0, 0xf, 0,	"RL5306" },
408 	{ 0x10, 0xf0, 0xf, 0,	"RL5382" },
409 	{ 0x20, 0xf0, 0xf, 0,	"RL5383" },
410 }, ac97_cm[] = {
411 	{ 0x41,	0xff, 0, 0,	"CMI9738" },
412 	{ 0x61,	0xff, 0, 0,	"CMI9739" },
413 	{ 0x78,	0xff, 0, 0,	"CMI9761A" },
414 	{ 0x82,	0xff, 0, 0,	"CMI9761B" },
415 	{ 0x83,	0xff, 0, 0,	"CMI9761A+" },
416 }, ac97_cr[] = {
417 	{ 0x84,	0xff, 0, 0,	"EV1938" },
418 }, ac97_cs[] = {
419 	{ 0x00,	0xf8, 7, 0,	"CS4297" },
420 	{ 0x10,	0xf8, 7, 0,	"CS4297A" },
421 	{ 0x20,	0xf8, 7, 0,	"CS4298" },
422 	{ 0x28,	0xf8, 7, 0,	"CS4294" },
423 	{ 0x30,	0xf8, 7, 0,	"CS4299" },
424 	{ 0x48,	0xf8, 7, 0,	"CS4201" },
425 	{ 0x58,	0xf8, 7, 0,	"CS4205" },
426 	{ 0x60,	0xf8, 7, 0,	"CS4291" },
427 	{ 0x70,	0xf8, 7, 0,	"CS4202" },
428 }, ac97_cx[] = {
429 	{ 0x21, 0xff, 0, 0,	"HSD11246" },
430 	{ 0x28, 0xf8, 7, 0,	"CX20468",	ac97_cx20468_init },
431 	{ 0x30, 0xff, 0, 0,	"CXT48", },
432 	{ 0x42, 0xff, 0, 0,	"CXT66", },
433 }, ac97_dt[] = {
434 	{ 0x00, 0xff, 0, 0,	"DT0398" },
435 }, ac97_em[] = {
436 	{ 0x23, 0xff, 0, 0,	"EM28023" },
437 	{ 0x28, 0xff, 0, 0,	"EM28028" },
438 }, ac97_es[] = {
439 	{ 0x08, 0xff, 0, 0,	"ES1921" },
440 }, ac97_is[] = {
441 	{ 0x00, 0xff, 0, 0,	"HMP9701" },
442 }, ac97_ic[] = {
443 	{ 0x01, 0xff, 0, 0,	"ICE1230" },
444 	{ 0x11, 0xff, 0, 0,	"ICE1232" },
445 	{ 0x14, 0xff, 0, 0,	"ICE1232A" },
446 	{ 0x51, 0xff, 0, 0,	"VIA VT1616" },
447 	{ 0x52, 0xff, 0, 0,	"VIA VT1616i",	ac97_vt1616_init },
448 }, ac97_it[] = {
449 	{ 0x20, 0xff, 0, 0,	"ITE2226E" },
450 	{ 0x60, 0xff, 0, 0,	"ITE2646E" },
451 }, ac97_ns[] = {
452 	{ 0x00,	0xff, 0, 0,	"LM454[03568]" },
453 	{ 0x31,	0xff, 0, 0,	"LM4549" },
454 	{ 0x40, 0xff, 0, 0,	"LM4540" },
455 	{ 0x43, 0xff, 0, 0,	"LM4543" },
456 	{ 0x46, 0xff, 0, 0,	"LM4546A" },
457 	{ 0x48, 0xff, 0, 0,	"LM4548A" },
458 	{ 0x49, 0xff, 0, 0,	"LM4549A" },
459 	{ 0x50, 0xff, 0, 0,	"LM4550" },
460 }, ac97_ps[] = {
461 	{ 0x01,	0xff, 0, 0,	"UCB1510" },
462 	{ 0x04,	0xff, 0, 0,	"UCB1400" },
463 }, ac97_sl[] = {
464 	{ 0x20,	0xe0, 0, 0,	"Si3036/38" },
465 }, ac97_st[] = {
466 	{ 0x00,	0xff, 0, 0,	"STAC9700" },
467 	{ 0x04,	0xff, 0, 0,	"STAC970[135]" },
468 	{ 0x05,	0xff, 0, 0,	"STAC9704" },
469 	{ 0x08,	0xff, 0, 0,	"STAC9708/11" },
470 	{ 0x09,	0xff, 0, 0,	"STAC9721/23" },
471 	{ 0x44,	0xff, 0, 0,	"STAC9744/45" },
472 	{ 0x50,	0xff, 0, 0,	"STAC9750/51" },
473 	{ 0x52,	0xff, 0, 0,	"STAC9752/53" },
474 	{ 0x56,	0xff, 0, 0,	"STAC9756/57" },
475 	{ 0x58,	0xff, 0, 0,	"STAC9758/59" },
476 	{ 0x60,	0xff, 0, 0,	"STAC9760/61" },
477 	{ 0x62,	0xff, 0, 0,	"STAC9762/63" },
478 	{ 0x66,	0xff, 0, 0,	"STAC9766/67" },
479 	{ 0x84,	0xff, 0, 0,	"STAC9784/85" },
480 }, ac97_vi[] = {
481 	{ 0x61, 0xff, 0, 0,	"VT1612A" },
482 	{ 0x70, 0xff, 0, 0,	"VT1617" },
483 }, ac97_tt[] = {
484 	{ 0x02,	0xff, 0, 0,	"TR28022" },
485 	{ 0x03,	0xff, 0, 0,	"TR28023" },
486 	{ 0x06,	0xff, 0, 0,	"TR28026" },
487 	{ 0x08,	0xff, 0, 0,	"TR28028" },
488 	{ 0x23,	0xff, 0, 0,	"TR28602" },
489 }, ac97_ti[] = {
490 	{ 0x20, 0xff, 0, 0,	"TLC320AD9xC" },
491 }, ac97_wb[] = {
492 	{ 0x01, 0xff, 0, 0,	"W83971D" },
493 }, ac97_wo[] = {
494 	{ 0x00,	0xff, 0, 0,	"WM9701A" },
495 	{ 0x03,	0xff, 0, 0,	"WM9704M/Q-0" }, /* & WM9703 */
496 	{ 0x04,	0xff, 0, 0,	"WM9704M/Q-1" },
497 	{ 0x05,	0xff, 0, 0,	"WM9705/10" },
498 	{ 0x09,	0xff, 0, 0,	"WM9709" },
499 	{ 0x12,	0xff, 0, 0,	"WM9711/12" },
500 }, ac97_ym[] = {
501 	{ 0x00, 0xff, 0, 0,	"YMF743-S" },
502 	{ 0x02, 0xff, 0, 0,	"YMF752-S" },
503 	{ 0x03, 0xff, 0, 0,	"YMF753-S" },
504 };
505 
506 #define	cl(n)	n, nitems(n)
507 const struct ac97_vendorid {
508 	u_int32_t id;
509 	char * const name;
510 	const struct ac97_codecid * const codecs;
511 	u_int8_t num;
512 } ac97_vendors[] = {
513 	{ 0x01408300, "Creative",		cl(ac97_cr) },
514 	{ 0x41445300, "Analog Devices",		cl(ac97_ad) },
515 	{ 0x414b4D00, "Asahi Kasei",		cl(ac97_ak) },
516 	{ 0x414c4300, "Realtek",		cl(ac97_rl) },
517 	{ 0x414c4700, "Avance Logic",		cl(ac97_av) },
518 	{ 0x434d4900, "C-Media Electronics",	cl(ac97_cm) },
519 	{ 0x43525900, "Cirrus Logic",		cl(ac97_cs) },
520 	{ 0x43585400, "Conexant",		cl(ac97_cx) },
521 	{ 0x44543000, "Diamond Technology",	cl(ac97_dt) },
522 	{ 0x454d4300, "eMicro",			cl(ac97_em) },
523 	{ 0x45838300, "ESS Technology",		cl(ac97_es) },
524 	{ 0x48525300, "Intersil",		cl(ac97_is) },
525 	{ 0x49434500, "ICEnsemble",		cl(ac97_ic) },
526 	{ 0x49544500, "ITE, Inc.",		cl(ac97_it) },
527 	{ 0x4e534300, "National Semiconductor", cl(ac97_ns) },
528 	{ 0x50534300, "Philips Semiconductor",	cl(ac97_ps) },
529 	{ 0x53494c00, "Silicon Laboratory",	cl(ac97_sl) },
530 	{ 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
531 	{ 0x54584e00, "Texas Instruments",	cl(ac97_ti) },
532 	{ 0x56494100, "VIA Technologies",	cl(ac97_vi) },
533 	{ 0x57454300, "Winbond",		cl(ac97_wb) },
534 	{ 0x574d4c00, "Wolfson",		cl(ac97_wo) },
535 	{ 0x594d4800, "Yamaha",			cl(ac97_ym) },
536 	{ 0x83847600, "SigmaTel",		cl(ac97_st) },
537 };
538 #undef cl
539 
540 const char * const ac97enhancement[] = {
541 	"No 3D Stereo",
542 	"Analog Devices Phat Stereo",
543 	"Creative",
544 	"National Semi 3D",
545 	"Yamaha Ymersion",
546 	"BBE 3D",
547 	"Crystal Semi 3D",
548 	"Qsound QXpander",
549 	"Spatializer 3D",
550 	"SRS 3D",
551 	"Platform Tech 3D",
552 	"AKM 3D",
553 	"Aureal",
554 	"AZTECH 3D",
555 	"Binaura 3D",
556 	"ESS Technology",
557 	"Harman International VMAx",
558 	"Nvidea 3D",
559 	"Philips Incredible Sound",
560 	"Texas Instruments 3D",
561 	"VLSI Technology 3D",
562 	"TriTech 3D",
563 	"Realtek 3D",
564 	"Samsung 3D",
565 	"Wolfson Microelectronics 3D",
566 	"Delta Integration 3D",
567 	"SigmaTel 3D",
568 	"KS Waves 3D",
569 	"Rockwell 3D",
570 	"Unknown 3D",
571 	"Unknown 3D",
572 	"Unknown 3D"
573 };
574 
575 const char * const ac97feature[] = {
576 	"mic channel",
577 	"reserved",
578 	"tone",
579 	"simulated stereo",
580 	"headphone",
581 	"bass boost",
582 	"18 bit DAC",
583 	"20 bit DAC",
584 	"18 bit ADC",
585 	"20 bit ADC"
586 };
587 
588 
589 int	ac97_str_equal(const char *, const char *);
590 int	ac97_check_capability(struct ac97_softc *, int);
591 void	ac97_setup_source_info(struct ac97_softc *);
592 void	ac97_setup_defaults(struct ac97_softc *);
593 int	ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
594 int	ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
595 
596 
597 #ifdef AUDIO_DEBUG
598 #define DPRINTF(x)	if (ac97debug) printf x
599 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
600 #ifdef AC97_DEBUG
601 int	ac97debug = 1;
602 #else
603 int	ac97debug = 0;
604 #endif
605 #else
606 #define DPRINTF(x)
607 #define DPRINTFN(n,x)
608 #endif
609 
610 void
611 ac97_get_default_params(struct audio_params *params)
612 {
613 	*params = ac97_audio_default;
614 }
615 
616 int
617 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
618 {
619 	int error;
620 
621 	if (((as->host_flags & AC97_HOST_DONT_READ) &&
622 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
623 	    reg != AC97_REG_RESET)) ||
624 	    (as->host_flags & AC97_HOST_DONT_READANY)) {
625 		*val = as->shadow_reg[reg >> 1];
626 		return (0);
627 	}
628 
629 	if ((error = as->host_if->read(as->host_if->arg, reg, val)))
630 		*val = as->shadow_reg[reg >> 1];
631 	return (error);
632 }
633 
634 int
635 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
636 {
637 	as->shadow_reg[reg >> 1] = val;
638 	return (as->host_if->write(as->host_if->arg, reg, val));
639 }
640 
641 void
642 ac97_setup_defaults(struct ac97_softc *as)
643 {
644 	int idx;
645 
646 	bzero(as->shadow_reg, sizeof(as->shadow_reg));
647 
648 	for (idx = 0; idx < nitems(source_info); idx++) {
649 		const struct ac97_source_info *si = &source_info[idx];
650 
651 		ac97_write(as, si->reg, si->default_value);
652 	}
653 }
654 
655 void
656 ac97_restore_shadow(struct ac97_codec_if *self)
657 {
658 	struct ac97_softc *as = (struct ac97_softc *)self;
659 	int idx;
660 
661 	for (idx = 0; idx < nitems(source_info); idx++) {
662 		const struct ac97_source_info *si = &source_info[idx];
663 
664 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
665 	}
666 }
667 
668 int
669 ac97_str_equal(const char *a, const char *b)
670 {
671 	return ((a == b) || (a && b && (!strcmp(a, b))));
672 }
673 
674 int
675 ac97_check_capability(struct ac97_softc *as, int check)
676 {
677 	switch (check) {
678 	case CHECK_NONE:
679 		return 1;
680 	case CHECK_SURROUND:
681 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
682 	case CHECK_CENTER:
683 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
684 	case CHECK_LFE:
685 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
686 	case CHECK_SPDIF:
687 		return as->ext_id & AC97_EXT_AUDIO_SPDIF;
688 	case CHECK_HEADPHONES:
689 		return as->caps & AC97_CAPS_HEADPHONES;
690 	case CHECK_TONE:
691 		return as->caps & AC97_CAPS_TONECTRL;
692 	case CHECK_MIC:
693 		return as->caps & AC97_CAPS_MICIN;
694 	case CHECK_LOUDNESS:
695 		return as->caps & AC97_CAPS_LOUDNESS;
696 	case CHECK_3D:
697 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
698 	default:
699 		printf("%s: internal error: feature=%d\n", __func__, check);
700 		return 0;
701 	}
702 }
703 
704 void
705 ac97_setup_source_info(struct ac97_softc *as)
706 {
707 	struct ac97_source_info *si, *si2;
708 	int idx, ouridx;
709 
710 	for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
711 		si = &as->source_info[ouridx];
712 
713 		if (!ac97_check_capability(as, source_info[idx].req_feature))
714 			continue;
715 
716 		bcopy(&source_info[idx], si, sizeof(*si));
717 
718 		switch (si->type) {
719 		case AUDIO_MIXER_CLASS:
720 			si->mixer_class = ouridx;
721 			ouridx++;
722 			break;
723 		case AUDIO_MIXER_VALUE:
724 			/* Todo - Test to see if it works */
725 			ouridx++;
726 
727 			/* Add an entry for mute, if necessary */
728 			if (si->mute) {
729 				si = &as->source_info[ouridx];
730 				bcopy(&source_info[idx], si, sizeof(*si));
731 				si->qualifier = AudioNmute;
732 				si->type = AUDIO_MIXER_ENUM;
733 				si->info = &ac97_on_off;
734 				si->info_size = sizeof(ac97_on_off);
735 				si->bits = 1;
736 				si->ofs = 15;
737 				si->mute = 0;
738 				si->polarity = 0;
739 				ouridx++;
740 			}
741 			break;
742 		case AUDIO_MIXER_ENUM:
743 			/* Todo - Test to see if it works */
744 			ouridx++;
745 			break;
746 		default:
747 			printf ("ac97: shouldn't get here\n");
748 			break;
749 		}
750 	}
751 
752 	as->num_source_info = ouridx;
753 
754 	for (idx = 0; idx < as->num_source_info; idx++) {
755 		int idx2, previdx;
756 
757 		si = &as->source_info[idx];
758 
759 		/* Find mixer class */
760 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
761 			si2 = &as->source_info[idx2];
762 
763 			if (si2->type == AUDIO_MIXER_CLASS &&
764 			    ac97_str_equal(si->class, si2->class)) {
765 				si->mixer_class = idx2;
766 			}
767 		}
768 
769 
770 		/* Setup prev and next pointers */
771 		if (si->prev != 0 || si->qualifier)
772 			continue;
773 
774 		si->prev = AUDIO_MIXER_LAST;
775 		previdx = idx;
776 
777 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
778 			if (idx2 == idx)
779 				continue;
780 
781 			si2 = &as->source_info[idx2];
782 
783 			if (!si2->prev &&
784 			    ac97_str_equal(si->class, si2->class) &&
785 			    ac97_str_equal(si->device, si2->device)) {
786 				as->source_info[previdx].next = idx2;
787 				as->source_info[idx2].prev = previdx;
788 
789 				previdx = idx2;
790 			}
791 		}
792 
793 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
794 	}
795 }
796 
797 int
798 ac97_attach(struct ac97_host_if *host_if)
799 {
800 	struct ac97_softc *as;
801 	u_int16_t id1, id2, val;
802 	u_int32_t id;
803 	u_int16_t extstat, rate;
804 	mixer_ctrl_t ctl;
805 	int error, i;
806 	void (*initfunc)(struct ac97_softc *, int);
807 
808 	initfunc = NULL;
809 
810 	if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
811 		return (ENOMEM);
812 
813 	as->codec_if.as = as;
814 	as->codec_if.vtbl = &ac97civ;
815 	as->host_if = host_if;
816 
817 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
818 		free(as, M_DEVBUF, sizeof(*as));
819 		return (error);
820 	}
821 
822 	host_if->reset(host_if->arg);
823 	DELAY(1000);
824 
825 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
826 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
827 	DELAY(10000);
828 
829 	if (host_if->flags)
830 		as->host_flags = host_if->flags(host_if->arg);
831 
832 	ac97_setup_defaults(as);
833 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
834 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
835 	ac97_read(as, AC97_REG_RESET, &as->caps);
836 
837 	id = (id1 << 16) | id2;
838 	if (id) {
839 		register const struct ac97_vendorid *vendor;
840 		register const struct ac97_codecid *codec;
841 
842 		printf("ac97: codec id 0x%08x", id);
843 		for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
844 		     sizeof(ac97_vendors[0]) - 1];
845 		     vendor >= ac97_vendors; vendor--) {
846 			if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
847 				printf(" (%s", vendor->name);
848 				for (codec = &vendor->codecs[vendor->num-1];
849 				     codec >= vendor->codecs; codec--) {
850 					if (codec->id == (id & codec->mask))
851 						break;
852 				}
853 				if (codec >= vendor->codecs && codec->mask) {
854 					printf(" %s", codec->name);
855 					initfunc = codec->init;
856 				} else
857 					printf(" <%02x>", id & 0xff);
858 				if (codec >= vendor->codecs && codec->rev)
859 					printf(" rev %d", id & codec->rev);
860 				printf(")");
861 				break;
862 			}
863 		}
864 		printf("\n");
865 	} else
866 		printf("ac97: codec id not read\n");
867 
868 	if (as->caps) {
869 		printf("ac97: codec features ");
870 		for (i = 0; i < 10; i++) {
871 			if (as->caps & (1 << i))
872 				printf("%s, ", ac97feature[i]);
873 		}
874 		printf("%s\n",
875 		    ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
876 	}
877 
878 
879 	as->ac97_clock = AC97_STANDARD_CLOCK;
880 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
881 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
882 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
883 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
884 			  | AC97_EXT_AUDIO_LDAC)) {
885 
886 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
887 		extstat &= ~AC97_EXT_AUDIO_DRA;
888 
889 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
890 			extstat |= AC97_EXT_AUDIO_VRM;
891 
892 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
893 			extstat |= AC97_EXT_AUDIO_LDAC;
894 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
895 			extstat |= AC97_EXT_AUDIO_SDAC;
896 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
897 			extstat |= AC97_EXT_AUDIO_CDAC;
898 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
899 			/* XXX S/PDIF gets same data as DAC?
900 			 * maybe this should be settable?
901 			 * default is SPSAAB (10/11) on AD1980 and ALC codecs.
902 			 */
903 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
904 			extstat |= AC97_EXT_AUDIO_SPSA34;
905 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
906 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
907 			    AC97_SPDIF_SPSR_48K;
908 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
909 		}
910 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
911 			extstat |= AC97_EXT_AUDIO_VRA;
912 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
913 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
914 			/* VRA should be enabled. */
915 			/* so it claims to do variable rate, let's make sure */
916 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
917 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
918 			if (rate != 44100) {
919 				/* We can't believe ext_id */
920 				as->ext_id = 0;
921 			}
922 			/* restore the default value */
923 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
924 				   AC97_SINGLE_RATE);
925 		}
926 	}
927 
928 	ac97_setup_source_info(as);
929 
930 	DELAY(900 * 1000);
931 
932 	/* use initfunc for specific device */
933 	as->codec_if.initfunc = initfunc;
934 	if (initfunc != NULL)
935 		initfunc(as, 0);
936 
937 	/* Just enable the DAC and master volumes by default */
938 	bzero(&ctl, sizeof(ctl));
939 
940 	ctl.type = AUDIO_MIXER_ENUM;
941 	ctl.un.ord = 0;  /* off */
942 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
943 	    AudioNmaster, AudioNmute);
944 	ac97_mixer_set_port(&as->codec_if, &ctl);
945 
946 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
947 	    AudioNdac, AudioNmute);
948 	ac97_mixer_set_port(&as->codec_if, &ctl);
949 
950 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
951 	    AudioNvolume, AudioNmute);
952 	ac97_mixer_set_port(&as->codec_if, &ctl);
953 
954 	ctl.type = AUDIO_MIXER_ENUM;
955 	ctl.un.ord = 0;
956 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
957 	    AudioNsource, NULL);
958 	ac97_mixer_set_port(&as->codec_if, &ctl);
959 
960 	return (0);
961 }
962 
963 int
964 ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
965 {
966 	struct ac97_softc *as = codec_if->as;
967 	u_int16_t val, extstat;
968 
969 	host_if->reset(host_if->arg);
970 	DELAY(1000);
971 
972 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
973 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
974 	DELAY(10000);
975 
976 	codec_if->vtbl->restore_ports(codec_if);
977 
978 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
979 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
980 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
981 			  | AC97_EXT_AUDIO_LDAC)) {
982 
983 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
984 		extstat &= ~AC97_EXT_AUDIO_DRA;
985 
986 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
987 			extstat |= AC97_EXT_AUDIO_VRM;
988 
989 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
990 			extstat |= AC97_EXT_AUDIO_LDAC;
991 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
992 			extstat |= AC97_EXT_AUDIO_SDAC;
993 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
994 			extstat |= AC97_EXT_AUDIO_CDAC;
995 
996 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
997 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
998 			extstat |= AC97_EXT_AUDIO_SPSA34;
999 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
1000 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
1001 			    AC97_SPDIF_SPSR_48K;
1002 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
1003 		}
1004 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
1005 			extstat |= AC97_EXT_AUDIO_VRA;
1006 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1007 	}
1008 
1009 	/* use initfunc for specific device */
1010 	if (as->codec_if.initfunc != NULL)
1011 		as->codec_if.initfunc(as, 1);
1012 
1013 	return (0);
1014 }
1015 
1016 void
1017 ac97_lock(struct ac97_codec_if *codec_if)
1018 {
1019 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1020 	as->lock_counter++;
1021 }
1022 
1023 void
1024 ac97_unlock(struct ac97_codec_if *codec_if)
1025 {
1026 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1027 	as->lock_counter--;
1028 }
1029 
1030 int
1031 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1032 {
1033 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1034 
1035 	if (dip->index < as->num_source_info && dip->index >= 0) {
1036 		struct ac97_source_info *si = &as->source_info[dip->index];
1037 		const char *name;
1038 
1039 		dip->type = si->type;
1040 		dip->mixer_class = si->mixer_class;
1041 		dip->prev = si->prev;
1042 		dip->next = si->next;
1043 
1044 		if (si->qualifier)
1045 			name = si->qualifier;
1046 		else if (si->device)
1047 			name = si->device;
1048 		else if (si->class)
1049 			name = si->class;
1050 		else
1051 			name = NULL;
1052 
1053 		if (name)
1054 			strlcpy(dip->label.name, name, sizeof dip->label.name);
1055 
1056 		bcopy(si->info, &dip->un, si->info_size);
1057 
1058 		/* Set the delta for volume sources */
1059 		if (dip->type == AUDIO_MIXER_VALUE)
1060 			dip->un.v.delta = 1 << (8 - si->bits);
1061 
1062 		return (0);
1063 	}
1064 
1065 	return (ENXIO);
1066 }
1067 
1068 int
1069 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1070 {
1071 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1072 	struct ac97_source_info *si = &as->source_info[cp->dev];
1073 	u_int16_t mask;
1074 	u_int16_t val, newval;
1075 	int error, spdif;
1076 
1077 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
1078 	    cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1079 		return (EINVAL);
1080 
1081 	spdif = si->req_feature == CHECK_SPDIF &&
1082 	    si->reg == AC97_REG_EXT_AUDIO_CTRL;
1083 	if (spdif && as->lock_counter >= 0)
1084 		return EBUSY;
1085 
1086 	ac97_read(as, si->reg, &val);
1087 
1088 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1089 
1090 	mask = (1 << si->bits) - 1;
1091 
1092 	switch (cp->type) {
1093 	case AUDIO_MIXER_ENUM:
1094 		if (cp->un.ord > mask || cp->un.ord < 0)
1095 			return (EINVAL);
1096 
1097 		newval = (cp->un.ord << si->ofs);
1098 		if (si->reg == AC97_REG_RECORD_SELECT) {
1099 			newval |= (newval << (8 + si->ofs));
1100 			mask |= (mask << 8);
1101 			mask = mask << si->ofs;
1102 		} else if (si->reg == AC97_REG_SURR_MASTER) {
1103 			newval = cp->un.ord ? 0x8080 : 0x0000;
1104 			mask = 0x8080;
1105 		} else
1106 			mask = mask << si->ofs;
1107 
1108 		if (si->mute) {
1109 			newval |= newval << 8;
1110 			mask |= mask << 8;
1111 		}
1112 
1113 		break;
1114 	case AUDIO_MIXER_VALUE:
1115 	{
1116 		const struct audio_mixer_value *value = si->info;
1117 		u_int16_t  l, r;
1118 
1119 		if (cp->un.value.num_channels <= 0 ||
1120 		    cp->un.value.num_channels > value->num_channels)
1121 			return (EINVAL);
1122 
1123 		if (cp->un.value.num_channels == 1) {
1124 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1125 		} else {
1126 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1127 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1128 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1129 			} else {
1130 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1131 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1132 			}
1133 		}
1134 
1135 		if (!si->polarity) {
1136 			l = 255 - l;
1137 			r = 255 - r;
1138 		}
1139 
1140 		l >>= 8 - si->bits;
1141 		r >>= 8 - si->bits;
1142 
1143 		newval = ((l & mask) << si->ofs);
1144 		if (value->num_channels == 2) {
1145 			newval |= ((r & mask) << (si->ofs + 8));
1146 			mask |= (mask << 8);
1147 		}
1148 		mask = mask << si->ofs;
1149 		break;
1150 	}
1151 	default:
1152 		return (EINVAL);
1153 	}
1154 
1155 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
1156 	if (error)
1157 		return (error);
1158 
1159 	if (spdif && as->host_if->spdif_event != NULL)
1160 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1161 
1162 	return (0);
1163 }
1164 
1165 
1166 int
1167 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1168 {
1169 	struct ac97_softc *as;
1170 	u_long value;
1171 	u_int16_t ext_stat;
1172 	u_int16_t actual;
1173 	u_int16_t power;
1174 	u_int16_t power_bit;
1175 
1176 	as = (struct ac97_softc *)codec_if;
1177 
1178 	if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
1179 	    !(as->ext_id & AC97_EXT_AUDIO_SDAC))
1180 			return 0;
1181 	if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
1182 	    !(as->ext_id & AC97_EXT_AUDIO_LDAC))
1183 			return 0;
1184 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1185 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1186 			*rate = AC97_SINGLE_RATE;
1187 			return 0;
1188 		}
1189 	} else {
1190 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1191 			*rate = AC97_SINGLE_RATE;
1192 			return 0;
1193 		}
1194 	}
1195 	if (as->ac97_clock == 0)
1196 		as->ac97_clock = AC97_STANDARD_CLOCK;
1197 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1198 	ext_stat = 0;
1199 	/*
1200 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1201 	 *	Check VRA, DRA
1202 	 * PCM_LR_ADC_RATE
1203 	 *	Check VRA
1204 	 * PCM_MIC_ADC_RATE
1205 	 *	Check VRM
1206 	 */
1207 	switch (target) {
1208 	case AC97_REG_PCM_FRONT_DAC_RATE:
1209 	case AC97_REG_PCM_SURR_DAC_RATE:
1210 	case AC97_REG_PCM_LFE_DAC_RATE:
1211 		power_bit = AC97_POWER_OUT;
1212 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1213 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1214 			if (value > 0x1ffff) {
1215 				return EINVAL;
1216 			} else if (value > 0xffff) {
1217 				/* Enable DRA */
1218 				ext_stat |= AC97_EXT_AUDIO_DRA;
1219 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1220 				value /= 2;
1221 			} else {
1222 				/* Disable DRA */
1223 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
1224 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1225 			}
1226 		} else {
1227 			if (value > 0xffff)
1228 				return EINVAL;
1229 		}
1230 		break;
1231 	case AC97_REG_PCM_LR_ADC_RATE:
1232 		power_bit = AC97_POWER_IN;
1233 		if (value > 0xffff)
1234 			return EINVAL;
1235 		break;
1236 	case AC97_REG_PCM_MIC_ADC_RATE:
1237 		power_bit = AC97_POWER_IN;
1238 		if (value > 0xffff)
1239 			return EINVAL;
1240 		break;
1241 	default:
1242 		printf("%s: Unknown register: 0x%x\n", __func__, target);
1243 		return EINVAL;
1244 	}
1245 
1246 	ac97_read(as, AC97_REG_POWER, &power);
1247 	ac97_write(as, AC97_REG_POWER, power | power_bit);
1248 
1249 	ac97_write(as, target, (u_int16_t)value);
1250 	ac97_read(as, target, &actual);
1251 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1252 
1253 	ac97_write(as, AC97_REG_POWER, power);
1254 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
1255 		*rate = actual * 2;
1256 	} else {
1257 		*rate = actual;
1258 	}
1259 	return 0;
1260 }
1261 
1262 void
1263 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1264 {
1265 	struct ac97_softc *as;
1266 
1267 	as = (struct ac97_softc *)codec_if;
1268 	as->ac97_clock = clock;
1269 }
1270 
1271 u_int16_t
1272 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1273 {
1274 	struct ac97_softc *as;
1275 
1276 	as = (struct ac97_softc *)codec_if;
1277 	return as->ext_id;
1278 }
1279 
1280 int
1281 ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src)
1282 {
1283 	struct ac97_source_info *si;
1284 	int ouridx, idx;
1285 
1286 	if (as->num_source_info >= MAX_SOURCES) {
1287 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
1288 		       __func__, __FILE__);
1289 		return -1;
1290 	}
1291 	if (!ac97_check_capability(as, src->req_feature))
1292 		return -1;
1293 	ouridx = as->num_source_info;
1294 	si = &as->source_info[ouridx];
1295 	memcpy(si, src, sizeof(*si));
1296 
1297 	switch (si->type) {
1298 	case AUDIO_MIXER_CLASS:
1299 	case AUDIO_MIXER_VALUE:
1300 		printf("%s: adding class/value is not supported yet.\n",
1301 		       __func__);
1302 		return -1;
1303 	case AUDIO_MIXER_ENUM:
1304 		break;
1305 	default:
1306 		printf("%s: unknown type: %d\n", __func__, si->type);
1307 		return -1;
1308 	}
1309 	as->num_source_info++;
1310 
1311 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1312 						   NULL, NULL);
1313 	/* Find the root of the device */
1314 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1315 				       si->device, NULL);
1316 	/* Find the last item */
1317 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1318 		idx = as->source_info[idx].next;
1319 	/* Append */
1320 	as->source_info[idx].next = ouridx;
1321 	si->prev = idx;
1322 	si->next = AUDIO_MIXER_LAST;
1323 
1324 	return 0;
1325 }
1326 
1327 int
1328 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
1329     char *device, char *qualifier)
1330 {
1331 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1332 	int idx;
1333 
1334 	for (idx = 0; idx < as->num_source_info; idx++) {
1335 		struct ac97_source_info *si = &as->source_info[idx];
1336 		if (ac97_str_equal(class, si->class) &&
1337 		    ac97_str_equal(device, si->device) &&
1338 		    ac97_str_equal(qualifier, si->qualifier))
1339 			return (idx);
1340 	}
1341 
1342 	return (-1);
1343 }
1344 
1345 int
1346 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1347 {
1348 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1349 	struct ac97_source_info *si = &as->source_info[cp->dev];
1350 	u_int16_t mask;
1351 	u_int16_t val;
1352 
1353 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
1354 	    cp->type != si->type)
1355 		return (EINVAL);
1356 
1357 	ac97_read(as, si->reg, &val);
1358 
1359 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1360 
1361 	mask = (1 << si->bits) - 1;
1362 
1363 	switch (cp->type) {
1364 	case AUDIO_MIXER_ENUM:
1365 		cp->un.ord = (val >> si->ofs) & mask;
1366 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
1367 		    mask, cp->un.ord));
1368 		break;
1369 	case AUDIO_MIXER_VALUE:
1370 	{
1371 		const struct audio_mixer_value *value = si->info;
1372 		u_int16_t  l, r;
1373 
1374 		if ((cp->un.value.num_channels <= 0) ||
1375 		    (cp->un.value.num_channels > value->num_channels))
1376 			return (EINVAL);
1377 
1378 		if (value->num_channels == 1)
1379 			l = r = (val >> si->ofs) & mask;
1380 		else {
1381 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1382 				l = (val >> si->ofs) & mask;
1383 				r = (val >> (si->ofs + 8)) & mask;
1384 			} else {
1385 				r = (val >> si->ofs) & mask;
1386 				l = (val >> (si->ofs + 8)) & mask;
1387 			}
1388 		}
1389 
1390 		l <<= 8 - si->bits;
1391 		r <<= 8 - si->bits;
1392 		if (!si->polarity) {
1393 			l = 255 - l;
1394 			r = 255 - r;
1395 		}
1396 
1397 		/*
1398 		 * The EAP driver averages l and r for stereo
1399 		 * channels that are requested in MONO mode. Does this
1400 		 * make sense?
1401 		 */
1402 		if (cp->un.value.num_channels == 1) {
1403 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1404 		} else if (cp->un.value.num_channels == 2) {
1405 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1406 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1407 		}
1408 
1409 		break;
1410 	}
1411 	default:
1412 		return (EINVAL);
1413 	}
1414 
1415 	return (0);
1416 }
1417 
1418 
1419 /*
1420  * Codec-dependent initialization
1421  */
1422 
1423 void
1424 ac97_ad1885_init(struct ac97_softc *as, int resuming)
1425 {
1426 	int i;
1427 
1428 	if (resuming)
1429 		return;
1430 
1431 	for (i = 0; i < as->num_source_info; i++) {
1432 		if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
1433 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1434 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1435 			as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
1436 	}
1437 }
1438 
1439 #define AC97_AD1886_JACK_SENSE	0x72
1440 
1441 void
1442 ac97_ad1886_init(struct ac97_softc *as, int resuming)
1443 {
1444 	ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
1445 }
1446 
1447 void
1448 ac97_ad198x_init(struct ac97_softc *as, int resuming)
1449 {
1450 	int i;
1451 	u_int16_t misc;
1452 
1453 	ac97_read(as, AC97_AD_REG_MISC, &misc);
1454 	ac97_write(as, AC97_AD_REG_MISC,
1455 	    misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
1456 
1457 	if (resuming)
1458 		return;
1459 
1460 	for (i = 0; i < as->num_source_info; i++) {
1461 		if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1462 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1463 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1464 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
1465 	}
1466 }
1467 
1468 void
1469 ac97_alc650_init(struct ac97_softc *as, int resuming)
1470 {
1471 	u_int16_t misc;
1472 
1473 	ac97_read(as, AC97_ALC650_REG_MISC, &misc);
1474 	if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
1475 		misc &= ~AC97_ALC650_MISC_PIN47;
1476 	misc &= ~AC97_ALC650_MISC_VREFDIS;
1477 	ac97_write(as, AC97_ALC650_REG_MISC, misc);
1478 
1479 	if (resuming)
1480 		return;
1481 
1482 	struct ac97_source_info sources[3] = {
1483 		{ AudioCoutputs, AudioNsurround, "lineinjack",
1484 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1485 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1486 		  0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1487 		{ AudioCoutputs, AudioNcenter, "micjack",
1488 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1489 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1490 		  0x0000, 1, 10, 0, 0, CHECK_CENTER },
1491 		{ AudioCoutputs, AudioNlfe, "micjack",
1492 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1493 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1494 		  0x0000, 1, 10, 0, 0, CHECK_LFE }};
1495 
1496 	ac97_add_port(as, &sources[0]);
1497 	ac97_add_port(as, &sources[1]);
1498 	ac97_add_port(as, &sources[2]);
1499 }
1500 
1501 void
1502 ac97_cx20468_init(struct ac97_softc *as, int resuming)
1503 {
1504 	u_int16_t misc;
1505 
1506 	ac97_read(as, AC97_CX_REG_MISC, &misc);
1507 	ac97_write(as, AC97_CX_REG_MISC, misc &
1508 	    ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
1509 }
1510 
1511 void
1512 ac97_vt1616_init(struct ac97_softc *as, int resuming)
1513 {
1514 	u_int16_t reg;
1515 
1516 	if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
1517 		ac97_read(as, AC97_VT_REG_TEST, &reg);
1518 
1519 		/* disable 'hp' mixer controls controlling the surround pins */
1520 		reg &= ~(AC97_VT_LVL);
1521 
1522 		/* disable downmixing */
1523 		reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
1524 
1525 		/* enable DC offset removal */
1526 		reg |= AC97_VT_BPDC;
1527 
1528 		ac97_write(as, AC97_VT_REG_TEST, reg);
1529 	}
1530 }
1531