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