xref: /openbsd-src/sys/dev/ic/ac97.c (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 /*	$OpenBSD: ac97.c,v 1.84 2018/04/11 04:48:31 ratchov 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 int	ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
341 void	ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
342 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
343 int	ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src);
344 
345 void	ac97_ad1885_init(struct ac97_softc *, int);
346 void	ac97_ad1886_init(struct ac97_softc *, int);
347 void	ac97_ad198x_init(struct ac97_softc *, int);
348 void	ac97_alc650_init(struct ac97_softc *, int);
349 void	ac97_cx20468_init(struct ac97_softc *, int);
350 void	ac97_vt1616_init(struct ac97_softc *, int);
351 
352 struct ac97_codec_if_vtbl ac97civ = {
353 	ac97_mixer_get_port,
354 	ac97_mixer_set_port,
355 	ac97_query_devinfo,
356 	ac97_get_portnum_by_name,
357 	ac97_get_extcaps,
358 	ac97_set_rate,
359 	ac97_set_clock,
360 	ac97_lock,
361 	ac97_unlock
362 };
363 
364 const struct ac97_codecid {
365 	u_int8_t id;
366 	u_int8_t mask;
367 	u_int8_t rev;
368 	u_int8_t shift;	/* no use yet */
369 	char * const name;
370 	void (*init)(struct ac97_softc *, int);
371 }  ac97_ad[] = {
372 	{ 0x03, 0xff, 0, 0,	"AD1819" },
373 	{ 0x40, 0xff, 0, 0,	"AD1881" },
374 	{ 0x48, 0xff, 0, 0,	"AD1881A" },
375 	{ 0x60, 0xff, 0, 0,	"AD1885", 	ac97_ad1885_init },
376 	{ 0x61, 0xff, 0, 0,	"AD1886",	ac97_ad1886_init },
377 	{ 0x63, 0xff, 0, 0,	"AD1886A" },
378 	{ 0x68, 0xff, 0, 0,	"AD1888",	ac97_ad198x_init },
379 	{ 0x70, 0xff, 0, 0,	"AD1980",	ac97_ad198x_init },
380 	{ 0x72, 0xff, 0, 0,	"AD1981A" },
381 	{ 0x74, 0xff, 0, 0,	"AD1981B" },
382 	{ 0x75, 0xff, 0, 0,	"AD1985",	ac97_ad198x_init },
383 }, ac97_ak[] = {
384 	{ 0x00,	0xfe, 1, 0,	"AK4540" },
385 	{ 0x01,	0xfe, 1, 0,	"AK4540" },
386 	{ 0x02,	0xff, 0, 0,	"AK4543" },
387 	{ 0x05,	0xff, 0, 0,	"AK4544" },
388 	{ 0x06,	0xff, 0, 0,	"AK4544A" },
389 	{ 0x07,	0xff, 0, 0,	"AK4545" },
390 }, ac97_av[] = {
391 	{ 0x10, 0xff, 0, 0,	"ALC200" },
392 	{ 0x20, 0xff, 0, 0,	"ALC650" },
393 	{ 0x21, 0xff, 0, 0,	"ALC650D" },
394 	{ 0x22, 0xff, 0, 0,	"ALC650E" },
395 	{ 0x23, 0xff, 0, 0,	"ALC650F" },
396 	{ 0x30, 0xff, 0, 0,	"ALC101" },
397 	{ 0x40, 0xff, 0, 0,	"ALC202" },
398 	{ 0x50, 0xff, 0, 0,	"ALC250" },
399 	{ 0x52, 0xff, 0, 0,	"ALC250A?" },
400 	{ 0x60, 0xf0, 0xf, 0,	"ALC655",	ac97_alc650_init },
401 	{ 0x70, 0xf0, 0xf, 0,	"ALC203" },
402 	{ 0x80, 0xf0, 0xf, 0,	"ALC658",	ac97_alc650_init },
403 	{ 0x90, 0xf0, 0xf, 0,	"ALC850" },
404 }, ac97_rl[] = {
405 	{ 0x00, 0xf0, 0xf, 0,	"RL5306" },
406 	{ 0x10, 0xf0, 0xf, 0,	"RL5382" },
407 	{ 0x20, 0xf0, 0xf, 0,	"RL5383" },
408 }, ac97_cm[] = {
409 	{ 0x41,	0xff, 0, 0,	"CMI9738" },
410 	{ 0x61,	0xff, 0, 0,	"CMI9739" },
411 	{ 0x78,	0xff, 0, 0,	"CMI9761A" },
412 	{ 0x82,	0xff, 0, 0,	"CMI9761B" },
413 	{ 0x83,	0xff, 0, 0,	"CMI9761A+" },
414 }, ac97_cr[] = {
415 	{ 0x84,	0xff, 0, 0,	"EV1938" },
416 }, ac97_cs[] = {
417 	{ 0x00,	0xf8, 7, 0,	"CS4297" },
418 	{ 0x10,	0xf8, 7, 0,	"CS4297A" },
419 	{ 0x20,	0xf8, 7, 0,	"CS4298" },
420 	{ 0x28,	0xf8, 7, 0,	"CS4294" },
421 	{ 0x30,	0xf8, 7, 0,	"CS4299" },
422 	{ 0x48,	0xf8, 7, 0,	"CS4201" },
423 	{ 0x58,	0xf8, 7, 0,	"CS4205" },
424 	{ 0x60,	0xf8, 7, 0,	"CS4291" },
425 	{ 0x70,	0xf8, 7, 0,	"CS4202" },
426 }, ac97_cx[] = {
427 	{ 0x21, 0xff, 0, 0,	"HSD11246" },
428 	{ 0x28, 0xf8, 7, 0,	"CX20468",	ac97_cx20468_init },
429 	{ 0x30, 0xff, 0, 0,	"CXT48", },
430 	{ 0x42, 0xff, 0, 0,	"CXT66", },
431 }, ac97_dt[] = {
432 	{ 0x00, 0xff, 0, 0,	"DT0398" },
433 }, ac97_em[] = {
434 	{ 0x23, 0xff, 0, 0,	"EM28023" },
435 	{ 0x28, 0xff, 0, 0,	"EM28028" },
436 }, ac97_es[] = {
437 	{ 0x08, 0xff, 0, 0,	"ES1921" },
438 }, ac97_is[] = {
439 	{ 0x00, 0xff, 0, 0,	"HMP9701" },
440 }, ac97_ic[] = {
441 	{ 0x01, 0xff, 0, 0,	"ICE1230" },
442 	{ 0x11, 0xff, 0, 0,	"ICE1232" },
443 	{ 0x14, 0xff, 0, 0,	"ICE1232A" },
444 	{ 0x51, 0xff, 0, 0,	"VIA VT1616" },
445 	{ 0x52, 0xff, 0, 0,	"VIA VT1616i",	ac97_vt1616_init },
446 }, ac97_it[] = {
447 	{ 0x20, 0xff, 0, 0,	"ITE2226E" },
448 	{ 0x60, 0xff, 0, 0,	"ITE2646E" },
449 }, ac97_ns[] = {
450 	{ 0x00,	0xff, 0, 0,	"LM454[03568]" },
451 	{ 0x31,	0xff, 0, 0,	"LM4549" },
452 	{ 0x40, 0xff, 0, 0,	"LM4540" },
453 	{ 0x43, 0xff, 0, 0,	"LM4543" },
454 	{ 0x46, 0xff, 0, 0,	"LM4546A" },
455 	{ 0x48, 0xff, 0, 0,	"LM4548A" },
456 	{ 0x49, 0xff, 0, 0,	"LM4549A" },
457 	{ 0x50, 0xff, 0, 0,	"LM4550" },
458 }, ac97_ps[] = {
459 	{ 0x01,	0xff, 0, 0,	"UCB1510" },
460 	{ 0x04,	0xff, 0, 0,	"UCB1400" },
461 }, ac97_sl[] = {
462 	{ 0x20,	0xe0, 0, 0,	"Si3036/38" },
463 }, ac97_st[] = {
464 	{ 0x00,	0xff, 0, 0,	"STAC9700" },
465 	{ 0x04,	0xff, 0, 0,	"STAC970[135]" },
466 	{ 0x05,	0xff, 0, 0,	"STAC9704" },
467 	{ 0x08,	0xff, 0, 0,	"STAC9708/11" },
468 	{ 0x09,	0xff, 0, 0,	"STAC9721/23" },
469 	{ 0x44,	0xff, 0, 0,	"STAC9744/45" },
470 	{ 0x50,	0xff, 0, 0,	"STAC9750/51" },
471 	{ 0x52,	0xff, 0, 0,	"STAC9752/53" },
472 	{ 0x56,	0xff, 0, 0,	"STAC9756/57" },
473 	{ 0x58,	0xff, 0, 0,	"STAC9758/59" },
474 	{ 0x60,	0xff, 0, 0,	"STAC9760/61" },
475 	{ 0x62,	0xff, 0, 0,	"STAC9762/63" },
476 	{ 0x66,	0xff, 0, 0,	"STAC9766/67" },
477 	{ 0x84,	0xff, 0, 0,	"STAC9784/85" },
478 }, ac97_vi[] = {
479 	{ 0x61, 0xff, 0, 0,	"VT1612A" },
480 	{ 0x70, 0xff, 0, 0,	"VT1617" },
481 }, ac97_tt[] = {
482 	{ 0x02,	0xff, 0, 0,	"TR28022" },
483 	{ 0x03,	0xff, 0, 0,	"TR28023" },
484 	{ 0x06,	0xff, 0, 0,	"TR28026" },
485 	{ 0x08,	0xff, 0, 0,	"TR28028" },
486 	{ 0x23,	0xff, 0, 0,	"TR28602" },
487 }, ac97_ti[] = {
488 	{ 0x20, 0xff, 0, 0,	"TLC320AD9xC" },
489 }, ac97_wb[] = {
490 	{ 0x01, 0xff, 0, 0,	"W83971D" },
491 }, ac97_wo[] = {
492 	{ 0x00,	0xff, 0, 0,	"WM9701A" },
493 	{ 0x03,	0xff, 0, 0,	"WM9704M/Q-0" }, /* & WM9703 */
494 	{ 0x04,	0xff, 0, 0,	"WM9704M/Q-1" },
495 	{ 0x05,	0xff, 0, 0,	"WM9705/10" },
496 	{ 0x09,	0xff, 0, 0,	"WM9709" },
497 	{ 0x12,	0xff, 0, 0,	"WM9711/12" },
498 }, ac97_ym[] = {
499 	{ 0x00, 0xff, 0, 0,	"YMF743-S" },
500 	{ 0x02, 0xff, 0, 0,	"YMF752-S" },
501 	{ 0x03, 0xff, 0, 0,	"YMF753-S" },
502 };
503 
504 #define	cl(n)	n, nitems(n)
505 const struct ac97_vendorid {
506 	u_int32_t id;
507 	char * const name;
508 	const struct ac97_codecid * const codecs;
509 	u_int8_t num;
510 } ac97_vendors[] = {
511 	{ 0x01408300, "Creative",		cl(ac97_cr) },
512 	{ 0x41445300, "Analog Devices",		cl(ac97_ad) },
513 	{ 0x414b4D00, "Asahi Kasei",		cl(ac97_ak) },
514 	{ 0x414c4300, "Realtek",		cl(ac97_rl) },
515 	{ 0x414c4700, "Avance Logic",		cl(ac97_av) },
516 	{ 0x434d4900, "C-Media Electronics",	cl(ac97_cm) },
517 	{ 0x43525900, "Cirrus Logic",		cl(ac97_cs) },
518 	{ 0x43585400, "Conexant",		cl(ac97_cx) },
519 	{ 0x44543000, "Diamond Technology",	cl(ac97_dt) },
520 	{ 0x454d4300, "eMicro",			cl(ac97_em) },
521 	{ 0x45838300, "ESS Technology",		cl(ac97_es) },
522 	{ 0x48525300, "Intersil",		cl(ac97_is) },
523 	{ 0x49434500, "ICEnsemble",		cl(ac97_ic) },
524 	{ 0x49544500, "ITE, Inc.",		cl(ac97_it) },
525 	{ 0x4e534300, "National Semiconductor", cl(ac97_ns) },
526 	{ 0x50534300, "Philips Semiconductor",	cl(ac97_ps) },
527 	{ 0x53494c00, "Silicon Laboratory",	cl(ac97_sl) },
528 	{ 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
529 	{ 0x54584e00, "Texas Instruments",	cl(ac97_ti) },
530 	{ 0x56494100, "VIA Technologies",	cl(ac97_vi) },
531 	{ 0x57454300, "Winbond",		cl(ac97_wb) },
532 	{ 0x574d4c00, "Wolfson",		cl(ac97_wo) },
533 	{ 0x594d4800, "Yamaha",			cl(ac97_ym) },
534 	{ 0x83847600, "SigmaTel",		cl(ac97_st) },
535 };
536 #undef cl
537 
538 const char * const ac97enhancement[] = {
539 	"No 3D Stereo",
540 	"Analog Devices Phat Stereo",
541 	"Creative",
542 	"National Semi 3D",
543 	"Yamaha Ymersion",
544 	"BBE 3D",
545 	"Crystal Semi 3D",
546 	"Qsound QXpander",
547 	"Spatializer 3D",
548 	"SRS 3D",
549 	"Platform Tech 3D",
550 	"AKM 3D",
551 	"Aureal",
552 	"AZTECH 3D",
553 	"Binaura 3D",
554 	"ESS Technology",
555 	"Harman International VMAx",
556 	"Nvidea 3D",
557 	"Philips Incredible Sound",
558 	"Texas Instruments 3D",
559 	"VLSI Technology 3D",
560 	"TriTech 3D",
561 	"Realtek 3D",
562 	"Samsung 3D",
563 	"Wolfson Microelectronics 3D",
564 	"Delta Integration 3D",
565 	"SigmaTel 3D",
566 	"KS Waves 3D",
567 	"Rockwell 3D",
568 	"Unknown 3D",
569 	"Unknown 3D",
570 	"Unknown 3D"
571 };
572 
573 const char * const ac97feature[] = {
574 	"mic channel",
575 	"reserved",
576 	"tone",
577 	"simulated stereo",
578 	"headphone",
579 	"bass boost",
580 	"18 bit DAC",
581 	"20 bit DAC",
582 	"18 bit ADC",
583 	"20 bit ADC"
584 };
585 
586 
587 int	ac97_str_equal(const char *, const char *);
588 int	ac97_check_capability(struct ac97_softc *, int);
589 void	ac97_setup_source_info(struct ac97_softc *);
590 void	ac97_setup_defaults(struct ac97_softc *);
591 int	ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
592 int	ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
593 
594 
595 #ifdef AUDIO_DEBUG
596 #define DPRINTF(x)	if (ac97debug) printf x
597 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
598 #ifdef AC97_DEBUG
599 int	ac97debug = 1;
600 #else
601 int	ac97debug = 0;
602 #endif
603 #else
604 #define DPRINTF(x)
605 #define DPRINTFN(n,x)
606 #endif
607 
608 int
609 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
610 {
611 	int error;
612 
613 	if (((as->host_flags & AC97_HOST_DONT_READ) &&
614 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
615 	    reg != AC97_REG_RESET)) ||
616 	    (as->host_flags & AC97_HOST_DONT_READANY)) {
617 		*val = as->shadow_reg[reg >> 1];
618 		return (0);
619 	}
620 
621 	if ((error = as->host_if->read(as->host_if->arg, reg, val)))
622 		*val = as->shadow_reg[reg >> 1];
623 	return (error);
624 }
625 
626 int
627 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
628 {
629 	as->shadow_reg[reg >> 1] = val;
630 	return (as->host_if->write(as->host_if->arg, reg, val));
631 }
632 
633 void
634 ac97_setup_defaults(struct ac97_softc *as)
635 {
636 	int idx;
637 
638 	bzero(as->shadow_reg, sizeof(as->shadow_reg));
639 
640 	for (idx = 0; idx < nitems(source_info); idx++) {
641 		const struct ac97_source_info *si = &source_info[idx];
642 
643 		ac97_write(as, si->reg, si->default_value);
644 	}
645 }
646 
647 int
648 ac97_str_equal(const char *a, const char *b)
649 {
650 	return ((a == b) || (a && b && (!strcmp(a, b))));
651 }
652 
653 int
654 ac97_check_capability(struct ac97_softc *as, int check)
655 {
656 	switch (check) {
657 	case CHECK_NONE:
658 		return 1;
659 	case CHECK_SURROUND:
660 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
661 	case CHECK_CENTER:
662 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
663 	case CHECK_LFE:
664 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
665 	case CHECK_SPDIF:
666 		return as->ext_id & AC97_EXT_AUDIO_SPDIF;
667 	case CHECK_HEADPHONES:
668 		return as->caps & AC97_CAPS_HEADPHONES;
669 	case CHECK_TONE:
670 		return as->caps & AC97_CAPS_TONECTRL;
671 	case CHECK_MIC:
672 		return as->caps & AC97_CAPS_MICIN;
673 	case CHECK_LOUDNESS:
674 		return as->caps & AC97_CAPS_LOUDNESS;
675 	case CHECK_3D:
676 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
677 	default:
678 		printf("%s: internal error: feature=%d\n", __func__, check);
679 		return 0;
680 	}
681 }
682 
683 void
684 ac97_setup_source_info(struct ac97_softc *as)
685 {
686 	struct ac97_source_info *si, *si2;
687 	int idx, ouridx;
688 
689 	for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
690 		si = &as->source_info[ouridx];
691 
692 		if (!ac97_check_capability(as, source_info[idx].req_feature))
693 			continue;
694 
695 		bcopy(&source_info[idx], si, sizeof(*si));
696 
697 		switch (si->type) {
698 		case AUDIO_MIXER_CLASS:
699 			si->mixer_class = ouridx;
700 			ouridx++;
701 			break;
702 		case AUDIO_MIXER_VALUE:
703 			/* Todo - Test to see if it works */
704 			ouridx++;
705 
706 			/* Add an entry for mute, if necessary */
707 			if (si->mute) {
708 				si = &as->source_info[ouridx];
709 				bcopy(&source_info[idx], si, sizeof(*si));
710 				si->qualifier = AudioNmute;
711 				si->type = AUDIO_MIXER_ENUM;
712 				si->info = &ac97_on_off;
713 				si->info_size = sizeof(ac97_on_off);
714 				si->bits = 1;
715 				si->ofs = 15;
716 				si->mute = 0;
717 				si->polarity = 0;
718 				ouridx++;
719 			}
720 			break;
721 		case AUDIO_MIXER_ENUM:
722 			/* Todo - Test to see if it works */
723 			ouridx++;
724 			break;
725 		default:
726 			printf ("ac97: shouldn't get here\n");
727 			break;
728 		}
729 	}
730 
731 	as->num_source_info = ouridx;
732 
733 	for (idx = 0; idx < as->num_source_info; idx++) {
734 		int idx2, previdx;
735 
736 		si = &as->source_info[idx];
737 
738 		/* Find mixer class */
739 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
740 			si2 = &as->source_info[idx2];
741 
742 			if (si2->type == AUDIO_MIXER_CLASS &&
743 			    ac97_str_equal(si->class, si2->class)) {
744 				si->mixer_class = idx2;
745 			}
746 		}
747 
748 
749 		/* Setup prev and next pointers */
750 		if (si->prev != 0 || si->qualifier)
751 			continue;
752 
753 		si->prev = AUDIO_MIXER_LAST;
754 		previdx = idx;
755 
756 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
757 			if (idx2 == idx)
758 				continue;
759 
760 			si2 = &as->source_info[idx2];
761 
762 			if (!si2->prev &&
763 			    ac97_str_equal(si->class, si2->class) &&
764 			    ac97_str_equal(si->device, si2->device)) {
765 				as->source_info[previdx].next = idx2;
766 				as->source_info[idx2].prev = previdx;
767 
768 				previdx = idx2;
769 			}
770 		}
771 
772 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
773 	}
774 }
775 
776 int
777 ac97_attach(struct ac97_host_if *host_if)
778 {
779 	struct ac97_softc *as;
780 	u_int16_t id1, id2, val;
781 	u_int32_t id;
782 	u_int16_t extstat, rate;
783 	mixer_ctrl_t ctl;
784 	int error, i;
785 	void (*initfunc)(struct ac97_softc *, int);
786 
787 	initfunc = NULL;
788 
789 	if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
790 		return (ENOMEM);
791 
792 	as->codec_if.as = as;
793 	as->codec_if.vtbl = &ac97civ;
794 	as->host_if = host_if;
795 
796 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
797 		free(as, M_DEVBUF, sizeof(*as));
798 		return (error);
799 	}
800 
801 	host_if->reset(host_if->arg);
802 	DELAY(1000);
803 
804 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
805 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
806 	DELAY(10000);
807 
808 	if (host_if->flags)
809 		as->host_flags = host_if->flags(host_if->arg);
810 
811 	ac97_setup_defaults(as);
812 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
813 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
814 	ac97_read(as, AC97_REG_RESET, &as->caps);
815 
816 	id = (id1 << 16) | id2;
817 	if (id) {
818 		register const struct ac97_vendorid *vendor;
819 		register const struct ac97_codecid *codec;
820 
821 		printf("ac97: codec id 0x%08x", id);
822 		for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
823 		     sizeof(ac97_vendors[0]) - 1];
824 		     vendor >= ac97_vendors; vendor--) {
825 			if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
826 				printf(" (%s", vendor->name);
827 				for (codec = &vendor->codecs[vendor->num-1];
828 				     codec >= vendor->codecs; codec--) {
829 					if (codec->id == (id & codec->mask))
830 						break;
831 				}
832 				if (codec >= vendor->codecs && codec->mask) {
833 					printf(" %s", codec->name);
834 					initfunc = codec->init;
835 				} else
836 					printf(" <%02x>", id & 0xff);
837 				if (codec >= vendor->codecs && codec->rev)
838 					printf(" rev %d", id & codec->rev);
839 				printf(")");
840 				break;
841 			}
842 		}
843 		printf("\n");
844 	} else
845 		printf("ac97: codec id not read\n");
846 
847 	if (as->caps) {
848 		printf("ac97: codec features ");
849 		for (i = 0; i < 10; i++) {
850 			if (as->caps & (1 << i))
851 				printf("%s, ", ac97feature[i]);
852 		}
853 		printf("%s\n",
854 		    ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
855 	}
856 
857 
858 	as->ac97_clock = AC97_STANDARD_CLOCK;
859 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
860 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
861 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
862 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
863 			  | AC97_EXT_AUDIO_LDAC)) {
864 
865 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
866 		extstat &= ~AC97_EXT_AUDIO_DRA;
867 
868 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
869 			extstat |= AC97_EXT_AUDIO_VRM;
870 
871 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
872 			extstat |= AC97_EXT_AUDIO_LDAC;
873 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
874 			extstat |= AC97_EXT_AUDIO_SDAC;
875 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
876 			extstat |= AC97_EXT_AUDIO_CDAC;
877 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
878 			/* XXX S/PDIF gets same data as DAC?
879 			 * maybe this should be settable?
880 			 * default is SPSAAB (10/11) on AD1980 and ALC codecs.
881 			 */
882 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
883 			extstat |= AC97_EXT_AUDIO_SPSA34;
884 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
885 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
886 			    AC97_SPDIF_SPSR_48K;
887 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
888 		}
889 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
890 			extstat |= AC97_EXT_AUDIO_VRA;
891 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
892 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
893 			/* VRA should be enabled. */
894 			/* so it claims to do variable rate, let's make sure */
895 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
896 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
897 			if (rate != 44100) {
898 				/* We can't believe ext_id */
899 				as->ext_id = 0;
900 			}
901 			/* restore the default value */
902 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
903 				   AC97_SINGLE_RATE);
904 		}
905 	}
906 
907 	ac97_setup_source_info(as);
908 
909 	DELAY(900 * 1000);
910 
911 	/* use initfunc for specific device */
912 	as->codec_if.initfunc = initfunc;
913 	if (initfunc != NULL)
914 		initfunc(as, 0);
915 
916 	/* Just enable the DAC and master volumes by default */
917 	bzero(&ctl, sizeof(ctl));
918 
919 	ctl.type = AUDIO_MIXER_ENUM;
920 	ctl.un.ord = 0;  /* off */
921 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
922 	    AudioNmaster, AudioNmute);
923 	ac97_mixer_set_port(&as->codec_if, &ctl);
924 
925 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
926 	    AudioNdac, AudioNmute);
927 	ac97_mixer_set_port(&as->codec_if, &ctl);
928 
929 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
930 	    AudioNvolume, AudioNmute);
931 	ac97_mixer_set_port(&as->codec_if, &ctl);
932 
933 	ctl.type = AUDIO_MIXER_ENUM;
934 	ctl.un.ord = 0;
935 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
936 	    AudioNsource, NULL);
937 	ac97_mixer_set_port(&as->codec_if, &ctl);
938 
939 	return (0);
940 }
941 
942 int
943 ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
944 {
945 	struct ac97_softc *as = codec_if->as;
946 	u_int16_t val, extstat;
947 
948 	host_if->reset(host_if->arg);
949 	DELAY(1000);
950 
951 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
952 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
953 	DELAY(10000);
954 
955 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
956 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
957 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
958 			  | AC97_EXT_AUDIO_LDAC)) {
959 
960 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
961 		extstat &= ~AC97_EXT_AUDIO_DRA;
962 
963 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
964 			extstat |= AC97_EXT_AUDIO_VRM;
965 
966 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
967 			extstat |= AC97_EXT_AUDIO_LDAC;
968 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
969 			extstat |= AC97_EXT_AUDIO_SDAC;
970 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
971 			extstat |= AC97_EXT_AUDIO_CDAC;
972 
973 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
974 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
975 			extstat |= AC97_EXT_AUDIO_SPSA34;
976 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
977 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
978 			    AC97_SPDIF_SPSR_48K;
979 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
980 		}
981 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
982 			extstat |= AC97_EXT_AUDIO_VRA;
983 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
984 	}
985 
986 	/* use initfunc for specific device */
987 	if (as->codec_if.initfunc != NULL)
988 		as->codec_if.initfunc(as, 1);
989 
990 	return (0);
991 }
992 
993 void
994 ac97_lock(struct ac97_codec_if *codec_if)
995 {
996 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
997 	as->lock_counter++;
998 }
999 
1000 void
1001 ac97_unlock(struct ac97_codec_if *codec_if)
1002 {
1003 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1004 	as->lock_counter--;
1005 }
1006 
1007 int
1008 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1009 {
1010 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1011 
1012 	if (dip->index < as->num_source_info && dip->index >= 0) {
1013 		struct ac97_source_info *si = &as->source_info[dip->index];
1014 		const char *name;
1015 
1016 		dip->type = si->type;
1017 		dip->mixer_class = si->mixer_class;
1018 		dip->prev = si->prev;
1019 		dip->next = si->next;
1020 
1021 		if (si->qualifier)
1022 			name = si->qualifier;
1023 		else if (si->device)
1024 			name = si->device;
1025 		else if (si->class)
1026 			name = si->class;
1027 		else
1028 			name = NULL;
1029 
1030 		if (name)
1031 			strlcpy(dip->label.name, name, sizeof dip->label.name);
1032 
1033 		bcopy(si->info, &dip->un, si->info_size);
1034 
1035 		/* Set the delta for volume sources */
1036 		if (dip->type == AUDIO_MIXER_VALUE)
1037 			dip->un.v.delta = 1 << (8 - si->bits);
1038 
1039 		return (0);
1040 	}
1041 
1042 	return (ENXIO);
1043 }
1044 
1045 int
1046 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1047 {
1048 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1049 	struct ac97_source_info *si;
1050 	u_int16_t mask;
1051 	u_int16_t val, newval;
1052 	int error, spdif;
1053 
1054 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
1055 		return (EINVAL);
1056 
1057 	si = &as->source_info[cp->dev];
1058 
1059 	if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1060 		return (EINVAL);
1061 
1062 	spdif = si->req_feature == CHECK_SPDIF &&
1063 	    si->reg == AC97_REG_EXT_AUDIO_CTRL;
1064 	if (spdif && as->lock_counter >= 0)
1065 		return EBUSY;
1066 
1067 	ac97_read(as, si->reg, &val);
1068 
1069 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1070 
1071 	mask = (1 << si->bits) - 1;
1072 
1073 	switch (cp->type) {
1074 	case AUDIO_MIXER_ENUM:
1075 		if (cp->un.ord > mask || cp->un.ord < 0)
1076 			return (EINVAL);
1077 
1078 		newval = (cp->un.ord << si->ofs);
1079 		if (si->reg == AC97_REG_RECORD_SELECT) {
1080 			newval |= (newval << (8 + si->ofs));
1081 			mask |= (mask << 8);
1082 			mask = mask << si->ofs;
1083 		} else if (si->reg == AC97_REG_SURR_MASTER) {
1084 			newval = cp->un.ord ? 0x8080 : 0x0000;
1085 			mask = 0x8080;
1086 		} else
1087 			mask = mask << si->ofs;
1088 
1089 		if (si->mute) {
1090 			newval |= newval << 8;
1091 			mask |= mask << 8;
1092 		}
1093 
1094 		break;
1095 	case AUDIO_MIXER_VALUE:
1096 	{
1097 		const struct audio_mixer_value *value = si->info;
1098 		u_int16_t  l, r;
1099 
1100 		if (cp->un.value.num_channels <= 0 ||
1101 		    cp->un.value.num_channels > value->num_channels)
1102 			return (EINVAL);
1103 
1104 		if (cp->un.value.num_channels == 1) {
1105 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1106 		} else {
1107 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1108 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1109 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1110 			} else {
1111 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1112 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1113 			}
1114 		}
1115 
1116 		if (!si->polarity) {
1117 			l = 255 - l;
1118 			r = 255 - r;
1119 		}
1120 
1121 		l >>= 8 - si->bits;
1122 		r >>= 8 - si->bits;
1123 
1124 		newval = ((l & mask) << si->ofs);
1125 		if (value->num_channels == 2) {
1126 			newval |= ((r & mask) << (si->ofs + 8));
1127 			mask |= (mask << 8);
1128 		}
1129 		mask = mask << si->ofs;
1130 		break;
1131 	}
1132 	default:
1133 		return (EINVAL);
1134 	}
1135 
1136 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
1137 	if (error)
1138 		return (error);
1139 
1140 	if (spdif && as->host_if->spdif_event != NULL)
1141 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1142 
1143 	return (0);
1144 }
1145 
1146 
1147 int
1148 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1149 {
1150 	struct ac97_softc *as;
1151 	u_long value;
1152 	u_int16_t ext_stat;
1153 	u_int16_t actual;
1154 	u_int16_t power;
1155 	u_int16_t power_bit;
1156 
1157 	as = (struct ac97_softc *)codec_if;
1158 
1159 	if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
1160 	    !(as->ext_id & AC97_EXT_AUDIO_SDAC))
1161 			return 0;
1162 	if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
1163 	    !(as->ext_id & AC97_EXT_AUDIO_LDAC))
1164 			return 0;
1165 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1166 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1167 			*rate = AC97_SINGLE_RATE;
1168 			return 0;
1169 		}
1170 	} else {
1171 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1172 			*rate = AC97_SINGLE_RATE;
1173 			return 0;
1174 		}
1175 	}
1176 	if (as->ac97_clock == 0)
1177 		as->ac97_clock = AC97_STANDARD_CLOCK;
1178 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1179 	ext_stat = 0;
1180 	/*
1181 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1182 	 *	Check VRA, DRA
1183 	 * PCM_LR_ADC_RATE
1184 	 *	Check VRA
1185 	 * PCM_MIC_ADC_RATE
1186 	 *	Check VRM
1187 	 */
1188 	switch (target) {
1189 	case AC97_REG_PCM_FRONT_DAC_RATE:
1190 	case AC97_REG_PCM_SURR_DAC_RATE:
1191 	case AC97_REG_PCM_LFE_DAC_RATE:
1192 		power_bit = AC97_POWER_OUT;
1193 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1194 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1195 			if (value > 0x1ffff) {
1196 				return EINVAL;
1197 			} else if (value > 0xffff) {
1198 				/* Enable DRA */
1199 				ext_stat |= AC97_EXT_AUDIO_DRA;
1200 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1201 				value /= 2;
1202 			} else {
1203 				/* Disable DRA */
1204 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
1205 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1206 			}
1207 		} else {
1208 			if (value > 0xffff)
1209 				return EINVAL;
1210 		}
1211 		break;
1212 	case AC97_REG_PCM_LR_ADC_RATE:
1213 		power_bit = AC97_POWER_IN;
1214 		if (value > 0xffff)
1215 			return EINVAL;
1216 		break;
1217 	case AC97_REG_PCM_MIC_ADC_RATE:
1218 		power_bit = AC97_POWER_IN;
1219 		if (value > 0xffff)
1220 			return EINVAL;
1221 		break;
1222 	default:
1223 		printf("%s: Unknown register: 0x%x\n", __func__, target);
1224 		return EINVAL;
1225 	}
1226 
1227 	ac97_read(as, AC97_REG_POWER, &power);
1228 	ac97_write(as, AC97_REG_POWER, power | power_bit);
1229 
1230 	ac97_write(as, target, (u_int16_t)value);
1231 	ac97_read(as, target, &actual);
1232 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1233 
1234 	ac97_write(as, AC97_REG_POWER, power);
1235 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
1236 		*rate = actual * 2;
1237 	} else {
1238 		*rate = actual;
1239 	}
1240 	return 0;
1241 }
1242 
1243 void
1244 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1245 {
1246 	struct ac97_softc *as;
1247 
1248 	as = (struct ac97_softc *)codec_if;
1249 	as->ac97_clock = clock;
1250 }
1251 
1252 u_int16_t
1253 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1254 {
1255 	struct ac97_softc *as;
1256 
1257 	as = (struct ac97_softc *)codec_if;
1258 	return as->ext_id;
1259 }
1260 
1261 int
1262 ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src)
1263 {
1264 	struct ac97_source_info *si;
1265 	int ouridx, idx;
1266 
1267 	if (as->num_source_info >= MAX_SOURCES) {
1268 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
1269 		       __func__, __FILE__);
1270 		return -1;
1271 	}
1272 	if (!ac97_check_capability(as, src->req_feature))
1273 		return -1;
1274 	ouridx = as->num_source_info;
1275 	si = &as->source_info[ouridx];
1276 	memcpy(si, src, sizeof(*si));
1277 
1278 	switch (si->type) {
1279 	case AUDIO_MIXER_CLASS:
1280 	case AUDIO_MIXER_VALUE:
1281 		printf("%s: adding class/value is not supported yet.\n",
1282 		       __func__);
1283 		return -1;
1284 	case AUDIO_MIXER_ENUM:
1285 		break;
1286 	default:
1287 		printf("%s: unknown type: %d\n", __func__, si->type);
1288 		return -1;
1289 	}
1290 	as->num_source_info++;
1291 
1292 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1293 						   NULL, NULL);
1294 	/* Find the root of the device */
1295 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1296 				       si->device, NULL);
1297 	/* Find the last item */
1298 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1299 		idx = as->source_info[idx].next;
1300 	/* Append */
1301 	as->source_info[idx].next = ouridx;
1302 	si->prev = idx;
1303 	si->next = AUDIO_MIXER_LAST;
1304 
1305 	return 0;
1306 }
1307 
1308 int
1309 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
1310     char *device, char *qualifier)
1311 {
1312 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1313 	int idx;
1314 
1315 	for (idx = 0; idx < as->num_source_info; idx++) {
1316 		struct ac97_source_info *si = &as->source_info[idx];
1317 		if (ac97_str_equal(class, si->class) &&
1318 		    ac97_str_equal(device, si->device) &&
1319 		    ac97_str_equal(qualifier, si->qualifier))
1320 			return (idx);
1321 	}
1322 
1323 	return (-1);
1324 }
1325 
1326 int
1327 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1328 {
1329 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1330 	struct ac97_source_info *si;
1331 	u_int16_t mask;
1332 	u_int16_t val;
1333 
1334 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
1335 		return (EINVAL);
1336 
1337 	si = &as->source_info[cp->dev];
1338 
1339 	if (cp->type != si->type)
1340 		return (EINVAL);
1341 
1342 	ac97_read(as, si->reg, &val);
1343 
1344 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1345 
1346 	mask = (1 << si->bits) - 1;
1347 
1348 	switch (cp->type) {
1349 	case AUDIO_MIXER_ENUM:
1350 		cp->un.ord = (val >> si->ofs) & mask;
1351 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
1352 		    mask, cp->un.ord));
1353 		break;
1354 	case AUDIO_MIXER_VALUE:
1355 	{
1356 		const struct audio_mixer_value *value = si->info;
1357 		u_int16_t  l, r;
1358 
1359 		if ((cp->un.value.num_channels <= 0) ||
1360 		    (cp->un.value.num_channels > value->num_channels))
1361 			return (EINVAL);
1362 
1363 		if (value->num_channels == 1)
1364 			l = r = (val >> si->ofs) & mask;
1365 		else {
1366 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1367 				l = (val >> si->ofs) & mask;
1368 				r = (val >> (si->ofs + 8)) & mask;
1369 			} else {
1370 				r = (val >> si->ofs) & mask;
1371 				l = (val >> (si->ofs + 8)) & mask;
1372 			}
1373 		}
1374 
1375 		l <<= 8 - si->bits;
1376 		r <<= 8 - si->bits;
1377 		if (!si->polarity) {
1378 			l = 255 - l;
1379 			r = 255 - r;
1380 		}
1381 
1382 		/*
1383 		 * The EAP driver averages l and r for stereo
1384 		 * channels that are requested in MONO mode. Does this
1385 		 * make sense?
1386 		 */
1387 		if (cp->un.value.num_channels == 1) {
1388 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1389 		} else if (cp->un.value.num_channels == 2) {
1390 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1391 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1392 		}
1393 
1394 		break;
1395 	}
1396 	default:
1397 		return (EINVAL);
1398 	}
1399 
1400 	return (0);
1401 }
1402 
1403 
1404 /*
1405  * Codec-dependent initialization
1406  */
1407 
1408 void
1409 ac97_ad1885_init(struct ac97_softc *as, int resuming)
1410 {
1411 	int i;
1412 
1413 	if (resuming)
1414 		return;
1415 
1416 	for (i = 0; i < as->num_source_info; i++) {
1417 		if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
1418 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1419 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1420 			as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
1421 	}
1422 }
1423 
1424 #define AC97_AD1886_JACK_SENSE	0x72
1425 
1426 void
1427 ac97_ad1886_init(struct ac97_softc *as, int resuming)
1428 {
1429 	ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
1430 }
1431 
1432 void
1433 ac97_ad198x_init(struct ac97_softc *as, int resuming)
1434 {
1435 	int i;
1436 	u_int16_t misc;
1437 
1438 	ac97_read(as, AC97_AD_REG_MISC, &misc);
1439 	ac97_write(as, AC97_AD_REG_MISC,
1440 	    misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
1441 
1442 	if (resuming)
1443 		return;
1444 
1445 	for (i = 0; i < as->num_source_info; i++) {
1446 		if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1447 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1448 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1449 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
1450 	}
1451 }
1452 
1453 void
1454 ac97_alc650_init(struct ac97_softc *as, int resuming)
1455 {
1456 	u_int16_t misc;
1457 
1458 	ac97_read(as, AC97_ALC650_REG_MISC, &misc);
1459 	if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
1460 		misc &= ~AC97_ALC650_MISC_PIN47;
1461 	misc &= ~AC97_ALC650_MISC_VREFDIS;
1462 	ac97_write(as, AC97_ALC650_REG_MISC, misc);
1463 
1464 	if (resuming)
1465 		return;
1466 
1467 	struct ac97_source_info sources[3] = {
1468 		{ AudioCoutputs, AudioNsurround, "lineinjack",
1469 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1470 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1471 		  0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1472 		{ AudioCoutputs, AudioNcenter, "micjack",
1473 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1474 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1475 		  0x0000, 1, 10, 0, 0, CHECK_CENTER },
1476 		{ AudioCoutputs, AudioNlfe, "micjack",
1477 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1478 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1479 		  0x0000, 1, 10, 0, 0, CHECK_LFE }};
1480 
1481 	ac97_add_port(as, &sources[0]);
1482 	ac97_add_port(as, &sources[1]);
1483 	ac97_add_port(as, &sources[2]);
1484 }
1485 
1486 void
1487 ac97_cx20468_init(struct ac97_softc *as, int resuming)
1488 {
1489 	u_int16_t misc;
1490 
1491 	ac97_read(as, AC97_CX_REG_MISC, &misc);
1492 	ac97_write(as, AC97_CX_REG_MISC, misc &
1493 	    ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
1494 }
1495 
1496 void
1497 ac97_vt1616_init(struct ac97_softc *as, int resuming)
1498 {
1499 	u_int16_t reg;
1500 
1501 	if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
1502 		ac97_read(as, AC97_VT_REG_TEST, &reg);
1503 
1504 		/* disable 'hp' mixer controls controlling the surround pins */
1505 		reg &= ~(AC97_VT_LVL);
1506 
1507 		/* disable downmixing */
1508 		reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
1509 
1510 		/* enable DC offset removal */
1511 		reg |= AC97_VT_BPDC;
1512 
1513 		ac97_write(as, AC97_VT_REG_TEST, reg);
1514 	}
1515 }
1516