brintos

brintos / linux-shallow public Read only

0
0
Text · 21.9 KiB · 71c1310 Raw
923 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/***************************************************************************3 *            au88x0_eq.c4 *  Aureal Vortex Hardware EQ control/access.5 *6 *  Sun Jun  8 18:19:19 20037 *  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	 0x2b00032#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 0x3037 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	else51		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 0134static 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#endif161/* 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 0182static 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#endif197static void198vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)199{200	hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);201}202 203static void204vortex_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 0250static 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#endif311/* 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 0336static 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#endif367/* 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 0379static 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#endif390static 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 void459vortex_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 0544static int545vortex_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_GetRightGain557		    (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#endif566static 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 int577vortex_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 void595vortex_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	else605		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	else619		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 0670static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)671{672	eqlzr_t *eq = &(vortex->eq);673 674	return (&(eq->coefset));675}676#endif677static 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_info720 721static int722snd_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 int735snd_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_put757};758 759static int760snd_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 int770snd_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 int784snd_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_put815};816 817static int818snd_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 int828snd_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] == 4912	   int i;913	   for (i=0; i<10; i++) {914	   if (vortex->eqctrl[i])915	   snd_ctl_remove(vortex->card, vortex->eqctrl[i]);916	   }917	 */918	vortex_Eqlzr_shutdown(vortex);919	return 0;920}921 922/* End */923