⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmdevsample.c

📁 此代码为WCE5.0下电源管理的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// 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.
//
/*++


Module Name:

    pmdevsample.c

Abstract:

    Sample power managed device driver.

Notes:

	This device driver doesn't talk to any actual devices.  It is intended
	to provide a simple example of how to write a real power managed driver.

	PDX --> Power-managed Device Example

Revision History:

--*/

#include <windows.h>
#include <devload.h>
#include <pm.h>
#include <nkintr.h>

#ifndef DEBUG
#define	DEBUG				// always turn on debug output
#endif	// DEBUG

#ifdef DEBUG

#define	DEBUGMASK(bit)		(1 << (bit))

#define	MASK_ERROR			DEBUGMASK(0)
#define	MASK_WARN			DEBUGMASK(1)
#define	MASK_INIT			DEBUGMASK(2)
#define	MASK_FUNCTION		DEBUGMASK(3)
#define	MASK_IOCTL			DEBUGMASK(4)
#define	MASK_DEVICE			DEBUGMASK(5)
#define	MASK_ACTIVITY		DEBUGMASK(6)

DBGPARAM dpCurSettings = {
    _T("PMSampleDev"), 
	{
		_T("Errors"), _T("Warnings"), _T("Init"), _T("Function"), 
		_T("Ioctl"), _T("Device"), _T("Activity"), _T(""),
		_T(""),_T(""),_T(""),_T(""),
		_T(""),_T(""),_T(""),_T("") 
	},
    MASK_ERROR | MASK_WARN | MASK_INIT | MASK_IOCTL | MASK_DEVICE
}; 

#define	ZONE_ERROR			DEBUGZONE(0)
#define	ZONE_WARN			DEBUGZONE(1)
#define	ZONE_INIT			DEBUGZONE(2)
#define	ZONE_FUNCTION		DEBUGZONE(3)
#define	ZONE_IOCTL			DEBUGZONE(4)
#define	ZONE_DEVICE			DEBUGZONE(5)
#define	ZONE_ACTIVITY		DEBUGZONE(6)

#endif

// this structure keeps track of each device instance
typedef struct _DeviceState_tag {
	CRITICAL_SECTION		csDevice;		// serialize access to this device's state
	HANDLE					hevStop;		// when signaled, the device thread exits
	HANDLE					htDevice;		// device thread handle
	HANDLE					htActivity;		// activity generating thread
	TCHAR					szName[16];		// should be of the format"PDXn" (no colon)
	CEDEVICE_POWER_STATE	CurrentDx;		// current power level
	DWORD					dwInactivityTimeout;	// in ms
	DWORD					dwMaxActivityTimeout;	// in ms
	BOOL                    fBoostRequested;      // TRUE if we request a power state increase
	BOOL                    fReductionRequested;  // TRUE if we request a power state decrease
} DEVICESTATE, *PDEVICESTATE;

#define	LOCK(pd)			EnterCriticalSection(&(pd)->csDevice)
#define	UNLOCK(pd)			LeaveCriticalSection(&(pd)->csDevice)

#define	dim(x)				(sizeof(x) / sizeof(x[0]))

#define	MAXDEVICES			1

#define	SYSERRORSTRING(s)		SysErrorString((s), szErrorString, dim(szErrorString))

// global variables
DEVICESTATE gDevices[MAXDEVICES];
INT giDevices = 0;
HANDLE ghevResume = NULL;

// this routine returns a pointer to an error string for a given GetLastError() value.
// See public\common\sdk\winerror.h for error codes.
LPTSTR
SysErrorString(DWORD dwStatus, LPTSTR pszBuf, DWORD nSize)
{
	if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwStatus, 0, pszBuf, nSize, NULL) == 0) {
		_tcsncpy(pszBuf, _T("<FormatMessage() failed>"), nSize);
	}

	return pszBuf;
}


