📄 chw.cpp
字号:
usbcmd.bit.IntThreshCtrl = 8; // 8 Micro Frame
usbcmd.bit.RunStop = 1;
Write_USBCMD( usbcmd );
DEBUGMSG( ZONE_INIT, (TEXT("-CHW::EnterOperationalState\n")));
}
// ******************************************************************
void CHW::StopHostController( void )
//
// Purpose: Signal the host controller to stop processing the schedule
//
// Parameters: None
//
// Returns: Nothing.
//
// Notes:
//
// This function is static
// ******************************************************************
{
USBCMD usbcmd=Read_USBCMD();
// Check run bit. Despite what the UHCI spec says, Intel's controller
// does not always set the HCHALTED bit when the controller is stopped.
if(usbcmd.bit.RunStop) {
// clear run bit
usbcmd.bit.RunStop= 0;
Write_USBCMD( usbcmd );
USBINTR usbIntr;
usbIntr.ul=0;
// clear all interrupts
Write_USBINTR(usbIntr);
// spin until the controller really is stopped
while( Read_USBSTS().bit.HCHalted == 0 ) //Wait until it stop.
Sleep(0);
}
}
BOOL CHW::AsyncBell()
{
m_DoorBellLock.Lock();
ResetEvent(m_hAsyncDoorBell);
USBCMD usbcmd=Read_USBCMD();
usbcmd.bit.IntOnAADoorbell=1;
Write_USBCMD( usbcmd );
DWORD dwReturn=WaitForSingleObject( m_hAsyncDoorBell,10);
m_DoorBellLock.Unlock();
return (dwReturn == WAIT_OBJECT_0);
}
BOOL CHW::AsyncDequeueQH( CQH * pQh)
{
BOOL bReturn= m_cAsyncMgr.DequeueQHead( pQh);
if (bReturn) {
AsyncBell();
}
return bReturn;
};
BOOL CHW::PeriodQueueITD(CITD * piTD,DWORD FrameIndex)
{
FRINDEX frameIndex= Read_FRINDEX();
if (((FrameIndex - frameIndex.bit.FrameIndex) & m_FrameListMask) > 1)
return m_cPeriodicMgr.QueueITD(piTD,FrameIndex);
else
return FALSE;// To Close EHCI 4.7.2.1
};
BOOL CHW::PeriodQueueSITD(CSITD * psiTD,DWORD FrameIndex)
{
FRINDEX frameIndex= Read_FRINDEX();
if (((FrameIndex - frameIndex.bit.FrameIndex) & m_FrameListMask) > 1)
return m_cPeriodicMgr.QueueSITD(psiTD,FrameIndex);
else
return FALSE;
};
BOOL CHW::PeriodDeQueueTD(DWORD dwPhysAddr,DWORD FrameIndex)
{
FRINDEX frameIndex= Read_FRINDEX();
while (((FrameIndex - frameIndex.bit.FrameIndex) & m_FrameListMask) <=1) {
Sleep(1);
frameIndex= Read_FRINDEX();
}
return m_cPeriodicMgr.DeQueueTD(dwPhysAddr, FrameIndex);
};
DWORD CALLBACK CHW::CeResumeThreadStub ( IN PVOID context )
{
return ((CHW *)context)->CeResumeThread ( );
}
// ******************************************************************
DWORD CHW::CeResumeThread ( )
//
// Purpose: Force the HCD to reset and regenerate itself after power loss.
//
// Parameters: None
//
// Returns: Nothing.
//
// Notes: Because the PDD is probably maintaining pointers to the Hcd and Memory
// objects, we cannot free/delete them and then reallocate. Instead, we destruct
// them explicitly and use the placement form of the new operator to reconstruct
// them in situ. The two flags synchronize access to the objects so that they
// cannot be accessed before being reconstructed while also guaranteeing that
// we don't miss power-on events that occur during the reconstruction.
//
// This function is static
// ******************************************************************
{
// reconstruct the objects at the same addresses where they were before;
// this allows us not to have to alert the PDD that the addresses have changed.
DEBUGCHK( g_fPowerResuming == FALSE );
// order is important! resuming indicates that the hcd object is temporarily invalid
// while powerup simply signals that a powerup event has occurred. once the powerup
// flag is cleared, we will repeat this whole sequence should it get resignalled.
g_fPowerUpFlag = FALSE;
g_fPowerResuming = TRUE;
DeviceDeInitialize();
while (1) { // breaks out upon successful reinit of the object
if (DeviceInitialize())
break;
// getting here means we couldn't reinit the HCD object!
ASSERT(FALSE);
DEBUGMSG(ZONE_ERROR, (TEXT("USB cannot reinit the HCD at CE resume; retrying...\n")));
DeviceDeInitialize();
Sleep(15000);
}
// the hcd object is valid again. if a power event occurred between the two flag
// assignments above then the IST will reinitiate this sequence.
g_fPowerResuming = FALSE;
if (g_fPowerUpFlag)
PowerMgmtCallback(TRUE);
return 0;
}
DWORD CHW::UsbInterruptThreadStub( IN PVOID context )
{
return ((CHW *)context)->UsbInterruptThread();
}
// ******************************************************************
DWORD CHW::UsbInterruptThread( )
//
// Purpose: Main IST to handle interrupts from the USB host controller
//
// Parameters: context - parameter passed in when starting thread,
// (currently unused)
//
// Returns: 0 on thread exit.
//
// Notes:
//
// This function is private
// ******************************************************************
{
DEBUGMSG(ZONE_INIT && ZONE_VERBOSE, (TEXT("+CHW::Entered USBInterruptThread\n")));
while ( !m_fUsbInterruptThreadClosing ) {
WaitForSingleObject(m_hUsbInterruptEvent, INFINITE);
if ( m_fUsbInterruptThreadClosing ) {
break;
}
USBSTS usbsts = Read_USBSTS();
#ifdef DEBUG
DWORD dwFrame;
GetFrameNumber(&dwFrame); // calls UpdateFrameCounter
DEBUGMSG( ZONE_REGISTERS, (TEXT("!!!interrupt!!!! on frame index + 1 = 0x%08x, USBSTS = 0x%04x\n"), dwFrame, usbsts.ul ) );
if (usbsts.bit.HSError) { // Error Happens.
DumpAllRegisters( );
ASSERT(FALSE);
}
#else
UpdateFrameCounter();
#endif // DEBUG
if (usbsts.bit.PortChanged) {
SetEvent(m_hUsbHubChangeEvent);
}
Write_USBSTS(usbsts);// Clear_USBSTS( );
if (usbsts.bit.ASAdvance) {
SetEvent(m_hAsyncDoorBell);
}
// TODO - differentiate between USB interrupts, which are
// for transfers, and host interrupts (UHCI spec 2.1.2).
// For the former, we need to call CPipe::SignalCheckForDoneTransfers.
// For the latter, we need to call whoever will handle
// resume/error processing.
// For now, we just notify CPipe so that transfers
// can be checked for completion
// This flag gets cleared in the resume thread.
if(g_fPowerUpFlag)
{
if (m_bDoResume) {
g_fPowerUpFlag=FALSE;
USBCMD USBCmd = Read_USBCMD();
USBCmd.bit.RunStop=1;
Sleep(20);
Write_USBCMD(USBCmd);
}
else {
if (g_fPowerResuming) {
// this means we've restarted an IST and it's taken an early interrupt;
// just pretend it didn't happen for now because we're about to be told to exit again.
continue;
}
HcdPdd_InitiatePowerUp((DWORD) m_pPddContext);
HANDLE ht;
while ((ht = CreateThread(NULL, 0, CeResumeThreadStub, this, 0, NULL)) == NULL) {
RETAILMSG(1, (TEXT("HCD IST: cannot spin a new thread to handle CE resume of USB host controller; sleeping.\n")));
Sleep(15000); // 15 seconds later, maybe it'll work.
}
CeSetThreadPriority( ht, g_IstThreadPriority );
CloseHandle(ht);
// The CE resume thread will force this IST to exit so we'll be cooperative proactively.
break;
}
}
else
//CPipe::SignalCheckForDoneTransfers( );
SignalCheckForDoneTransfers( );
InterruptDone(m_dwSysIntr);
}
DEBUGMSG(ZONE_INIT && ZONE_VERBOSE, (TEXT("-CHW::Leaving USBInterruptThread\n")));
return (0);
}
// ******************************************************************
void CHW::UpdateFrameCounter( void )
//
// Purpose: Updates our internal frame counter
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: The UHCI frame number register is only 11 bits, or 2047
// long. Thus, the counter will wrap approx. every 2 seconds.
// That is insufficient for Isoch Transfers, which
// may need to be scheduled out into the future by more
// than 2 seconds. So, we maintain an internal 32 bit counter
// for the frame number, which will wrap in 50 days.
//
// This function should be called at least once every two seconds,
// otherwise we will miss frames.
//
// ******************************************************************
{
#ifdef DEBUG
DWORD dwTickCountLastTime = GetTickCount();
#endif
EnterCriticalSection( &m_csFrameCounter );
#ifdef DEBUG
// If this fails, we haven't been called in a long time,
// so the frame number is no longer accurate
if (GetTickCount() - dwTickCountLastTime >= 800 )
DEBUGMSG(1, (TEXT("!UHCI - CHW::UpdateFrameCounter missed frame count;")
TEXT(" isoch packets may have been dropped.\n")));
dwTickCountLastTime = GetTickCount();
#endif // DEBUG
DWORD currentFRNUM = Read_FRINDEX().bit.FrameIndex;
DWORD dwCarryBit = m_FrameListMask + 1;
if ((currentFRNUM & dwCarryBit ) != (m_frameCounterHighPart & dwCarryBit ) ) { // Overflow
m_frameCounterHighPart += dwCarryBit;
}
m_frameCounterLowPart = currentFRNUM;
LeaveCriticalSection( &m_csFrameCounter );
}
// ******************************************************************
BOOL CHW::GetFrameNumber( OUT LPDWORD lpdwFrameNumber )
//
// Purpose: Return the current frame number
//
// Parameters: None
//
// Returns: 32 bit current frame number
//
// Notes: See also comment in UpdateFrameCounter
// ******************************************************************
{
EnterCriticalSection( &m_csFrameCounter );
// This algorithm is right out of the Win98 uhcd.c code
UpdateFrameCounter();
DWORD frame = m_frameCounterHighPart + (m_frameCounterLowPart & m_FrameListMask);
LeaveCriticalSection( &m_csFrameCounter );
*lpdwFrameNumber=frame;
return TRUE;
}
// ******************************************************************
BOOL CHW::GetFrameLength( OUT LPUSHORT lpuFrameLength )
//
// Purpose: Return the current frame length in 12 MHz clocks
// (i.e. 12000 = 1ms)
//
// Parameters: None
//
// Returns: frame length
//
// Notes: Only part of the frame length is stored in the hardware
// register, so an offset needs to be added.
// ******************************************************************
{
*lpuFrameLength=60000;
return TRUE;
}
// ******************************************************************
BOOL CHW::SetFrameLength( IN HANDLE , IN USHORT )
//
// Purpose: Set the Frame Length in 12 Mhz clocks. i.e. 12000 = 1ms
//
// Parameters: hEvent - event to set when frame has reached required
// length
//
// uFrameLength - new frame length
//
// Returns: TRUE if frame length changed, else FALSE
//
// Notes:
// ******************************************************************
{
return FALSE;
}
// ******************************************************************
BOOL CHW::StopAdjustingFrame( void )
//
// Purpose: Stop modifying the host controller frame length
//
// Parameters: None
//
// Returns: TRUE
//
// Notes:
// ******************************************************************
{
return FALSE;
}
// ******************************************************************
BOOL CHW::DidPortStatusChange( IN const UCHAR port )
//
// Purpose: Determine whether the status of root hub port # "port" changed
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -