xref: /freebsd/sys/dev/sound/pcm/ac97.c (revision acd3428b7d3e94cef0e1881c868cb4b131d4ff41)
1 /*-
2  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <dev/sound/pcm/sound.h>
28 #include <dev/sound/pcm/ac97.h>
29 #include <dev/sound/pcm/ac97_patch.h>
30 
31 #include "mixer_if.h"
32 
33 SND_DECLARE_FILE("$FreeBSD$");
34 
35 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36 
37 struct ac97mixtable_entry {
38 	int	 reg:8;		/* register index		*/
39 				/* reg < 0 if inverted polarity	*/
40 	unsigned bits:4;	/* width of control field	*/
41 	unsigned ofs:4;		/* offset (only if stereo=0)	*/
42 	unsigned stereo:1;	/* set for stereo controls	*/
43 	unsigned mute:1;	/* bit15 is MUTE		*/
44 	unsigned recidx:4;	/* index in rec mux		*/
45 	unsigned mask:1;	/* use only masked bits		*/
46 	unsigned enable:1;	/* entry is enabled		*/
47 };
48 
49 #define AC97_NAMELEN	16
50 struct ac97_info {
51 	kobj_t methods;
52 	device_t dev;
53 	void *devinfo;
54 	u_int32_t id;
55 	unsigned count, caps, se, extcaps, extid, extstat, noext:1;
56 	u_int32_t flags;
57 	struct ac97mixtable_entry mix[32];
58 	char name[AC97_NAMELEN];
59 	struct mtx *lock;
60 };
61 
62 struct ac97_vendorid {
63 	u_int32_t   id;
64 	const char *name;
65 };
66 
67 struct ac97_codecid {
68 	u_int32_t  id;
69 	u_int8_t   stepmask;
70 	u_int8_t   noext:1;
71 	char 	  *name;
72 	ac97_patch patch;
73 };
74 
75 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
76     /*	[offset]			reg	     bits of st mu re mk en */
77 	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
78 	[SOUND_MIXER_OGAIN]	= { AC97_MIX_AUXOUT, 	5, 0, 1, 1, 0, 0, 0 },
79 	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
80 	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
81 	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
82 	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
83 	[SOUND_MIXER_SPEAKER]	= { AC97_MIX_BEEP, 	4, 1, 0, 1, 0, 0, 0 },
84 	[SOUND_MIXER_LINE]	= { AC97_MIX_LINE, 	5, 0, 1, 1, 5, 0, 1 },
85 	[SOUND_MIXER_PHONEIN]	= { AC97_MIX_PHONE, 	5, 0, 0, 1, 8, 0, 0 },
86 	[SOUND_MIXER_MIC] 	= { AC97_MIX_MIC, 	5, 0, 0, 1, 1, 1, 1 },
87 	/* use igain for the mic 20dB boost */
88 	[SOUND_MIXER_IGAIN] 	= { -AC97_MIX_MIC, 	1, 6, 0, 0, 0, 1, 1 },
89 	[SOUND_MIXER_CD]	= { AC97_MIX_CD, 	5, 0, 1, 1, 2, 0, 1 },
90 	[SOUND_MIXER_LINE1]	= { AC97_MIX_AUX, 	5, 0, 1, 1, 4, 0, 0 },
91 	[SOUND_MIXER_VIDEO]	= { AC97_MIX_VIDEO, 	5, 0, 1, 1, 3, 0, 0 },
92 	[SOUND_MIXER_RECLEV]	= { -AC97_MIX_RGAIN, 	4, 0, 1, 1, 0, 0, 1 }
93 };
94 
95 static const struct ac97_vendorid ac97vendorid[] = {
96 	{ 0x41445300, "Analog Devices" },
97 	{ 0x414b4d00, "Asahi Kasei" },
98 	{ 0x414c4300, "Realtek" },
99 	{ 0x414c4700, "Avance Logic" },
100 	{ 0x43525900, "Cirrus Logic" },
101 	{ 0x434d4900, "C-Media Electronics" },
102 	{ 0x43585400, "Conexant" },
103 	{ 0x44543000, "Diamond Technology" },
104 	{ 0x454d4300, "eMicro" },
105 	{ 0x45838300, "ESS Technology" },
106 	{ 0x48525300, "Intersil" },
107 	{ 0x49434500, "ICEnsemble" },
108 	{ 0x49544500, "ITE, Inc." },
109 	{ 0x4e534300, "National Semiconductor" },
110 	{ 0x50534300, "Philips Semiconductor" },
111 	{ 0x83847600, "SigmaTel" },
112 	{ 0x53494c00, "Silicon Laboratories" },
113 	{ 0x54524100, "TriTech" },
114 	{ 0x54584e00, "Texas Instruments" },
115 	{ 0x56494100, "VIA Technologies" },
116 	{ 0x57454300, "Winbond" },
117 	{ 0x574d4c00, "Wolfson" },
118 	{ 0x594d4800, "Yamaha" },
119 	/*
120 	 * XXX This is a fluke, really! The real vendor
121 	 * should be SigmaTel, not this! This should be
122 	 * removed someday!
123 	 */
124 	{ 0x01408300, "Creative" },
125 	{ 0x00000000, NULL }
126 };
127 
128 static struct ac97_codecid ac97codecid[] = {
129 	{ 0x41445303, 0x00, 0, "AD1819",	0 },
130 	{ 0x41445340, 0x00, 0, "AD1881",	0 },
131 	{ 0x41445348, 0x00, 0, "AD1881A",	0 },
132 	{ 0x41445360, 0x00, 0, "AD1885",	0 },
133 	{ 0x41445361, 0x00, 0, "AD1886", 	ad1886_patch },
134 	{ 0x41445362, 0x00, 0, "AD1887", 	0 },
135 	{ 0x41445363, 0x00, 0, "AD1886A", 	0 },
136 	{ 0x41445368, 0x00, 0, "AD1888", 	ad198x_patch },
137 	{ 0x41445370, 0x00, 0, "AD1980",	ad198x_patch },
138 	{ 0x41445372, 0x00, 0, "AD1981A",	0 },
139 	{ 0x41445374, 0x00, 0, "AD1981B",	ad1981b_patch },
140 	{ 0x41445375, 0x00, 0, "AD1985",	ad198x_patch },
141 	{ 0x41445378, 0x00, 0, "AD1986",	ad198x_patch },
142 	{ 0x414b4d00, 0x00, 1, "AK4540", 	0 },
143 	{ 0x414b4d01, 0x00, 1, "AK4542", 	0 },
144 	{ 0x414b4d02, 0x00, 1, "AK4543", 	0 },
145 	{ 0x414b4d06, 0x00, 0, "AK4544A",	0 },
146 	{ 0x454b4d07, 0x00, 0, "AK4545",	0 },
147 	{ 0x414c4320, 0x0f, 0, "ALC100",	0 },
148 	{ 0x414c4730, 0x0f, 0, "ALC101",	0 },
149 	{ 0x414c4710, 0x0f, 0, "ALC200", 	0 },
150 	{ 0x414c4740, 0x0f, 0, "ALC202", 	0 },
151 	{ 0x414c4720, 0x0f, 0, "ALC650", 	0 },
152 	{ 0x414c4752, 0x0f, 0, "ALC250",	0 },
153 	{ 0x414c4760, 0x0f, 0, "ALC655",	0 },
154 	{ 0x414c4770, 0x0f, 0, "ALC203",	0 },
155 	{ 0x414c4780, 0x0f, 0, "ALC658",	0 },
156 	{ 0x414c4790, 0x0f, 0, "ALC850",	0 },
157 	{ 0x43525900, 0x07, 0, "CS4297", 	0 },
158 	{ 0x43525910, 0x07, 0, "CS4297A", 	0 },
159 	{ 0x43525920, 0x07, 0, "CS4294/98",	0 },
160 	{ 0x4352592d, 0x07, 0, "CS4294",	0 },
161 	{ 0x43525930, 0x07, 0, "CS4299",	0 },
162 	{ 0x43525940, 0x07, 0, "CS4201",	0 },
163 	{ 0x43525958, 0x07, 0, "CS4205",	0 },
164 	{ 0x43525960, 0x07, 0, "CS4291A",	0 },
165 	{ 0x434d4961, 0x00, 0, "CMI9739",	cmi9739_patch },
166 	{ 0x434d4941, 0x00, 0, "CMI9738",	0 },
167 	{ 0x434d4978, 0x00, 0, "CMI9761",	0 },
168 	{ 0x434d4982, 0x00, 0, "CMI9761",	0 },
169 	{ 0x434d4983, 0x00, 0, "CMI9761",	0 },
170 	{ 0x43585421, 0x00, 0, "HSD11246",	0 },
171 	{ 0x43585428, 0x07, 0, "CX20468",	0 },
172 	{ 0x43585430, 0x00, 0, "CX20468-21",	0 },
173 	{ 0x44543000, 0x00, 0, "DT0398",	0 },
174 	{ 0x454d4323, 0x00, 0, "EM28023",	0 },
175 	{ 0x454d4328, 0x00, 0, "EM28028",	0 },
176 	{ 0x45838308, 0x00, 0, "ES1988",	0 }, /* Formerly ES1921(?) */
177 	{ 0x48525300, 0x00, 0, "HMP9701",	0 },
178 	{ 0x49434501, 0x00, 0, "ICE1230",	0 },
179 	{ 0x49434511, 0x00, 0, "ICE1232",	0 },
180 	{ 0x49434514, 0x00, 0, "ICE1232A",	0 },
181 	{ 0x49434551, 0x03, 0, "VT1616",	0 }, /* Via badged ICE */
182 	{ 0x49544520, 0x00, 0, "ITE2226E",	0 },
183 	{ 0x49544560, 0x07, 0, "ITE2646E",	0 }, /* XXX: patch needed */
184 	{ 0x4e534340, 0x00, 0, "LM4540",	0 }, /* Spec blank on revid */
185 	{ 0x4e534343, 0x00, 0, "LM4543",	0 }, /* Ditto */
186 	{ 0x4e534346, 0x00, 0, "LM4546A",	0 },
187 	{ 0x4e534348, 0x00, 0, "LM4548A",	0 },
188 	{ 0x4e534331, 0x00, 0, "LM4549",	0 },
189 	{ 0x4e534349, 0x00, 0, "LM4549A",	0 },
190 	{ 0x4e534350, 0x00, 0, "LM4550",	0 },
191 	{ 0x50534301, 0x00, 0, "UCB1510",	0 },
192 	{ 0x50534304, 0x00, 0, "UCB1400",	0 },
193 	{ 0x83847600, 0x00, 0, "STAC9700/83/84",	0 },
194 	{ 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
195 	{ 0x83847605, 0x00, 0, "STAC9704",	0 },
196 	{ 0x83847608, 0x00, 0, "STAC9708/11",	0 },
197 	{ 0x83847609, 0x00, 0, "STAC9721/23",	0 },
198 	{ 0x83847644, 0x00, 0, "STAC9744/45",	0 },
199 	{ 0x83847650, 0x00, 0, "STAC9750/51",	0 },
200 	{ 0x83847652, 0x00, 0, "STAC9752/53",	0 },
201 	{ 0x83847656, 0x00, 0, "STAC9756/57",	0 },
202 	{ 0x83847658, 0x00, 0, "STAC9758/59",	0 },
203 	{ 0x83847660, 0x00, 0, "STAC9760/61",	0 }, /* Extrapolated */
204 	{ 0x83847662, 0x00, 0, "STAC9762/63",	0 }, /* Extrapolated */
205 	{ 0x83847666, 0x00, 0, "STAC9766/67",	0 },
206 	{ 0x53494c22, 0x00, 0, "Si3036",	0 },
207 	{ 0x53494c23, 0x00, 0, "Si3038",	0 },
208 	{ 0x54524103, 0x00, 0, "TR28023",	0 }, /* Extrapolated */
209 	{ 0x54524106, 0x00, 0, "TR28026",	0 },
210 	{ 0x54524108, 0x00, 0, "TR28028",	0 },
211 	{ 0x54524123, 0x00, 0, "TR28602",	0 },
212 	{ 0x54524e03, 0x07, 0, "TLV320AIC27",	0 },
213 	{ 0x54584e20, 0x00, 0, "TLC320AD90",	0 },
214 	{ 0x56494161, 0x00, 0, "VIA1612A",      0 },
215 	{ 0x56494170, 0x00, 0, "VIA1617A",      0 },
216 	{ 0x574d4c00, 0x00, 0, "WM9701A",	0 },
217 	{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8",	0 },
218 	{ 0x574d4c04, 0x00, 0, "WM9704Q",	0 },
219 	{ 0x574d4c05, 0x00, 0, "WM9705/10",	0 },
220 	{ 0x574d4d09, 0x00, 0, "WM9709",	0 },
221 	{ 0x574d4c12, 0x00, 0, "WM9711/12",	0 }, /* XXX: patch needed */
222 	{ 0x57454301, 0x00, 0, "W83971D",	0 },
223 	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
224 	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
225 	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
226 	/*
227 	 * XXX This is a fluke, really! The real codec
228 	 * should be STAC9704, not this! This should be
229 	 * removed someday!
230 	 */
231 	{ 0x01408384, 0x00, 0, "EV1938",	0 },
232 	{ 0, 0, 0, NULL, 0 }
233 };
234 
235 static char *ac97enhancement[] = {
236 	"no 3D Stereo Enhancement",
237 	"Analog Devices Phat Stereo",
238 	"Creative Stereo Enhancement",
239 	"National Semi 3D Stereo Enhancement",
240 	"Yamaha Ymersion",
241 	"BBE 3D Stereo Enhancement",
242 	"Crystal Semi 3D Stereo Enhancement",
243 	"Qsound QXpander",
244 	"Spatializer 3D Stereo Enhancement",
245 	"SRS 3D Stereo Enhancement",
246 	"Platform Tech 3D Stereo Enhancement",
247 	"AKM 3D Audio",
248 	"Aureal Stereo Enhancement",
249 	"Aztech 3D Enhancement",
250 	"Binaura 3D Audio Enhancement",
251 	"ESS Technology Stereo Enhancement",
252 	"Harman International VMAx",
253 	"Nvidea 3D Stereo Enhancement",
254 	"Philips Incredible Sound",
255 	"Texas Instruments 3D Stereo Enhancement",
256 	"VLSI Technology 3D Stereo Enhancement",
257 	"TriTech 3D Stereo Enhancement",
258 	"Realtek 3D Stereo Enhancement",
259 	"Samsung 3D Stereo Enhancement",
260 	"Wolfson Microelectronics 3D Enhancement",
261 	"Delta Integration 3D Enhancement",
262 	"SigmaTel 3D Enhancement",
263 	"Reserved 27",
264 	"Rockwell 3D Stereo Enhancement",
265 	"Reserved 29",
266 	"Reserved 30",
267 	"Reserved 31"
268 };
269 
270 static char *ac97feature[] = {
271 	"mic channel",
272 	"reserved",
273 	"tone",
274 	"simulated stereo",
275 	"headphone",
276 	"bass boost",
277 	"18 bit DAC",
278 	"20 bit DAC",
279 	"18 bit ADC",
280 	"20 bit ADC"
281 };
282 
283 static char *ac97extfeature[] = {
284 	"variable rate PCM",
285 	"double rate PCM",
286 	"reserved 1",
287 	"variable rate mic",
288 	"reserved 2",
289 	"reserved 3",
290 	"center DAC",
291 	"surround DAC",
292 	"LFE DAC",
293 	"AMAP",
294 	"reserved 4",
295 	"reserved 5",
296 	"reserved 6",
297 	"reserved 7",
298 };
299 
300 u_int16_t
301 ac97_rdcd(struct ac97_info *codec, int reg)
302 {
303 	if (codec->flags & AC97_F_RDCD_BUG) {
304 		u_int16_t i[2], j = 100;
305 
306 		i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
307 		i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
308 		while (i[0] != i[1] && j)
309 			i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
310 #if 0
311 		if (j < 100) {
312 			device_printf(codec->dev, "%s(): Inconsistent register value at"
313 					" 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
314 		}
315 #endif
316 		return i[!(j & 1)];
317 	}
318 	return AC97_READ(codec->methods, codec->devinfo, reg);
319 }
320 
321 void
322 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
323 {
324 	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
325 }
326 
327 static void
328 ac97_reset(struct ac97_info *codec)
329 {
330 	u_int32_t i, ps;
331 	ac97_wrcd(codec, AC97_REG_RESET, 0);
332 	for (i = 0; i < 500; i++) {
333 		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
334 		if (ps == AC97_POWER_STATUS)
335 			return;
336 		DELAY(1000);
337 	}
338 	device_printf(codec->dev, "AC97 reset timed out.\n");
339 }
340 
341 int
342 ac97_setrate(struct ac97_info *codec, int which, int rate)
343 {
344 	u_int16_t v;
345 
346 	switch(which) {
347 	case AC97_REGEXT_FDACRATE:
348 	case AC97_REGEXT_SDACRATE:
349 	case AC97_REGEXT_LDACRATE:
350 	case AC97_REGEXT_LADCRATE:
351 	case AC97_REGEXT_MADCRATE:
352 		break;
353 
354 	default:
355 		return -1;
356 	}
357 
358 	snd_mtxlock(codec->lock);
359 	if (rate != 0) {
360 		v = rate;
361 		if (codec->extstat & AC97_EXTCAP_DRA)
362 			v >>= 1;
363 		ac97_wrcd(codec, which, v);
364 	}
365 	v = ac97_rdcd(codec, which);
366 	if (codec->extstat & AC97_EXTCAP_DRA)
367 		v <<= 1;
368 	snd_mtxunlock(codec->lock);
369 	return v;
370 }
371 
372 int
373 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
374 {
375 	mode &= AC97_EXTCAPS;
376 	if ((mode & ~codec->extcaps) != 0) {
377 		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
378 			      mode);
379 		return -1;
380 	}
381 	snd_mtxlock(codec->lock);
382 	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
383 	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
384 	snd_mtxunlock(codec->lock);
385 	return (mode == codec->extstat)? 0 : -1;
386 }
387 
388 u_int16_t
389 ac97_getextmode(struct ac97_info *codec)
390 {
391 	return codec->extstat;
392 }
393 
394 u_int16_t
395 ac97_getextcaps(struct ac97_info *codec)
396 {
397 	return codec->extcaps;
398 }
399 
400 u_int16_t
401 ac97_getcaps(struct ac97_info *codec)
402 {
403 	return codec->caps;
404 }
405 
406 static int
407 ac97_setrecsrc(struct ac97_info *codec, int channel)
408 {
409 	struct ac97mixtable_entry *e = &codec->mix[channel];
410 
411 	if (e->recidx > 0) {
412 		int val = e->recidx - 1;
413 		val |= val << 8;
414 		snd_mtxlock(codec->lock);
415 		ac97_wrcd(codec, AC97_REG_RECSEL, val);
416 		snd_mtxunlock(codec->lock);
417 		return 0;
418 	} else
419 		return -1;
420 }
421 
422 static int
423 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
424 {
425 	struct ac97mixtable_entry *e = &codec->mix[channel];
426 
427 	if (e->reg && e->enable && e->bits) {
428 		int mask, max, val, reg;
429 
430 		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
431 		max = (1 << e->bits) - 1;		/* actual range	    */
432 		mask = (max << 8) | max;		/* bits of interest */
433 
434 		if (!e->stereo)
435 			right = left;
436 
437 		/*
438 		 * Invert the range if the polarity requires so,
439 		 * then scale to 0..max-1 to compute the value to
440 		 * write into the codec, and scale back to 0..100
441 		 * for the return value.
442 		 */
443 		if (e->reg > 0) {
444 			left = 100 - left;
445 			right = 100 - right;
446 		}
447 
448 		left = (left * max) / 100;
449 		right = (right * max) / 100;
450 
451 		val = (left << 8) | right;
452 
453 		left = (left * 100) / max;
454 		right = (right * 100) / max;
455 
456 		if (e->reg > 0) {
457 			left = 100 - left;
458 			right = 100 - right;
459 		}
460 
461 		/*
462 		 * For mono controls, trim val and mask, also taking
463 		 * care of e->ofs (offset of control field).
464 		 */
465 		if (e->ofs) {
466 			val &= max;
467 			val <<= e->ofs;
468 			mask = (max << e->ofs);
469 		}
470 
471 		/*
472 		 * If we have a mute bit, add it to the mask and
473 		 * update val and set mute if both channels require a
474 		 * zero volume.
475 		 */
476 		if (e->mute == 1) {
477 			mask |= AC97_MUTE;
478 			if (left == 0 && right == 0)
479 				val = AC97_MUTE;
480 		}
481 
482 		/*
483 		 * If the mask bit is set, do not alter the other bits.
484 		 */
485 		snd_mtxlock(codec->lock);
486 		if (e->mask) {
487 			int cur = ac97_rdcd(codec, reg);
488 			val |= cur & ~(mask);
489 		}
490 		ac97_wrcd(codec, reg, val);
491 		snd_mtxunlock(codec->lock);
492 		return left | (right << 8);
493 	} else {
494 #if 0
495 		printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
496 #endif
497 		return -1;
498 	}
499 }
500 
501 static void
502 ac97_fix_auxout(struct ac97_info *codec)
503 {
504 	int keep_ogain;
505 
506 	/*
507 	 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
508 	 * OGAIN setting.
509 	 *
510 	 * We first check whether aux_out is a valid register.  If not
511 	 * we may not want to keep ogain.
512 	 */
513 	keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
514 
515 	/*
516 	 * Determine what AUX_OUT really means, it can be:
517 	 *
518 	 * 1. Headphone out.
519 	 * 2. 4-Channel Out
520 	 * 3. True line level out (effectively master volume).
521 	 *
522 	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
523 	 */
524 	if (codec->extcaps & AC97_EXTCAP_SDAC &&
525 	    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
526 		codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
527 		keep_ogain = 1;
528 	}
529 
530 	if (keep_ogain == 0) {
531 		bzero(&codec->mix[SOUND_MIXER_OGAIN],
532 		      sizeof(codec->mix[SOUND_MIXER_OGAIN]));
533 	}
534 }
535 
536 static void
537 ac97_fix_tone(struct ac97_info *codec)
538 {
539 	/* Hide treble and bass if they don't exist */
540 	if ((codec->caps & AC97_CAP_TONE) == 0) {
541 		bzero(&codec->mix[SOUND_MIXER_BASS],
542 		      sizeof(codec->mix[SOUND_MIXER_BASS]));
543 		bzero(&codec->mix[SOUND_MIXER_TREBLE],
544 		      sizeof(codec->mix[SOUND_MIXER_TREBLE]));
545 	}
546 }
547 
548 static const char*
549 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
550 {
551 	if (cname == NULL) {
552 		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
553 		return buf;
554 	}
555 
556 	if (vname == NULL) vname = "Unknown";
557 
558 	if (bootverbose) {
559 		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
560 	} else {
561 		sprintf(buf, "%s %s AC97 Codec", vname, cname);
562 	}
563 	return buf;
564 }
565 
566 static unsigned
567 ac97_initmixer(struct ac97_info *codec)
568 {
569 	ac97_patch codec_patch;
570 	const char *cname, *vname;
571 	char desc[80];
572 	u_int8_t model, step;
573 	unsigned i, j, k, bit, old;
574 	u_int32_t id;
575 	int reg;
576 
577 	snd_mtxlock(codec->lock);
578 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
579 	if (codec->count == 0) {
580 		device_printf(codec->dev, "ac97 codec init failed\n");
581 		snd_mtxunlock(codec->lock);
582 		return ENODEV;
583 	}
584 
585 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
586 	ac97_reset(codec);
587 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
588 
589 	i = ac97_rdcd(codec, AC97_REG_RESET);
590 	j = ac97_rdcd(codec, AC97_REG_RESET);
591 	/*
592 	 * Let see if this codec can return consistent value.
593 	 * If not, turn on aggressive read workaround
594 	 * (STAC9704 comes in mind).
595 	 */
596 	if (i != j) {
597 		codec->flags |= AC97_F_RDCD_BUG;
598 		i = ac97_rdcd(codec, AC97_REG_RESET);
599 	}
600 	codec->caps = i & 0x03ff;
601 	codec->se =  (i & 0x7c00) >> 10;
602 
603 	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
604 	if (id == 0 || id == 0xffffffff) {
605 		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
606 		snd_mtxunlock(codec->lock);
607 		return ENODEV;
608 	}
609 
610 	codec->id = id;
611 	codec->noext = 0;
612 	codec_patch = NULL;
613 
614 	cname = NULL;
615 	model = step = 0;
616 	for (i = 0; ac97codecid[i].id; i++) {
617 		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
618 		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
619 			codec->noext = ac97codecid[i].noext;
620 			codec_patch = ac97codecid[i].patch;
621 			cname = ac97codecid[i].name;
622 			model = (id & modelmask) & 0xff;
623 			step = (id & ~modelmask) & 0xff;
624 			break;
625 		}
626 	}
627 
628 	vname = NULL;
629 	for (i = 0; ac97vendorid[i].id; i++) {
630 		if (ac97vendorid[i].id == (id & 0xffffff00)) {
631 			vname = ac97vendorid[i].name;
632 			break;
633 		}
634 	}
635 
636 	codec->extcaps = 0;
637 	codec->extid = 0;
638 	codec->extstat = 0;
639 	if (!codec->noext) {
640 		i = ac97_rdcd(codec, AC97_REGEXT_ID);
641 		if (i != 0xffff) {
642 			codec->extcaps = i & 0x3fff;
643 			codec->extid =  (i & 0xc000) >> 14;
644 			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
645 		}
646 	}
647 
648 	for (i = 0; i < 32; i++) {
649 		codec->mix[i] = ac97mixtable_default[i];
650 	}
651 	ac97_fix_auxout(codec);
652 	ac97_fix_tone(codec);
653 	if (codec_patch)
654 		codec_patch(codec);
655 
656 	for (i = 0; i < 32; i++) {
657 		k = codec->noext? codec->mix[i].enable : 1;
658 		reg = codec->mix[i].reg;
659 		if (reg < 0)
660 			reg = -reg;
661 		if (k && reg) {
662 			j = old = ac97_rdcd(codec, reg);
663 			/*
664 			 * Test for mute bit (except for AC97_MIX_TONE,
665 			 * where we simply assume it as available).
666 			 */
667 			if (codec->mix[i].mute) {
668 				ac97_wrcd(codec, reg, j | 0x8000);
669 				j = ac97_rdcd(codec, reg);
670 			} else
671 				j |= 0x8000;
672 			if ((j & 0x8000)) {
673 				/*
674 				 * Test whether the control width should be
675 				 * 4, 5 or 6 bit. For 5bit register, we should
676 				 * test it whether it's really 5 or 6bit. Leave
677 				 * 4bit register alone, because sometimes an
678 				 * attempt to write past 4th bit may cause
679 				 * incorrect result especially for AC97_MIX_BEEP
680 				 * (ac97 2.3).
681 				 */
682 				bit = codec->mix[i].bits;
683 				if (bit == 5)
684 					bit++;
685 				j = ((1 << bit) - 1) << codec->mix[i].ofs;
686 				ac97_wrcd(codec, reg,
687 					j | (codec->mix[i].mute ? 0x8000 : 0));
688 				k = ac97_rdcd(codec, reg) & j;
689 				k >>= codec->mix[i].ofs;
690 				if (reg == AC97_MIX_TONE &&
691 							((k & 0x0001) == 0x0000))
692 					k >>= 1;
693 				for (j = 0; k >> j; j++)
694 					;
695 				if (j != 0) {
696 #if 0
697 					device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
698 						i, k, bit, codec->mix[i].bits, j);
699 #endif
700 					codec->mix[i].enable = 1;
701 					codec->mix[i].bits = j;
702 				} else if (reg == AC97_MIX_BEEP) {
703 					/*
704 					 * Few codec such as CX20468-21 does
705 					 * have this control register, although
706 					 * the only usable part is the mute bit.
707 					 */
708 					codec->mix[i].enable = 1;
709 				} else
710 					codec->mix[i].enable = 0;
711 			} else
712 				codec->mix[i].enable = 0;
713 			ac97_wrcd(codec, reg, old);
714 		}
715 #if 0
716 		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
717 #endif
718 	}
719 
720 	device_printf(codec->dev, "<%s>\n",
721 		      ac97_hw_desc(codec->id, vname, cname, desc));
722 
723 	if (bootverbose) {
724 		if (codec->flags & AC97_F_RDCD_BUG)
725 			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
726 		device_printf(codec->dev, "Codec features ");
727 		for (i = j = 0; i < 10; i++)
728 			if (codec->caps & (1 << i))
729 				printf("%s%s", j++? ", " : "", ac97feature[i]);
730 		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
731 		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
732 
733 		if (codec->extcaps != 0 || codec->extid) {
734 			device_printf(codec->dev, "%s codec",
735 				      codec->extid? "Secondary" : "Primary");
736 			if (codec->extcaps)
737 				printf(" extended features ");
738 			for (i = j = 0; i < 14; i++)
739 				if (codec->extcaps & (1 << i))
740 					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
741 			printf("\n");
742 		}
743 	}
744 
745 	i = 0;
746 	while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
747 		if (++i == 100) {
748 			device_printf(codec->dev, "ac97 codec reports dac not ready\n");
749 			break;
750 		}
751 		DELAY(1000);
752 	}
753 	if (bootverbose)
754 		device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
755 	snd_mtxunlock(codec->lock);
756 	return 0;
757 }
758 
759 static unsigned
760 ac97_reinitmixer(struct ac97_info *codec)
761 {
762 	snd_mtxlock(codec->lock);
763 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
764 	if (codec->count == 0) {
765 		device_printf(codec->dev, "ac97 codec init failed\n");
766 		snd_mtxunlock(codec->lock);
767 		return ENODEV;
768 	}
769 
770 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
771 	ac97_reset(codec);
772 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
773 
774 	if (!codec->noext) {
775 		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
776 		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
777 		    != codec->extstat)
778 			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
779 				      codec->extstat,
780 				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
781 				      AC97_EXTCAPS);
782 	}
783 
784 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
785 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
786 	snd_mtxunlock(codec->lock);
787 	return 0;
788 }
789 
790 struct ac97_info *
791 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
792 {
793 	struct ac97_info *codec;
794 	int eapd_inv;
795 
796 	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT | M_ZERO);
797 	if (codec == NULL)
798 		return NULL;
799 
800 	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
801 	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
802 	codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
803 	if (codec->methods == NULL) {
804 		snd_mtxlock(codec->lock);
805 		snd_mtxfree(codec->lock);
806 		free(codec, M_AC97);
807 		return NULL;
808 	}
809 
810 	codec->dev = dev;
811 	codec->devinfo = devinfo;
812 	codec->flags = 0;
813 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
814 		    "ac97_eapd_inv", &eapd_inv) == 0) {
815 		if (eapd_inv != 0)
816 			codec->flags |= AC97_F_EAPD_INV;
817 	}
818 	return codec;
819 }
820 
821 void
822 ac97_destroy(struct ac97_info *codec)
823 {
824 	snd_mtxlock(codec->lock);
825 	if (codec->methods != NULL)
826 		kobj_delete(codec->methods, M_AC97);
827 	snd_mtxfree(codec->lock);
828 	free(codec, M_AC97);
829 }
830 
831 void
832 ac97_setflags(struct ac97_info *codec, u_int32_t val)
833 {
834 	codec->flags = val;
835 }
836 
837 u_int32_t
838 ac97_getflags(struct ac97_info *codec)
839 {
840 	return codec->flags;
841 }
842 
843 /* -------------------------------------------------------------------- */
844 
845 static int
846 ac97mix_init(struct snd_mixer *m)
847 {
848 	struct ac97_info *codec = mix_getdevinfo(m);
849 	struct snddev_info *d;
850 	u_int32_t i, mask;
851 
852 	if (codec == NULL)
853 		return -1;
854 
855 	if (ac97_initmixer(codec))
856 		return -1;
857 
858 	switch (codec->id) {
859 	case 0x41445374:	/* AD1981B */
860 #if 0
861 		mask = 0;
862 		if (codec->mix[SOUND_MIXER_OGAIN].enable)
863 			mask |= SOUND_MASK_OGAIN;
864 		if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
865 			mask |= SOUND_MASK_PHONEOUT;
866 		/* Tie ogain/phone to master volume */
867 		if (codec->mix[SOUND_MIXER_VOLUME].enable)
868 			mix_setparentchild(m, SOUND_MIXER_VOLUME, mask);
869 		else {
870 			mix_setparentchild(m, SOUND_MIXER_VOLUME, mask);
871 			mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
872 		}
873 #endif
874 		break;
875 	case 0x434d4941:	/* CMI9738 */
876 	case 0x434d4961:	/* CMI9739 */
877 	case 0x434d4978:	/* CMI9761 */
878 	case 0x434d4982:	/* CMI9761 */
879 	case 0x434d4983:	/* CMI9761 */
880 		ac97_wrcd(codec, AC97_MIX_PCM, 0);
881 		bzero(&codec->mix[SOUND_MIXER_PCM],
882 		    sizeof(codec->mix[SOUND_MIXER_PCM]));
883 		d = device_get_softc(codec->dev);
884 		if (d != NULL)
885 			d->flags |= SD_F_SOFTPCMVOL;
886 		/* XXX How about master volume ? */
887 		break;
888 	default:
889 		break;
890 	}
891 
892 #if 0
893 	/* XXX For the sake of debugging purposes */
894 	mix_setparentchild(m, SOUND_MIXER_VOLUME,
895 	    SOUND_MASK_PCM | SOUND_MASK_CD);
896 	mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
897 	ac97_wrcd(codec, AC97_MIX_MASTER, 0);
898 #endif
899 
900 	mask = 0;
901 	for (i = 0; i < 32; i++)
902 		mask |= codec->mix[i].enable? 1 << i : 0;
903 	mix_setdevs(m, mask);
904 
905 	mask = 0;
906 	for (i = 0; i < 32; i++)
907 		mask |= codec->mix[i].recidx? 1 << i : 0;
908 	mix_setrecdevs(m, mask);
909 	return 0;
910 }
911 
912 static int
913 ac97mix_uninit(struct snd_mixer *m)
914 {
915 	struct ac97_info *codec = mix_getdevinfo(m);
916 
917 	if (codec == NULL)
918 		return -1;
919 	/*
920 	if (ac97_uninitmixer(codec))
921 		return -1;
922 	*/
923 	ac97_destroy(codec);
924 	return 0;
925 }
926 
927 static int
928 ac97mix_reinit(struct snd_mixer *m)
929 {
930 	struct ac97_info *codec = mix_getdevinfo(m);
931 
932 	if (codec == NULL)
933 		return -1;
934 	return ac97_reinitmixer(codec);
935 }
936 
937 static int
938 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
939 {
940 	struct ac97_info *codec = mix_getdevinfo(m);
941 
942 	if (codec == NULL)
943 		return -1;
944 	return ac97_setmixer(codec, dev, left, right);
945 }
946 
947 static int
948 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
949 {
950 	int i;
951 	struct ac97_info *codec = mix_getdevinfo(m);
952 
953 	if (codec == NULL)
954 		return -1;
955 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
956 		if ((src & (1 << i)) != 0)
957 			break;
958 	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
959 }
960 
961 static kobj_method_t ac97mixer_methods[] = {
962     	KOBJMETHOD(mixer_init,		ac97mix_init),
963     	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
964     	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
965     	KOBJMETHOD(mixer_set,		ac97mix_set),
966     	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
967 	{ 0, 0 }
968 };
969 MIXER_DECLARE(ac97mixer);
970 
971 /* -------------------------------------------------------------------- */
972 
973 kobj_class_t
974 ac97_getmixerclass(void)
975 {
976 	return &ac97mixer_class;
977 }
978 
979 
980