// This thread imitates a device that is somewhat intelligent about its usage patterns.
//
// During periods of inactivity, it will reduce step down its power consumption by
// one level every INACTIVITY_TIMEOUT seconds until it gets to D3 (sleep).  That is,
// it won't turn itself all the way off as a result of inactivity.  The device must notify
// the Power Manager of each self-initiated state transition; the power manager will
// not allow the change unless it fits within the boundaries set up by system power
// state configuration and requirements imposed by applications.  Although this one
// does note, some devices may choose to attempt to go into D3 or D4 automatically.
//
// When the device detects activity it will attempt to set its power level
// to the highest it supports, which is D0.
//
// To keep things interesting, let's assume that this driver doesn't support D3.  Requests
// to go to D3 will actually turn the device off (D4).
DWORD WINAPI 
DeviceThreadProc(PVOID pvParam)
{
	PDEVICESTATE pds = (PDEVICESTATE) pvParam;
	TCHAR szBuf[128], szErrorString[256];
	HANDLE hevActivity, hev[3];
	BOOL fDone = FALSE;
	DWORD dwTimeout;
	LPTSTR pszFname = _T("DeviceThreadProc");

	UNREFERENCED_PARAMETER(szErrorString[0]);

	// create an event that indicates something is happening with our device.  This
	// might normally be an interrupt event, and this thread might be our IST.  This
	// sample program relies on the user to set this event manually.  Note that a
	// real IST can't call WaitForMultipleObjects() on an interrupt event; we do it
	// here to make the code easier to read.
	_stprintf(szBuf, _T("PmDevSampleActivityEvent_%s"), pds->szName);
	szBuf[_tcslen(szBuf) - 1] = 0;		// remove the trailing colon
	hevActivity = CreateEvent(NULL, FALSE, FALSE, szBuf);
	if(hevActivity == NULL) {
		DEBUGMSG(ZONE_ERROR, (_T("%s: CreateEvent('%s') failed %d\r\n"), pszFname, szBuf, GetLastError()));
		return 1;
	}
	DEBUGMSG(ZONE_DEVICE, (_T("%s(%x): activity event name is '%s'\r\n"), pszFname, pds, szBuf));

	// wait until we're told to exit or until something happens
	hev[0] = hevActivity;
	hev[1] = pds->hevStop;
	hev[2] = ghevResume;
	dwTimeout = pds->dwInactivityTimeout;
	_stprintf(szBuf, _T("DeviceThreadProc(%08x)"), pds);
	pszFname = szBuf;
	DEBUGMSG(ZONE_DEVICE, (_T("%s: entering device loop, device name is '%s'\r\n"), pszFname, pds->szName));
	while(!fDone) {
		DWORD dwStatus = WaitForMultipleObjects(dim(hev), hev, FALSE, dwTimeout);
		switch(dwStatus) {
		case WAIT_TIMEOUT:
			LOCK(pds);

#if 0
			// if we're "off" don't display a timeout message
			if(pds->CurrentDx != D4) {
#endif 
				DEBUGMSG(ZONE_DEVICE, (_T("%s: inactivity timeout, Dx is %d, fBoost %d, fReduction %d\r\n"), 
				    pszFname, pds->CurrentDx, pds->fBoostRequested, pds->fReductionRequested));
#if 0
			}
#endif

			// we don't want to automatically go all the way off (D4), or to "sleep" (D3), but in other cases 
			// step down our power consumption one level
			if(pds->fReductionRequested == FALSE && pds->CurrentDx < D2) {
				CEDEVICE_POWER_STATE NewDx = (CEDEVICE_POWER_STATE) ((DWORD) pds->CurrentDx + 1);
				pds->fReductionRequested = TRUE;
				dwStatus = DevicePowerNotify(pds->szName, NewDx, POWER_NAME);
				if(dwStatus != ERROR_SUCCESS) {
					DEBUGMSG(ZONE_DEVICE | ZONE_WARN, (_T("%s: DevicePowerNotify(%u) failed %d ('%s')\r\n"), pszFname, NewDx,
						dwStatus, SYSERRORSTRING(dwStatus)));
				}
			}

			// don't need to maintain an inactivity timeout if we've gotten to our lowest power state
			if(pds->CurrentDx >= D2) {
			    dwTimeout = INFINITE;
			}

			UNLOCK(pds);
			break;
		case (WAIT_OBJECT_0 + 0):
			LOCK(pds);
			DEBUGMSG(ZONE_DEVICE, (_T("%s: device activity, Dx is %d, fBoost %d, fReduction %d\r\n"), 
			    pszFname, pds->CurrentDx, pds->fBoostRequested, pds->fReductionRequested));

			// are we at our top activity level?
			if(pds->fBoostRequested == FALSE && pds->CurrentDx != D0) {
				// no, try to go to D0
				pds->fBoostRequested = TRUE;
				dwStatus = DevicePowerNotify(pds->szName, D0, POWER_NAME);
				if(dwStatus != ERROR_SUCCESS) {
					DEBUGMSG(ZONE_DEVICE | ZONE_WARN, (_T("%s: DevicePowerNotify(D0) failed %d ('%s')\r\n"), pszFname,
						dwStatus, SYSERRORSTRING(dwStatus)));
				}
			}
			dwTimeout = pds->dwInactivityTimeout;

			UNLOCK(pds);
			break;
		case (WAIT_OBJECT_0 + 1):
			DEBUGMSG(ZONE_DEVICE, (_T("%s: stop event set, exiting...\r\n"), pszFname));
			fDone = TRUE;
			break;
		case (WAIT_OBJECT_0 + 2):
			DEBUGMSG(ZONE_DEVICE, (_T("%s: system resuming\r\n"), pszFname));
			break;
		default:
			DEBUGMSG(ZONE_ERROR, (_T("%s: WaitForMultipleObjects() returned %u, error %u\r\n"), pszFname, dwStatus, GetLastError()));
			fDone = TRUE;
			break;
		}
	}

	// release resources
	CloseHandle(hevActivity);
	DEBUGMSG(ZONE_DEVICE, (_T("%s: all done\r\n"), pszFname));
	return 0;
}

