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