• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/sound/pci/au88x0/
1/***************************************************************************
2 *            au88x0_eq.c
3 *  Aureal Vortex Hardware EQ control/access.
4 *
5 *  Sun Jun  8 18:19:19 2003
6 *  2003  Manuel Jander (mjander@users.sourceforge.net)
7 *
8 *  02 July 2003: First time something works :)
9 *  November 2003: A3D Bypass code completed but untested.
10 *
11 *  TODO:
12 *     - Debug (testing)
13 *     - Test peak visualization support.
14 *
15 ****************************************************************************/
16
17/*
18 *  This program is free software; you can redistribute it and/or modify
19 *  it under the terms of the GNU General Public License as published by
20 *  the Free Software Foundation; either version 2 of the License, or
21 *  (at your option) any later version.
22 *
23 *  This program is distributed in the hope that it will be useful,
24 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26 *  GNU Library General Public License for more details.
27 *
28 *  You should have received a copy of the GNU General Public License
29 *  along with this program; if not, write to the Free Software
30 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 */
32
33/*
34 The Aureal Hardware EQ is found on AU8810 and AU8830 chips only.
35 it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed
36 to be routed to the codec).
37*/
38
39#include "au88x0.h"
40#include "au88x0_eq.h"
41#include "au88x0_eqdata.c"
42
43#define VORTEX_EQ_BASE	 0x2b000
44#define VORTEX_EQ_DEST   (VORTEX_EQ_BASE + 0x410)
45#define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430)
46#define VORTEX_EQ_CTRL   (VORTEX_EQ_BASE + 0x440)
47
48#define VORTEX_BAND_COEFF_SIZE 0x30
49
50/* CEqHw.s */
51static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
52{
53	hwwrite(vortex->mmio, 0x2b3c4, gain);
54	hwwrite(vortex->mmio, 0x2b3c8, level);
55}
56
57static inline u16 sign_invert(u16 a)
58{
59	/* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */
60	if (a == (u16)-32768)
61		return 32767;
62	else
63		return -a;
64}
65
66static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[])
67{
68	eqhw_t *eqhw = &(vortex->eq.this04);
69	int i = 0, n /*esp2c */;
70
71	for (n = 0; n < eqhw->this04; n++) {
72		hwwrite(vortex->mmio, 0x2b000 + n * 0x30, coefs[i + 0]);
73		hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]);
74
75		if (eqhw->this08 == 0) {
76			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]);
77			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]);
78			hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]);
79		} else {
80			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]));
81			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]));
82		        hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]));
83		}
84		i += 5;
85	}
86}
87
88static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[])
89{
90	eqhw_t *eqhw = &(vortex->eq.this04);
91	int i = 0, n /*esp2c */;
92
93	for (n = 0; n < eqhw->this04; n++) {
94		hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, coefs[0 + i]);
95		hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]);
96
97		if (eqhw->this08 == 0) {
98			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]);
99			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]);
100			hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]);
101		} else {
102			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]));
103			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]));
104			hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]));
105		}
106		i += 5;
107	}
108
109}
110
111static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[])
112{
113	eqhw_t *eqhw = &(vortex->eq.this04);
114	int i = 0, ebx;
115
116	hwwrite(vortex->mmio, 0x2b3fc, a[0]);
117	hwwrite(vortex->mmio, 0x2b400, a[1]);
118
119	for (ebx = 0; ebx < eqhw->this04; ebx++) {
120		hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]);
121		hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]);
122		hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]);
123		hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]);
124		i += 4;
125	}
126}
127
128static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[])
129{
130	eqhw_t *eqhw = &(vortex->eq.this04);
131	int i = 0, ebx;
132
133	hwwrite(vortex->mmio, 0x2b404, a[0]);
134	hwwrite(vortex->mmio, 0x2b408, a[1]);
135
136	for (ebx = 0; ebx < eqhw->this04; ebx++) {
137		hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]);
138		hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]);
139		hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]);
140		hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]);
141		i += 4;
142	}
143}
144
145/* Mix Gains */
146static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
147{
148	eqhw_t *eqhw = &(vortex->eq.this04);
149	if (eqhw->this08 == 0) {
150		hwwrite(vortex->mmio, 0x2b3d4, a);
151		hwwrite(vortex->mmio, 0x2b3ec, b);
152	} else {
153		hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
154		hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
155	}
156}
157
158static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
159{
160
161	hwwrite(vortex->mmio, 0x2b3e0, a);
162	hwwrite(vortex->mmio, 0x2b3f8, b);
163}
164
165static void
166vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
167{
168	hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
169}
170
171static void
172vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
173{
174	hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
175}
176
177static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
178{
179	eqhw_t *eqhw = &(vortex->eq.this04);
180	int ebx;
181
182	for (ebx = 0; ebx < eqhw->this04; ebx++) {
183		hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
184	}
185}
186
187static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
188{
189	eqhw_t *eqhw = &(vortex->eq.this04);
190	int ebx;
191
192	for (ebx = 0; ebx < eqhw->this04; ebx++) {
193		hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
194	}
195}
196
197static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
198{
199	eqhw_t *eqhw = &(vortex->eq.this04);
200	int ebx;
201
202	for (ebx = 0; ebx < eqhw->this04; ebx++) {
203		hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
204	}
205}
206
207static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
208{
209	eqhw_t *eqhw = &(vortex->eq.this04);
210	int ebx;
211
212	for (ebx = 0; ebx < eqhw->this04; ebx++) {
213		hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
214	}
215}
216
217/* EQ band levels settings */
218static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
219{
220	eqhw_t *eqhw = &(vortex->eq.this04);
221	int i;
222
223	/* set left peaks */
224	for (i = 0; i < eqhw->this04; i++) {
225		hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
226	}
227
228	hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
229	hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
230
231	/* set right peaks */
232	for (i = 0; i < eqhw->this04; i++) {
233		hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
234			peaks[i + (eqhw->this04 + 2)]);
235	}
236
237	hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
238	hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
239}
240
241/* Global Control */
242static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
243{
244	hwwrite(vortex->mmio, 0x2b440, reg);
245}
246
247static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
248{
249	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
250}
251
252static void vortex_EqHw_Enable(vortex_t * vortex)
253{
254	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001);
255}
256
257static void vortex_EqHw_Disable(vortex_t * vortex)
258{
259	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000);
260}
261
262/* Reset (zero) buffers */
263static void vortex_EqHw_ZeroIO(vortex_t * vortex)
264{
265	int i;
266	for (i = 0; i < 0x8; i++)
267		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
268	for (i = 0; i < 0x4; i++)
269		hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0);
270}
271
272static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
273{
274	int i;
275	for (i = 0; i < 0x4; i++)
276		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
277}
278
279static void vortex_EqHw_ZeroState(vortex_t * vortex)
280{
281
282	vortex_EqHw_SetControlReg(vortex, 0);
283	vortex_EqHw_ZeroIO(vortex);
284	hwwrite(vortex->mmio, 0x2b3c0, 0);
285
286	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
287
288	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
289	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
290
291	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
292	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
293	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
294	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
295
296	vortex_EqHw_SetBypassGain(vortex, 0, 0);
297	//vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
298	vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
299	//vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
300	vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
301	vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
302	vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
303}
304
305/* Program coeficients as pass through */
306static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
307{
308	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
309
310	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
311	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
312
313	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
314	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
315	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
316	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
317}
318
319/* Program EQ block as 10 band Equalizer */
320static void
321vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
322{
323
324	vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
325
326	vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
327	vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
328
329	vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
330
331	vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
332	vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
333
334	vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
335}
336
337/* Read all EQ peaks. (think VU meter) */
338static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
339{
340	eqhw_t *eqhw = &(vortex->eq.this04);
341	int i;
342
343	if (eqhw->this04 <= 0)
344		return;
345
346	for (i = 0; i < eqhw->this04; i++)
347		peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
348	for (i = 0; i < eqhw->this04; i++)
349		peaks[i + eqhw->this04] =
350		    hwread(vortex->mmio, 0x2B204 + i * 0x30);
351}
352
353/* CEqlzr.s */
354
355static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
356{
357	eqlzr_t *eq = &(vortex->eq);
358
359	if (eq->this28) {
360		*gain = eq->this130[index];
361		return 0;
362	}
363	return 1;
364}
365
366static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
367{
368	eqlzr_t *eq = &(vortex->eq);
369
370	if (eq->this28 == 0)
371		return;
372
373	eq->this130[index] = gain;
374	if (eq->this54)
375		return;
376
377	vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
378}
379
380static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
381{
382	eqlzr_t *eq = &(vortex->eq);
383
384	if (eq->this28) {
385		*gain = eq->this130[index + eq->this10];
386		return 0;
387	}
388	return 1;
389}
390
391static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
392{
393	eqlzr_t *eq = &(vortex->eq);
394
395	if (eq->this28 == 0)
396		return;
397
398	eq->this130[index + eq->this10] = gain;
399	if (eq->this54)
400		return;
401
402	vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
403}
404
405static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
406{
407	eqlzr_t *eq = &(vortex->eq);
408
409	vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
410	vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
411
412	return 0;
413}
414
415static int
416vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
417{
418	eqlzr_t *eq = &(vortex->eq);
419	int i;
420
421	if (((eq->this10) * 2 != count) || (eq->this28 == 0))
422		return 1;
423
424	for (i = 0; i < count; i++) {
425		eq->this130[i] = gains[i];
426	}
427
428	if (eq->this54)
429		return 0;
430	return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
431}
432
433static void
434vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
435{
436	eqlzr_t *eq = &(vortex->eq);
437	u32 eax, ebx;
438
439	eq->this58 = a;
440	eq->this5c = b;
441	if (eq->this54)
442		eax = eq->this0e;
443	else
444		eax = eq->this0a;
445	ebx = (eax * eq->this58) >> 0x10;
446	eax = (eax * eq->this5c) >> 0x10;
447	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
448}
449
450static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
451{
452	eqlzr_t *eq = &(vortex->eq);
453	u32 eax, ebx;
454
455	if (eq->this54)
456		eax = eq->this0e;
457	else
458		eax = eq->this0a;
459	ebx = (eax * eq->this58) >> 0x10;
460	eax = (eax * eq->this5c) >> 0x10;
461	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
462}
463
464static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
465{
466	if (vortex != NULL)
467		vortex_EqHw_ZeroA3DIO(vortex);
468}
469
470static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
471{
472	eqlzr_t *eq = &(vortex->eq);
473
474	if ((eq->this28) && (bp == 0)) {
475		/* EQ enabled */
476		vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
477		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
478	} else {
479		/* EQ disabled. */
480		vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
481		vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
482		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
483	}
484	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
485}
486
487static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
488{
489	eqlzr_t *eq = &(vortex->eq);
490
491	/* Set EQ BiQuad filter coeficients */
492	memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
493	/* Set EQ Band gain levels and dump into hardware registers. */
494	vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
495}
496
497static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
498{
499	eqlzr_t *eq = &(vortex->eq);
500
501	if (eq->this10 == 0)
502		return 1;
503	*count = eq->this10 * 2;
504	vortex_EqHw_GetTenBandLevels(vortex, peaks);
505	return 0;
506}
507
508static void vortex_Eqlzr_init(vortex_t * vortex)
509{
510	eqlzr_t *eq = &(vortex->eq);
511
512	/* Object constructor */
513	//eq->this04 = 0;
514	eq->this08 = 0;		/* Bypass gain with EQ in use. */
515	eq->this0a = 0x5999;
516	eq->this0c = 0x5999;	/* Bypass gain with EQ disabled. */
517	eq->this0e = 0x5999;
518
519	eq->this10 = 0xa;	/* 10 eq frequency bands. */
520	eq->this04.this04 = eq->this10;
521	eq->this28 = 0x1;	/* if 1 => Allow read access to this130 (gains) */
522	eq->this54 = 0x0;	/* if 1 => Dont Allow access to hardware (gains) */
523	eq->this58 = 0xffff;
524	eq->this5c = 0xffff;
525
526	/* Set gains. */
527	memset(eq->this14_array, 0, sizeof(eq->this14_array));
528
529	/* Actual init. */
530	vortex_EqHw_ZeroState(vortex);
531	vortex_EqHw_SetSampleRate(vortex, 0x11);
532	vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
533
534	vortex_EqHw_Program10Band(vortex, &(eq->coefset));
535	vortex_Eqlzr_SetBypass(vortex, eq->this54);
536	vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
537	vortex_EqHw_Enable(vortex);
538}
539
540static void vortex_Eqlzr_shutdown(vortex_t * vortex)
541{
542	vortex_Eqlzr_ShutDownA3d(vortex);
543	vortex_EqHw_ProgramPipe(vortex);
544	vortex_EqHw_Disable(vortex);
545}
546
547/* ALSA interface */
548
549/* Control interface */
550#define snd_vortex_eqtoggle_info	snd_ctl_boolean_mono_info
551
552static int
553snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol,
554			struct snd_ctl_elem_value *ucontrol)
555{
556	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
557	eqlzr_t *eq = &(vortex->eq);
558	//int i = kcontrol->private_value;
559
560	ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
561
562	return 0;
563}
564
565static int
566snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol,
567			struct snd_ctl_elem_value *ucontrol)
568{
569	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
570	eqlzr_t *eq = &(vortex->eq);
571	//int i = kcontrol->private_value;
572
573	eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
574	vortex_Eqlzr_SetBypass(vortex, eq->this54);
575
576	return 1;		/* Allways changes */
577}
578
579static struct snd_kcontrol_new vortex_eqtoggle_kcontrol __devinitdata = {
580	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
581	.name = "EQ Enable",
582	.index = 0,
583	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
584	.private_value = 0,
585	.info = snd_vortex_eqtoggle_info,
586	.get = snd_vortex_eqtoggle_get,
587	.put = snd_vortex_eqtoggle_put
588};
589
590static int
591snd_vortex_eq_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
592{
593	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
594	uinfo->count = 2;
595	uinfo->value.integer.min = 0x0000;
596	uinfo->value.integer.max = 0x7fff;
597	return 0;
598}
599
600static int
601snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
602{
603	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
604	int i = kcontrol->private_value;
605	u16 gainL = 0, gainR = 0;
606
607	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
608	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
609	ucontrol->value.integer.value[0] = gainL;
610	ucontrol->value.integer.value[1] = gainR;
611	return 0;
612}
613
614static int
615snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
616{
617	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
618	int changed = 0, i = kcontrol->private_value;
619	u16 gainL = 0, gainR = 0;
620
621	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
622	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
623
624	if (gainL != ucontrol->value.integer.value[0]) {
625		vortex_Eqlzr_SetLeftGain(vortex, i,
626					 ucontrol->value.integer.value[0]);
627		changed = 1;
628	}
629	if (gainR != ucontrol->value.integer.value[1]) {
630		vortex_Eqlzr_SetRightGain(vortex, i,
631					  ucontrol->value.integer.value[1]);
632		changed = 1;
633	}
634	return changed;
635}
636
637static struct snd_kcontrol_new vortex_eq_kcontrol __devinitdata = {
638	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
639	.name = "                        .",
640	.index = 0,
641	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
642	.private_value = 0,
643	.info = snd_vortex_eq_info,
644	.get = snd_vortex_eq_get,
645	.put = snd_vortex_eq_put
646};
647
648static int
649snd_vortex_peaks_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
650{
651	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
652	uinfo->count = 20;
653	uinfo->value.integer.min = 0x0000;
654	uinfo->value.integer.max = 0x7fff;
655	return 0;
656}
657
658static int
659snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
660{
661	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
662	int i, count = 0;
663	u16 peaks[20];
664
665	vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
666	if (count != 20) {
667		printk(KERN_ERR "vortex: peak count error 20 != %d \n", count);
668		return -1;
669	}
670	for (i = 0; i < 20; i++)
671		ucontrol->value.integer.value[i] = peaks[i];
672
673	return 0;
674}
675
676static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = {
677	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
678	.name = "EQ Peaks",
679	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
680	.info = snd_vortex_peaks_info,
681	.get = snd_vortex_peaks_get,
682};
683
684/* EQ band gain labels. */
685static char *EqBandLabels[10] __devinitdata = {
686	"EQ0 31Hz\0",
687	"EQ1 63Hz\0",
688	"EQ2 125Hz\0",
689	"EQ3 250Hz\0",
690	"EQ4 500Hz\0",
691	"EQ5 1KHz\0",
692	"EQ6 2KHz\0",
693	"EQ7 4KHz\0",
694	"EQ8 8KHz\0",
695	"EQ9 16KHz\0",
696};
697
698/* ALSA driver entry points. Init and exit. */
699static int __devinit vortex_eq_init(vortex_t * vortex)
700{
701	struct snd_kcontrol *kcontrol;
702	int err, i;
703
704	vortex_Eqlzr_init(vortex);
705
706	if ((kcontrol =
707	     snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
708		return -ENOMEM;
709	kcontrol->private_value = 0;
710	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
711		return err;
712
713	/* EQ gain controls */
714	for (i = 0; i < 10; i++) {
715		if ((kcontrol =
716		     snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
717			return -ENOMEM;
718		strcpy(kcontrol->id.name, EqBandLabels[i]);
719		kcontrol->private_value = i;
720		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
721			return err;
722		//vortex->eqctrl[i] = kcontrol;
723	}
724	/* EQ band levels */
725	if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
726		return -ENOMEM;
727	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
728		return err;
729
730	return 0;
731}
732
733static int vortex_eq_free(vortex_t * vortex)
734{
735	vortex_Eqlzr_shutdown(vortex);
736	return 0;
737}
738
739/* End */
740