// This thread waits a random amount of time before simulating device activity by setting
// the sample device's activity event.  However, if the device is in D4 this thread stops
// simulating activity.
DWORD WINAPI 
ActivityThreadProc(PVOID pvParam)
{
	PDEVICESTATE pds = (PDEVICESTATE) pvParam;
	TCHAR szBuf[128];
	HANDLE hevActivity;
	BOOL fDone = FALSE;
	DWORD dwTimeout, dwStatus;
	LPTSTR pszFname = _T("ActivityThreadProc");

	// open the device activity event
	_stprintf(szBuf, _T("PmDevSampleActivityEvent_%s"), pds->szName);
	szBuf[_tcslen(szBuf) - 1] = 0;		// remove the trailing colon
	hevActivity = CreateEvent(NULL, FALSE, FALSE, szBuf);
	if(hevActivity == NULL) {
		DEBUGMSG(ZONE_ERROR, (_T("%s: CreateEvent('%s') failed %d\r\n"), pszFname, szBuf, GetLastError()));
		return 1;
	}

	// wait until we're told to exit or until something happens
	_stprintf(szBuf, _T("ActivityThreadProc(%08x)"), pds);
	pszFname = szBuf;
	DEBUGMSG(ZONE_ACTIVITY | ZONE_DEVICE, (_T("%s: entering device loop, device name is '%s'\r\n"), pszFname, pds->szName));
	while(!fDone) {
		if(pds->dwMaxActivityTimeout == INFINITE) {
			dwTimeout = INFINITE;
		} else {
			dwTimeout = Random() % pds->dwMaxActivityTimeout;
		}
		DEBUGMSG(ZONE_ACTIVITY, (_T("%s: timeout %u ms\r\n"), pszFname, dwTimeout));
		dwStatus = WaitForSingleObject(pds->hevStop, dwTimeout);
		switch(dwStatus) {
		case WAIT_TIMEOUT:
			LOCK(pds);
			if(pds->CurrentDx != D4) {
				DEBUGMSG(ZONE_ACTIVITY, (_T("%s: generating activity\r\n"), pszFname));
				SetEvent(hevActivity);
			}
			UNLOCK(pds);
			break;
		case WAIT_OBJECT_0:
			DEBUGMSG(ZONE_ACTIVITY, (_T("%s: stop event set, exiting...\r\n"), pszFname));
			fDone = TRUE;
			break;
		default:
			DEBUGMSG(ZONE_ERROR, (_T("%s: WaitForSingleObject() returned %u, error %u\r\n"), pszFname, dwStatus, GetLastError()));
			fDone = TRUE;
			break;
		}
	}

	// release resources
	CloseHandle(hevActivity);
	DEBUGMSG(ZONE_ACTIVITY, (_T("%s: all done\r\n"), pszFname));
	return 0;
}

