📄 chw.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// 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.
//
// Module Name:
// CHW.cpp
// Abstract:
// This file implements the UHCI specific register routines
//
// Notes:
//
//
#include "chw.hpp"
#include "cpipe.hpp"
#include "Cuhcd.hpp"
#include <nkintr.h>
CHW::CHW( IN const REGISTER portBase,
IN const DWORD dwSysIntr,
IN CPhysMem * const pCPhysMem,
//IN CUhcd * const pHcd,
IN LPVOID pvUhcdPddObject )
{
// definitions for static variables
DEBUGMSG( ZONE_INIT, (TEXT("+CHW::CHW base=0x%x, intr=0x%x\n"), portBase, dwSysIntr));
g_fPowerUpFlag = FALSE;
g_fPowerResuming = FALSE;
m_portBase = portBase;
//m_pHcd = pHcd;
m_pMem = pCPhysMem;
m_pPddContext = pvUhcdPddObject;
m_frameCounterHighPart = 0;
m_frameCounterLowPart = 0;
m_pFrameList = 0;
m_dwSysIntr = dwSysIntr;
m_hUsbInterruptEvent = NULL;
m_hUsbInterruptThread = NULL;
m_fUsbInterruptThreadClosing = FALSE;
m_fFrameLengthIsBeingAdjusted = FALSE;
m_fStopAdjustingFrameLength = FALSE;
m_hAdjustDoneCallbackEvent = NULL;
m_uNewFrameLength = 0;
m_dwCapability = 0;
m_bDoResume=FALSE;
}
//extern BOOL g_fPowerUpFlag;
//extern BOOL g_fPowerResuming;
// ******************************************************************
BOOL CHW::Initialize( )
// Purpose: Reset and Configure the Host Controller with the schedule.
//
// Parameters: portBase - base address for host controller registers
//
// dwSysIntr - system interrupt number to use for USB
// interrupts from host controller
//
// frameListPhysAddr - physical address of frame list index
// maintained by CPipe class
//
// pvUhcdPddObject - PDD specific structure used during suspend/resume
//
// Returns: TRUE if initialization succeeded, else FALSE
//
// Notes: This function is only called from the CUhcd::Initialize routine.
//
// This function is static
// ******************************************************************
{
DEBUGMSG( ZONE_INIT, (TEXT("+CHW::Initialize\n")));
DEBUGCHK( m_frameCounterLowPart == 0 &&
m_frameCounterHighPart == 0 );
ULONG frameListPhysAddr;
InitializeCriticalSection( &m_csFrameCounter );
// set up the frame list area.
if (m_pFrameList==NULL && m_pMem->AllocateSpecialMemory(FRAME_LIST_SIZE_IN_BYTES, (PUCHAR *) &m_pFrameList) == FALSE) {
DEBUGMSG(ZONE_ERROR, (TEXT("-CHW::Initialize, cannot allocate the frame list!!\n")));
m_pFrameList = 0;
frameListPhysAddr = 0;
return FALSE;
}
frameListPhysAddr = m_pMem->VaToPa((PUCHAR) m_pFrameList);
if ( m_portBase == 0 || frameListPhysAddr == 0 ) {
DEBUGMSG( ZONE_ERROR, (TEXT("-CHW::Initialize - zero Register Base or Frame List Address\n")));
return FALSE;
}
// UHCI spec 2.1.6 - save SOFMOD before resetting HC
UCHAR savedSOFMOD = Read_SOFMOD() & UHCD_SOFMOD_MASK;
// Signal Global Reset - do this ***BEFORE*** any other USB I/O register writing,
// since Global Reset will cause all registers to revert to their hardware-reset
// state.
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS, (TEXT("CHW::Initialize - signalling global reset\n")));
Write_USBCMD( Read_USBCMD() | UHCD_USBCMD_GLOBAL_RESET );
Sleep( 20 );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS, (TEXT("CHW::Initialize - end signalling global reset\n")));
Write_USBCMD( Read_USBCMD() & ~UHCD_USBCMD_GLOBAL_RESET );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS, (TEXT("CHW::Initialize - setting USBINTR to all interrupts on\n")));
// initialize interrupt register - set all interrupts to enabled
Write_USBINTR( UHCD_USBINTR_SHORT_PACKET_INTERRUPT
| UHCD_USBINTR_INTERRUPT_ON_COMPLETE
| UHCD_USBINTR_RESUME_INTERRUPT
| UHCD_USBINTR_TIMEOUT_CRC_INTERRUPT );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("CHW::Initialize - setting FRNUM = 0\n")));
// initialize FRNUM register with index 0 of frame list
Write_FRNUM( 0x0000 );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("CHW::Initialize - setting FLBASEADD = 0x%X\n"), frameListPhysAddr));
// initialize FLBASEADD with address of frame list
DEBUGCHK( frameListPhysAddr != 0 );
// frame list should be aligned on a 4Kb boundary
DEBUGCHK( (frameListPhysAddr & UHCD_FLBASEADD_MASK) == frameListPhysAddr );
Write_FLBASEADD( frameListPhysAddr );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("CHW::Initialize - setting SOFMOD to 0x%x\n"), savedSOFMOD ));
Write_SOFMOD( savedSOFMOD );
// m_hUsbInterrupt - Auto Reset, and Initial State = non-signaled
DEBUGCHK( m_hUsbInterruptEvent == NULL );
m_hUsbInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( m_hUsbInterruptEvent == NULL ) {
DEBUGMSG(ZONE_ERROR, (TEXT("-CHW::Initialize. Error creating USBInterrupt event\n")));
return FALSE;
}
InterruptDisable( m_dwSysIntr ); // Just to make sure this is really ours.
// Initialize Interrupt. When interrupt id # m_sysIntr is triggered,
// m_hUsbInterruptEvent will be signaled. Last 2 params must be NULL
if ( !InterruptInitialize( m_dwSysIntr, m_hUsbInterruptEvent, NULL, NULL) ) {
DEBUGMSG(ZONE_ERROR, (TEXT("-CHW::Initialize. Error on InterruptInitialize\r\n")));
return FALSE;
}
// Start up our IST - the parameter passed to the thread
// is unused for now
DEBUGCHK( m_hUsbInterruptThread == NULL &&
m_fUsbInterruptThreadClosing == FALSE );
if (m_hUsbInterruptThread==NULL)
m_hUsbInterruptThread = CreateThread( 0, 0, UsbInterruptThreadStub, this, 0, NULL );
if ( m_hUsbInterruptThread == NULL ) {
DEBUGMSG(ZONE_ERROR, (TEXT("-CHW::Initialize. Error creating IST\n")));
return FALSE;
}
CeSetThreadPriority( m_hUsbInterruptThread, g_IstThreadPriority );
DEBUGMSG( ZONE_INIT, (TEXT("-CHW::Initialize, success!\n")));
return TRUE;
}
CHW::~CHW()
{
if (m_dwSysIntr)
KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &m_dwSysIntr, sizeof(m_dwSysIntr), NULL, 0, NULL);
DeInitialize();
}
// ******************************************************************
void CHW::DeInitialize( void )
//
// Purpose: Delete any resources associated with static members
//
// Parameters: none
//
// Returns: nothing
//
// Notes: This function is only called from the ~CUhcd() routine.
//
// This function is static
// ******************************************************************
{
m_fUsbInterruptThreadClosing = TRUE; // tell USBInterruptThread that we are closing
// tell adjustment thread (if it exists) to close
InterlockedExchange( &m_fStopAdjustingFrameLength, TRUE );
if ( m_fFrameLengthIsBeingAdjusted ) {
Sleep( 20 ); // give adjustment thread time to close
DEBUGCHK( !m_fFrameLengthIsBeingAdjusted );
}
// m_hAdjustDoneCallbackEvent <- don't need to do anything to this
// m_uNewFrameLength <- don't need to do anything to this
// Wake up the interrupt thread and give it time to die.
if ( m_hUsbInterruptEvent ) {
SetEvent(m_hUsbInterruptEvent);
if ( m_hUsbInterruptThread ) {
DWORD dwWaitReturn = WaitForSingleObject(m_hUsbInterruptThread, 1000);
if ( dwWaitReturn != WAIT_OBJECT_0 ) {
DEBUGCHK( 0 );
TerminateThread(m_hUsbInterruptThread, DWORD(-1));
}
CloseHandle(m_hUsbInterruptThread);
m_hUsbInterruptThread = NULL;
}
// we have to close our interrupt before closing the event!
InterruptDisable( m_dwSysIntr );
CloseHandle(m_hUsbInterruptEvent);
m_hUsbInterruptEvent = NULL;
} else {
InterruptDisable( m_dwSysIntr );
}
// no need to free the frame list; the entire pool will be freed as a unit.
m_pFrameList = 0;
DeleteCriticalSection( &m_csFrameCounter );
m_fUsbInterruptThreadClosing = FALSE;
m_frameCounterLowPart = 0;
m_frameCounterHighPart = 0;
}
// ******************************************************************
void CHW::EnterOperationalState( void )
//
// Purpose: Signal the host controller to start processing the schedule
//
// Parameters: None
//
// Returns: Nothing.
//
// Notes: This function is only called from the CUhcd::Initialize routine.
// It assumes that CPipe::Initialize and CHW::Initialize
// have already been called.
//
// This function is static
// ******************************************************************
{
DEBUGMSG( ZONE_INIT, (TEXT("+CHW::EnterOperationalState\n")));
USHORT usData;
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("CHW::EnterOperationalState - clearing status reg\n")));
Clear_USBSTS( );
DEBUGMSG(ZONE_INIT && ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("CHW::EnterOperationalState - setting USBCMD run bit\n")));
usData = Read_USBCMD();
// if reclamation size is 32, we shouldn't set the USBCMD bit
DEBUGCHK( UHCD_MAX_RECLAMATION_PACKET_SIZE == 64 );
Write_USBCMD( usData | UHCD_USBCMD_MAX_RECLAMATION_SIZE_64 | UHCD_USBCMD_RUN_STOP | UHCD_USBCMD_CONFIGURE_FLAG );
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
// ******************************************************************
{
if ( m_portBase != 0 ) {
WORD wUSBCmd = 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(wUSBCmd & UHCD_USBCMD_RUN_STOP)
{
// clear run bit
Write_USBCMD( wUSBCmd & ~UHCD_USBCMD_RUN_STOP );
// clear all interrupts
Write_USBINTR( 0x0000 );
// spin until the controller really is stopped
while ( ! (Read_USBSTS() & UHCD_USBSTS_HCHALTED) )
;
}
}
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -