Exemple #1
0
///////////////////////////////////////////////////////////////////////////////
//  SDMemErase       - Erase a contiguous set of blocks
//  Input:  pMemCard - SD memory card structure
//          pDSI     - structure describing the range of sectors to erase
//  Output:
//  Return: Status   - windows status code
//  Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD SDMemErase( PSD_MEMCARD_INFO pMemCard, PDELETE_SECTOR_INFO pDSI )
{
    DWORD dwStatus = ERROR_SUCCESS;

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: +SDMemErase\n")));

    PREFAST_DEBUGCHK(pMemCard);
    PREFAST_DEBUGCHK(pDSI);

    // Validate Gather request
    if ((pDSI->startsector + pDSI->numsectors) > pMemCard->DiskInfo.di_total_sectors) {
        dwStatus = ERROR_INVALID_PARAMETER;
        goto statusReturn;
    }

    /*
    dwStatus = SDMemDoErase(
        pMemCard,
        (LONG) pDSI->startsector,
        (LONG) pDSI->numsectors
        );
    */

statusReturn:

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: -SDMemErase\n")));

    return dwStatus;
}
Exemple #2
0
///////////////////////////////////////////////////////////////////////////////
//  SDHCBusRequestHandler - bus request handler 
//  Input:  pHostContext - host controller context
//          dwSlot - slot the request is going to
//          pRequest - the request
//          
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  The request passed in is marked as uncancelable, this function
//          has the option of making the outstanding request cancelable    
//          returns status pending
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS 
CSDHCBase::SDHCBusRequestHandler(
                      PSDCARD_HC_CONTEXT pHCContext, 
                      DWORD              dwSlot, 
                      PSD_BUS_REQUEST    pRequest
                      ) 
{
    PREFAST_DEBUGCHK(pHCContext);
    PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
    PREFAST_DEBUGCHK(pController);
    return pController->BusRequestHandler(dwSlot, pRequest);
}
Exemple #3
0
///////////////////////////////////////////////////////////////////////////////
//  SDHCDeinitialize - Deinitialize the SDHC Controller
//  Input:  pHCContext - HC context
//          
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  
//          
//
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS CSDHCBase::SDHCDeinitialize(PSDCARD_HC_CONTEXT pHCContext)
{
    DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCDeinitialize++\n")));

    PREFAST_DEBUGCHK(pHCContext);
    PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
    PREFAST_DEBUGCHK(pController);
    SD_API_STATUS status = pController->Stop();

    DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCDeinitialize--\n")));

    return status;
}
Exemple #4
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 #5
0
DWORD CDiskPower::DiskPowerThreadStub(LPVOID lpvParam)
{
    PREFAST_DEBUGCHK(lpvParam != NULL);
    CDiskPower *pDiskPower = (CDiskPower *) lpvParam;
    DWORD dwStatus = pDiskPower->DiskPowerThread();
    return dwStatus;
}
// This routine releases a power relationship that was created with 
// PmRegisterPowerRelationship().  It returns
//      ERROR_SUCCESS - relationship removed
//      ERROR_INVALID_PARAMETER - bad handle
// Deregistering a power relationship has the side effect of deregistering
// the child device with the PM.  Note that if the child exits while
// the relationship is outstanding, the caller will get ERROR_INVALID_PARAMETER
// when they attempt to release the relationship handle.
EXTERN_C DWORD WINAPI 
PmReleasePowerRelationship(HANDLE h)
{
    PDEVICE_STATE pds = (PDEVICE_STATE) h;
    DWORD dwStatus = ERROR_INVALID_PARAMETER;

#ifndef SHIP_BUILD
    SETFNAME(_T("PmReleasePowerRelationship"));
#endif

    PMLOGMSG(ZONE_API, (_T("%s: releasing 0x%08x\r\n"), pszFname, h));

    // make sure that this pointer is a child node with a parent
    if(pds != NULL) {
        BOOL fExists = CheckDevicePointer(pds); // increments refcnt if TRUE
        if(fExists) {
            // delete the device
            PREFAST_DEBUGCHK(pds->pListHead != NULL);
            RemoveDevice(pds->pListHead->pGuid, pds->pszName);

            // done with the pointer
            DeviceStateDecRef(pds);

            // return a good status
            dwStatus = ERROR_SUCCESS;
        }
    }

    PMLOGMSG(ZONE_API || (dwStatus != ERROR_SUCCESS && ZONE_WARN), (_T("%s: returning %d\r\n"), 
        pszFname, dwStatus));
    return dwStatus;
}
Exemple #7
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 #8
0
DWORD 
CSDHCBase::DetermineFirstSlotWindow(
                                    PDDKWINDOWINFO pwini
                                    )
{
    PREFAST_DEBUGCHK(pwini);
    DEBUGCHK(pwini->dwNumMemWindows >= m_cSlots);
    DEBUGCHK(pwini->dwNumMemWindows > 0);

    DWORD dwSlotZeroWindow = 0;

    return dwSlotZeroWindow;
}
Exemple #9
0
///////////////////////////////////////////////////////////////////////////////
//  SDHCSlotOptionHandler - handler for slot option changes
//  Input:  pHostContext - host controller context
//          dwSlot       - the slot the change is being applied to
//          Option       - the option code
//          pData        - data associaSHC with the option
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS 
CSDHCBase::SDHCSlotOptionHandler(
                      PSDCARD_HC_CONTEXT    pHCContext,
                      DWORD                 dwSlot, 
                      SD_SLOT_OPTION_CODE   sdOption, 
                      PVOID                 pData,
                      ULONG                 ulOptionSize
                      )
{
    PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
    PREFAST_DEBUGCHK(pController);
    return pController->SlotOptionHandler(dwSlot, sdOption, pData, ulOptionSize);
}
Exemple #10
0
// This routine returns TRUE to indicate that the pfBatteriesChangedSinceLastCall
// value filled in by BatteryPDDGetStatus() is valid.  If there is no way to
// tell that the platform's batteries have been changed this routine should
// return FALSE.
//Not support
BOOL
BatteryPDDSupportsChangeNotification(void)
{
    BOOL fSupportsChange;
    SETFNAME(_T("BatteryPDDPowerHandler"));
    RETAILMSG(ZONE_REG_PRINT, (TEXT("+BatteryPDDSupportsChangeNotification...  \r\n"))); 

    PREFAST_DEBUGCHK(gpStatus != NULL);

    LockBattery();
    fSupportsChange = gpStatus->fSupportsChange;
		DPNOK(fSupportsChange);
    UnlockBattery();

    return fSupportsChange;

}
Exemple #11
0
BOOL 
CSDHCBase::DeinitializeHardware(
                                )
{
    DEBUGCHK(m_hBusAccess);
    PREFAST_DEBUGCHK(m_pSlotInfos);
    ValidateSlotCount();

    for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
        PVOID pvRegisters = (PVOID) m_pSlotInfos[dwSlot].pucRegisters;
        DWORD dwLen = m_pSlotInfos[dwSlot].dwExtraInfo;
        if (pvRegisters) MmUnmapIoSpace(pvRegisters, dwLen);
    }

    if (m_hISRHandler) FreeIntChainHandler(m_hISRHandler);

    return TRUE;
}
Exemple #12
0
///////////////////////////////////////////////////////////////////////////////
//  SDMemEraseAll    - Erase all blocks
//  Input:  pMemCard - SD memory card structure
//  Output:
//  Return: Status   - windows status code
//  Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD SDMemEraseAll( PSD_MEMCARD_INFO pMemCard )
{
    DWORD              dwStatus = ERROR_SUCCESS;
    DELETE_SECTOR_INFO DSI;

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: +SDMemEraseAll\n")));

    PREFAST_DEBUGCHK(pMemCard);

    DSI.cbSize = sizeof(DSI);
    DSI.startsector = 0;
    DSI.numsectors = pMemCard->DiskInfo.di_total_sectors;

    dwStatus = SDMemErase(pMemCard, &DSI);

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: -SDMemEraseAll\n")));

    return dwStatus;
}
Exemple #13
0
// This routine indicates how many battery levels will be reported
// in the BatteryFlag and BackupBatteryFlag fields of the PSYSTEM_POWER_STATUS_EX2
// filed in by BatteryPDDGetStatus().  This number ranges from 0 through 3 --
// see the Platform Builder documentation for details.  The main battery
// level count is reported in the low word of the return value; the count 
// for the backup battery is in the high word.
//have not used currently
LONG
BatteryPDDGetLevels(void)
{
    LONG lLevels;
    SETFNAME(_T("BatteryPDDPowerHandler"));

    RETAILMSG(ZONE_REG_PRINT, (TEXT("+BatteryPDDGetLevels...  \r\n"))); 

    PREFAST_DEBUGCHK(gpStatus != NULL);

    LockBattery();
    lLevels = MAKELONG (gpStatus->wMainLevels, gpStatus->wBackupLevels);
	DPNOK(lLevels);
    UnlockBattery();

    DEBUGMSG(ZONE_PDD, (_T("%s: returning %u (%d main levels, %d backup levels)\r\n"),
        TEXT(__FUNCTION__), lLevels, LOWORD(lLevels), HIWORD(lLevels)));

    return lLevels;
}
Exemple #14
0
// 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 = 0x11;       // support D4, D2, D1, D0        
    } else {
        pCap->DeviceDx = 0x11;       // support D4, D2, D1, D0
    }

    return dwStatus;
}
Exemple #15
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 #16
0
BOOL 
CSDHCBase::InitializeHardware(
                              )
{
    SETFNAME(_T("InitializeHardware"));

    DEBUGCHK(m_hBusAccess);
    DEBUGCHK(m_regDevice.IsOK());
    PREFAST_DEBUGCHK(m_pSlotInfos);
	RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware\n")));
	ValidateSlotCount();

    BOOL fRet = FALSE;
    PHYSICAL_ADDRESS PortAddress;
    DWORD inIoSpace = 0;

    // Read window information
    DDKWINDOWINFO wini;
    wini.cbSize = sizeof(wini);
    DWORD dwStatus = DDKReg_GetWindowInfo(m_regDevice, &wini);
    if (dwStatus != ERROR_SUCCESS) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error getting window information\r\n"),
            pszFname));
        goto EXIT;
    }

    // Read ISR information
    DDKISRINFO isri;
    isri.cbSize = sizeof(isri);
    dwStatus = DDKReg_GetIsrInfo(m_regDevice, &isri);
    if (dwStatus != ERROR_SUCCESS) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error getting ISR information\r\n"),
            pszFname));
        goto EXIT;
    }

#ifdef SET_TI_BOARD_PCI_REG
	{
		DDKPCIINFO dpi;
		dpi.cbSize = sizeof(dpi);
		DDKReg_GetPciInfo(m_regDevice, &dpi);

		DWORD RetVal;
		PCI_SLOT_NUMBER SlotNumber;
		SlotNumber.u.AsULONG = 0;
		SlotNumber.u.bits.DeviceNumber = dpi.dwDeviceNumber;
		SlotNumber.u.bits.FunctionNumber = 1;

		HalGetBusDataByOffset( PCIConfiguration,
							   wini.dwBusNumber,
							   SlotNumber.u.AsULONG,
							   &RetVal,
							   0x84,
							   sizeof( RetVal ) );

		if (!(RetVal & 0x00200000)) {
			RetVal |= 0x00200000;
			HalSetBusDataByOffset( PCIConfiguration,
								   wini.dwBusNumber,
								   SlotNumber.u.AsULONG,
								   &RetVal,
								   0x84,
								   sizeof( RetVal ) );
		}
	}
#endif

    // Sanity check ISR
    if (isri.dwSysintr == SYSINTR_NOP) {
		RETAILMSG(0,(TEXT("%s No sysintr specified in registry\r\n"),pszFname));
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s No sysintr specified in registry\r\n"),
            pszFname));
        goto EXIT;
    }

    if (isri.szIsrDll[0] != 0) {
        if ( (isri.szIsrHandler[0] == 0) || (isri.dwIrq == IRQ_UNSPECIFIED) ) {
            DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Invalid installable ISR information in registry\r\n"),
                pszFname));
            goto EXIT;
        }
    }

    m_interfaceType = (INTERFACE_TYPE) wini.dwInterfaceType;
    m_dwBusNumber = wini.dwBusNumber;

    DWORD dwSlotZeroWindow;
    dwSlotZeroWindow = DetermineFirstSlotWindow(&wini);

    DEBUGCHK(dwSlotZeroWindow < wini.dwNumMemWindows);
    DEBUGCHK( (dwSlotZeroWindow + m_cSlots) <= wini.dwNumMemWindows );

    // Use the slot zero window for the ISR
    PDEVICEWINDOW pWindowSlotZero = &wini.memWindows[dwSlotZeroWindow];
    PortAddress.LowPart = pWindowSlotZero->dwBase;
    PortAddress.HighPart = 0;

	RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware go on...\n")));

    // Install an ISR, if present
    if (isri.szIsrDll[0] != 0) {
        m_hISRHandler = LoadIntChainHandler(isri.szIsrDll, isri.szIsrHandler, 
            (BYTE) isri.dwIrq);

        if (m_hISRHandler == NULL) {
            DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error installing ISR\r\n"), pszFname));
            goto EXIT;
        } 
        else {
            GIISR_INFO  Info;
            DWORD       dwPhysAddr;

            fRet = BusTransBusAddrToStatic(m_hBusAccess, 
                (INTERFACE_TYPE) wini.dwInterfaceType,
                wini.dwBusNumber, PortAddress, pWindowSlotZero->dwLen,
                &inIoSpace, (PVOID *) &dwPhysAddr);
            if (fRet == FALSE) {
                DEBUGMSG(SDCARD_ZONE_ERROR,
                    (_T("%s Error translating bus address to static address\r\n"), 
                    pszFname));
                goto EXIT;
            }

            // Initialize ISR
            Info.SysIntr = isri.dwSysintr;
            Info.CheckPort = TRUE;
            Info.PortIsIO = (inIoSpace != 0);
            Info.UseMaskReg = FALSE;
            Info.PortAddr = dwPhysAddr + SDHC_SLOT_INT_STATUS;
            Info.PortSize = sizeof(USHORT);
            Info.Mask = 0xFF;

            fRet = KernelLibIoControl(m_hISRHandler, IOCTL_GIISR_INFO, &Info, 
                sizeof(Info), NULL, 0, NULL);
            if (fRet == FALSE) {
                DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error setting up ISR\r\n"), pszFname));
                goto EXIT;
            }
        }
    }

    m_dwSysIntr = isri.dwSysintr;
    DEBUGMSG(SDCARD_ZONE_INIT, (_T("%s IRQ 0x%X mapped to SYS_INTR 0x%X\r\n"), 
        pszFname, isri.dwIrq, m_dwSysIntr));

    const DWORD dwEndWindow = dwSlotZeroWindow + m_cSlots;

    for (DWORD dwWindow = dwSlotZeroWindow; dwWindow < dwEndWindow; ++dwWindow) {
        DEBUGCHK(dwWindow < wini.dwNumMemWindows);
        PDEVICEWINDOW pWindowSD = &wini.memWindows[dwWindow];

        DEBUGMSG(SDCARD_ZONE_INIT,
            (_T("%s Base address -> 0x%x; length -> 0x%x \r\n"),
            pszFname, pWindowSD->dwBase, pWindowSD->dwLen));

        PortAddress.LowPart = pWindowSD->dwBase;
        PortAddress.HighPart = 0;

        inIoSpace = 0;
        PVOID pvRegisters;
        DEBUGCHK(pWindowSlotZero->dwLen >= sizeof(SSDHC_REGISTERS));

	RETAILMSG(0,(TEXT("BusTransBusAddrToVirtual. 0x%X\n"),PortAddress));
        fRet = BusTransBusAddrToVirtual(m_hBusAccess, 
            (INTERFACE_TYPE) wini.dwInterfaceType,
            wini.dwBusNumber, PortAddress, pWindowSD->dwLen, &inIoSpace, 
            &pvRegisters);
        if (fRet == FALSE) {
				RETAILMSG(0,(TEXT("%s error translating SD address \r\n"),pszFname));
            DEBUGMSG(SDCARD_ZONE_ERROR,
                (_T("%s error translating SD address \r\n"),
                pszFname));
            goto EXIT;
        }

        DEBUGCHK(inIoSpace == 0); // Will not work for I/O mappings.

        DWORD dwSlot = dwWindow - dwSlotZeroWindow;
        DEBUGCHK(dwSlot < m_cSlots);
        m_pSlotInfos[dwSlot].pucRegisters = (volatile UCHAR*) pvRegisters;
        m_pSlotInfos[dwSlot].dwExtraInfo = pWindowSD->dwLen;
    }

    m_fHardwareInitialized = TRUE;
    fRet = TRUE;
	RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware finished.\n")));
EXIT:
    return fRet;
}
Exemple #17
0
///////////////////////////////////////////////////////////////////////////////
//  SDMemWrite       - Write data to card from pSG scatter gather buffers
//  Input:  pMemCard - SD memory card structure
//          pSG      - Scatter Gather buffer structure from FATFS
//  Output:
//  Return: Status   - windows status code
//  Notes:  Writes to the card are split into groups of size TransferBlockSize
//          This is controlled by a registry entry for the driver.
///////////////////////////////////////////////////////////////////////////////
DWORD SDMemWrite( PSD_MEMCARD_INFO pMemCard, PSG_REQ pSG )
{
    DWORD  NumBlocks;
    DWORD  StartBlock;
    PUCHAR pBlockBuffer = NULL, pCardDataPtr = NULL;
    PUCHAR pSGBuffer = NULL;
    DWORD  status = ERROR_SUCCESS;
    DWORD  SGBufNum, SGBufLen, SGBufRemaining;
    DWORD  PartialStartBlock;
    DWORD  CardDataRemaining;

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: +SDMemWrite\r\n")));

    PREFAST_DEBUGCHK(pSG);

    // pSG is a sterile SG_REQ copy of the callers's SG_REQ; we can map the
    // embedded pointers back into it

    // validate the embedded sb_bufs
    for (ULONG ul = 0; ul < pSG->sr_num_sg; ul += 1) {
        if (
            (NULL == pSG->sr_sglist[ul].sb_buf) ||
            (0 == pSG->sr_sglist[ul].sb_buf)
        ) {
            status = ERROR_INVALID_PARAMETER;
            goto statusReturn;
        }
        pSG->sr_sglist[ul].sb_buf = (PUCHAR)MapCallerPtr(
            (LPVOID)pSG->sr_sglist[ul].sb_buf,
            pSG->sr_sglist[ul].sb_len);
        if (pSG->sr_sglist[ul].sb_buf == NULL) {
            status = ERROR_INVALID_PARAMETER;
            goto statusReturn;
        }
    }

    // validate the I/O request
    if ((pSG->sr_start > pSG->sr_start + pSG->sr_num_sec) 
        ||(pSG->sr_start + pSG->sr_num_sec) > pMemCard->DiskInfo.di_total_sectors) {
        status = ERROR_INVALID_PARAMETER;
        goto statusReturn;
    }

    // check card write protect status
    if (pMemCard->WriteProtected) {
        DEBUGMSG(SDMEM_ZONE_DISK_IO, (TEXT("SDMemWrite: Card is write protected\r\n")));
        status = ERROR_WRITE_PROTECT;
        goto statusReturn;
    }

    // get number of sectors
    StartBlock = pSG->sr_start;
    NumBlocks = pSG->sr_num_sec;

    DEBUGMSG(SDMEM_ZONE_DISK_IO, (TEXT("SDMemWrite: Writing blocks %d-%d\r\n"),
        StartBlock,
        StartBlock+NumBlocks-1));

    // calculate total buffer space of scatter gather buffers
    SGBufLen = 0;
    for (SGBufNum = 0; SGBufNum < pSG->sr_num_sg; SGBufNum++) {
        SGBufLen += pSG->sr_sglist[SGBufNum].sb_len;
    }

    // check total SG buffer space is enough for reqeusted transfer size
    if(SGBufLen < NumBlocks * SD_BLOCK_SIZE) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDMemWrite: SG Buffer space %d bytes less than block write size %d bytes\r\n"),
            SGBufLen,
            NumBlocks * SD_BLOCK_SIZE));
        status = ERROR_GEN_FAILURE;
        goto statusReturn;
    }

    // get block transfer buffer
    pBlockBuffer = (PUCHAR)SDAllocateFromMemList(pMemCard->hBufferList);

    // initialize some variables used in data copy
    SGBufNum = 0;
    SGBufRemaining = pSG->sr_sglist[SGBufNum].sb_len;
    pSGBuffer = pSG->sr_sglist[SGBufNum].sb_buf;

    // split the writes into groups of TransferBlockSize in size to avoid
    // hogging the SD Bus with large writes
    for(PartialStartBlock = StartBlock; PartialStartBlock < StartBlock+NumBlocks; PartialStartBlock += pMemCard->BlockTransferSize) {

        // some variables just used for copying
        DWORD PartialTransferSize;
        DWORD CopySize;

        pCardDataPtr = pBlockBuffer;

        PartialTransferSize = MIN(
            pMemCard->BlockTransferSize,
            StartBlock+NumBlocks-PartialStartBlock);

        // copy from pSG buffers to pBlockArray
        CardDataRemaining = PartialTransferSize*SD_BLOCK_SIZE;

        while (CardDataRemaining) {

            // get minimum of remaining size in SG buf and data left in pBlockBuffer
            CopySize = MIN(SGBufRemaining, CardDataRemaining);

            // copy that much data to block buffer
            if (0 == CeSafeCopyMemory(pCardDataPtr, pSGBuffer, CopySize)) {
                status = ERROR_INVALID_PARAMETER;
                goto statusReturn;
            }

            // update pointers and counts
            pSGBuffer += CopySize;
            pCardDataPtr += CopySize;
            CardDataRemaining -= CopySize;
            SGBufRemaining -= CopySize;

            // get the next SG Buffer if needed
            if (!SGBufRemaining && CardDataRemaining) {
                SGBufNum++;
                SGBufRemaining = pSG->sr_sglist[SGBufNum].sb_len;
                pSGBuffer = pSG->sr_sglist[SGBufNum].sb_buf;
            }
        }

        // write the data to the SD Card
        status = SDMemWriteMultiple(
            pMemCard,
            PartialStartBlock,
            PartialTransferSize,
            pBlockBuffer);

        if (status != ERROR_SUCCESS) {
            break;
        }
    }
