cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

au88x0_eq.c (22449B)


      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, 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, 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, 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 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(&vortex_eqtoggle_kcontrol, vortex);
    877	if (!kcontrol)
    878		return -ENOMEM;
    879	kcontrol->private_value = 0;
    880	err = snd_ctl_add(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(&vortex_eq_kcontrol, vortex);
    887		if (!kcontrol)
    888			return -ENOMEM;
    889		snprintf(kcontrol->id.name, sizeof(kcontrol->id.name),
    890			"%s Playback Volume", EqBandLabels[i]);
    891		kcontrol->private_value = i;
    892		err = snd_ctl_add(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(&vortex_levels_kcontrol, vortex);
    899	if (!kcontrol)
    900		return -ENOMEM;
    901	err = snd_ctl_add(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 */