📄 cx5530audio.cpp
字号:
// CX5530Audio.cpp: implementation of the CCX5530Audio class.
//
//////////////////////////////////////////////////////////////////////
#include "includes.h"
#include <nkintr.h>
#include <pc_pnp.h>
#include <dsdriver.h>
#include "globals.h"
#include "mixhw.h"
#include "hardware.h"
#include "DMAChannel.h"
#include "HardwareBuffer.h"
#include "DsDriverBuffer.h"
#include "DsCaptureDriverBuffer.h"
#include "AC97CODEC.h"
#include "CX5530Audio.h"
extern "C" unsigned short __cdecl _outpw(unsigned short, unsigned short);
// a couple of mixer driver defines (for SetVolumePan)
DWORD SetMixerVolume(PDRIVER_CONTEXT pDriverContext, DWORD dwId, DWORD dwLeft, DWORD dwRight );
typedef enum
{
PCM_TYPE_M8,
PCM_TYPE_M16,
PCM_TYPE_S8,
PCM_TYPE_S16
} PCM_TYPE, *PPCM_TYPE;
CCX5530Audio* CCX5530Audio::m_pSingleObject= NULL;
DWORD WINAPI InterruptThreadHelper(PVOID lpParm)
{
FUNCMSG("+InterruptThreadHelper");
((CCX5530Audio*)lpParm)->InterruptThreadRoutine();
return FALSE;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCX5530Audio::CCX5530Audio():
m_pCodec(NULL),
m_hInterruptThread(NULL),
m_hInterruptEvent(NULL),
m_bExiting(false),
m_pAudioRegisters(NULL),
m_dwInterrupt(0)
{
FUNCMSG("+CCX5530Audio::CCX5530Audio()");
for (UINT i = 0; i < sizeof(m_PlaybackChannels)/sizeof(m_PlaybackChannels[0]); i++)
m_PlaybackChannels[i] = NULL;
for (i = 0; i < sizeof(m_CaptureChannels)/sizeof(m_CaptureChannels[0]); i++)
m_CaptureChannels[i] = NULL;
InitializeCriticalSection(&m_csCX5530Audio);
}
CCX5530Audio::~CCX5530Audio()
{
FUNCMSG("+CCX5530Audio::~CCX5530Audio()");
CleanUpObject();
}
bool CCX5530Audio::Initialize()
{
DWORD dwThreadId;
FUNCMSG("+CCX5530Audio::Initialize()");
// get the interrupt from the registry
if (!GetRegistryConfig())
{
ERRMSG("CCX5530Audio::Initialize(): registry info not found");
return false;
}
// initialize the hardware
if (!InitAudio())
{
ERRMSG("CCX5530Audio::Initialize(): sound device error");
return false;
}
// Create and register for the interrupt
// CAUTION: on Cedar the call to InterruptInitialize(hEvent,IRQ)
// must be made before the Interrupt Service Thread (IST) calls
// WaitForSingleObject(hEvent). InterruptInitialize() will fail if the
// event is already being waited upon, and the interrupt will not be enabled.
// The solution is to call InterruptInitialize() before CreateThread(), or you can
// create the thread suspended and call ResumeThread() after InterruptInitialize().
m_hInterruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hInterruptEvent)
{
ERRMSG1("Can't create interrupt event: %d!", GetLastError());
return false;
}
m_dwInterrupt = MapIrq2SysIntr(m_dwInterrupt);
INFMSG1("Mapped Interrupt is %d", m_dwInterrupt);
if (!InterruptInitialize(m_dwInterrupt, m_hInterruptEvent, NULL, 0))
{
ERRMSG1("Can't initialize interrupt: %d!", GetLastError());
return false;
}
m_hInterruptThread = CreateThread(NULL, 0, InterruptThreadHelper, this, 0, &dwThreadId);
if (!m_hInterruptThread)
{
ERRMSG1("Can't create interrupt thread: %d!", GetLastError());
return false;
}
SetThreadPriority (m_hInterruptThread, THREAD_PRIORITY_HIGHEST);
InterruptDone(m_dwInterrupt);
FUNCMSG("-CCX5530Audio::Initialize()");
return true;
}
bool CCX5530Audio::InitAudio()
{
PCI_SLOT_NUMBER pciSlotNumber;
PCI_COMMON_CONFIG pciConfig;
ULONG bus;
ULONG readVal;
BYTE byHeaderType;
FUNCMSG("+CCX5530Audio::InitAudio()");
// find the card and get its memory mapped base address
if (!PciFindDevice(CYRIX_VENDOR_ID, AUDIO_DEVICE_ID, &bus, &pciSlotNumber, &pciConfig))
{
ERRMSG("Couldn't find PCI device");
return false;
}
InitVSA();
ULONG ulOffset = offsetof(PCI_COMMON_CONFIG, HeaderType);
// find out header type
HalGetBusDataByOffset(
PCIConfiguration, bus, pciSlotNumber.u.AsULONG,
&byHeaderType,
ulOffset,
sizeof(UCHAR));
if (byHeaderType == 0)
ulOffset = offsetof(PCI_COMMON_CONFIG, u.type0.BaseAddresses);
else
ulOffset = offsetof(PCI_COMMON_CONFIG, u.type1.BaseAddresses);
//---- Mem-map the audio regs.
// Mem-map of PCI audio regs (Enable 5530 audio regs memory) done by BIOS
// get the physical address where the BIOS mapped the audio registers
HalGetBusDataByOffset(
PCIConfiguration,
bus,
pciSlotNumber.u.AsULONG,
&readVal,
ulOffset, // get the base address register from the PCI header structure,
sizeof(ULONG));
INFMSG2("Reading base at 0x%x, retval is 0x%x", ulOffset, readVal);
if (readVal == 0)
{
ERRMSG("Badly mapped registers!");
return false;
}
//---- Create an address window to map to the regs.
{
PHYSICAL_ADDRESS ioPhysicalBase = {readVal, 0};
ULONG inIoSpace = 0; // 0 : memory space, 1: I/O space
if (!HalTranslateBusAddress(PCIBus, bus, ioPhysicalBase, &inIoSpace, &ioPhysicalBase))
{
ERRMSG("Error translating register address");
return false;
}
if (!inIoSpace)
{
//INFMSG1("Base is 0x%8.8x, calling MmMapIoSpace", ioPhysicalBase.LowPart);
m_pAudioRegisters = (struct AudioRegisters *)MmMapIoSpace(ioPhysicalBase, 128, FALSE);
if (m_pAudioRegisters == NULL)
{
ERRMSG1("MmMapIoSpace failed: %d", GetLastError());
return false;
}
}
else
{
INFMSG("Not in IO space, direct mapping");
m_pAudioRegisters = (struct AudioRegisters *)ioPhysicalBase.LowPart;
}
}
INFMSG2("Registers physical addr 0x%8.8x, mapped at 0x%8.8x", readVal, m_pAudioRegisters);
m_pAudioRegisters->regCodecCommand.dwValue = 0; // reset codec circuitry
// identify codec
{
m_pCodec = CAC97Codec::CreateCodec(this);
if (!m_pCodec)
{
ERRMSG("Error creating codec");
return false;
}
}
// initialize codec
m_pCodec->Reset();
FUNCMSG("-CCX5530Audio::InitAudio()");
return true;
}
bool CCX5530Audio::PciFindDevice(
IN USHORT VendorId,
IN USHORT DeviceId,
OUT PULONG pBusNumber,
OUT PPCI_SLOT_NUMBER pPciSlotNumber,
OUT PPCI_COMMON_CONFIG pPciCommonConfig
)
{
PCI_SLOT_NUMBER slotNumber;
PCI_COMMON_CONFIG pciConfig;
int bus, device, function;
int length;
// FUNCMSG("+CCX5530Audio::PciFindDevice()");
for (bus = 0; bus < PCI_MAX_BUS; bus++)
{
for (device = 0; device < PCI_MAX_DEVICES; device++)
{
slotNumber.u.bits.DeviceNumber = device;
for (function = 0; function < PCI_MAX_FUNCTION; function++)
{
slotNumber.u.bits.FunctionNumber = function;
length = HalGetBusData(
PCIConfiguration,
bus,
slotNumber.u.AsULONG,
&pciConfig,
sizeof(pciConfig) - sizeof(pciConfig.DeviceSpecific));
if(length == 0)
{
// RETAILMSG(1, (TEXT("Not found %d, %d, %d\r\n"), bus, device, function));
break;
}
// RETAILMSG(1, (TEXT("PciFindDevice: VendorId: 0x%x, DeviceID: 0x%x\r\n"), pciConfig.VendorID, pciConfig.DeviceID));
if((VendorId == pciConfig.VendorID) &&
(DeviceId == pciConfig.DeviceID))
{
if (pBusNumber)
*pBusNumber = bus;
if (pPciSlotNumber)
*pPciSlotNumber = slotNumber;
if (pPciCommonConfig )
*pPciCommonConfig = pciConfig;
// FUNCMSG("-CCX5530Audio::PciFindDevice() success");
return true;
}
// Is device multifunction?
if(!function && !(pciConfig.HeaderType & PCI_MULTIFUNCTION))
{
break;
}
}
}
}
FUNCMSG("-CCX5530Audio::PciFindDevice() FAILURE");
return false;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function:
CCX5530Audio::WriteAC97
Description:
writes a 16-bit value to a register on an AC97 compliant audio codec.
Arguments:
Index - register index to write
Data - 16-bit value to write
Return Value: bool: true for success or false if CODEC timed out
-------------------------------------------------------------------*/
bool CCX5530Audio::WriteAC97(USHORT Index, USHORT Data)
{
union CodecCommand cmd;
int writeCount = CODEC_TIMEOUT_COUNT;
CriticalSectionAcquisition csa(&m_csCX5530Audio);
// wait for the codec to finish processing previous command
// loop until either we tried CODEC_TIMEOUT_COUNT times,
// or the command becomes invalid (that is, it's been sent)
while(writeCount >= 0 && m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
{
writeCount--;
Sleep(1);
}
// command still not sent?
if (m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
{
ERRMSG("Codec Not Allowing Write");
return false;
}
// set up new command
cmd.dwValue = 0;
cmd.fields.Codec = PRIMARY_CODEC; // hardwired here! This driver only handles the primary codec!
cmd.fields.Command = Data;
// the Index has 7 bits for register addresses; the eighth bit is the read flag
cmd.fields.CommandAddress = Index;
// and write it;
//INFMSG1("Writing command 0x%8.8x", cmd.dwValue);
m_pAudioRegisters->regCodecCommand.dwValue = cmd.dwValue;
// Wait for ready state, check AC CODEC access time out
writeCount = CODEC_TIMEOUT_COUNT;
while(writeCount >= 0 && m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
{
writeCount--;
Sleep(1);
}
// command still not sent?
if (m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
{
ERRMSG("Codec Timed Out On Write");
return false;
}
// all seems Ok
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -