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

📄 ohcd.cpp

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1998  Microsoft Corporation

Module Name:  
    ohcd.cpp
Abstract:  
    This file implements the USB host controller driver for the
    Open HCI interface.
    
Notes: 

Revision History:

	2/03/00	dma		Modified for HD64465 differences from sample code
	2/07/00	dma		Fixed debouncing and insertion at boot problems
	4/24/00 dma		Ported HD64465 changes to WinCE 3.0

--*/


// There are four warnings that I like from Warning level 4.  Since we build
// at warning level 3, I'm setting these four down to level 3 so I still get
// them.
// C4100 unrefrenced formal parameter
// C4101 unrefrenced local variable
// C4705 statement has no effect
// C4706 assignment in conditional
#pragma warning (3 : 4100 4101 4705 4706)

#include <windows.h>
extern "C" {  // nkintr.h now contains this, but autopc doesn't have the latest,
              // so include here as well for now.
#include <nkintr.h>
}
#include <ceddk.h>
#include <ohcdddsi.h>

#include "hcdi.h"
#include "globals.hpp"
#include "mem.hpp"
#include "hub.hpp"
#include "ohcdinc.hpp"
#include "ohcd.hpp"

// This flag will cause our free routines to overwrite structures with invalid
// data, to verify that no one is still accessing them.  For test only.
#undef  OVERWRITE_STRUCTS_ON_FREE
#ifdef  OVERWRITE_STRUCTS_ON_FREE
#define INVALID_STRUCT_DATA 0xff
#endif

// Define the following constant to be gcTdNoInterrupt to cause the HC to
// be interrupted only at the end of each transfer; this has some unpleasant
// side effects at the moment due to the way in which transfers are aborted
// and the fact that we don't track TDs well enough; nonetheless, you can get
// a performance gain with that setting if you don't do frequent power-suspend
// operations or hot-plugging of USB devices.
// Define the constant to be zero to get interrupts on every single TD.
// Note that we always arrange for an interrupt on the last TD of any transfer.
#define TDIRQ_NORM 0

#define NUM_ELEMENTS(a)  ((sizeof(a) / sizeof(a[0])))

const TCHAR gcszUSBDFileName[]     = TEXT("USBD.DLL");
const TCHAR gcszHcdAttach[]        = TEXT("HcdAttach");
const TCHAR gcszHcdDetach[]        = TEXT("HcdDetach");
const TCHAR gcszHcdDeviceAttach[]  = TEXT("HcdDeviceAttached");
const TCHAR gcszHcdDeviceDettach[] = TEXT("HcdDeviceDetached");

// Definitions for accessing OHCI registry values
const TCHAR gcOhciKeyName[]              = TEXT("Drivers\\OHCI");
const TCHAR gcOhciRsvdBandwidthValName[] = TEXT("ReservedBandwidth");


