1) Improved detecting and handling AC97 VRA possibilites. Thanks to Maxim for testing;

2) Functionality of the handling the rate for AC97 Front PCM DAC added.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40327 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Siarzhuk Zharski
2011-01-30 19:59:30 +00:00
parent 38bda6536f
commit a4f1824882
7 changed files with 65 additions and 11 deletions
@@ -175,7 +175,6 @@ Device::Open(uint32 flags)
ERROR("Error of starting playback stream:%#010x\n", status); ERROR("Error of starting playback stream:%#010x\n", status);
} }
return B_OK; return B_OK;
} }
@@ -57,6 +57,8 @@ public:
static int32 InterruptHandler(void *interruptParam); static int32 InterruptHandler(void *interruptParam);
void SignalReadyBuffers(); void SignalReadyBuffers();
class Mixer& Mixer() { return fMixer; }
cpu_status Lock(); cpu_status Lock();
void Unlock(cpu_status st); void Unlock(cpu_status st);
@@ -90,7 +92,7 @@ private:
int32 fInterruptsNest; int32 fInterruptsNest;
sem_id fBuffersReadySem; sem_id fBuffersReadySem;
Mixer fMixer; class Mixer fMixer;
Stream fPlaybackStream; Stream fPlaybackStream;
Stream fRecordStream; Stream fRecordStream;
}; };
@@ -16,7 +16,7 @@
#define MAX_DEVICES 3 #define MAX_DEVICES 3
const char* const kVersion = "ver.2.0.0"; const char* const kVersion = "2.0.2";
extern pci_module_info *gPCI; extern pci_module_info *gPCI;
@@ -26,6 +26,7 @@ Mixer::Mixer(Device *device)
fMaskRW(1 << 15), fMaskRW(1 << 15),
fMaskRD(1 << 15), fMaskRD(1 << 15),
fMaskWD(1 << 15), fMaskWD(1 << 15),
fHasVRA(false),
fInputRates(0), fInputRates(0),
fOutputRates(0), fOutputRates(0),
fInputFormats(0), fInputFormats(0),
@@ -69,6 +70,25 @@ Mixer::Init()
void void
Mixer::_ReadSupportedFormats() Mixer::_ReadSupportedFormats()
{ {
fInputRates = B_SR_48000;
fOutputRates = 0;
fInputFormats = B_FMT_16BIT;
fOutputFormats = B_FMT_16BIT;
uint16 extId = ac97_reg_cached_read(fAC97Dev, AC97_EXTENDED_ID);
uint16 extCtrl = ac97_reg_cached_read(fAC97Dev, AC97_EXTENDED_STAT_CTRL);
TRACE("Ext.ID:%#010x %#010x\n", extId, extCtrl);
fHasVRA = ((extId & EXID_VRA) == EXID_VRA);
if (!fHasVRA) {
fOutputRates = B_SR_8000 | B_SR_11025 | B_SR_12000
| B_SR_16000 | B_SR_22050 | B_SR_24000
| B_SR_32000 | B_SR_44100 | B_SR_48000;
TRACE("VRA is not supported. Assume all rates are ok:%#010x\n",
fOutputRates);
return;
}
struct _Cap { struct _Cap {
ac97_capability fCap; ac97_capability fCap;
uint32 fRate; uint32 fRate;
@@ -89,9 +109,12 @@ Mixer::_ReadSupportedFormats()
fOutputRates |= caps[i].fRate; fOutputRates |= caps[i].fRate;
} }
fInputRates = B_SR_48000; if(fOutputRates == 0) {
fInputFormats = B_FMT_16BIT; ERROR("Output rates are not guessed. Force to 48 kHz.\n");
fOutputFormats = B_FMT_16BIT; fOutputRates = B_SR_48000;
}
TRACE("Output rates are:%#010x\n", fOutputRates);
} }
@@ -195,6 +218,28 @@ Mixer::_WriteAC97(uint8 reg, uint16 data)
} }
void
Mixer::SetOutputRate(uint32 outputRate)
{
if (!fHasVRA)
return;
uint32 rate = 0;
if (!ac97_get_rate(fAC97Dev, AC97_PCM_FRONT_DAC_RATE, &rate)) {
ERROR("Failed to read PCM Front DAC Rate. Force to %d.\n", outputRate);
} else
if (rate == outputRate) {
TRACE("AC97 PCM Front DAC rate not set to %d\n", outputRate);
return;
}
if (!ac97_set_rate(fAC97Dev, AC97_PCM_FRONT_DAC_RATE, rate))
ERROR("Failed to set AC97 PCM Front DAC rate\n");
else
TRACE("AC97 PCM Front DAC rate set to %d\n", outputRate);
}
// Control ids are encoded in the following way: // Control ids are encoded in the following way:
// GGBBRRTT -- // GGBBRRTT --
// GG - in gain controls: 10th of granularity. Signed! // GG - in gain controls: 10th of granularity. Signed!
@@ -35,6 +35,8 @@ public:
uint32 InputFormats() { return fInputFormats; } uint32 InputFormats() { return fInputFormats; }
uint32 OutputFormats() { return fOutputFormats; } uint32 OutputFormats() { return fOutputFormats; }
void SetOutputRate(uint32 rate);
private: private:
void _ReadSupportedFormats(); void _ReadSupportedFormats();
bool _WaitPortReady(uint8 reg, uint32 mask, uint32* result = NULL); bool _WaitPortReady(uint8 reg, uint32 mask, uint32* result = NULL);
@@ -57,6 +59,7 @@ static void _WriteAC97(void* cookie, uint8 reg, uint16 data);
uint32 fMaskRD; uint32 fMaskRD;
uint32 fMaskWD; uint32 fMaskWD;
bool fHasVRA;
uint32 fInputRates; uint32 fInputRates;
uint32 fOutputRates; uint32 fOutputRates;
uint32 fInputFormats; uint32 fInputFormats;
@@ -213,6 +213,9 @@ Stream::GetBuffers(uint32& Flags, int32& BuffersCount, int32& ChannelsCount,
status_t status_t
Stream::Start() Stream::Start()
{ {
if (!fIsInput)
fDevice->Mixer().SetOutputRate(fFormat.cvsr);
uint32 CSO = 0; uint32 CSO = 0;
uint32 LBA = uint32(fBuffersPhysAddress) & 0x3fffffff; uint32 LBA = uint32(fBuffersPhysAddress) & 0x3fffffff;
uint32 ESO = ((fBufferSamplesCount * 2) - 1) & 0xffff; uint32 ESO = ((fBufferSamplesCount * 2) - 1) & 0xffff;
@@ -290,6 +293,7 @@ Stream::Start()
// start current channel // start current channel
fDevice->WritePCI32(_UseBankB() ? RegStartB : RegStartA, 1 << _HWVoice()); fDevice->WritePCI32(_UseBankB() ? RegStartB : RegStartA, 1 << _HWVoice());
fIsActive = true;
fDevice->Unlock(cst); fDevice->Unlock(cst);
@@ -297,8 +301,6 @@ Stream::Start()
fIsInput ? "Rec" : "Play", CSO, LBA, ESO, Delta, FMControlEtc, fIsInput ? "Rec" : "Play", CSO, LBA, ESO, Delta, FMControlEtc,
ControlEtc, ChIntReg); ControlEtc, ChIntReg);
fIsActive = true;
return B_OK; return B_OK;
} }
@@ -306,11 +308,15 @@ Stream::Start()
status_t status_t
Stream::Stop() Stream::Stop()
{ {
if (!fIsActive)
return B_OK;
cpu_status cst = fDevice->Lock(); cpu_status cst = fDevice->Lock();
// stop current channel // stop current channel
fDevice->WritePCI32(_UseBankB() ? RegStopB : RegStopA, 1 << _HWVoice()); fDevice->WritePCI32(_UseBankB() ? RegStopB : RegStopA, 1 << _HWVoice());
fIsActive = false;
if (_HWId() == ALi5451 && fIsInput) { if (_HWId() == ALi5451 && fIsInput) {
uint32 reg = fDevice->ReadPCI32(RegALiDigiMixer); uint32 reg = fDevice->ReadPCI32(RegALiDigiMixer);
fDevice->WritePCI32(RegALiDigiMixer, reg & ~(1 << _HWVoice())); fDevice->WritePCI32(RegALiDigiMixer, reg & ~(1 << _HWVoice()));
@@ -320,8 +326,6 @@ Stream::Stop()
TRACE("%s:OK\n", fIsInput ? "Rec" : "Play"); TRACE("%s:OK\n", fIsInput ? "Rec" : "Play");
fIsActive = false;
fBufferCycle = fIsInput ? 1 : 0; fBufferCycle = fIsInput ? 1 : 0;
return B_OK; return B_OK;
@@ -35,6 +35,7 @@ public:
void ExchangeBuffers(bigtime_t& RealTime, void ExchangeBuffers(bigtime_t& RealTime,
bigtime_t& FramesCount, bigtime_t& FramesCount,
int32& BufferCycle); int32& BufferCycle);
void GetFormat(multi_format_info *Format); void GetFormat(multi_format_info *Format);
status_t SetFormat(_multi_format& format, status_t SetFormat(_multi_format& format,
uint32 formats, uint32 rates); uint32 formats, uint32 rates);