DWORD
PDX_Init(
    PVOID Context
    )
{
	DWORD dwIndex, dwStatus, dwType, dwSize;
	DWORD dwHandle = 0;
	HKEY hkDevice;
	TCHAR szName[16];

    UNREFERENCED_PARAMETER(Context);

    DEBUGMSG(ZONE_INIT, (_T("PDX_Init: context %s\n"), Context));

	// get our activation information
	dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) Context, 0, 0, &hkDevice);
	if(dwStatus != ERROR_SUCCESS) {
		DEBUGMSG(ZONE_ERROR, (_T("PDX_Init: OpenDeviceKey('%s') failed %u\r\n"), Context, dwStatus));
		return 0;
	}
	dwSize = sizeof(szName);
	dwStatus = RegQueryValueEx(hkDevice, DEVLOAD_DEVNAME_VALNAME, NULL, &dwType, (LPBYTE) szName, &dwSize);
	if(dwStatus != ERROR_SUCCESS || dwType != DEVLOAD_DEVNAME_VALTYPE) {
		DEBUGMSG(ZONE_ERROR, (_T("PDX_Init: RegQueryValueEx('%s', '%s') failed %u\r\n"),
			Context, DEVLOAD_DEVNAME_VALNAME, dwStatus));
		RegCloseKey(hkDevice);
		return 0;
	}
	DEBUGMSG(ZONE_INIT, (_T("PDX_Init: device name is '%s'\r\n"), szName));
	RegCloseKey(hkDevice);

	// look for a free device instance
	for(dwIndex = 0; dwIndex < dim(gDevices) && dwHandle == 0; dwIndex++) {
		PDEVICESTATE pds = &gDevices[dwIndex];
		if(pds->htDevice == NULL) {
			// initialize this device instance
			InitializeCriticalSection(&pds->csDevice);
			_tcsncpy(pds->szName, szName, dim(pds->szName));
			pds->dwInactivityTimeout = 2000;
			pds->dwMaxActivityTimeout = 15000;

			// override defaults with registry settings, if present
			hkDevice = OpenDeviceKey(Context);
			if(hkDevice != NULL) {
				DWORD dwVal;

				// inactivity timeout
				dwSize = sizeof(dwVal);
				dwStatus = RegQueryValueEx(hkDevice, _T("InactivityTimeout"), NULL, &dwType, (LPBYTE) &dwVal, &dwSize);
				if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) {
					pds->dwInactivityTimeout = dwVal;
				}

				// activity generation timeout
				dwSize = sizeof(dwVal);
				dwStatus = RegQueryValueEx(hkDevice, _T("MaxActivityTimeout"), NULL, &dwType, (LPBYTE) &dwVal, &dwSize);
				if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) {
					pds->dwMaxActivityTimeout = dwVal;
				}

				RegCloseKey(hkDevice);
			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -