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