?? atapipm.cpp
字號(hào):
//
// 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.
//
#include <atamain.h>
#define dim(x) (sizeof(x) / sizeof(x[0]))
static BOOL
HexStringToDword(LPCWSTR FAR& lpsz, DWORD FAR& Value,
int cDigits, WCHAR chDelim)
{
int Count;
Value = 0;
for (Count = 0; Count < cDigits; Count++, lpsz++)
{
if (*lpsz >= '0' && *lpsz <= '9')
Value = (Value << 4) + *lpsz - '0';
else if (*lpsz >= 'A' && *lpsz <= 'F')
Value = (Value << 4) + *lpsz - 'A' + 10;
else if (*lpsz >= 'a' && *lpsz <= 'f')
Value = (Value << 4) + *lpsz - 'a' + 10;
else
return(FALSE);
}
if (chDelim != 0)
return *lpsz++ == chDelim;
else
return TRUE;
}
static BOOL
wUUIDFromString(LPCWSTR lpsz, LPGUID pguid)
{
DWORD dw;
if (!HexStringToDword(lpsz, pguid->Data1, sizeof(DWORD)*2, '-'))
return FALSE;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data2 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data3 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[0] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '-'))
return FALSE;
pguid->Data4[1] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[2] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[3] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[4] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[5] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[6] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[7] = (BYTE)dw;
return TRUE;
}
static BOOL
GUIDFromString(LPCWSTR lpsz, LPGUID pguid)
{
if (*lpsz++ != '{' )
return FALSE;
if(wUUIDFromString(lpsz, pguid) != TRUE)
return FALSE;
lpsz +=36;
if (*lpsz++ != '}' )
return FALSE;
return TRUE;
}
CDiskPower::CDiskPower(void) :
m_curDx(D0),
m_timeoutDx(D2),
m_fBoostRequested(FALSE),
m_fReductionRequested(FALSE),
m_dwPowerTimeout(1000),
m_htPower(NULL),
m_hevPowerSignal(NULL),
m_fShutdownPowerThread(FALSE),
m_PowerThreadPriority(250), // THREAD_PRIORITY_ABOVE_NORMAL
m_pDisk(NULL),
m_pszPMName(NULL),
m_UseCount(0),
m_pfnDevicePowerNotify(NULL)
{
memset(&m_dxInfo, 0, sizeof(m_dxInfo));
m_dwStartTickCount = GetTickCount();
QueryPerformanceCounter(&m_startQPC);
m_dxInfo[m_curDx].dwCount++;
InitializeCriticalSection(&m_csPower);
}
CDiskPower::~CDiskPower(void)
{
if(m_htPower) {
DEBUGCHK(m_hevPowerSignal);
m_fShutdownPowerThread = TRUE;
SignalActivity();
WaitForSingleObject(m_htPower, INFINITE);
CloseHandle(m_htPower);
}
if(m_hevPowerSignal) {
CloseHandle(m_hevPowerSignal);
}
if(m_hevDummy) {
CloseHandle(m_hevDummy);
}
if(m_pszPMName) {
LocalFree((LPWSTR) m_pszPMName); // cast to remove const
}
DeleteCriticalSection(&m_csPower);
}
// Note: the caller should own the parent disk device's critical section
void CDiskPower::TakeCS(void)
{
EnterCriticalSection(&m_csPower);
}
void CDiskPower::ReleaseCS(void)
{
LeaveCriticalSection(&m_csPower);
}
// this routine wakes the power timeout thread
void CDiskPower::SignalActivity(void)
{
DEBUGCHK(m_hevPowerSignal);
DEBUGCHK(m_htPower);
SetEvent(m_hevPowerSignal);
}
// This routine marks the disk as in use. If it is powered down,
// it spins it up and waits for it to become ready. The caller
// must hold the disk critical section.
BOOL CDiskPower::RequestDevice(void)
{
BOOL fOk = TRUE;
PREFAST_DEBUGCHK(m_pfnDevicePowerNotify != NULL);
TakeCS();
// is the disk powered up?
if(m_curDx != D0) {
// don't bother requesting from the PM if we've already asked in a previous request
DEBUGMSG(ZONE_POWER, (_T("CDiskPower::RequestDevice: device at D%d, m_fBoostRequested is %d\r\n"), m_curDx, m_fBoostRequested));
if(!m_fBoostRequested) {
// request that the PM make us available
m_fBoostRequested = TRUE;
DWORD dwStatus = m_pfnDevicePowerNotify((PVOID) m_pszPMName, D0, POWER_NAME);
if(dwStatus != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::RequestDevice: DevicePowerNotify('%s') failed %d\r\n"), m_pszPMName, dwStatus));
m_fBoostRequested = FALSE;
fOk = FALSE;
}
}
}
if(m_curDx == D0) {
// wait for the disk to spin up so that we can do I/O
DEBUGCHK(m_UseCount == 0);
m_UseCount++;
} else {
fOk = FALSE;
}
ReleaseCS();
return fOk;
}
// This API signals that the caller is done doing I/O. The caller must hold the
// parent disk's critical section.
void CDiskPower::ReleaseDevice(void)
{
PREFAST_DEBUGCHK(m_pfnDevicePowerNotify);
TakeCS();
// update the usage counter
DEBUGCHK(m_UseCount != 0);
m_UseCount--;
DEBUGCHK(m_UseCount == 0);
// wake the timeout thread to restart its countdown
SignalActivity();
if(m_fReductionRequested) {
// cancel outstanding requests to spin down the disk
DWORD dwStatus = m_pfnDevicePowerNotify((PVOID) m_pszPMName, D0, POWER_NAME);
if(dwStatus != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::DiskPowerThread: DevicePowerNotify('%s', D%d) failed %d\r\n"), m_pszPMName, D0, dwStatus));
} else {
m_fReductionRequested = FALSE;
}
}
ReleaseCS();
}
DWORD CDiskPower::DiskPowerThread(void)
{
BOOL fDone = FALSE;
DWORD dwTimeout = m_dwPowerTimeout;
HANDLE hev = m_hevPowerSignal;
PREFAST_DEBUGCHK(m_pfnDevicePowerNotify != NULL);
DEBUGCHK(m_hevPowerSignal);
DEBUGCHK(m_hevDummy);
DEBUGMSG(ZONE_INIT, (_T("CDiskPower::DiskPowerThread: starting up for '%s', timeout is %d ms\r\n"), m_pszPMName, m_dwPowerTimeout));
while(!fDone) {
//DEBUGMSG(ZONE_POWER, (_T("CDiskPower::DiskPowerThread: waiting on '%s', timeout is %u\r\n"), m_pszPMName, dwTimeout));
DWORD dwStatus = WaitForSingleObject(hev, dwTimeout);
//DEBUGMSG(ZONE_POWER, (_T("CDiskPower::DiskPowerThread: WaitForSingleObject() returned %u\r\n"), dwStatus));
switch(dwStatus) {
case WAIT_OBJECT_0:
// are we supposed to exit?
if(m_fShutdownPowerThread) {
DEBUGMSG(ZONE_INIT, (_T("CDiskPower::DiskPowerThread: shutdown event signaled\r\n")));
fDone = TRUE;
} else {
// ignore further activity until the timeout expires
TakeCS(); // Note: if you take the disk cs here, take it first
DEBUGMSG(ZONE_POWER, (_T("CDiskPower::DiskPowerThread: disk activity detected on '%s', use count is %d\r\n"), m_pszPMName, m_UseCount));
DEBUGCHK(hev != m_hevDummy);
hev = m_hevDummy;
dwTimeout = m_dwPowerTimeout;
ReleaseCS();
}
break;
case WAIT_TIMEOUT:
// inactivity timeout -- see if we should spin down the disk
m_pDisk->TakeCS();
TakeCS();
// we should be the only thread in the driver at this point
DEBUGCHK(m_UseCount == 0);
// By the time we have acquired these critical sections, we may have seen
// some disk activity from an I/O thread that held them previously. Check
// for this by polling our timeout event.
if(WaitForSingleObject(m_hevPowerSignal, 0) == WAIT_TIMEOUT) {
// don't bother asking the PM if we've already requested to spin down
DEBUGMSG(ZONE_POWER, (_T("CDiskPower::DiskPowerThread: no disk activity on '%s', m_fReductionRequested is %d\r\n"), m_pszPMName, m_fReductionRequested));
if(!m_fReductionRequested) {
// spin down the disk to m_timeoutDx
m_fReductionRequested = TRUE;
dwStatus = m_pfnDevicePowerNotify((PVOID) m_pszPMName, m_timeoutDx, POWER_NAME);
if(dwStatus != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::DiskPowerThread: DevicePowerNotify('%s', D%d) failed %d\r\n"), m_pszPMName, m_timeoutDx, dwStatus));
m_fReductionRequested = FALSE;
}
}
// no need for more timeouts until the disk spins up again
hev = m_hevPowerSignal;
dwTimeout = INFINITE;
} else {
DEBUGMSG(ZONE_POWER, (_T("CDiskPower::DiskPowerThread: activity on '%s' after timeout, device at D%d\r\n"), m_pszPMName, m_curDx));
DEBUGCHK(hev == m_hevDummy);
// if we are already at or below the spin-down disk power state we don't need
// to have a timeout. The comparison relies on the fact that D0 >= Dx >= D4.
if(m_curDx < m_timeoutDx) {
dwTimeout = m_dwPowerTimeout;
} else {
dwTimeout = INFINITE;
}
// if we are not spun up, allow disk activity to wake us up
if(m_curDx != D0) {
hev = m_hevPowerSignal;
}
}
// release resources
ReleaseCS();
m_pDisk->ReleaseCS();
break;
default:
DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::DiskPowerThread: WaitForSingleObject() returned %d, error %d\r\n"), dwStatus, GetLastError()));
break;
}
}
DEBUGMSG(ZONE_INIT, (_T("CDiskPower::DiskPowerThread: all done\r\n")));
return 0;
}
DWORD CDiskPower::DiskPowerThreadStub(LPVOID lpvParam)
{
PREFAST_DEBUGCHK(lpvParam != NULL);
CDiskPower *pDiskPower = (CDiskPower *) lpvParam;
DWORD dwStatus = pDiskPower->DiskPowerThread();
return dwStatus;
}
// This routine is called during IOCTL_POWER_CAPABILITIES processing. It
// returns TRUE if successful and FALSE if not. The caller is expected to
// destroy the CDiskPower object if this routine fails.
BOOL CDiskPower::Init(CDisk *pDiskParent)
{
DWORD dwStatus;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -