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