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
Mixer(Device * device)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
Init()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
_ReadSupportedFormats()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 < B_COUNT_OF(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
Free()122 Mixer::Free()
123 {
124 ac97_detach(fAC97Dev);
125 }
126
127
128 uint16
_ReadAC97(void * cookie,uint8 reg)129 Mixer::_ReadAC97(void* cookie, uint8 reg)
130 {
131 return reinterpret_cast<Mixer*>(cookie)->_ReadAC97(reg);
132 }
133
134
135 void
_WriteAC97(void * cookie,uint8 reg,uint16 data)136 Mixer::_WriteAC97(void* cookie, uint8 reg, uint16 data)
137 {
138 return reinterpret_cast<Mixer*>(cookie)->_WriteAC97(reg, data);
139 }
140
141
142 bool
_WaitPortReady(uint8 reg,uint32 mask,uint32 * result)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
_WaitSTimerReady()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
_ReadAC97(uint8 reg)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
_WriteAC97(uint8 reg,uint16 data)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
SetOutputRate(uint32 outputRate)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
_InitGainLimits(multi_mix_control & Control,GainInfo & Info)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
_CheckRegFeatures(uint8 AC97Reg,uint16 & mask,uint16 & result)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
_CorrectMIXControlInfo(MIXControlInfo & Info,GainInfo & gainInfo)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
_CreateMIXControlGroup(multi_mix_control_info * MultiInfo,int32 & index,int32 parentIndex,MIXControlInfo & Info)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 strlcpy(Controls[index].name, Info.fName,
481 sizeof(Controls[index].name));
482 index++;
483
484 if (Info.fType & MIX_Mute) {
485 Controls[index].id = IdReg | MIX_Check;
486 Controls[index].id |= Info.fInfo->fEnaOff << baseShift;
487 Controls[index].flags = B_MULTI_MIX_ENABLE;
488 Controls[index].parent = groupIndex;
489 Controls[index].string = S_MUTE;
490
491 TRACE("Mute:%#010x\n", Controls[index].id);
492 index++;
493 }
494
495 if (Info.fType & MIX_Enable) {
496 int32 IdExReg = Info.fExAC97Reg << regShift;
497 Controls[index].id = IdExReg | MIX_Check;
498 Controls[index].id |= (Info.fExOff << baseShift);
499 Controls[index].flags = B_MULTI_MIX_ENABLE;
500 Controls[index].parent = groupIndex;
501 Controls[index].string = Info.fExNameId;
502 if (Info.fExName != NULL)
503 strlcpy(Controls[index].name, Info.fExName,
504 sizeof(Controls[index].name));
505
506 TRACE("Enable:%#010x\n", Controls[index].id);
507 index++;
508 }
509
510 int32 gainIndex = 0;
511 if (Info.fType & MIX_LGain) {
512 Controls[index].id = IdReg | MIX_LGain;
513 Controls[index].flags = B_MULTI_MIX_GAIN;
514 Controls[index].parent = groupIndex;
515 Controls[index].string = S_GAIN;
516 _InitGainLimits(Controls[index], gainInfo);
517 gainIndex = Controls[index].id;
518 index++;
519 }
520
521 if (Info.fType & MIX_RGain) {
522 Controls[index].id = IdReg | MIX_RGain;
523 Controls[index].flags = B_MULTI_MIX_GAIN;
524 Controls[index].parent = groupIndex;
525 Controls[index].master = gainIndex;
526 Controls[index].string = S_GAIN;
527 _InitGainLimits(Controls[index], gainInfo);
528 index++;
529 }
530
531 if (Info.fType & MIX_Boost) {
532 Controls[index].id = IdReg | MIX_Check;
533 Controls[index].id |= (Info.fExOff << baseShift);
534 Controls[index].flags = B_MULTI_MIX_ENABLE;
535 Controls[index].parent = groupIndex;
536 Controls[index].string = Info.fExNameId;
537 if (Info.fExName != NULL)
538 strlcpy(Controls[index].name, Info.fExName,
539 sizeof(Controls[index].name));
540
541 TRACE("Boost:%#010x\n", Controls[index].id);
542 index++;
543 }
544
545 if (Info.fType & MIX_MUX) {
546 int32 IdMUXReg = Info.fExAC97Reg << regShift;
547 int32 recordMUX
548 = Controls[index].id = IdMUXReg | MIX_MUX;
549 Controls[index].flags = B_MULTI_MIX_MUX;
550 Controls[index].parent = groupIndex;
551 Controls[index].string = S_null;
552 if (Info.fExName != NULL)
553 strlcpy(Controls[index].name, Info.fExName,
554 sizeof(Controls[index].name));
555
556 TRACE("MUX:%#010x\n", Controls[index].id);
557 index++;
558
559 for (size_t i = 0; i < B_COUNT_OF(RecordSources); i++) {
560 Controls[index].id = IdMUXReg | (i << stepShift) | MIX_MUX;
561 Controls[index].flags = B_MULTI_MIX_MUX_VALUE;
562 Controls[index].master = 0;
563 Controls[index].string = RecordSources[i];
564 Controls[index].parent = recordMUX;
565
566 TRACE("MUX Item:%#010x\n", Controls[index].id);
567
568 index++;
569 }
570 }
571
572 return groupIndex;
573 }
574
575
576 status_t
ListMixControls(multi_mix_control_info * Info)577 Mixer::ListMixControls(multi_mix_control_info* Info)
578 {
579 int32 index = 0;
580 multi_mix_control* Controls = Info->controls;
581 int32 mixerGroup
582 = Controls[index].id = 0x8000; // 0x80 - is not a valid AC97 register
583 Controls[index].flags = B_MULTI_MIX_GROUP;
584 Controls[index].parent = 0;
585 Controls[index].string = S_OUTPUT;
586 index++;
587
588 for (size_t i = 0; i < B_COUNT_OF(OutputControls); i++) {
589 _CreateMIXControlGroup(Info, index, mixerGroup, OutputControls[i]);
590 }
591
592 int32 inputGroup
593 = Controls[index].id = 0x8100;
594 Controls[index].flags = B_MULTI_MIX_GROUP;
595 Controls[index].parent = 0;
596 Controls[index].string = S_INPUT;
597 index++;
598
599 for (size_t i = 0; i < B_COUNT_OF(InputControls); i++) {
600 _CreateMIXControlGroup(Info, index, inputGroup, InputControls[i]);
601 }
602
603 int32 recordGroup
604 = Controls[index].id = 0x8200;
605 Controls[index].flags = B_MULTI_MIX_GROUP;
606 Controls[index].parent = 0;
607 Controls[index].string = S_null;
608 strlcpy(Controls[index].name, "Record", sizeof(Controls[index].name));
609 index++;
610
611 for (size_t i = 0; i < B_COUNT_OF(RecordControls); i++) {
612 _CreateMIXControlGroup(Info, index, recordGroup, RecordControls[i]);
613 }
614
615 Info->control_count = index;
616
617 return B_OK;
618 }
619
620
621 status_t
GetMix(multi_mix_value_info * Info)622 Mixer::GetMix(multi_mix_value_info *Info)
623 {
624 for (int32 i = 0; i < Info->item_count; i++) {
625
626 int32 Id= Info->values[i].id;
627 uint8 Reg = (Id >> regShift) & 0xFF;
628
629 if ((Reg & 0x01) || Reg > 0x7e) {
630 ERROR("Invalid AC97 register:%#04x.Bypass it.\n", Reg);
631 continue;
632 }
633
634 uint16 RegValue = ac97_reg_cached_read(fAC97Dev, Reg);
635
636 if ((Id & MIX_Check) == MIX_Check) {
637 uint16 mask = 1 << ((Id >> baseShift) & 0xff);
638 Info->values[i].enable = (RegValue & mask) == mask;
639 TRACE("%#04x Mute|Enable|Boost:%d [data:%#04x]\n",
640 Reg, Info->values[i].enable, RegValue);
641 continue;
642 }
643
644 if ((Id & MIX_MUX) == MIX_MUX) {
645 Info->values[i].mux = (RegValue | (RegValue >> 8)) & 0x7;
646 TRACE("%#04x MUX:%d [data:%#04x]\n",
647 Reg, Info->values[i].mux, RegValue);
648 continue;
649 }
650
651 float mult = 0.1 * (int8)(Id >> stepShift);
652 float base = mult * ((Id >> baseShift) & 0xff);
653
654 if ((Id & MIX_RGain) == MIX_RGain) {
655 uint8 gain = RegValue & 0x3f;
656 Info->values[i].gain = mult * gain - base;
657 TRACE("%#04x for RGain:%f [mult:%f base:%f] <- %#04x\n",
658 Reg, Info->values[i].gain, mult, base, gain);
659 continue;
660 }
661
662 if ((Id & MIX_LGain) == MIX_LGain) {
663 uint8 gain = (RegValue >> 8) & 0x3f;
664 Info->values[i].gain = mult * gain - base;
665 TRACE("%#04x for LGain:%f [mult:%f base:%f] <- %#04x\n",
666 Reg, Info->values[i].gain, mult, base, gain);
667 }
668 }
669
670 return B_OK;
671 }
672
673
674 status_t
SetMix(multi_mix_value_info * Info)675 Mixer::SetMix(multi_mix_value_info *Info)
676 {
677 for (int32 i = 0; i < Info->item_count; i++) {
678
679 int32 Id = Info->values[i].id;
680 uint8 Reg = (Id >> regShift) & 0xFF;
681
682 if ((Reg & 0x01) || Reg > 0x7e) {
683 ERROR("Invalid AC97 register:%#04x.Bypass it.\n", Reg);
684 continue;
685 }
686
687 uint16 RegValue = ac97_reg_cached_read(fAC97Dev, Reg);
688
689 if ((Id & MIX_Check) == MIX_Check) {
690 uint16 mask = 1 << ((Id >> baseShift) & 0xff);
691 if (Info->values[i].enable)
692 RegValue |= mask;
693 else
694 RegValue &= ~mask;
695 TRACE("%#04x Mute/Enable:%d -> data:%#04x\n",
696 Reg, Info->values[i].enable, RegValue);
697 }
698
699 if ((Id & MIX_MUX) == MIX_MUX) {
700 uint8 mux = Info->values[i].mux & 0x7;
701 RegValue = mux | (mux << 8);
702 TRACE("%#04x MUX:%d -> data:%#04x\n",
703 Reg, Info->values[i].mux, RegValue);
704 }
705
706 float mult = 0.1 * (int8)(Id >> stepShift);
707 float base = mult * ((Id >> baseShift) & 0xff);
708
709 float gain = (Info->values[i].gain + base) / mult;
710 gain += (gain > 0.) ? 0.5 : -0.5;
711 uint8 gainValue = (uint8)gain;
712
713 if ((Id & MIX_RGain) == MIX_RGain) {
714 RegValue &= 0xffc0;
715 RegValue |= gainValue;
716
717 TRACE("%#04x for RGain:%f [mult:%f base:%f] -> %#04x\n",
718 Reg, Info->values[i].gain, mult, base, gainValue);
719 }
720
721 if ((Id & MIX_LGain) == MIX_LGain) {
722 RegValue &= 0xc0ff;
723 RegValue |= (gainValue << 8);
724 TRACE("%#04x for LGain:%f [mult:%f base:%f] -> %#04x\n",
725 Reg, Info->values[i].gain, mult, base, gainValue);
726 }
727
728 TRACE("%#04x Write:%#06x\n", Reg, RegValue);
729
730 ac97_reg_cached_write(fAC97Dev, Reg, RegValue);
731 }
732
733 return B_OK;
734 }
735
736