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