xref: /freebsd/sys/dev/sound/pcm/ac97.c (revision 262e143bd46171a6415a5b28af260a5efa2a3db8)
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",	0 },
140 	{ 0x41445375, 0x00, 0, "AD1985",	ad198x_patch },
141 	{ 0x414b4d00, 0x00, 1, "AK4540", 	0 },
142 	{ 0x414b4d01, 0x00, 1, "AK4542", 	0 },
143 	{ 0x414b4d02, 0x00, 1, "AK4543", 	0 },
144 	{ 0x414b4d06, 0x00, 0, "AK4544A",	0 },
145 	{ 0x454b4d07, 0x00, 0, "AK4545",	0 },
146 	{ 0x414c4320, 0x0f, 0, "ALC100",	0 },
147 	{ 0x414c4730, 0x0f, 0, "ALC101",	0 },
148 	{ 0x414c4710, 0x0f, 0, "ALC200", 	0 },
149 	{ 0x414c4740, 0x0f, 0, "ALC202", 	0 },
150 	{ 0x414c4720, 0x0f, 0, "ALC650", 	0 },
151 	{ 0x414c4752, 0x0f, 0, "ALC250",	0 },
152 	{ 0x414c4760, 0x0f, 0, "ALC655",	0 },
153 	{ 0x414c4770, 0x0f, 0, "ALC203",	0 },
154 	{ 0x414c4780, 0x0f, 0, "ALC658",	0 },
155 	{ 0x414c4790, 0x0f, 0, "ALC850",	0 },
156 	{ 0x43525900, 0x07, 0, "CS4297", 	0 },
157 	{ 0x43525910, 0x07, 0, "CS4297A", 	0 },
158 	{ 0x43525920, 0x07, 0, "CS4294/98",	0 },
159 	{ 0x4352592d, 0x07, 0, "CS4294",	0 },
160 	{ 0x43525930, 0x07, 0, "CS4299",	0 },
161 	{ 0x43525940, 0x07, 0, "CS4201",	0 },
162 	{ 0x43525958, 0x07, 0, "CS4205",	0 },
163 	{ 0x43525960, 0x07, 0, "CS4291A",	0 },
164 	{ 0x434d4961, 0x00, 0, "CMI9739",	cmi9739_patch },
165 	{ 0x434d4941, 0x00, 0, "CMI9738",	0 },
166 	{ 0x434d4978, 0x00, 0, "CMI9761",	0 },
167 	{ 0x434d4982, 0x00, 0, "CMI9761",	0 },
168 	{ 0x434d4983, 0x00, 0, "CMI9761",	0 },
169 	{ 0x43585421, 0x00, 0, "HSD11246",	0 },
170 	{ 0x43585428, 0x07, 0, "CX20468",	0 },
171 	{ 0x43585430, 0x00, 0, "CX20468-21",	0 },
172 	{ 0x44543000, 0x00, 0, "DT0398",	0 },
173 	{ 0x454d4323, 0x00, 0, "EM28023",	0 },
174 	{ 0x454d4328, 0x00, 0, "EM28028",	0 },
175 	{ 0x45838308, 0x00, 0, "ES1988",	0 }, /* Formerly ES1921(?) */
176 	{ 0x48525300, 0x00, 0, "HMP9701",	0 },
177 	{ 0x49434501, 0x00, 0, "ICE1230",	0 },
178 	{ 0x49434511, 0x00, 0, "ICE1232",	0 },
179 	{ 0x49434514, 0x00, 0, "ICE1232A",	0 },
180 	{ 0x49434551, 0x03, 0, "VT1616",	0 }, /* Via badged ICE */
181 	{ 0x49544520, 0x00, 0, "ITE2226E",	0 },
182 	{ 0x49544560, 0x07, 0, "ITE2646E",	0 }, /* XXX: patch needed */
183 	{ 0x4e534340, 0x00, 0, "LM4540",	0 }, /* Spec blank on revid */
184 	{ 0x4e534343, 0x00, 0, "LM4543",	0 }, /* Ditto */
185 	{ 0x4e534346, 0x00, 0, "LM4546A",	0 },
186 	{ 0x4e534348, 0x00, 0, "LM4548A",	0 },
187 	{ 0x4e534331, 0x00, 0, "LM4549",	0 },
188 	{ 0x4e534349, 0x00, 0, "LM4549A",	0 },
189 	{ 0x4e534350, 0x00, 0, "LM4550",	0 },
190 	{ 0x50534301, 0x00, 0, "UCB1510",	0 },
191 	{ 0x50534304, 0x00, 0, "UCB1400",	0 },
192 	{ 0x83847600, 0x00, 0, "STAC9700/83/84",	0 },
193 	{ 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
194 	{ 0x83847605, 0x00, 0, "STAC9704",	0 },
195 	{ 0x83847608, 0x00, 0, "STAC9708/11",	0 },
196 	{ 0x83847609, 0x00, 0, "STAC9721/23",	0 },
197 	{ 0x83847644, 0x00, 0, "STAC9744/45",	0 },
198 	{ 0x83847650, 0x00, 0, "STAC9750/51",	0 },
199 	{ 0x83847652, 0x00, 0, "STAC9752/53",	0 },
200 	{ 0x83847656, 0x00, 0, "STAC9756/57",	0 },
201 	{ 0x83847658, 0x00, 0, "STAC9758/59",	0 },
202 	{ 0x83847660, 0x00, 0, "STAC9760/61",	0 }, /* Extrapolated */
203 	{ 0x83847662, 0x00, 0, "STAC9762/63",	0 }, /* Extrapolated */
204 	{ 0x83847666, 0x00, 0, "STAC9766/67",	0 },
205 	{ 0x53494c22, 0x00, 0, "Si3036",	0 },
206 	{ 0x53494c23, 0x00, 0, "Si3038",	0 },
207 	{ 0x54524103, 0x00, 0, "TR28023",	0 }, /* Extrapolated */
208 	{ 0x54524106, 0x00, 0, "TR28026",	0 },
209 	{ 0x54524108, 0x00, 0, "TR28028",	0 },
210 	{ 0x54524123, 0x00, 0, "TR28602",	0 },
211 	{ 0x54524e03, 0x07, 0, "TLV320AIC27",	0 },
212 	{ 0x54584e20, 0x00, 0, "TLC320AD90",	0 },
213 	{ 0x56494161, 0x00, 0, "VIA1612A",      0 },
214 	{ 0x56494170, 0x00, 0, "VIA1617A",      0 },
215 	{ 0x574d4c00, 0x00, 0, "WM9701A",	0 },
216 	{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8",	0 },
217 	{ 0x574d4c04, 0x00, 0, "WM9704Q",	0 },
218 	{ 0x574d4c05, 0x00, 0, "WM9705/10",	0 },
219 	{ 0x574d4d09, 0x00, 0, "WM9709",	0 },
220 	{ 0x574d4c12, 0x00, 0, "WM9711/12",	0 }, /* XXX: patch needed */
221 	{ 0x57454301, 0x00, 0, "W83971D",	0 },
222 	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
223 	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
224 	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
225 	/*
226 	 * XXX This is a fluke, really! The real codec
227 	 * should be STAC9704, not this! This should be
228 	 * removed someday!
229 	 */
230 	{ 0x01408384, 0x00, 0, "EV1938",	0 },
231 	{ 0, 0, 0, NULL, 0 }
232 };
233 
234 static char *ac97enhancement[] = {
235 	"no 3D Stereo Enhancement",
236 	"Analog Devices Phat Stereo",
237 	"Creative Stereo Enhancement",
238 	"National Semi 3D Stereo Enhancement",
239 	"Yamaha Ymersion",
240 	"BBE 3D Stereo Enhancement",
241 	"Crystal Semi 3D Stereo Enhancement",
242 	"Qsound QXpander",
243 	"Spatializer 3D Stereo Enhancement",
244 	"SRS 3D Stereo Enhancement",
245 	"Platform Tech 3D Stereo Enhancement",
246 	"AKM 3D Audio",
247 	"Aureal Stereo Enhancement",
248 	"Aztech 3D Enhancement",
249 	"Binaura 3D Audio Enhancement",
250 	"ESS Technology Stereo Enhancement",
251 	"Harman International VMAx",
252 	"Nvidea 3D Stereo Enhancement",
253 	"Philips Incredible Sound",
254 	"Texas Instruments 3D Stereo Enhancement",
255 	"VLSI Technology 3D Stereo Enhancement",
256 	"TriTech 3D Stereo Enhancement",
257 	"Realtek 3D Stereo Enhancement",
258 	"Samsung 3D Stereo Enhancement",
259 	"Wolfson Microelectronics 3D Enhancement",
260 	"Delta Integration 3D Enhancement",
261 	"SigmaTel 3D Enhancement",
262 	"Reserved 27",
263 	"Rockwell 3D Stereo Enhancement",
264 	"Reserved 29",
265 	"Reserved 30",
266 	"Reserved 31"
267 };
268 
269 static char *ac97feature[] = {
270 	"mic channel",
271 	"reserved",
272 	"tone",
273 	"simulated stereo",
274 	"headphone",
275 	"bass boost",
276 	"18 bit DAC",
277 	"20 bit DAC",
278 	"18 bit ADC",
279 	"20 bit ADC"
280 };
281 
282 static char *ac97extfeature[] = {
283 	"variable rate PCM",
284 	"double rate PCM",
285 	"reserved 1",
286 	"variable rate mic",
287 	"reserved 2",
288 	"reserved 3",
289 	"center DAC",
290 	"surround DAC",
291 	"LFE DAC",
292 	"AMAP",
293 	"reserved 4",
294 	"reserved 5",
295 	"reserved 6",
296 	"reserved 7",
297 };
298 
299 u_int16_t
300 ac97_rdcd(struct ac97_info *codec, int reg)
301 {
302 	if (codec->flags & AC97_F_RDCD_BUG) {
303 		u_int16_t i[2], j = 100;
304 
305 		i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
306 		i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
307 		while (i[0] != i[1] && j)
308 			i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
309 #if 0
310 		if (j < 100) {
311 			device_printf(codec->dev, "%s(): Inconsistent register value at"
312 					" 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
313 		}
314 #endif
315 		return i[!(j & 1)];
316 	}
317 	return AC97_READ(codec->methods, codec->devinfo, reg);
318 }
319 
320 void
321 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
322 {
323 	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
324 }
325 
326 static void
327 ac97_reset(struct ac97_info *codec)
328 {
329 	u_int32_t i, ps;
330 	ac97_wrcd(codec, AC97_REG_RESET, 0);
331 	for (i = 0; i < 500; i++) {
332 		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
333 		if (ps == AC97_POWER_STATUS)
334 			return;
335 		DELAY(1000);
336 	}
337 	device_printf(codec->dev, "AC97 reset timed out.\n");
338 }
339 
340 int
341 ac97_setrate(struct ac97_info *codec, int which, int rate)
342 {
343 	u_int16_t v;
344 
345 	switch(which) {
346 	case AC97_REGEXT_FDACRATE:
347 	case AC97_REGEXT_SDACRATE:
348 	case AC97_REGEXT_LDACRATE:
349 	case AC97_REGEXT_LADCRATE:
350 	case AC97_REGEXT_MADCRATE:
351 		break;
352 
353 	default:
354 		return -1;
355 	}
356 
357 	snd_mtxlock(codec->lock);
358 	if (rate != 0) {
359 		v = rate;
360 		if (codec->extstat & AC97_EXTCAP_DRA)
361 			v >>= 1;
362 		ac97_wrcd(codec, which, v);
363 	}
364 	v = ac97_rdcd(codec, which);
365 	if (codec->extstat & AC97_EXTCAP_DRA)
366 		v <<= 1;
367 	snd_mtxunlock(codec->lock);
368 	return v;
369 }
370 
371 int
372 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
373 {
374 	mode &= AC97_EXTCAPS;
375 	if ((mode & ~codec->extcaps) != 0) {
376 		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
377 			      mode);
378 		return -1;
379 	}
380 	snd_mtxlock(codec->lock);
381 	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
382 	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
383 	snd_mtxunlock(codec->lock);
384 	return (mode == codec->extstat)? 0 : -1;
385 }
386 
387 u_int16_t
388 ac97_getextmode(struct ac97_info *codec)
389 {
390 	return codec->extstat;
391 }
392 
393 u_int16_t
394 ac97_getextcaps(struct ac97_info *codec)
395 {
396 	return codec->extcaps;
397 }
398 
399 u_int16_t
400 ac97_getcaps(struct ac97_info *codec)
401 {
402 	return codec->caps;
403 }
404 
405 static int
406 ac97_setrecsrc(struct ac97_info *codec, int channel)
407 {
408 	struct ac97mixtable_entry *e = &codec->mix[channel];
409 
410 	if (e->recidx > 0) {
411 		int val = e->recidx - 1;
412 		val |= val << 8;
413 		snd_mtxlock(codec->lock);
414 		ac97_wrcd(codec, AC97_REG_RECSEL, val);
415 		snd_mtxunlock(codec->lock);
416 		return 0;
417 	} else
418 		return -1;
419 }
420 
421 static int
422 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
423 {
424 	struct ac97mixtable_entry *e = &codec->mix[channel];
425 
426 	if (e->reg && e->enable && e->bits) {
427 		int mask, max, val, reg;
428 
429 		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
430 		max = (1 << e->bits) - 1;		/* actual range	    */
431 		mask = (max << 8) | max;		/* bits of interest */
432 
433 		if (!e->stereo)
434 			right = left;
435 
436 		/*
437 		 * Invert the range if the polarity requires so,
438 		 * then scale to 0..max-1 to compute the value to
439 		 * write into the codec, and scale back to 0..100
440 		 * for the return value.
441 		 */
442 		if (e->reg > 0) {
443 			left = 100 - left;
444 			right = 100 - right;
445 		}
446 
447 		left = (left * max) / 100;
448 		right = (right * max) / 100;
449 
450 		val = (left << 8) | right;
451 
452 		left = (left * 100) / max;
453 		right = (right * 100) / max;
454 
455 		if (e->reg > 0) {
456 			left = 100 - left;
457 			right = 100 - right;
458 		}
459 
460 		/*
461 		 * For mono controls, trim val and mask, also taking
462 		 * care of e->ofs (offset of control field).
463 		 */
464 		if (e->ofs) {
465 			val &= max;
466 			val <<= e->ofs;
467 			mask = (max << e->ofs);
468 		}
469 
470 		/*
471 		 * If we have a mute bit, add it to the mask and
472 		 * update val and set mute if both channels require a
473 		 * zero volume.
474 		 */
475 		if (e->mute == 1) {
476 			mask |= AC97_MUTE;
477 			if (left == 0 && right == 0)
478 				val = AC97_MUTE;
479 		}
480 
481 		/*
482 		 * If the mask bit is set, do not alter the other bits.
483 		 */
484 		snd_mtxlock(codec->lock);
485 		if (e->mask) {
486 			int cur = ac97_rdcd(codec, reg);
487 			val |= cur & ~(mask);
488 		}
489 		ac97_wrcd(codec, reg, val);
490 		snd_mtxunlock(codec->lock);
491 		return left | (right << 8);
492 	} else {
493 #if 0
494 		printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
495 #endif
496 		return -1;
497 	}
498 }
499 
500 static void
501 ac97_fix_auxout(struct ac97_info *codec)
502 {
503 	int keep_ogain;
504 
505 	/*
506 	 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
507 	 * OGAIN setting.
508 	 *
509 	 * We first check whether aux_out is a valid register.  If not
510 	 * we may not want to keep ogain.
511 	 */
512 	keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
513 
514 	/*
515 	 * Determine what AUX_OUT really means, it can be:
516 	 *
517 	 * 1. Headphone out.
518 	 * 2. 4-Channel Out
519 	 * 3. True line level out (effectively master volume).
520 	 *
521 	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
522 	 */
523 	if (codec->extcaps & AC97_EXTCAP_SDAC &&
524 	    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
525 		codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
526 		keep_ogain = 1;
527 	}
528 
529 	if (keep_ogain == 0) {
530 		bzero(&codec->mix[SOUND_MIXER_OGAIN],
531 		      sizeof(codec->mix[SOUND_MIXER_OGAIN]));
532 	}
533 }
534 
535 static void
536 ac97_fix_tone(struct ac97_info *codec)
537 {
538 	/* Hide treble and bass if they don't exist */
539 	if ((codec->caps & AC97_CAP_TONE) == 0) {
540 		bzero(&codec->mix[SOUND_MIXER_BASS],
541 		      sizeof(codec->mix[SOUND_MIXER_BASS]));
542 		bzero(&codec->mix[SOUND_MIXER_TREBLE],
543 		      sizeof(codec->mix[SOUND_MIXER_TREBLE]));
544 	}
545 }
546 
547 static void
548 ac97_fix_volume(struct ac97_info *codec)
549 {
550     	struct snddev_info *d = device_get_softc(codec->dev);
551 
552 #if 0
553 	/* XXX For the sake of debugging purposes */
554 	ac97_wrcd(codec, AC97_MIX_PCM, 0);
555 	bzero(&codec->mix[SOUND_MIXER_PCM],
556 		sizeof(codec->mix[SOUND_MIXER_PCM]));
557 	codec->flags |= AC97_F_SOFTVOL;
558 	if (d)
559 		d->flags |= SD_F_SOFTVOL;
560 	return;
561 #endif
562 	switch (codec->id) {
563 		case 0x434d4941:	/* CMI9738 */
564 		case 0x434d4961:	/* CMI9739 */
565 		case 0x434d4978:	/* CMI9761 */
566 		case 0x434d4982:	/* CMI9761 */
567 		case 0x434d4983:	/* CMI9761 */
568 			ac97_wrcd(codec, AC97_MIX_PCM, 0);
569 			break;
570 		default:
571 			return;
572 			break;
573 	}
574 	bzero(&codec->mix[SOUND_MIXER_PCM],
575 			sizeof(codec->mix[SOUND_MIXER_PCM]));
576 	codec->flags |= AC97_F_SOFTVOL;
577 	if (d)
578 		d->flags |= SD_F_SOFTVOL;
579 }
580 
581 static const char*
582 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
583 {
584 	if (cname == NULL) {
585 		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
586 		return buf;
587 	}
588 
589 	if (vname == NULL) vname = "Unknown";
590 
591 	if (bootverbose) {
592 		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
593 	} else {
594 		sprintf(buf, "%s %s AC97 Codec", vname, cname);
595 	}
596 	return buf;
597 }
598 
599 static unsigned
600 ac97_initmixer(struct ac97_info *codec)
601 {
602 	ac97_patch codec_patch;
603 	const char *cname, *vname;
604 	char desc[80];
605 	u_int8_t model, step;
606 	unsigned i, j, k, bit, old;
607 	u_int32_t id;
608 	int reg;
609 
610 	snd_mtxlock(codec->lock);
611 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
612 	if (codec->count == 0) {
613 		device_printf(codec->dev, "ac97 codec init failed\n");
614 		snd_mtxunlock(codec->lock);
615 		return ENODEV;
616 	}
617 
618 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
619 	ac97_reset(codec);
620 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
621 
622 	i = ac97_rdcd(codec, AC97_REG_RESET);
623 	j = ac97_rdcd(codec, AC97_REG_RESET);
624 	/*
625 	 * Let see if this codec can return consistent value.
626 	 * If not, turn on aggressive read workaround
627 	 * (STAC9704 comes in mind).
628 	 */
629 	if (i != j) {
630 		codec->flags |= AC97_F_RDCD_BUG;
631 		i = ac97_rdcd(codec, AC97_REG_RESET);
632 	}
633 	codec->caps = i & 0x03ff;
634 	codec->se =  (i & 0x7c00) >> 10;
635 
636 	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
637 	if (id == 0 || id == 0xffffffff) {
638 		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
639 		snd_mtxunlock(codec->lock);
640 		return ENODEV;
641 	}
642 
643 	codec->id = id;
644 	codec->noext = 0;
645 	codec_patch = NULL;
646 
647 	cname = NULL;
648 	model = step = 0;
649 	for (i = 0; ac97codecid[i].id; i++) {
650 		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
651 		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
652 			codec->noext = ac97codecid[i].noext;
653 			codec_patch = ac97codecid[i].patch;
654 			cname = ac97codecid[i].name;
655 			model = (id & modelmask) & 0xff;
656 			step = (id & ~modelmask) & 0xff;
657 			break;
658 		}
659 	}
660 
661 	vname = NULL;
662 	for (i = 0; ac97vendorid[i].id; i++) {
663 		if (ac97vendorid[i].id == (id & 0xffffff00)) {
664 			vname = ac97vendorid[i].name;
665 			break;
666 		}
667 	}
668 
669 	codec->extcaps = 0;
670 	codec->extid = 0;
671 	codec->extstat = 0;
672 	if (!codec->noext) {
673 		i = ac97_rdcd(codec, AC97_REGEXT_ID);
674 		if (i != 0xffff) {
675 			codec->extcaps = i & 0x3fff;
676 			codec->extid =  (i & 0xc000) >> 14;
677 			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
678 		}
679 	}
680 
681 	for (i = 0; i < 32; i++) {
682 		codec->mix[i] = ac97mixtable_default[i];
683 	}
684 	ac97_fix_auxout(codec);
685 	ac97_fix_tone(codec);
686 	ac97_fix_volume(codec);
687 	if (codec_patch)
688 		codec_patch(codec);
689 
690 	for (i = 0; i < 32; i++) {
691 		k = codec->noext? codec->mix[i].enable : 1;
692 		reg = codec->mix[i].reg;
693 		if (reg < 0)
694 			reg = -reg;
695 		if (k && reg) {
696 			j = old = ac97_rdcd(codec, reg);
697 			/*
698 			 * Test for mute bit (except for AC97_MIX_TONE,
699 			 * where we simply assume it as available).
700 			 */
701 			if (codec->mix[i].mute) {
702 				ac97_wrcd(codec, reg, j | 0x8000);
703 				j = ac97_rdcd(codec, reg);
704 			} else
705 				j |= 0x8000;
706 			if ((j & 0x8000)) {
707 				/*
708 				 * Test whether the control width should be
709 				 * 4, 5 or 6 bit. For 5bit register, we should
710 				 * test it whether it's really 5 or 6bit. Leave
711 				 * 4bit register alone, because sometimes an
712 				 * attempt to write past 4th bit may cause
713 				 * incorrect result especially for AC97_MIX_BEEP
714 				 * (ac97 2.3).
715 				 */
716 				bit = codec->mix[i].bits;
717 				if (bit == 5)
718 					bit++;
719 				j = ((1 << bit) - 1) << codec->mix[i].ofs;
720 				ac97_wrcd(codec, reg,
721 					j | (codec->mix[i].mute ? 0x8000 : 0));
722 				k = ac97_rdcd(codec, reg) & j;
723 				k >>= codec->mix[i].ofs;
724 				if (reg == AC97_MIX_TONE &&
725 							((k & 0x0001) == 0x0000))
726 					k >>= 1;
727 				for (j = 0; k >> j; j++)
728 					;
729 				if (j != 0) {
730 #if 0
731 					device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
732 						i, k, bit, codec->mix[i].bits, j);
733 #endif
734 					codec->mix[i].enable = 1;
735 					codec->mix[i].bits = j;
736 				} else
737 					codec->mix[i].enable = 0;
738 			} else
739 				codec->mix[i].enable = 0;
740 			ac97_wrcd(codec, reg, old);
741 		}
742 #if 0
743 		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
744 #endif
745 	}
746 
747 	device_printf(codec->dev, "<%s>\n",
748 		      ac97_hw_desc(codec->id, vname, cname, desc));
749 
750 	if (bootverbose) {
751 		if (codec->flags & AC97_F_RDCD_BUG)
752 			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
753 		if (codec->flags & AC97_F_SOFTVOL)
754 			device_printf(codec->dev, "Soft PCM volume\n");
755 		device_printf(codec->dev, "Codec features ");
756 		for (i = j = 0; i < 10; i++)
757 			if (codec->caps & (1 << i))
758 				printf("%s%s", j++? ", " : "", ac97feature[i]);
759 		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
760 		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
761 
762 		if (codec->extcaps != 0 || codec->extid) {
763 			device_printf(codec->dev, "%s codec",
764 				      codec->extid? "Secondary" : "Primary");
765 			if (codec->extcaps)
766 				printf(" extended features ");
767 			for (i = j = 0; i < 14; i++)
768 				if (codec->extcaps & (1 << i))
769 					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
770 			printf("\n");
771 		}
772 	}
773 
774 	i = 0;
775 	while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
776 		if (++i == 100) {
777 			device_printf(codec->dev, "ac97 codec reports dac not ready\n");
778 			break;
779 		}
780 		DELAY(1000);
781 	}
782 	if (bootverbose)
783 		device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
784 	snd_mtxunlock(codec->lock);
785 	return 0;
786 }
787 
788 static unsigned
789 ac97_reinitmixer(struct ac97_info *codec)
790 {
791 	snd_mtxlock(codec->lock);
792 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
793 	if (codec->count == 0) {
794 		device_printf(codec->dev, "ac97 codec init failed\n");
795 		snd_mtxunlock(codec->lock);
796 		return ENODEV;
797 	}
798 
799 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
800 	ac97_reset(codec);
801 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
802 
803 	if (!codec->noext) {
804 		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
805 		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
806 		    != codec->extstat)
807 			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
808 				      codec->extstat,
809 				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
810 				      AC97_EXTCAPS);
811 	}
812 
813 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
814 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
815 	snd_mtxunlock(codec->lock);
816 	return 0;
817 }
818 
819 struct ac97_info *
820 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
821 {
822 	struct ac97_info *codec;
823 
824 	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
825 	if (codec == NULL)
826 		return NULL;
827 
828 	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
829 	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
830 	codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
831 	if (codec->methods == NULL) {
832 		snd_mtxlock(codec->lock);
833 		snd_mtxfree(codec->lock);
834 		free(codec, M_AC97);
835 		return NULL;
836 	}
837 
838 	codec->dev = dev;
839 	codec->devinfo = devinfo;
840 	codec->flags = 0;
841 	return codec;
842 }
843 
844 void
845 ac97_destroy(struct ac97_info *codec)
846 {
847 	snd_mtxlock(codec->lock);
848 	if (codec->methods != NULL)
849 		kobj_delete(codec->methods, M_AC97);
850 	snd_mtxfree(codec->lock);
851 	free(codec, M_AC97);
852 }
853 
854 void
855 ac97_setflags(struct ac97_info *codec, u_int32_t val)
856 {
857 	codec->flags = val;
858 }
859 
860 u_int32_t
861 ac97_getflags(struct ac97_info *codec)
862 {
863 	return codec->flags;
864 }
865 
866 /* -------------------------------------------------------------------- */
867 
868 static int
869 ac97mix_init(struct snd_mixer *m)
870 {
871 	struct ac97_info *codec = mix_getdevinfo(m);
872 	u_int32_t i, mask;
873 
874 	if (codec == NULL)
875 		return -1;
876 
877 	if (ac97_initmixer(codec))
878 		return -1;
879 
880 	mask = 0;
881 	for (i = 0; i < 32; i++)
882 		mask |= codec->mix[i].enable? 1 << i : 0;
883 	mix_setdevs(m, mask);
884 
885 	mask = 0;
886 	for (i = 0; i < 32; i++)
887 		mask |= codec->mix[i].recidx? 1 << i : 0;
888 	mix_setrecdevs(m, mask);
889 	return 0;
890 }
891 
892 static int
893 ac97mix_uninit(struct snd_mixer *m)
894 {
895 	struct ac97_info *codec = mix_getdevinfo(m);
896 
897 	if (codec == NULL)
898 		return -1;
899 	/*
900 	if (ac97_uninitmixer(codec))
901 		return -1;
902 	*/
903 	ac97_destroy(codec);
904 	return 0;
905 }
906 
907 static int
908 ac97mix_reinit(struct snd_mixer *m)
909 {
910 	struct ac97_info *codec = mix_getdevinfo(m);
911 
912 	if (codec == NULL)
913 		return -1;
914 	return ac97_reinitmixer(codec);
915 }
916 
917 static int
918 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
919 {
920 	struct ac97_info *codec = mix_getdevinfo(m);
921 
922 	if (codec == NULL)
923 		return -1;
924 	return ac97_setmixer(codec, dev, left, right);
925 }
926 
927 static int
928 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
929 {
930 	int i;
931 	struct ac97_info *codec = mix_getdevinfo(m);
932 
933 	if (codec == NULL)
934 		return -1;
935 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
936 		if ((src & (1 << i)) != 0)
937 			break;
938 	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
939 }
940 
941 static kobj_method_t ac97mixer_methods[] = {
942     	KOBJMETHOD(mixer_init,		ac97mix_init),
943     	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
944     	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
945     	KOBJMETHOD(mixer_set,		ac97mix_set),
946     	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
947 	{ 0, 0 }
948 };
949 MIXER_DECLARE(ac97mixer);
950 
951 /* -------------------------------------------------------------------- */
952 
953 kobj_class_t
954 ac97_getmixerclass(void)
955 {
956 	return &ac97mixer_class;
957 }
958 
959 
960