?? nscdevice.cpp
字號(hào):
/*******************************************************************************
* @doc
*
* @module NSCDevice.cpp |
*
* This module contains <o UsdNSCDevice> object methods and helpers that
* implement the IStiUSDDevice interface which is one of the standard
* STI interfaces
*
* Copyright (c) National Semiconductor Corporation 1999-2000
* All rights reserved
*
******************************************************************************/
#include "NSCStiU.h"
#include "NscDevice.h"
#include "NSCUtils.h"
#include "NSCUsbIO.h"
// Uncomment this if the device has to be polled for events otherwise it will
// be assumed that the device will generate events
#define NS_POLL_FOR_EVENTS
const DWORD NS_READ_DATA_TIMEOUT = 20000; // in milliseconds
const DWORD NS_WRITE_DATA_TIMEOUT = 20000; // in milliseconds
const DWORD NS_READ_CMD_TIMEOUT = 20000; // in milliseconds
const DWORD NS_WRITE_CMD_TIMEOUT = 20000; // in milliseconds
const DWORD NS_THREADWAIT_TIMEOUT = 5000; // in milliseconds
const DWORD NS_MAX_ERRORSTRING = 254; // characters
const UCHAR NS_MAX_INTERRUPT_PACKET = 1; // bytes
const DWORD NS_MAX_LOCKTIMEOUT = 1000; // in milliseconds
const DWORD NS_POLLING_INTERVAL = 500; // in milliseconds
const DWORD NS_DEFAULT_KICKSTART = 250; // in milliseconds
const DWORD NS_DEFAULT_DEBOUNCE = 5000; // in milliseconds
const DWORD NS_MIN_DEBOUNCE = 500; // in milliseconds
const DWORD NS_MAX_DEBOUNCE = 10000; // in milliseconds
// The "Significant Events" recognized by the interrupt thread
const DWORD NS_DEVICE_INTERRUPT = 0x0001; // Process a device event
const DWORD NS_SHUTDOWN_REQUEST = 0x0002; // Shutdown the interrupt thread
const DWORD NS_WAIT_ERROR = 0x0003; // Error while polling/waiting
// for events
const DWORD NS_IOCONTROL_ERROR = 0x004; // Error while using the IOcontrol
// call to talk to the device
// Temporary define for the device descriptor the next version
// of the DDK should have this value defined
const UCHAR NS_USB_DEVICE = 1;
// Constants for reading and writing registers from the
// LM9831 using the bulk endpoints
const UCHAR COMMAND_BYTE_COUNT = 4;
const BYTE LM_COMMAND_REGISTER = 7;
const BYTE LM_IOSTATUS_REGISTER = 2;
const BYTE NS_MISC_IO_BIT[] = { 0x04, 0x08, 0x10};
const BYTE NS_EVENT_BIT[] = { 0x01, 0x02, 0x04};
const BYTE NS_RESET_BIT = 0x20 ;
// The first byte for the bulk register reads is the mode
// byte and this is bit mapped
// Bit 0 , 1 - Read, 0 - Write
// Bit 1 , 1 - Inc, 0 - No Inc
const BYTE MODE_INC_READ = 0x03;
const BYTE MODE_NOINC_READ = 0x01;
const BYTE MODE_INC_WRITE = 0x02;
const BYTE MODE_NOINC_WRITE = 0x00;
const TCHAR NSCUSD_MUTEX[] = TEXT("NSCSTIU_MUTEX_");
const TCHAR NSCUSD_POLLING_MUTEX[] = TEXT("NSCSTIU_POLLING_MUTEX_");
const TCHAR NSCUSD_KICKSTART_MUTEX[] = TEXT("NSCSTIU_KICKSTART_MUTEX_");
const BYTE NS_ENABLE_REMOTEWAKEUP = 3;
const BYTE NS_DISABLE_REMOTEWAKEUP = 1;
// The prototype for the interrupt thread fucntion
VOID InterruptThreadFunc(LPVOID lpParameter);
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::UsdNSCDevice is the constructor for this class
PARAMETERS:
LPUNKNOWN punkOuter - This is the pointer to the controlling unknown, if we are
being aggregated otherwise this will be NULL - For more info on COM
aggregation, see Inside COM by Dale Rogerson of other articles on the MSDN
RETURN VALUE:
none
NOTES:
This constructor handles COM delegation using the non delgating unknonw
base class. The only other thing that is done here is the creation of the
event objects that we will need to use later on to signal the event thread
to shutdown
*******************************************************************************/
UsdNSCDevice::UsdNSCDevice( LPUNKNOWN punkOuter ):
m_cRef(1),
m_punkOuter(NULL),
m_fValid(FALSE),
m_pDcb(NULL),
m_DeviceDataHandle(INVALID_HANDLE_VALUE),
m_pszDeviceNameA(NULL),
m_hSignalEvent(INVALID_HANDLE_VALUE),
m_hThread(NULL),
m_guidLastEvent(GUID_NULL),
m_bEventMask(0),
m_bEventsInitialized(false),
m_hMutex(NULL),
m_dwDebounceTime(NS_DEFAULT_DEBOUNCE),
m_bPolling(false),
m_bRemoteWakeup(false),
m_bWHQLTest(false),
m_dwKickStartTime(NS_DEFAULT_KICKSTART),
m_hKickStartMutex(NULL)
{
NSC_TRACE("In UsdNSCDevice::UsdNSCDevice");
for (int index = 0; index < NS_MAX_OPEN_APPS ; index++)
m_hPollingMutex[index] = NULL;
//
// See if we are aggregated. If we are ( which will be almost always the case )
// save pointer to controlling Unknown , so subsequent calls will be delegated
// If not, set the same pointer to "this" .
// N.b. cast below is important in order to point to right virtual table
//
if (punkOuter)
{
m_punkOuter = punkOuter;
}
else
{
m_punkOuter = reinterpret_cast<IUnknown*>
(static_cast<INonDelegatingUnknown*>
(this));
}
m_hShutdownEvent = CreateEvent( NULL, // Attributes
TRUE, // Manual reset
FALSE, // Initial state - not set
NULL ); // Anonymous
if (m_hShutdownEvent && (INVALID_HANDLE_VALUE !=m_hShutdownEvent))
{
// We are now properly initialized and ready for action
m_fValid = TRUE;
}
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::~UsdNSCDevice is the destructor for this object class
PARAMETERS:
VOID
RETURN VALUE:
none
NOTES:
This method cleans up after this object. The main actions performed here are
1) shutting down the event thread in case it is active
2) Closing the handle to the actual device
3) Destroying the mutex used for synchronization
*******************************************************************************/
UsdNSCDevice::~UsdNSCDevice( VOID )
{
NSC_TRACE("In UsdNSCDevice::~UsdNSCDevice");
// Kill the notification thread if it exists by
// making sure that any notification handles are
// NULLed out.
if (m_hSignalEvent && (m_hSignalEvent != INVALID_HANDLE_VALUE))
{
SetNotificationHandle(NULL);
}
if (m_hShutdownEvent && (m_hShutdownEvent!=INVALID_HANDLE_VALUE))
{
CloseHandle(m_hShutdownEvent);
}
CloseDevice();
if (m_pszDeviceNameA)
{
delete [] m_pszDeviceNameA;
m_pszDeviceNameA = NULL;
}
// Close the mutex object
if (m_hMutex != NULL)
{
ReleaseMutex(m_hMutex);
CloseHandle(m_hMutex);
}
for (int index = 0; index < NS_MAX_OPEN_APPS; index++)
{
if (m_hPollingMutex[index] != NULL)
{
ReleaseMutex(m_hPollingMutex[index]);
CloseHandle(m_hPollingMutex[index]);
}
}
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::GetCapabilities is called by STI to determine the capabilities
supported by this device
PARAMETERS:
PSTI_USD_CAPS pUsdCaps - This structure has to be filled in with data
indicting the capabilitoes of the device
RETURN VALUE:
STDMETHODIMP - This is a macro that indicates that we return HRESULT
NOTES:
The only capability which we want the STI to know about at this
point is the fact that we don't need polling and can generate our
own events
*******************************************************************************/
STDMETHODIMP UsdNSCDevice::GetCapabilities( PSTI_USD_CAPS pUsdCaps )
{
NSC_TRACE("In UsdNSCDevice::GetCapabilities");
HRESULT hres = STI_OK;
ZeroMemory(pUsdCaps,sizeof(*pUsdCaps));
pUsdCaps->dwVersion = STI_VERSION;
// We support device notifications without polling
pUsdCaps->dwGenericCaps = STI_USD_GENCAP_NATIVE_PUSHSUPPORT;
return hres;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::GetStatus is called by the STI to determine if the device that we
represent is still online
PARAMETERS:
PSTI_DEVICE_STATUS pDevStatus
RETURN VALUE:
STDMETHODIMP - This is a macro that indicates that we return HRESULT
NOTES:
*******************************************************************************/
STDMETHODIMP UsdNSCDevice::GetStatus( PSTI_DEVICE_STATUS pDevStatus )
{
WriteToLog( STI_TRACE_INFORMATION,
L"In UsdNSCDevice::GetStatus - Online Status : %d, Event Status : %d",
pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE,
pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE);
HRESULT hres = STI_OK;
//
// If we are asked, verify whether device is online
//
pDevStatus->dwOnlineState = 0L;
if( pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE )
{
hres = GetDeviceStatus(pDevStatus);
}
//
// If we are asked, verify state of event
//
pDevStatus->dwEventHandlingState = 0L;
if( pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE )
{
if(m_guidLastEvent != GUID_NULL)
{
pDevStatus->dwEventHandlingState |= STI_EVENTHANDLING_PENDING;
}
if (m_hSignalEvent && (m_hSignalEvent!= INVALID_HANDLE_VALUE))
{
pDevStatus->dwEventHandlingState |= STI_EVENTHANDLING_ENABLED;
}
}
return hres;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::DeviceReset
PARAMETERS:
VOID
RETURN VALUE:
STDMETHODIMP - This is a macro that indicates that we return HRESULT
NOTES:
*******************************************************************************/
STDMETHODIMP UsdNSCDevice::DeviceReset( VOID )
{
NSC_TRACE("In UsdNSCDevice::DeviceReset");
HRESULT hres = STIERR_NOT_INITIALIZED;
// Reset the current active device - this can be
// accomplished by a DeviceIOControl call with an
// IOCTL of RESET_PIPE and a value of all pipes
// Use the escape command to handle all the niceties
// of the overlapped IO on this call
if (INVALID_HANDLE_VALUE != m_DeviceDataHandle)
{
DWORD cbBytesWritten;
PIPE_TYPE ePipes = ALL_PIPE;
hres = Escape( IOCTL_RESET_PIPE,
&ePipes,
sizeof(ePipes),
NULL,
0,
&cbBytesWritten);
}
return hres;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::Diagnostic
PARAMETERS:
LPDIAG pBuffer
RETURN VALUE:
STDMETHODIMP - This is a macro that indicates that we return HRESULT
NOTES:
*******************************************************************************/
STDMETHODIMP UsdNSCDevice::Diagnostic( LPDIAG pBuffer )
{
NSC_TRACE("In UsdNSCDevice::Diagnostic");
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Diagnostic",
L"testing",
0) ;
HRESULT hres = STI_OK;
// We will try to get the maximum packet size for the
// USB pipes. This must obviously be greater than zero
// If there is an error during this operation or the
// size is not greater than zero then the device is offline
if (INVALID_HANDLE_VALUE != m_DeviceDataHandle)
{
// Get the maximum packet size - this has to be
// greater than zero for all the pipes
CHANNEL_INFO channelInfo = {0,0,0};
DWORD cbBytesWritten(0);
hres = Escape( IOCTL_GET_CHANNEL_ALIGN_RQST,
NULL,
0,
&channelInfo,
sizeof(channelInfo),
&cbBytesWritten);
if (FAILED(hres) || !channelInfo.EventChannelSize)
{
hres = STIERR_GENERIC;
m_dwLastOperationError = ::GetLastError();
// Fill in the error info using the GetLastErrorInfo call
GetLastErrorInfo(&pBuffer->sErrorInfo);
}
else
{
m_dwLastOperationError = 0;
GetLastErrorInfo(&pBuffer->sErrorInfo);
}
}
else
{
hres = STIERR_NOT_INITIALIZED;
}
return hres;
}
/*******************************************************************************
DESCRIPTION:
SetNotificationHandle
PARAMETERS:
HANDLE hEvent
RETURN VALUE:
STDMETHODIMP - This is a macro that indicates that we return HRESULT
NOTES:
// SYNCHRONIZED
*******************************************************************************/
STDMETHODIMP UsdNSCDevice::SetNotificationHandle( HANDLE hEvent )
{
WriteToLog( STI_TRACE_INFORMATION,
L"In UsdNSCDevice::SetNotificationHandle with handle Ox%X",
hEvent);
HRESULT hres = STI_OK;
TAKE_CRIT_SECT t(m_cs);
if (hEvent && (hEvent !=INVALID_HANDLE_VALUE))
{
m_hSignalEvent = hEvent;
if (m_DeviceDataHandle != INVALID_HANDLE_VALUE)
{
m_guidLastEvent = GUID_NULL;
if (!m_hThread)
{
DWORD dwThread;
m_hThread = ::CreateThread(NULL,
2*1024,
(LPTHREAD_START_ROUTINE)InterruptThreadFunc,
(LPVOID)this,
0,
&dwThread);
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Enabling notification monitoring",
L"Created Thread (handle) ",
m_hThread) ;
}
}
else
{
// If we have not been initialized (like when we are
// opened in status mode) we will start listening
// when we are actually opened in data mode so there is
// no need to return an error code at this point
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Device not initialized",
L"Deferring notification monitoring",
0) ;
}
}
else
{
//
// Disable hardware notifications
//
m_hSignalEvent = INVALID_HANDLE_VALUE;
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Disabling notification monitoring",
L"Closing Thread (handle)",
m_hThread) ;
if ( m_hThread )
{
::SetEvent(m_hShutdownEvent);
WaitForSingleObject(m_hThread, NS_THREADWAIT_TIMEOUT);
CloseHandle(m_hThread);
m_hThread = NULL;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -