xref: /dragonfly/sys/dev/sound/pcm/ac97.c (revision 17b61719)
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.49 2003/11/11 22:15:17 kuriyama Exp $
27  * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.19 2004/07/16 08:13:28 asmodai Exp $
28  */
29 
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pcm/ac97_patch.h>
33 
34 #include "mixer_if.h"
35 
36 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.19 2004/07/16 08:13:28 asmodai Exp $");
37 
38 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
39 
40 struct ac97mixtable_entry {
41 	int	 reg:8;		/* register index		*/
42 				/* reg < 0 if inverted polarity	*/
43 	unsigned bits:4;	/* width of control field	*/
44 	unsigned ofs:4;		/* offset (only if stereo=0)	*/
45 	unsigned stereo:1;	/* set for stereo controls	*/
46 	unsigned mute:1;	/* bit15 is MUTE		*/
47 	unsigned recidx:4;	/* index in rec mux		*/
48 	unsigned mask:1;	/* use only masked bits		*/
49 	unsigned enable:1;	/* entry is enabled		*/
50 };
51 
52 #define AC97_NAMELEN	16
53 struct ac97_info {
54 	kobj_t methods;
55 	device_t dev;
56 	void *devinfo;
57 	u_int32_t id;
58 	unsigned count, caps, se, extcaps, extid, extstat, noext:1;
59 	u_int32_t flags;
60 	struct ac97mixtable_entry mix[32];
61 	char name[AC97_NAMELEN];
62 	struct mtx *lock;
63 };
64 
65 struct ac97_vendorid {
66 	u_int32_t   id;
67 	const char *name;
68 };
69 
70 struct ac97_codecid {
71 	u_int32_t  id;
72 	u_int8_t   stepmask;
73 	u_int8_t   noext:1;
74 	char 	  *name;
75 	ac97_patch patch;
76 };
77 
78 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
79     /*	[offset]			reg	     bits of st mu re mk en */
80 	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
81 	[SOUND_MIXER_OGAIN]	= { AC97_MIX_AUXOUT, 	5, 0, 1, 1, 0, 0, 0 },
82 	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
83 	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
84 	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
85 	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
86 	[SOUND_MIXER_SPEAKER]	= { AC97_MIX_BEEP, 	4, 1, 0, 1, 0, 0, 0 },
87 	[SOUND_MIXER_LINE]	= { AC97_MIX_LINE, 	5, 0, 1, 1, 5, 0, 1 },
88 	[SOUND_MIXER_PHONEIN]	= { AC97_MIX_PHONE, 	5, 0, 0, 1, 8, 0, 0 },
89 	[SOUND_MIXER_MIC] 	= { AC97_MIX_MIC, 	5, 0, 0, 1, 1, 1, 1 },
90 #if 0
91 	/* use igain for the mic 20dB boost */
92 	[SOUND_MIXER_IGAIN] 	= { -AC97_MIX_MIC, 	1, 6, 0, 0, 0, 1, 1 },
93 #endif
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" },		/* Nowadays Realtek */
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 	{ 0x01408300, "Creative" },
125 	{ 0x00000000, NULL }
126 };
127 
128 static struct ac97_codecid ac97codecid[] = {
129 	{ 0x41445303, 0x00, 0, "AD1819",	0 },
130 	{ 0x41445340, 0x00, 0, "AD1881",	0 },
131 	{ 0x41445348, 0x00, 0, "AD1881A",	0 },
132 	{ 0x41445360, 0x00, 0, "AD1885",	0 },
133 	{ 0x41445361, 0x00, 0, "AD1886", 	ad1886_patch },
134 	{ 0x41445362, 0x00, 0, "AD1887", 	0 },
135 	{ 0x41445363, 0x00, 0, "AD1886A", 	0 },
136 	{ 0x41445370, 0x00, 0, "AD1980",	ad198x_patch },
137 	{ 0x41445372, 0x00, 0, "AD1981A",	0 },
138 	{ 0x41445374, 0x00, 0, "AD1981B",	0 },
139 	{ 0x41445375, 0x00, 0, "AD1985",	ad198x_patch },
140 	{ 0x414b4d00, 0x00, 1, "AK4540", 	0 },
141 	{ 0x414b4d01, 0x00, 1, "AK4542", 	0 },
142 	{ 0x414b4d02, 0x00, 1, "AK4543", 	0 },
143 	{ 0x414b4d06, 0x00, 0, "AK4544A",	0 },
144 	{ 0x454b4d07, 0x00, 0, "AK4545",	0 },
145 	{ 0x414c4320, 0x0f, 0, "ALC100",	0 },
146 	{ 0x414c4730, 0x0f, 0, "ALC101",	0 },
147 	{ 0x414c4710, 0x0f, 0, "ALC200", 	0 },
148 	{ 0x414c4740, 0x0f, 0, "ALC202", 	0 },
149 	{ 0x414c4720, 0x0f, 0, "ALC650", 	0 },
150 	{ 0x414c4750, 0x0f, 0, "ALC250",	0 },
151 	{ 0x414c4760, 0x0f, 0, "ALC655",	0 },
152 	{ 0x414c4770, 0x0f, 0, "ALC203",	0 },
153 	{ 0x414c4780, 0x0f, 0, "ALC658",	0 },
154 	{ 0x414c4790, 0x0f, 0, "ALC850",	0 },
155 	{ 0x43525900, 0x07, 0, "CS4297", 	0 },
156 	{ 0x43525910, 0x07, 0, "CS4297A", 	0 },
157 	{ 0x43525920, 0x07, 0, "CS4294/98",	0 },
158 	{ 0x4352592d, 0x07, 0, "CS4294",	0 },
159 	{ 0x43525930, 0x07, 0, "CS4299",	0 },
160 	{ 0x43525940, 0x07, 0, "CS4201",	0 },
161 	{ 0x43525958, 0x07, 0, "CS4205",	0 },
162 	{ 0x43525960, 0x07, 0, "CS4291A",	0 },
163 	{ 0x434d4961, 0x00, 0, "CMI9739",	0 },
164 	{ 0x434d4941, 0x00, 0, "CMI9738",	0 },
165 	{ 0x43585421, 0x00, 0, "HSD11246",	0 },
166 	{ 0x43585428, 0x07, 0, "CX20468",	0 },
167 	{ 0x44543000, 0x00, 0, "DT0398",	0 },
168 	{ 0x454d4323, 0x00, 0, "EM28023",	0 },
169 	{ 0x454d4328, 0x00, 0, "EM28028",	0 },
170 	{ 0x45838308, 0x00, 0, "ES1988",	0 }, /* Formerly ES1921(?) */
171 	{ 0x48525300, 0x00, 0, "HMP9701",	0 },
172 	{ 0x49434501, 0x00, 0, "ICE1230",	0 },
173 	{ 0x49434511, 0x00, 0, "ICE1232",	0 },
174 	{ 0x49434514, 0x00, 0, "ICE1232A",	0 },
175 	{ 0x49434551, 0x03, 0, "VT1616",	0 }, /* Via badged ICE */
176 	{ 0x49544520, 0x00, 0, "ITE2226E",	0 },
177 	{ 0x49544560, 0x07, 0, "ITE2646E",	0 }, /* XXX: patch needed */
178 	{ 0x4e534340, 0x00, 0, "LM4540",	0 }, /* Spec blank on revid */
179 	{ 0x4e534343, 0x00, 0, "LM4543",	0 }, /* Ditto */
180 	{ 0x4e534346, 0x00, 0, "LM4546A",	0 },
181 	{ 0x4e534348, 0x00, 0, "LM4548A",	0 },
182 	{ 0x4e534331, 0x00, 0, "LM4549",	0 },
183 	{ 0x4e534349, 0x00, 0, "LM4549A",	0 },
184 	{ 0x4e534350, 0x00, 0, "LM4550",	0 },
185 	{ 0x50534301, 0x00, 0, "UCB1510",	0 },
186 	{ 0x50534304, 0x00, 0, "UCB1400",	0 },
187 	{ 0x83847600, 0x00, 0, "STAC9700/83/84",	0 },
188 	{ 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
189 	{ 0x83847605, 0x00, 0, "STAC9704",	0 },
190 	{ 0x83847608, 0x00, 0, "STAC9708/11",	0 },
191 	{ 0x83847609, 0x00, 0, "STAC9721/23",	0 },
192 	{ 0x83847644, 0x00, 0, "STAC9744/45",	0 },
193 	{ 0x83847650, 0x00, 0, "STAC9750/51",	0 },
194 	{ 0x83847652, 0x00, 0, "STAC9752/53",	0 },
195 	{ 0x83847656, 0x00, 0, "STAC9756/57",	0 },
196 	{ 0x83847658, 0x00, 0, "STAC9758/59",	0 },
197 	{ 0x83847660, 0x00, 0, "STAC9760/61",	0 }, /* Extrapolated */
198 	{ 0x83847662, 0x00, 0, "STAC9762/63",	0 }, /* Extrapolated */
199 	{ 0x53494c22, 0x00, 0, "Si3036",	0 },
200 	{ 0x53494c23, 0x00, 0, "Si3038",	0 },
201 	{ 0x54524103, 0x00, 0, "TR28023",	0 }, /* Extrapolated */
202 	{ 0x54524106, 0x00, 0, "TR28026",	0 },
203 	{ 0x54524108, 0x00, 0, "TR28028",	0 },
204 	{ 0x54524123, 0x00, 0, "TR28602",	0 },
205 	{ 0x54524e03, 0x07, 0, "TLV320AIC27",	0 },
206 	{ 0x54584e20, 0x00, 0, "TLC320AD90",	0 },
207 	{ 0x56494161, 0x00, 0, "VIA1612A",      0 },
208 	{ 0x574d4c00, 0x00, 0, "WM9701A",	0 },
209 	{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8",	0 },
210 	{ 0x574d4c04, 0x00, 0, "WM9704Q",	0 },
211 	{ 0x574d4c05, 0x00, 0, "WM9705/10",	0 },
212 	{ 0x574d4d09, 0x00, 0, "WM9709",	0 },
213 	{ 0x574d4c12, 0x00, 0, "WM9711/12",	0 }, /* XXX: patch needed */
214 	{ 0x57454301, 0x00, 0, "W83971D",	0 },
215 	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
216 	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
217 	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
218 	{ 0x01408384, 0x00, 0, "EV1938",	0 },
219 	{ 0, 0, 0, NULL, 0 }
220 };
221 
222 static char *ac97enhancement[] = {
223 	"no 3D Stereo Enhancement",
224 	"Analog Devices Phat Stereo",
225 	"Creative Stereo Enhancement",
226 	"National Semi 3D Stereo Enhancement",
227 	"Yamaha Ymersion",
228 	"BBE 3D Stereo Enhancement",
229 	"Crystal Semi 3D Stereo Enhancement",
230 	"Qsound QXpander",
231 	"Spatializer 3D Stereo Enhancement",
232 	"SRS 3D Stereo Enhancement",
233 	"Platform Tech 3D Stereo Enhancement",
234 	"AKM 3D Audio",
235 	"Aureal Stereo Enhancement",
236 	"Aztech 3D Enhancement",
237 	"Binaura 3D Audio Enhancement",
238 	"ESS Technology Stereo Enhancement",
239 	"Harman International VMAx",
240 	"Nvidea 3D Stereo Enhancement",
241 	"Philips Incredible Sound",
242 	"Texas Instruments 3D Stereo Enhancement",
243 	"VLSI Technology 3D Stereo Enhancement",
244 	"TriTech 3D Stereo Enhancement",
245 	"Realtek 3D Stereo Enhancement",
246 	"Samsung 3D Stereo Enhancement",
247 	"Wolfson Microelectronics 3D Enhancement",
248 	"Delta Integration 3D Enhancement",
249 	"SigmaTel 3D Enhancement",
250 	"Reserved 27",
251 	"Rockwell 3D Stereo Enhancement",
252 	"Reserved 29",
253 	"Reserved 30",
254 	"Reserved 31"
255 };
256 
257 static char *ac97feature[] = {
258 	"mic channel",
259 	"reserved",
260 	"tone",
261 	"simulated stereo",
262 	"headphone",
263 	"bass boost",
264 	"18 bit DAC",
265 	"20 bit DAC",
266 	"18 bit ADC",
267 	"20 bit ADC"
268 };
269 
270 static char *ac97extfeature[] = {
271 	"variable rate PCM",
272 	"double rate PCM",
273 	"reserved 1",
274 	"variable rate mic",
275 	"reserved 2",
276 	"reserved 3",
277 	"center DAC",
278 	"surround DAC",
279 	"LFE DAC",
280 	"AMAP",
281 	"reserved 4",
282 	"reserved 5",
283 	"reserved 6",
284 	"reserved 7",
285 };
286 
287 u_int16_t
288 ac97_rdcd(struct ac97_info *codec, int reg)
289 {
290 	return AC97_READ(codec->methods, codec->devinfo, reg);
291 }
292 
293 void
294 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
295 {
296 	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
297 }
298 
299 static void
300 ac97_reset(struct ac97_info *codec)
301 {
302 	u_int32_t i, ps;
303 	ac97_wrcd(codec, AC97_REG_RESET, 0);
304 	for (i = 0; i < 500; i++) {
305 		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
306 		if (ps == AC97_POWER_STATUS)
307 			return;
308 		DELAY(1000);
309 	}
310 	device_printf(codec->dev, "AC97 reset timed out.\n");
311 }
312 
313 int
314 ac97_setrate(struct ac97_info *codec, int which, int rate)
315 {
316 	u_int16_t v;
317 
318 	switch(which) {
319 	case AC97_REGEXT_FDACRATE:
320 	case AC97_REGEXT_SDACRATE:
321 	case AC97_REGEXT_LDACRATE:
322 	case AC97_REGEXT_LADCRATE:
323 	case AC97_REGEXT_MADCRATE:
324 		break;
325 
326 	default:
327 		return -1;
328 	}
329 
330 	snd_mtxlock(codec->lock);
331 	if (rate != 0) {
332 		v = rate;
333 		if (codec->extstat & AC97_EXTCAP_DRA)
334 			v >>= 1;
335 		ac97_wrcd(codec, which, v);
336 	}
337 	v = ac97_rdcd(codec, which);
338 	if (codec->extstat & AC97_EXTCAP_DRA)
339 		v <<= 1;
340 	snd_mtxunlock(codec->lock);
341 	return v;
342 }
343 
344 int
345 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
346 {
347 	mode &= AC97_EXTCAPS;
348 	if ((mode & ~codec->extcaps) != 0) {
349 		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
350 			      mode);
351 		return -1;
352 	}
353 	snd_mtxlock(codec->lock);
354 	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
355 	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
356 	snd_mtxunlock(codec->lock);
357 	return (mode == codec->extstat)? 0 : -1;
358 }
359 
360 u_int16_t
361 ac97_getextmode(struct ac97_info *codec)
362 {
363 	return codec->extstat;
364 }
365 
366 u_int16_t
367 ac97_getextcaps(struct ac97_info *codec)
368 {
369 	return codec->extcaps;
370 }
371 
372 u_int16_t
373 ac97_getcaps(struct ac97_info *codec)
374 {
375 	return codec->caps;
376 }
377 
378 static int
379 ac97_setrecsrc(struct ac97_info *codec, int channel)
380 {
381 	struct ac97mixtable_entry *e = &codec->mix[channel];
382 
383 	if (e->recidx > 0) {
384 		int val = e->recidx - 1;
385 		val |= val << 8;
386 		snd_mtxlock(codec->lock);
387 		ac97_wrcd(codec, AC97_REG_RECSEL, val);
388 		snd_mtxunlock(codec->lock);
389 		return 0;
390 	} else
391 		return -1;
392 }
393 
394 static int
395 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
396 {
397 	struct ac97mixtable_entry *e = &codec->mix[channel];
398 
399 	if (e->reg && e->enable && e->bits) {
400 		int mask, max, val, reg;
401 
402 		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
403 		max = (1 << e->bits) - 1;		/* actual range	    */
404 		mask = (max << 8) | max;		/* bits of interest */
405 
406 		if (!e->stereo)
407 			right = left;
408 
409 		/*
410 		 * Invert the range if the polarity requires so,
411 		 * then scale to 0..max-1 to compute the value to
412 		 * write into the codec, and scale back to 0..100
413 		 * for the return value.
414 		 */
415 		if (e->reg > 0) {
416 			left = 100 - left;
417 			right = 100 - right;
418 		}
419 
420 		left = (left * max) / 100;
421 		right = (right * max) / 100;
422 
423 		val = (left << 8) | right;
424 
425 		left = (left * 100) / max;
426 		right = (right * 100) / max;
427 
428 		if (e->reg > 0) {
429 			left = 100 - left;
430 			right = 100 - right;
431 		}
432 
433 		/*
434 		 * For mono controls, trim val and mask, also taking
435 		 * care of e->ofs (offset of control field).
436 		 */
437 		if (e->ofs) {
438 			val &= max;
439 			val <<= e->ofs;
440 			mask = (max << e->ofs);
441 		}
442 
443 		/*
444 		 * If we have a mute bit, add it to the mask and
445 		 * update val and set mute if both channels require a
446 		 * zero volume.
447 		 */
448 		if (e->mute == 1) {
449 			mask |= AC97_MUTE;
450 			if (left == 0 && right == 0)
451 				val = AC97_MUTE;
452 		}
453 
454 		/*
455 		 * If the mask bit is set, do not alter the other bits.
456 		 */
457 		snd_mtxlock(codec->lock);
458 		if (e->mask) {
459 			int cur = ac97_rdcd(codec, e->reg);
460 			val |= cur & ~(mask);
461 		}
462 		ac97_wrcd(codec, reg, val);
463 		snd_mtxunlock(codec->lock);
464 		return left | (right << 8);
465 	} else {
466 		/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
467 		return -1;
468 	}
469 }
470 
471 static void
472 ac97_fix_auxout(struct ac97_info *codec)
473 {
474 	int keep_ogain;
475 
476 	/*
477 	 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
478 	 * OGAIN setting.
479 	 *
480 	 * We first check whether aux_out is a valid register.  If not
481 	 * we may not want to keep ogain.
482 	 */
483 	keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
484 
485 	/*
486 	 * Determine what AUX_OUT really means, it can be:
487 	 *
488 	 * 1. Headphone out.
489 	 * 2. 4-Channel Out
490 	 * 3. True line level out (effectively master volume).
491 	 *
492 	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
493 	 */
494 	if (codec->extcaps & AC97_EXTCAP_SDAC &&
495 	    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
496 		codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
497 		keep_ogain = 1;
498 	}
499 
500 	if (keep_ogain == 0) {
501 		bzero(&codec->mix[SOUND_MIXER_OGAIN],
502 		      sizeof(codec->mix[SOUND_MIXER_OGAIN]));
503 	}
504 }
505 
506 static void
507 ac97_fix_tone(struct ac97_info *codec)
508 {
509 	/* Hide treble and bass if they don't exist */
510 	if ((codec->caps & AC97_CAP_TONE) == 0) {
511 		bzero(&codec->mix[SOUND_MIXER_BASS],
512 		      sizeof(codec->mix[SOUND_MIXER_BASS]));
513 		bzero(&codec->mix[SOUND_MIXER_TREBLE],
514 		      sizeof(codec->mix[SOUND_MIXER_TREBLE]));
515 	}
516 }
517 
518 static const char*
519 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
520 {
521 	if (cname == NULL) {
522 		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
523 		return buf;
524 	}
525 
526 	if (vname == NULL) vname = "Unknown";
527 
528 	if (bootverbose) {
529 		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
530 	} else {
531 		sprintf(buf, "%s %s AC97 Codec", vname, cname);
532 	}
533 	return buf;
534 }
535 
536 static unsigned
537 ac97_initmixer(struct ac97_info *codec)
538 {
539 	ac97_patch codec_patch;
540 	const char *cname, *vname;
541 	char desc[80];
542 	u_int8_t model, step;
543 	unsigned i, j, k, old;
544 	u_int32_t id;
545 
546 	snd_mtxlock(codec->lock);
547 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
548 	if (codec->count == 0) {
549 		device_printf(codec->dev, "ac97 codec init failed\n");
550 		snd_mtxunlock(codec->lock);
551 		return ENODEV;
552 	}
553 
554 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
555 	ac97_reset(codec);
556 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
557 
558 	i = ac97_rdcd(codec, AC97_REG_RESET);
559 	codec->caps = i & 0x03ff;
560 	codec->se =  (i & 0x7c00) >> 10;
561 
562 	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
563 	if (id == 0 || id == 0xffffffff) {
564 		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
565 		snd_mtxunlock(codec->lock);
566 		return ENODEV;
567 	}
568 
569 	codec->id = id;
570 	codec->noext = 0;
571 	codec_patch = NULL;
572 
573 	cname = NULL;
574 	model = step = 0;
575 	for (i = 0; ac97codecid[i].id; i++) {
576 		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
577 		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
578 			codec->noext = ac97codecid[i].noext;
579 			codec_patch = ac97codecid[i].patch;
580 			cname = ac97codecid[i].name;
581 			model = (id & modelmask) & 0xff;
582 			step = (id & ~modelmask) & 0xff;
583 			break;
584 		}
585 	}
586 
587 	vname = NULL;
588 	for (i = 0; ac97vendorid[i].id; i++) {
589 		if (ac97vendorid[i].id == (id & 0xffffff00)) {
590 			vname = ac97vendorid[i].name;
591 			break;
592 		}
593 	}
594 
595 	codec->extcaps = 0;
596 	codec->extid = 0;
597 	codec->extstat = 0;
598 	if (!codec->noext) {
599 		i = ac97_rdcd(codec, AC97_REGEXT_ID);
600 		if (i != 0xffff) {
601 			codec->extcaps = i & 0x3fff;
602 			codec->extid =  (i & 0xc000) >> 14;
603 			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
604 		}
605 	}
606 
607 	for (i = 0; i < 32; i++) {
608 		codec->mix[i] = ac97mixtable_default[i];
609 	}
610 	ac97_fix_auxout(codec);
611 	ac97_fix_tone(codec);
612 	if (codec_patch)
613 		codec_patch(codec);
614 
615 	for (i = 0; i < 32; i++) {
616 		k = codec->noext? codec->mix[i].enable : 1;
617 		if (k && (codec->mix[i].reg > 0)) {
618 			old = ac97_rdcd(codec, codec->mix[i].reg);
619 			ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
620 			j = ac97_rdcd(codec, codec->mix[i].reg);
621 			ac97_wrcd(codec, codec->mix[i].reg, old);
622 			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
623 			for (k = 1; j & (1 << k); k++);
624 			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
625 		}
626 		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
627 	}
628 
629 	device_printf(codec->dev, "<%s>\n",
630 		      ac97_hw_desc(codec->id, vname, cname, desc));
631 
632 	if (bootverbose) {
633 		device_printf(codec->dev, "Codec features ");
634 		for (i = j = 0; i < 10; i++)
635 			if (codec->caps & (1 << i))
636 				printf("%s%s", j++? ", " : "", ac97feature[i]);
637 		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
638 		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
639 
640 		if (codec->extcaps != 0 || codec->extid) {
641 			device_printf(codec->dev, "%s codec",
642 				      codec->extid? "Secondary" : "Primary");
643 			if (codec->extcaps)
644 				printf(" extended features ");
645 			for (i = j = 0; i < 14; i++)
646 				if (codec->extcaps & (1 << i))
647 					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
648 			printf("\n");
649 		}
650 	}
651 
652 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
653 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
654 	snd_mtxunlock(codec->lock);
655 	return 0;
656 }
657 
658 static unsigned
659 ac97_reinitmixer(struct ac97_info *codec)
660 {
661 	snd_mtxlock(codec->lock);
662 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
663 	if (codec->count == 0) {
664 		device_printf(codec->dev, "ac97 codec init failed\n");
665 		snd_mtxunlock(codec->lock);
666 		return ENODEV;
667 	}
668 
669 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
670 	ac97_reset(codec);
671 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
672 
673 	if (!codec->noext) {
674 		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
675 		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
676 		    != codec->extstat)
677 			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
678 				      codec->extstat,
679 				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
680 				      AC97_EXTCAPS);
681 	}
682 
683 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
684 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
685 	snd_mtxunlock(codec->lock);
686 	return 0;
687 }
688 
689 struct ac97_info *
690 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
691 {
692 	struct ac97_info *codec;
693 
694 	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
695 	if (codec == NULL)
696 		return NULL;
697 
698 	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
699 	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
700 	codec->methods = kobj_create(cls, M_AC97, 0);
701 	if (codec->methods == NULL) {
702 		snd_mtxlock(codec->lock);
703 		snd_mtxfree(codec->lock);
704 		free(codec, M_AC97);
705 		return NULL;
706 	}
707 
708 	codec->dev = dev;
709 	codec->devinfo = devinfo;
710 	codec->flags = 0;
711 	return codec;
712 }
713 
714 void
715 ac97_destroy(struct ac97_info *codec)
716 {
717 	snd_mtxlock(codec->lock);
718 	if (codec->methods != NULL)
719 		kobj_delete(codec->methods, M_AC97);
720 	snd_mtxfree(codec->lock);
721 	free(codec, M_AC97);
722 }
723 
724 void
725 ac97_setflags(struct ac97_info *codec, u_int32_t val)
726 {
727 	codec->flags = val;
728 }
729 
730 u_int32_t
731 ac97_getflags(struct ac97_info *codec)
732 {
733 	return codec->flags;
734 }
735 
736 /* -------------------------------------------------------------------- */
737 
738 static int
739 ac97mix_init(struct snd_mixer *m)
740 {
741 	struct ac97_info *codec = mix_getdevinfo(m);
742 	u_int32_t i, mask;
743 
744 	if (codec == NULL)
745 		return -1;
746 
747 	if (ac97_initmixer(codec))
748 		return -1;
749 
750 	mask = 0;
751 	for (i = 0; i < 32; i++)
752 		mask |= codec->mix[i].enable? 1 << i : 0;
753 	mix_setdevs(m, mask);
754 
755 	mask = 0;
756 	for (i = 0; i < 32; i++)
757 		mask |= codec->mix[i].recidx? 1 << i : 0;
758 	mix_setrecdevs(m, mask);
759 	return 0;
760 }
761 
762 static int
763 ac97mix_uninit(struct snd_mixer *m)
764 {
765 	struct ac97_info *codec = mix_getdevinfo(m);
766 
767 	if (codec == NULL)
768 		return -1;
769 	/*
770 	if (ac97_uninitmixer(codec))
771 		return -1;
772 	*/
773 	ac97_destroy(codec);
774 	return 0;
775 }
776 
777 static int
778 ac97mix_reinit(struct snd_mixer *m)
779 {
780 	struct ac97_info *codec = mix_getdevinfo(m);
781 
782 	if (codec == NULL)
783 		return -1;
784 	return ac97_reinitmixer(codec);
785 }
786 
787 static int
788 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
789 {
790 	struct ac97_info *codec = mix_getdevinfo(m);
791 
792 	if (codec == NULL)
793 		return -1;
794 	return ac97_setmixer(codec, dev, left, right);
795 }
796 
797 static int
798 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
799 {
800 	int i;
801 	struct ac97_info *codec = mix_getdevinfo(m);
802 
803 	if (codec == NULL)
804 		return -1;
805 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
806 		if ((src & (1 << i)) != 0)
807 			break;
808 	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
809 }
810 
811 static kobj_method_t ac97mixer_methods[] = {
812     	KOBJMETHOD(mixer_init,		ac97mix_init),
813     	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
814     	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
815     	KOBJMETHOD(mixer_set,		ac97mix_set),
816     	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
817 	{ 0, 0 }
818 };
819 MIXER_DECLARE(ac97mixer);
820 
821 /* -------------------------------------------------------------------- */
822 
823 kobj_class_t
824 ac97_getmixerclass(void)
825 {
826 	return &ac97mixer_class;
827 }
828 
829 
830