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

📄 atapipm.cpp

📁 3sc2443的CF卡IDE源代码,肯定好用.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    int nPriority = 250;    // THREAD_PRIORITY_ABOVE_NORMAL
    HANDLE hActive = NULL;
    BOOL fOk = TRUE;

    PREFAST_DEBUGCHK(pDiskParent != NULL);
    DEBUGMSG(ZONE_INIT, (_T("+CDiskPower::Init(): parent is 0x%08x\r\n"), pDiskParent));

    // record the parent device
    m_pDisk = pDiskParent;

    // get a pointer to the PM APIs we need
    if(fOk) {
        HMODULE hmCoreDll = LoadLibrary(L"coredll.dll");
        if(hmCoreDll == NULL) {
            DEBUGMSG(ZONE_INIT || ZONE_ERROR, (_T("CDevicePower::Init: LoadLibrary('coredll.dll') failed %d\r\n"), GetLastError()));
            fOk = FALSE;
        } else {
            m_pfnDevicePowerNotify = (DWORD ((*)(PVOID, CEDEVICE_POWER_STATE, DWORD))) GetProcAddress(hmCoreDll, L"DevicePowerNotify");
            if(m_pfnDevicePowerNotify == NULL) {
                DEBUGMSG(ZONE_INIT || ZONE_ERROR, (_T("CDevicePower::Init: GetProcAddress('DevicePowerNotify') failed %d\r\n"), GetLastError()));
                fOk = FALSE;
            }
            // we're explicitly linked with coredll so we don't need the handle
            FreeLibrary(hmCoreDll);
        }
    }

    // read registry configuration
    if(fOk) {
        HKEY hk;
        BOOL fGotClass = FALSE;
        WCHAR szClass[64];     // big enough for a GUID

        // determine the power class we are advertising
        dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_pDisk->m_szDeviceKey, 0, 0, &hk);
        if(dwStatus == ERROR_SUCCESS) {
            // read the PM class
            DWORD dwSize = sizeof(szClass);
            dwStatus = RegQueryValueEx(hk, L"PowerClass", NULL, NULL, (LPBYTE) szClass, &dwSize);
            if(dwStatus == ERROR_SUCCESS) {
                fGotClass = TRUE;
            }

            // get the inactivity timeout
            DWORD dwValue;
            dwSize = sizeof(dwValue);
            dwStatus = RegQueryValueEx(hk, L"InactivityTimeout", NULL, NULL, (LPBYTE) &dwValue, &dwSize);
            if(dwStatus == ERROR_SUCCESS) {
                m_dwPowerTimeout = dwValue;
            }
            DEBUGMSG(ZONE_INIT, (_T("CDiskPower::Init: inactivity timeout is %u ms\r\n"), m_dwPowerTimeout));
            
            // get the inactivity timeout
            dwSize = sizeof(dwValue);
            dwStatus = RegQueryValueEx(hk, L"TimeoutDx", NULL, NULL, (LPBYTE) &dwValue, &dwSize);
            if(dwStatus == ERROR_SUCCESS) {
                if(VALID_DX((CEDEVICE_POWER_STATE)dwValue) && dwValue != D3) {
                    m_timeoutDx = (CEDEVICE_POWER_STATE) dwValue;
                } else {
                    DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::Init: invalid or unsupported timeout device power state %d (0x%x)\r\n"), dwValue, dwValue));
                }
            }
            DEBUGMSG(ZONE_INIT, (_T("CDiskPower::Init: timeout state is D%d\r\n"), m_timeoutDx));
            
            // get the inactivity timeout
            dwSize = sizeof(dwValue);
            dwStatus = RegQueryValueEx(hk, L"InactivityPriority256", NULL, NULL, (LPBYTE) &dwValue, &dwSize);
            if(dwStatus == ERROR_SUCCESS) {
                nPriority = (int) dwValue;
            }
            DEBUGMSG(ZONE_INIT, (_T("CDiskPower::Init: inactivity timeout thread priority is %d\r\n"), nPriority));
            
            RegCloseKey(hk);
        }   

        // did we get a class string?
        if(!fGotClass) {
            // no, use the default disk class
            wcsncpy(szClass, PMCLASS_BLOCK_DEVICE, dim(szClass));
            szClass[dim(szClass) - 1] = 0;
        }

        // convert to a GUID
        fOk = GUIDFromString(szClass, &gPMClass);
        if(!fOk) {
            DEBUGMSG(ZONE_WARNING || ZONE_INIT, (_T("CDiskPower::Init: invalid power management class '%s'\r\n"),
                szClass));
        }
       
    }

    // get our active key from the registry
    if(fOk) {
        HKEY hk;
        dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_pDisk->m_szActiveKey, 0, 0, &hk);
        if(dwStatus == ERROR_SUCCESS) {
            DWORD dwValue;
            DWORD dwSize = sizeof(dwValue);
            dwStatus = RegQueryValueEx(hk, DEVLOAD_HANDLE_VALNAME, NULL, NULL, (LPBYTE) &dwValue, &dwSize);
            if(dwStatus != ERROR_SUCCESS) {
                DEBUGMSG(ZONE_WARNING || ZONE_INIT, (_T("CDiskPower::Init: can't read '%s' from '%s'\r\n"),
                    DEVLOAD_HANDLE_VALNAME, m_pDisk->m_szActiveKey));
                fOk = FALSE;
            } else {
                DEBUGCHK(dwValue != 0);
                hActive = (HANDLE) dwValue;
            }
        }
    }

    // figure out the name we are using
    if(fOk) {
        WCHAR szName[MAX_PATH];
        DWORD dwIndex = 0;
        do {
            DWORD dwSize = sizeof(szName);
            GUID gClass;
            fOk = EnumDeviceInterfaces(hActive, dwIndex, &gClass, szName, &dwSize);
            if(fOk && gPMClass == gClass) {
                // we found the interface
                break;
            }
            dwIndex++;
        } while(fOk);
        DEBUGMSG(!fOk && (ZONE_WARNING || ZONE_INIT), (_T("CDiskPower::Init: can't find PM interface\r\n")));

        // did we find the name?
        if(fOk) {
            // yes, allocate a name buffer to use to talk to the power manager
            DWORD dwChars = wcslen(PMCLASS_BLOCK_DEVICE) + wcslen(szName) + 2;  // class + separator + name + null
            LPWSTR pszPMName = (LPWSTR) LocalAlloc(LPTR, dwChars * sizeof(WCHAR));
            fOk = FALSE;        // assume failure
            if(pszPMName) {
                HRESULT hr = StringCchPrintfW(pszPMName, dwChars, L"{%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x}\\%s",
                    gPMClass.Data1, gPMClass.Data2, gPMClass.Data3,
                    (gPMClass.Data4[0] << 8) + gPMClass.Data4[1], gPMClass.Data4[2], gPMClass.Data4[3], 
                    gPMClass.Data4[4], gPMClass.Data4[5], gPMClass.Data4[6], gPMClass.Data4[7],
                    szName);
                if(SUCCEEDED(hr)) {
                    m_pszPMName = (LPCWSTR) pszPMName;
                    fOk = TRUE;
                }
            }
            DEBUGMSG(!fOk && (ZONE_WARNING || ZONE_INIT), (_T("CDiskPower::Init: can't find PM interface\r\n")));
        }
    }

    // create an event to tell the timeout thread about activity
    if(fOk) {
        m_hevPowerSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
        m_hevDummy = CreateEvent(NULL, FALSE, FALSE, NULL);
        if(!m_hevPowerSignal || !m_hevDummy) {
            DEBUGMSG(ZONE_WARNING || ZONE_INIT, (_T("CDiskPower::Init: couldn't create status events\r\n")));
            fOk = FALSE;
        }
    }

    // create the timeout thread
    if(fOk) {
        m_htPower = CreateThread(NULL, 0, DiskPowerThreadStub, this, 0, NULL);
        if(!m_htPower) {
            DEBUGMSG(ZONE_WARNING || ZONE_INIT, (_T("CDiskPower::Init: CreateThread() failed %d\r\n"), GetLastError()));
            fOk = FALSE;
        } else {
            BOOL fSuccess = CeSetThreadPriority(m_htPower, nPriority);
            DEBUGMSG(!fSuccess && (ZONE_WARNING || ZONE_INIT), (_T("CDiskPower::Init: CeSetThreadPriority(%d) failed %d\r\n"), nPriority, GetLastError()));
        }
    }

    // disable the standby timer, since the PM is going to be controlling
    // the disk power state
    if(fOk) {
        if(!m_pDisk->SendDiskPowerCommand(ATA_NEW_CMD_IDLE, 0)) {
            DEBUGMSG(ZONE_WARNING || ZONE_INIT, (_T("CDiskPower::Init: disable standby timer failed\r\n")));
        }
    }

    // on error, cleanup will happen in the destructor
    DEBUGMSG(ZONE_INIT, (_T("-CDiskPower::Init(): returning %d\r\n"), fOk));

    return fOk;
}

// This routine issues the ATAPI commands necessary to put the disk into a new power state.
// The caller must hold the disk critical section.
DWORD CDiskPower::SetDiskPower(CEDEVICE_POWER_STATE newDx)
{
    DWORD dwStatus = ERROR_SUCCESS;
    
    DEBUGCHK(VALID_DX(newDx));
    PREFAST_DEBUGCHK(m_pDisk != NULL);
    
    TakeCS();
    DEBUGMSG(ZONE_POWER, (_T("CDiskPower::SetDiskPower: updating from D%d to D%d\r\n"), m_curDx, newDx));
    if(newDx != m_curDx) {
        switch(newDx) {
        case D0:
        case D1:
        case D2:
            if(m_curDx == D4) {
                // have to reset and reinitialize to come out of SLEEP mode
                if(!m_pDisk->WakeUp()) {
                    DEBUGMSG(ZONE_ERROR, (_T("CDiskPower::SetDiskPower: couldn't re-initialize hard drive\r\n")));
                    dwStatus = ERROR_GEN_FAILURE;
                }
            }
            break;
        case D3:
        case D4:
            newDx = D4;         // no D3 support
            break;
        }

        // enter the new device state
        if(dwStatus == ERROR_SUCCESS && !m_pDisk->SetDiskPowerState(newDx)) {
            DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::SetDiskPower: SetDiskPowerState(D%d) failed\r\n"), newDx));
            dwStatus = ERROR_GEN_FAILURE;
        }
        
        // update the device power status
        if(dwStatus == ERROR_SUCCESS) {
            LARGE_INTEGER li;
            BOOL fGotQPC = QueryPerformanceCounter(&li);
            if(!fGotQPC) {
                DEBUGMSG(ZONE_WARNING, (_T("CDiskPower::SetDiskPower: QueryPerformanceCounter() failed, can't update statistics\r\n")));
            } else {
                m_dxInfo[m_curDx].totalQPC.QuadPart += li.QuadPart - m_startQPC.QuadPart;
            }
            m_curDx = newDx;
            m_dxInfo[m_curDx].dwCount++;
            if(fGotQPC) {
                m_startQPC = li;
            }
        }
    }

    ReleaseCS();
    return dwStatus;
}

