diff options
Diffstat (limited to 'sound/pci/au88x0/au88x0_eq.c')
-rw-r--r-- | sound/pci/au88x0/au88x0_eq.c | 937 |
1 files changed, 937 insertions, 0 deletions
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c new file mode 100644 index 000000000000..53b47a42c7d8 --- /dev/null +++ b/sound/pci/au88x0/au88x0_eq.c | |||
@@ -0,0 +1,937 @@ | |||
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 */ | ||
51 | static 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 | |||
57 | static 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 | |||
66 | static 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 | |||
88 | static 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 | |||
111 | static 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 | |||
128 | static 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 | ||
146 | static 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 | |||
152 | static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[]) | ||
153 | { | ||
154 | |||
155 | } | ||
156 | |||
157 | static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[]) | ||
158 | { | ||
159 | |||
160 | } | ||
161 | |||
162 | static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[]) | ||
163 | { | ||
164 | |||
165 | } | ||
166 | |||
167 | static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[]) | ||
168 | { | ||
169 | |||
170 | } | ||
171 | |||
172 | #endif | ||
173 | /* Mix Gains */ | ||
174 | static 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 | |||
186 | static 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 | ||
194 | static 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 | |||
201 | static 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 | ||
209 | static void | ||
210 | vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) | ||
211 | { | ||
212 | hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b); | ||
213 | } | ||
214 | |||
215 | static void | ||
216 | vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) | ||
217 | { | ||
218 | hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b); | ||
219 | } | ||
220 | |||
221 | static 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 | |||
231 | static 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 | |||
241 | static 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 | |||
251 | static 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 | ||
262 | static 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 | |||
277 | static 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 | |||
292 | static 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 | |||
307 | static 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 */ | ||
324 | static 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 | ||
348 | static 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 */ | ||
380 | static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg) | ||
381 | { | ||
382 | hwwrite(vortex->mmio, 0x2b440, reg); | ||
383 | } | ||
384 | |||
385 | static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr) | ||
386 | { | ||
387 | hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800); | ||
388 | } | ||
389 | |||
390 | #if 0 | ||
391 | static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg) | ||
392 | { | ||
393 | *reg = hwread(vortex->mmio, 0x2b440); | ||
394 | } | ||
395 | |||
396 | static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr) | ||
397 | { | ||
398 | *sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f; | ||
399 | } | ||
400 | |||
401 | #endif | ||
402 | static void vortex_EqHw_Enable(vortex_t * vortex) | ||
403 | { | ||
404 | hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001); | ||
405 | } | ||
406 | |||
407 | static void vortex_EqHw_Disable(vortex_t * vortex) | ||
408 | { | ||
409 | hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000); | ||
410 | } | ||
411 | |||
412 | /* Reset (zero) buffers */ | ||
413 | static 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 | |||
422 | static 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 | |||
429 | static 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 */ | ||
456 | static 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 */ | ||
470 | static void | ||
471 | vortex_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) */ | ||
488 | static 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 | |||
505 | static 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 | |||
516 | static 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 | |||
530 | static 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 | |||
541 | static 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 | ||
556 | static int | ||
557 | vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *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 | ||
578 | static 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 | |||
588 | static int | ||
589 | vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long 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 | |||
606 | static void | ||
607 | vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a, | ||
608 | unsigned long b) | ||
609 | { | ||
610 | eqlzr_t *eq = &(vortex->eq); | ||
611 | int eax, ebx; | ||
612 | |||
613 | eq->this58 = a; | ||
614 | eq->this5c = b; | ||
615 | if (eq->this54) | ||
616 | eax = eq->this0e; | ||
617 | else | ||
618 | eax = eq->this0a; | ||
619 | ebx = (eax * eq->this58) >> 0x10; | ||
620 | eax = (eax * eq->this5c) >> 0x10; | ||
621 | vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); | ||
622 | } | ||
623 | |||
624 | static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex) | ||
625 | { | ||
626 | eqlzr_t *eq = &(vortex->eq); | ||
627 | int eax, ebx; | ||
628 | |||
629 | if (eq->this54) | ||
630 | eax = eq->this0e; | ||
631 | else | ||
632 | eax = eq->this0a; | ||
633 | ebx = (eax * eq->this58) >> 0x10; | ||
634 | eax = (eax * eq->this5c) >> 0x10; | ||
635 | vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); | ||
636 | } | ||
637 | |||
638 | static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex) | ||
639 | { | ||
640 | if (vortex != NULL) | ||
641 | vortex_EqHw_ZeroA3DIO(vortex); | ||
642 | } | ||
643 | |||
644 | static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp) | ||
645 | { | ||
646 | eqlzr_t *eq = &(vortex->eq); | ||
647 | |||
648 | if ((eq->this28) && (bp == 0)) { | ||
649 | /* EQ enabled */ | ||
650 | vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex); | ||
651 | vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08); | ||
652 | } else { | ||
653 | /* EQ disabled. */ | ||
654 | vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14)); | ||
655 | vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14)); | ||
656 | vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c); | ||
657 | } | ||
658 | vortex_Eqlzr_ProgramA3dBypassGain(vortex); | ||
659 | } | ||
660 | |||
661 | static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex) | ||
662 | { | ||
663 | eqlzr_t *eq = &(vortex->eq); | ||
664 | |||
665 | /* Set EQ BiQuad filter coeficients */ | ||
666 | memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t)); | ||
667 | /* Set EQ Band gain levels and dump into hardware registers. */ | ||
668 | vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2); | ||
669 | } | ||
670 | |||
671 | static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count) | ||
672 | { | ||
673 | eqlzr_t *eq = &(vortex->eq); | ||
674 | |||
675 | if (eq->this10 == 0) | ||
676 | return 1; | ||
677 | *count = eq->this10 * 2; | ||
678 | vortex_EqHw_GetTenBandLevels(vortex, peaks); | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | #if 0 | ||
683 | static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex) | ||
684 | { | ||
685 | eqlzr_t *eq = &(vortex->eq); | ||
686 | |||
687 | return (&(eq->coefset)); | ||
688 | } | ||
689 | #endif | ||
690 | static void vortex_Eqlzr_init(vortex_t * vortex) | ||
691 | { | ||
692 | eqlzr_t *eq = &(vortex->eq); | ||
693 | |||
694 | /* Object constructor */ | ||
695 | //eq->this04 = 0; | ||
696 | eq->this08 = 0; /* Bypass gain with EQ in use. */ | ||
697 | eq->this0a = 0x5999; | ||
698 | eq->this0c = 0x5999; /* Bypass gain with EQ disabled. */ | ||
699 | eq->this0e = 0x5999; | ||
700 | |||
701 | eq->this10 = 0xa; /* 10 eq frequency bands. */ | ||
702 | eq->this04.this04 = eq->this10; | ||
703 | eq->this28 = 0x1; /* if 1 => Allow read access to this130 (gains) */ | ||
704 | eq->this54 = 0x0; /* if 1 => Dont Allow access to hardware (gains) */ | ||
705 | eq->this58 = 0xffff; | ||
706 | eq->this5c = 0xffff; | ||
707 | |||
708 | /* Set gains. */ | ||
709 | memset(eq->this14, 0, 2 * 10); | ||
710 | |||
711 | /* Actual init. */ | ||
712 | vortex_EqHw_ZeroState(vortex); | ||
713 | vortex_EqHw_SetSampleRate(vortex, 0x11); | ||
714 | vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex); | ||
715 | |||
716 | vortex_EqHw_Program10Band(vortex, &(eq->coefset)); | ||
717 | vortex_Eqlzr_SetBypass(vortex, eq->this54); | ||
718 | vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0); | ||
719 | vortex_EqHw_Enable(vortex); | ||
720 | } | ||
721 | |||
722 | static void vortex_Eqlzr_shutdown(vortex_t * vortex) | ||
723 | { | ||
724 | vortex_Eqlzr_ShutDownA3d(vortex); | ||
725 | vortex_EqHw_ProgramPipe(vortex); | ||
726 | vortex_EqHw_Disable(vortex); | ||
727 | } | ||
728 | |||
729 | /* ALSA interface */ | ||
730 | |||
731 | /* Control interface */ | ||
732 | static int | ||
733 | snd_vortex_eqtoggle_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) | ||
734 | { | ||
735 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
736 | uinfo->count = 1; | ||
737 | uinfo->value.integer.min = 0; | ||
738 | uinfo->value.integer.max = 1; | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int | ||
743 | snd_vortex_eqtoggle_get(snd_kcontrol_t * kcontrol, | ||
744 | snd_ctl_elem_value_t * ucontrol) | ||
745 | { | ||
746 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
747 | eqlzr_t *eq = &(vortex->eq); | ||
748 | //int i = kcontrol->private_value; | ||
749 | |||
750 | ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1; | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static int | ||
756 | snd_vortex_eqtoggle_put(snd_kcontrol_t * kcontrol, | ||
757 | snd_ctl_elem_value_t * ucontrol) | ||
758 | { | ||
759 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
760 | eqlzr_t *eq = &(vortex->eq); | ||
761 | //int i = kcontrol->private_value; | ||
762 | |||
763 | eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1; | ||
764 | vortex_Eqlzr_SetBypass(vortex, eq->this54); | ||
765 | |||
766 | return 1; /* Allways changes */ | ||
767 | } | ||
768 | |||
769 | static snd_kcontrol_new_t vortex_eqtoggle_kcontrol __devinitdata = { | ||
770 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
771 | .name = "EQ Enable", | ||
772 | .index = 0, | ||
773 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
774 | .private_value = 0, | ||
775 | .info = snd_vortex_eqtoggle_info, | ||
776 | .get = snd_vortex_eqtoggle_get, | ||
777 | .put = snd_vortex_eqtoggle_put | ||
778 | }; | ||
779 | |||
780 | static int | ||
781 | snd_vortex_eq_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) | ||
782 | { | ||
783 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
784 | uinfo->count = 2; | ||
785 | uinfo->value.integer.min = 0x0000; | ||
786 | uinfo->value.integer.max = 0x7fff; | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int | ||
791 | snd_vortex_eq_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
792 | { | ||
793 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
794 | int i = kcontrol->private_value; | ||
795 | u16 gainL, gainR; | ||
796 | |||
797 | vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); | ||
798 | vortex_Eqlzr_GetRightGain(vortex, i, &gainR); | ||
799 | ucontrol->value.integer.value[0] = gainL; | ||
800 | ucontrol->value.integer.value[1] = gainR; | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int | ||
805 | snd_vortex_eq_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
806 | { | ||
807 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
808 | int changed = 0, i = kcontrol->private_value; | ||
809 | u16 gainL, gainR; | ||
810 | |||
811 | vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); | ||
812 | vortex_Eqlzr_GetRightGain(vortex, i, &gainR); | ||
813 | |||
814 | if (gainL != ucontrol->value.integer.value[0]) { | ||
815 | vortex_Eqlzr_SetLeftGain(vortex, i, | ||
816 | ucontrol->value.integer.value[0]); | ||
817 | changed = 1; | ||
818 | } | ||
819 | if (gainR != ucontrol->value.integer.value[1]) { | ||
820 | vortex_Eqlzr_SetRightGain(vortex, i, | ||
821 | ucontrol->value.integer.value[1]); | ||
822 | changed = 1; | ||
823 | } | ||
824 | return changed; | ||
825 | } | ||
826 | |||
827 | static snd_kcontrol_new_t vortex_eq_kcontrol __devinitdata = { | ||
828 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
829 | .name = " .", | ||
830 | .index = 0, | ||
831 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
832 | .private_value = 0, | ||
833 | .info = snd_vortex_eq_info, | ||
834 | .get = snd_vortex_eq_get, | ||
835 | .put = snd_vortex_eq_put | ||
836 | }; | ||
837 | |||
838 | static int | ||
839 | snd_vortex_peaks_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) | ||
840 | { | ||
841 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
842 | uinfo->count = 20; | ||
843 | uinfo->value.integer.min = 0x0000; | ||
844 | uinfo->value.integer.max = 0x7fff; | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static int | ||
849 | snd_vortex_peaks_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
850 | { | ||
851 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
852 | int i, count; | ||
853 | u16 peaks[20]; | ||
854 | |||
855 | vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); | ||
856 | if (count != 20) { | ||
857 | printk("vortex: peak count error 20 != %d \n", count); | ||
858 | return -1; | ||
859 | } | ||
860 | for (i = 0; i < 20; i++) | ||
861 | ucontrol->value.integer.value[i] = peaks[i]; | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static snd_kcontrol_new_t vortex_levels_kcontrol __devinitdata = { | ||
867 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
868 | .name = "EQ Peaks", | ||
869 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
870 | .info = snd_vortex_peaks_info, | ||
871 | .get = snd_vortex_peaks_get, | ||
872 | }; | ||
873 | |||
874 | /* EQ band gain labels. */ | ||
875 | static char *EqBandLabels[10] __devinitdata = { | ||
876 | "EQ0 31Hz\0", | ||
877 | "EQ1 63Hz\0", | ||
878 | "EQ2 125Hz\0", | ||
879 | "EQ3 250Hz\0", | ||
880 | "EQ4 500Hz\0", | ||
881 | "EQ5 1KHz\0", | ||
882 | "EQ6 2KHz\0", | ||
883 | "EQ7 4KHz\0", | ||
884 | "EQ8 8KHz\0", | ||
885 | "EQ9 16KHz\0", | ||
886 | }; | ||
887 | |||
888 | /* ALSA driver entry points. Init and exit. */ | ||
889 | static int vortex_eq_init(vortex_t * vortex) | ||
890 | { | ||
891 | snd_kcontrol_t *kcontrol; | ||
892 | int err, i; | ||
893 | |||
894 | vortex_Eqlzr_init(vortex); | ||
895 | |||
896 | if ((kcontrol = | ||
897 | snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL) | ||
898 | return -ENOMEM; | ||
899 | kcontrol->private_value = 0; | ||
900 | if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) | ||
901 | return err; | ||
902 | |||
903 | /* EQ gain controls */ | ||
904 | for (i = 0; i < 10; i++) { | ||
905 | if ((kcontrol = | ||
906 | snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL) | ||
907 | return -ENOMEM; | ||
908 | strcpy(kcontrol->id.name, EqBandLabels[i]); | ||
909 | kcontrol->private_value = i; | ||
910 | if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) | ||
911 | return err; | ||
912 | //vortex->eqctrl[i] = kcontrol; | ||
913 | } | ||
914 | /* EQ band levels */ | ||
915 | if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL) | ||
916 | return -ENOMEM; | ||
917 | if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) | ||
918 | return err; | ||
919 | |||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | static int vortex_eq_free(vortex_t * vortex) | ||
924 | { | ||
925 | /* | ||
926 | //FIXME: segfault because vortex->eqctrl[i] == 4 | ||
927 | int i; | ||
928 | for (i=0; i<10; i++) { | ||
929 | if (vortex->eqctrl[i]) | ||
930 | snd_ctl_remove(vortex->card, vortex->eqctrl[i]); | ||
931 | } | ||
932 | */ | ||
933 | vortex_Eqlzr_shutdown(vortex); | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | /* End */ | ||