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