📄 ohcd.cpp
字号:
/*++
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 + -