brintos

brintos / linux-shallow public Read only

0
0
Text · 23.9 KiB · eabaee0 Raw
907 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/***************************************************************************3 *            au88x0_a3d.c4 *5 *  Fri Jul 18 14:16:22 20036 *  Copyright  2003  mjander7 *  mjander@users.sourceforge.net8 *9 * A3D. You may think i'm crazy, but this may work someday. Who knows...10 ****************************************************************************/11 12/*13 */14 15#include "au88x0_a3d.h"16#include "au88x0_a3ddata.c"17#include "au88x0_xtalk.h"18#include "au88x0.h"19 20static void21a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack,22		     short GTrack, short CTrack)23{24	vortex_t *vortex = (vortex_t *) (a->vortex);25	hwwrite(vortex->mmio,26		a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack);27	hwwrite(vortex->mmio,28		a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack);29	hwwrite(vortex->mmio,30		a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack);31	hwwrite(vortex->mmio,32		a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack);33}34 35#if 036static void37a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack,38		     short *GTrack, short *CTrack)39{40	// stub!41}42 43#endif44/* Atmospheric absorption. */45 46static void47a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d,48		      short e)49{50	vortex_t *vortex = (vortex_t *) (a->vortex);51	hwwrite(vortex->mmio,52		a3d_addrB(a->slice, a->source, A3D_B_A21Target),53		(e << 0x10) | d);54	hwwrite(vortex->mmio,55		a3d_addrB(a->slice, a->source, A3D_B_B10Target),56		(b << 0x10) | aa);57	hwwrite(vortex->mmio,58		a3d_addrB(a->slice, a->source, A3D_B_B2Target), c);59}60 61static void62a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d,63		       short e)64{65	vortex_t *vortex = (vortex_t *) (a->vortex);66	hwwrite(vortex->mmio,67		a3d_addrB(a->slice, a->source, A3D_B_A12Current),68		(e << 0x10) | d);69	hwwrite(vortex->mmio,70		a3d_addrB(a->slice, a->source, A3D_B_B01Current),71		(b << 0x10) | aa);72	hwwrite(vortex->mmio,73		a3d_addrB(a->slice, a->source, A3D_B_B2Current), c);74}75 76static void77a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2)78{79	vortex_t *vortex = (vortex_t *) (a->vortex);80	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1);81	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2);82	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1);83	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2);84}85 86#if 087static void88a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c,89		      short *d, short *e)90{91}92static void93a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2,94		       short *aa12, short *ba12)95{96	vortex_t *vortex = (vortex_t *) (a->vortex);97	*aa12 =98	    hwread(vortex->mmio,99		   a3d_addrA(a->slice, a->source, A3D_A_A12Current));100	*ba12 =101	    hwread(vortex->mmio,102		   a3d_addrB(a->slice, a->source, A3D_B_A12Current));103	*ab01 =104	    hwread(vortex->mmio,105		   a3d_addrA(a->slice, a->source, A3D_A_B01Current));106	*bb01 =107	    hwread(vortex->mmio,108		   a3d_addrB(a->slice, a->source, A3D_B_B01Current));109	*b2 =110	    hwread(vortex->mmio,111		   a3d_addrA(a->slice, a->source, A3D_A_B2Current));112}113 114static void115a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2)116{117 118}119 120#endif121/* HRTF */122 123static void124a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)125{126	vortex_t *vortex = (vortex_t *) (a->vortex);127	int i;128 129	for (i = 0; i < HRTF_SZ; i++)130		hwwrite(vortex->mmio,131			a3d_addrB(a->slice, a->source,132				  A3D_B_HrtfTarget) + (i << 2),133			(b[i] << 0x10) | aa[i]);134}135 136static void137a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)138{139	vortex_t *vortex = (vortex_t *) (a->vortex);140	int i;141 142	for (i = 0; i < HRTF_SZ; i++)143		hwwrite(vortex->mmio,144			a3d_addrB(a->slice, a->source,145				  A3D_B_HrtfCurrent) + (i << 2),146			(b[i] << 0x10) | aa[i]);147}148 149static void150a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)151{152	vortex_t *vortex = (vortex_t *) (a->vortex);153	int i;154 155	for (i = 0; i < HRTF_SZ; i++)156		hwwrite(vortex->mmio,157			a3d_addrB(a->slice, a->source,158				  A3D_B_HrtfDelayLine) + (i << 2),159			(b[i] << 0x10) | aa[i]);160}161 162static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right)163{164	vortex_t *vortex = (vortex_t *) (a->vortex);165	hwwrite(vortex->mmio,166		a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left);167	hwwrite(vortex->mmio,168		a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right);169}170 171#if 0172static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)173{174	vortex_t *vortex = (vortex_t *) (a->vortex);175	int i;176 177	for (i = 0; i < HRTF_SZ; i++)178		aa[i] =179		    hwread(vortex->mmio,180			   a3d_addrA(a->slice, a->source,181				     A3D_A_HrtfTarget + (i << 2)));182	for (i = 0; i < HRTF_SZ; i++)183		b[i] =184		    hwread(vortex->mmio,185			   a3d_addrB(a->slice, a->source,186				     A3D_B_HrtfTarget + (i << 2)));187}188 189static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)190{191	vortex_t *vortex = (vortex_t *) (a->vortex);192	int i;193 194	for (i = 0; i < HRTF_SZ; i++)195		aa[i] =196		    hwread(vortex->mmio,197			   a3d_addrA(a->slice, a->source,198				     A3D_A_HrtfCurrent + (i << 2)));199	for (i = 0; i < HRTF_SZ; i++)200		b[i] =201		    hwread(vortex->mmio,202			   a3d_addrB(a->slice, a->source,203				     A3D_B_HrtfCurrent + (i << 2)));204}205 206static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)207{208	vortex_t *vortex = (vortex_t *) (a->vortex);209	int i;210	// FIXME: verify this!211	for (i = 0; i < HRTF_SZ; i++)212		aa[i] =213		    hwread(vortex->mmio,214			   a3d_addrA(a->slice, a->source,215				     A3D_A_HrtfDelayLine + (i << 2)));216	for (i = 0; i < HRTF_SZ; i++)217		b[i] =218		    hwread(vortex->mmio,219			   a3d_addrB(a->slice, a->source,220				     A3D_B_HrtfDelayLine + (i << 2)));221}222 223static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right)224{225	vortex_t *vortex = (vortex_t *) (a->vortex);226	*left =227	    hwread(vortex->mmio,228		   a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL));229	*right =230	    hwread(vortex->mmio,231		   a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR));232}233 234#endif235 236/* Interaural Time Difference. 237 * "The other main clue that humans use to locate sounds, is called 238 * Interaural Time Difference (ITD). The differences in distance from 239 * the sound source to a listeners ears means  that the sound will 240 * reach one ear slightly before the other....", found somewhere with google.*/241static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd)242{243	vortex_t *vortex = (vortex_t *) (a->vortex);244 245	if (litd < 0)246		litd = 0;247	if (litd > 0x57FF)248		litd = 0x57FF;249	if (ritd < 0)250		ritd = 0;251	if (ritd > 0x57FF)252		ritd = 0x57FF;253	hwwrite(vortex->mmio,254		a3d_addrB(a->slice, a->source, A3D_B_ITDTarget),255		(ritd << 0x10) | litd);256	//hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd);257}258 259static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd)260{261	vortex_t *vortex = (vortex_t *) (a->vortex);262 263	if (litd < 0)264		litd = 0;265	if (litd > 0x57FF)266		litd = 0x57FF;267	if (ritd < 0)268		ritd = 0;269	if (ritd > 0x57FF)270		ritd = 0x57FF;271	hwwrite(vortex->mmio,272		a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent),273		(ritd << 0x10) | litd);274	//hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd);275}276 277static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline)278{279	vortex_t *vortex = (vortex_t *) (a->vortex);280	int i;281	/* 45 != 40 -> Check this ! */282	for (i = 0; i < DLINE_SZ; i++)283		hwwrite(vortex->mmio,284			a3d_addrA(a->slice, a->source,285				  A3D_A_ITDDelayLine) + (i << 2), dline[i]);286}287 288#if 0289static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd)290{291	vortex_t *vortex = (vortex_t *) (a->vortex);292	*ritd =293	    hwread(vortex->mmio,294		   a3d_addrA(a->slice, a->source, A3D_A_ITDTarget));295	*litd =296	    hwread(vortex->mmio,297		   a3d_addrB(a->slice, a->source, A3D_B_ITDTarget));298}299 300static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd)301{302	vortex_t *vortex = (vortex_t *) (a->vortex);303 304	*ritd =305	    hwread(vortex->mmio,306		   a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent));307	*litd =308	    hwread(vortex->mmio,309		   a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent));310}311 312static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline)313{314	vortex_t *vortex = (vortex_t *) (a->vortex);315	int i;316 317	for (i = 0; i < DLINE_SZ; i++)318		dline[i] =319		    hwread(vortex->mmio,320			   a3d_addrA(a->slice, a->source,321				     A3D_A_ITDDelayLine + (i << 2)));322}323 324#endif325/* This is may be used for ILD Interaural Level Difference. */326 327static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right)328{329	vortex_t *vortex = (vortex_t *) (a->vortex);330	hwwrite(vortex->mmio,331		a3d_addrB(a->slice, a->source, A3D_B_GainTarget),332		(right << 0x10) | left);333}334 335static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right)336{337	vortex_t *vortex = (vortex_t *) (a->vortex);338	hwwrite(vortex->mmio,339		a3d_addrB(a->slice, a->source, A3D_B_GainCurrent),340		(right << 0x10) | left);341}342 343#if 0344static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right)345{346	vortex_t *vortex = (vortex_t *) (a->vortex);347	*right =348	    hwread(vortex->mmio,349		   a3d_addrA(a->slice, a->source, A3D_A_GainTarget));350	*left =351	    hwread(vortex->mmio,352		   a3d_addrB(a->slice, a->source, A3D_B_GainTarget));353}354 355static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right)356{357	vortex_t *vortex = (vortex_t *) (a->vortex);358	*right =359	    hwread(vortex->mmio,360		   a3d_addrA(a->slice, a->source, A3D_A_GainCurrent));361	*left =362	    hwread(vortex->mmio,363		   a3d_addrB(a->slice, a->source, A3D_B_GainCurrent));364}365 366/* CA3dIO this func seems to be inlined all over this place. */367static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b)368{369	vortex_t *vortex = (vortex_t *) (a->vortex);370	hwwrite(vortex->mmio, addr, (aa << 0x10) | b);371}372 373#endif374/* Generic A3D stuff */375 376static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr)377{378	vortex_t *vortex = (vortex_t *) (a->vortex);379	int esp0 = 0;380 381	esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3);382	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0);383	//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0);384}385 386static void a3dsrc_EnableA3D(a3dsrc_t * a)387{388	vortex_t *vortex = (vortex_t *) (a->vortex);389	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),390		0xF0000001);391	//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001);392}393 394static void a3dsrc_DisableA3D(a3dsrc_t * a)395{396	vortex_t *vortex = (vortex_t *) (a->vortex);397	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),398		0xF0000000);399}400 401static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl)402{403	vortex_t *vortex = (vortex_t *) (a->vortex);404	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl);405}406 407static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr)408{409	vortex_t *vortex = (vortex_t *) (a->vortex);410	hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr);411}412 413#if 0414static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr)415{416	vortex_t *vortex = (vortex_t *) (a->vortex);417	*sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd))418		>> 3) & 0x1f);419	//*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f);420}421 422static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl)423{424	vortex_t *vortex = (vortex_t *) (a->vortex);425	*ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd));426}427 428static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr)429{430	vortex_t *vortex = (vortex_t *) (a->vortex);431	*ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd));432}433 434#endif435static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)436{437	vortex_t *vortex = (vortex_t *) (a->vortex);438	int i;439 440	for (i = 0; i < 8; i++)441		hwwrite(vortex->mmio,442			A3D_SLICE_VDBDest +443			((((a->slice) << 0xb) + i) << 2), 0);444	for (i = 0; i < 4; i++)445		hwwrite(vortex->mmio,446			A3D_SLICE_VDBSource +447			((((a->slice) << 0xb) + i) << 2), 0);448}449 450/* Reset Single A3D source. */451static void a3dsrc_ZeroState(a3dsrc_t * a)452{453	/*454	pr_debug( "vortex: ZeroState slice: %d, source %d\n",455	       a->slice, a->source);456	*/457	a3dsrc_SetAtmosState(a, 0, 0, 0, 0);458	a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);459	a3dsrc_SetItdDline(a, A3dItdDlineZeros);460	a3dsrc_SetHrtfOutput(a, 0, 0);461	a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);462 463	a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0);464	a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0);465	a3dsrc_SetItdCurrent(a, 0, 0);466	a3dsrc_SetItdTarget(a, 0, 0);467	a3dsrc_SetGainCurrent(a, 0, 0);468	a3dsrc_SetGainTarget(a, 0, 0);469 470	a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros);471	a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros);472}473 474/* Reset entire A3D engine */475static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v)476{477	int i, var, var2;478 479	if ((a->vortex) == NULL) {480		dev_err(v->card->dev,481			"ZeroStateA3D: ERROR: a->vortex is NULL\n");482		return;483	}484 485	a3dsrc_SetA3DControlReg(a, 0);486	a3dsrc_SetA3DPointerReg(a, 0);487 488	var = a->slice;489	var2 = a->source;490	for (i = 0; i < 4; i++) {491		a->slice = i;492		a3dsrc_ZeroSliceIO(a);493		//a3dsrc_ZeroState(a);494	}495	a->source = var2;496	a->slice = var;497}498 499/* Program A3D block as pass through */500static void a3dsrc_ProgramPipe(a3dsrc_t * a)501{502	a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);503	a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0);504	a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0);505	a3dsrc_SetItdCurrent(a, 0, 0);506	a3dsrc_SetItdTarget(a, 0, 0);507	a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff);508	a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff);509 510	/* SET HRTF HERE */511 512	/* Single spike leads to identity transfer function. */513	a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse);514	a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse);515 516	/* Test: Sounds saturated. */517	//a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest);518	//a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest);      519}520 521/* VDB = Vortex audio Dataflow Bus */522#if 0523static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa)524{525	vortex_t *vortex = (vortex_t *) (a->vortex);526 527	// ((aa >> 2) << 8) - (aa >> 2)528	hwwrite(vortex->mmio,529		a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0);530	hwwrite(vortex->mmio,531		a3d_addrS(a->slice,532			  A3D_SLICE_VDBDest + 4) + (a->source << 2), 0);533	/*534	   hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0);535	   hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0);536	 */537}538#endif539 540/* A3D HwSource stuff. */541 542static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice)543{544	a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]);545	//a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]);546 547	a3dsrc->vortex = (void *)v;548	a3dsrc->source = source;	/* source */549	a3dsrc->slice = slice;	/* slice */550	a3dsrc_ZeroState(a3dsrc);551	/* Added by me. */552	a3dsrc_SetA3DSampleRate(a3dsrc, 0x11);553}554 555static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode)556{557	v->xt_mode = mode;	/* this_14 */558 559	vortex_XtalkHw_init(v);560	vortex_XtalkHw_SetGainsAllChan(v);561	switch (v->xt_mode) {562	case XT_SPEAKER0:563		vortex_XtalkHw_ProgramXtalkNarrow(v);564		break;565	case XT_SPEAKER1:566		vortex_XtalkHw_ProgramXtalkWide(v);567		break;568	default:569	case XT_HEADPHONE:570		vortex_XtalkHw_ProgramPipe(v);571		break;572	case XT_DIAMOND:573		vortex_XtalkHw_ProgramDiamondXtalk(v);574		break;575	}576	vortex_XtalkHw_SetSampleRate(v, 0x11);577	vortex_XtalkHw_Enable(v);578	return 0;579}580 581/* 3D Sound entry points. */582 583static int vortex_a3d_register_controls(vortex_t * vortex);584static void vortex_a3d_unregister_controls(vortex_t * vortex);585/* A3D base support init/shudown */586static void vortex_Vort3D_enable(vortex_t *v)587{588	int i;589 590	Vort3DRend_Initialize(v, XT_HEADPHONE);591	for (i = 0; i < NR_A3D; i++) {592		vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);593		a3dsrc_ZeroStateA3D(&v->a3d[0], v);594	}595	/* Register ALSA controls */596	vortex_a3d_register_controls(v);597}598 599static void vortex_Vort3D_disable(vortex_t * v)600{601	vortex_XtalkHw_Disable(v);602	vortex_a3d_unregister_controls(v);603}604 605/* Make A3D subsystem connections. */606static void vortex_Vort3D_connect(vortex_t * v, int en)607{608	int i;609	610// Disable AU8810 routes, since they seem to be wrong (in au8810.h).611#ifdef CHIP_AU8810612	return;613#endif614	615#if 1616	/* Alloc Xtalk mixin resources */617	v->mixxtlk[0] =618	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);619	if (v->mixxtlk[0] < 0) {620		dev_warn(v->card->dev,621			 "vortex_Vort3D: ERROR: not enough free mixer resources.\n");622		return;623	}624	v->mixxtlk[1] =625	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);626	if (v->mixxtlk[1] < 0) {627		dev_warn(v->card->dev,628			 "vortex_Vort3D: ERROR: not enough free mixer resources.\n");629		return;630	}631#endif632 633	/* Connect A3D -> XTALK */634	for (i = 0; i < 4; i++) {635		// 2 outputs per each A3D slice. 636		vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i));637		vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i));638	}639#if 0640	vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2));641	vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3));642#else643	/* Connect XTalk -> mixer */644	vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0]));645	vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1]));646	vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0);647	vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0);648	vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0],649				      en ? MIX_DEFIGAIN : VOL_MIN);650	vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1],651				      en ? MIX_DEFIGAIN : VOL_MIN);652	if (VORTEX_IS_QUAD(v)) {653		vortex_connection_mixin_mix(v, en, v->mixxtlk[0],654					    v->mixplayb[2], 0);655		vortex_connection_mixin_mix(v, en, v->mixxtlk[1],656					    v->mixplayb[3], 0);657		vortex_mix_setinputvolumebyte(v, v->mixplayb[2],658					      v->mixxtlk[0],659					      en ? MIX_DEFIGAIN : VOL_MIN);660		vortex_mix_setinputvolumebyte(v, v->mixplayb[3],661					      v->mixxtlk[1],662					      en ? MIX_DEFIGAIN : VOL_MIN);663	}664#endif665}666 667/* Initialize one single A3D source. */668static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v)669{670	if (a->vortex == NULL) {671		dev_warn(v->card->dev,672			 "Vort3D_InitializeSource: A3D source not initialized\n");673		return;674	}675	if (en) {676		a3dsrc_ProgramPipe(a);677		a3dsrc_SetA3DSampleRate(a, 0x11);678		a3dsrc_SetTimeConsts(a, HrtfTCDefault,679				     ItdTCDefault, GainTCDefault,680				     CoefTCDefault);681		/* Remark: zero gain is muted. */682		//a3dsrc_SetGainTarget(a,0,0);683		//a3dsrc_SetGainCurrent(a,0,0);684		a3dsrc_EnableA3D(a);685	} else {686		a3dsrc_DisableA3D(a);687		a3dsrc_ZeroState(a);688	}689}690 691/* Conversion of coordinates into 3D parameters. */692 693static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord)694{695	/* FIXME: implement this. */696 697}698static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord)699{700	/* FIXME: implement this. */701 702}703static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right)704{705	/* FIXME: implement this. */706 707}708static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params)709{710	/* FIXME: implement this. */711 712}713 714/* ALSA control interface.  */715 716static int717snd_vortex_a3d_hrtf_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)718{719	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;720	uinfo->count = 6;721	uinfo->value.integer.min = 0x00000000;722	uinfo->value.integer.max = 0xffffffff;723	return 0;724}725static int726snd_vortex_a3d_itd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)727{728	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;729	uinfo->count = 2;730	uinfo->value.integer.min = 0x00000000;731	uinfo->value.integer.max = 0xffffffff;732	return 0;733}734static int735snd_vortex_a3d_ild_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)736{737	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;738	uinfo->count = 2;739	uinfo->value.integer.min = 0x00000000;740	uinfo->value.integer.max = 0xffffffff;741	return 0;742}743static int744snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol,745			   struct snd_ctl_elem_info *uinfo)746{747	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;748	uinfo->count = 4;749	uinfo->value.integer.min = 0x00000000;750	uinfo->value.integer.max = 0xffffffff;751	return 0;752}753 754static int755snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)756{757	//a3dsrc_t *a = kcontrol->private_data;758	/* No read yet. Would this be really useable/needed ? */759 760	return 0;761}762 763static int764snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,765			struct snd_ctl_elem_value *ucontrol)766{767	a3dsrc_t *a = kcontrol->private_data;768	int i;769	int coord[6];770	for (i = 0; i < 6; i++)771		coord[i] = ucontrol->value.integer.value[i];772	/* Translate orientation coordinates to a3d params. */773	vortex_a3d_coord2hrtf(a->hrtf[0], coord);774	vortex_a3d_coord2hrtf(a->hrtf[1], coord);775	a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);776	a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);777	return 1;778}779 780static int781snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,782		       struct snd_ctl_elem_value *ucontrol)783{784	a3dsrc_t *a = kcontrol->private_data;785	int coord[6];786	int i;787	for (i = 0; i < 6; i++)788		coord[i] = ucontrol->value.integer.value[i];789	/* Translate orientation coordinates to a3d params. */790	vortex_a3d_coord2itd(a->hrtf[0], coord);791	vortex_a3d_coord2itd(a->hrtf[1], coord);792	/* Inter aural time difference. */793	a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);794	a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);795	a3dsrc_SetItdDline(a, a->dline);796	return 1;797}798 799static int800snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,801		       struct snd_ctl_elem_value *ucontrol)802{803	a3dsrc_t *a = kcontrol->private_data;804	int l, r;805	/* There may be some scale tranlation needed here. */806	l = ucontrol->value.integer.value[0];807	r = ucontrol->value.integer.value[1];808	vortex_a3d_coord2ild(a->ild, l, r);809	/* Left Right panning. */810	a3dsrc_SetGainTarget(a, l, r);811	a3dsrc_SetGainCurrent(a, l, r);812	return 1;813}814 815static int816snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,817			  struct snd_ctl_elem_value *ucontrol)818{819	a3dsrc_t *a = kcontrol->private_data;820	int i;821	int params[6];822	for (i = 0; i < 6; i++)823		params[i] = ucontrol->value.integer.value[i];824	/* Translate generic filter params to a3d filter params. */825	vortex_a3d_translate_filter(a->filter, params);826	/* Atmospheric absorption and filtering. */827	a3dsrc_SetAtmosTarget(a, a->filter[0],828			      a->filter[1], a->filter[2],829			      a->filter[3], a->filter[4]);830	a3dsrc_SetAtmosCurrent(a, a->filter[0],831			       a->filter[1], a->filter[2],832			       a->filter[3], a->filter[4]);833	return 1;834}835 836static const struct snd_kcontrol_new vortex_a3d_kcontrol = {837	.iface = SNDRV_CTL_ELEM_IFACE_PCM,838	.name = "Playback PCM advanced processing",839	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,840	.info = snd_vortex_a3d_hrtf_info,841	.get = snd_vortex_a3d_get,842	.put = snd_vortex_a3d_hrtf_put,843};844 845/* Control (un)registration. */846static int vortex_a3d_register_controls(vortex_t *vortex)847{848	struct snd_kcontrol *kcontrol;849	int err, i;850	/* HRTF controls. */851	for (i = 0; i < NR_A3D; i++) {852		kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]);853		if (!kcontrol)854			return -ENOMEM;855		kcontrol->id.numid = CTRLID_HRTF;856		kcontrol->info = snd_vortex_a3d_hrtf_info;857		kcontrol->put = snd_vortex_a3d_hrtf_put;858		err = snd_ctl_add(vortex->card, kcontrol);859		if (err < 0)860			return err;861	}862	/* ITD controls. */863	for (i = 0; i < NR_A3D; i++) {864		kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]);865		if (!kcontrol)866			return -ENOMEM;867		kcontrol->id.numid = CTRLID_ITD;868		kcontrol->info = snd_vortex_a3d_itd_info;869		kcontrol->put = snd_vortex_a3d_itd_put;870		err = snd_ctl_add(vortex->card, kcontrol);871		if (err < 0)872			return err;873	}874	/* ILD (gains) controls. */875	for (i = 0; i < NR_A3D; i++) {876		kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]);877		if (!kcontrol)878			return -ENOMEM;879		kcontrol->id.numid = CTRLID_GAINS;880		kcontrol->info = snd_vortex_a3d_ild_info;881		kcontrol->put = snd_vortex_a3d_ild_put;882		err = snd_ctl_add(vortex->card, kcontrol);883		if (err < 0)884			return err;885	}886	/* Filter controls. */887	for (i = 0; i < NR_A3D; i++) {888		kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]);889		if (!kcontrol)890			return -ENOMEM;891		kcontrol->id.numid = CTRLID_FILTER;892		kcontrol->info = snd_vortex_a3d_filter_info;893		kcontrol->put = snd_vortex_a3d_filter_put;894		err = snd_ctl_add(vortex->card, kcontrol);895		if (err < 0)896			return err;897	}898	return 0;899}900 901static void vortex_a3d_unregister_controls(vortex_t * vortex)902{903 904}905 906/* End of File*/907