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
41static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
42
43struct 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
57struct 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
70struct ac97_vendorid {
71	u_int32_t   id;
72	const char *name;
73};
74
75struct 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
83static 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
103static 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
136static 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
243static 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
278static 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
291static 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
308u_int16_t
309ac97_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
329void
330ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
331{
332	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
333}
334
335static void
336ac97_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
349int
350ac97_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
380int
381ac97_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
396u_int16_t
397ac97_getextmode(struct ac97_info *codec)
398{
399	return codec->extstat;
400}
401
402u_int16_t
403ac97_getextcaps(struct ac97_info *codec)
404{
405	return codec->extcaps;
406}
407
408u_int16_t
409ac97_getcaps(struct ac97_info *codec)
410{
411	return codec->caps;
412}
413
414u_int32_t
415ac97_getsubvendor(struct ac97_info *codec)
416{
417	return codec->subvendor;
418}
419
420static int
421ac97_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
436static int
437ac97_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
515static void
516ac97_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
550static void
551ac97_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
579static const char*
580ac97_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
597static unsigned
598ac97_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
796static unsigned
797ac97_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
827struct ac97_info *
828ac97_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
853void
854ac97_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
863void
864ac97_setflags(struct ac97_info *codec, u_int32_t val)
865{
866	codec->flags = val;
867}
868
869u_int32_t
870ac97_getflags(struct ac97_info *codec)
871{
872	return codec->flags;
873}
874
875/* -------------------------------------------------------------------- */
876
877static int
878sysctl_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
905static void
906ac97_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
928static int
929ac97mix_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
1029static int
1030ac97mix_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
1044static int
1045ac97mix_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
1054static int
1055ac97mix_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
1064static u_int32_t
1065ac97mix_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
1078static 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};
1086MIXER_DECLARE(ac97mixer);
1087
1088/* -------------------------------------------------------------------- */
1089
1090kobj_class_t
1091ac97_getmixerclass(void)
1092{
1093	return &ac97mixer_class;
1094}
1095