// This routine returns the disk's current device power state.  The caller must hold the disk
// critical section.
CEDEVICE_POWER_STATE CDiskPower::GetDiskPower(void)
{
    CEDEVICE_POWER_STATE curDx;
    TakeCS();
    curDx = m_curDx;
    DEBUGMSG(ZONE_POWER, (_T("CDiskPower::GetDiskPower: returning D%d\r\n"), curDx));
    ReleaseCS();
    return curDx;
}

// This routine fills in the POWER_CAPABILITIES structure with information for this driver
DWORD CDiskPower::GetDiskCapabilities(PPOWER_CAPABILITIES pCap)
{
    DWORD dwStatus = ERROR_SUCCESS;
    
    DEBUGCHK(pCap != NULL);
    PREFAST_DEBUGCHK(m_pDisk != NULL);

    // clear the capabilities structure
    memset(pCap, 0, sizeof(*pCap));

    // has power management been enabled for this drive?
    if(!m_pDisk->IsPMEnabled()) {
        // no, just report D0 support
        //pCap->DeviceDx = 0x01;
        pCap->DeviceDx = 0x11;       // support D4, D2, D1, D0        
    } else {
        pCap->DeviceDx = 0x17;       // support D4, D2, D1, D0
    }

    return dwStatus;
}

