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