#ifdef DEBUG
static const TCHAR *szCfgStateStrings[] =
{
   TEXT("NoState"),
   TEXT("UsingAddr0"),
   TEXT("GettingInitialDescriptor"),
   TEXT("SettingAddress"),
   TEXT("GettingDeviceDescriptor"),
   TEXT("GettingInitialConfig"),
   TEXT("GettingConfig"),
   TEXT("SettingConfig"),
   TEXT("DoneConfig"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("HubGettingDescriptor"),
   TEXT("HubConfiguring"),
   TEXT("HubPoweringPorts"),
   TEXT("HubReady"),
   TEXT("HubClearingChanges"),
   TEXT("HubGettingPortStatus"),
   TEXT("HubStartingPortReset"),
   TEXT("HubResettingPort"),
   TEXT("HubWaitingForPortReset"),
   TEXT("HubWaitingForPortShutoff"),
   TEXT("HubKillingPort"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("Unused"),
   TEXT("HubWaitingForHubClearFlags"),
   TEXT("HubClearingLocalPowerFlag"),
   TEXT("HubClearingOverCurrentFlag"),
};

#define CONFIG_STATE_STR(pDev)  (( pDev->configStatus < NUM_ELEMENTS(szCfgStateStrings)) ? \
                                   szCfgStateStrings[pDev->configStatus] : TEXT("Invalid"))
#endif

// Inline function to copy data to or from a client buffer.  Return successful
// if copy was successful, or invalidBuffer if an exception occurs while copying
// the data.
//
// Note the dwPerms parameter - this is used for the OHCI interrupt thread, which
// may have different process permissions than the client that initiated the 
// transfer (e.g. if client driver exposes another interface and some application
// calls through with a buffer).  This isn't necessary as long as we are in the
// context of the thread that owns the memory, since permissions are automatically
// added in a PSL call.
static inline EError
CopyClientData(PUCHAR pDst, PUCHAR pSrc, UINT cLen, DWORD dwPerms)
{
    DWORD dwOldPerms;
    EError eRet;

    // Set process permissions for accessing client buffer, if necessary
    if (dwPerms)
        dwOldPerms = SetProcPermissions(dwPerms);
    __try {
        memcpy(pDst,pSrc,cLen);
        eRet = successful;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        ERRORMSG(1,(TEXT("!OHCD: Exception copying client data: 0x%X-->0x%X (%u)\r\n"),
                     pSrc,pDst,cLen));
        eRet = invalidPtr;
    }
    if (dwPerms)
        SetProcPermissions(dwOldPerms);
    return eRet;
}
static inline EError
CopyClientDWORD(PDWORD pDst, PBYTE pSrc, UINT cLen, DWORD dwPerms)
{
    DWORD dwOldPerms;
	register UINT uCount1,uCount2;
    EError eRet;
	union {
		DWORD dwData;
		BYTE bDatas[sizeof(DWORD)];
	} dwTemp;

    // Set process permissions for accessing client buffer, if necessary
    if (dwPerms)
        dwOldPerms = SetProcPermissions(dwPerms);
    __try {
		for (uCount2=0;uCount2<cLen;) {
			dwTemp.dwData=0;
			for (uCount1=0;uCount1<sizeof(DWORD) && uCount2<cLen;uCount1++,uCount2++) 
				dwTemp.bDatas[uCount1]=*(pSrc++);
			*(pDst++)=dwTemp.dwData;
		}
        eRet = successful;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        ERRORMSG(1,(TEXT("!OHCD: Exception copying client data: 0x%X-->0x%X (%u)\r\n"),
                     pSrc,pDst,cLen));
        eRet = invalidPtr;
    }
    if (dwPerms)
        SetProcPermissions(dwOldPerms);
    return eRet;
}

ULONG CALLBACK COhcd::UsbDriverThreadStub(PVOID context)
{
    COhcd* pHcd = (COhcd*)context;
    return(pHcd->UsbDriverThread());
}

#ifdef USE_CRITICAL_THREAD
ULONG CALLBACK COhcd::UsbDriverCriticalThreadStub(PVOID context)
{
    COhcd* pHcd = (COhcd*)context;
    return(pHcd->UsbDriverCriticalThread());
}
#endif // USE_CRITICAL_THREAD

COhcd::COhcd(LPVOID pvOhcdPddObject, CPhysMem * pobMem,
        LPCWSTR szDriverRegistryKey, REGISTER regBase, DWORD dwSysIntr)
{
    extern HCD_FUNCS gc_HcdFuncs;

    //save this to pass on the the USBD
    UnusedParameter(szDriverRegistryKey);

    UINT index;

    m_pHcdFuncs = &gc_HcdFuncs;

    m_pvOhcdPddObject = pvOhcdPddObject;
    m_pobMem = pobMem;
    m_regBase = regBase;
    m_sysIntr = dwSysIntr;

    m_nAdjustFrame = 0;
    m_fAdjust = FALSE;
    m_hAdjustmentEvent = NULL;

    m_numRootHubPorts = 0;
    m_PowerOnToPowerGoodTime = 0;
    m_bAddr0Busy = FALSE;
    m_addrThatOwnsAddr0 = 0;
    m_numPortsWaitingForAddr0 = 0;
    m_addr0CurRetryValue = 0;
    m_schedOverrunCount = 0;

    m_pHcca = NULL;
    m_paLastIntrEd = NULL;
                                                      
    DEBUGMSG(ZONE_INIT, (TEXT("OHCD: SysIntr = %d, regBase = 0x%X\r\n"),
             dwSysIntr, regBase));

    m_bClosing = FALSE;
    m_bPoweredUpAfterPowerDown = FALSE;
    m_fStabilizing = FALSE;

    m_fTimeWarp = FALSE;
    m_fWDH = FALSE;
    m_fSF = FALSE;
    m_fRHSC = FALSE;
    m_fSO = FALSE;
    m_fUE = FALSE;
    m_fFNO = FALSE;

    m_paWriteBackDone = 0;
    m_paWriteBackDone2 = 0;
    m_paLastWriteBackDone = 0;

    m_hClientDriverComplete = NULL;
    m_hUsbPsudoInterrupt = NULL;
    
    m_fCriticalRunning = FALSE;
#ifdef USE_CRITICAL_THREAD
    m_cCriticalTds = 0;
    m_hReleaseCriticalThread = NULL;
    m_hCriticalThreadDone = NULL;
    m_hCriticalThread = NULL;
#endif

    m_hUsbInterrupt = NULL;
    m_hIsrThread = NULL;

    m_nReserveFakeBandwidth = 0;
    // Allow fake bandwidth to be initialized via registry.  This gives platforms
    // a way to account for delays in accessing the host bus, etc.
    HKEY hKey;
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,gcOhciKeyName,0,KEY_READ,&hKey) == ERROR_SUCCESS) {
        DWORD dwSize = sizeof(m_nReserveFakeBandwidth);
        if (RegQueryValueEx(hKey,gcOhciRsvdBandwidthValName,NULL,NULL,
                            (UCHAR *)&m_nReserveFakeBandwidth,&dwSize) == ERROR_SUCCESS) {
            DEBUGMSG(ZONE_INIT,(TEXT("OHCD: Reserved bandwidth read from registry: %u\r\n"),
                                m_nReserveFakeBandwidth));
        }
        RegCloseKey(hKey);
    }
    m_dwFrameNumber = 0;

    m_pFreeSEdInfoHead = NULL;
    m_pFreePhysAddrHead = NULL;
    m_pFreeTransferHead = NULL;
    m_pFreeSTdInfoHead = NULL;

    m_curMaxNumDevices = gcInitialMaxNumDevices;
    m_ppDevices = new SDevice * [gcInitialMaxNumDevices];
    for (index = 0; index < gcInitialMaxNumDevices; index++)
    {
        m_ppDevices[index] = NULL;
    }

    m_pTdProcessList = NULL;
    m_pEdRemovalList = NULL;

    m_hUSBDInstance = NULL;
    m_pAttachProc = NULL;
    m_pDetachProc = NULL;

    m_pFreeThreadParamsHead = NULL;
    m_pActiveThreadParamsHead = NULL;

    InitializeCriticalSection(&m_csSTdInfoListLock);
    InitializeCriticalSection(&m_csThreadParamListLock);
    InitializeCriticalSection(&m_csAddr0Lock);
    InitializeCriticalSection(&m_csDeviceListLock);
    InitializeCriticalSection(&m_csOtherListsLock);
    InitializeCriticalSection(&m_csFrameAdjustment);
    InitializeCriticalSection(&m_csPortPower);
    InitializeCriticalSection(&m_csEdInfoListsLock);
    InitializeCriticalSection(&m_csTdListsLock);
    InitializeCriticalSection(&m_csScheduleLock);

