1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /*************************************************************************** 3 * au88x0_a3d.c 4 * 5 * Fri Jul 18 14:16:22 2003 6 * Copyright 2003 mjander 7 * mjander@users.sourceforge.net 8 * 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 20 static void 21 a3dsrc_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 0 36 static void 37 a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack, 38 short *GTrack, short *CTrack) 39 { 40 // stub! 41 } 42 43 #endif 44 /* Atmospheric absorption. */ 45 46 static void 47 a3dsrc_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 61 static void 62 a3dsrc_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 76 static void 77 a3dsrc_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 0 87 static void 88 a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c, 89 short *d, short *e) 90 { 91 } 92 static void 93 a3dsrc_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 114 static void 115 a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2) 116 { 117 118 } 119 120 #endif 121 /* HRTF */ 122 123 static void 124 a3dsrc_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 136 static void 137 a3dsrc_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 149 static void 150 a3dsrc_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 162 static 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 0 172 static 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 189 static 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 206 static 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 223 static 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 #endif 235 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.*/ 241 static 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 259 static 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 277 static 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 0 289 static 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 300 static 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 312 static 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 #endif 325 /* This is may be used for ILD Interaural Level Difference. */ 326 327 static 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 335 static 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 0 344 static 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 355 static 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. */ 367 static 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 #endif 374 /* Generic A3D stuff */ 375 376 static 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 386 static 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 394 static 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 401 static 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 407 static 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 0 414 static 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 422 static 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 428 static 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 #endif 435 static 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. */ 451 static 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 */ 475 static 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 */ 500 static 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 0 523 static 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 #endif 539 540 /* A3D HwSource stuff. */ 541 542 static 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 555 static 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 583 static int vortex_a3d_register_controls(vortex_t * vortex); 584 static void vortex_a3d_unregister_controls(vortex_t * vortex); 585 /* A3D base support init/shudown */ 586 static 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 599 static 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. */ 606 static 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_AU8810 612 return; 613 #endif 614 615 #if 1 616 /* 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 #endif 632 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 0 640 vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2)); 641 vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3)); 642 #else 643 /* 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 #endif 665 } 666 667 /* Initialize one single A3D source. */ 668 static 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 693 static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord) 694 { 695 /* FIXME: implement this. */ 696 697 } 698 static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord) 699 { 700 /* FIXME: implement this. */ 701 702 } 703 static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right) 704 { 705 /* FIXME: implement this. */ 706 707 } 708 static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params) 709 { 710 /* FIXME: implement this. */ 711 712 } 713 714 /* ALSA control interface. */ 715 716 static int 717 snd_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 } 725 static int 726 snd_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 } 734 static int 735 snd_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 } 743 static int 744 snd_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 754 static int 755 snd_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 763 static int 764 snd_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 780 static int 781 snd_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 799 static int 800 snd_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 815 static int 816 snd_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 836 static 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. */ 846 static 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 901 static void vortex_a3d_unregister_controls(vortex_t * vortex) 902 { 903 904 } 905 906 /* End of File*/ 907
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.