ac97.c revision 113907
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <dev/sound/pcm/sound.h>
28#include <dev/sound/pcm/ac97.h>
29#include <dev/sound/pcm/ac97_patch.h>
30
31#include "mixer_if.h"
32
33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 113907 2003-04-23 16:49:53Z jhb $");
34
35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36
37struct ac97mixtable_entry {
38	int	 reg:8;		/* register index		*/
39				/* reg < 0 if inverted polarity	*/
40	unsigned bits:4;	/* width of control field	*/
41	unsigned ofs:4;		/* offset (only if stereo=0)	*/
42	unsigned stereo:1;	/* set for stereo controls	*/
43	unsigned mute:1;	/* bit15 is MUTE		*/
44	unsigned recidx:4;	/* index in rec mux		*/
45	unsigned mask:1;	/* use only masked bits		*/
46	unsigned enable:1;	/* entry is enabled		*/
47};
48
49#define AC97_NAMELEN	16
50struct ac97_info {
51	kobj_t methods;
52	device_t dev;
53	void *devinfo;
54	u_int32_t id;
55	unsigned count, caps, se, extcaps, extid, extstat, noext:1;
56	u_int32_t flags;
57	struct ac97mixtable_entry mix[32];
58	char name[AC97_NAMELEN];
59	struct mtx *lock;
60};
61
62struct ac97_vendorid {
63	u_int32_t   id;
64	const char *name;
65};
66
67struct ac97_codecid {
68	u_int32_t  id;
69	u_int8_t   stepmask;
70	u_int8_t   noext:1;
71	char 	  *name;
72	ac97_patch patch;
73};
74
75static const struct ac97mixtable_entry ac97mixtable_default[32] = {
76    /*	[offset]			reg	     bits of st mu re mk en */
77	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
78	[SOUND_MIXER_MONITOR]	= { AC97_MIX_AUXOUT, 	5, 0, 1, 1, 0, 0, 0 },
79	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
80	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
81	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
82	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
83	[SOUND_MIXER_SPEAKER]	= { AC97_MIX_BEEP, 	4, 1, 0, 1, 0, 0, 0 },
84	[SOUND_MIXER_LINE]	= { AC97_MIX_LINE, 	5, 0, 1, 1, 5, 0, 1 },
85	[SOUND_MIXER_PHONEIN]	= { AC97_MIX_PHONE, 	5, 0, 0, 1, 8, 0, 0 },
86	[SOUND_MIXER_MIC] 	= { AC97_MIX_MIC, 	5, 0, 0, 1, 1, 1, 1 },
87#if 0
88	/* use igain for the mic 20dB boost */
89	[SOUND_MIXER_IGAIN] 	= { -AC97_MIX_MIC, 	1, 6, 0, 0, 0, 1, 1 },
90#endif
91	[SOUND_MIXER_CD]	= { AC97_MIX_CD, 	5, 0, 1, 1, 2, 0, 1 },
92	[SOUND_MIXER_LINE1]	= { AC97_MIX_AUX, 	5, 0, 1, 1, 4, 0, 0 },
93	[SOUND_MIXER_VIDEO]	= { AC97_MIX_VIDEO, 	5, 0, 1, 1, 3, 0, 0 },
94	[SOUND_MIXER_RECLEV]	= { -AC97_MIX_RGAIN, 	4, 0, 1, 1, 0, 0, 1 }
95};
96
97static const struct ac97_vendorid ac97vendorid[] = {
98	{ 0x41445300, "Analog Devices" },
99	{ 0x414b4d00, "Asahi Kasei" },
100	{ 0x414c4300, "Realtek" },
101	{ 0x414c4700, "Avance Logic" },
102	{ 0x43525900, "Cirrus Logic" },
103	{ 0x434d4900, "C-Media Electronics" },
104	{ 0x43585400, "Conexant" },
105	{ 0x454d4300, "eMicro" },
106	{ 0x45838300, "ESS Technology" },
107	{ 0x49434500, "ICEnsemble" },
108	{ 0x4e534300, "National Semiconductor" },
109	{ 0x50534300, "Philips Semiconductor" },
110	{ 0x83847600, "SigmaTel" },
111	{ 0x53494c00, "Silicon Laboratory" },
112	{ 0x54524100, "TriTech" },
113	{ 0x56494100, "VIA Technologies" },
114	{ 0x574d4c00, "Wolfson" },
115	{ 0x594d4800, "Yamaha" },
116	{ 0x00000000, NULL }
117};
118
119static struct ac97_codecid ac97codecid[] = {
120	{ 0x41445303, 0x00, 0, "AD1819",	0 },
121	{ 0x41445340, 0x00, 0, "AD1881",	0 },
122	{ 0x41445348, 0x00, 0, "AD1881A",	0 },
123	{ 0x41445360, 0x00, 0, "AD1885",	0 },
124	{ 0x41445361, 0x00, 0, "AD1886", 	ad1886_patch },
125	{ 0x41445362, 0x00, 0, "AD1887", 	0 },
126	{ 0x41445363, 0x00, 0, "AD1886A", 	0 },
127	{ 0x41445370, 0x00, 0, "AD1980",	0 },
128	{ 0x41445372, 0x00, 0, "AD1981A",	0 },
129	{ 0x41445374, 0x00, 0, "AD1981B",	0 },
130	{ 0x41445375, 0x00, 0, "AD1985",	0 },
131	{ 0x414b4d00, 0x00, 1, "AK4540", 	0 },
132	{ 0x414b4d01, 0x00, 1, "AK4542", 	0 },
133	{ 0x414b4d02, 0x00, 1, "AK4543", 	0 },
134	{ 0x414c4320, 0x0f, 0, "ALC100",	0 },
135	{ 0x414c4730, 0x0f, 0, "ALC101",	0 },
136	{ 0x414c4710, 0x0f, 0, "ALC200", 	0 },
137	{ 0x414c4740, 0x0f, 0, "ALC202", 	0 },
138	{ 0x414c4720, 0x0f, 0, "ALC650", 	0 },
139	{ 0x43525900, 0x07, 0, "CS4297", 	0 },
140	{ 0x43525910, 0x07, 0, "CS4297A", 	0 },
141	{ 0x43525920, 0x07, 0, "CS4294/98",	0 },
142	{ 0x43525930, 0x07, 0, "CS4299",	0 },
143	{ 0x43525940, 0x07, 0, "CS4201",	0 },
144	{ 0x43525958, 0x07, 0, "CS4205",	0 },
145	{ 0x43525960, 0x07, 0, "CS4291A",	0 },
146	{ 0x434d4961, 0x00, 0, "CMI9739",	0 },
147	{ 0x434d4941, 0x00, 0, "CMI9738",	0 },
148	{ 0x43585429, 0x00, 0, "CX20468",	0 },
149	{ 0x454d4323, 0x00, 0, "EM28023",	0 },
150	{ 0x454d4328, 0x00, 0, "EM28028",	0 },
151	{ 0x45838308, 0x00, 0, "ES1988",	0 }, /* Formerly ES1921(?) */
152	{ 0x49434501, 0x00, 0, "ICE1230",	0 },
153	{ 0x49434511, 0x00, 0, "ICE1232",	0 },
154	{ 0x49434514, 0x00, 0, "ICE1232A",	0 },
155	{ 0x49434551, 0x00, 0, "VT1616",	0 }, /* Via badged ICE */
156	{ 0x4e534340, 0x00, 0, "LM4540",	0 }, /* Spec blank on revid */
157	{ 0x4e534343, 0x00, 0, "LM4543",	0 }, /* Ditto */
158	{ 0x4e534346, 0x00, 0, "LM4546A",	0 },
159	{ 0x4e534348, 0x00, 0, "LM4548A",	0 },
160	{ 0x4e534331, 0x00, 0, "LM4549",	0 }, /* (?) */
161	{ 0x4e534349, 0x00, 0, "LM4549A",	0 },
162	{ 0x4e534350, 0x00, 0, "LM4550",	0 },
163	{ 0x50534301, 0x00, 0, "UCB1510",	0 },
164	{ 0x50534304, 0x00, 0, "UCB1400",	0 },
165	{ 0x83847600, 0x00, 0, "STAC9700/83/84",	0 },
166	{ 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
167	{ 0x83847605, 0x00, 0, "STAC9704",	0 },
168	{ 0x83847608, 0x00, 0, "STAC9708/11",	0 },
169	{ 0x83847609, 0x00, 0, "STAC9721/23",	0 },
170	{ 0x83847644, 0x00, 0, "STAC9744/45",	0 },
171	{ 0x83847650, 0x00, 0, "STAC9750/51",	0 },
172	{ 0x83847652, 0x00, 0, "STAC9752/53",	0 },
173	{ 0x83847656, 0x00, 0, "STAC9756/57",	0 },
174	{ 0x83847658, 0x00, 0, "STAC9758/59",	0 },
175	{ 0x83847660, 0x00, 0, "STAC9760/61",	0 }, /* Extrapolated */
176	{ 0x83847662, 0x00, 0, "STAC9762/63",	0 }, /* Extrapolated */
177	{ 0x53494c22, 0x00, 0, "Si3036",	0 },
178	{ 0x53494c23, 0x00, 0, "Si3038",	0 },
179	{ 0x54524103, 0x00, 0, "TR28023",	0 }, /* Extrapolated */
180	{ 0x54524106, 0x00, 0, "TR28026",	0 },
181	{ 0x54524108, 0x00, 0, "TR28028",	0 },
182	{ 0x54524123, 0x00, 0, "TR28602",	0 },
183	{ 0x56494161, 0x00, 0, "VIA1612A",      0 },
184	{ 0x574d4c00, 0x00, 0, "WM9701A",	0 },
185	{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8",	0 },
186	{ 0x574d4c04, 0x00, 0, "WM9704Q",	0 },
187	{ 0x574d4c05, 0x00, 0, "WM9705/10",	0 },
188	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
189	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
190	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
191	{ 0, 0, 0, NULL, 0 }
192};
193
194static char *ac97enhancement[] = {
195	"no 3D Stereo Enhancement",
196	"Analog Devices Phat Stereo",
197	"Creative Stereo Enhancement",
198	"National Semi 3D Stereo Enhancement",
199	"Yamaha Ymersion",
200	"BBE 3D Stereo Enhancement",
201	"Crystal Semi 3D Stereo Enhancement",
202	"Qsound QXpander",
203	"Spatializer 3D Stereo Enhancement",
204	"SRS 3D Stereo Enhancement",
205	"Platform Tech 3D Stereo Enhancement",
206	"AKM 3D Audio",
207	"Aureal Stereo Enhancement",
208	"Aztech 3D Enhancement",
209	"Binaura 3D Audio Enhancement",
210	"ESS Technology Stereo Enhancement",
211	"Harman International VMAx",
212	"Nvidea 3D Stereo Enhancement",
213	"Philips Incredible Sound",
214	"Texas Instruments 3D Stereo Enhancement",
215	"VLSI Technology 3D Stereo Enhancement",
216	"TriTech 3D Stereo Enhancement",
217	"Realtek 3D Stereo Enhancement",
218	"Samsung 3D Stereo Enhancement",
219	"Wolfson Microelectronics 3D Enhancement",
220	"Delta Integration 3D Enhancement",
221	"SigmaTel 3D Enhancement",
222	"Reserved 27",
223	"Rockwell 3D Stereo Enhancement",
224	"Reserved 29",
225	"Reserved 30",
226	"Reserved 31"
227};
228
229static char *ac97feature[] = {
230	"mic channel",
231	"reserved",
232	"tone",
233	"simulated stereo",
234	"headphone",
235	"bass boost",
236	"18 bit DAC",
237	"20 bit DAC",
238	"18 bit ADC",
239	"20 bit ADC"
240};
241
242static char *ac97extfeature[] = {
243	"variable rate PCM",
244	"double rate PCM",
245	"reserved 1",
246	"variable rate mic",
247	"reserved 2",
248	"reserved 3",
249	"center DAC",
250	"surround DAC",
251	"LFE DAC",
252	"AMAP",
253	"reserved 4",
254	"reserved 5",
255	"reserved 6",
256	"reserved 7",
257};
258
259u_int16_t
260ac97_rdcd(struct ac97_info *codec, int reg)
261{
262	return AC97_READ(codec->methods, codec->devinfo, reg);
263}
264
265void
266ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
267{
268	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
269}
270
271static void
272ac97_reset(struct ac97_info *codec)
273{
274	u_int32_t i, ps;
275	ac97_wrcd(codec, AC97_REG_RESET, 0);
276	for (i = 0; i < 500; i++) {
277		ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
278		if (ps == AC97_POWER_STATUS)
279			return;
280		DELAY(1000);
281	}
282	device_printf(codec->dev, "AC97 reset timed out.\n");
283}
284
285int
286ac97_setrate(struct ac97_info *codec, int which, int rate)
287{
288	u_int16_t v;
289
290	switch(which) {
291	case AC97_REGEXT_FDACRATE:
292	case AC97_REGEXT_SDACRATE:
293	case AC97_REGEXT_LDACRATE:
294	case AC97_REGEXT_LADCRATE:
295	case AC97_REGEXT_MADCRATE:
296		break;
297
298	default:
299		return -1;
300	}
301
302	snd_mtxlock(codec->lock);
303	if (rate != 0) {
304		v = rate;
305		if (codec->extstat & AC97_EXTCAP_DRA)
306			v >>= 1;
307		ac97_wrcd(codec, which, v);
308	}
309	v = ac97_rdcd(codec, which);
310	if (codec->extstat & AC97_EXTCAP_DRA)
311		v <<= 1;
312	snd_mtxunlock(codec->lock);
313	return v;
314}
315
316int
317ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
318{
319	mode &= AC97_EXTCAPS;
320	if ((mode & ~codec->extcaps) != 0) {
321		device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
322			      mode);
323		return -1;
324	}
325	snd_mtxlock(codec->lock);
326	ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
327	codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
328	snd_mtxunlock(codec->lock);
329	return (mode == codec->extstat)? 0 : -1;
330}
331
332u_int16_t
333ac97_getextmode(struct ac97_info *codec)
334{
335	return codec->extstat;
336}
337
338u_int16_t
339ac97_getextcaps(struct ac97_info *codec)
340{
341	return codec->extcaps;
342}
343
344u_int16_t
345ac97_getcaps(struct ac97_info *codec)
346{
347	return codec->caps;
348}
349
350static int
351ac97_setrecsrc(struct ac97_info *codec, int channel)
352{
353	struct ac97mixtable_entry *e = &codec->mix[channel];
354
355	if (e->recidx > 0) {
356		int val = e->recidx - 1;
357		val |= val << 8;
358		snd_mtxlock(codec->lock);
359		ac97_wrcd(codec, AC97_REG_RECSEL, val);
360		snd_mtxunlock(codec->lock);
361		return 0;
362	} else
363		return -1;
364}
365
366static int
367ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
368{
369	struct ac97mixtable_entry *e = &codec->mix[channel];
370
371	if (e->reg && e->enable && e->bits) {
372		int mask, max, val, reg;
373
374		reg = (e->reg >= 0) ? e->reg : -e->reg;	/* AC97 register    */
375		max = (1 << e->bits) - 1;		/* actual range	    */
376		mask = (max << 8) | max;		/* bits of interest */
377
378		if (!e->stereo)
379			right = left;
380
381		/*
382		 * Invert the range if the polarity requires so,
383		 * then scale to 0..max-1 to compute the value to
384		 * write into the codec, and scale back to 0..100
385		 * for the return value.
386		 */
387		if (e->reg > 0) {
388			left = 100 - left;
389			right = 100 - right;
390		}
391
392		left = (left * max) / 100;
393		right = (right * max) / 100;
394
395		val = (left << 8) | right;
396
397		left = (left * 100) / max;
398		right = (right * 100) / max;
399
400		if (e->reg > 0) {
401			left = 100 - left;
402			right = 100 - right;
403		}
404
405		/*
406		 * For mono controls, trim val and mask, also taking
407		 * care of e->ofs (offset of control field).
408		 */
409		if (e->ofs) {
410			val &= max;
411			val <<= e->ofs;
412			mask = (max << e->ofs);
413		}
414
415		/*
416		 * If we have a mute bit, add it to the mask and
417		 * update val and set mute if both channels require a
418		 * zero volume.
419		 */
420		if (e->mute == 1) {
421			mask |= AC97_MUTE;
422			if (left == 0 && right == 0)
423				val = AC97_MUTE;
424		}
425
426		/*
427		 * If the mask bit is set, do not alter the other bits.
428		 */
429		snd_mtxlock(codec->lock);
430		if (e->mask) {
431			int cur = ac97_rdcd(codec, e->reg);
432			val |= cur & ~(mask);
433		}
434		ac97_wrcd(codec, reg, val);
435		snd_mtxunlock(codec->lock);
436		return left | (right << 8);
437	} else {
438		/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
439		return -1;
440	}
441}
442
443#if 0
444static int
445ac97_getmixer(struct ac97_info *codec, int channel)
446{
447	struct ac97mixtable_entry *e = &codec->mix[channel];
448	if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
449		int max, val, volume;
450
451		max = (1 << e->bits) - 1;
452		val = ac97_rdcd(code, e->reg);
453		if (val == AC97_MUTE && e->mute == 1)
454			volume = 0;
455		else {
456			if (e->stereo == 0) val >>= e->ofs;
457			val &= max;
458			volume = (val * 100) / max;
459			if (e->reg > 0) volume = 100 - volume;
460		}
461		return volume;
462	} else
463		return -1;
464}
465#endif
466
467static void
468ac97_fix_auxout(struct ac97_info *codec)
469{
470	/* Determine what AUXOUT really means, it can be:
471	 *
472	 * 1. Headphone out.
473	 * 2. 4-Channel Out
474	 * 3. True line level out (effectively master volume).
475	 *
476	 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
477	 */
478	if (codec->caps & AC97_CAP_HEADPHONE) {
479		/* XXX We should probably check the AUX_OUT initial value.
480		 * Leave AC97_MIX_AUXOUT - SOUND_MIXER_MONITOR relationship */
481		return;
482	} else if (codec->extcaps & AC97_EXTCAP_SDAC &&
483		   ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
484		/* 4-Channel Out, add an additional gain setting. */
485		codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
486	} else {
487		/* Master volume is/maybe fixed in h/w, not sufficiently
488		 * clear in spec to blat SOUND_MIXER_MASTER. */
489		codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
490	}
491	/* Blat monitor, inappropriate label if we get here */
492	bzero(&codec->mix[SOUND_MIXER_MONITOR],
493	      sizeof(codec->mix[SOUND_MIXER_MONITOR]));
494}
495
496static const char*
497ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
498{
499	if (cname == NULL) {
500		sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
501		return buf;
502	}
503
504	if (vname == NULL) vname = "Unknown";
505
506	if (bootverbose) {
507		sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
508	} else {
509		sprintf(buf, "%s %s AC97 Codec", vname, cname);
510	}
511	return buf;
512}
513
514static unsigned
515ac97_initmixer(struct ac97_info *codec)
516{
517	ac97_patch codec_patch;
518	const char *cname, *vname;
519	char desc[80];
520	u_int8_t model, step;
521	unsigned i, j, k, old;
522	u_int32_t id;
523
524	snd_mtxlock(codec->lock);
525	codec->count = AC97_INIT(codec->methods, codec->devinfo);
526	if (codec->count == 0) {
527		device_printf(codec->dev, "ac97 codec init failed\n");
528		snd_mtxunlock(codec->lock);
529		return ENODEV;
530	}
531
532	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
533	ac97_reset(codec);
534	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
535
536	i = ac97_rdcd(codec, AC97_REG_RESET);
537	codec->caps = i & 0x03ff;
538	codec->se =  (i & 0x7c00) >> 10;
539
540	id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
541	if (id == 0 || id == 0xffffffff) {
542		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
543		snd_mtxunlock(codec->lock);
544		return ENODEV;
545	}
546
547	codec->id = id;
548	codec->noext = 0;
549	codec_patch = NULL;
550
551	cname = NULL;
552	model = step = 0;
553	for (i = 0; ac97codecid[i].id; i++) {
554		u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
555		if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
556			codec->noext = ac97codecid[i].noext;
557			codec_patch = ac97codecid[i].patch;
558			cname = ac97codecid[i].name;
559			model = (id & modelmask) & 0xff;
560			step = (id & ~modelmask) & 0xff;
561			break;
562		}
563	}
564
565	vname = NULL;
566	for (i = 0; ac97vendorid[i].id; i++) {
567		if (ac97vendorid[i].id == (id & 0xffffff00)) {
568			vname = ac97vendorid[i].name;
569			break;
570		}
571	}
572
573	codec->extcaps = 0;
574	codec->extid = 0;
575	codec->extstat = 0;
576	if (!codec->noext) {
577		i = ac97_rdcd(codec, AC97_REGEXT_ID);
578		if (i != 0xffff) {
579			codec->extcaps = i & 0x3fff;
580			codec->extid =  (i & 0xc000) >> 14;
581			codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
582		}
583	}
584
585	for (i = 0; i < 32; i++) {
586		codec->mix[i] = ac97mixtable_default[i];
587	}
588	ac97_fix_auxout(codec);
589	if (codec_patch)
590		codec_patch(codec);
591
592	for (i = 0; i < 32; i++) {
593		k = codec->noext? codec->mix[i].enable : 1;
594		if (k && (codec->mix[i].reg > 0)) {
595			old = ac97_rdcd(codec, codec->mix[i].reg);
596			ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
597			j = ac97_rdcd(codec, codec->mix[i].reg);
598			ac97_wrcd(codec, codec->mix[i].reg, old);
599			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
600			for (k = 1; j & (1 << k); k++);
601			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
602		}
603		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
604	}
605
606	device_printf(codec->dev, "<%s>\n",
607		      ac97_hw_desc(codec->id, vname, cname, desc));
608
609	if (bootverbose) {
610		device_printf(codec->dev, "Codec features ");
611		for (i = j = 0; i < 10; i++)
612			if (codec->caps & (1 << i))
613				printf("%s%s", j++? ", " : "", ac97feature[i]);
614		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
615		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
616
617		if (codec->extcaps != 0 || codec->extid) {
618			device_printf(codec->dev, "%s codec",
619				      codec->extid? "Secondary" : "Primary");
620			if (codec->extcaps)
621				printf(" extended features ");
622			for (i = j = 0; i < 14; i++)
623				if (codec->extcaps & (1 << i))
624					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
625			printf("\n");
626		}
627	}
628
629	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
630		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
631	snd_mtxunlock(codec->lock);
632	return 0;
633}
634
635static unsigned
636ac97_reinitmixer(struct ac97_info *codec)
637{
638	snd_mtxlock(codec->lock);
639	codec->count = AC97_INIT(codec->methods, codec->devinfo);
640	if (codec->count == 0) {
641		device_printf(codec->dev, "ac97 codec init failed\n");
642		snd_mtxunlock(codec->lock);
643		return ENODEV;
644	}
645
646	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
647	ac97_reset(codec);
648	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
649
650	if (!codec->noext) {
651		ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
652		if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
653		    != codec->extstat)
654			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
655				      codec->extstat,
656				      ac97_rdcd(codec, AC97_REGEXT_STAT) &
657				      AC97_EXTCAPS);
658	}
659
660	if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
661		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
662	snd_mtxunlock(codec->lock);
663	return 0;
664}
665
666struct ac97_info *
667ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
668{
669	struct ac97_info *codec;
670
671	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
672	if (codec == NULL)
673		return NULL;
674
675	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
676	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
677	codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
678	if (codec->methods == NULL) {
679		snd_mtxlock(codec->lock);
680		snd_mtxfree(codec->lock);
681		free(codec, M_AC97);
682		return NULL;
683	}
684
685	codec->dev = dev;
686	codec->devinfo = devinfo;
687	codec->flags = 0;
688	return codec;
689}
690
691void
692ac97_destroy(struct ac97_info *codec)
693{
694	snd_mtxlock(codec->lock);
695	if (codec->methods != NULL)
696		kobj_delete(codec->methods, M_AC97);
697	snd_mtxfree(codec->lock);
698	free(codec, M_AC97);
699}
700
701void
702ac97_setflags(struct ac97_info *codec, u_int32_t val)
703{
704	codec->flags = val;
705}
706
707u_int32_t
708ac97_getflags(struct ac97_info *codec)
709{
710	return codec->flags;
711}
712
713/* -------------------------------------------------------------------- */
714
715static int
716ac97mix_init(struct snd_mixer *m)
717{
718	struct ac97_info *codec = mix_getdevinfo(m);
719	u_int32_t i, mask;
720
721	if (codec == NULL)
722		return -1;
723
724	if (ac97_initmixer(codec))
725		return -1;
726
727	mask = 0;
728	for (i = 0; i < 32; i++)
729		mask |= codec->mix[i].enable? 1 << i : 0;
730	mix_setdevs(m, mask);
731
732	mask = 0;
733	for (i = 0; i < 32; i++)
734		mask |= codec->mix[i].recidx? 1 << i : 0;
735	mix_setrecdevs(m, mask);
736	return 0;
737}
738
739static int
740ac97mix_uninit(struct snd_mixer *m)
741{
742	struct ac97_info *codec = mix_getdevinfo(m);
743
744	if (codec == NULL)
745		return -1;
746	/*
747	if (ac97_uninitmixer(codec))
748		return -1;
749	*/
750	ac97_destroy(codec);
751	return 0;
752}
753
754static int
755ac97mix_reinit(struct snd_mixer *m)
756{
757	struct ac97_info *codec = mix_getdevinfo(m);
758
759	if (codec == NULL)
760		return -1;
761	return ac97_reinitmixer(codec);
762}
763
764static int
765ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
766{
767	struct ac97_info *codec = mix_getdevinfo(m);
768
769	if (codec == NULL)
770		return -1;
771	return ac97_setmixer(codec, dev, left, right);
772}
773
774static int
775ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
776{
777	int i;
778	struct ac97_info *codec = mix_getdevinfo(m);
779
780	if (codec == NULL)
781		return -1;
782	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
783		if ((src & (1 << i)) != 0)
784			break;
785	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
786}
787
788static kobj_method_t ac97mixer_methods[] = {
789    	KOBJMETHOD(mixer_init,		ac97mix_init),
790    	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
791    	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
792    	KOBJMETHOD(mixer_set,		ac97mix_set),
793    	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
794	{ 0, 0 }
795};
796MIXER_DECLARE(ac97mixer);
797
798/* -------------------------------------------------------------------- */
799
800kobj_class_t
801ac97_getmixerclass(void)
802{
803	return &ac97mixer_class;
804}
805
806
807