ac97.c revision 152939
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 152939 2005-11-30 01:44:22Z yongari $");
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	{ 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
234static 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
269static 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
282static 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
299u_int16_t
300ac97_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
320void
321ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
322{
323	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
324}
325
326static void
327ac97_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
340int
341ac97_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
371int
372ac97_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
387u_int16_t
388ac97_getextmode(struct ac97_info *codec)
389{
390	return codec->extstat;
391}
392
393u_int16_t
394ac97_getextcaps(struct ac97_info *codec)
395{
396	return codec->extcaps;
397}
398
399u_int16_t
400ac97_getcaps(struct ac97_info *codec)
401{
402	return codec->caps;
403}
404
405static int
406ac97_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
421static int
422ac97_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
500static void
501ac97_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
535static void
536ac97_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
547static void
548ac97_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
581static const char*
582ac97_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
599static unsigned
600ac97_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
788static unsigned
789ac97_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
819struct ac97_info *
820ac97_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
844void
845ac97_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
854void
855ac97_setflags(struct ac97_info *codec, u_int32_t val)
856{
857	codec->flags = val;
858}
859
860u_int32_t
861ac97_getflags(struct ac97_info *codec)
862{
863	return codec->flags;
864}
865
866/* -------------------------------------------------------------------- */
867
868static int
869ac97mix_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
892static int
893ac97mix_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
907static int
908ac97mix_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
917static int
918ac97mix_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
927static int
928ac97mix_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
941static 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};
949MIXER_DECLARE(ac97mixer);
950
951/* -------------------------------------------------------------------- */
952
953kobj_class_t
954ac97_getmixerclass(void)
955{
956	return &ac97mixer_class;
957}
958
959
960