1/*************************************************************************** 2 * au88x0_eq.c 3 * Aureal Vortex Hardware EQ control/access. 4 * 5 * Sun Jun 8 18:19:19 2003 6 * 2003 Manuel Jander (mjander@users.sourceforge.net) 7 * 8 * 02 July 2003: First time something works :) 9 * November 2003: A3D Bypass code completed but untested. 10 * 11 * TODO: 12 * - Debug (testing) 13 * - Test peak visualization support. 14 * 15 ****************************************************************************/ 16 17/* 18 * This program is free software; you can redistribute it and/or modify 19 * it under the terms of the GNU General Public License as published by 20 * the Free Software Foundation; either version 2 of the License, or 21 * (at your option) any later version. 22 * 23 * This program is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * GNU Library General Public License for more details. 27 * 28 * You should have received a copy of the GNU General Public License 29 * along with this program; if not, write to the Free Software 30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 31 */ 32 33/* 34 The Aureal Hardware EQ is found on AU8810 and AU8830 chips only. 35 it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed 36 to be routed to the codec). 37*/ 38 39#include "au88x0.h" 40#include "au88x0_eq.h" 41#include "au88x0_eqdata.c" 42 43#define VORTEX_EQ_BASE 0x2b000 44#define VORTEX_EQ_DEST (VORTEX_EQ_BASE + 0x410) 45#define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430) 46#define VORTEX_EQ_CTRL (VORTEX_EQ_BASE + 0x440) 47 48#define VORTEX_BAND_COEFF_SIZE 0x30 49 50/* CEqHw.s */ 51static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level) 52{ 53 hwwrite(vortex->mmio, 0x2b3c4, gain); 54 hwwrite(vortex->mmio, 0x2b3c8, level); 55} 56 57static inline u16 sign_invert(u16 a) 58{ 59 /* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */ 60 if (a == (u16)-32768) 61 return 32767; 62 else 63 return -a; 64} 65 66static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[]) 67{ 68 eqhw_t *eqhw = &(vortex->eq.this04); 69 int i = 0, n /*esp2c */; 70 71 for (n = 0; n < eqhw->this04; n++) { 72 hwwrite(vortex->mmio, 0x2b000 + n * 0x30, coefs[i + 0]); 73 hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]); 74 75 if (eqhw->this08 == 0) { 76 hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]); 77 hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]); 78 hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]); 79 } else { 80 hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i])); 81 hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i])); 82 hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i])); 83 } 84 i += 5; 85 } 86} 87 88static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[]) 89{ 90 eqhw_t *eqhw = &(vortex->eq.this04); 91 int i = 0, n /*esp2c */; 92 93 for (n = 0; n < eqhw->this04; n++) { 94 hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, coefs[0 + i]); 95 hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]); 96 97 if (eqhw->this08 == 0) { 98 hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]); 99 hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]); 100 hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]); 101 } else { 102 hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i])); 103 hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i])); 104 hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i])); 105 } 106 i += 5; 107 } 108 109} 110 111static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[]) 112{ 113 eqhw_t *eqhw = &(vortex->eq.this04); 114 int i = 0, ebx; 115 116 hwwrite(vortex->mmio, 0x2b3fc, a[0]); 117 hwwrite(vortex->mmio, 0x2b400, a[1]); 118 119 for (ebx = 0; ebx < eqhw->this04; ebx++) { 120 hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]); 121 hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]); 122 hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]); 123 hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]); 124 i += 4; 125 } 126} 127 128static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[]) 129{ 130 eqhw_t *eqhw = &(vortex->eq.this04); 131 int i = 0, ebx; 132 133 hwwrite(vortex->mmio, 0x2b404, a[0]); 134 hwwrite(vortex->mmio, 0x2b408, a[1]); 135 136 for (ebx = 0; ebx < eqhw->this04; ebx++) { 137 hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]); 138 hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]); 139 hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]); 140 hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]); 141 i += 4; 142 } 143} 144 145/* Mix Gains */ 146static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b) 147{ 148 eqhw_t *eqhw = &(vortex->eq.this04); 149 if (eqhw->this08 == 0) { 150 hwwrite(vortex->mmio, 0x2b3d4, a); 151 hwwrite(vortex->mmio, 0x2b3ec, b); 152 } else { 153 hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a)); 154 hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b)); 155 } 156} 157 158static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b) 159{ 160 161 hwwrite(vortex->mmio, 0x2b3e0, a); 162 hwwrite(vortex->mmio, 0x2b3f8, b); 163} 164 165static void 166vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) 167{ 168 hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b); 169} 170 171static void 172vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) 173{ 174 hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b); 175} 176 177static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[]) 178{ 179 eqhw_t *eqhw = &(vortex->eq.this04); 180 int ebx; 181 182 for (ebx = 0; ebx < eqhw->this04; ebx++) { 183 hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]); 184 } 185} 186 187static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[]) 188{ 189 eqhw_t *eqhw = &(vortex->eq.this04); 190 int ebx; 191 192 for (ebx = 0; ebx < eqhw->this04; ebx++) { 193 hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]); 194 } 195} 196 197static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[]) 198{ 199 eqhw_t *eqhw = &(vortex->eq.this04); 200 int ebx; 201 202 for (ebx = 0; ebx < eqhw->this04; ebx++) { 203 hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]); 204 } 205} 206 207static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[]) 208{ 209 eqhw_t *eqhw = &(vortex->eq.this04); 210 int ebx; 211 212 for (ebx = 0; ebx < eqhw->this04; ebx++) { 213 hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]); 214 } 215} 216 217/* EQ band levels settings */ 218static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[]) 219{ 220 eqhw_t *eqhw = &(vortex->eq.this04); 221 int i; 222 223 /* set left peaks */ 224 for (i = 0; i < eqhw->this04; i++) { 225 hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]); 226 } 227 228 hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]); 229 hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]); 230 231 /* set right peaks */ 232 for (i = 0; i < eqhw->this04; i++) { 233 hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE, 234 peaks[i + (eqhw->this04 + 2)]); 235 } 236 237 hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]); 238 hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]); 239} 240 241/* Global Control */ 242static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg) 243{ 244 hwwrite(vortex->mmio, 0x2b440, reg); 245} 246 247static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr) 248{ 249 hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800); 250} 251 252static void vortex_EqHw_Enable(vortex_t * vortex) 253{ 254 hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001); 255} 256 257static void vortex_EqHw_Disable(vortex_t * vortex) 258{ 259 hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000); 260} 261 262/* Reset (zero) buffers */ 263static void vortex_EqHw_ZeroIO(vortex_t * vortex) 264{ 265 int i; 266 for (i = 0; i < 0x8; i++) 267 hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0); 268 for (i = 0; i < 0x4; i++) 269 hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0); 270} 271 272static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex) 273{ 274 int i; 275 for (i = 0; i < 0x4; i++) 276 hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0); 277} 278 279static void vortex_EqHw_ZeroState(vortex_t * vortex) 280{ 281 282 vortex_EqHw_SetControlReg(vortex, 0); 283 vortex_EqHw_ZeroIO(vortex); 284 hwwrite(vortex->mmio, 0x2b3c0, 0); 285 286 vortex_EqHw_SetTimeConsts(vortex, 0, 0); 287 288 vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros); 289 vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros); 290 291 vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero); 292 vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero); 293 vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero); 294 vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero); 295 296 vortex_EqHw_SetBypassGain(vortex, 0, 0); 297 //vortex_EqHw_SetCurrBypassGain(vortex, 0, 0); 298 vortex_EqHw_SetA3DBypassGain(vortex, 0, 0); 299 //vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0); 300 vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros); 301 vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros); 302 vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels); 303} 304 305/* Program coeficients as pass through */ 306static void vortex_EqHw_ProgramPipe(vortex_t * vortex) 307{ 308 vortex_EqHw_SetTimeConsts(vortex, 0, 0); 309 310 vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes); 311 vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes); 312 313 vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current); 314 vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current); 315 vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current); 316 vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current); 317} 318 319/* Program EQ block as 10 band Equalizer */ 320static void 321vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset) 322{ 323 324 vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0); 325 326 vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs); 327 vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs); 328 329 vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains); 330 331 vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains); 332 vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains); 333 334 vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains); 335} 336 337/* Read all EQ peaks. (think VU meter) */ 338static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[]) 339{ 340 eqhw_t *eqhw = &(vortex->eq.this04); 341 int i; 342 343 if (eqhw->this04 <= 0) 344 return; 345 346 for (i = 0; i < eqhw->this04; i++) 347 peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30); 348 for (i = 0; i < eqhw->this04; i++) 349 peaks[i + eqhw->this04] = 350 hwread(vortex->mmio, 0x2B204 + i * 0x30); 351} 352 353/* CEqlzr.s */ 354 355static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain) 356{ 357 eqlzr_t *eq = &(vortex->eq); 358 359 if (eq->this28) { 360 *gain = eq->this130[index]; 361 return 0; 362 } 363 return 1; 364} 365 366static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain) 367{ 368 eqlzr_t *eq = &(vortex->eq); 369 370 if (eq->this28 == 0) 371 return; 372 373 eq->this130[index] = gain; 374 if (eq->this54) 375 return; 376 377 vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain); 378} 379 380static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain) 381{ 382 eqlzr_t *eq = &(vortex->eq); 383 384 if (eq->this28) { 385 *gain = eq->this130[index + eq->this10]; 386 return 0; 387 } 388 return 1; 389} 390 391static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain) 392{ 393 eqlzr_t *eq = &(vortex->eq); 394 395 if (eq->this28 == 0) 396 return; 397 398 eq->this130[index + eq->this10] = gain; 399 if (eq->this54) 400 return; 401 402 vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain); 403} 404 405static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex) 406{ 407 eqlzr_t *eq = &(vortex->eq); 408 409 vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130); 410 vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10])); 411 412 return 0; 413} 414 415static int 416vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count) 417{ 418 eqlzr_t *eq = &(vortex->eq); 419 int i; 420 421 if (((eq->this10) * 2 != count) || (eq->this28 == 0)) 422 return 1; 423 424 for (i = 0; i < count; i++) { 425 eq->this130[i] = gains[i]; 426 } 427 428 if (eq->this54) 429 return 0; 430 return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex); 431} 432 433static void 434vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b) 435{ 436 eqlzr_t *eq = &(vortex->eq); 437 u32 eax, ebx; 438 439 eq->this58 = a; 440 eq->this5c = b; 441 if (eq->this54) 442 eax = eq->this0e; 443 else 444 eax = eq->this0a; 445 ebx = (eax * eq->this58) >> 0x10; 446 eax = (eax * eq->this5c) >> 0x10; 447 vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); 448} 449 450static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex) 451{ 452 eqlzr_t *eq = &(vortex->eq); 453 u32 eax, ebx; 454 455 if (eq->this54) 456 eax = eq->this0e; 457 else 458 eax = eq->this0a; 459 ebx = (eax * eq->this58) >> 0x10; 460 eax = (eax * eq->this5c) >> 0x10; 461 vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); 462} 463 464static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex) 465{ 466 if (vortex != NULL) 467 vortex_EqHw_ZeroA3DIO(vortex); 468} 469 470static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp) 471{ 472 eqlzr_t *eq = &(vortex->eq); 473 474 if ((eq->this28) && (bp == 0)) { 475 /* EQ enabled */ 476 vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex); 477 vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08); 478 } else { 479 /* EQ disabled. */ 480 vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array); 481 vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array); 482 vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c); 483 } 484 vortex_Eqlzr_ProgramA3dBypassGain(vortex); 485} 486 487static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex) 488{ 489 eqlzr_t *eq = &(vortex->eq); 490 491 /* Set EQ BiQuad filter coeficients */ 492 memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t)); 493 /* Set EQ Band gain levels and dump into hardware registers. */ 494 vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2); 495} 496 497static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count) 498{ 499 eqlzr_t *eq = &(vortex->eq); 500 501 if (eq->this10 == 0) 502 return 1; 503 *count = eq->this10 * 2; 504 vortex_EqHw_GetTenBandLevels(vortex, peaks); 505 return 0; 506} 507 508static void vortex_Eqlzr_init(vortex_t * vortex) 509{ 510 eqlzr_t *eq = &(vortex->eq); 511 512 /* Object constructor */ 513 //eq->this04 = 0; 514 eq->this08 = 0; /* Bypass gain with EQ in use. */ 515 eq->this0a = 0x5999; 516 eq->this0c = 0x5999; /* Bypass gain with EQ disabled. */ 517 eq->this0e = 0x5999; 518 519 eq->this10 = 0xa; /* 10 eq frequency bands. */ 520 eq->this04.this04 = eq->this10; 521 eq->this28 = 0x1; /* if 1 => Allow read access to this130 (gains) */ 522 eq->this54 = 0x0; /* if 1 => Dont Allow access to hardware (gains) */ 523 eq->this58 = 0xffff; 524 eq->this5c = 0xffff; 525 526 /* Set gains. */ 527 memset(eq->this14_array, 0, sizeof(eq->this14_array)); 528 529 /* Actual init. */ 530 vortex_EqHw_ZeroState(vortex); 531 vortex_EqHw_SetSampleRate(vortex, 0x11); 532 vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex); 533 534 vortex_EqHw_Program10Band(vortex, &(eq->coefset)); 535 vortex_Eqlzr_SetBypass(vortex, eq->this54); 536 vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0); 537 vortex_EqHw_Enable(vortex); 538} 539 540static void vortex_Eqlzr_shutdown(vortex_t * vortex) 541{ 542 vortex_Eqlzr_ShutDownA3d(vortex); 543 vortex_EqHw_ProgramPipe(vortex); 544 vortex_EqHw_Disable(vortex); 545} 546 547/* ALSA interface */ 548 549/* Control interface */ 550#define snd_vortex_eqtoggle_info snd_ctl_boolean_mono_info 551 552static int 553snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol, 554 struct snd_ctl_elem_value *ucontrol) 555{ 556 vortex_t *vortex = snd_kcontrol_chip(kcontrol); 557 eqlzr_t *eq = &(vortex->eq); 558 //int i = kcontrol->private_value; 559 560 ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1; 561 562 return 0; 563} 564 565static int 566snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol, 567 struct snd_ctl_elem_value *ucontrol) 568{ 569 vortex_t *vortex = snd_kcontrol_chip(kcontrol); 570 eqlzr_t *eq = &(vortex->eq); 571 //int i = kcontrol->private_value; 572 573 eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1; 574 vortex_Eqlzr_SetBypass(vortex, eq->this54); 575 576 return 1; /* Allways changes */ 577} 578 579static struct snd_kcontrol_new vortex_eqtoggle_kcontrol __devinitdata = { 580 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 581 .name = "EQ Enable", 582 .index = 0, 583 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 584 .private_value = 0, 585 .info = snd_vortex_eqtoggle_info, 586 .get = snd_vortex_eqtoggle_get, 587 .put = snd_vortex_eqtoggle_put 588}; 589 590static int 591snd_vortex_eq_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 592{ 593 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 594 uinfo->count = 2; 595 uinfo->value.integer.min = 0x0000; 596 uinfo->value.integer.max = 0x7fff; 597 return 0; 598} 599 600static int 601snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 602{ 603 vortex_t *vortex = snd_kcontrol_chip(kcontrol); 604 int i = kcontrol->private_value; 605 u16 gainL = 0, gainR = 0; 606 607 vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); 608 vortex_Eqlzr_GetRightGain(vortex, i, &gainR); 609 ucontrol->value.integer.value[0] = gainL; 610 ucontrol->value.integer.value[1] = gainR; 611 return 0; 612} 613 614static int 615snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 616{ 617 vortex_t *vortex = snd_kcontrol_chip(kcontrol); 618 int changed = 0, i = kcontrol->private_value; 619 u16 gainL = 0, gainR = 0; 620 621 vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); 622 vortex_Eqlzr_GetRightGain(vortex, i, &gainR); 623 624 if (gainL != ucontrol->value.integer.value[0]) { 625 vortex_Eqlzr_SetLeftGain(vortex, i, 626 ucontrol->value.integer.value[0]); 627 changed = 1; 628 } 629 if (gainR != ucontrol->value.integer.value[1]) { 630 vortex_Eqlzr_SetRightGain(vortex, i, 631 ucontrol->value.integer.value[1]); 632 changed = 1; 633 } 634 return changed; 635} 636 637static struct snd_kcontrol_new vortex_eq_kcontrol __devinitdata = { 638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 639 .name = " .", 640 .index = 0, 641 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 642 .private_value = 0, 643 .info = snd_vortex_eq_info, 644 .get = snd_vortex_eq_get, 645 .put = snd_vortex_eq_put 646}; 647 648static int 649snd_vortex_peaks_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 650{ 651 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 652 uinfo->count = 20; 653 uinfo->value.integer.min = 0x0000; 654 uinfo->value.integer.max = 0x7fff; 655 return 0; 656} 657 658static int 659snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 660{ 661 vortex_t *vortex = snd_kcontrol_chip(kcontrol); 662 int i, count = 0; 663 u16 peaks[20]; 664 665 vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); 666 if (count != 20) { 667 printk(KERN_ERR "vortex: peak count error 20 != %d \n", count); 668 return -1; 669 } 670 for (i = 0; i < 20; i++) 671 ucontrol->value.integer.value[i] = peaks[i]; 672 673 return 0; 674} 675 676static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = { 677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 678 .name = "EQ Peaks", 679 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 680 .info = snd_vortex_peaks_info, 681 .get = snd_vortex_peaks_get, 682}; 683 684/* EQ band gain labels. */ 685static char *EqBandLabels[10] __devinitdata = { 686 "EQ0 31Hz\0", 687 "EQ1 63Hz\0", 688 "EQ2 125Hz\0", 689 "EQ3 250Hz\0", 690 "EQ4 500Hz\0", 691 "EQ5 1KHz\0", 692 "EQ6 2KHz\0", 693 "EQ7 4KHz\0", 694 "EQ8 8KHz\0", 695 "EQ9 16KHz\0", 696}; 697 698/* ALSA driver entry points. Init and exit. */ 699static int __devinit vortex_eq_init(vortex_t * vortex) 700{ 701 struct snd_kcontrol *kcontrol; 702 int err, i; 703 704 vortex_Eqlzr_init(vortex); 705 706 if ((kcontrol = 707 snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL) 708 return -ENOMEM; 709 kcontrol->private_value = 0; 710 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 711 return err; 712 713 /* EQ gain controls */ 714 for (i = 0; i < 10; i++) { 715 if ((kcontrol = 716 snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL) 717 return -ENOMEM; 718 strcpy(kcontrol->id.name, EqBandLabels[i]); 719 kcontrol->private_value = i; 720 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 721 return err; 722 //vortex->eqctrl[i] = kcontrol; 723 } 724 /* EQ band levels */ 725 if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL) 726 return -ENOMEM; 727 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 728 return err; 729 730 return 0; 731} 732 733static int vortex_eq_free(vortex_t * vortex) 734{ 735 vortex_Eqlzr_shutdown(vortex); 736 return 0; 737} 738 739/* End */ 740