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