xref: /freebsd/sys/dev/sound/pcm/ac97.c (revision be4f245e1e4fe60d43aaff5b11b45f2a9a66a51c)
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 	{ 0x01408300, "SigmaTel" },
129 	{ 0x00000000, NULL }
130 };
131 
132 static void ad1886_patch(struct ac97_info *);
133 static void ad198x_patch(struct ac97_info *);
134 static void ad1981b_patch(struct ac97_info *);
135 static void cmi9739_patch(struct ac97_info *);
136 static void alc655_patch(struct ac97_info *);
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 	{ 0x01408384, 0x00, 0, "STAC9704",	0 },
237 	{ 0, 0, 0, NULL, 0 }
238 };
239 
240 static char *ac97enhancement[] = {
241 	"no 3D Stereo Enhancement",
242 	"Analog Devices Phat Stereo",
243 	"Creative Stereo Enhancement",
244 	"National Semi 3D Stereo Enhancement",
245 	"Yamaha Ymersion",
246 	"BBE 3D Stereo Enhancement",
247 	"Crystal Semi 3D Stereo Enhancement",
248 	"Qsound QXpander",
249 	"Spatializer 3D Stereo Enhancement",
250 	"SRS 3D Stereo Enhancement",
251 	"Platform Tech 3D Stereo Enhancement",
252 	"AKM 3D Audio",
253 	"Aureal Stereo Enhancement",
254 	"Aztech 3D Enhancement",
255 	"Binaura 3D Audio Enhancement",
256 	"ESS Technology Stereo Enhancement",
257 	"Harman International VMAx",
258 	"Nvidea 3D Stereo Enhancement",
259 	"Philips Incredible Sound",
260 	"Texas Instruments 3D Stereo Enhancement",
261 	"VLSI Technology 3D Stereo Enhancement",
262 	"TriTech 3D Stereo Enhancement",
263 	"Realtek 3D Stereo Enhancement",
264 	"Samsung 3D Stereo Enhancement",
265 	"Wolfson Microelectronics 3D Enhancement",
266 	"Delta Integration 3D Enhancement",
267 	"SigmaTel 3D Enhancement",
268 	"Reserved 27",
269 	"Rockwell 3D Stereo Enhancement",
270 	"Reserved 29",
271 	"Reserved 30",
272 	"Reserved 31"
273 };
274 
275 static char *ac97feature[] = {
276 	"mic channel",
277 	"reserved",
278 	"tone",
279 	"simulated stereo",
280 	"headphone",
281 	"bass boost",
282 	"18 bit DAC",
283 	"20 bit DAC",
284 	"18 bit ADC",
285 	"20 bit ADC"
286 };
287 
288 static char *ac97extfeature[] = {
289 	"variable rate PCM",
290 	"double rate PCM",
291 	"reserved 1",
292 	"variable rate mic",
293 	"reserved 2",
294 	"reserved 3",
295 	"center DAC",
296 	"surround DAC",
297 	"LFE DAC",
298 	"AMAP",
299 	"reserved 4",
300 	"reserved 5",
301 	"reserved 6",
302 	"reserved 7",
303 };
304 
305 u_int16_t
ac97_rdcd(struct ac97_info * codec,int reg)306 ac97_rdcd(struct ac97_info *codec, int reg)
307 {
308 	if (codec->flags & AC97_F_RDCD_BUG) {
309 		u_int16_t i[2], j = 100;
310 
311 		i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
312 		i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
313 		while (i[0] != i[1] && j)
314 			i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
315 		return i[!(j & 1)];
316 	}
317 	return AC97_READ(codec->methods, codec->devinfo, reg);
318 }
319 
320 void
ac97_wrcd(struct ac97_info * codec,int reg,u_int16_t val)321 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
322 {
323 	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
324 }
325 
326 static void
ac97_reset(struct ac97_info * codec)327 ac97_reset(struct ac97_info *codec)
328 {
329 	u_int32_t i, ps;
330 	ac97_wrcd(codec, AC97_REG_RESET, 0);
331 	for (i = 0; i < 500; i++) {
332 		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
333 		if (ps == AC97_POWER_STATUS)
334 			return;
335 		DELAY(1000);
336 	}
337 	device_printf(codec->dev, "AC97 reset timed out.\n");
338 }
339 
340 int
ac97_setrate(struct ac97_info * codec,int which,int rate)341 ac97_setrate(struct ac97_info *codec, int which, int rate)
342 {
343 	u_int16_t v;
344 
345 	switch(which) {
346 	case AC97_REGEXT_FDACRATE:
347 	case AC97_REGEXT_SDACRATE:
348 	case AC97_REGEXT_LDACRATE:
349 	case AC97_REGEXT_LADCRATE:
350 	case AC97_REGEXT_MADCRATE:
351 		break;
352 
353 	default:
354 		return -1;
355 	}
356 
357 	mtx_lock(&codec->lock);
358 	if (rate != 0) {
359 		v = rate;
360 		if (codec->extstat & AC97_EXTCAP_DRA)
361 			v >>= 1;
362 		ac97_wrcd(codec, which, v);
363 	}
364 	v = ac97_rdcd(codec, which);
365 	if (codec->extstat & AC97_EXTCAP_DRA)
366 		v <<= 1;
367 	mtx_unlock(&codec->lock);
368 	return v;
369 }
370 
371 int
ac97_setextmode(struct ac97_info * codec,u_int16_t mode)372 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
373 {
374 	mode &= AC97_EXTCAPS;
375 	if ((mode & ~codec->extcaps) != 0) {
376 		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
377 			      mode);
378 		return -1;
379 	}
380 	mtx_lock(&codec->lock);
381 	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
382 	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
383 	mtx_unlock(&codec->lock);
384 	return (mode == codec->extstat)? 0 : -1;
385 }
386 
387 u_int16_t
ac97_getextmode(struct ac97_info * codec)388 ac97_getextmode(struct ac97_info *codec)
389 {
390 	return codec->extstat;
391 }
392 
393 u_int16_t
ac97_getextcaps(struct ac97_info * codec)394 ac97_getextcaps(struct ac97_info *codec)
395 {
396 	return codec->extcaps;
397 }
398 
399 u_int16_t
ac97_getcaps(struct ac97_info * codec)400 ac97_getcaps(struct ac97_info *codec)
401 {
402 	return codec->caps;
403 }
404 
405 u_int32_t
ac97_getsubvendor(struct ac97_info * codec)406 ac97_getsubvendor(struct ac97_info *codec)
407 {
408 	return codec->subvendor;
409 }
410 
411 static int
ac97_setrecsrc(struct ac97_info * codec,int channel)412 ac97_setrecsrc(struct ac97_info *codec, int channel)
413 {
414 	struct ac97mixtable_entry *e = &codec->mix[channel];
415 
416 	if (e->recidx > 0) {
417 		int val = e->recidx - 1;
418 		val |= val << 8;
419 		mtx_lock(&codec->lock);
420 		ac97_wrcd(codec, AC97_REG_RECSEL, val);
421 		mtx_unlock(&codec->lock);
422 		return 0;
423 	} else
424 		return -1;
425 }
426 
427 static int
ac97_setmixer(struct ac97_info * codec,unsigned channel,unsigned left,unsigned right)428 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
429 {
430 	struct ac97mixtable_entry *e = &codec->mix[channel];
431 
432 	if (e->reg && e->enable && e->bits) {
433 		int mask, max, val, reg;
434 
435 		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
436 		max = (1 << e->bits) - 1;		/* actual range	    */
437 		mask = (max << 8) | max;		/* bits of interest */
438 
439 		if (!e->stereo)
440 			right = left;
441 
442 		/*
443 		 * Invert the range if the polarity requires so,
444 		 * then scale to 0..max-1 to compute the value to
445 		 * write into the codec, and scale back to 0..100
446 		 * for the return value.
447 		 */
448 		if (e->reg > 0) {
449 			left = 100 - left;
450 			right = 100 - right;
451 		}
452 
453 		left = (left * max) / 100;
454 		right = (right * max) / 100;
455 
456 		val = (left << 8) | right;
457 
458 		left = (left * 100) / max;
459 		right = (right * 100) / max;
460 
461 		if (e->reg > 0) {
462 			left = 100 - left;
463 			right = 100 - right;
464 		}
465 
466 		/*
467 		 * For mono controls, trim val and mask, also taking
468 		 * care of e->ofs (offset of control field).
469 		 */
470 		if (e->ofs) {
471 			val &= max;
472 			val <<= e->ofs;
473 			mask = (max << e->ofs);
474 		}
475 
476 		/*
477 		 * If we have a mute bit, add it to the mask and
478 		 * update val and set mute if both channels require a
479 		 * zero volume.
480 		 */
481 		if (e->mute == 1) {
482 			mask |= AC97_MUTE;
483 			if (left == 0 && right == 0)
484 				val = AC97_MUTE;
485 		}
486 
487 		/*
488 		 * If the mask bit is set, do not alter the other bits.
489 		 */
490 		mtx_lock(&codec->lock);
491 		if (e->mask) {
492 			int cur = ac97_rdcd(codec, reg);
493 			val |= cur & ~(mask);
494 		}
495 		ac97_wrcd(codec, reg, val);
496 		mtx_unlock(&codec->lock);
497 		return left | (right << 8);
498 	} else {
499 		return -1;
500 	}
501 }
502 
503 static void
ac97_fix_auxout(struct ac97_info * codec)504 ac97_fix_auxout(struct ac97_info *codec)
505 {
506 	int keep_ogain;
507 
508 	/*
509 	 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
510 	 * OGAIN setting.
511 	 *
512 	 * We first check whether aux_out is a valid register.  If not
513 	 * we may not want to keep ogain.
514 	 */
515 	keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
516 
517 	/*
518 	 * Determine what AUX_OUT really means, it can be:
519 	 *
520 	 * 1. Headphone out.
521 	 * 2. 4-Channel Out
522 	 * 3. True line level out (effectively master volume).
523 	 *
524 	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
525 	 */
526 	if (codec->extcaps & AC97_EXTCAP_SDAC &&
527 	    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
528 		codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
529 		keep_ogain = 1;
530 	}
531 
532 	if (keep_ogain == 0) {
533 		bzero(&codec->mix[SOUND_MIXER_OGAIN],
534 		      sizeof(codec->mix[SOUND_MIXER_OGAIN]));
535 	}
536 }
537 
538 static void
ac97_fix_tone(struct ac97_info * codec)539 ac97_fix_tone(struct ac97_info *codec)
540 {
541 	/*
542 	 * YMF chips does not indicate tone and 3D enhancement capability
543 	 * in the AC97_REG_RESET register.
544 	 */
545 	switch (codec->id) {
546 	case 0x594d4800:	/* YMF743 */
547 	case 0x594d4803:	/* YMF753 */
548 		codec->caps |= AC97_CAP_TONE;
549 		codec->se |= 0x04;
550 		break;
551 	case 0x594d4802:	/* YMF752 */
552 		codec->se |= 0x04;
553 		break;
554 	default:
555 		break;
556 	}
557 
558 	/* Hide treble and bass if they don't exist */
559 	if ((codec->caps & AC97_CAP_TONE) == 0) {
560 		bzero(&codec->mix[SOUND_MIXER_BASS],
561 		      sizeof(codec->mix[SOUND_MIXER_BASS]));
562 		bzero(&codec->mix[SOUND_MIXER_TREBLE],
563 		      sizeof(codec->mix[SOUND_MIXER_TREBLE]));
564 	}
565 }
566 
567 static const char*
ac97_hw_desc(u_int32_t id,const char * vname,const char * cname,char * buf)568 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
569 {
570 	if (cname == NULL) {
571 		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
572 		return buf;
573 	}
574 
575 	if (vname == NULL) vname = "Unknown";
576 
577 	if (bootverbose) {
578 		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
579 	} else {
580 		sprintf(buf, "%s %s AC97 Codec", vname, cname);
581 	}
582 	return buf;
583 }
584 
585 static unsigned
ac97_initmixer(struct ac97_info * codec)586 ac97_initmixer(struct ac97_info *codec)
587 {
588 	ac97_patch codec_patch;
589 	const char *cname, *vname;
590 	char desc[80];
591 	device_t pdev;
592 	unsigned i, j, k, bit, old;
593 	u_int32_t id;
594 	int reg;
595 
596 	mtx_lock(&codec->lock);
597 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
598 	if (codec->count == 0) {
599 		device_printf(codec->dev, "ac97 codec init failed\n");
600 		mtx_unlock(&codec->lock);
601 		return ENODEV;
602 	}
603 
604 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
605 	ac97_reset(codec);
606 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
607 
608 	i = ac97_rdcd(codec, AC97_REG_RESET);
609 	j = ac97_rdcd(codec, AC97_REG_RESET);
610 	k = ac97_rdcd(codec, AC97_REG_RESET);
611 	/*
612 	 * Let see if this codec can return consistent value.
613 	 * If not, turn on aggressive read workaround
614 	 * (STAC9704 comes in mind).
615 	 */
616 	if (i != j || j != k) {
617 		codec->flags |= AC97_F_RDCD_BUG;
618 		i = ac97_rdcd(codec, AC97_REG_RESET);
619 	}
620 	codec->caps = i & 0x03ff;
621 	codec->se =  (i & 0x7c00) >> 10;
622 
623 	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
624 	if (id == 0 || id == 0xffffffff) {
625 		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
626 		mtx_unlock(&codec->lock);
627 		return ENODEV;
628 	}
629 
630 	pdev = codec->dev;
631 	while (!is_pci_device(pdev)) {
632 		/* find the top-level PCI device handler */
633 		pdev = device_get_parent(pdev);
634 	}
635 	codec->id = id;
636 	codec->subvendor = (u_int32_t)pci_get_subdevice(pdev) << 16;
637 	codec->subvendor |= (u_int32_t)pci_get_subvendor(pdev) &
638 	    0x0000ffff;
639 	codec->noext = 0;
640 	codec_patch = NULL;
641 
642 	cname = NULL;
643 	for (i = 0; ac97codecid[i].id; i++) {
644 		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
645 		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
646 			codec->noext = ac97codecid[i].noext;
647 			codec_patch = ac97codecid[i].patch;
648 			cname = ac97codecid[i].name;
649 			break;
650 		}
651 	}
652 
653 	vname = NULL;
654 	for (i = 0; ac97vendorid[i].id; i++) {
655 		if (ac97vendorid[i].id == (id & 0xffffff00)) {
656 			vname = ac97vendorid[i].name;
657 			break;
658 		}
659 	}
660 
661 	codec->extcaps = 0;
662 	codec->extid = 0;
663 	codec->extstat = 0;
664 	if (!codec->noext) {
665 		i = ac97_rdcd(codec, AC97_REGEXT_ID);
666 		if (i != 0xffff) {
667 			codec->extcaps = i & 0x3fff;
668 			codec->extid =  (i & 0xc000) >> 14;
669 			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
670 		}
671 	}
672 
673 	for (i = 0; i < AC97_MIXER_SIZE; i++) {
674 		codec->mix[i] = ac97mixtable_default[i];
675 	}
676 	ac97_fix_auxout(codec);
677 	ac97_fix_tone(codec);
678 	if (codec_patch)
679 		codec_patch(codec);
680 
681 	for (i = 0; i < AC97_MIXER_SIZE; i++) {
682 		k = codec->noext? codec->mix[i].enable : 1;
683 		reg = codec->mix[i].reg;
684 		if (reg < 0)
685 			reg = -reg;
686 		if (k && reg) {
687 			j = old = ac97_rdcd(codec, reg);
688 			/*
689 			 * Test for mute bit (except for AC97_MIX_TONE,
690 			 * where we simply assume it as available).
691 			 */
692 			if (codec->mix[i].mute) {
693 				ac97_wrcd(codec, reg, j | 0x8000);
694 				j = ac97_rdcd(codec, reg);
695 			} else
696 				j |= 0x8000;
697 			if ((j & 0x8000)) {
698 				/*
699 				 * Test whether the control width should be
700 				 * 4, 5 or 6 bit. For 5bit register, we should
701 				 * test it whether it's really 5 or 6bit. Leave
702 				 * 4bit register alone, because sometimes an
703 				 * attempt to write past 4th bit may cause
704 				 * incorrect result especially for AC97_MIX_BEEP
705 				 * (ac97 2.3).
706 				 */
707 				bit = codec->mix[i].bits;
708 				if (bit == 5)
709 					bit++;
710 				j = ((1 << bit) - 1) << codec->mix[i].ofs;
711 				ac97_wrcd(codec, reg,
712 					j | (codec->mix[i].mute ? 0x8000 : 0));
713 				k = ac97_rdcd(codec, reg) & j;
714 				k >>= codec->mix[i].ofs;
715 				if (reg == AC97_MIX_TONE &&
716 							((k & 0x0001) == 0x0000))
717 					k >>= 1;
718 				for (j = 0; k >> j; j++)
719 					;
720 				if (j != 0) {
721 					codec->mix[i].enable = 1;
722 					codec->mix[i].bits = j;
723 				} else if (reg == AC97_MIX_BEEP) {
724 					/*
725 					 * Few codec such as CX20468-21 does
726 					 * have this control register, although
727 					 * the only usable part is the mute bit.
728 					 */
729 					codec->mix[i].enable = 1;
730 				} else
731 					codec->mix[i].enable = 0;
732 			} else
733 				codec->mix[i].enable = 0;
734 			ac97_wrcd(codec, reg, old);
735 		}
736 	}
737 
738 	device_printf(codec->dev, "<%s>\n",
739 		      ac97_hw_desc(codec->id, vname, cname, desc));
740 
741 	if (bootverbose) {
742 		if (codec->flags & AC97_F_RDCD_BUG)
743 			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
744 		device_printf(codec->dev, "Codec features ");
745 		for (i = j = 0; i < 10; i++)
746 			if (codec->caps & (1 << i))
747 				printf("%s%s", j++? ", " : "", ac97feature[i]);
748 		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
749 		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
750 
751 		if (codec->extcaps != 0 || codec->extid) {
752 			device_printf(codec->dev, "%s codec",
753 				      codec->extid? "Secondary" : "Primary");
754 			if (codec->extcaps)
755 				printf(" extended features ");
756 			for (i = j = 0; i < 14; i++)
757 				if (codec->extcaps & (1 << i))
758 					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
759 			printf("\n");
760 		}
761 	}
762 
763 	i = 0;
764 	while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
765 		if (++i == 100) {
766 			device_printf(codec->dev, "ac97 codec reports dac not ready\n");
767 			break;
768 		}
769 		DELAY(1000);
770 	}
771 	if (bootverbose)
772 		device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
773 	mtx_unlock(&codec->lock);
774 	return 0;
775 }
776 
777 static unsigned
ac97_reinitmixer(struct ac97_info * codec)778 ac97_reinitmixer(struct ac97_info *codec)
779 {
780 	mtx_lock(&codec->lock);
781 	codec->count = AC97_INIT(codec->methods, codec->devinfo);
782 	if (codec->count == 0) {
783 		device_printf(codec->dev, "ac97 codec init failed\n");
784 		mtx_unlock(&codec->lock);
785 		return ENODEV;
786 	}
787 
788 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
789 	ac97_reset(codec);
790 	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
791 
792 	if (!codec->noext) {
793 		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
794 		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
795 		    != codec->extstat)
796 			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
797 				      codec->extstat,
798 				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
799 				      AC97_EXTCAPS);
800 	}
801 
802 	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
803 		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
804 	mtx_unlock(&codec->lock);
805 	return 0;
806 }
807 
808 struct ac97_info *
ac97_create(device_t dev,void * devinfo,kobj_class_t cls)809 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
810 {
811 	struct ac97_info *codec;
812 	int i;
813 
814 	codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
815 	snprintf(codec->name, sizeof(codec->name), "%s:ac97",
816 	    device_get_nameunit(dev));
817 	mtx_init(&codec->lock, codec->name, "ac97 codec", MTX_DEF);
818 	codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
819 	codec->dev = dev;
820 	codec->devinfo = devinfo;
821 	codec->flags = 0;
822 
823 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
824 	    "eapdinv", &i) == 0 && i != 0)
825 		codec->flags |= AC97_F_EAPD_INV;
826 
827 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
828 	    "softpcmvol", &i) == 0 && i != 0)
829 		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
830 
831 	return codec;
832 }
833 
834 void
ac97_destroy(struct ac97_info * codec)835 ac97_destroy(struct ac97_info *codec)
836 {
837 	mtx_lock(&codec->lock);
838 	kobj_delete(codec->methods, M_AC97);
839 	mtx_destroy(&codec->lock);
840 	free(codec, M_AC97);
841 }
842 
843 void
ac97_setflags(struct ac97_info * codec,u_int32_t val)844 ac97_setflags(struct ac97_info *codec, u_int32_t val)
845 {
846 	codec->flags = val;
847 }
848 
849 u_int32_t
ac97_getflags(struct ac97_info * codec)850 ac97_getflags(struct ac97_info *codec)
851 {
852 	return codec->flags;
853 }
854 
855 static void
ad1886_patch(struct ac97_info * codec)856 ad1886_patch(struct ac97_info *codec)
857 {
858 #define AC97_AD_JACK_SPDIF 0x72
859 	/*
860 	 *    Presario700 workaround
861 	 *     for Jack Sense/SPDIF Register misetting causing
862 	 *    no audible output
863 	 *    by Santiago Nullo 04/05/2002
864 	 */
865 	ac97_wrcd(codec, AC97_AD_JACK_SPDIF, 0x0010);
866 }
867 
868 static void
ad198x_patch(struct ac97_info * codec)869 ad198x_patch(struct ac97_info *codec)
870 {
871 	switch (ac97_getsubvendor(codec)) {
872 	case 0x11931043:	/* Not for ASUS A9T (probably else too). */
873 		break;
874 	default:
875 		ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420);
876 		break;
877 	}
878 }
879 
880 static void
ad1981b_patch(struct ac97_info * codec)881 ad1981b_patch(struct ac97_info *codec)
882 {
883 	/*
884 	 * Enable headphone jack sensing.
885 	 */
886 	switch (ac97_getsubvendor(codec)) {
887 	case 0x02d91014:	/* IBM Thinkcentre */
888 	case 0x099c103c:	/* HP nx6110 */
889 		ac97_wrcd(codec, AC97_AD_JACK_SPDIF,
890 		    ac97_rdcd(codec, AC97_AD_JACK_SPDIF) | 0x0800);
891 		break;
892 	default:
893 		break;
894 	}
895 }
896 
897 static void
cmi9739_patch(struct ac97_info * codec)898 cmi9739_patch(struct ac97_info *codec)
899 {
900 	/*
901 	 * Few laptops need extra register initialization
902 	 * to power up the internal speakers.
903 	 */
904 	switch (ac97_getsubvendor(codec)) {
905 	case 0x18431043:	/* ASUS W1000N */
906 		ac97_wrcd(codec, AC97_REG_POWER, 0x000f);
907 		ac97_wrcd(codec, AC97_MIXEXT_CLFE, 0x0000);
908 		ac97_wrcd(codec, 0x64, 0x7110);
909 		break;
910 	default:
911 		break;
912 	}
913 }
914 
915 static void
alc655_patch(struct ac97_info * codec)916 alc655_patch(struct ac97_info *codec)
917 {
918 	/*
919 	 * MSI (Micro-Star International) specific EAPD quirk.
920 	 */
921 	switch (ac97_getsubvendor(codec)) {
922 	case 0x00611462:	/* MSI S250 */
923 	case 0x01311462:	/* MSI S270 */
924 	case 0x01611462:	/* LG K1 Express */
925 	case 0x03511462:	/* MSI L725 */
926 		ac97_wrcd(codec, 0x7a, ac97_rdcd(codec, 0x7a) & 0xfffd);
927 		break;
928 	case 0x10ca1734:
929 		/*
930 		 * Amilo Pro V2055 with ALC655 has phone out by default
931 		 * disabled (surround on), leaving us only with internal
932 		 * speakers. This should really go to mixer. We write the
933 		 * Data Flow Control reg.
934 		 */
935 		ac97_wrcd(codec, 0x6a, ac97_rdcd(codec, 0x6a) | 0x0001);
936 		break;
937 	default:
938 		break;
939 	}
940 }
941 
942 /* -------------------------------------------------------------------- */
943 
944 static int
sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)945 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
946 {
947 	struct ac97_info *codec;
948 	int ea, inv, err = 0;
949 	u_int16_t val;
950 
951 	codec = oidp->oid_arg1;
952 	if (codec == NULL || codec->id == 0)
953 		return EINVAL;
954 	mtx_lock(&codec->lock);
955 	val = ac97_rdcd(codec, AC97_REG_POWER);
956 	inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
957 	ea = (val >> 15) ^ inv;
958 	mtx_unlock(&codec->lock);
959 	err = sysctl_handle_int(oidp, &ea, 0, req);
960 	if (err == 0 && req->newptr != NULL) {
961 		if (ea != 0 && ea != 1)
962 			return EINVAL;
963 		if (ea != ((val >> 15) ^ inv)) {
964 			mtx_lock(&codec->lock);
965 			ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
966 			mtx_unlock(&codec->lock);
967 		}
968 	}
969 	return err;
970 }
971 
972 static void
ac97_init_sysctl(struct ac97_info * codec)973 ac97_init_sysctl(struct ac97_info *codec)
974 {
975 	u_int16_t orig, val;
976 
977 	if (codec == NULL || codec->dev == NULL)
978 		return;
979 	mtx_lock(&codec->lock);
980 	orig = ac97_rdcd(codec, AC97_REG_POWER);
981 	ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
982 	val = ac97_rdcd(codec, AC97_REG_POWER);
983 	ac97_wrcd(codec, AC97_REG_POWER, orig);
984 	mtx_unlock(&codec->lock);
985 	if ((val & 0x8000) == (orig & 0x8000))
986 		return;
987 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
988 	    SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
989             OID_AUTO, "eapd",
990 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
991 	    codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
992 	    "I", "AC97 External Amplifier");
993 }
994 
995 static int
ac97mix_init(struct snd_mixer * m)996 ac97mix_init(struct snd_mixer *m)
997 {
998 	struct ac97_info *codec = mix_getdevinfo(m);
999 	u_int32_t i, mask;
1000 
1001 	if (codec == NULL)
1002 		return -1;
1003 
1004 	if (ac97_initmixer(codec))
1005 		return -1;
1006 
1007 	switch (codec->id) {
1008 	case 0x41445374:	/* AD1981B */
1009 		switch (codec->subvendor) {
1010 		case 0x02d91014:
1011 			/*
1012 			 * IBM Thinkcentre:
1013 			 *
1014 			 * Tie "ogain" and "phout" to "vol" since its
1015 			 * master volume is basically useless and can't
1016 			 * control anything.
1017 			 */
1018 			mask = 0;
1019 			if (codec->mix[SOUND_MIXER_OGAIN].enable)
1020 				mask |= SOUND_MASK_OGAIN;
1021 			if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
1022 				mask |= SOUND_MASK_PHONEOUT;
1023 			if (codec->mix[SOUND_MIXER_VOLUME].enable)
1024 				mix_setparentchild(m, SOUND_MIXER_VOLUME,
1025 				    mask);
1026 			else {
1027 				mix_setparentchild(m, SOUND_MIXER_VOLUME,
1028 				    mask);
1029 				mix_setrealdev(m, SOUND_MIXER_VOLUME,
1030 				    SOUND_MIXER_NONE);
1031 			}
1032 			break;
1033 		case 0x099c103c:
1034 			/*
1035 			 * HP nx6110:
1036 			 *
1037 			 * By default, "vol" is controlling internal speakers
1038 			 * (not a master volume!) and "ogain" is controlling
1039 			 * headphone. Enable dummy "phout" so it can be
1040 			 * remapped to internal speakers and virtualize
1041 			 * "vol" to control both.
1042 			 */
1043 			codec->mix[SOUND_MIXER_OGAIN].enable = 1;
1044 			codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
1045 			mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
1046 			    SOUND_MIXER_VOLUME);
1047 			mix_setrealdev(m, SOUND_MIXER_VOLUME,
1048 			    SOUND_MIXER_NONE);
1049 			mix_setparentchild(m, SOUND_MIXER_VOLUME,
1050 			    SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
1051 			break;
1052 		default:
1053 			break;
1054 		}
1055 		break;
1056 	case 0x434d4941:	/* CMI9738 */
1057 	case 0x434d4961:	/* CMI9739 */
1058 	case 0x434d4978:	/* CMI9761 */
1059 	case 0x434d4982:	/* CMI9761 */
1060 	case 0x434d4983:	/* CMI9761 */
1061 		bzero(&codec->mix[SOUND_MIXER_PCM],
1062 		    sizeof(codec->mix[SOUND_MIXER_PCM]));
1063 		pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
1064 		    SD_F_SOFTPCMVOL);
1065 		/* XXX How about master volume ? */
1066 		break;
1067 	default:
1068 		break;
1069 	}
1070 
1071 	if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1072 		ac97_wrcd(codec, AC97_MIX_PCM, 0);
1073 
1074 	mask = 0;
1075 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1076 		mask |= codec->mix[i].enable? 1 << i : 0;
1077 	mix_setdevs(m, mask);
1078 
1079 	mask = 0;
1080 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1081 		mask |= codec->mix[i].recidx? 1 << i : 0;
1082 	mix_setrecdevs(m, mask);
1083 
1084 	ac97_init_sysctl(codec);
1085 
1086 	return 0;
1087 }
1088 
1089 static int
ac97mix_uninit(struct snd_mixer * m)1090 ac97mix_uninit(struct snd_mixer *m)
1091 {
1092 	struct ac97_info *codec = mix_getdevinfo(m);
1093 
1094 	if (codec == NULL)
1095 		return -1;
1096 	ac97_destroy(codec);
1097 	return 0;
1098 }
1099 
1100 static int
ac97mix_reinit(struct snd_mixer * m)1101 ac97mix_reinit(struct snd_mixer *m)
1102 {
1103 	struct ac97_info *codec = mix_getdevinfo(m);
1104 
1105 	if (codec == NULL)
1106 		return -1;
1107 	return ac97_reinitmixer(codec);
1108 }
1109 
1110 static int
ac97mix_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)1111 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1112 {
1113 	struct ac97_info *codec = mix_getdevinfo(m);
1114 
1115 	if (codec == NULL || dev >= AC97_MIXER_SIZE)
1116 		return -1;
1117 	return ac97_setmixer(codec, dev, left, right);
1118 }
1119 
1120 static u_int32_t
ac97mix_setrecsrc(struct snd_mixer * m,u_int32_t src)1121 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1122 {
1123 	int i;
1124 	struct ac97_info *codec = mix_getdevinfo(m);
1125 
1126 	if (codec == NULL)
1127 		return -1;
1128 	for (i = 0; i < AC97_MIXER_SIZE; i++)
1129 		if ((src & (1 << i)) != 0)
1130 			break;
1131 	return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1132 }
1133 
1134 static kobj_method_t ac97mixer_methods[] = {
1135     	KOBJMETHOD(mixer_init,		ac97mix_init),
1136     	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
1137     	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
1138     	KOBJMETHOD(mixer_set,		ac97mix_set),
1139     	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
1140 	KOBJMETHOD_END
1141 };
1142 MIXER_DECLARE(ac97mixer);
1143 
1144 /* -------------------------------------------------------------------- */
1145 
1146 kobj_class_t
ac97_getmixerclass(void)1147 ac97_getmixerclass(void)
1148 {
1149 	return &ac97mixer_class;
1150 }
1151