#ifdef USE_CRITICAL_THREAD
    InitializeCriticalSection(&m_csClientInstallCriticalThread);
    InitializeCriticalSection(&m_csCriticalTds);
#endif // USE_CRITICAL_THREAD

    // now we check for certain values to ensure that the HC is present

    __try
    {
        if(m_regBase)
        {
            DWORD dwRevision = READ_REGISTER_ULONG(HcRevision(m_regBase));
            if((dwRevision & gcHcRevisonMask) != gcHcRevisonNominal)
                m_regBase = 0;
        }

        if(m_regBase)
        {
            DWORD dwInterval = READ_REGISTER_ULONG(HcFmInterval(m_regBase));
            dwInterval &= gcHcFmIntervalFImask;
            if(dwInterval != gcHcFmIntervalNominal)
                m_regBase = 0;
        }

        if(m_regBase)
        {
            DWORD dwThreshold = READ_REGISTER_ULONG(HcLSThreshold(m_regBase));
#if 0 // the CMD HC uses a non-standard threshold; hosts using their chip cannot make this check.
            if((dwThreshold & gcHcLSThresholdLSTmask) != gcHcLSThresholdNominal)
                m_regBase = 0;
#endif
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        m_regBase = 0;
    }
}


COhcd::~COhcd()
{
    DWORD   dwWaitReturn;
    UINT    dev, endpt;
    SDevice *pDev;
    SEndpoint *pEndpt;

    m_bClosing = TRUE;

    // Most of this destructor is never used!  We can remove
    // the parts that are never called...

    // Wake up the interrupt thread and give it time to die.
    if(m_hUsbInterrupt)
        SetEvent(m_hUsbInterrupt);

    // set the psudo interrupt to free it too
    if(m_hUsbPsudoInterrupt)
        SetEvent(m_hUsbPsudoInterrupt);

    if (m_hIsrThread)
    {
        dwWaitReturn = WaitForSingleObject(m_hIsrThread, 1000);
        if (dwWaitReturn != WAIT_OBJECT_0)
        {
            TerminateThread(m_hIsrThread, DWORD(-1));
        }

⌨️ 快捷键说明

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