1 /* 2 * SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver. 3 * Copyright (c) 2002, 2008-2011 S.Zharski <imker@gmx.li> 4 * Distributed under the terms of the MIT license. 5 * 6 * Copyright for ali5451 support: 7 * (c) 2009, Krzysztof Ćwiertnia (krzysiek.bmkx_gmail_com). 8 */ 9 10 11 #include "Mixer.h" 12 13 #include <string.h> 14 15 #include "Device.h" 16 #include "Registers.h" 17 #include "Settings.h" 18 19 20 Mixer::Mixer(Device *device) 21 : 22 fDevice(device), 23 fAC97Dev(NULL), 24 fReadPort(RegCodecRead), 25 fWritePort(RegCodecWrite), 26 fMaskRW(1 << 15), 27 fMaskRD(1 << 15), 28 fMaskWD(1 << 15), 29 fHasVRA(false), 30 fInputRates(0), 31 fOutputRates(0), 32 fInputFormats(0), 33 fOutputFormats(0) 34 { 35 switch (device->HardwareId()) { 36 case ALi5451: 37 if (fDevice->PCIInfo().revision > 0x01) { 38 fReadPort = RegCodecWrite; 39 fMaskWD = 1 << 8; 40 } 41 case SiS7018: 42 break; 43 case TridentDX: 44 break; 45 case TridentNX: 46 fReadPort = RegNXCodecRead; 47 fWritePort = RegNXCodecWrite; 48 fMaskRW = 1 << 11; 49 fMaskRD = 1 << 10; 50 fMaskWD = 1 << 11; 51 break; 52 } 53 54 TRACE("Regs:R:%#x;W:%#x;MRW:%#x;MRD:%#x;MWD:%#x\n", 55 fReadPort, fWritePort, fMaskRW, fMaskRD, fMaskWD); 56 } 57 58 59 void 60 Mixer::Init() 61 { 62 ac97_attach(&fAC97Dev, _ReadAC97, _WriteAC97, this, 63 fDevice->PCIInfo().u.h0.subsystem_vendor_id, 64 fDevice->PCIInfo().u.h0.subsystem_id); 65 66 _ReadSupportedFormats(); 67 } 68 69 70 void 71 Mixer::_ReadSupportedFormats() 72 { 73 fInputRates = B_SR_48000; 74 fOutputRates = 0; 75 fInputFormats = B_FMT_16BIT; 76 fOutputFormats = B_FMT_16BIT; 77 78 uint16 extId = ac97_reg_cached_read(fAC97Dev, AC97_EXTENDED_ID); 79 uint16 extCtrl = ac97_reg_cached_read(fAC97Dev, AC97_EXTENDED_STAT_CTRL); 80 TRACE("Ext.ID:%#010x %#010x\n", extId, extCtrl); 81 82 fHasVRA = ((extId & EXID_VRA) == EXID_VRA); 83 if (!fHasVRA) { 84 fOutputRates = B_SR_8000 | B_SR_11025 | B_SR_12000 85 | B_SR_16000 | B_SR_22050 | B_SR_24000 86 | B_SR_32000 | B_SR_44100 | B_SR_48000; 87 TRACE("VRA is not supported. Assume all rates are ok:%#010x\n", 88 fOutputRates); 89 return; 90 } 91 92 struct _Cap { 93 ac97_capability fCap; 94 uint32 fRate; 95 } caps[] = { 96 { CAP_PCM_RATE_8000, B_SR_8000 }, 97 { CAP_PCM_RATE_11025, B_SR_11025 }, 98 { CAP_PCM_RATE_12000, B_SR_12000 }, 99 { CAP_PCM_RATE_16000, B_SR_16000 }, 100 { CAP_PCM_RATE_22050, B_SR_22050 }, 101 { CAP_PCM_RATE_24000, B_SR_24000 }, 102 { CAP_PCM_RATE_32000, B_SR_32000 }, 103 { CAP_PCM_RATE_44100, B_SR_44100 }, 104 { CAP_PCM_RATE_48000, B_SR_48000 } 105 }; 106 107 for (size_t i = 0; i < _countof(caps); i++) { 108 if (ac97_has_capability(fAC97Dev, caps[i].fCap)) 109 fOutputRates |= caps[i].fRate; 110 } 111 112 if (fOutputRates == 0) { 113 ERROR("Output rates are not guessed. Force to 48 kHz.\n"); 114 fOutputRates = B_SR_48000; 115 } 116 117 TRACE("Output rates are:%#010x\n", fOutputRates); 118 } 119 120 121 void 122 Mixer::Free() 123 { 124 ac97_detach(fAC97Dev); 125 } 126 127 128 uint16 129 Mixer::_ReadAC97(void* cookie, uint8 reg) 130 { 131 return reinterpret_cast<Mixer*>(cookie)->_ReadAC97(reg); 132 } 133 134 135 void 136 Mixer::_WriteAC97(void* cookie, uint8 reg, uint16 data) 137 { 138 return reinterpret_cast<Mixer*>(cookie)->_WriteAC97(reg, data); 139 } 140 141 142 bool 143 Mixer::_WaitPortReady(uint8 reg, uint32 mask, uint32* result) 144 { 145 int count = 200; 146 uint32 data = 0; 147 148 while (count--) { 149 data = fDevice->ReadPCI32(reg); 150 if ((data & mask) == 0) { 151 if (result != NULL) 152 *result = data; 153 return true; 154 } 155 spin(1); 156 } 157 158 ERROR("AC97 register %#04x is not ready.\n", reg); 159 return false; 160 } 161 162 163 bool 164 Mixer::_WaitSTimerReady() 165 { 166 if (fDevice->HardwareId() != ALi5451) 167 return true; 168 169 int count = 200; 170 uint32 time1 = fDevice->ReadPCI32(RegALiSTimer); 171 172 while (count--) { 173 uint32 time2 = fDevice->ReadPCI32(RegALiSTimer); 174 if (time2 != time1) 175 return true; 176 spin(1); 177 } 178 179 ERROR("AC97 STimer is not ready.\n"); 180 return false; 181 } 182 183 184 uint16 185 Mixer::_ReadAC97(uint8 reg) 186 { 187 uint32 result = 0; 188 189 cpu_status cp = fDevice->Lock(); 190 191 if (_WaitPortReady(fWritePort, fMaskRD) 192 && _WaitPortReady(fReadPort, fMaskRD) && _WaitSTimerReady()) { 193 194 fDevice->WritePCI32(fReadPort, (reg & 0x7f) | fMaskRW); 195 196 if (_WaitSTimerReady() && _WaitPortReady(fReadPort, fMaskRD, &result)) 197 result = (result >> 16) & 0xffff; 198 } 199 200 fDevice->Unlock(cp); 201 202 return result; 203 } 204 205 206 void 207 Mixer::_WriteAC97(uint8 reg, uint16 data) 208 { 209 cpu_status cp = fDevice->Lock(); 210 211 if (_WaitPortReady(fWritePort, fMaskRW) && _WaitSTimerReady()) { 212 213 fDevice->WritePCI32(fWritePort, 214 (data << 16) | (reg & 0x7f) | fMaskRW | fMaskWD); 215 } 216 217 fDevice->Unlock(cp); 218 } 219 220 221 void 222 Mixer::SetOutputRate(uint32 outputRate) 223 { 224 if (!fHasVRA) 225 return; 226 227 uint32 rate = 0; 228 if (!ac97_get_rate(fAC97Dev, AC97_PCM_FRONT_DAC_RATE, &rate)) { 229 ERROR("Failed to read PCM Front DAC Rate. Force to %d.\n", outputRate); 230 } else 231 if (rate == outputRate) { 232 TRACE("AC97 PCM Front DAC rate not set to %d\n", outputRate); 233 return; 234 } 235 236 if (!ac97_set_rate(fAC97Dev, AC97_PCM_FRONT_DAC_RATE, rate)) 237 ERROR("Failed to set AC97 PCM Front DAC rate\n"); 238 else 239 TRACE("AC97 PCM Front DAC rate set to %d\n", outputRate); 240 } 241 242 243 // Control ids are encoded in the following way: 244 // GGBBRRTT -- 245 // GG - in gain controls: 10th of granularity. Signed! 246 // - in MUX controls: value of selector. 247 // BB - in gain controls: base level - correspond to 0 db. 248 // - mute, boost, enable controls: offset of "on/off" bit 249 // RR - AC97 Register handled by this control 250 // TT - MIXControlTypes bits 251 252 const int stepShift = 24; // offset to GG 253 const int baseShift = 16; // offset to BB 254 const int regShift = 8; // offset to RR 255 256 enum MIXControlTypes { 257 MIX_RGain = 0x01, 258 MIX_LGain = 0x10, 259 MIX_Mono = MIX_RGain, 260 MIX_Stereo = MIX_LGain | MIX_RGain, 261 MIX_Mute = 0x04, 262 MIX_Boost = 0x08, 263 MIX_MUX = 0x20, 264 MIX_Enable = 0x40, 265 MIX_Check = MIX_Mute | MIX_Boost | MIX_Enable 266 }; 267 268 269 struct GainInfo { 270 uint8 fOff; // offset of mask in register word 271 uint8 fBase; // base - default value of register 272 uint8 fMask; // mask - maximal value of register 273 float fMult; // multiplier - bits to dB recalculate 274 uint8 fEnaOff; // offset of "on/off" bit in register word 275 }; 276 277 278 GainInfo MixGain = { 0x00, 0x00, 0x3f, -1.5, 0x0f }; 279 GainInfo InGain = { 0x00, 0x08, 0x1f, -1.5, 0x0f }; 280 GainInfo RecGain = { 0x00, 0x00, 0x0f, 1.5, 0x0f }; 281 GainInfo BeepGain = { 0x01, 0x00, 0x1e, 3.0, 0x0f }; 282 GainInfo ToneGain = { 0x00, 0x07, 0x0f, -1.5, 0x10 }; // 0x10 - mean no "mute" 283 GainInfo D3DGain = { 0x00, 0x00, 0x0f, 1.0, 0x10 }; 284 285 286 struct MIXControlInfo { 287 uint8 fAC97Reg; 288 GainInfo* fInfo; 289 strind_id fNameId; 290 uint16 fType; 291 const char* fName; 292 293 uint8 fExAC97Reg; 294 strind_id fExNameId; 295 const char* fExName; 296 uint8 fExOff; 297 }; 298 299 300 MIXControlInfo OutputControls[] = { 301 { AC97_MASTER_VOLUME, &MixGain, S_MASTER, 302 MIX_Stereo | MIX_Mute, NULL }, 303 { AC97_AUX_OUT_VOLUME, &MixGain, S_AUX, 304 MIX_Stereo | MIX_Mute, NULL }, 305 { AC97_MASTER_TONE, &ToneGain, S_OUTPUT_BASS, 306 MIX_LGain, NULL }, 307 { AC97_MASTER_TONE, &ToneGain, S_OUTPUT_TREBLE, 308 MIX_RGain, NULL }, 309 { AC97_3D_CONTROL, &D3DGain, S_OUTPUT_3D_DEPTH, 310 MIX_RGain | MIX_Enable, NULL, 311 AC97_GENERAL_PURPOSE, S_ENABLE, NULL, 0x0d }, 312 { AC97_3D_CONTROL, &D3DGain, S_OUTPUT_3D_CENTER, 313 MIX_LGain, NULL }, 314 { AC97_MONO_VOLUME, &MixGain, S_MONO_MIX, 315 MIX_Mono | MIX_Mute, NULL }, 316 { AC97_PC_BEEP_VOLUME, &BeepGain, S_BEEP, 317 MIX_Mono | MIX_Mute, NULL } 318 }; 319 320 321 MIXControlInfo InputControls[] = { 322 { AC97_PCM_OUT_VOLUME, &InGain, S_WAVE, 323 MIX_Stereo | MIX_Mute, NULL }, 324 { AC97_MIC_VOLUME, &InGain, S_MIC, 325 MIX_Mono | MIX_Mute | MIX_Boost, NULL, 326 AC97_MIC_VOLUME, S_null, "+ 20 dB", 0x06 }, 327 { AC97_LINE_IN_VOLUME, &InGain, S_LINE, 328 MIX_Stereo | MIX_Mute, NULL }, 329 { AC97_CD_VOLUME, &InGain, S_CD, 330 MIX_Stereo | MIX_Mute, NULL }, 331 { AC97_VIDEO_VOLUME, &InGain, S_VIDEO, 332 MIX_Stereo | MIX_Mute, NULL }, 333 { AC97_AUX_IN_VOLUME, &InGain, S_AUX, 334 MIX_Stereo | MIX_Mute, NULL }, 335 { AC97_PHONE_VOLUME, &InGain, S_PHONE, 336 MIX_Mono | MIX_Mute, NULL } 337 }; 338 339 340 strind_id RecordSources[] = { 341 S_MIC, 342 S_CD, 343 S_VIDEO, 344 S_AUX, 345 S_LINE, 346 S_STEREO_MIX, 347 S_MONO_MIX, 348 S_PHONE 349 }; 350 351 352 MIXControlInfo RecordControls[] = { 353 { AC97_RECORD_GAIN, &RecGain, S_null, 354 MIX_Stereo | MIX_Mute | MIX_MUX, "Record Gain", 355 AC97_RECORD_SELECT, S_null, "Source" }, 356 { AC97_RECORD_GAIN_MIC, &RecGain, S_MIC, 357 MIX_Mono | MIX_Mute, NULL } 358 }; 359 360 361 void 362 Mixer::_InitGainLimits(multi_mix_control& Control, GainInfo& Info) 363 { 364 float base = Info.fBase >> Info.fOff; 365 float max = Info.fMask >> Info.fOff; 366 367 float min_gain = Info.fMult * (0.0 - base); 368 float max_gain = Info.fMult * (max - base); 369 370 Control.gain.min_gain = (Info.fMult > 0) ? min_gain : max_gain; 371 Control.gain.max_gain = (Info.fMult > 0) ? max_gain : min_gain; 372 Control.gain.granularity = Info.fMult; 373 374 // encode gain granularity in the MSB of the control id. 375 uint8 gran = (uint8)(Info.fMult * 10.); 376 Control.id |= (gran << stepShift); 377 Control.id |= (Info.fBase << baseShift); 378 379 TRACE("base:%#04x; mask:%#04x; mult:%f\n", 380 Info.fBase, Info.fMask, Info.fMult); 381 TRACE(" min:%f; max:%f; gran:%f -> %#010x\n", 382 Control.gain.min_gain, Control.gain.max_gain, 383 Control.gain.granularity, Control.id); 384 } 385 386 387 bool 388 Mixer::_CheckRegFeatures(uint8 AC97Reg, uint16& mask, uint16& result) 389 { 390 uint16 backup = ac97_reg_cached_read(fAC97Dev, AC97Reg); 391 392 ac97_reg_cached_write(fAC97Dev, AC97Reg, mask); 393 result = ac97_reg_cached_read(fAC97Dev, AC97Reg); 394 TRACE("Check for register %#02x: %#x -> %#x.\n", AC97Reg, mask, result); 395 396 ac97_reg_cached_write(fAC97Dev, AC97Reg, backup); 397 398 return mask != result; 399 } 400 401 402 bool 403 Mixer::_CorrectMIXControlInfo(MIXControlInfo& Info, GainInfo& gainInfo) 404 { 405 uint16 newMask = gainInfo.fMask; 406 uint16 testMask = 0; 407 uint16 testResult = 0; 408 409 switch (Info.fAC97Reg) { 410 case AC97_AUX_OUT_VOLUME: 411 if (ac97_has_capability(fAC97Dev, CAP_HEADPHONE_OUT)) { 412 Info.fNameId = S_HEADPHONE; 413 Info.fName = NULL; 414 } 415 case AC97_MASTER_VOLUME: 416 testMask = 0x2020; 417 newMask = 0x1f; 418 break; 419 case AC97_MASTER_TONE: 420 if (!ac97_has_capability(fAC97Dev, CAP_BASS_TREBLE_CTRL)) 421 return false; 422 testMask = 0x0f0f; 423 break; 424 case AC97_3D_CONTROL: 425 if (!ac97_has_capability(fAC97Dev, CAP_3D_ENHANCEMENT)) 426 return false; 427 testMask = 0x0f0f; 428 break; 429 case AC97_RECORD_GAIN_MIC: 430 if (!ac97_has_capability(fAC97Dev, CAP_PCM_MIC)) 431 return false; 432 testMask = 0x0f; 433 break; 434 case AC97_MONO_VOLUME: 435 testMask = 0x20; 436 newMask = 0x1f; 437 break; 438 case AC97_PC_BEEP_VOLUME: 439 testMask = 0x1e; 440 break; 441 case AC97_VIDEO_VOLUME: 442 case AC97_AUX_IN_VOLUME: 443 case AC97_PHONE_VOLUME: 444 testMask = 0x1f; 445 break; 446 default: 447 return true; 448 } 449 450 if (_CheckRegFeatures(Info.fAC97Reg, testMask, testResult)) { 451 if (testResult == 0) 452 return false; 453 454 gainInfo.fMask = newMask; 455 } 456 457 return true; 458 } 459 460 461 int32 462 Mixer::_CreateMIXControlGroup(multi_mix_control_info* MultiInfo, int32& index, 463 int32 parentIndex, MIXControlInfo& Info) 464 { 465 // check the optional registers and features, 466 // correct the range if required and do not add if not supported 467 GainInfo gainInfo = *Info.fInfo; 468 if (!_CorrectMIXControlInfo(Info, gainInfo)) 469 return 0; 470 471 int32 IdReg = Info.fAC97Reg << regShift; 472 multi_mix_control* Controls = MultiInfo->controls; 473 474 int32 groupIndex 475 = Controls[index].id = IdReg | Info.fType; 476 Controls[index].flags = B_MULTI_MIX_GROUP; 477 Controls[index].parent = parentIndex; 478 Controls[index].string = Info.fNameId; 479 if (Info.fName != NULL) 480 strncpy(Controls[index].name, Info.fName, sizeof(Controls[index].name)); 481 index++; 482 483 if (Info.fType & MIX_Mute) { 484 Controls[index].id = IdReg | MIX_Check; 485 Controls[index].id |= Info.fInfo->fEnaOff << baseShift; 486 Controls[index].flags = B_MULTI_MIX_ENABLE; 487 Controls[index].parent = groupIndex; 488 Controls[index].string = S_MUTE; 489 490 TRACE("Mute:%#010x\n", Controls[index].id); 491 index++; 492 } 493 494 if (Info.fType & MIX_Enable) { 495 int32 IdExReg = Info.fExAC97Reg << regShift; 496 Controls[index].id = IdExReg | MIX_Check; 497 Controls[index].id |= (Info.fExOff << baseShift); 498 Controls[index].flags = B_MULTI_MIX_ENABLE; 499 Controls[index].parent = groupIndex; 500 Controls[index].string = Info.fExNameId; 501 if (Info.fExName != NULL) 502 strncpy(Controls[index].name, Info.fExName, 503 sizeof(Controls[index].name)); 504 505 TRACE("Enable:%#010x\n", Controls[index].id); 506 index++; 507 } 508 509 int32 gainIndex = 0; 510 if (Info.fType & MIX_LGain) { 511 Controls[index].id = IdReg | MIX_LGain; 512 Controls[index].flags = B_MULTI_MIX_GAIN; 513 Controls[index].parent = groupIndex; 514 Controls[index].string = S_GAIN; 515 _InitGainLimits(Controls[index], gainInfo); 516 gainIndex = Controls[index].id; 517 index++; 518 } 519 520 if (Info.fType & MIX_RGain) { 521 Controls[index].id = IdReg | MIX_RGain; 522 Controls[index].flags = B_MULTI_MIX_GAIN; 523 Controls[index].parent = groupIndex; 524 Controls[index].master = gainIndex; 525 Controls[index].string = S_GAIN; 526 _InitGainLimits(Controls[index], gainInfo); 527 index++; 528 } 529 530 if (Info.fType & MIX_Boost) { 531 Controls[index].id = IdReg | MIX_Check; 532 Controls[index].id |= (Info.fExOff << baseShift); 533 Controls[index].flags = B_MULTI_MIX_ENABLE; 534 Controls[index].parent = groupIndex; 535 Controls[index].string = Info.fExNameId; 536 if (Info.fExName != NULL) 537 strncpy(Controls[index].name, Info.fExName, 538 sizeof(Controls[index].name)); 539 540 TRACE("Boost:%#010x\n", Controls[index].id); 541 index++; 542 } 543 544 if (Info.fType & MIX_MUX) { 545 int32 IdMUXReg = Info.fExAC97Reg << regShift; 546 int32 recordMUX 547 = Controls[index].id = IdMUXReg | MIX_MUX; 548 Controls[index].flags = B_MULTI_MIX_MUX; 549 Controls[index].parent = groupIndex; 550 Controls[index].string = S_null; 551 strncpy(Controls[index].name, Info.fExName, sizeof(Controls[index].name)); 552 553 TRACE("MUX:%#010x\n", Controls[index].id); 554 index++; 555 556 for (size_t i = 0; i < _countof(RecordSources); i++) { 557 Controls[index].id = IdMUXReg | (i << stepShift) | MIX_MUX; 558 Controls[index].flags = B_MULTI_MIX_MUX_VALUE; 559 Controls[index].master = 0; 560 Controls[index].string = RecordSources[i]; 561 Controls[index].parent = recordMUX; 562 563 TRACE("MUX Item:%#010x\n", Controls[index].id); 564 565 index++; 566 } 567 } 568 569 return groupIndex; 570 } 571 572 573 status_t 574 Mixer::ListMixControls(multi_mix_control_info* Info) 575 { 576 int32 index = 0; 577 multi_mix_control* Controls = Info->controls; 578 int32 mixerGroup 579 = Controls[index].id = 0x8000; // 0x80 - is not a valid AC97 register 580 Controls[index].flags = B_MULTI_MIX_GROUP; 581 Controls[index].parent = 0; 582 Controls[index].string = S_OUTPUT; 583 index++; 584 585 for (size_t i = 0; i < _countof(OutputControls); i++) { 586 _CreateMIXControlGroup(Info, index, mixerGroup, OutputControls[i]); 587 } 588 589 int32 inputGroup 590 = Controls[index].id = 0x8100; 591 Controls[index].flags = B_MULTI_MIX_GROUP; 592 Controls[index].parent = 0; 593 Controls[index].string = S_INPUT; 594 index++; 595 596 for (size_t i = 0; i < _countof(InputControls); i++) { 597 _CreateMIXControlGroup(Info, index, inputGroup, InputControls[i]); 598 } 599 600 int32 recordGroup 601 = Controls[index].id = 0x8200; 602 Controls[index].flags = B_MULTI_MIX_GROUP; 603 Controls[index].parent = 0; 604 Controls[index].string = S_null; 605 strncpy(Controls[index].name, "Record", sizeof(Controls[index].name)); 606 index++; 607 608 for (size_t i = 0; i < _countof(RecordControls); i++) { 609 _CreateMIXControlGroup(Info, index, recordGroup, RecordControls[i]); 610 } 611 612 return B_OK; 613 } 614 615 616 status_t 617 Mixer::GetMix(multi_mix_value_info *Info) 618 { 619 for (int32 i = 0; i < Info->item_count; i++) { 620 621 int32 Id= Info->values[i].id; 622 uint8 Reg = (Id >> regShift) & 0xFF; 623 624 if ((Reg & 0x01) || Reg > 0x7e) { 625 ERROR("Invalid AC97 register:%#04x.Bypass it.\n", Reg); 626 continue; 627 } 628 629 uint16 RegValue = ac97_reg_cached_read(fAC97Dev, Reg); 630 631 if ((Id & MIX_Check) == MIX_Check) { 632 uint16 mask = 1 << ((Id >> baseShift) & 0xff); 633 Info->values[i].enable = (RegValue & mask) == mask; 634 TRACE("%#04x Mute|Enable|Boost:%d [data:%#04x]\n", 635 Reg, Info->values[i].enable, RegValue); 636 continue; 637 } 638 639 if ((Id & MIX_MUX) == MIX_MUX) { 640 Info->values[i].mux = (RegValue | (RegValue >> 8)) & 0x7; 641 TRACE("%#04x MUX:%d [data:%#04x]\n", 642 Reg, Info->values[i].mux, RegValue); 643 continue; 644 } 645 646 float mult = 0.1 * (int8)(Id >> stepShift); 647 float base = mult * ((Id >> baseShift) & 0xff); 648 649 if ((Id & MIX_RGain) == MIX_RGain) { 650 uint8 gain = RegValue & 0x3f; 651 Info->values[i].gain = mult * gain - base; 652 TRACE("%#04x for RGain:%f [mult:%f base:%f] <- %#04x\n", 653 Reg, Info->values[i].gain, mult, base, gain); 654 continue; 655 } 656 657 if ((Id & MIX_LGain) == MIX_LGain) { 658 uint8 gain = (RegValue >> 8) & 0x3f; 659 Info->values[i].gain = mult * gain - base; 660 TRACE("%#04x for LGain:%f [mult:%f base:%f] <- %#04x\n", 661 Reg, Info->values[i].gain, mult, base, gain); 662 } 663 } 664 665 return B_OK; 666 } 667 668 669 status_t 670 Mixer::SetMix(multi_mix_value_info *Info) 671 { 672 for (int32 i = 0; i < Info->item_count; i++) { 673 674 int32 Id = Info->values[i].id; 675 uint8 Reg = (Id >> regShift) & 0xFF; 676 677 if ((Reg & 0x01) || Reg > 0x7e) { 678 ERROR("Invalid AC97 register:%#04x.Bypass it.\n", Reg); 679 continue; 680 } 681 682 uint16 RegValue = ac97_reg_cached_read(fAC97Dev, Reg); 683 684 if ((Id & MIX_Check) == MIX_Check) { 685 uint16 mask = 1 << ((Id >> baseShift) & 0xff); 686 if (Info->values[i].enable) 687 RegValue |= mask; 688 else 689 RegValue &= ~mask; 690 TRACE("%#04x Mute/Enable:%d -> data:%#04x\n", 691 Reg, Info->values[i].enable, RegValue); 692 } 693 694 if ((Id & MIX_MUX) == MIX_MUX) { 695 uint8 mux = Info->values[i].mux & 0x7; 696 RegValue = mux | (mux << 8); 697 TRACE("%#04x MUX:%d -> data:%#04x\n", 698 Reg, Info->values[i].mux, RegValue); 699 } 700 701 float mult = 0.1 * (int8)(Id >> stepShift); 702 float base = mult * ((Id >> baseShift) & 0xff); 703 704 float gain = (Info->values[i].gain + base) / mult; 705 gain += (gain > 0.) ? 0.5 : -0.5; 706 uint8 gainValue = (uint8)gain; 707 708 if ((Id & MIX_RGain) == MIX_RGain) { 709 RegValue &= 0xffc0; 710 RegValue |= gainValue; 711 712 TRACE("%#04x for RGain:%f [mult:%f base:%f] -> %#04x\n", 713 Reg, Info->values[i].gain, mult, base, gainValue); 714 } 715 716 if ((Id & MIX_LGain) == MIX_LGain) { 717 RegValue &= 0xc0ff; 718 RegValue |= (gainValue << 8); 719 TRACE("%#04x for LGain:%f [mult:%f base:%f] -> %#04x\n", 720 Reg, Info->values[i].gain, mult, base, gainValue); 721 } 722 723 TRACE("%#04x Write:%#06x\n", Reg, RegValue); 724 725 ac97_reg_cached_write(fAC97Dev, Reg, RegValue); 726 } 727 728 return B_OK; 729 } 730 731