Exemple #1
0
// 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;
}
Exemple #2
0
// 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;
}
Exemple #3
0
// 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;
}
Exemple #4
0
///
/// @brief Init required IO-pins. This function should be called as
///        early as possible in a systems with several SPI-devices.
///
/// @param  None
/// @return None
///
void libRFM69_InitHW(void)
{
    InitReset();

    InitCS();
    ReleaseCS();

    InitIO();

    return;
}
Exemple #5
0
// 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();
}
Exemple #6
0
// 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);

    if (GetCurrentProcessId() != (DWORD)GetDirectCallerProcessId())
    {
        RETAILMSG(1, (L"ERROR: ATAPI: "
            L"Power IOCTLs can be called only from device process (caller process id 0x%08x)\n", GetDirectCallerProcessId()));
        SetLastError(ERROR_ACCESS_DENIED);
        return FALSE;
    }

    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;
}
Exemple #7
0
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;
}