linux/sound/pci/au88x0/au88x0_eq.c
<<
>>
Prefs
   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, 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, 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, u16 a[], 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, u16 a[], 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, 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, 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, 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, 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, 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, 0);
 421        vortex_EqHw_ZeroIO(vortex);
 422        hwwrite(vortex->mmio, 0x2b3c0, 0);
 423
 424        vortex_EqHw_SetTimeConsts(vortex, 0, 0);
 425
 426        vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
 427        vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
 428
 429        vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
 430        vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
 431        vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
 432        vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
 433
 434        vortex_EqHw_SetBypassGain(vortex, 0, 0);
 435        //vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
 436        vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
 437        //vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
 438        vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
 439        vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
 440        vortex_EqHw_SetLevels(vortex, (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, 0, 0);
 447
 448        vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
 449        vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
 450
 451        vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
 452        vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
 453        vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
 454        vortex_EqHw_SetRightGainsTarget(vortex, 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, 0xc, 0x7fe0);
 463
 464        vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
 465        vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
 466
 467        vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
 468
 469        vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
 470        vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
 471
 472        vortex_EqHw_SetRightGainsCurrent(vortex, 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, 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, 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, eq->this130);
 571        vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
 572
 573        return 0;
 574}
 575
 576static int
 577vortex_Eqlzr_SetAllBands(vortex_t * vortex, 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, ebx, 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, ebx, 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, eq->this08, eq->this08);
 639        } else {
 640                /* EQ disabled. */
 641                vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
 642                vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
 643                vortex_EqHw_SetBypassGain(vortex, eq->this0c, 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, eq_gains_normal, 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, 0x11);
 701        vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
 702
 703        vortex_EqHw_Program10Band(vortex, &(eq->coefset));
 704        vortex_Eqlzr_SetBypass(vortex, eq->this54);
 705        vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 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, 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, i, &gainL);
 777        vortex_Eqlzr_GetRightGain(vortex, i, &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, i, &gainL);
 791        vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
 792
 793        if (gainL != ucontrol->value.integer.value[0]) {
 794                vortex_Eqlzr_SetLeftGain(vortex, i,
 795                                         ucontrol->value.integer.value[0]);
 796                changed = 1;
 797        }
 798        if (gainR != ucontrol->value.integer.value[1]) {
 799                vortex_Eqlzr_SetRightGain(vortex, i,
 800                                          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);
 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 char *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        if ((kcontrol =
 877             snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
 878                return -ENOMEM;
 879        kcontrol->private_value = 0;
 880        if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
 881                return err;
 882
 883        /* EQ gain controls */
 884        for (i = 0; i < 10; i++) {
 885                if ((kcontrol =
 886                     snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
 887                        return -ENOMEM;
 888                snprintf(kcontrol->id.name, sizeof(kcontrol->id.name),
 889                        "%s Playback Volume", EqBandLabels[i]);
 890                kcontrol->private_value = i;
 891                if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
 892                        return err;
 893                //vortex->eqctrl[i] = kcontrol;
 894        }
 895        /* EQ band levels */
 896        if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
 897                return -ENOMEM;
 898        if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
 899                return err;
 900
 901        return 0;
 902}
 903
 904static int vortex_eq_free(vortex_t * vortex)
 905{
 906        /*
 907           //FIXME: segfault because vortex->eqctrl[i] == 4
 908           int i;
 909           for (i=0; i<10; i++) {
 910           if (vortex->eqctrl[i])
 911           snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
 912           }
 913         */
 914        vortex_Eqlzr_shutdown(vortex);
 915        return 0;
 916}
 917
 918/* End */
 919