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