?? phcd.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:
phcd.cpp
Abstract:
This file implements the USB host controller driver for the
Open HCI interface.
Notes:
--*/
// 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 <phcdddsi.h>
#include "hcdi.h"
#include "globals.hpp"
#include "mem.hpp"
#include "hub.hpp"
#include "phcdinc.hpp"
#include "phcd.hpp"
#include "bcr.h"
#undef ZONE_HUB
#define ZONE_HUB 0
#undef ZONE_TD
#define ZONE_TD 0
#undef ZONE_WARNING
#define ZONE_WARNING 2
#define ISPDBG 0
#define PLAT_STRONGARM
extern "C" PVOID VirtualAllocCopy(unsigned size,char *str,PVOID pVirtualAddress);
// 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 PHCI registry values
const TCHAR gcPhciKeyName[] = TEXT("Drivers\\PHCI");
const TCHAR gcPhciRsvdBandwidthValName[] = TEXT("ReservedBandwidth");
//#ifdef DEBUG
#if 1
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 PHCI 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("!PHCD: Exception copying client data: 0x%X-->0x%X (%u)\r\n"),
pSrc,pDst,cLen));
eRet = invalidPtr;
}
if (dwPerms)
SetProcPermissions(dwOldPerms);
return eRet;
}
ULONG CALLBACK CPhcd::UsbDriverThreadStub(PVOID context)
{
CPhcd* pHcd = (CPhcd*)context;
return(pHcd->UsbDriverThread());
}
#ifdef USE_CRITICAL_THREAD
ULONG CALLBACK CPhcd::UsbDriverCriticalThreadStub(PVOID context)
{
CPhcd* pHcd = (CPhcd*)context;
return(pHcd->UsbDriverCriticalThread());
}
#endif // USE_CRITICAL_THREAD
ULONG CALLBACK CPhcd::Isp1161AuxThreadStub (PVOID context)
{
CPhcd* pHcd = (CPhcd*)context;
return(pHcd->Isp1161AuxThread());
}
DWORD CPhcd::Isp1161AuxThread(void)
{
RETAILMSG(1, (TEXT("PHCD: Enter Isp1161AuxThread\r\n")));
while (!m_bClosing)
{
WaitForSingleObject(m_hUsbInterrupt, INFINITE);
RETAILMSG(1, (TEXT("PHCD: Got one interrupt\r\n")));
InterruptDone(m_sysIntr);
}
// DumpRegisters();
return 0;
}
CPhcd::CPhcd(LPVOID pvPhcdPddObject, 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_pvPhcdPddObject = pvPhcdPddObject;
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("PHCD: 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;
//Zouying
m_EdpointServicedOne1ms = 0;
m_TdsPutToATLIndex = 0;
m_TdsPutToITLFirstIndex = 0;
m_TdsPutToITLSecondIndex = 0;
m_ATLTransferLen = 0;
m_ATLBeingReadOut = FALSE;
m_bReDump = FALSE;
for(UINT i=0; i< sizeof(m_bsPTDReDump)/sizeof(BOOL); i++)
m_bsPTDReDump[i] = FALSE;
m_DataToggleBit = 1;
uFrameNumber = 0;
uTimes = 0;
m_HcBulkHeadED = 0;
m_HcBulkCurrentED = 0;
m_HcControlHeadED = 0;
m_HcControlCurrentED = 0;
m_HcHCCA = 0;
m_HcPeriodCurrentED = 0;
m_HcDoneHead = 0;
m_HcPeriodicStart = 0;
m_HcControlCBSR = 4;
m_HcControlPLE = 0;
m_HcControlIE = 0;
m_HcControlCLE = 0;
m_HcControlBLE = 0;
m_HcCommandCLF = 0;
m_HcCommandBLF = 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,gcPhciKeyName,0,KEY_READ,&hKey) == ERROR_SUCCESS)
{
DWORD dwSize = sizeof(m_nReserveFakeBandwidth);
if (RegQueryValueEx(hKey,gcPhciRsvdBandwidthValName,NULL,NULL,
(UCHAR *)&m_nReserveFakeBandwidth,&dwSize) == ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT,(TEXT("PHCD: 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
{
#ifdef PLAT_STRONGARM
//edge trigger, active high, 16-bits
WRITE_REGISTER_USHORT(HcWRHwConfig(m_regBase), 0x2F);
#else
//Hardware config write,
//level trigger, active high, 16-bits
WRITE_REGISTER_USHORT(HcWRHwConfig(m_regBase), 0x2D);
#endif
//Hardware config read
USHORT temp = READ_REGISTER_USHORT(HcRDHwConfig(m_regBase));
RETAILMSG(1, (TEXT("PHCD: Hardware config %x\r\n"), temp));
if(m_regBase)
{
DWORD dwRevision = READ_REGISTER_ULONG(HcRevision(m_regBase));
if((dwRevision & gcHcRevisonMask) != gcHcRevisonNominal)
m_regBase = 0;
}
if(m_regBase)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -