xref: /freebsd/sys/dev/sound/pcm/ac97.c (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include "opt_snd.h"
31 #endif
32 
33 #include <dev/sound/pcm/sound.h>
34 #include <dev/sound/pcm/ac97.h>
35 
36 #include <dev/pci/pcivar.h>
37 
38 #include "mixer_if.h"
39 
40 static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
41 
42 typedef void (*ac97_patch)(struct ac97_info *);
43 
44 struct ac97mixtable_entry {
45 	int reg;		/* register index		*/
46 				/* reg < 0 if inverted polarity	*/
47 	unsigned bits:4;	/* width of control field	*/
48 	unsigned ofs:4;		/* offset (only if stereo=0)	*/
49 	unsigned stereo:1;	/* set for stereo controls	*/
50 	unsigned mute:1;	/* bit15 is MUTE		*/
51 	unsigned recidx:4;	/* index in rec mux		*/
52 	unsigned mask:1;	/* use only masked bits		*/
53 	unsigned enable:1;	/* entry is enabled		*/
54 };
55 
56 #define AC97_MIXER_SIZE		SOUND_MIXER_NRDEVICES
57 
58 struct ac97_info {
59 	kobj_t methods;
60 	device_t dev;
61 	void *devinfo;
62 	u_int32_t id;
63 	u_int32_t subvendor;
64 	unsigned count, caps, se, extcaps, extid, extstat, noext:1;
65 	u_int32_t flags;
66 	struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
67 	char name[16];
68 	struct mtx *lock;
69 };
70 
71 struct ac97_vendorid {
72 	u_int32_t   id;
73 	const char *name;
74 };
75 
76 struct ac97_codecid {
77 	u_int32_t  id;
78 	u_int8_t   stepmask;
79 	u_int8_t   noext:1;
80 	char 	  *name;
81 	ac97_patch patch;
82 };
83 
84 static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
85     /*	[offset]			reg	     bits of st mu re mk en */
86 	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
87 	[SOUND_MIXER_OGAIN]	= { AC97_MIX_AUXOUT, 	5, 0, 1, 1, 0, 0, 0 },
88 	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
89 	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
90 	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
91 	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
92 	[SOUND_MIXER_SPEAKER]	= { AC97_MIX_BEEP, 	4, 1, 0, 1, 0, 0, 0 },
93 	[SOUND_MIXER_LINE]	= { AC97_MIX_LINE, 	5, 0, 1, 1, 5, 0, 1 },
94 	[SOUND_MIXER_PHONEIN]	= { AC97_MIX_PHONE, 	5, 0, 0, 1, 8, 0, 0 },
95 	[SOUND_MIXER_MIC] 	= { AC97_MIX_MIC, 	5, 0, 0, 1, 1, 1, 1 },
96 	/* use igain for the mic 20dB boost */
97 	[SOUND_MIXER_IGAIN] 	= { -AC97_MIX_MIC, 	1, 6, 0, 0, 0, 1, 1 },
98 	[SOUND_MIXER_CD]	= { AC97_MIX_CD, 	5, 0, 1, 1, 2, 0, 1 },
99 	[SOUND_MIXER_LINE1]	= { AC97_MIX_AUX, 	5, 0, 1, 1, 4, 0, 0 },
100 	[SOUND_MIXER_VIDEO]	= { AC97_MIX_VIDEO, 	5, 0, 1, 1, 3, 0, 0 },
101 	[SOUND_MIXER_RECLEV]	= { -AC97_MIX_RGAIN, 	4, 0, 1, 1, 0, 0, 1 }
102 };
103 
104 static const struct ac97_vendorid ac97vendorid[] = {
105 	{ 0x41445300, "Analog Devices" },
106 	{ 0x414b4d00, "Asahi Kasei" },
107 	{ 0x414c4300, "Realtek" },
108 	{ 0x414c4700, "Avance Logic" },
109 	{ 0x43525900, "Cirrus Logic" },
110 	{ 0x434d4900, "C-Media Electronics" },
111 	{ 0x43585400, "Conexant" },
112 	{ 0x44543000, "Diamond Technology" },
113 	{ 0x454d4300, "eMicro" },
114 	{ 0x45838300, "ESS Technology" },
115 	{ 0x48525300, "Intersil" },
116 	{ 0x49434500, "ICEnsemble" },
117 	{ 0x49544500, "ITE, Inc." },
118 	{ 0x4e534300, "National Semiconductor" },
119 	{ 0x50534300, "Philips Semiconductor" },
120 	{ 0x83847600, "SigmaTel" },
121 	{ 0x53494c00, "Silicon Laboratories" },
122 	{ 0x54524100, "TriTech" },
123 	{ 0x54584e00, "Texas Instruments" },
124 	{ 0x56494100, "VIA Technologies" },
125 	{ 0x57454300, "Winbond" },
126 	{ 0x574d4c00, "Wolfson" },
127 	{ 0x594d4800, "Yamaha" },
128 	/*
129 	 * XXX This is a fluke, really! The real vendor
130 	 * should be SigmaTel, not this! This should be
131 	 * removed someday!
132 	 */
133 	{ 0x01408300, "Creative" },
134 	{ 0x00000000, NULL }
135 };
136 
137 static void ad1886_patch(struct ac97_info *);
138 static void ad198x_patch(struct ac97_info *);
139 static void ad1981b_patch(struct ac97_info *);
140 static void cmi9739_patch(struct ac97_info *);
141 static void alc655_patch(struct ac97_info *);
142 
143 static struct ac97_codecid ac97codecid[] = {
144 	{ 0x41445303, 0x00, 0, "AD1819",	0 },
145 	{ 0x41445340, 0x00, 0, "AD1881",	0 },
146 	{ 0x41445348, 0x00, 0, "AD1881A",	0 },
147 	{ 0x41445360, 0x00, 0, "AD1885",	0 },
148 	{ 0x41445361, 0x00, 0, "AD1886", 	ad1886_patch },
149 	{ 0x41445362, 0x00, 0, "AD1887", 	0 },
150 	{ 0x41445363, 0x00, 0, "AD1886A", 	0 },
151 	{ 0x41445368, 0x00, 0, "AD1888", 	ad198x_patch },
152 	{ 0x41445370, 0x00, 0, "AD1980",	ad198x_patch },
153 	{ 0x41445372, 0x00, 0, "AD1981A",	0 },
154 	{ 0x41445374, 0x00, 0, "AD1981B",	ad1981b_patch },
155 	{ 0x41445375, 0x00, 0, "AD1985",	ad198x_patch },
156 	{ 0x41445378, 0x00, 0, "AD1986",	ad198x_patch },
157 	{ 0x414b4d00, 0x00, 1, "AK4540", 	0 },
158 	{ 0x414b4d01, 0x00, 1, "AK4542", 	0 },
159 	{ 0x414b4d02, 0x00, 1, "AK4543", 	0 },
160 	{ 0x414b4d06, 0x00, 0, "AK4544A",	0 },
161 	{ 0x454b4d07, 0x00, 0, "AK4545",	0 },
162 	{ 0x414c4320, 0x0f, 0, "ALC100",	0 },
163 	{ 0x414c4730, 0x0f, 0, "ALC101",	0 },
164 	{ 0x414c4710, 0x0f, 0, "ALC200", 	0 },
165 	{ 0x414c4740, 0x0f, 0, "ALC202", 	0 },
166 	{ 0x414c4720, 0x0f, 0, "ALC650", 	0 },
167 	{ 0x414c4752, 0x0f, 0, "ALC250",	0 },
168 	{ 0x414c4760, 0x0f, 0, "ALC655",	alc655_patch },
169 	{ 0x414c4770, 0x0f, 0, "ALC203",	0 },
170 	{ 0x414c4780, 0x0f, 0, "ALC658",	0 },
171 	{ 0x414c4790, 0x0f, 0, "ALC850",	0 },
172 	{ 0x43525900, 0x07, 0, "CS4297", 	0 },
173 	{ 0x43525910, 0x07, 0, "CS4297A", 	0 },
174 	{ 0x43525920, 0x07, 0, "CS4294/98",	0 },
175 	{ 0x4352592d, 0x07, 0, "CS4294",	0 },
176 	{ 0x43525930, 0x07, 0, "CS4299",	0 },
177 	{ 0x43525940, 0x07, 0, "CS4201",	0 },
178 	{ 0x43525958, 0x07, 0, "CS4205",	0 },
179 	{ 0x43525960, 0x07, 0, "CS4291A",	0 },
180 	{ 0x434d4961, 0x00, 0, "CMI9739",	cmi9739_patch },
181 	{ 0x434d4941, 0x00, 0, "CMI9738",	0 },
182 	{ 0x434d4978, 0x00, 0, "CMI9761",	0 },
183 	{ 0x434d4982, 0x00, 0, "CMI9761",	0 },
184 	{ 0x434d4983, 0x00, 0, "CMI9761",	0 },
185 	{ 0x43585421, 0x00, 0, "HSD11246",	0 },
186 	{ 0x43585428, 0x07, 0, "CX20468",	0 },
187 	{ 0x43585430, 0x00, 0, "CX20468-21",	0 },
188 	{ 0x44543000, 0x00, 0, "DT0398",	0 },
189 	{ 0x454d4323, 0x00, 0, "EM28023",	0 },
190 	{ 0x454d4328, 0x00, 0, "EM28028",	0 },
191 	{ 0x45838308, 0x00, 0, "ES1988",	0 }, /* Formerly ES1921(?) */
192 	{ 0x48525300, 0x00, 0, "HMP9701",	0 },
193 	{ 0x49434501, 0x00, 0, "ICE1230",	0 },
194 	{ 0x49434511, 0x00, 0, "ICE1232",	0 },
195 	{ 0x49434514, 0x00, 0, "ICE1232A",	0 },
196 	{ 0x49434551, 0x03, 0, "VT1616",	0 }, /* Via badged ICE */
197 	{ 0x49544520, 0x00, 0, "ITE2226E",	0 },
198 	{ 0x49544560, 0x07, 0, "ITE2646E",	0 }, /* XXX: patch needed */
199 	{ 0x4e534340, 0x00, 0, "LM4540",	0 }, /* Spec blank on revid */
200 	{ 0x4e534343, 0x00, 0, "LM4543",	0 }, /* Ditto */
201 	{ 0x4e534346, 0x00, 0, "LM4546A",	0 },
202 	{ 0x4e534348, 0x00, 0, "LM4548A",	0 },
203 	{ 0x4e534331, 0x00, 0, "LM4549",	0 },
204 	{ 0x4e534349, 0x00, 0, "LM4549A",	0 },
205 	{ 0x4e534350, 0x00, 0, "LM4550",	0 },
206 	{ 0x50534301, 0x00, 0, "UCB1510",	0 },
207 	{ 0x50534304, 0x00, 0, "UCB1400",	0 },
208 	{ 0x83847600, 0x00, 0, "STAC9700/83/84",	0 },
209 	{ 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
210 	{ 0x83847605, 0x00, 0, "STAC9704",	0 },
211 	{ 0x83847608, 0x00, 0, "STAC9708/11",	0 },
212 	{ 0x83847609, 0x00, 0, "STAC9721/23",	0 },
213 	{ 0x83847644, 0x00, 0, "STAC9744/45",	0 },
214 	{ 0x83847650, 0x00, 0, "STAC9750/51",	0 },
215 	{ 0x83847652, 0x00, 0, "STAC9752/53",	0 },
216 	{ 0x83847656, 0x00, 0, "STAC9756/57",	0 },
217 	{ 0x83847658, 0x00, 0, "STAC9758/59",	0 },
218 	{ 0x83847660, 0x00, 0, "STAC9760/61",	0 }, /* Extrapolated */
219 	{ 0x83847662, 0x00, 0, "STAC9762/63",	0 }, /* Extrapolated */
220 	{ 0x83847666, 0x00, 0, "STAC9766/67",	0 },
221 	{ 0x53494c22, 0x00, 0, "Si3036",	0 },
222 	{ 0x53494c23, 0x00, 0, "Si3038",	0 },
223 	{ 0x54524103, 0x00, 0, "TR28023",	0 }, /* Extrapolated */
224 	{ 0x54524106, 0x00, 0, "TR28026",	0 },
225 	{ 0x54524108, 0x00, 0, "TR28028",	0 },
226 	{ 0x54524123, 0x00, 0, "TR28602",	0 },
227 	{ 0x54524e03, 0x07, 0, "TLV320AIC27",	0 },
228 	{ 0x54584e20, 0x00, 0, "TLC320AD90",	0 },
229 	{ 0x56494161, 0x00, 0, "VIA1612A",      0 },
230 	{ 0x56494170, 0x00, 0, "VIA1617A",      0 },
231 	{ 0x574d4c00, 0x00, 0, "WM9701A",	0 },
232 	{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8",	0 },
233 	{ 0x574d4c04, 0x00, 0, "WM9704Q",	0 },
234 	{ 0x574d4c05, 0x00, 0, "WM9705/10",	0 },
235 	{ 0x574d4d09, 0x00, 0, "WM9709",	0 },
236 	{ 0x574d4c12, 0x00, 0, "WM9711/12",	0 }, /* XXX: patch needed */
237 	{ 0x57454301, 0x00, 0, "W83971D",	0 },
238 	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
239 	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
240 	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
241 	/*
242 	 * XXX This is a fluke, really! The real codec
243 	 * should be STAC9704, not this! This should be
244 	 * removed someday!
245 	 */
246 	{ 0x01408384, 0x00, 0, "EV1938",	0 },
247 	{ 0, 0, 0, NULL, 0 }
248 };
249 
250 static char *ac97enhancement[] = {
251 	"no 3D Stereo Enhancement",
252 	"Analog Devices Phat Stereo",
253 	"Creative Stereo Enhancement",
254 	"National Semi 3D Stereo Enhancement",
255 	"Yamaha Ymersion",
256 	"BBE 3D Stereo Enhancement",
257 	"Crystal Semi 3D Stereo Enhancement",
258 	"Qsound QXpander",
259 	"Spatializer 3D Stereo Enhancement",
260 	"SRS 3D Stereo Enhancement",
261 	"Platform Tech 3D Stereo Enhancement",
262 	"AKM 3D Audio",
263 	"Aureal Stereo Enhancement",
264 	"Aztech 3D Enhancement",
265 	"Binaura 3D Audio Enhancement",
266 	"ESS Technology Stereo Enhancement",
267 	"Harman International VMAx",
268 	"Nvidea 3D Stereo Enhancement",
269 	"Philips Incredible Sound",
270 	"Texas Instruments 3D Stereo Enhancement",
271 	"VLSI Technology 3D Stereo Enhancement",
272 	"TriTech 3D Stereo Enhancement",
273 	"Realtek 3D Stereo Enhancement",
274 	"Samsung 3D Stereo Enhancement",
275 	"Wolfson Microelectronics 3D Enhancement",
276 	"Delta Integration 3D Enhancement",
277 	"SigmaTel 3D Enhancement",
278 	"Reserved 27",
279 	"Rockwell 3D Stereo Enhancement",
280 	"Reserved 29",
281 	"Reserved 30",
282 	"Reserved 31"
283 };
284 
285 static char *ac97feature[] = {
286 	"mic channel",
287 	"reserved",
288 	"tone",
289 	"simulated stereo",
290 	"headphone",
291 	"bass boost",
292 	"18 bit DAC",
293 	"20 bit DAC",
294 	"18 bit ADC",
295 	"20 bit ADC"
296 };
297 
298 static char *ac97extfeature[] = {
299 	"variable rate PCM",
300 	"double rate PCM",
301 	"reserved 1",
302 	"variable rate mic",
303 	"reserved 2",
304 	"reserved 3",
305 	"center DAC",
306 	"surround DAC",
307 	"LFE DAC",
308 	"AMAP",
309 	"reserved 4",
310 	"reserved 5",
311 	"reserved 6",
312 	"reserved 7",
313 };
314 
315 u_int16_t
316 ac97_rdcd(struct ac97_info *codec, int reg)
317 {
318 	if (codec->flags & AC97_F_RDCD_BUG) {
319 		u_int16_t i[2], j = 100;
320 
321 		i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
322 		i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
323 		while (i[0] != i[1] && j)
324 			i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
325 		return i[!(j & 1)];
326 	}
327 	return AC97_READ(codec->methods, codec->devinfo, reg);
328 }
329 
330 void
331 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
332 {
333 	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
334 }
335 
336 static void
337 ac97_reset(struct ac97_info *codec)
338 {
339 	u_int32_t i, ps;
340 	ac97_wrcd(codec, AC97_REG_RESET, 0);
341 	for (i = 0; i < 500; i++) {
342 		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
343 		if (ps == AC97_POWER_STATUS)
344 			return;
345 		DELAY(1000);
346 	}
347 	device_printf(codec->dev, "AC97 reset timed out.\n");
348 }
349 
350 int
351 ac97_setrate(struct ac97_info *codec, int which, int rate)
352 {
353 	u_int16_t v;
354 
355 	switch(which) {
356 	case AC97_REGEXT_FDACRATE:
357 	case AC97_REGEXT_SDACRATE:
358 	case AC97_REGEXT_LDACRATE:
359 	case AC97_REGEXT_LADCRATE:
360 	case AC97_REGEXT_MADCRATE:
361 		break;
362 
363 	default:
364 		return -1;
365 	}
366 
367 	snd_mtxlock(codec->lock);
368 	if (rate != 0) {
369 		v = rate;
370 		if (codec->extstat & AC97_EXTCAP_DRA)
371 			v >>= 1;
372 		ac97_wrcd(codec, which, v);
373 	}
374 	v = ac97_rdcd(codec, which);
375 	if (codec->extstat & AC97_EXTCAP_DRA)
376 		v <<= 1;
377 	snd_mtxunlock(codec->lock);
378 	return v;
379 }
380 
381 int
382 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
383 {
384 	mode &= AC97_EXTCAPS;
385 	if ((mode & ~codec->extcaps) != 0) {
386 		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
387 			      mode);
388 		return -1;
389 	}
390 	snd_mtxlock(codec->lock);
391 	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
392 	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
393 	snd_mtxunlock(codec->lock);
394 	return (mode == codec->extstat)? 0 : -1;
395 }
396 
397 u_int16_t
398 ac97_getextmode(struct ac97_info *codec)
399 {
400 	return codec->extstat;
401 }
402 
403 u_int16_t
404 ac97_getextcaps(struct ac97_info *codec)
405 {
406 	return codec->extcaps;
407 }
408 
409 u_int16_t
410 ac97_getcaps(struct ac97_info *codec)
411 {
412 	return codec->caps;
413 }
414 
415 u_int32_t
416 ac97_getsubvendor(struct ac97_info *codec)
417 {
418 	return codec->subvendor;
419 }
420 
421 static int
422 ac97_setrecsrc(struct ac97_info *codec, int channel)
423 {
424 	struct ac97mixtable_entry *e = &codec->mix[channel];
425 
426 	if (e->recidx > 0) {
427 		int val = e->recidx - 1;
428 		val |= val << 8;
429 		snd_mtxlock(codec->lock);
430 		ac97_wrcd(codec, AC97_REG_RECSEL, val);
431 		snd_mtxunlock(codec->lock);
432 		return 0;
433 	} else
434 		return -1;
435 }
436 
437 static int
438 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
439 {
440 	struct ac97mixtable_entry *e = &codec->mix[channel];
441 
442 	if (e->reg && e->enable && e->bits) {
443 		int mask, max, val, reg;
444 
445 		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
446 		max = (1 << e->bits) - 1;		/* actual range	    */
447 		mask = (max << 8) | max;		/* bits of interest */
448 
449 		if (!e->stereo)
450 			right = left;
451 
452 		/*
453 		 * Invert the range if the polarity requires so,
454 		 * then scale to 0..max-1 to compute the value to
455 		 * write into the codec, and scale back to 0..100
456 		 * for the return value.
457 		 */
458 		if (e->reg > 0) {
459 			left = 100 - left;
460 			right = 100 - right;
461 		}
462 
463 		left = (left * max) / 100;
464 		right = (right * max) / 100;
465 
466 		val = (left << 8) | right;
467 
468 		left = (left * 100) / max;
469 		right = (right * 100) / max;
470 
471 		if (e->reg > 0) {
472 			left = 100 - left;
473 			right = 100 - right;
474 		}
475 
476 		/*
477 		 * For mono controls, trim val and mask, also taking
478 		 * care of e->ofs (offset of control field).
479 		 */
480 		if (e->ofs) {
481 			val &= max;
482 			val <<= e->ofs;
483 			mask = (max << e->ofs);
484 		}
485 
486 		/*
487 		 * If we have a mute bit, add it to the mask and
488 		 * update val and set mute if both channels require a
489 		 * zero volume.
490 		 */
491 		if (e->mute == 1) {
492 			mask |= AC97_MUTE;
493 			if (left == 0 && right == 0)
494 				val = AC97_MUTE;
495 		}
496 
497 		/*
498 		 * If the mask bit is set, do not alter the other bits.
499 		 */
500 		snd_mtxlock(codec->lock);
501 		if (e->mask) {
502 			int cur = ac97_rdcd(codec, reg);
503 			val |= cur & ~(mask);
504 		}
505 		ac97_wrcd(codec, reg, val);
506 		snd_mtxunlock(codec->lock);
507 		return left | (right << 8);
508 	} else {
509 		return -1;
510 	}
511 }
512 
513 static void
514 ac97_fix_auxout(struct ac97_info *codec)
515 {
516 	int keep_ogain;
517 
518 	/*
519 	 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
520 	 * OGAIN setting.
521 	 *
522 	 * We first check whether aux_out is a valid register.  If not
523 	 * we may not want to keep ogain.
524 	 */
525 	keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
526 
527 	/*
528 	 * Determine what AUX_OUT really means, it can be:
529 	 *
530 	 * 1. Headphone out.
531 	 * 2. 4-Channel Out
532 	 * 3. True line level out (effectively master volume).
533 	 *
534 	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
535 	 */
536 	if (codec->extcaps & AC97_EXTCAP_SDAC &&
537 	    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
538 		codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
539 		keep_ogain = 1;
540 	}
541 
542 	if (keep_ogain == 0) {
543 		bzero(&codec->mix[SOUND_MIXER_OGAIN],
544 		      sizeof(codec->mix[SOUND_MIXER_OGAIN]));
545 	}
546 }
547 
548 static void
549 ac97_fix_tone(struct ac97_info *codec)
550 {
551 	/*
552 	 * YMF chips does not indicate tone and 3D enhancement capability
553 	 * in the AC97_REG_RESET register.
554 	 */
555 	switch (codec->id) {
556 	case 0x594d4800:	/* YMF743 */
557 	case 0x594d4803:	/* YMF753 */
558 		codec->caps |= AC97_CAP_TONE;
559 		codec->se |= 0x04;
560 		break;
561 	case 0x594d4802:	/* YMF752 */
562 		codec->se |= 0x04;
563 		break;
564 	default:
565 		break;
566 	}
567 
568 	/* Hide treble and bass if they don't exist */
569 	if ((codec->caps & AC97_CAP_TONE) == 0) {
570 		bzero(&codec->mix[SOUND_MIXER_BASS],
571 		      sizeof(codec->mix[SOUND_MIXER_BASS]));
572 		bzero(&codec->mix[SOUND_MIXER_TREBLE],
573 		      sizeof(codec->mix[SOUND_MIXER_TREBLE]));
574 	}
575 }
576 
577 static const char*
578 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
579 {
580 	if (cname == NULL) {
581 		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
582 		return buf;
583 	}
584 
585 	if (vname == NULL) vname = "Unknown";
586 
587 	if (bootverbose) {
588 		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
589 	} else {
590 		sprintf(buf, "%s %s AC97 Codec", vname, cname);
591 	}
592 	return buf;
593 }
594 
595 static unsigned
596 ac97_initmixer(struct ac97_info *codec)
597 {
598 	ac97_patch codec_patch;
599 	const char *cname, *vname;
600 	char desc[80];
601 	device_t pdev;
602 	unsigned i, j, k, bit, old;
603 	u_int32_t id;
604 	int reg;
605 
606 	snd_mtxlock(codec->lock);
607 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
608 	if (codec->count == 0) {
609 		device_printf(codec->dev, "ac97 codec init failed\n");
610 		snd_mtxunlock(codec->lock);
611 		return ENODEV;
612 	}
613 
614 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
615 	ac97_reset(codec);
616 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
617 
618 	i = ac97_rdcd(codec, AC97_REG_RESET);
619 	j = ac97_rdcd(codec, AC97_REG_RESET);
620 	k = ac97_rdcd(codec, AC97_REG_RESET);
621 	/*
622 	 * Let see if this codec can return consistent value.
623 	 * If not, turn on aggressive read workaround
624 	 * (STAC9704 comes in mind).
625 	 */
626 	if (i != j || j != k) {
627 		codec->flags |= AC97_F_RDCD_BUG;
628 		i = ac97_rdcd(codec, AC97_REG_RESET);
629 	}
630 	codec->caps = i & 0x03ff;
631 	codec->se =  (i & 0x7c00) >> 10;
632 
633 	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
634 	if (id == 0 || id == 0xffffffff) {
635 		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
636 		snd_mtxunlock(codec->lock);
637 		return ENODEV;
638 	}
639 
640 	pdev = codec->dev;
641 	while (strcmp(device_get_name(device_get_parent(pdev)), "pci") != 0) {
642 		/* find the top-level PCI device handler */
643 		pdev = device_get_parent(pdev);
644 	}
645 	codec->id = id;
646 	codec->subvendor = (u_int32_t)pci_get_subdevice(pdev) << 16;
647 	codec->subvendor |= (u_int32_t)pci_get_subvendor(pdev) &
648 	    0x0000ffff;
649 	codec->noext = 0;
650 	codec_patch = NULL;
651 
652 	cname = NULL;
653 	for (i = 0; ac97codecid[i].id; i++) {
654 		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
655 		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
656 			codec->noext = ac97codecid[i].noext;
657 			codec_patch = ac97codecid[i].patch;
658 			cname = ac97codecid[i].name;
659 			break;
660 		}
661 	}
662 
663 	vname = NULL;
664 	for (i = 0; ac97vendorid[i].id; i++) {
665 		if (ac97vendorid[i].id == (id & 0xffffff00)) {
666 			vname = ac97vendorid[i].name;
667 			break;
668 		}
669 	}
670 
671 	codec->extcaps = 0;
672 	codec->extid = 0;
673 	codec->extstat = 0;
674 	if (!codec->noext) {
675 		i = ac97_rdcd(codec, AC97_REGEXT_ID);
676 		if (i != 0xffff) {
677 			codec->extcaps = i & 0x3fff;
678 			codec->extid =  (i & 0xc000) >> 14;
679 			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
680 		}
681 	}
682 
683 	for (i = 0; i < AC97_MIXER_SIZE; i++) {
684 		codec->mix[i] = ac97mixtable_default[i];
685 	}
686 	ac97_fix_auxout(codec);
687 	ac97_fix_tone(codec);
688 	if (codec_patch)
689 		codec_patch(codec);
690 
691 	for (i = 0; i < AC97_MIXER_SIZE; i++) {
692 		k = codec->noext? codec->mix[i].enable : 1;
693 		reg = codec->mix[i].reg;
694 		if (reg < 0)
695 			reg = -reg;
696 		if (k && reg) {
697 			j = old = ac97_rdcd(codec, reg);
698 			/*
699 			 * Test for mute bit (except for AC97_MIX_TONE,
700 			 * where we simply assume it as available).
701 			 */
702 			if (codec->mix[i].mute) {
703 				ac97_wrcd(codec, reg, j | 0x8000);
704 				j = ac97_rdcd(codec, reg);
705 			} else
706 				j |= 0x8000;
707 			if ((j & 0x8000)) {
708 				/*
709 				 * Test whether the control width should be
710 				 * 4, 5 or 6 bit. For 5bit register, we should
711 				 * test it whether it's really 5 or 6bit. Leave
712 				 * 4bit register alone, because sometimes an
713 				 * attempt to write past 4th bit may cause
714 				 * incorrect result especially for AC97_MIX_BEEP
715 				 * (ac97 2.3).
716 				 */
717 				bit = codec->mix[i].bits;
718 				if (bit == 5)
719 					bit++;
720 				j = ((1 << bit) - 1) << codec->mix[i].ofs;
721 				ac97_wrcd(codec, reg,
722 					j | (codec->mix[i].mute ? 0x8000 : 0));
723 				k = ac97_rdcd(codec, reg) & j;
724 				k >>= codec->mix[i].ofs;
725 				if (reg == AC97_MIX_TONE &&
726 							((k & 0x0001) == 0x0000))
727 					k >>= 1;
728 				for (j = 0; k >> j; j++)
729 					;
730 				if (j != 0) {
731 					codec->mix[i].enable = 1;
732 					codec->mix[i].bits = j;
733 				} else if (reg == AC97_MIX_BEEP) {
734 					/*
735 					 * Few codec such as CX20468-21 does
736 					 * have this control register, although
737 					 * the only usable part is the mute bit.
738 					 */
739 					codec->mix[i].enable = 1;
740 				} else
741 					codec->mix[i].enable = 0;
742 			} else
743 				codec->mix[i].enable = 0;
744 			ac97_wrcd(codec, reg, old);
745 		}
746 	}
747 
748 	device_printf(codec->dev, "<%s>\n",
749 		      ac97_hw_desc(codec->id, vname, cname, desc));
750 
751 	if (bootverbose) {
752 		if (codec->flags & AC97_F_RDCD_BUG)
753 			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
754 		device_printf(codec->dev, "Codec features ");
755 		for (i = j = 0; i < 10; i++)
756 			if (codec->caps & (1 << i))
757 				printf("%s%s", j++? ", " : "", ac97feature[i]);
758 		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
759 		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
760 
761 		if (codec->extcaps != 0 || codec->extid) {
762 			device_printf(codec->dev, "%s codec",
763 				      codec->extid? "Secondary" : "Primary");
764 			if (codec->extcaps)
765 				printf(" extended features ");
766 			for (i = j = 0; i < 14; i++)
767 				if (codec->extcaps & (1 << i))
768 					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
769 			printf("\n");
770 		}
771 	}
772 
773 	i = 0;
774 	while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
775 		if (++i == 100) {
776 			device_printf(codec->dev, "ac97 codec reports dac not ready\n");
777 			break;
778 		}
779 		DELAY(1000);
780 	}
781 	if (bootverbose)
782 		device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
783 	snd_mtxunlock(codec->lock);
784 	return 0;
785 }
786 
787 static unsigned
788 ac97_reinitmixer(struct ac97_info *codec)
789 {
790 	snd_mtxlock(codec->lock);
791 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
792 	if (codec->count == 0) {
793 		device_printf(codec->dev, "ac97 codec init failed\n");
794 		snd_mtxunlock(codec->lock);
795 		return ENODEV;
796 	}
797 
798 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
799 	ac97_reset(codec);
800 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
801 
802 	if (!codec->noext) {
803 		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
804 		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
805 		    != codec->extstat)
806 			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
807 				      codec->extstat,
808 				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
809 				      AC97_EXTCAPS);
810 	}
811 
812 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
813 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
814 	snd_mtxunlock(codec->lock);
815 	return 0;
816 }
817 
818 struct ac97_info *
819 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
820 {
821 	struct ac97_info *codec;
822 	int i;
823 
824 	codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
825 	snprintf(codec->name, sizeof(codec->name), "%s:ac97",
826 	    device_get_nameunit(dev));
827 	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
828 	codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
829 	codec->dev = dev;
830 	codec->devinfo = devinfo;
831 	codec->flags = 0;
832 
833 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
834 	    "eapdinv", &i) == 0 && i != 0)
835 		codec->flags |= AC97_F_EAPD_INV;
836 
837 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
838 	    "softpcmvol", &i) == 0 && i != 0)
839 		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
840 
841 	return codec;
842 }
843 
844 void
845 ac97_destroy(struct ac97_info *codec)
846 {
847 	snd_mtxlock(codec->lock);
848 	if (codec->methods != NULL)
849 		kobj_delete(codec->methods, M_AC97);
850 	snd_mtxfree(codec->lock);
851 	free(codec, M_AC97);
852 }
853 
854 void
855 ac97_setflags(struct ac97_info *codec, u_int32_t val)
856 {
857 	codec->flags = val;
858 }
859 
860 u_int32_t
861 ac97_getflags(struct ac97_info *codec)
862 {
863 	return codec->flags;
864 }
865 
866 static void
867 ad1886_patch(struct ac97_info *codec)
868 {
869 #define AC97_AD_JACK_SPDIF 0x72
870 	/*
871 	 *    Presario700 workaround
872 	 *     for Jack Sense/SPDIF Register misetting causing
873 	 *    no audible output
874 	 *    by Santiago Nullo 04/05/2002
875 	 */
876 	ac97_wrcd(codec, AC97_AD_JACK_SPDIF, 0x0010);
877 }
878 
879 static void
880 ad198x_patch(struct ac97_info *codec)
881 {
882 	switch (ac97_getsubvendor(codec)) {
883 	case 0x11931043:	/* Not for ASUS A9T (probably else too). */
884 		break;
885 	default:
886 		ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420);
887 		break;
888 	}
889 }
890 
891 static void
892 ad1981b_patch(struct ac97_info *codec)
893 {
894 	/*
895 	 * Enable headphone jack sensing.
896 	 */
897 	switch (ac97_getsubvendor(codec)) {
898 	case 0x02d91014:	/* IBM Thinkcentre */
899 	case 0x099c103c:	/* HP nx6110 */
900 		ac97_wrcd(codec, AC97_AD_JACK_SPDIF,
901 		    ac97_rdcd(codec, AC97_AD_JACK_SPDIF) | 0x0800);
902 		break;
903 	default:
904 		break;
905 	}
906 }
907 
908 static void
909 cmi9739_patch(struct ac97_info *codec)
910 {
911 	/*
912 	 * Few laptops need extra register initialization
913 	 * to power up the internal speakers.
914 	 */
915 	switch (ac97_getsubvendor(codec)) {
916 	case 0x18431043:	/* ASUS W1000N */
917 		ac97_wrcd(codec, AC97_REG_POWER, 0x000f);
918 		ac97_wrcd(codec, AC97_MIXEXT_CLFE, 0x0000);
919 		ac97_wrcd(codec, 0x64, 0x7110);
920 		break;
921 	default:
922 		break;
923 	}
924 }
925 
926 static void
927 alc655_patch(struct ac97_info *codec)
928 {
929 	/*
930 	 * MSI (Micro-Star International) specific EAPD quirk.
931 	 */
932 	switch (ac97_getsubvendor(codec)) {
933 	case 0x00611462:	/* MSI S250 */
934 	case 0x01311462:	/* MSI S270 */
935 	case 0x01611462:	/* LG K1 Express */
936 	case 0x03511462:	/* MSI L725 */
937 		ac97_wrcd(codec, 0x7a, ac97_rdcd(codec, 0x7a) & 0xfffd);
938 		break;
939 	case 0x10ca1734:
940 		/*
941 		 * Amilo Pro V2055 with ALC655 has phone out by default
942 		 * disabled (surround on), leaving us only with internal
943 		 * speakers. This should really go to mixer. We write the
944 		 * Data Flow Control reg.
945 		 */
946 		ac97_wrcd(codec, 0x6a, ac97_rdcd(codec, 0x6a) | 0x0001);
947 		break;
948 	default:
949 		break;
950 	}
951 }
952 
953 /* -------------------------------------------------------------------- */
954 
955 static int
956 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
957 {
958 	struct ac97_info *codec;
959 	int ea, inv, err = 0;
960 	u_int16_t val;
961 
962 	codec = oidp->oid_arg1;
963 	if (codec == NULL || codec->id == 0 || codec->lock == NULL)
964 		return EINVAL;
965 	snd_mtxlock(codec->lock);
966 	val = ac97_rdcd(codec, AC97_REG_POWER);
967 	inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
968 	ea = (val >> 15) ^ inv;
969 	snd_mtxunlock(codec->lock);
970 	err = sysctl_handle_int(oidp, &ea, 0, req);
971 	if (err == 0 && req->newptr != NULL) {
972 		if (ea != 0 && ea != 1)
973 			return EINVAL;
974 		if (ea != ((val >> 15) ^ inv)) {
975 			snd_mtxlock(codec->lock);
976 			ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
977 			snd_mtxunlock(codec->lock);
978 		}
979 	}
980 	return err;
981 }
982 
983 static void
984 ac97_init_sysctl(struct ac97_info *codec)
985 {
986 	u_int16_t orig, val;
987 
988 	if (codec == NULL || codec->dev == NULL)
989 		return;
990 	snd_mtxlock(codec->lock);
991 	orig = ac97_rdcd(codec, AC97_REG_POWER);
992 	ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
993 	val = ac97_rdcd(codec, AC97_REG_POWER);
994 	ac97_wrcd(codec, AC97_REG_POWER, orig);
995 	snd_mtxunlock(codec->lock);
996 	if ((val & 0x8000) == (orig & 0x8000))
997 		return;
998 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
999 	    SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
1000             OID_AUTO, "eapd",
1001 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
1002 	    codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
1003 	    "I", "AC97 External Amplifier");
1004 }
1005 
1006 static int
1007 ac97mix_init(struct snd_mixer *m)
1008 {
1009 	struct ac97_info *codec = mix_getdevinfo(m);
1010 	u_int32_t i, mask;
1011 
1012 	if (codec == NULL)
1013 		return -1;
1014 
1015 	if (ac97_initmixer(codec))
1016 		return -1;
1017 
1018 	switch (codec->id) {
1019 	case 0x41445374:	/* AD1981B */
1020 		switch (codec->subvendor) {
1021 		case 0x02d91014:
1022 			/*
1023 			 * IBM Thinkcentre:
1024 			 *
1025 			 * Tie "ogain" and "phout" to "vol" since its
1026 			 * master volume is basically useless and can't
1027 			 * control anything.
1028 			 */
1029 			mask = 0;
1030 			if (codec->mix[SOUND_MIXER_OGAIN].enable)
1031 				mask |= SOUND_MASK_OGAIN;
1032 			if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
1033 				mask |= SOUND_MASK_PHONEOUT;
1034 			if (codec->mix[SOUND_MIXER_VOLUME].enable)
1035 				mix_setparentchild(m, SOUND_MIXER_VOLUME,
1036 				    mask);
1037 			else {
1038 				mix_setparentchild(m, SOUND_MIXER_VOLUME,
1039 				    mask);
1040 				mix_setrealdev(m, SOUND_MIXER_VOLUME,
1041 				    SOUND_MIXER_NONE);
1042 			}
1043 			break;
1044 		case 0x099c103c:
1045 			/*
1046 			 * HP nx6110:
1047 			 *
1048 			 * By default, "vol" is controlling internal speakers
1049 			 * (not a master volume!) and "ogain" is controlling
1050 			 * headphone. Enable dummy "phout" so it can be
1051 			 * remapped to internal speakers and virtualize
1052 			 * "vol" to control both.
1053 			 */
1054 			codec->mix[SOUND_MIXER_OGAIN].enable = 1;
1055 			codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
1056 			mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
1057 			    SOUND_MIXER_VOLUME);
1058 			mix_setrealdev(m, SOUND_MIXER_VOLUME,
1059 			    SOUND_MIXER_NONE);
1060 			mix_setparentchild(m, SOUND_MIXER_VOLUME,
1061 			    SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
1062 			break;
1063 		default:
1064 			break;
1065 		}
1066 		break;
1067 	case 0x434d4941:	/* CMI9738 */
1068 	case 0x434d4961:	/* CMI9739 */
1069 	case 0x434d4978:	/* CMI9761 */
1070 	case 0x434d4982:	/* CMI9761 */
1071 	case 0x434d4983:	/* CMI9761 */
1072 		bzero(&codec->mix[SOUND_MIXER_PCM],
1073 		    sizeof(codec->mix[SOUND_MIXER_PCM]));
1074 		pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
1075 		    SD_F_SOFTPCMVOL);
1076 		/* XXX How about master volume ? */
1077 		break;
1078 	default:
1079 		break;
1080 	}
1081 
1082 	if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1083 		ac97_wrcd(codec, AC97_MIX_PCM, 0);
1084 
1085 	mask = 0;
1086 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1087 		mask |= codec->mix[i].enable? 1 << i : 0;
1088 	mix_setdevs(m, mask);
1089 
1090 	mask = 0;
1091 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1092 		mask |= codec->mix[i].recidx? 1 << i : 0;
1093 	mix_setrecdevs(m, mask);
1094 
1095 	ac97_init_sysctl(codec);
1096 
1097 	return 0;
1098 }
1099 
1100 static int
1101 ac97mix_uninit(struct snd_mixer *m)
1102 {
1103 	struct ac97_info *codec = mix_getdevinfo(m);
1104 
1105 	if (codec == NULL)
1106 		return -1;
1107 	/*
1108 	if (ac97_uninitmixer(codec))
1109 		return -1;
1110 	*/
1111 	ac97_destroy(codec);
1112 	return 0;
1113 }
1114 
1115 static int
1116 ac97mix_reinit(struct snd_mixer *m)
1117 {
1118 	struct ac97_info *codec = mix_getdevinfo(m);
1119 
1120 	if (codec == NULL)
1121 		return -1;
1122 	return ac97_reinitmixer(codec);
1123 }
1124 
1125 static int
1126 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1127 {
1128 	struct ac97_info *codec = mix_getdevinfo(m);
1129 
1130 	if (codec == NULL || dev >= AC97_MIXER_SIZE)
1131 		return -1;
1132 	return ac97_setmixer(codec, dev, left, right);
1133 }
1134 
1135 static u_int32_t
1136 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1137 {
1138 	int i;
1139 	struct ac97_info *codec = mix_getdevinfo(m);
1140 
1141 	if (codec == NULL)
1142 		return -1;
1143 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1144 		if ((src & (1 << i)) != 0)
1145 			break;
1146 	return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1147 }
1148 
1149 static kobj_method_t ac97mixer_methods[] = {
1150     	KOBJMETHOD(mixer_init,		ac97mix_init),
1151     	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
1152     	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
1153     	KOBJMETHOD(mixer_set,		ac97mix_set),
1154     	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
1155 	KOBJMETHOD_END
1156 };
1157 MIXER_DECLARE(ac97mixer);
1158 
1159 /* -------------------------------------------------------------------- */
1160 
1161 kobj_class_t
1162 ac97_getmixerclass(void)
1163 {
1164 	return &ac97mixer_class;
1165 }
1166