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

source code of linux/sound/pci/au88x0/au88x0_eq.c