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