📄 serrdwr.cpp
字号:
// Handle read interval timeout
//
VOID SerialDevice::ReadIntervalExpired(PVOID arg1, PVOID arg2)
{
if (SynchronizeReceiverAccess(LinkTo(SynchReadIntervalExpired), this))
{
LARGE_INTEGER Large;
Large.QuadPart = m_IntervalTimerPeriod;
m_ReadIntervalCallback.Set(
Large,
LinkTo(ReadIntervalExpired),
this
);
}
}
/////////////////////////////////////////////////////////////////////////////
// SynchReadIntervalExpired
//
// Synchronized handling of interval timer
//
BOOLEAN SerialDevice::SynchReadIntervalExpired(void)
{
// if the read is done, there is nothing to do
if (m_ReadCount == 0)
return FALSE;
LARGE_INTEGER Now;
KeQuerySystemTime(&Now);
// if no characters have arrived since the last call, then check the
// elapsed time
if ( (m_ReadCount == m_ReadCountLastInterval) && (m_ReadCount != 0) )
{
LONGLONG Elapsed = Now.QuadPart - m_TimeLastInterval;
if (Elapsed > m_MaxCharacterInterval)
{
m_ReadCompleteDpc.Request((PVOID)STATUS_TIMEOUT, (PVOID)m_ReadCount);
m_ReadCount = 0;
m_ReadBuffer = 0;
m_ReadCountLastInterval = 0;
return FALSE;
}
}
m_ReadCountLastInterval = m_ReadCount;
m_TimeLastInterval = Now.QuadPart;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Static linkage members
//
// These static members pass control between SynchronizeReceiverAccess
// and various non-static members.
//
BOOLEAN SerialDevice::LinkTo(SynchCancelRead)(PVOID Context)
{
return ((SerialDevice*)Context)->SynchCancelRead();
}
BOOLEAN SerialDevice::LinkTo(SynchReadIntervalExpired)(PVOID Context)
{
return ((SerialDevice*)Context)->SynchReadIntervalExpired();
}
BOOLEAN SerialDevice::LinkTo(SynchReadStart)(PVOID Context)
{
_read_start* prs = (_read_start*)Context;
return prs->device->SynchReadStart(prs->buffer, prs->count);
}
/////////////////////////////////////////////////////////////////////////////
// Synchronize access to receiver data
//
// Most subclasses will override this member function. The function is
// designed to be compatible with subclasses that need interrupt level
// synchronization, although a subclass could equally well implement
// this function by acquiring a spin lock, making the call, and releasing
// the spin lock. The base class just calls the function.
BOOLEAN SerialDevice::SynchronizeReceiverAccess(
PKSYNCHRONIZE_ROUTINE func,
PVOID context
)
{
return func(context);
}
/////////////////////////////////////////////////////////////////////////////
// CopyReceivedData
//
// Copy any unsolicited data which has been buffered while no read was
// pending. The base class has none. Most subclasses will override
// this member.
//
ULONG SerialDevice::CopyReceivedData(PUCHAR buffer, ULONG count)
{
return 0;
}
struct CopyReceivedDataArgs
{
SerialDevice* device;
PUCHAR buf;
ULONG count;
};
/////////////////////////////////////////////////////////////////////////////
// NoPendRead
//
// Non-blocking read for special RAS support
//
NTSTATUS SerialDevice::NoPendRead(KIrp I)
{
CopyReceivedDataArgs crsargs;
crsargs.device = this;
crsargs.buf = (PUCHAR)I.BufferedReadDest();
crsargs.count = I.ReadSize();
SynchronizeReceiverAccess(LinkTo(CopyReceivedData), &crsargs);
if ( ((m_Timeouts.ReadIntervalTimeout == MAXULONG) &&
(m_Timeouts.ReadTotalTimeoutMultiplier == 0) &&
(m_Timeouts.ReadTotalTimeoutConstant == 0)
) || (crsargs.count > 0)
)
{
I.Information() = crsargs.count;
I.Complete(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
else
return STATUS_MORE_PROCESSING_REQUIRED;
}
///////////////// Functions for Write //////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CancelCurrentWrite
//
// Cancel the current write operation
//
VOID SerialDevice::CancelCurrentWrite(void)
{
SynchronizeTransmitterAccess(LinkTo(SynchCancelWrite), this);
}
/////////////////////////////////////////////////////////////////////////////
// SynchCancelWrite
//
// Cancel the current write operation
//
BOOLEAN SerialDevice::SynchCancelWrite(void)
{
BOOLEAN status = (m_WriteBuffer != 0);
m_FinalWriteCount = m_WriteCount;
m_WriteBuffer = 0;
m_WriteCount = 0;
return status;
}
/////////////////////////////////////////////////////////////////////////////
// Start a write operation
//
// Subclasses should override this member if additional functionality
// is required, as will most often be the case.
//
VOID SerialDevice::StartWrite(PUCHAR buffer, ULONG count)
{
ASSERT (m_WriteBuffer == NULL);
// Handle a write of zero characters
if (count == 0)
{
m_WriteIrpQueue.CompleteCurrent(STATUS_SUCCESS, 0);
return;
}
GTRACE( (TLEVEL, "Start write: |%s|\n", buffer));
// Set up write state data
m_WriteBuffer = buffer;
m_WriteCount = count;
// If the write has a timeout, start it
if (m_Timeouts.WriteTotalTimeoutMultiplier ||
m_Timeouts.WriteTotalTimeoutConstant )
m_StartWriteTimerDpc.Request((PVOID)count);
}
/////////////////////////////////////////////////////////////////////////////
// WriteComplete
//
// Finish a write operation (this is a DPC). Status is arg1.
// The subclass must request DPC m_WriteCompleteDpc when it
// detects that a write is complete. The constructor for
// SerialDevice sets up the DPC to call this function.
//
VOID SerialDevice::WriteComplete(PVOID arg1, PVOID arg2)
{
NTSTATUS status = (NTSTATUS)arg1;
// Cancel a write timeout if one is active
if ((status != STATUS_TIMEOUT) && (m_WriteTimeout != 0))
{
m_WriteTimeout = 0;
m_WriteExpiredCallback.Cancel();
}
m_WriteIrpQueue.CompleteCurrent(status, m_FinalWriteCount);
}
/////////////////////////////////////////////////////////////////////////////
// StartWriteTimer
//
// Start timing a write. This is a DPC. arg1 is the character count.
//
VOID SerialDevice::StartWriteTimer(PVOID arg1, PVOID arg2)
{
LONGLONG Count = (LONGLONG)(LONG)arg1;
LARGE_INTEGER l;
m_WriteTimeout =
m_Timeouts.WriteTotalTimeoutConstant +
(Count*m_Timeouts.WriteTotalTimeoutMultiplier);
l.QuadPart = 10000 * (ULONGLONG)(-m_WriteTimeout);
m_WriteExpiredCallback.Set(l, LinkTo(WriteExpired), this);
}
/////////////////////////////////////////////////////////////////////////////
// WriteExpired
//
// Handle Write timeout
//
VOID SerialDevice::WriteExpired(PVOID arg1, PVOID arg2)
{
if (SynchronizeTransmitterAccess(LinkTo(SynchCancelWrite), this))
WriteComplete( (PVOID)STATUS_TIMEOUT, NULL );
}
/////////////////////////////////////////////////////////////////////////////
// Synchronize transmitter access
//
// Most subclasses will override this member function. The function is
// designed to be compatible with subclasses that need interrupt level
// synchronization, although a subclass could equally well implement
// this function by acquiring a spin lock, making the call, and releasing
// the spin lock. The base class just calls the function.
BOOLEAN SerialDevice::SynchronizeTransmitterAccess(
PKSYNCHRONIZE_ROUTINE func,
PVOID context
)
{
return func(context);
}
/////////////////////////////////////////////////////////////////////////////
// Static linkage members
//
// These static members pass control between SynchronizeReceiverAccess
// and various non-static members.
//
BOOLEAN SerialDevice::LinkTo(SynchCancelWrite)(PVOID Context)
{
return ((SerialDevice*)Context)->SynchCancelWrite();
}
BOOLEAN SerialDevice::LinkTo(CopyReceivedData)(PVOID Context)
{
CopyReceivedDataArgs* pcrs = (CopyReceivedDataArgs*)Context;
pcrs->count = pcrs->device->CopyReceivedData(pcrs->buf, pcrs->count);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -