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