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