statusReturn:

    // free the allocated block buffer
    if (pBlockBuffer) {
        SDFreeToMemList(pMemCard->hBufferList, pBlockBuffer);
    }

    // FATFS wants the status returned in the SG buffers also
    pSG->sr_status = status;

    DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: -SDMemWrite\r\n")));

    return status;
}
Exemple #18
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 #19
0
EXTERN_C BOOL WINAPI
PlatformDeviceListInit (PDEVICE_LIST pdl)
{
	BOOL fOk = FALSE;
	PDEVICE_INTERFACE pInterface;

	SETFNAME (_T ("PlatformDeviceListInit"));

	PREFAST_DEBUGCHK (pdl != NULL);
	DEBUGCHK (pdl->pGuid != NULL);

	if (*pdl->pGuid == idPMDisplayDeviceClass)
	{
		PMLOGMSG (ZONE_INIT || ZONE_PLATFORM,
				  (_T
				   ("%s: using display interface to access class %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\r\n"),
				   pszFname, pdl->pGuid->Data1, pdl->pGuid->Data2, pdl->pGuid->Data3,
				   (pdl->pGuid->Data4[0] << 8) + pdl->pGuid->Data4[1], pdl->pGuid->Data4[2],
				   pdl->pGuid->Data4[3], pdl->pGuid->Data4[4], pdl->pGuid->Data4[5],
				   pdl->pGuid->Data4[6], pdl->pGuid->Data4[7]));

		// Use the display driver interface to get to the device.  To remove
		// display code from the link, edit or conditionally compile this code out
		// of the Power Manager.

		extern DEVICE_INTERFACE gDisplayInterface;	// defined in the MDD

		pInterface = &gDisplayInterface;
	}
	else
	{
		// Use the standard stream interface to get to the device:
		PMLOGMSG (ZONE_INIT || ZONE_PLATFORM,
				  (_T
				   ("%s: using stream interface to access class %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\r\n"),
				   pszFname, pdl->pGuid->Data1, pdl->pGuid->Data2, pdl->pGuid->Data3,
				   (pdl->pGuid->Data4[0] << 8) + pdl->pGuid->Data4[1], pdl->pGuid->Data4[2],
				   pdl->pGuid->Data4[3], pdl->pGuid->Data4[4], pdl->pGuid->Data4[5],
				   pdl->pGuid->Data4[6], pdl->pGuid->Data4[7]));
		extern DEVICE_INTERFACE gStreamInterface;	// defined in the MDD

		pInterface = &gStreamInterface;
	}

	// Try to initialize the interface:
	if (pInterface != NULL)
	{
		if (pInterface->pfnInitInterface () == FALSE)
		{
			PMLOGMSG (ZONE_WARN,
					  (_T ("%s: warning: pfnInitInterface() failed for interface\r\n"), pszFname));
		}
		else
		{
			// Pass back the pointer
			pdl->pInterface = pInterface;
			fOk = TRUE;
		}
	}
	return fOk;
}
Exemple #20
0
// 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;
    GUID gPMClass;
    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] = {0}; // 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;
}
Exemple #21
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;
}