xref: /openbsd-src/sys/dev/ic/ac97.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: ac97.c,v 1.82 2016/09/14 06:12:19 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 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 int
611 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
612 {
613 	int error;
614 
615 	if (((as->host_flags & AC97_HOST_DONT_READ) &&
616 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
617 	    reg != AC97_REG_RESET)) ||
618 	    (as->host_flags & AC97_HOST_DONT_READANY)) {
619 		*val = as->shadow_reg[reg >> 1];
620 		return (0);
621 	}
622 
623 	if ((error = as->host_if->read(as->host_if->arg, reg, val)))
624 		*val = as->shadow_reg[reg >> 1];
625 	return (error);
626 }
627 
628 int
629 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
630 {
631 	as->shadow_reg[reg >> 1] = val;
632 	return (as->host_if->write(as->host_if->arg, reg, val));
633 }
634 
635 void
636 ac97_setup_defaults(struct ac97_softc *as)
637 {
638 	int idx;
639 
640 	bzero(as->shadow_reg, sizeof(as->shadow_reg));
641 
642 	for (idx = 0; idx < nitems(source_info); idx++) {
643 		const struct ac97_source_info *si = &source_info[idx];
644 
645 		ac97_write(as, si->reg, si->default_value);
646 	}
647 }
648 
649 void
650 ac97_restore_shadow(struct ac97_codec_if *self)
651 {
652 	struct ac97_softc *as = (struct ac97_softc *)self;
653 	int idx;
654 
655 	for (idx = 0; idx < nitems(source_info); idx++) {
656 		const struct ac97_source_info *si = &source_info[idx];
657 
658 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
659 	}
660 }
661 
662 int
663 ac97_str_equal(const char *a, const char *b)
664 {
665 	return ((a == b) || (a && b && (!strcmp(a, b))));
666 }
667 
668 int
669 ac97_check_capability(struct ac97_softc *as, int check)
670 {
671 	switch (check) {
672 	case CHECK_NONE:
673 		return 1;
674 	case CHECK_SURROUND:
675 		return as->ext_id & AC97_EXT_AUDIO_SDAC;
676 	case CHECK_CENTER:
677 		return as->ext_id & AC97_EXT_AUDIO_CDAC;
678 	case CHECK_LFE:
679 		return as->ext_id & AC97_EXT_AUDIO_LDAC;
680 	case CHECK_SPDIF:
681 		return as->ext_id & AC97_EXT_AUDIO_SPDIF;
682 	case CHECK_HEADPHONES:
683 		return as->caps & AC97_CAPS_HEADPHONES;
684 	case CHECK_TONE:
685 		return as->caps & AC97_CAPS_TONECTRL;
686 	case CHECK_MIC:
687 		return as->caps & AC97_CAPS_MICIN;
688 	case CHECK_LOUDNESS:
689 		return as->caps & AC97_CAPS_LOUDNESS;
690 	case CHECK_3D:
691 		return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
692 	default:
693 		printf("%s: internal error: feature=%d\n", __func__, check);
694 		return 0;
695 	}
696 }
697 
698 void
699 ac97_setup_source_info(struct ac97_softc *as)
700 {
701 	struct ac97_source_info *si, *si2;
702 	int idx, ouridx;
703 
704 	for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
705 		si = &as->source_info[ouridx];
706 
707 		if (!ac97_check_capability(as, source_info[idx].req_feature))
708 			continue;
709 
710 		bcopy(&source_info[idx], si, sizeof(*si));
711 
712 		switch (si->type) {
713 		case AUDIO_MIXER_CLASS:
714 			si->mixer_class = ouridx;
715 			ouridx++;
716 			break;
717 		case AUDIO_MIXER_VALUE:
718 			/* Todo - Test to see if it works */
719 			ouridx++;
720 
721 			/* Add an entry for mute, if necessary */
722 			if (si->mute) {
723 				si = &as->source_info[ouridx];
724 				bcopy(&source_info[idx], si, sizeof(*si));
725 				si->qualifier = AudioNmute;
726 				si->type = AUDIO_MIXER_ENUM;
727 				si->info = &ac97_on_off;
728 				si->info_size = sizeof(ac97_on_off);
729 				si->bits = 1;
730 				si->ofs = 15;
731 				si->mute = 0;
732 				si->polarity = 0;
733 				ouridx++;
734 			}
735 			break;
736 		case AUDIO_MIXER_ENUM:
737 			/* Todo - Test to see if it works */
738 			ouridx++;
739 			break;
740 		default:
741 			printf ("ac97: shouldn't get here\n");
742 			break;
743 		}
744 	}
745 
746 	as->num_source_info = ouridx;
747 
748 	for (idx = 0; idx < as->num_source_info; idx++) {
749 		int idx2, previdx;
750 
751 		si = &as->source_info[idx];
752 
753 		/* Find mixer class */
754 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
755 			si2 = &as->source_info[idx2];
756 
757 			if (si2->type == AUDIO_MIXER_CLASS &&
758 			    ac97_str_equal(si->class, si2->class)) {
759 				si->mixer_class = idx2;
760 			}
761 		}
762 
763 
764 		/* Setup prev and next pointers */
765 		if (si->prev != 0 || si->qualifier)
766 			continue;
767 
768 		si->prev = AUDIO_MIXER_LAST;
769 		previdx = idx;
770 
771 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
772 			if (idx2 == idx)
773 				continue;
774 
775 			si2 = &as->source_info[idx2];
776 
777 			if (!si2->prev &&
778 			    ac97_str_equal(si->class, si2->class) &&
779 			    ac97_str_equal(si->device, si2->device)) {
780 				as->source_info[previdx].next = idx2;
781 				as->source_info[idx2].prev = previdx;
782 
783 				previdx = idx2;
784 			}
785 		}
786 
787 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
788 	}
789 }
790 
791 int
792 ac97_attach(struct ac97_host_if *host_if)
793 {
794 	struct ac97_softc *as;
795 	u_int16_t id1, id2, val;
796 	u_int32_t id;
797 	u_int16_t extstat, rate;
798 	mixer_ctrl_t ctl;
799 	int error, i;
800 	void (*initfunc)(struct ac97_softc *, int);
801 
802 	initfunc = NULL;
803 
804 	if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
805 		return (ENOMEM);
806 
807 	as->codec_if.as = as;
808 	as->codec_if.vtbl = &ac97civ;
809 	as->host_if = host_if;
810 
811 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
812 		free(as, M_DEVBUF, sizeof(*as));
813 		return (error);
814 	}
815 
816 	host_if->reset(host_if->arg);
817 	DELAY(1000);
818 
819 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
820 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
821 	DELAY(10000);
822 
823 	if (host_if->flags)
824 		as->host_flags = host_if->flags(host_if->arg);
825 
826 	ac97_setup_defaults(as);
827 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
828 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
829 	ac97_read(as, AC97_REG_RESET, &as->caps);
830 
831 	id = (id1 << 16) | id2;
832 	if (id) {
833 		register const struct ac97_vendorid *vendor;
834 		register const struct ac97_codecid *codec;
835 
836 		printf("ac97: codec id 0x%08x", id);
837 		for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
838 		     sizeof(ac97_vendors[0]) - 1];
839 		     vendor >= ac97_vendors; vendor--) {
840 			if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
841 				printf(" (%s", vendor->name);
842 				for (codec = &vendor->codecs[vendor->num-1];
843 				     codec >= vendor->codecs; codec--) {
844 					if (codec->id == (id & codec->mask))
845 						break;
846 				}
847 				if (codec >= vendor->codecs && codec->mask) {
848 					printf(" %s", codec->name);
849 					initfunc = codec->init;
850 				} else
851 					printf(" <%02x>", id & 0xff);
852 				if (codec >= vendor->codecs && codec->rev)
853 					printf(" rev %d", id & codec->rev);
854 				printf(")");
855 				break;
856 			}
857 		}
858 		printf("\n");
859 	} else
860 		printf("ac97: codec id not read\n");
861 
862 	if (as->caps) {
863 		printf("ac97: codec features ");
864 		for (i = 0; i < 10; i++) {
865 			if (as->caps & (1 << i))
866 				printf("%s, ", ac97feature[i]);
867 		}
868 		printf("%s\n",
869 		    ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
870 	}
871 
872 
873 	as->ac97_clock = AC97_STANDARD_CLOCK;
874 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
875 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
876 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
877 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
878 			  | AC97_EXT_AUDIO_LDAC)) {
879 
880 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
881 		extstat &= ~AC97_EXT_AUDIO_DRA;
882 
883 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
884 			extstat |= AC97_EXT_AUDIO_VRM;
885 
886 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
887 			extstat |= AC97_EXT_AUDIO_LDAC;
888 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
889 			extstat |= AC97_EXT_AUDIO_SDAC;
890 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
891 			extstat |= AC97_EXT_AUDIO_CDAC;
892 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
893 			/* XXX S/PDIF gets same data as DAC?
894 			 * maybe this should be settable?
895 			 * default is SPSAAB (10/11) on AD1980 and ALC codecs.
896 			 */
897 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
898 			extstat |= AC97_EXT_AUDIO_SPSA34;
899 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
900 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
901 			    AC97_SPDIF_SPSR_48K;
902 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
903 		}
904 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
905 			extstat |= AC97_EXT_AUDIO_VRA;
906 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
907 		if (as->ext_id & AC97_EXT_AUDIO_VRA) {
908 			/* VRA should be enabled. */
909 			/* so it claims to do variable rate, let's make sure */
910 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
911 			ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
912 			if (rate != 44100) {
913 				/* We can't believe ext_id */
914 				as->ext_id = 0;
915 			}
916 			/* restore the default value */
917 			ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
918 				   AC97_SINGLE_RATE);
919 		}
920 	}
921 
922 	ac97_setup_source_info(as);
923 
924 	DELAY(900 * 1000);
925 
926 	/* use initfunc for specific device */
927 	as->codec_if.initfunc = initfunc;
928 	if (initfunc != NULL)
929 		initfunc(as, 0);
930 
931 	/* Just enable the DAC and master volumes by default */
932 	bzero(&ctl, sizeof(ctl));
933 
934 	ctl.type = AUDIO_MIXER_ENUM;
935 	ctl.un.ord = 0;  /* off */
936 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
937 	    AudioNmaster, AudioNmute);
938 	ac97_mixer_set_port(&as->codec_if, &ctl);
939 
940 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
941 	    AudioNdac, AudioNmute);
942 	ac97_mixer_set_port(&as->codec_if, &ctl);
943 
944 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
945 	    AudioNvolume, AudioNmute);
946 	ac97_mixer_set_port(&as->codec_if, &ctl);
947 
948 	ctl.type = AUDIO_MIXER_ENUM;
949 	ctl.un.ord = 0;
950 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
951 	    AudioNsource, NULL);
952 	ac97_mixer_set_port(&as->codec_if, &ctl);
953 
954 	return (0);
955 }
956 
957 int
958 ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
959 {
960 	struct ac97_softc *as = codec_if->as;
961 	u_int16_t val, extstat;
962 
963 	host_if->reset(host_if->arg);
964 	DELAY(1000);
965 
966 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
967 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
968 	DELAY(10000);
969 
970 	codec_if->vtbl->restore_ports(codec_if);
971 
972 	if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
973 			  | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
974 			  | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
975 			  | AC97_EXT_AUDIO_LDAC)) {
976 
977 		ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
978 		extstat &= ~AC97_EXT_AUDIO_DRA;
979 
980 		if (as->ext_id & AC97_EXT_AUDIO_VRM)
981 			extstat |= AC97_EXT_AUDIO_VRM;
982 
983 		if (as->ext_id & AC97_EXT_AUDIO_LDAC)
984 			extstat |= AC97_EXT_AUDIO_LDAC;
985 		if (as->ext_id & AC97_EXT_AUDIO_SDAC)
986 			extstat |= AC97_EXT_AUDIO_SDAC;
987 		if (as->ext_id & AC97_EXT_AUDIO_CDAC)
988 			extstat |= AC97_EXT_AUDIO_CDAC;
989 
990 		if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
991 			extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
992 			extstat |= AC97_EXT_AUDIO_SPSA34;
993 			ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
994 			val = (val & ~AC97_SPDIF_SPSR_MASK) |
995 			    AC97_SPDIF_SPSR_48K;
996 			ac97_write(as, AC97_REG_SPDIF_CTRL, val);
997 		}
998 		if (as->ext_id & AC97_EXT_AUDIO_VRA)
999 			extstat |= AC97_EXT_AUDIO_VRA;
1000 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1001 	}
1002 
1003 	/* use initfunc for specific device */
1004 	if (as->codec_if.initfunc != NULL)
1005 		as->codec_if.initfunc(as, 1);
1006 
1007 	return (0);
1008 }
1009 
1010 void
1011 ac97_lock(struct ac97_codec_if *codec_if)
1012 {
1013 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1014 	as->lock_counter++;
1015 }
1016 
1017 void
1018 ac97_unlock(struct ac97_codec_if *codec_if)
1019 {
1020 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1021 	as->lock_counter--;
1022 }
1023 
1024 int
1025 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1026 {
1027 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1028 
1029 	if (dip->index < as->num_source_info && dip->index >= 0) {
1030 		struct ac97_source_info *si = &as->source_info[dip->index];
1031 		const char *name;
1032 
1033 		dip->type = si->type;
1034 		dip->mixer_class = si->mixer_class;
1035 		dip->prev = si->prev;
1036 		dip->next = si->next;
1037 
1038 		if (si->qualifier)
1039 			name = si->qualifier;
1040 		else if (si->device)
1041 			name = si->device;
1042 		else if (si->class)
1043 			name = si->class;
1044 		else
1045 			name = NULL;
1046 
1047 		if (name)
1048 			strlcpy(dip->label.name, name, sizeof dip->label.name);
1049 
1050 		bcopy(si->info, &dip->un, si->info_size);
1051 
1052 		/* Set the delta for volume sources */
1053 		if (dip->type == AUDIO_MIXER_VALUE)
1054 			dip->un.v.delta = 1 << (8 - si->bits);
1055 
1056 		return (0);
1057 	}
1058 
1059 	return (ENXIO);
1060 }
1061 
1062 int
1063 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1064 {
1065 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1066 	struct ac97_source_info *si = &as->source_info[cp->dev];
1067 	u_int16_t mask;
1068 	u_int16_t val, newval;
1069 	int error, spdif;
1070 
1071 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
1072 	    cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1073 		return (EINVAL);
1074 
1075 	spdif = si->req_feature == CHECK_SPDIF &&
1076 	    si->reg == AC97_REG_EXT_AUDIO_CTRL;
1077 	if (spdif && as->lock_counter >= 0)
1078 		return EBUSY;
1079 
1080 	ac97_read(as, si->reg, &val);
1081 
1082 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1083 
1084 	mask = (1 << si->bits) - 1;
1085 
1086 	switch (cp->type) {
1087 	case AUDIO_MIXER_ENUM:
1088 		if (cp->un.ord > mask || cp->un.ord < 0)
1089 			return (EINVAL);
1090 
1091 		newval = (cp->un.ord << si->ofs);
1092 		if (si->reg == AC97_REG_RECORD_SELECT) {
1093 			newval |= (newval << (8 + si->ofs));
1094 			mask |= (mask << 8);
1095 			mask = mask << si->ofs;
1096 		} else if (si->reg == AC97_REG_SURR_MASTER) {
1097 			newval = cp->un.ord ? 0x8080 : 0x0000;
1098 			mask = 0x8080;
1099 		} else
1100 			mask = mask << si->ofs;
1101 
1102 		if (si->mute) {
1103 			newval |= newval << 8;
1104 			mask |= mask << 8;
1105 		}
1106 
1107 		break;
1108 	case AUDIO_MIXER_VALUE:
1109 	{
1110 		const struct audio_mixer_value *value = si->info;
1111 		u_int16_t  l, r;
1112 
1113 		if (cp->un.value.num_channels <= 0 ||
1114 		    cp->un.value.num_channels > value->num_channels)
1115 			return (EINVAL);
1116 
1117 		if (cp->un.value.num_channels == 1) {
1118 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1119 		} else {
1120 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1121 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1122 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1123 			} else {
1124 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1125 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1126 			}
1127 		}
1128 
1129 		if (!si->polarity) {
1130 			l = 255 - l;
1131 			r = 255 - r;
1132 		}
1133 
1134 		l >>= 8 - si->bits;
1135 		r >>= 8 - si->bits;
1136 
1137 		newval = ((l & mask) << si->ofs);
1138 		if (value->num_channels == 2) {
1139 			newval |= ((r & mask) << (si->ofs + 8));
1140 			mask |= (mask << 8);
1141 		}
1142 		mask = mask << si->ofs;
1143 		break;
1144 	}
1145 	default:
1146 		return (EINVAL);
1147 	}
1148 
1149 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
1150 	if (error)
1151 		return (error);
1152 
1153 	if (spdif && as->host_if->spdif_event != NULL)
1154 		as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1155 
1156 	return (0);
1157 }
1158 
1159 
1160 int
1161 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1162 {
1163 	struct ac97_softc *as;
1164 	u_long value;
1165 	u_int16_t ext_stat;
1166 	u_int16_t actual;
1167 	u_int16_t power;
1168 	u_int16_t power_bit;
1169 
1170 	as = (struct ac97_softc *)codec_if;
1171 
1172 	if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
1173 	    !(as->ext_id & AC97_EXT_AUDIO_SDAC))
1174 			return 0;
1175 	if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
1176 	    !(as->ext_id & AC97_EXT_AUDIO_LDAC))
1177 			return 0;
1178 	if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1179 		if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1180 			*rate = AC97_SINGLE_RATE;
1181 			return 0;
1182 		}
1183 	} else {
1184 		if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1185 			*rate = AC97_SINGLE_RATE;
1186 			return 0;
1187 		}
1188 	}
1189 	if (as->ac97_clock == 0)
1190 		as->ac97_clock = AC97_STANDARD_CLOCK;
1191 	value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1192 	ext_stat = 0;
1193 	/*
1194 	 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1195 	 *	Check VRA, DRA
1196 	 * PCM_LR_ADC_RATE
1197 	 *	Check VRA
1198 	 * PCM_MIC_ADC_RATE
1199 	 *	Check VRM
1200 	 */
1201 	switch (target) {
1202 	case AC97_REG_PCM_FRONT_DAC_RATE:
1203 	case AC97_REG_PCM_SURR_DAC_RATE:
1204 	case AC97_REG_PCM_LFE_DAC_RATE:
1205 		power_bit = AC97_POWER_OUT;
1206 		if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1207 			ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1208 			if (value > 0x1ffff) {
1209 				return EINVAL;
1210 			} else if (value > 0xffff) {
1211 				/* Enable DRA */
1212 				ext_stat |= AC97_EXT_AUDIO_DRA;
1213 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1214 				value /= 2;
1215 			} else {
1216 				/* Disable DRA */
1217 				ext_stat &= ~AC97_EXT_AUDIO_DRA;
1218 				ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1219 			}
1220 		} else {
1221 			if (value > 0xffff)
1222 				return EINVAL;
1223 		}
1224 		break;
1225 	case AC97_REG_PCM_LR_ADC_RATE:
1226 		power_bit = AC97_POWER_IN;
1227 		if (value > 0xffff)
1228 			return EINVAL;
1229 		break;
1230 	case AC97_REG_PCM_MIC_ADC_RATE:
1231 		power_bit = AC97_POWER_IN;
1232 		if (value > 0xffff)
1233 			return EINVAL;
1234 		break;
1235 	default:
1236 		printf("%s: Unknown register: 0x%x\n", __func__, target);
1237 		return EINVAL;
1238 	}
1239 
1240 	ac97_read(as, AC97_REG_POWER, &power);
1241 	ac97_write(as, AC97_REG_POWER, power | power_bit);
1242 
1243 	ac97_write(as, target, (u_int16_t)value);
1244 	ac97_read(as, target, &actual);
1245 	actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1246 
1247 	ac97_write(as, AC97_REG_POWER, power);
1248 	if (ext_stat & AC97_EXT_AUDIO_DRA) {
1249 		*rate = actual * 2;
1250 	} else {
1251 		*rate = actual;
1252 	}
1253 	return 0;
1254 }
1255 
1256 void
1257 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1258 {
1259 	struct ac97_softc *as;
1260 
1261 	as = (struct ac97_softc *)codec_if;
1262 	as->ac97_clock = clock;
1263 }
1264 
1265 u_int16_t
1266 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1267 {
1268 	struct ac97_softc *as;
1269 
1270 	as = (struct ac97_softc *)codec_if;
1271 	return as->ext_id;
1272 }
1273 
1274 int
1275 ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src)
1276 {
1277 	struct ac97_source_info *si;
1278 	int ouridx, idx;
1279 
1280 	if (as->num_source_info >= MAX_SOURCES) {
1281 		printf("%s: internal error: increase MAX_SOURCES in %s\n",
1282 		       __func__, __FILE__);
1283 		return -1;
1284 	}
1285 	if (!ac97_check_capability(as, src->req_feature))
1286 		return -1;
1287 	ouridx = as->num_source_info;
1288 	si = &as->source_info[ouridx];
1289 	memcpy(si, src, sizeof(*si));
1290 
1291 	switch (si->type) {
1292 	case AUDIO_MIXER_CLASS:
1293 	case AUDIO_MIXER_VALUE:
1294 		printf("%s: adding class/value is not supported yet.\n",
1295 		       __func__);
1296 		return -1;
1297 	case AUDIO_MIXER_ENUM:
1298 		break;
1299 	default:
1300 		printf("%s: unknown type: %d\n", __func__, si->type);
1301 		return -1;
1302 	}
1303 	as->num_source_info++;
1304 
1305 	si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1306 						   NULL, NULL);
1307 	/* Find the root of the device */
1308 	idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1309 				       si->device, NULL);
1310 	/* Find the last item */
1311 	while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1312 		idx = as->source_info[idx].next;
1313 	/* Append */
1314 	as->source_info[idx].next = ouridx;
1315 	si->prev = idx;
1316 	si->next = AUDIO_MIXER_LAST;
1317 
1318 	return 0;
1319 }
1320 
1321 int
1322 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
1323     char *device, char *qualifier)
1324 {
1325 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1326 	int idx;
1327 
1328 	for (idx = 0; idx < as->num_source_info; idx++) {
1329 		struct ac97_source_info *si = &as->source_info[idx];
1330 		if (ac97_str_equal(class, si->class) &&
1331 		    ac97_str_equal(device, si->device) &&
1332 		    ac97_str_equal(qualifier, si->qualifier))
1333 			return (idx);
1334 	}
1335 
1336 	return (-1);
1337 }
1338 
1339 int
1340 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1341 {
1342 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
1343 	struct ac97_source_info *si = &as->source_info[cp->dev];
1344 	u_int16_t mask;
1345 	u_int16_t val;
1346 
1347 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
1348 	    cp->type != si->type)
1349 		return (EINVAL);
1350 
1351 	ac97_read(as, si->reg, &val);
1352 
1353 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1354 
1355 	mask = (1 << si->bits) - 1;
1356 
1357 	switch (cp->type) {
1358 	case AUDIO_MIXER_ENUM:
1359 		cp->un.ord = (val >> si->ofs) & mask;
1360 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
1361 		    mask, cp->un.ord));
1362 		break;
1363 	case AUDIO_MIXER_VALUE:
1364 	{
1365 		const struct audio_mixer_value *value = si->info;
1366 		u_int16_t  l, r;
1367 
1368 		if ((cp->un.value.num_channels <= 0) ||
1369 		    (cp->un.value.num_channels > value->num_channels))
1370 			return (EINVAL);
1371 
1372 		if (value->num_channels == 1)
1373 			l = r = (val >> si->ofs) & mask;
1374 		else {
1375 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1376 				l = (val >> si->ofs) & mask;
1377 				r = (val >> (si->ofs + 8)) & mask;
1378 			} else {
1379 				r = (val >> si->ofs) & mask;
1380 				l = (val >> (si->ofs + 8)) & mask;
1381 			}
1382 		}
1383 
1384 		l <<= 8 - si->bits;
1385 		r <<= 8 - si->bits;
1386 		if (!si->polarity) {
1387 			l = 255 - l;
1388 			r = 255 - r;
1389 		}
1390 
1391 		/*
1392 		 * The EAP driver averages l and r for stereo
1393 		 * channels that are requested in MONO mode. Does this
1394 		 * make sense?
1395 		 */
1396 		if (cp->un.value.num_channels == 1) {
1397 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1398 		} else if (cp->un.value.num_channels == 2) {
1399 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1400 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1401 		}
1402 
1403 		break;
1404 	}
1405 	default:
1406 		return (EINVAL);
1407 	}
1408 
1409 	return (0);
1410 }
1411 
1412 
1413 /*
1414  * Codec-dependent initialization
1415  */
1416 
1417 void
1418 ac97_ad1885_init(struct ac97_softc *as, int resuming)
1419 {
1420 	int i;
1421 
1422 	if (resuming)
1423 		return;
1424 
1425 	for (i = 0; i < as->num_source_info; i++) {
1426 		if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
1427 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1428 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1429 			as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
1430 	}
1431 }
1432 
1433 #define AC97_AD1886_JACK_SENSE	0x72
1434 
1435 void
1436 ac97_ad1886_init(struct ac97_softc *as, int resuming)
1437 {
1438 	ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
1439 }
1440 
1441 void
1442 ac97_ad198x_init(struct ac97_softc *as, int resuming)
1443 {
1444 	int i;
1445 	u_int16_t misc;
1446 
1447 	ac97_read(as, AC97_AD_REG_MISC, &misc);
1448 	ac97_write(as, AC97_AD_REG_MISC,
1449 	    misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
1450 
1451 	if (resuming)
1452 		return;
1453 
1454 	for (i = 0; i < as->num_source_info; i++) {
1455 		if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1456 			as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1457 		else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1458 			as->source_info[i].reg = AC97_REG_SURR_MASTER;
1459 	}
1460 }
1461 
1462 void
1463 ac97_alc650_init(struct ac97_softc *as, int resuming)
1464 {
1465 	u_int16_t misc;
1466 
1467 	ac97_read(as, AC97_ALC650_REG_MISC, &misc);
1468 	if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
1469 		misc &= ~AC97_ALC650_MISC_PIN47;
1470 	misc &= ~AC97_ALC650_MISC_VREFDIS;
1471 	ac97_write(as, AC97_ALC650_REG_MISC, misc);
1472 
1473 	if (resuming)
1474 		return;
1475 
1476 	struct ac97_source_info sources[3] = {
1477 		{ AudioCoutputs, AudioNsurround, "lineinjack",
1478 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1479 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1480 		  0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1481 		{ AudioCoutputs, AudioNcenter, "micjack",
1482 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1483 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1484 		  0x0000, 1, 10, 0, 0, CHECK_CENTER },
1485 		{ AudioCoutputs, AudioNlfe, "micjack",
1486 		  AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1487 		  AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1488 		  0x0000, 1, 10, 0, 0, CHECK_LFE }};
1489 
1490 	ac97_add_port(as, &sources[0]);
1491 	ac97_add_port(as, &sources[1]);
1492 	ac97_add_port(as, &sources[2]);
1493 }
1494 
1495 void
1496 ac97_cx20468_init(struct ac97_softc *as, int resuming)
1497 {
1498 	u_int16_t misc;
1499 
1500 	ac97_read(as, AC97_CX_REG_MISC, &misc);
1501 	ac97_write(as, AC97_CX_REG_MISC, misc &
1502 	    ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
1503 }
1504 
1505 void
1506 ac97_vt1616_init(struct ac97_softc *as, int resuming)
1507 {
1508 	u_int16_t reg;
1509 
1510 	if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
1511 		ac97_read(as, AC97_VT_REG_TEST, &reg);
1512 
1513 		/* disable 'hp' mixer controls controlling the surround pins */
1514 		reg &= ~(AC97_VT_LVL);
1515 
1516 		/* disable downmixing */
1517 		reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
1518 
1519 		/* enable DC offset removal */
1520 		reg |= AC97_VT_BPDC;
1521 
1522 		ac97_write(as, AC97_VT_REG_TEST, reg);
1523 	}
1524 }
1525