📄 wavepdd.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#define ZONE_WPDD 0
//
// Module Name:
//
// wavepdd.c
//
// Abstract:
// The PDD (Platform Dependent Driver) is responsible for
// communicating with the audio circuit to start and stop playback
// and/or recording and initialize and deinitialize the circuits.
//
// Functions:
// PDD_AudioGetInterruptType
// PDD_AudioMessage
// PDD_AudioInitialize
// PDD_AudioDeinitialize
// PDD_AudioPowerHandler
// PDD_WaveProc
//
// Notes:
//
// -----------------------------------------------------------------------------
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <excpt.h>
#include <nkintr.h>
#include <ceddk.h>
#include <cardserv.h>
#include <devload.h>
#include <ddkreg.h>
#include <giisr.h>
#include <wavedbg.h>
#include <waveddsi.h>
#include "es1371.h"
#define ZONE_VOLUME 0
// Globals
typedef VOID (* PFNDMATRANSFER) (PWAVEHDR pwh, PBYTE pBuffer, ULONG cbBytes);
DWORD g_dwBusNumber;
INTERFACE_TYPE g_IfcType;
struct _global_volume
{
ULONG dwMasterVolume;
ULONG dwLineInVolume;
ULONG dwMicVolume;
BOOL fMasterMute;
BOOL fLineInMute;
BOOL fMicMute;
ULONG dwInputSelect;
} g_VolumeSettings;
CES1371* pCES1371;
const ULONG dma_buffer_size = 4096;
BOOL g_fInUse[2];
PBYTE g_dma_buffer[2];
PHYSICAL_ADDRESS g_dma_logical_address[2];
ULONG g_dmapos[2]; // last known DMA position for the stream
UCHAR g_dmachannel[2]; // ES1371_DAC0 or ES1371_ADC
PWAVEFORMATEX g_pwfx[2];
UCHAR g_silence;
PFNDMATRANSFER g_pfnDmaTransfer[2];
HANDLE g_IsrHandle = NULL;
VOID private_AudioGetBuffer (PWAVEHDR pwh, PBYTE pSrcBuffer, ULONG cbSrcBytes);
VOID private_AudioCompleteAndFill (PWAVEHDR pwh, PBYTE pDstBuffer, ULONG cbDstBytes);
// Volume Linear to Log Lookup table
// aproximates to roughly 2 db's per increment
UCHAR volumeLUT[] = {
0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x2,
0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x5,
0x6,0x6,0x7,0x8,0x9,0x9,0xA,0xB,
0xC,0xE,0xF,0x11,0x13,0x15,0x19,0x1F};
// -----------------------------------------------------------------------------
//
// Function to get the SysIntr and I/O port range from the registry
//
// NOTE: lpRegPath is assumed to be under HKEY_LOCAL_MACHINE
//
// Returns ERROR_SUCCESS on success or a Win32 error code on failure
//
// -----------------------------------------------------------------------------
DWORD
GetRegistryConfig(
LPWSTR lpRegPath,
DWORD * lpdwSysIntr,
DWORD * lpdwIoBase,
DWORD * lpdwIoLen,
DWORD * lpdwDeviceID,
DWORD * lpdwRevisionID,
BOOL * bInstallIsr, // OUT - TRUE if ISR Handler found in registry
LPWSTR IsrDll, // OUT - Name of ISR Handler dll
LPWSTR IsrHandler, // OUT - Name of ISR Handler routine
DWORD * Irq, // OUT - IRQ number, used to hook ISR handler
DWORD *lpdwBusNumber,
PINTERFACE_TYPE pIfcType
)
{
HKEY hConfig = NULL;
DWORD dwRet = ERROR_SUCCESS;
DDKISRINFO dii;
DDKWINDOWINFO dwi;
DDKPCIINFO dpi;
*bInstallIsr = FALSE;
*Irq = -1;
// get a pointer to our configuration key in the registry
hConfig = OpenDeviceKey(lpRegPath);
if(hConfig == NULL) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: OpenDeviceKey('%s') failed\r\n"), lpRegPath));
dwRet = ERROR_BADKEY;
goto EXIT;
}
// read window configuration from the registry
dwi.cbSize = sizeof(dwi);
dwRet = DDKReg_GetWindowInfo(hConfig, &dwi);
if(dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: DDKReg_GetWindowInfo() failed %d\r\n"), dwRet));
goto EXIT;
} else if(dwi.dwNumIoWindows != 1) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: %d windows configured, expected 1\r\n"), dwi.dwNumIoWindows));
dwRet = ERROR_INVALID_DATA;
goto EXIT;
} else {
*lpdwIoBase = dwi.ioWindows[0].dwBase;
*lpdwIoLen = dwi.ioWindows[0].dwLen;
*lpdwBusNumber = dwi.dwBusNumber;
*pIfcType = (INTERFACE_TYPE) dwi.dwInterfaceType;
}
// get ISR configuration information
dii.cbSize = sizeof(dii);
dwRet = DDKReg_GetIsrInfo(hConfig, &dii);
if(dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: DDKReg_GetIsrInfo() failed %d\r\n"), dwRet));
goto EXIT;
} else if(dii.dwSysintr == SYSINTR_NOP) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: no SYSINTR value specified\r\n")));
dwRet = ERROR_INVALID_DATA;
goto EXIT;
} else {
// get installable ISR information
if(dii.szIsrDll[0] != 0) {
if(dii.szIsrHandler[0] == 0 || dii.dwIrq == IRQ_UNSPECIFIED) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: garbled or missing installable ISR settings\r\n")));
dwRet = ERROR_INVALID_DATA;
goto EXIT;
} else {
_tcscpy(IsrDll, dii.szIsrDll);
_tcscpy(IsrHandler, dii.szIsrHandler);
*bInstallIsr = TRUE;
}
}
// was an IRQ specified?
if(dii.dwIrq != IRQ_UNSPECIFIED) {
*Irq = dii.dwIrq;
}
// pass back the sysintr
*lpdwSysIntr = dii.dwSysintr;
}
// get device ID information
dpi.cbSize = sizeof(dpi);
dwRet = DDKReg_GetPciInfo(hConfig, &dpi);
if(dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: DDKReg_GetPciInfo() failed %d\r\n"), dwRet));
goto EXIT;
} else if((dpi.dwWhichIds & (PCIIDM_DEVICEID | PCIIDM_REVISIONID)) != (PCIIDM_DEVICEID | PCIIDM_REVISIONID)) {
DEBUGMSG(ZONE_PDD, (_T("WAVEDEV: missing device or revision ID\r\n")));
dwRet = ERROR_INVALID_DATA;
goto EXIT;
} else {
*lpdwDeviceID = dpi.idVals[PCIID_DEVICEID];
*lpdwRevisionID = dpi.idVals[PCIID_REVISIONID];
}
EXIT:
if (hConfig != NULL) {
RegCloseKey(hConfig);
}
return dwRet;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
MMRESULT
private_WaveGetDevCaps(
WAPI_INOUT apidir,
PVOID pCaps,
UINT wSize
)
{
PWAVEINCAPS pwic = (PWAVEINCAPS)pCaps;
PWAVEOUTCAPS pwoc = (PWAVEOUTCAPS)pCaps;
MMRESULT mmRet = MMSYSERR_NOERROR;
FUNC_WPDD("+PDD_WaveGetDevCaps");
if (pCaps == NULL) {
//
// If pCaps == NULL, we are requesting if the driver PDD is capable of
// this mode at all. In other words, if APIDIR == WAPI_IN, we return
// no error if input is supported, and MMSYSERR_NOTSUPPORTED otherwise.
// Since Odo has both, we return MMSYSERR_NOERROR regardless.
//
return MMSYSERR_NOERROR;
}
//
// Fill in the DevCaps here.
//
pwoc->wMid = MM_MICROSOFT;
pwoc->wPid = (apidir == WAPI_OUT ? 24 : 23); // generic in or out...
pwoc->vDriverVersion = 0x0001;
wsprintf (pwoc->szPname, TEXT("CE/PC Audio (%hs)"), __DATE__);
pwoc->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 |
WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 |
WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 |
WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 |
WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 |
WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16;
pwoc->wChannels = 2;
if (apidir == WAPI_OUT)
{
// Caution: the WAVEINCAPS structure doesn't have a dwSupport field. Touch here and die!
pwoc->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
}
FUNC_WPDD("-PDD_WaveGetDevCaps");
return mmRet;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_AudioFillBuffer (PWAVEHDR pwh, PBYTE pDstBuffer, ULONG cbDstBytes)
{
DEBUGMSG(ZONE_WPDD, (TEXT("WPDD: FillBuffer (%08x,%5d,%08x,%5d)\r\n"), pwh, pwh->reserved, pDstBuffer, cbDstBytes));
while ((pwh != NULL) && (cbDstBytes > 0)) {
if (pwh->reserved >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
}
else {
// trasfer min(data_in_dma, room_in_buffer)
ULONG cbSrcBytes = pwh->dwBufferLength - pwh->reserved;
ULONG cbBytesTransferred = min(cbSrcBytes, cbDstBytes);
DEBUGMSG(ZONE_WPDD, (TEXT("WPDD: memcpy (%08x,%5d,%08x,%5d)\r\n"), pwh, pwh->reserved, pDstBuffer, cbBytesTransferred));
memcpy(pDstBuffer, pwh->lpData + pwh->reserved, cbBytesTransferred);
pwh->reserved += cbBytesTransferred;
pDstBuffer += cbBytesTransferred;
cbDstBytes -= cbBytesTransferred;
}
}
// Nothing left to copy, so clear the remainder of the buffer with silence
DEBUGMSG(ZONE_WPDD, (TEXT("WPDD: memset (%08x,%5d,%08x,%5d)\r\n"), pwh, pwh?pwh->reserved:0, pDstBuffer, cbDstBytes));
memset(pDstBuffer, g_silence, cbDstBytes);
}
VOID
private_AudioComplete(PWAVEHDR pwh, ULONG cbBytesCompleted)
{
DEBUGMSG(ZONE_WPDD, (TEXT("WPDD: AudioAdvance (%08x,%5d)\r\n"), pwh, cbBytesCompleted));
// we've just finished playing another cbDstBytes of data.
// update the queued headers accordingly
while ((pwh != NULL) && (cbBytesCompleted > 0)) {
if (pwh->dwBytesRecorded >= pwh->reserved) {
pwh = pwh->lpNext;
}
else {
ULONG cbBytesLeft = pwh->reserved - pwh->dwBytesRecorded;
ULONG cbAdvance = min(cbBytesCompleted, cbBytesLeft);
cbBytesCompleted -= cbAdvance;
pwh->dwBytesRecorded += cbAdvance;
DEBUGMSG(ZONE_WPDD, (TEXT("WPDD: Advance (%08x,%5d,%5d,%5d)\r\n"), pwh, cbAdvance, cbBytesCompleted));
}
}
}
//------------------------------------------------------------
// private_AudioCompleteAndFill:
// called after an interrupt has informed us that cbDstBytes
// have just finished playing and can be replaced with fresh data
// from the cued data starting at pwh+latency
//
//------------------------------------------------------------
VOID
private_AudioCompleteAndFill (PWAVEHDR pwh, PBYTE pDstBuffer, ULONG cbDstBytes)
{
// update the queued headers to indicate which ones we've played out
private_AudioComplete(pwh, cbDstBytes);
//
// Fill the DMA Buffer and clear the remainder if nessary
//
private_AudioFillBuffer (pwh, pDstBuffer, cbDstBytes);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_AudioGetBuffer (PWAVEHDR pwh, PBYTE pSrcBuffer, ULONG cbSrcBytes)
{
FUNC_VERBOSE("+PDD_AudioGetBuffer");
//
// Copy from the DMA buffer to the client buffer
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -