ac97.c revision 154094
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
33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 154094 2006-01-07 05:20:46Z ariff $");
34
35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36
37struct 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
50struct 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
62struct ac97_vendorid {
63	u_int32_t   id;
64	const char *name;
65};
66
67struct 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
75static 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
95static 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
128static 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	{ 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
235static 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
270static 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
283static 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
300u_int16_t
301ac97_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
321void
322ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
323{
324	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
325}
326
327static void
328ac97_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
341int
342ac97_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
372int
373ac97_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
388u_int16_t
389ac97_getextmode(struct ac97_info *codec)
390{
391	return codec->extstat;
392}
393
394u_int16_t
395ac97_getextcaps(struct ac97_info *codec)
396{
397	return codec->extcaps;
398}
399
400u_int16_t
401ac97_getcaps(struct ac97_info *codec)
402{
403	return codec->caps;
404}
405
406static int
407ac97_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
422static int
423ac97_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
501static void
502ac97_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
536static void
537ac97_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
548static void
549ac97_fix_volume(struct ac97_info *codec)
550{
551    	struct snddev_info *d = device_get_softc(codec->dev);
552
553#if 0
554	/* XXX For the sake of debugging purposes */
555	ac97_wrcd(codec, AC97_MIX_PCM, 0);
556	bzero(&codec->mix[SOUND_MIXER_PCM],
557		sizeof(codec->mix[SOUND_MIXER_PCM]));
558	codec->flags |= AC97_F_SOFTVOL;
559	if (d)
560		d->flags |= SD_F_SOFTVOL;
561	return;
562#endif
563	switch (codec->id) {
564		case 0x434d4941:	/* CMI9738 */
565		case 0x434d4961:	/* CMI9739 */
566		case 0x434d4978:	/* CMI9761 */
567		case 0x434d4982:	/* CMI9761 */
568		case 0x434d4983:	/* CMI9761 */
569			ac97_wrcd(codec, AC97_MIX_PCM, 0);
570			break;
571		default:
572			return;
573			break;
574	}
575	bzero(&codec->mix[SOUND_MIXER_PCM],
576			sizeof(codec->mix[SOUND_MIXER_PCM]));
577	codec->flags |= AC97_F_SOFTVOL;
578	if (d)
579		d->flags |= SD_F_SOFTVOL;
580}
581
582static const char*
583ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
584{
585	if (cname == NULL) {
586		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
587		return buf;
588	}
589
590	if (vname == NULL) vname = "Unknown";
591
592	if (bootverbose) {
593		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
594	} else {
595		sprintf(buf, "%s %s AC97 Codec", vname, cname);
596	}
597	return buf;
598}
599
600static unsigned
601ac97_initmixer(struct ac97_info *codec)
602{
603	ac97_patch codec_patch;
604	const char *cname, *vname;
605	char desc[80];
606	u_int8_t model, step;
607	unsigned i, j, k, bit, old;
608	u_int32_t id;
609	int reg;
610
611	snd_mtxlock(codec->lock);
612	codec->count = AC97_INIT(codec->methods, codec->devinfo);
613	if (codec->count == 0) {
614		device_printf(codec->dev, "ac97 codec init failed\n");
615		snd_mtxunlock(codec->lock);
616		return ENODEV;
617	}
618
619	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
620	ac97_reset(codec);
621	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
622
623	i = ac97_rdcd(codec, AC97_REG_RESET);
624	j = ac97_rdcd(codec, AC97_REG_RESET);
625	/*
626	 * Let see if this codec can return consistent value.
627	 * If not, turn on aggressive read workaround
628	 * (STAC9704 comes in mind).
629	 */
630	if (i != j) {
631		codec->flags |= AC97_F_RDCD_BUG;
632		i = ac97_rdcd(codec, AC97_REG_RESET);
633	}
634	codec->caps = i & 0x03ff;
635	codec->se =  (i & 0x7c00) >> 10;
636
637	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
638	if (id == 0 || id == 0xffffffff) {
639		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
640		snd_mtxunlock(codec->lock);
641		return ENODEV;
642	}
643
644	codec->id = id;
645	codec->noext = 0;
646	codec_patch = NULL;
647
648	cname = NULL;
649	model = step = 0;
650	for (i = 0; ac97codecid[i].id; i++) {
651		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
652		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
653			codec->noext = ac97codecid[i].noext;
654			codec_patch = ac97codecid[i].patch;
655			cname = ac97codecid[i].name;
656			model = (id & modelmask) & 0xff;
657			step = (id & ~modelmask) & 0xff;
658			break;
659		}
660	}
661
662	vname = NULL;
663	for (i = 0; ac97vendorid[i].id; i++) {
664		if (ac97vendorid[i].id == (id & 0xffffff00)) {
665			vname = ac97vendorid[i].name;
666			break;
667		}
668	}
669
670	codec->extcaps = 0;
671	codec->extid = 0;
672	codec->extstat = 0;
673	if (!codec->noext) {
674		i = ac97_rdcd(codec, AC97_REGEXT_ID);
675		if (i != 0xffff) {
676			codec->extcaps = i & 0x3fff;
677			codec->extid =  (i & 0xc000) >> 14;
678			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
679		}
680	}
681
682	for (i = 0; i < 32; i++) {
683		codec->mix[i] = ac97mixtable_default[i];
684	}
685	ac97_fix_auxout(codec);
686	ac97_fix_tone(codec);
687	ac97_fix_volume(codec);
688	if (codec_patch)
689		codec_patch(codec);
690
691	for (i = 0; i < 32; i++) {
692		k = codec->noext? codec->mix[i].enable : 1;
693		reg = codec->mix[i].reg;
694		if (reg < 0)
695			reg = -reg;
696		if (k && reg) {
697			j = old = ac97_rdcd(codec, reg);
698			/*
699			 * Test for mute bit (except for AC97_MIX_TONE,
700			 * where we simply assume it as available).
701			 */
702			if (codec->mix[i].mute) {
703				ac97_wrcd(codec, reg, j | 0x8000);
704				j = ac97_rdcd(codec, reg);
705			} else
706				j |= 0x8000;
707			if ((j & 0x8000)) {
708				/*
709				 * Test whether the control width should be
710				 * 4, 5 or 6 bit. For 5bit register, we should
711				 * test it whether it's really 5 or 6bit. Leave
712				 * 4bit register alone, because sometimes an
713				 * attempt to write past 4th bit may cause
714				 * incorrect result especially for AC97_MIX_BEEP
715				 * (ac97 2.3).
716				 */
717				bit = codec->mix[i].bits;
718				if (bit == 5)
719					bit++;
720				j = ((1 << bit) - 1) << codec->mix[i].ofs;
721				ac97_wrcd(codec, reg,
722					j | (codec->mix[i].mute ? 0x8000 : 0));
723				k = ac97_rdcd(codec, reg) & j;
724				k >>= codec->mix[i].ofs;
725				if (reg == AC97_MIX_TONE &&
726							((k & 0x0001) == 0x0000))
727					k >>= 1;
728				for (j = 0; k >> j; j++)
729					;
730				if (j != 0) {
731#if 0
732					device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
733						i, k, bit, codec->mix[i].bits, j);
734#endif
735					codec->mix[i].enable = 1;
736					codec->mix[i].bits = j;
737				} else if (reg == AC97_MIX_BEEP) {
738					/*
739					 * Few codec such as CX20468-21 does
740					 * have this control register, although
741					 * the only usable part is the mute bit.
742					 */
743					codec->mix[i].enable = 1;
744				} else
745					codec->mix[i].enable = 0;
746			} else
747				codec->mix[i].enable = 0;
748			ac97_wrcd(codec, reg, old);
749		}
750#if 0
751		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
752#endif
753	}
754
755	device_printf(codec->dev, "<%s>\n",
756		      ac97_hw_desc(codec->id, vname, cname, desc));
757
758	if (bootverbose) {
759		if (codec->flags & AC97_F_RDCD_BUG)
760			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
761		if (codec->flags & AC97_F_SOFTVOL)
762			device_printf(codec->dev, "Soft PCM volume\n");
763		device_printf(codec->dev, "Codec features ");
764		for (i = j = 0; i < 10; i++)
765			if (codec->caps & (1 << i))
766				printf("%s%s", j++? ", " : "", ac97feature[i]);
767		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
768		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
769
770		if (codec->extcaps != 0 || codec->extid) {
771			device_printf(codec->dev, "%s codec",
772				      codec->extid? "Secondary" : "Primary");
773			if (codec->extcaps)
774				printf(" extended features ");
775			for (i = j = 0; i < 14; i++)
776				if (codec->extcaps & (1 << i))
777					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
778			printf("\n");
779		}
780	}
781
782	i = 0;
783	while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
784		if (++i == 100) {
785			device_printf(codec->dev, "ac97 codec reports dac not ready\n");
786			break;
787		}
788		DELAY(1000);
789	}
790	if (bootverbose)
791		device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
792	snd_mtxunlock(codec->lock);
793	return 0;
794}
795
796static unsigned
797ac97_reinitmixer(struct ac97_info *codec)
798{
799	snd_mtxlock(codec->lock);
800	codec->count = AC97_INIT(codec->methods, codec->devinfo);
801	if (codec->count == 0) {
802		device_printf(codec->dev, "ac97 codec init failed\n");
803		snd_mtxunlock(codec->lock);
804		return ENODEV;
805	}
806
807	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
808	ac97_reset(codec);
809	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
810
811	if (!codec->noext) {
812		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
813		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
814		    != codec->extstat)
815			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
816				      codec->extstat,
817				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
818				      AC97_EXTCAPS);
819	}
820
821	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
822		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
823	snd_mtxunlock(codec->lock);
824	return 0;
825}
826
827struct ac97_info *
828ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
829{
830	struct ac97_info *codec;
831
832	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
833	if (codec == NULL)
834		return NULL;
835
836	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
837	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
838	codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
839	if (codec->methods == NULL) {
840		snd_mtxlock(codec->lock);
841		snd_mtxfree(codec->lock);
842		free(codec, M_AC97);
843		return NULL;
844	}
845
846	codec->dev = dev;
847	codec->devinfo = devinfo;
848	codec->flags = 0;
849	return codec;
850}
851
852void
853ac97_destroy(struct ac97_info *codec)
854{
855	snd_mtxlock(codec->lock);
856	if (codec->methods != NULL)
857		kobj_delete(codec->methods, M_AC97);
858	snd_mtxfree(codec->lock);
859	free(codec, M_AC97);
860}
861
862void
863ac97_setflags(struct ac97_info *codec, u_int32_t val)
864{
865	codec->flags = val;
866}
867
868u_int32_t
869ac97_getflags(struct ac97_info *codec)
870{
871	return codec->flags;
872}
873
874/* -------------------------------------------------------------------- */
875
876static int
877ac97mix_init(struct snd_mixer *m)
878{
879	struct ac97_info *codec = mix_getdevinfo(m);
880	u_int32_t i, mask;
881
882	if (codec == NULL)
883		return -1;
884
885	if (ac97_initmixer(codec))
886		return -1;
887
888	mask = 0;
889	for (i = 0; i < 32; i++)
890		mask |= codec->mix[i].enable? 1 << i : 0;
891	mix_setdevs(m, mask);
892
893	mask = 0;
894	for (i = 0; i < 32; i++)
895		mask |= codec->mix[i].recidx? 1 << i : 0;
896	mix_setrecdevs(m, mask);
897	return 0;
898}
899
900static int
901ac97mix_uninit(struct snd_mixer *m)
902{
903	struct ac97_info *codec = mix_getdevinfo(m);
904
905	if (codec == NULL)
906		return -1;
907	/*
908	if (ac97_uninitmixer(codec))
909		return -1;
910	*/
911	ac97_destroy(codec);
912	return 0;
913}
914
915static int
916ac97mix_reinit(struct snd_mixer *m)
917{
918	struct ac97_info *codec = mix_getdevinfo(m);
919
920	if (codec == NULL)
921		return -1;
922	return ac97_reinitmixer(codec);
923}
924
925static int
926ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
927{
928	struct ac97_info *codec = mix_getdevinfo(m);
929
930	if (codec == NULL)
931		return -1;
932	return ac97_setmixer(codec, dev, left, right);
933}
934
935static int
936ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
937{
938	int i;
939	struct ac97_info *codec = mix_getdevinfo(m);
940
941	if (codec == NULL)
942		return -1;
943	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
944		if ((src & (1 << i)) != 0)
945			break;
946	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
947}
948
949static kobj_method_t ac97mixer_methods[] = {
950    	KOBJMETHOD(mixer_init,		ac97mix_init),
951    	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
952    	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
953    	KOBJMETHOD(mixer_set,		ac97mix_set),
954    	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
955	{ 0, 0 }
956};
957MIXER_DECLARE(ac97mixer);
958
959/* -------------------------------------------------------------------- */
960
961kobj_class_t
962ac97_getmixerclass(void)
963{
964	return &ac97mixer_class;
965}
966
967
968