📄 nscdevice.cpp
字号:
::CoUninitialize();
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::ListenForInterrupts
PARAMETERS:
RETURN VALUE:
void
NOTES:
*******************************************************************************/
void UsdNSCDevice::ListenForInterrupts()
{
NSC_TRACE("In UsdNSCDevice::ListenForInterrupts");
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Listening for Interrupts Started",
L"In Thread (id)",
::GetCurrentThreadId()) ;
if (!m_DeviceDataHandle || (m_DeviceDataHandle == INVALID_HANDLE_VALUE))
{
WriteToLog( STI_TRACE_ERROR,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Listening for Interrupts Aborted",
L"Device not Initialized in Thread (id)",
::GetCurrentThreadId()) ;
return;
}
// We dont have to create a overlapped event if we are only polling
// the device but we do it anyway just to make the code simpler to read
// and modify . The alternatice would be to bracket all this code and
// the code that closes the overlapped handle with #ifdef commands
// and that makes the code really messy
OVERLAPPED stOverlapped;
LPOVERLAPPED lpOverlapped = &stOverlapped;
ZeroMemory(lpOverlapped, sizeof(OVERLAPPED));
lpOverlapped->hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
BOOL fLooping = TRUE;
DWORD dwEventCode;
while(fLooping)
{
#ifdef NS_POLL_FOR_EVENTS
dwEventCode = PollForDriverEvent();
#else
dwEventCode = WaitForDriverEvent(lpOverlapped);
#endif
switch(dwEventCode)
{
case NS_DEVICE_INTERRUPT:
// Find out what kind of event has occured and then
// generate a event for the STI if necessary
// an event has occured
GenerateScannerEvent();
// We will be back through this loop to wait on device
// events so it is critical that we reset the event object
// as this is a manual reset event
::ResetEvent(lpOverlapped->hEvent);
break;
case NS_SHUTDOWN_REQUEST:
// We have to shutdown the interrupt thread
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Listening for Interrupts Aborted",
L"Shutdown Request",
0) ;
::ResetEvent(m_hShutdownEvent);
fLooping = false;
break;
case NS_WAIT_ERROR:
WriteToLog( STI_TRACE_ERROR,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Listening for Interrupts Aborted",
L"Wait Error ",
::GetLastError()) ;
fLooping = false;
break;
case NS_IOCONTROL_ERROR:
WriteToLog( STI_TRACE_ERROR,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Listening for Interrupts Aborted",
L"DeviceIoControl() Error",
::GetLastError()) ;
fLooping = FALSE;
break;
}
}
::CloseHandle(lpOverlapped->hEvent);
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::WaitForDriverEvent
PARAMETERS:
LPOVERLAPPED lpOverlapped
RETURN VALUE:
DWORD
NOTES:
*******************************************************************************/
DWORD UsdNSCDevice::WaitForDriverEvent(LPOVERLAPPED lpOverlapped)
{
DWORD dwBytesReturned;
BYTE pStatus[NS_MAX_INTERRUPT_PACKET];
DWORD dwReturnCode;
BOOL fRet = TRUE;
fRet = ::DeviceIoControl(m_DeviceDataHandle,
(DWORD) IOCTL_WAIT_ON_DEVICE_EVENT,
NULL,
0,
pStatus,
NS_MAX_INTERRUPT_PACKET,
&dwBytesReturned,
lpOverlapped);
// If the deviceIOControl call returned false and it was not
// because of a pending IO then we have a real error. In this case
// the wait will be aborted with an error return otherwise we
// can process the results of the call
if ( fRet || (::GetLastError() == ERROR_IO_PENDING))
{
HANDLE EventHandleArray[2] = {m_hShutdownEvent, lpOverlapped->hEvent};
int numEvents = sizeof(EventHandleArray) / sizeof(EventHandleArray[0]);
// Wait for an event to occur - one of the events could be a
// request for this thread to shutdown because our minidriver
// is being unloaded - this is not exactly a device event but it
// is handled here anyway as it is easy to do so
DWORD dwIndex = WaitForMultipleObjects( numEvents,
EventHandleArray,
FALSE,
INFINITE);
switch (dwIndex)
{
case WAIT_OBJECT_0 + 1:
// We have an interrupt, Trace the event
WriteToLog( STI_TRACE_INFORMATION,
L"%s : %s : 0x%X", // Message, Error, Code
L"UsdNSCDevice::Status Register Changed Event",
L"In Thread (id)",
::GetCurrentThreadId()) ;
dwReturnCode = NS_DEVICE_INTERRUPT;
break;
case WAIT_OBJECT_0:
dwReturnCode = NS_SHUTDOWN_REQUEST;
break;
default:
dwReturnCode = NS_WAIT_ERROR;
}
}
else // actual error in the device io control call
{
dwReturnCode = NS_IOCONTROL_ERROR;
}
return dwReturnCode;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::PollForDriverEvent
PARAMETERS:
RETURN VALUE:
DWORD
NOTES:
*******************************************************************************/
DWORD UsdNSCDevice::PollForDriverEvent()
{
// if some app has opened the driver then we will
// be stuck here till we either get a shutdown notice or
// the app closes the driver
bool mutex_wait = false;
for (int index = 0; index < NS_MAX_OPEN_APPS; index++)
{
while (::WaitForSingleObject(m_hPollingMutex[index],
min(m_dwKickStartTime,NS_POLLING_INTERVAL))
== WAIT_TIMEOUT)
{
// Check to make sure that we don't have a shutdown request
if (WaitForSingleObject(m_hShutdownEvent, 0) == WAIT_OBJECT_0)
return NS_SHUTDOWN_REQUEST;
// Check command reg = reset
mutex_wait = true;
// If waiting on bulkin, do some command to kick start
// any pause due to step counter termination
if (::WaitForSingleObject(m_hKickStartMutex,m_dwKickStartTime) == WAIT_TIMEOUT)
{
DoKickStart();
}
else
{
ReleaseMutex(m_hKickStartMutex);
}
}
ReleaseMutex(m_hPollingMutex[index]);
}
//flush status when exit mutex wait so don't get any events
if (mutex_wait)
{
ResetModeCheckAndClear();
BYTE bValue;
ReadStatusRegister(bValue); //flush first after wait
}
Sleep (NS_POLLING_INTERVAL);
// Check to make sure that we don't have a shutdown request
if (WaitForSingleObject(m_hShutdownEvent, 0) == WAIT_OBJECT_0)
return NS_SHUTDOWN_REQUEST;
// Pretend we just had a device event
return NS_DEVICE_INTERRUPT;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::WriteToLog
PARAMETERS:
DWORD dwType
LPWSTR lpszFormat
...
RETURN VALUE:
void
NOTES:
*******************************************************************************/
void UsdNSCDevice::WriteToLog(DWORD dwType, LPWSTR lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
int nBuf;
WCHAR szBuffer[512];
nBuf = _vsnwprintf(szBuffer, 511, lpszFormat, args);
va_end(args);
if (nBuf < 0)
return;
if (m_pDcb)
{
m_pDcb->WriteToErrorLog(dwType, szBuffer, NOERROR) ;
}
#ifdef _DEBUG
// Also trace the message to the debugger if in debug mode
// Convert name to SBCS as using OutputDebugStringW does not seem
// to work
UINT uiNameLen = WideCharToMultiByte(CP_ACP, 0, szBuffer, -1, NULL, NULL, 0, 0);
if (uiNameLen)
{
LPSTR lpszBuffer = new CHAR[uiNameLen+1];
if (lpszBuffer)
{
WideCharToMultiByte(CP_ACP, 0, szBuffer, -1, lpszBuffer, uiNameLen, 0, 0);
::OutputDebugString(lpszBuffer);
::OutputDebugString("\n");
delete lpszBuffer;
}
}
#endif
return;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::GetDeviceStatus
PARAMETERS:
PSTI_DEVICE_STATUS pDevStatus
RETURN VALUE:
HRESULT
NOTES:
*******************************************************************************/
HRESULT UsdNSCDevice::GetDeviceStatus(PSTI_DEVICE_STATUS pDevStatus)
{
// The device status can be one of the following
// and these conditions are checked for in the
// given order
// STI_ONLINESTATE_POWER_SAVE (reg 7, bit 4)
// STI_ONLINESTATE_BUSY (reg 7, bit 0-2 are NOT zero)
// STI_ONLINESTATE_OPERATIONAL (if none of the above)
HRESULT hres = STI_OK;
// Always lock the device before trying to access the scanner
hres = LockDevice();
// So the first order of business is to make sure that we
// can read register 7 and then based on the value we will
// determine the actual status of the device
if ( SUCCEEDED(hres) && (INVALID_HANDLE_VALUE != m_DeviceDataHandle))
{
BYTE pCommandBytes[COMMAND_BYTE_COUNT];
BYTE bValue;
// Write the command bytes for a register read
// without increment
pCommandBytes[0] = MODE_NOINC_READ;
pCommandBytes[1] = LM_COMMAND_REGISTER;
pCommandBytes[2] = 0;
pCommandBytes[3] = 1;
hres = RawWriteData(&pCommandBytes, COMMAND_BYTE_COUNT, NULL);
if (SUCCEEDED(hres))
{
// Then read the register in question
DWORD cbBytes(1);
hres = RawReadData(&bValue, &cbBytes, NULL);
}
if (SUCCEEDED(hres))
{
pDevStatus->dwOnlineState |= STI_ONLINESTATE_OPERATIONAL;
if (bValue & 0x10)
pDevStatus->dwOnlineState |= STI_ONLINESTATE_POWER_SAVE;
else if (bValue & 0x07)
pDevStatus->dwOnlineState |= STI_ONLINESTATE_BUSY;
}
UnLockDevice();
}
return hres;
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::GenerateScannerEvent
PARAMETERS:
RETURN VALUE:
void
NOTES:
*******************************************************************************/
void UsdNSCDevice::GenerateScannerEvent()
{
// Make sure that somebody is actually interested in hearing
// about this event
if ((m_hSignalEvent == INVALID_HANDLE_VALUE) || (!m_bEventsInitialized))
return;
// Find out if the scanner is online and is the scanner is in
// reset mode - if the scanner is in reset mode we will simply
// bring it out of this mode and ignore the event
HRESULT hres = S_OK;
//do every 20 times for safety
static int ct = 0;
if (!ct--)
{
ct = 20;
hres = ResetModeCheckAndClear();
}
BYTE bStatusRegister;
if SUCCEEDED(hres)
{
hres = ReadStatusRegister(bStatusRegister);
}
// If there was a scanner IO error then in all probability scanner
// is offline and this event should be ignored
if SUCCEEDED(hres)
{
// Get the event GUID corresponding to the current state
// of the register
m_guidLastEvent = GetEventGUID(bStatusRegister);
if (!IsEqualGUID(m_guidLastEvent,GUID_NULL))
{
// The event is forwarded onto the STI only if the
// status register bit is set and the event mask for that
// IO pin is turned on
::SetEvent(m_hSignalEvent);
// Once we successfully activate an event, we want to make
// sure that we debounce the input that is we dont want
// any more false positives till the debounce interval
// is finished so we just let this thread sleep for the
// debounce interval and then read and clear the status
// register
::Sleep(m_dwDebounceTime);
// Now clear any bits that were set when we were asleep
ReadStatusRegister(bStatusRegister);
}
}
}
/*******************************************************************************
DESCRIPTION:
UsdNSCDevice::ReadStatusRegister
PARAMETERS:
BYTE& bValue
RETURN VALUE:
HRESULT
NOTES:
*******************************************************************************/
HRESULT UsdNSCDevice::ReadStatusRegister(BYTE& bValue)
{
HRESULT hres = STI_OK;
if (!m_bPolling)
{
bValue = 0;
return hres;
}
hres = LockDevice();
// Follow the standard procedure of writing command bytes
// to the bulk out endpoint to read the io status register and then
// actually reading in the value from the bulk in endpoint
if ( SUCCEEDED(hres) && (INVALID_HANDLE_VALUE != m_DeviceDataHandle))
{
BYTE pCommandBytes[COMMAND_BYTE_COUNT];
// Write the command bytes for a register read
// without increment
pCommandBytes[0] = MODE_NOINC_READ;
pCommandBytes[1] = LM_IOSTATUS_REGISTER;
pCommandBytes[2] = 0;
pCommandBytes[3] = 1;
hres = RawWriteData(&pCommandBytes, COMMAND_BYTE_COUNT, NULL);
if (SUCCEEDED(hres))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -