📄 speakerheadset.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <windows.h>
#include "SpeakerHeadset.h"
#include <wdm.h> // for READ_PORT_XXXX, WRITE_PORT_XXXX
#include <Pkfuncs.h>
#include <nkintr.h>
#include <cardserv.h>
#include <devload.h>
#include <winnls.h>
#include <storemgr.h>
#include <diskio.h>
#include <s3c2410x_ioport.h>
#include <s3c2410x_base_regs.h>
#include <bsp_base_reg_cfg.h>
#include "Devnotify.h"
#include "NotifyWindowList.h"
typedef enum
{
CarKitMask = 1,
HeadsetMask = 2,
SpeakerphoneMask = 4
} DeviceMask_t;
bool fSpeakerHeadsetInitialized;
CRITICAL_SECTION SPKDeviceLock;
const wchar_t *szHardwareRegRootKey = L"System\\State\\Hardware";
struct SpeakerHeadsetDevice
{
unsigned __int8 SpeakerPhoneState;
};
static unsigned __int8 CurrentDriverState = 0;
volatile SpeakerHeadsetDevice *g_SpeakerHeadsetDevice = NULL;
NotifyWindowList g_HeadsetNotificationList;
NotifyWindowList g_SpeakerPhoneNotificationList;
NotifyWindowList g_CarkitNotificationList;
// Notify the registered clients of the change in the device state.
DWORD NotifyClientsOfStateChange(unsigned __int8 changedStateMask)
{
unsigned __int8 val = 0;
DEBUGMSG( TRUE, (TEXT("++SPK --> NotifyClientsOfStateChange ChangedMask=%d\n"), changedStateMask) );
if (changedStateMask & CarKitMask) {
val = (CurrentDriverState & CarKitMask)?1:0;
g_CarkitNotificationList.SendMessage(val);
}
if (changedStateMask & HeadsetMask) {
val = (CurrentDriverState & HeadsetMask)?1:0;
g_HeadsetNotificationList.SendMessage(val);
}
if (changedStateMask & SpeakerphoneMask) {
val = (CurrentDriverState & SpeakerphoneMask)?1:0;
g_SpeakerPhoneNotificationList.SendMessage(val);
}
DEBUGMSG( TRUE, (TEXT("--SPK --> NotifyClientsOfStateChange\n")) );
return 0;
}
DWORD UpdateRegistryValues(unsigned __int8 changedValMask)
{
HKEY hHardwareKey = NULL;
DWORD val;
DWORD error = 0;
DEBUGMSG( TRUE, (TEXT("++SPK --> UpdateRegistryValues ChangedMask=%d\n"), changedValMask) );
if (ERROR_SUCCESS == (error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szHardwareRegRootKey, 0, 0, &hHardwareKey))) {
if (changedValMask & CarKitMask) {
val = CurrentDriverState & CarKitMask;
if (ERROR_SUCCESS != RegSetValueEx(hHardwareKey, L"Car Kit", 0, REG_DWORD, (const BYTE*)&val, sizeof(DWORD))) {
error = GetLastError();
}
}
if (changedValMask & HeadsetMask) {
val = (CurrentDriverState & HeadsetMask)?1:0;
if (ERROR_SUCCESS != RegSetValueEx(hHardwareKey, L"Headset", 0, REG_DWORD, (const BYTE*)&val, sizeof(DWORD))) {
error = GetLastError();
}
}
if (changedValMask & SpeakerphoneMask) {
val = (CurrentDriverState & SpeakerphoneMask)?1:0;
if (ERROR_SUCCESS != RegSetValueEx(hHardwareKey, L"Speaker", 0, REG_DWORD, (const BYTE*)&val, sizeof(DWORD))) {
error = GetLastError();
}
}
RegCloseKey(hHardwareKey);
} else {
error = GetLastError();
}
DEBUGMSG( TRUE, (TEXT("--SPK --> UpdateRegistryValues %d\n"), error) );
return error;
}
/******************************************
This function reads the current state of the
device and verifies with the stored state, if
a difference is there in stored state and current
state, the device status is updated and a
notification is sent to all the registered
window handles. Please make sure that you take lock
as this modifies the datastructures.
**********************************************/
DWORD ProcessMaskChange()
{
DWORD error = 0;
unsigned __int8 deviceState = 0;
unsigned __int8 changedMask = 0;
DEBUGMSG( TRUE, (TEXT("++SPK --> ProcessMaskChange\n")) );
// Really shouldn't happen.
if (g_SpeakerHeadsetDevice == NULL) {
error = ERROR_INVALID_HANDLE;
goto Done;
}
// Read the current value of device state.
deviceState = g_SpeakerHeadsetDevice->SpeakerPhoneState;
// Check if device state and driver state are different.
if (deviceState != CurrentDriverState) {
changedMask = deviceState ^ CurrentDriverState;
CurrentDriverState = deviceState;
error = NotifyClientsOfStateChange(changedMask);
error = UpdateRegistryValues(changedMask);
}
Done:
DEBUGMSG( TRUE, (TEXT("--SPK --> ProcessMaskChange Error=%d\n"), error) );
return error;
}
/************************************************
This is just a wrapper over ProcessMaskChange but
takes a lock. This is called from EmulServ device.
*************************************************/
void ProcessSPKMaskChange()
{
if (fSpeakerHeadsetInitialized) {
EnterCriticalSection(&SPKDeviceLock);
ProcessMaskChange();
LeaveCriticalSection(&SPKDeviceLock);
}
}
BOOL SetSpeakerPhoneMode(unsigned __int8 newSpeakerMode)
{
BOOL success = TRUE;
unsigned __int8 maskVal;
// wparam should be 1 or 0. Any other value is taken as invalid parameter.
if (newSpeakerMode != 1 && newSpeakerMode != 0) {
SetLastError(ERROR_INVALID_PARAMETER);
success = FALSE;
} else {
if (newSpeakerMode) {
maskVal = SpeakerphoneMask;
} else {
maskVal = 0;
}
// Write the value into the device.
// Any other value written other than this mask will be taken as invalid and emulator will terminate.
g_SpeakerHeadsetDevice->SpeakerPhoneState = maskVal;
// Read the state from device.
CurrentDriverState = g_SpeakerHeadsetDevice->SpeakerPhoneState;
success = g_SpeakerPhoneNotificationList.SendMessage(newSpeakerMode);
UpdateRegistryValues(maskVal);
}
return success;
}
extern "C" DWORD SPK_Init(LPCTSTR pContext, DWORD dwBusContext)
{
DWORD error = 0;
DEBUGMSG( TRUE, (TEXT("++SPK_Init\n")) );
InitializeCriticalSection(&SPKDeviceLock);
// Really should not happen. But if happens then just return the same, device context.
ASSERT(NULL == g_SpeakerHeadsetDevice);
if (NULL != g_SpeakerHeadsetDevice) {
goto Done;
}
EnterCriticalSection(&SPKDeviceLock);
// Reset the driver state.
CurrentDriverState = 0;
g_HeadsetNotificationList.ResetRecordList();
g_SpeakerPhoneNotificationList.ResetRecordList();
g_CarkitNotificationList.ResetRecordList();
// Map the virtual address to physical address.
g_SpeakerHeadsetDevice = (volatile SpeakerHeadsetDevice*)VirtualAlloc(NULL, 0x02, MEM_RESERVE, PAGE_NOACCESS);
if (NULL == g_SpeakerHeadsetDevice) {
error = GetLastError();
goto Done;
}
// Map the entire page. Virtual copy needs page aligned address.
PVOID ppvSPKPhysical = (PVOID)((BSP_BASE_REG_PA_SPKHEADSET & ~0xfff) >> 8);
if (!VirtualCopy((LPVOID)g_SpeakerHeadsetDevice, ppvSPKPhysical, 0x1000, PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)) {
error = GetLastError();
goto Done;
}
// Now go to the actual address of the device.
g_SpeakerHeadsetDevice = (volatile SpeakerHeadsetDevice*)((size_t)g_SpeakerHeadsetDevice + (BSP_BASE_REG_PA_SPKHEADSET & 0xfff));
// Carry out the initialization.
error = ProcessMaskChange();
Done:
LeaveCriticalSection(&SPKDeviceLock);
if (error == 0) {
fSpeakerHeadsetInitialized = true;
}
DEBUGMSG( TRUE, (TEXT("--SPK_Init Error=%d\n"), error) );
return (DWORD)g_SpeakerHeadsetDevice;
}
extern "C" BOOL SPK_Deinit(DWORD hDeviceContext)
{
BOOL success = FALSE;
DEBUGMSG( TRUE, (TEXT("++SPK_Deinit\n")) );
EnterCriticalSection(&SPKDeviceLock);
// Really wondering if the mapping will be freed correctly, because i added the offset.
if (NULL != g_SpeakerHeadsetDevice) {
success = VirtualFree ((LPVOID)g_SpeakerHeadsetDevice, 0, MEM_RELEASE);
g_SpeakerHeadsetDevice = NULL;
}
// Reset the driver state.
CurrentDriverState = 0;
g_HeadsetNotificationList.ResetRecordList();
g_SpeakerPhoneNotificationList.ResetRecordList();
g_CarkitNotificationList.ResetRecordList();
LeaveCriticalSection(&SPKDeviceLock);
fSpeakerHeadsetInitialized = false;
DeleteCriticalSection(&SPKDeviceLock);
DEBUGMSG( TRUE, (TEXT("--SPK_Deinit\n")) );
return success;
}
extern "C" void SPK_PowerUp(DWORD hDeviceContext)
{
DEBUGMSG( TRUE, (TEXT("++SPK_PowerUp\n")) );
EnterCriticalSection(&SPKDeviceLock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -