1
2/*
3 * ac97_codec.c: Generic AC97 mixer/modem module
4 *
5 * Derived from ac97 mixer in maestro and trident driver.
6 *
7 * Copyright 2000 Silicon Integrated System Corporation
8 *
9 *	This program is free software; you can redistribute it and/or modify
10 *	it under the terms of the GNU General Public License as published by
11 *	the Free Software Foundation; either version 2 of the License, or
12 *	(at your option) any later version.
13 *
14 *	This program is distributed in the hope that it will be useful,
15 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *	GNU General Public License for more details.
18 *
19 *	You should have received a copy of the GNU General Public License
20 *	along with this program; if not, write to the Free Software
21 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 **************************************************************************
24 *
25 * The Intel Audio Codec '97 specification is available at the Intel
26 * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/
27 *
28 * The specification itself is currently available at:
29 * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf
30 *
31 **************************************************************************
32 *
33 * History
34 * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
35 *	corrections to support WM9707 in ViewPad 1000
36 * v0.4 Mar 15 2000 Ollie Lho
37 *	dual codecs support verified with 4 channels output
38 * v0.3 Feb 22 2000 Ollie Lho
39 *	bug fix for record mask setting
40 * v0.2 Feb 10 2000 Ollie Lho
41 *	add ac97_read_proc for /proc/driver/{vendor}/ac97
42 * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
43 *	Isolated from trident.c to support multiple ac97 codec
44 */
45#include <linux/module.h>
46#include <linux/version.h>
47#include <linux/kernel.h>
48#include <linux/string.h>
49#include <linux/errno.h>
50#include <linux/bitops.h>
51#include <linux/delay.h>
52#include <linux/ac97_codec.h>
53#include <asm/uaccess.h>
54
55static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
56static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
57			     unsigned int left, unsigned int right);
58static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
59static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
60static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
61
62static int ac97_init_mixer(struct ac97_codec *codec);
63
64static int wolfson_init00(struct ac97_codec * codec);
65static int wolfson_init03(struct ac97_codec * codec);
66static int wolfson_init04(struct ac97_codec * codec);
67static int tritech_init(struct ac97_codec * codec);
68static int tritech_maestro_init(struct ac97_codec * codec);
69static int sigmatel_9708_init(struct ac97_codec *codec);
70static int sigmatel_9721_init(struct ac97_codec *codec);
71static int sigmatel_9744_init(struct ac97_codec *codec);
72static int ad1886_init(struct ac97_codec *codec);
73static int eapd_control(struct ac97_codec *codec, int);
74static int crystal_digital_control(struct ac97_codec *codec, int mode);
75
76
77/*
78 *	AC97 operations.
79 *
80 *	If you are adding a codec then you should be able to use
81 *		eapd_ops - any codec that supports EAPD amp control (most)
82 *		null_ops - any ancient codec that supports nothing
83 *
84 *	The three functions are
85 *		init - used for non AC97 standard initialisation
86 *		amplifier - used to do amplifier control (1=on 0=off)
87 *		digital - switch to digital modes (0 = analog)
88 *
89 *	Not all codecs support all features, not all drivers use all the
90 *	operations yet
91 */
92
93static struct ac97_ops null_ops = { NULL, NULL, NULL };
94static struct ac97_ops default_ops = { NULL, eapd_control, NULL };
95static struct ac97_ops wolfson_ops00 = { wolfson_init00, NULL, NULL };
96static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
97static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
98static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
99static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
100static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
101static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
102static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
103static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
104static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
105
106/* sorted by vendor/device id */
107static const struct {
108	u32 id;
109	char *name;
110	struct ac97_ops *ops;
111} ac97_codec_ids[] = {
112	{0x41445303, "Analog Devices AD1819",	&null_ops},
113	{0x41445340, "Analog Devices AD1881",	&null_ops},
114	{0x41445348, "Analog Devices AD1881A",	&null_ops},
115	{0x41445360, "Analog Devices AD1885",	&default_ops},
116	{0x41445361, "Analog Devices AD1886",	&ad1886_ops},
117	{0x41445460, "Analog Devices AD1885",	&default_ops},
118	{0x41445461, "Analog Devices AD1886",	&ad1886_ops},
119	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
120	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
121	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
122	{0x414C4710, "ALC200/200P",		&null_ops},
123	{0x414C4720, "ALC650",			&null_ops},
124	{0x43525900, "Cirrus Logic CS4297",	&default_ops},
125	{0x43525903, "Cirrus Logic CS4297",	&default_ops},
126	{0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
127	{0x43525914, "Cirrus Logic CS4297A rev B", &default_ops},
128	{0x43525923, "Cirrus Logic CS4298",	&null_ops},
129	{0x4352592B, "Cirrus Logic CS4294",	&null_ops},
130	{0x4352592D, "Cirrus Logic CS4294",	&null_ops},
131	{0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
132	{0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
133	{0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
134	{0x45838308, "ESS Allegro ES1988",	&null_ops},
135	{0x49434511, "ICE1232",			&null_ops}, /* I hope --jk */
136	{0x4e534331, "National Semiconductor LM4549", &null_ops},
137	{0x53494c22, "Silicon Laboratory Si3036", &null_ops},
138	{0x53494c23, "Silicon Laboratory Si3038", &null_ops},
139	{0x545200FF, "TriTech TR?????",		&tritech_m_ops},
140	{0x54524102, "TriTech TR28022",		&null_ops},
141	{0x54524103, "TriTech TR28023",		&null_ops},
142	{0x54524106, "TriTech TR28026",		&null_ops},
143	{0x54524108, "TriTech TR28028",		&tritech_ops},
144	{0x54524123, "TriTech TR A5",		&null_ops},
145	{0x574D4C00, "Wolfson WM9700A",		&wolfson_ops00},
146	{0x574D4C03, "Wolfson WM9703/WM9707",	&wolfson_ops03},
147	{0x574D4C04, "Wolfson WM9704M/WM9704Q",	&wolfson_ops04},
148	{0x83847600, "SigmaTel STAC????",	&null_ops},
149	{0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
150	{0x83847605, "SigmaTel STAC9704",	&null_ops},
151	{0x83847608, "SigmaTel STAC9708",	&sigmatel_9708_ops},
152	{0x83847609, "SigmaTel STAC9721/23",	&sigmatel_9721_ops},
153	{0x83847644, "SigmaTel STAC9744/45",	&sigmatel_9744_ops},
154	{0x83847656, "SigmaTel STAC9756/57",	&sigmatel_9744_ops},
155	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
156	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
157	{0x57454301, "Winbond 83971D",		&null_ops},
158};
159
160static const char *ac97_stereo_enhancements[] =
161{
162	/*   0 */ "No 3D Stereo Enhancement",
163	/*   1 */ "Analog Devices Phat Stereo",
164	/*   2 */ "Creative Stereo Enhancement",
165	/*   3 */ "National Semi 3D Stereo Enhancement",
166	/*   4 */ "YAMAHA Ymersion",
167	/*   5 */ "BBE 3D Stereo Enhancement",
168	/*   6 */ "Crystal Semi 3D Stereo Enhancement",
169	/*   7 */ "Qsound QXpander",
170	/*   8 */ "Spatializer 3D Stereo Enhancement",
171	/*   9 */ "SRS 3D Stereo Enhancement",
172	/*  10 */ "Platform Tech 3D Stereo Enhancement",
173	/*  11 */ "AKM 3D Audio",
174	/*  12 */ "Aureal Stereo Enhancement",
175	/*  13 */ "Aztech 3D Enhancement",
176	/*  14 */ "Binaura 3D Audio Enhancement",
177	/*  15 */ "ESS Technology Stereo Enhancement",
178	/*  16 */ "Harman International VMAx",
179	/*  17 */ "Nvidea 3D Stereo Enhancement",
180	/*  18 */ "Philips Incredible Sound",
181	/*  19 */ "Texas Instruments 3D Stereo Enhancement",
182	/*  20 */ "VLSI Technology 3D Stereo Enhancement",
183	/*  21 */ "TriTech 3D Stereo Enhancement",
184	/*  22 */ "Realtek 3D Stereo Enhancement",
185	/*  23 */ "Samsung 3D Stereo Enhancement",
186	/*  24 */ "Wolfson Microelectronics 3D Enhancement",
187	/*  25 */ "Delta Integration 3D Enhancement",
188	/*  26 */ "SigmaTel 3D Enhancement",
189	/*  27 */ "Winbond 3D Stereo Enhancement",
190	/*  28 */ "Rockwell 3D Stereo Enhancement",
191	/*  29 */ "Reserved 29",
192	/*  30 */ "Reserved 30",
193	/*  31 */ "Reserved 31"
194};
195
196/* this table has default mixer values for all OSS mixers. */
197static struct mixer_defaults {
198	int mixer;
199	unsigned int value;
200} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
201	/* all values 0 -> 100 in bytes */
202	{SOUND_MIXER_VOLUME,	0x4343},
203	{SOUND_MIXER_BASS,	0x4343},
204	{SOUND_MIXER_TREBLE,	0x4343},
205	{SOUND_MIXER_PCM,	0x4343},
206	{SOUND_MIXER_SPEAKER,	0x4343},
207	{SOUND_MIXER_LINE,	0x4343},
208	{SOUND_MIXER_MIC,	0x0000},
209	{SOUND_MIXER_CD,	0x4343},
210	{SOUND_MIXER_ALTPCM,	0x4343},
211	{SOUND_MIXER_IGAIN,	0x4343},
212	{SOUND_MIXER_LINE1,	0x4343},
213	{SOUND_MIXER_PHONEIN,	0x4343},
214	{SOUND_MIXER_PHONEOUT,	0x4343},
215	{SOUND_MIXER_VIDEO,	0x4343},
216	{-1,0}
217};
218
219/* table to scale scale from OSS mixer value to AC97 mixer register value */
220static struct ac97_mixer_hw {
221	unsigned char offset;
222	int scale;
223} ac97_hw[SOUND_MIXER_NRDEVICES]= {
224	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,64},
225	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	16},
226	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE,	16},
227	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	32},
228	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,	16},
229	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	32},
230	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		32},
231	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		32},
232	[SOUND_MIXER_ALTPCM]	=	{AC97_HEADPHONE_VOL,	64},
233	[SOUND_MIXER_IGAIN]	=	{AC97_RECORD_GAIN,	16},
234	[SOUND_MIXER_LINE1]	=	{AC97_AUX_VOL,		32},
235	[SOUND_MIXER_PHONEIN]	= 	{AC97_PHONE_VOL,	32},
236	[SOUND_MIXER_PHONEOUT]	= 	{AC97_MASTER_VOL_MONO,	64},
237	[SOUND_MIXER_VIDEO]	=	{AC97_VIDEO_VOL,	32},
238};
239
240/* the following tables allow us to go from OSS <-> ac97 quickly. */
241enum ac97_recsettings {
242	AC97_REC_MIC=0,
243	AC97_REC_CD,
244	AC97_REC_VIDEO,
245	AC97_REC_AUX,
246	AC97_REC_LINE,
247	AC97_REC_STEREO, /* combination of all enabled outputs..  */
248	AC97_REC_MONO,	      /*.. or the mono equivalent */
249	AC97_REC_PHONE
250};
251
252static const unsigned int ac97_rm2oss[] = {
253	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC,
254	[AC97_REC_CD] 	 = SOUND_MIXER_CD,
255	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
256	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1,
257	[AC97_REC_LINE]  = SOUND_MIXER_LINE,
258	[AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
259	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
260};
261
262/* indexed by bit position */
263static const unsigned int ac97_oss_rm[] = {
264	[SOUND_MIXER_MIC] 	= AC97_REC_MIC,
265	[SOUND_MIXER_CD] 	= AC97_REC_CD,
266	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
267	[SOUND_MIXER_LINE1] 	= AC97_REC_AUX,
268	[SOUND_MIXER_LINE] 	= AC97_REC_LINE,
269	[SOUND_MIXER_IGAIN]	= AC97_REC_STEREO,
270	[SOUND_MIXER_PHONEIN] 	= AC97_REC_PHONE
271};
272
273/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
274   about that given mixer, and should be holding a spinlock for the card */
275static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel)
276{
277	u16 val;
278	int ret = 0;
279	int scale;
280	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
281
282	val = codec->codec_read(codec , mh->offset);
283
284	if (val & AC97_MUTE) {
285		ret = 0;
286	} else if (AC97_STEREO_MASK & (1 << oss_channel)) {
287		/* nice stereo mixers .. */
288		int left,right;
289
290		left = (val >> 8)  & 0x7f;
291		right = val  & 0x7f;
292
293		if (oss_channel == SOUND_MIXER_IGAIN) {
294			right = (right * 100) / mh->scale;
295			left = (left * 100) / mh->scale;
296		} else {
297			/* these may have 5 or 6 bit resolution */
298			if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
299				scale = (1 << codec->bit_resolution);
300			else
301				scale = mh->scale;
302
303			right = 100 - ((right * 100) / scale);
304			left = 100 - ((left * 100) / scale);
305		}
306		ret = left | (right << 8);
307	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
308		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
309	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
310		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
311	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
312		scale = (1 << codec->bit_resolution);
313		ret = 100 - (((val & 0x1f) * 100) / scale);
314	} else if (oss_channel == SOUND_MIXER_MIC) {
315		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
316		/*  the low bit is optional in the tone sliders and masking
317		    it lets us avoid the 0xf 'bypass'.. */
318	} else if (oss_channel == SOUND_MIXER_BASS) {
319		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
320	} else if (oss_channel == SOUND_MIXER_TREBLE) {
321		ret = 100 - (((val & 0xe) * 100) / mh->scale);
322	}
323
324#ifdef DEBUG
325	printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
326	       "0x%04x -> 0x%04x\n",
327	       oss_channel, codec->id ? "Secondary" : "Primary",
328	       mh->offset, val, ret);
329#endif
330
331	return ret;
332}
333
334/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
335   make sure all is well in arg land, call with spinlock held */
336static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
337		      unsigned int left, unsigned int right)
338{
339	u16 val = 0;
340	int scale;
341	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
342
343#ifdef DEBUG
344	printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
345	       "left vol:%2d, right vol:%2d:",
346	       oss_channel, codec->id ? "Secondary" : "Primary",
347	       mh->offset, left, right);
348#endif
349
350	if (AC97_STEREO_MASK & (1 << oss_channel)) {
351		/* stereo mixers */
352		if (left == 0 && right == 0) {
353			val = AC97_MUTE;
354		} else {
355			if (oss_channel == SOUND_MIXER_IGAIN) {
356				right = (right * mh->scale) / 100;
357				left = (left * mh->scale) / 100;
358				if (right >= mh->scale)
359					right = mh->scale-1;
360				if (left >= mh->scale)
361					left = mh->scale-1;
362			} else {
363				/* these may have 5 or 6 bit resolution */
364				if (oss_channel == SOUND_MIXER_VOLUME ||
365				    oss_channel == SOUND_MIXER_ALTPCM)
366					scale = (1 << codec->bit_resolution);
367				else
368					scale = mh->scale;
369
370				right = ((100 - right) * scale) / 100;
371				left = ((100 - left) * scale) / 100;
372				if (right >= scale)
373					right = scale-1;
374				if (left >= scale)
375					left = scale-1;
376			}
377			val = (left << 8) | right;
378		}
379	} else if (oss_channel == SOUND_MIXER_BASS) {
380		val = codec->codec_read(codec , mh->offset) & ~0x0f00;
381		left = ((100 - left) * mh->scale) / 100;
382		if (left >= mh->scale)
383			left = mh->scale-1;
384		val |= (left << 8) & 0x0e00;
385	} else if (oss_channel == SOUND_MIXER_TREBLE) {
386		val = codec->codec_read(codec , mh->offset) & ~0x000f;
387		left = ((100 - left) * mh->scale) / 100;
388		if (left >= mh->scale)
389			left = mh->scale-1;
390		val |= left & 0x000e;
391	} else if(left == 0) {
392		val = AC97_MUTE;
393	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
394		left = ((100 - left) * mh->scale) / 100;
395		if (left >= mh->scale)
396			left = mh->scale-1;
397		val = left << 1;
398	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
399		left = ((100 - left) * mh->scale) / 100;
400		if (left >= mh->scale)
401			left = mh->scale-1;
402		val = left;
403	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
404		scale = (1 << codec->bit_resolution);
405		left = ((100 - left) * scale) / 100;
406		if (left >= mh->scale)
407			left = mh->scale-1;
408		val = left;
409	} else if (oss_channel == SOUND_MIXER_MIC) {
410		val = codec->codec_read(codec , mh->offset) & ~0x801f;
411		left = ((100 - left) * mh->scale) / 100;
412		if (left >= mh->scale)
413			left = mh->scale-1;
414		val |= left;
415		/*  the low bit is optional in the tone sliders and masking
416		    it lets us avoid the 0xf 'bypass'.. */
417	}
418#ifdef DEBUG
419	printk(" 0x%04x", val);
420#endif
421
422	codec->codec_write(codec, mh->offset, val);
423
424#ifdef DEBUG
425	val = codec->codec_read(codec, mh->offset);
426	printk(" -> 0x%04x\n", val);
427#endif
428}
429
430/* a thin wrapper for write_mixer */
431static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val )
432{
433	unsigned int left,right;
434
435	/* cleanse input a little */
436	right = ((val >> 8)  & 0xff) ;
437	left = (val  & 0xff) ;
438
439	if (right > 100) right = 100;
440	if (left > 100) left = 100;
441
442	codec->mixer_state[oss_mixer] = (right << 8) | left;
443	codec->write_mixer(codec, oss_mixer, left, right);
444}
445
446/* read or write the recmask, the ac97 can really have left and right recording
447   inputs independantly set, but OSS doesn't seem to want us to express that to
448   the user. the caller guarantees that we have a supported bit set, and they
449   must be holding the card's spinlock */
450static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask)
451{
452	unsigned int val;
453
454	if (rw) {
455		/* read it from the card */
456		val = codec->codec_read(codec, AC97_RECORD_SELECT);
457#ifdef DEBUG
458		printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
459#endif
460		return (1 << ac97_rm2oss[val & 0x07]);
461	}
462
463	/* else, write the first set in the mask as the
464	   output */
465	/* clear out current set value first (AC97 supports only 1 input!) */
466	val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
467	if (mask != val)
468	    mask &= ~val;
469
470	val = ffs(mask);
471	val = ac97_oss_rm[val-1];
472	val |= val << 8;  /* set both channels */
473
474#ifdef DEBUG
475	printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
476#endif
477
478	codec->codec_write(codec, AC97_RECORD_SELECT, val);
479
480	return 0;
481};
482
483static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
484{
485	int i, val = 0;
486
487	if (cmd == SOUND_MIXER_INFO) {
488		mixer_info info;
489		strncpy(info.id, codec->name, sizeof(info.id));
490		strncpy(info.name, codec->name, sizeof(info.name));
491		info.modify_counter = codec->modcnt;
492		if (copy_to_user((void *)arg, &info, sizeof(info)))
493			return -EFAULT;
494		return 0;
495	}
496	if (cmd == SOUND_OLD_MIXER_INFO) {
497		_old_mixer_info info;
498		strncpy(info.id, codec->name, sizeof(info.id));
499		strncpy(info.name, codec->name, sizeof(info.name));
500		if (copy_to_user((void *)arg, &info, sizeof(info)))
501			return -EFAULT;
502		return 0;
503	}
504
505	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
506		return -EINVAL;
507
508	if (cmd == OSS_GETVERSION)
509		return put_user(SOUND_VERSION, (int *)arg);
510
511	if (_SIOC_DIR(cmd) == _SIOC_READ) {
512		switch (_IOC_NR(cmd)) {
513		case SOUND_MIXER_RECSRC: /* give them the current record source */
514			if (!codec->recmask_io) {
515				val = 0;
516			} else {
517				val = codec->recmask_io(codec, 1, 0);
518			}
519			break;
520
521		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
522			val = codec->supported_mixers;
523			break;
524
525		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
526			val = codec->record_sources;
527			break;
528
529		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
530			val = codec->stereo_mixers;
531			break;
532
533		case SOUND_MIXER_CAPS:
534			val = SOUND_CAP_EXCL_INPUT;
535			break;
536
537		default: /* read a specific mixer */
538			i = _IOC_NR(cmd);
539
540			if (!supported_mixer(codec, i))
541				return -EINVAL;
542
543			/* do we ever want to touch the hardware? */
544		        /* val = codec->read_mixer(codec, i); */
545			val = codec->mixer_state[i];
546 			break;
547		}
548		return put_user(val, (int *)arg);
549	}
550
551	if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
552		codec->modcnt++;
553		if (get_user(val, (int *)arg))
554			return -EFAULT;
555
556		switch (_IOC_NR(cmd)) {
557		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
558			if (!codec->recmask_io) return -EINVAL;
559			if (!val) return 0;
560			if (!(val &= codec->record_sources)) return -EINVAL;
561
562			codec->recmask_io(codec, 0, val);
563
564			return 0;
565		default: /* write a specific mixer */
566			i = _IOC_NR(cmd);
567
568			if (!supported_mixer(codec, i))
569				return -EINVAL;
570
571			ac97_set_mixer(codec, i, val);
572
573			return 0;
574		}
575	}
576	return -EINVAL;
577}
578
579/* entry point for /proc/driver/controller_vendor/ac97/%d */
580int ac97_read_proc (char *page, char **start, off_t off,
581		    int count, int *eof, void *data)
582{
583	int len = 0, cap, extid, val, id1, id2;
584	struct ac97_codec *codec;
585	int is_ac97_20 = 0;
586
587	if ((codec = data) == NULL)
588		return -ENODEV;
589
590	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
591	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
592	len += sprintf (page+len, "Vendor name      : %s\n", codec->name);
593	len += sprintf (page+len, "Vendor id        : %04X %04X\n", id1, id2);
594
595	extid = codec->codec_read(codec, AC97_EXTENDED_ID);
596	extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
597	len += sprintf (page+len, "AC97 Version     : %s\n",
598			extid ? "2.0 or later" : "1.0");
599	if (extid) is_ac97_20 = 1;
600
601	cap = codec->codec_read(codec, AC97_RESET);
602	len += sprintf (page+len, "Capabilities     :%s%s%s%s%s%s\n",
603			cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
604			cap & 0x0002 ? " -reserved1-" : "",
605			cap & 0x0004 ? " -bass & treble-" : "",
606			cap & 0x0008 ? " -simulated stereo-" : "",
607			cap & 0x0010 ? " -headphone out-" : "",
608			cap & 0x0020 ? " -loudness-" : "");
609	val = cap & 0x00c0;
610	len += sprintf (page+len, "DAC resolutions  :%s%s%s\n",
611			" -16-bit-",
612			val & 0x0040 ? " -18-bit-" : "",
613			val & 0x0080 ? " -20-bit-" : "");
614	val = cap & 0x0300;
615	len += sprintf (page+len, "ADC resolutions  :%s%s%s\n",
616			" -16-bit-",
617			val & 0x0100 ? " -18-bit-" : "",
618			val & 0x0200 ? " -20-bit-" : "");
619	len += sprintf (page+len, "3D enhancement   : %s\n",
620			ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
621
622	val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
623	len += sprintf (page+len, "POP path         : %s 3D\n"
624			"Sim. stereo      : %s\n"
625			"3D enhancement   : %s\n"
626			"Loudness         : %s\n"
627			"Mono output      : %s\n"
628			"MIC select       : %s\n"
629			"ADC/DAC loopback : %s\n",
630			val & 0x8000 ? "post" : "pre",
631			val & 0x4000 ? "on" : "off",
632			val & 0x2000 ? "on" : "off",
633			val & 0x1000 ? "on" : "off",
634			val & 0x0200 ? "MIC" : "MIX",
635			val & 0x0100 ? "MIC2" : "MIC1",
636			val & 0x0080 ? "on" : "off");
637
638	extid = codec->codec_read(codec, AC97_EXTENDED_ID);
639	cap = extid;
640	len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
641			cap & 0x0001 ? " -var rate PCM audio-" : "",
642			cap & 0x0002 ? " -2x PCM audio out-" : "",
643			cap & 0x0008 ? " -var rate MIC in-" : "",
644			cap & 0x0040 ? " -PCM center DAC-" : "",
645			cap & 0x0080 ? " -PCM surround DAC-" : "",
646			cap & 0x0100 ? " -PCM LFE DAC-" : "",
647			cap & 0x0200 ? " -slot/DAC mappings-" : "");
648	if (is_ac97_20) {
649		len += sprintf (page+len, "Front DAC rate   : %d\n",
650				codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
651	}
652
653	return len;
654}
655
656/**
657 *	codec_id	-  Turn id1/id2 into a PnP string
658 *	@id1: Vendor ID1
659 *	@id2: Vendor ID2
660 *	@buf: 10 byte buffer
661 *
662 *	Fills buf with a zero terminated PnP ident string for the id1/id2
663 *	pair. For convenience the return is the passed in buffer pointer.
664 */
665
666static char *codec_id(u16 id1, u16 id2, char *buf)
667{
668	if(id1&0x8080)
669		snprintf(buf, 10, "%0x4X:%0x4X", id1, id2);
670	buf[0] = (id1 >> 8);
671	buf[1] = (id1 & 0xFF);
672	buf[2] = (id2 >> 8);
673	snprintf(buf+3, 7, "%d", id2&0xFF);
674	return buf;
675}
676
677/**
678 *	ac97_probe_codec - Initialize and setup AC97-compatible codec
679 *	@codec: (in/out) Kernel info for a single AC97 codec
680 *
681 *	Reset the AC97 codec, then initialize the mixer and
682 *	the rest of the @codec structure.
683 *
684 *	The codec_read and codec_write fields of @codec are
685 *	required to be setup and working when this function
686 *	is called.  All other fields are set by this function.
687 *
688 *	codec_wait field of @codec can optionally be provided
689 *	when calling this function.  If codec_wait is not %NULL,
690 *	this function will call codec_wait any time it is
691 *	necessary to wait for the audio chip to reach the
692 *	codec-ready state.  If codec_wait is %NULL, then
693 *	the default behavior is to call schedule_timeout.
694 *	Currently codec_wait is used to wait for AC97 codec
695 *	reset to complete.
696 *
697 *	Returns 1 (true) on success, or 0 (false) on failure.
698 */
699
700int ac97_probe_codec(struct ac97_codec *codec)
701{
702	u16 id1, id2;
703	u16 audio, modem;
704	int i;
705	char cidbuf[10];
706
707	codec->codec_write(codec, AC97_RESET, 0L);
708
709	/* also according to spec, we wait for codec-ready state */
710	if (codec->codec_wait)
711		codec->codec_wait(codec);
712	else
713		udelay(10);
714
715	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
716		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
717		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
718		       : (codec->id&1 ? "Secondary":  "Primary"));
719		return 0;
720	}
721
722	/* probe for Modem Codec */
723	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
724	modem = codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1;
725	modem |= (audio&2);
726	audio &= ~2;
727
728	codec->name = NULL;
729	codec->codec_ops = &null_ops;
730
731	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
732	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
733	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
734		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
735			codec->type = ac97_codec_ids[i].id;
736			codec->name = ac97_codec_ids[i].name;
737			codec->codec_ops = ac97_codec_ids[i].ops;
738			break;
739		}
740	}
741	if (codec->name == NULL)
742		codec->name = "Unknown";
743	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s(%s)\n",
744		modem ? "Modem" : (audio ? "Audio" : ""),
745	       codec_id(id1, id2, cidbuf), codec->name);
746
747	return ac97_init_mixer(codec);
748}
749
750static int ac97_init_mixer(struct ac97_codec *codec)
751{
752	u16 cap;
753	int i;
754
755	cap = codec->codec_read(codec, AC97_RESET);
756
757	/* mixer masks */
758	codec->supported_mixers = AC97_SUPPORTED_MASK;
759	codec->stereo_mixers = AC97_STEREO_MASK;
760	codec->record_sources = AC97_RECORD_MASK;
761	if (!(cap & 0x04))
762		codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
763	if (!(cap & 0x10))
764		codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
765
766	/* detect bit resolution */
767	codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
768	if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020)
769		codec->bit_resolution = 6;
770	else
771		codec->bit_resolution = 5;
772
773	/* generic OSS to AC97 wrapper */
774	codec->read_mixer = ac97_read_mixer;
775	codec->write_mixer = ac97_write_mixer;
776	codec->recmask_io = ac97_recmask_io;
777	codec->mixer_ioctl = ac97_mixer_ioctl;
778
779	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
780	if (codec->codec_ops->init != NULL) {
781		codec->codec_ops->init(codec);
782	}
783
784	/* initialize mixer channel volumes */
785	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
786		struct mixer_defaults *md = &mixer_defaults[i];
787		if (md->mixer == -1)
788			break;
789		if (!supported_mixer(codec, md->mixer))
790			continue;
791		ac97_set_mixer(codec, md->mixer, md->value);
792	}
793
794	return 1;
795}
796
797#define AC97_SIGMATEL_ANALOG    0x6c	/* Analog Special */
798#define AC97_SIGMATEL_DAC2INVERT 0x6e
799#define AC97_SIGMATEL_BIAS1     0x70
800#define AC97_SIGMATEL_BIAS2     0x72
801#define AC97_SIGMATEL_MULTICHN  0x74	/* Multi-Channel programming */
802#define AC97_SIGMATEL_CIC1      0x76
803#define AC97_SIGMATEL_CIC2      0x78
804
805
806static int sigmatel_9708_init(struct ac97_codec * codec)
807{
808	u16 codec72, codec6c;
809
810	codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
811	codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
812
813	if ((codec72==0) && (codec6c==0)) {
814		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
815		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
816		codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
817		codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
818	} else if ((codec72==0x8000) && (codec6c==0)) {
819		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
820		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
821		codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
822	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
823		/* nothing */
824	}
825	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
826	return 0;
827}
828
829
830static int sigmatel_9721_init(struct ac97_codec * codec)
831{
832	/* Only set up secondary codec */
833	if (codec->id == 0)
834		return 0;
835
836	codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
837
838	/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
839	   sloc 3,4 = 0x01, slot 7,8 = 0x00, */
840	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
841
842	/* we don't have the crystal when we are on an AMR card, so use
843	   BIT_CLK as our clock source. Write the magic word ABBA and read
844	   back to enable register 0x78 */
845	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
846	codec->codec_read(codec, AC97_SIGMATEL_CIC1);
847
848	/* sync all the clocks*/
849	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
850
851	return 0;
852}
853
854
855static int sigmatel_9744_init(struct ac97_codec * codec)
856{
857	// patch for SigmaTel
858	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
859	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
860	codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
861	codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
862	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
863	return 0;
864}
865
866
867static int wolfson_init00(struct ac97_codec * codec)
868{
869	/* This initialization is suspect, but not known to be wrong.
870	   It was copied from the initialization for the WM9704Q, but
871	   that same sequence is known to fail for the WM9707.  Thus
872	   this warning may help someone with hardware to test
873	   this code. */
874	codec->codec_write(codec, 0x72, 0x0808);
875	codec->codec_write(codec, 0x74, 0x0808);
876
877	// patch for DVD noise
878	codec->codec_write(codec, 0x5a, 0x0200);
879
880	// init vol as PCM vol
881	codec->codec_write(codec, 0x70,
882		codec->codec_read(codec, AC97_PCMOUT_VOL));
883
884	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
885	return 0;
886}
887
888
889static int wolfson_init03(struct ac97_codec * codec)
890{
891	/* this is known to work for the ViewSonic ViewPad 1000 */
892	codec->codec_write(codec, 0x72, 0x0808);
893	codec->codec_write(codec, 0x20, 0x8000);
894	return 0;
895}
896
897
898static int wolfson_init04(struct ac97_codec * codec)
899{
900	codec->codec_write(codec, 0x72, 0x0808);
901	codec->codec_write(codec, 0x74, 0x0808);
902
903	// patch for DVD noise
904	codec->codec_write(codec, 0x5a, 0x0200);
905
906	// init vol as PCM vol
907	codec->codec_write(codec, 0x70,
908		codec->codec_read(codec, AC97_PCMOUT_VOL));
909
910	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
911	return 0;
912}
913
914
915static int tritech_init(struct ac97_codec * codec)
916{
917	codec->codec_write(codec, 0x26, 0x0300);
918	codec->codec_write(codec, 0x26, 0x0000);
919	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
920	codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
921	return 0;
922}
923
924
925/* copied from drivers/sound/maestro.c */
926static int tritech_maestro_init(struct ac97_codec * codec)
927{
928	/* no idea what this does */
929	codec->codec_write(codec, 0x2A, 0x0001);
930	codec->codec_write(codec, 0x2C, 0x0000);
931	codec->codec_write(codec, 0x2C, 0XFFFF);
932	return 0;
933}
934
935
936
937
938#define AC97_AD1886_JACK_SENSE 0x72
939
940static int ad1886_init(struct ac97_codec * codec)
941{
942	/* from AD1886 Specs */
943	codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
944	return 0;
945}
946
947
948
949
950/*
951 *	This is basically standard AC97. It should work as a default for
952 *	almost all modern codecs. Note that some cards wire EAPD *backwards*
953 *	That side of it is up to the card driver not us to cope with.
954 *
955 */
956
957static int eapd_control(struct ac97_codec * codec, int on)
958{
959	if(on)
960		codec->codec_write(codec, AC97_POWER_CONTROL,
961			codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
962	else
963		codec->codec_write(codec, AC97_POWER_CONTROL,
964			codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000);
965	return 0;
966}
967
968/*
969 *	Crystal digital audio control (CS4299
970 */
971
972static int crystal_digital_control(struct ac97_codec *codec, int mode)
973{
974	u16 cv;
975
976	switch(mode)
977	{
978		case 0: cv = 0x0; break;	/* SPEN off */
979		case 1: cv = 0x8004; break;	/* 48KHz digital */
980		case 2: cv = 0x8104; break;	/* 44.1KHz digital */
981		default:
982			return -1;		/* Not supported yet(eg AC3) */
983	}
984	codec->codec_write(codec, 0x68, cv);
985	return 0;
986}
987
988/* copied from drivers/sound/maestro.c */
989#if 0  /* there has been 1 person on the planet with a pt101 that we
990        know of.  If they care, they can put this back in :) */
991static int pt101_init(struct ac97_codec * codec)
992{
993	printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
994	/* who knows.. */
995	codec->codec_write(codec, 0x2A, 0x0001);
996	codec->codec_write(codec, 0x2C, 0x0000);
997	codec->codec_write(codec, 0x2C, 0xFFFF);
998	codec->codec_write(codec, 0x10, 0x9F1F);
999	codec->codec_write(codec, 0x12, 0x0808);
1000	codec->codec_write(codec, 0x14, 0x9F1F);
1001	codec->codec_write(codec, 0x16, 0x9F1F);
1002	codec->codec_write(codec, 0x18, 0x0404);
1003	codec->codec_write(codec, 0x1A, 0x0000);
1004	codec->codec_write(codec, 0x1C, 0x0000);
1005	codec->codec_write(codec, 0x02, 0x0404);
1006	codec->codec_write(codec, 0x04, 0x0808);
1007	codec->codec_write(codec, 0x0C, 0x801F);
1008	codec->codec_write(codec, 0x0E, 0x801F);
1009	return 0;
1010}
1011#endif
1012
1013
1014EXPORT_SYMBOL(ac97_read_proc);
1015EXPORT_SYMBOL(ac97_probe_codec);
1016
1017/*
1018 *	AC97 library support routines
1019 */
1020
1021/**
1022 *	ac97_set_dac_rate	-	set codec rate adaption
1023 *	@codec: ac97 code
1024 *	@rate: rate in hertz
1025 *
1026 *	Set the DAC rate. Assumes the codec supports VRA. The caller is
1027 *	expected to have checked this little detail.
1028 */
1029
1030unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate)
1031{
1032	unsigned int new_rate = rate;
1033	u32 dacp;
1034	u32 mast_vol, phone_vol, mono_vol, pcm_vol;
1035	u32 mute_vol = 0x8000;	/* The mute volume? */
1036
1037	if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE))
1038	{
1039		/* Mute several registers */
1040		mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO);
1041		mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO);
1042		phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL);
1043		pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL);
1044		codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol);
1045		codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol);
1046		codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol);
1047		codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol);
1048
1049		/* Power down the DAC */
1050		dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
1051		codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
1052		/* Load the rate and read the effective rate */
1053		codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
1054		new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE);
1055		/* Power it back up */
1056		codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
1057
1058		/* Restore volumes */
1059		codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol);
1060		codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol);
1061		codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol);
1062		codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol);
1063	}
1064	return new_rate;
1065}
1066
1067EXPORT_SYMBOL(ac97_set_dac_rate);
1068
1069/**
1070 *	ac97_set_adc_rate	-	set codec rate adaption
1071 *	@codec: ac97 code
1072 *	@rate: rate in hertz
1073 *
1074 *	Set the ADC rate. Assumes the codec supports VRA. The caller is
1075 *	expected to have checked this little detail.
1076 */
1077
1078unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
1079{
1080	unsigned int new_rate = rate;
1081	u32 dacp;
1082
1083	if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE))
1084	{
1085		/* Power down the ADC */
1086		dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
1087		codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100);
1088		/* Load the rate and read the effective rate */
1089		codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate);
1090		new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE);
1091		/* Power it back up */
1092		codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
1093	}
1094	return new_rate;
1095}
1096
1097EXPORT_SYMBOL(ac97_set_adc_rate);
1098
1099int ac97_save_state(struct ac97_codec *codec)
1100{
1101	return 0;
1102}
1103
1104EXPORT_SYMBOL(ac97_save_state);
1105
1106int ac97_restore_state(struct ac97_codec *codec)
1107{
1108	int i;
1109	unsigned int left, right, val;
1110
1111	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
1112		if (!supported_mixer(codec, i))
1113			continue;
1114
1115		val = codec->mixer_state[i];
1116		right = val >> 8;
1117		left = val  & 0xff;
1118		codec->write_mixer(codec, i, left, right);
1119	}
1120	return 0;
1121}
1122
1123EXPORT_SYMBOL(ac97_restore_state);
1124
1125MODULE_LICENSE("GPL");
1126