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#if 0
146static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b)
147{
148	*a = hwread(vortex->mmio, 0x2b3c4);
149	*b = hwread(vortex->mmio, 0x2b3c8);
150}
151
152static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[])
153{
154
155}
156
157static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[])
158{
159
160}
161
162static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[])
163{
164
165}
166
167static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[])
168{
169
170}
171
172#endif
173/* Mix Gains */
174static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
175{
176	eqhw_t *eqhw = &(vortex->eq.this04);
177	if (eqhw->this08 == 0) {
178		hwwrite(vortex->mmio, 0x2b3d4, a);
179		hwwrite(vortex->mmio, 0x2b3ec, b);
180	} else {
181		hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
182		hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
183	}
184}
185
186static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
187{
188
189	hwwrite(vortex->mmio, 0x2b3e0, a);
190	hwwrite(vortex->mmio, 0x2b3f8, b);
191}
192
193#if 0
194static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b)
195{
196
197	hwwrite(vortex->mmio, 0x2b3d0, a);
198	hwwrite(vortex->mmio, 0x2b3e8, b);
199}
200
201static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
202{
203
204	hwwrite(vortex->mmio, 0x2b3dc, a);
205	hwwrite(vortex->mmio, 0x2b3f4, b);
206}
207
208#endif
209static void
210vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
211{
212	hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
213}
214
215static void
216vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
217{
218	hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
219}
220
221static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
222{
223	eqhw_t *eqhw = &(vortex->eq.this04);
224	int ebx;
225
226	for (ebx = 0; ebx < eqhw->this04; ebx++) {
227		hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
228	}
229}
230
231static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
232{
233	eqhw_t *eqhw = &(vortex->eq.this04);
234	int ebx;
235
236	for (ebx = 0; ebx < eqhw->this04; ebx++) {
237		hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
238	}
239}
240
241static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
242{
243	eqhw_t *eqhw = &(vortex->eq.this04);
244	int ebx;
245
246	for (ebx = 0; ebx < eqhw->this04; ebx++) {
247		hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
248	}
249}
250
251static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
252{
253	eqhw_t *eqhw = &(vortex->eq.this04);
254	int ebx;
255
256	for (ebx = 0; ebx < eqhw->this04; ebx++) {
257		hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
258	}
259}
260
261#if 0
262static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[])
263{
264	eqhw_t *eqhw = &(vortex->eq.this04);
265	int ebx = 0;
266
267	if (eqhw->this04 < 0)
268		return;
269
270	do {
271		a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30);
272		ebx++;
273	}
274	while (ebx < eqhw->this04);
275}
276
277static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[])
278{
279	eqhw_t *eqhw = &(vortex->eq.this04);
280	int ebx = 0;
281
282	if (eqhw->this04 < 0)
283		return;
284
285	do {
286		a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30);
287		ebx++;
288	}
289	while (ebx < eqhw->this04);
290}
291
292static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[])
293{
294	eqhw_t *eqhw = &(vortex->eq.this04);
295	int ebx = 0;
296
297	if (eqhw->this04 < 0)
298		return;
299
300	do {
301		a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30);
302		ebx++;
303	}
304	while (ebx < eqhw->this04);
305}
306
307static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
308{
309	eqhw_t *eqhw = &(vortex->eq.this04);
310	int ebx = 0;
311
312	if (eqhw->this04 < 0)
313		return;
314
315	do {
316		a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30);
317		ebx++;
318	}
319	while (ebx < eqhw->this04);
320}
321
322#endif
323/* EQ band levels settings */
324static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
325{
326	eqhw_t *eqhw = &(vortex->eq.this04);
327	int i;
328
329	/* set left peaks */
330	for (i = 0; i < eqhw->this04; i++) {
331		hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
332	}
333
334	hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
335	hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
336
337	/* set right peaks */
338	for (i = 0; i < eqhw->this04; i++) {
339		hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
340			peaks[i + (eqhw->this04 + 2)]);
341	}
342
343	hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
344	hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
345}
346
347#if 0
348static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[])
349{
350	eqhw_t *eqhw = &(vortex->eq.this04);
351	int ebx;
352
353	if (eqhw->this04 < 0)
354		return;
355
356	ebx = 0;
357	do {
358		a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30);
359		ebx++;
360	}
361	while (ebx < eqhw->this04);
362
363	a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc);
364	a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8);
365
366	ebx = 0;
367	do {
368		a[ebx + (eqhw->this04 + 2)] =
369		    hwread(vortex->mmio, 0x2b204 + ebx * 0x30);
370		ebx++;
371	}
372	while (ebx < eqhw->this04);
373
374	a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4);
375	a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0);
376}
377
378#endif
379/* Global Control */
380static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
381{
382	hwwrite(vortex->mmio, 0x2b440, reg);
383}
384
385static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
386{
387	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
388}
389
390#if 0
391static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg)
392{
393	*reg = hwread(vortex->mmio, 0x2b440);
394}
395
396static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr)
397{
398	*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
399}
400
401#endif
402static void vortex_EqHw_Enable(vortex_t * vortex)
403{
404	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001);
405}
406
407static void vortex_EqHw_Disable(vortex_t * vortex)
408{
409	hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000);
410}
411
412/* Reset (zero) buffers */
413static void vortex_EqHw_ZeroIO(vortex_t * vortex)
414{
415	int i;
416	for (i = 0; i < 0x8; i++)
417		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
418	for (i = 0; i < 0x4; i++)
419		hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0);
420}
421
422static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
423{
424	int i;
425	for (i = 0; i < 0x4; i++)
426		hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
427}
428
429static void vortex_EqHw_ZeroState(vortex_t * vortex)
430{
431
432	vortex_EqHw_SetControlReg(vortex, 0);
433	vortex_EqHw_ZeroIO(vortex);
434	hwwrite(vortex->mmio, 0x2b3c0, 0);
435
436	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
437
438	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
439	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
440
441	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
442	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
443	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
444	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
445
446	vortex_EqHw_SetBypassGain(vortex, 0, 0);
447	//vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
448	vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
449	//vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
450	vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
451	vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
452	vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
453}
454
455/* Program coeficients as pass through */
456static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
457{
458	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
459
460	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
461	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
462
463	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
464	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
465	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
466	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
467}
468
469/* Program EQ block as 10 band Equalizer */
470static void
471vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
472{
473
474	vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
475
476	vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
477	vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
478
479	vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
480
481	vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
482	vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
483
484	vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
485}
486
487/* Read all EQ peaks. (think VU meter) */
488static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
489{
490	eqhw_t *eqhw = &(vortex->eq.this04);
491	int i;
492
493	if (eqhw->this04 <= 0)
494		return;
495
496	for (i = 0; i < eqhw->this04; i++)
497		peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
498	for (i = 0; i < eqhw->this04; i++)
499		peaks[i + eqhw->this04] =
500		    hwread(vortex->mmio, 0x2B204 + i * 0x30);
501}
502
503/* CEqlzr.s */
504
505static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
506{
507	eqlzr_t *eq = &(vortex->eq);
508
509	if (eq->this28) {
510		*gain = eq->this130[index];
511		return 0;
512	}
513	return 1;
514}
515
516static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
517{
518	eqlzr_t *eq = &(vortex->eq);
519
520	if (eq->this28 == 0)
521		return;
522
523	eq->this130[index] = gain;
524	if (eq->this54)
525		return;
526
527	vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
528}
529
530static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
531{
532	eqlzr_t *eq = &(vortex->eq);
533
534	if (eq->this28) {
535		*gain = eq->this130[index + eq->this10];
536		return 0;
537	}
538	return 1;
539}
540
541static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
542{
543	eqlzr_t *eq = &(vortex->eq);
544
545	if (eq->this28 == 0)
546		return;
547
548	eq->this130[index + eq->this10] = gain;
549	if (eq->this54)
550		return;
551
552	vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
553}
554
555#if 0
556static int
557vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt)
558{
559	eqlzr_t *eq = &(vortex->eq);
560	int si = 0;
561
562	if (eq->this10 == 0)
563		return 1;
564
565	{
566		if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si]))
567			return 1;
568		if (vortex_Eqlzr_GetRightGain
569		    (vortex, si, &gains[si + eq->this10]))
570			return 1;
571		si++;
572	}
573	while (eq->this10 > si) ;
574	*cnt = si * 2;
575	return 0;
576}
577#endif
578static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
579{
580	eqlzr_t *eq = &(vortex->eq);
581
582	vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
583	vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
584
585	return 0;
586}
587
588static int
589vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
590{
591	eqlzr_t *eq = &(vortex->eq);
592	int i;
593
594	if (((eq->this10) * 2 != count) || (eq->this28 == 0))
595		return 1;
596
597	for (i = 0; i < count; i++) {
598		eq->this130[i] = gains[i];
599	}
600
601	if (eq->this54)
602		return 0;
603	return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
604}
605
606static void
607vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
608{
609	eqlzr_t *eq = &(vortex->eq);
610	u32 eax, ebx;
611
612	eq->this58 = a;
613	eq->this5c = b;
614	if (eq->this54)
615		eax = eq->this0e;
616	else
617		eax = eq->this0a;
618	ebx = (eax * eq->this58) >> 0x10;
619	eax = (eax * eq->this5c) >> 0x10;
620	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
621}
622
623static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
624{
625	eqlzr_t *eq = &(vortex->eq);
626	u32 eax, ebx;
627
628	if (eq->this54)
629		eax = eq->this0e;
630	else
631		eax = eq->this0a;
632	ebx = (eax * eq->this58) >> 0x10;
633	eax = (eax * eq->this5c) >> 0x10;
634	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
635}
636
637static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
638{
639	if (vortex != NULL)
640		vortex_EqHw_ZeroA3DIO(vortex);
641}
642
643static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
644{
645	eqlzr_t *eq = &(vortex->eq);
646
647	if ((eq->this28) && (bp == 0)) {
648		/* EQ enabled */
649		vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
650		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
651	} else {
652		/* EQ disabled. */
653		vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
654		vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
655		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
656	}
657	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
658}
659
660static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
661{
662	eqlzr_t *eq = &(vortex->eq);
663
664	/* Set EQ BiQuad filter coeficients */
665	memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
666	/* Set EQ Band gain levels and dump into hardware registers. */
667	vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
668}
669
670static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
671{
672	eqlzr_t *eq = &(vortex->eq);
673
674	if (eq->this10 == 0)
675		return 1;
676	*count = eq->this10 * 2;
677	vortex_EqHw_GetTenBandLevels(vortex, peaks);
678	return 0;
679}
680
681#if 0
682static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)
683{
684	eqlzr_t *eq = &(vortex->eq);
685
686	return (&(eq->coefset));
687}
688#endif
689static void vortex_Eqlzr_init(vortex_t * vortex)
690{
691	eqlzr_t *eq = &(vortex->eq);
692
693	/* Object constructor */
694	//eq->this04 = 0;
695	eq->this08 = 0;		/* Bypass gain with EQ in use. */
696	eq->this0a = 0x5999;
697	eq->this0c = 0x5999;	/* Bypass gain with EQ disabled. */
698	eq->this0e = 0x5999;
699
700	eq->this10 = 0xa;	/* 10 eq frequency bands. */
701	eq->this04.this04 = eq->this10;
702	eq->this28 = 0x1;	/* if 1 => Allow read access to this130 (gains) */
703	eq->this54 = 0x0;	/* if 1 => Dont Allow access to hardware (gains) */
704	eq->this58 = 0xffff;
705	eq->this5c = 0xffff;
706
707	/* Set gains. */
708	memset(eq->this14_array, 0, sizeof(eq->this14_array));
709
710	/* Actual init. */
711	vortex_EqHw_ZeroState(vortex);
712	vortex_EqHw_SetSampleRate(vortex, 0x11);
713	vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
714
715	vortex_EqHw_Program10Band(vortex, &(eq->coefset));
716	vortex_Eqlzr_SetBypass(vortex, eq->this54);
717	vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
718	vortex_EqHw_Enable(vortex);
719}
720
721static void vortex_Eqlzr_shutdown(vortex_t * vortex)
722{
723	vortex_Eqlzr_ShutDownA3d(vortex);
724	vortex_EqHw_ProgramPipe(vortex);
725	vortex_EqHw_Disable(vortex);
726}
727
728/* ALSA interface */
729
730/* Control interface */
731#define snd_vortex_eqtoggle_info	snd_ctl_boolean_mono_info
732
733static int
734snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol,
735			struct snd_ctl_elem_value *ucontrol)
736{
737	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
738	eqlzr_t *eq = &(vortex->eq);
739	//int i = kcontrol->private_value;
740
741	ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
742
743	return 0;
744}
745
746static int
747snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol,
748			struct snd_ctl_elem_value *ucontrol)
749{
750	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
751	eqlzr_t *eq = &(vortex->eq);
752	//int i = kcontrol->private_value;
753
754	eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
755	vortex_Eqlzr_SetBypass(vortex, eq->this54);
756
757	return 1;		/* Allways changes */
758}
759
760static struct snd_kcontrol_new vortex_eqtoggle_kcontrol = {
761	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
762	.name = "EQ Enable",
763	.index = 0,
764	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
765	.private_value = 0,
766	.info = snd_vortex_eqtoggle_info,
767	.get = snd_vortex_eqtoggle_get,
768	.put = snd_vortex_eqtoggle_put
769};
770
771static int
772snd_vortex_eq_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
773{
774	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
775	uinfo->count = 2;
776	uinfo->value.integer.min = 0x0000;
777	uinfo->value.integer.max = 0x7fff;
778	return 0;
779}
780
781static int
782snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
783{
784	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
785	int i = kcontrol->private_value;
786	u16 gainL = 0, gainR = 0;
787
788	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
789	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
790	ucontrol->value.integer.value[0] = gainL;
791	ucontrol->value.integer.value[1] = gainR;
792	return 0;
793}
794
795static int
796snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
797{
798	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
799	int changed = 0, i = kcontrol->private_value;
800	u16 gainL = 0, gainR = 0;
801
802	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
803	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
804
805	if (gainL != ucontrol->value.integer.value[0]) {
806		vortex_Eqlzr_SetLeftGain(vortex, i,
807					 ucontrol->value.integer.value[0]);
808		changed = 1;
809	}
810	if (gainR != ucontrol->value.integer.value[1]) {
811		vortex_Eqlzr_SetRightGain(vortex, i,
812					  ucontrol->value.integer.value[1]);
813		changed = 1;
814	}
815	return changed;
816}
817
818static struct snd_kcontrol_new vortex_eq_kcontrol = {
819	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
820	.name = "                        .",
821	.index = 0,
822	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
823	.private_value = 0,
824	.info = snd_vortex_eq_info,
825	.get = snd_vortex_eq_get,
826	.put = snd_vortex_eq_put
827};
828
829static int
830snd_vortex_peaks_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
831{
832	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
833	uinfo->count = 20;
834	uinfo->value.integer.min = 0x0000;
835	uinfo->value.integer.max = 0x7fff;
836	return 0;
837}
838
839static int
840snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
841{
842	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
843	int i, count = 0;
844	u16 peaks[20];
845
846	vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
847	if (count != 20) {
848		dev_err(vortex->card->dev,
849			"peak count error 20 != %d\n", count);
850		return -1;
851	}
852	for (i = 0; i < 20; i++)
853		ucontrol->value.integer.value[i] = peaks[i];
854
855	return 0;
856}
857
858static struct snd_kcontrol_new vortex_levels_kcontrol = {
859	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
860	.name = "EQ Peaks",
861	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
862	.info = snd_vortex_peaks_info,
863	.get = snd_vortex_peaks_get,
864};
865
866/* EQ band gain labels. */
867static char *EqBandLabels[10] = {
868	"EQ0 31Hz\0",
869	"EQ1 63Hz\0",
870	"EQ2 125Hz\0",
871	"EQ3 250Hz\0",
872	"EQ4 500Hz\0",
873	"EQ5 1KHz\0",
874	"EQ6 2KHz\0",
875	"EQ7 4KHz\0",
876	"EQ8 8KHz\0",
877	"EQ9 16KHz\0",
878};
879
880/* ALSA driver entry points. Init and exit. */
881static int vortex_eq_init(vortex_t *vortex)
882{
883	struct snd_kcontrol *kcontrol;
884	int err, i;
885
886	vortex_Eqlzr_init(vortex);
887
888	if ((kcontrol =
889	     snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
890		return -ENOMEM;
891	kcontrol->private_value = 0;
892	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
893		return err;
894
895	/* EQ gain controls */
896	for (i = 0; i < 10; i++) {
897		if ((kcontrol =
898		     snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
899			return -ENOMEM;
900		snprintf(kcontrol->id.name, sizeof(kcontrol->id.name),
901			"%s Playback Volume", EqBandLabels[i]);
902		kcontrol->private_value = i;
903		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
904			return err;
905		//vortex->eqctrl[i] = kcontrol;
906	}
907	/* EQ band levels */
908	if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
909		return -ENOMEM;
910	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
911		return err;
912
913	return 0;
914}
915
916static int vortex_eq_free(vortex_t * vortex)
917{
918	/*
919	   //FIXME: segfault because vortex->eqctrl[i] == 4
920	   int i;
921	   for (i=0; i<10; i++) {
922	   if (vortex->eqctrl[i])
923	   snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
924	   }
925	 */
926	vortex_Eqlzr_shutdown(vortex);
927	return 0;
928}
929
930/* End */
931