// This routine handles Power Manager IOCTLs for the disk.  It returns a Win32 error
// code if there's a problem, ERROR_SUCCESS if the IOCTL was handled successfully, or 
// ERROR_NOT_SUPPORTED if the IOCTL was not from the PM.  The caller must hold the
// disk critical section.
DWORD CDiskPower::DiskPowerIoctl(PIOREQ pIOReq)
{
    DWORD dwStatus = ERROR_INVALID_PARAMETER;

    PREFAST_DEBUGCHK(pIOReq != NULL);

    switch(pIOReq->dwCode) {
    case IOCTL_POWER_CAPABILITIES:
        if(pIOReq->pOutBuf != NULL && pIOReq->dwOutBufSize >= sizeof(POWER_CAPABILITIES) && pIOReq->pBytesReturned != NULL) {
            POWER_CAPABILITIES pc;
            dwStatus = GetDiskCapabilities(&pc);
            if(dwStatus == ERROR_SUCCESS) {
                PPOWER_CAPABILITIES ppc = (PPOWER_CAPABILITIES) pIOReq->pOutBuf;
                *ppc = pc;
                *pIOReq->pBytesReturned = sizeof(*ppc);
            }
        }
        break;
    case IOCTL_POWER_SET:
        if(pIOReq->pOutBuf != NULL && pIOReq->dwOutBufSize == sizeof(CEDEVICE_POWER_STATE) && pIOReq->pBytesReturned != NULL) {
            CEDEVICE_POWER_STATE newDx = *(PCEDEVICE_POWER_STATE) pIOReq->pOutBuf;
            m_fReductionRequested = FALSE;
            m_fBoostRequested = FALSE;
            dwStatus = SetDiskPower(newDx);
            *pIOReq->pBytesReturned = sizeof(newDx);
            dwStatus = ERROR_SUCCESS;
        }
        break;
    case IOCTL_POWER_GET:
        if(pIOReq->pOutBuf != NULL && pIOReq->dwOutBufSize == sizeof(CEDEVICE_POWER_STATE) && pIOReq->pBytesReturned != NULL) {
            CEDEVICE_POWER_STATE curDx = GetDiskPower();
            *(PCEDEVICE_POWER_STATE) pIOReq->pOutBuf = curDx;
            *pIOReq->pBytesReturned = sizeof(curDx);
            dwStatus = ERROR_SUCCESS;
        }
        break;
    case IOCTL_DISK_GETPMTIMINGS:
        if(pIOReq->pInBuf != NULL && pIOReq->dwInBufSize >= sizeof(PowerTimings)) {
            PowerTimings pt;
            memset(&pt, 0, sizeof(pt));
            pt.dwSize = sizeof(pt);
            TakeCS();
            pt.dwLoadedTicks = GetTickCount() - m_dwStartTickCount;
            for(int i = 0; i < PwrDeviceMaximum; i++) {
                pt.DxTiming[i].dwCount = m_dxInfo[i].dwCount;
                pt.DxTiming[i].liElapsed = m_dxInfo[i].totalQPC;
            }
            LARGE_INTEGER li;
            if(QueryPerformanceCounter(&li)) {
                pt.DxTiming[m_curDx].liElapsed.QuadPart += li.QuadPart - m_startQPC.QuadPart;
            }
            ReleaseCS();

            // copy the data to the user buffer
            pPowerTimings ppt = (pPowerTimings) pIOReq->pInBuf;
            if(ppt->dwSize >= sizeof(PowerTimings) && ppt->dwSize <= pIOReq->dwInBufSize) {
                *ppt = pt;
                dwStatus = ERROR_SUCCESS;
            } else {
                dwStatus = ERROR_INVALID_PARAMETER;
            }
        }
        break;
    default:    // not a PM ioctl
        dwStatus = ERROR_NOT_SUPPORTED;
        break;
    }

    DEBUGMSG(dwStatus != ERROR_NOT_SUPPORTED && dwStatus != ERROR_SUCCESS && ZONE_WARNING, 
        (_T("CDiskPower::DiskPowerIoctl: ioctl 0x%x failed %u\r\n"), pIOReq->dwCode, dwStatus));
    return dwStatus;
}

⌨️ 快捷键说明

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