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