⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serrdwr.cpp

📁 串口驱动程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// serrdwr.cpp - read/write support for serial driver
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================

// Class SerialDevice handles most of the setup for reading and
// writing to or from the serial device.

// For read operations, the requirements of the subclass are as follows:
//
// 1. It must override member SynchronizeReceiverAccess. This member
//    function is used to serialize access to state information that 
//    controls a read operation. This may be implemented with a spin
//    lock or via synchronization with an interrupt object.
//
// 2. When a character is received, the subclass must check 
//    m_ReadBuffer for non-zero to see if a read is in progress. If
//    so, it must store the character in the buffer and decrement
//    m_ReadCount.
//
// 3. When a read is complete, the subclass must request the 
//    read complete DPC, m_ReadCompleteDpc, passing to it the
//    status (STATUS_SUCCESS) and the count of bytes remaining
//    (0).
// 
// 4. If the subclass provides buffering of data received while no
//    read is in progress, it must override member CopyReceivedData.
//
// For write operations, the requirements of the subclass are as follows:
//
// 1. It must override member SynchronizeTransmitterAccess. This member 
//    is used to serialize access to state information that controls
//    a write operation.
//
// 2. It must override member StartWrite, which initiates a write
//    operation. The base class member, which the override may
//    invoke, sets up m_WriteBuffer and m_WriteCount.
//
// 3. It must test m_WriteBuffer for zero to check if the write has
//    timed out or has been canceled.
//
// 4. When a write is complete, it must set m_WriteBuffer to zero, and
//    request the write complete DPC, m_WriteCompleteDpc.

#include <vdw.h>
#include "serdev.h"
#include "glbtrace.h"

///////////////// Functions for Read ////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
struct _read_start
{
	SerialDevice* device;
	PUCHAR buffer;
	ULONG count;
};

/////////////////////////////////////////////////////////////////////////////
// Start a read operation
//
// This is called from the SerialReadQueue::StartIo.
//
// Input:
//	buffer		Buffer to receive data
//	count		Maximum number of bytes to read
//
// This routine uses the receiver synchronization member functon of the
// subclass to invoke SynchReadStart.
//
VOID SerialDevice::StartRead(PUCHAR buffer, ULONG count)
{
// Call SynchReadStart, allowing subclasses to apply whatever
// synchronization is required.

	struct _read_start rs;

//	GTRACE( (TLEVEL,"Start Read, count=%d\n", count));

	rs.device = this;
	rs.buffer = buffer;
	rs.count  = count;

	SynchronizeReceiverAccess(LinkTo(SynchReadStart), &rs);
}

/////////////////////////////////////////////////////////////////////////////
// SynchReadStart
//
// Set up the state information to handle the read operation.
// This is called via SynchronizeReceiverAccess.
//
BOOLEAN SerialDevice::SynchReadStart(PUCHAR buffer, ULONG count)
{
	ASSERT (m_ReadBuffer == NULL);

	// See if there is any received data in the buffer.

	ULONG nReceived = CopyReceivedData(buffer, count);

	// Adjust count and buffer for received data.

	count -= nReceived;
	buffer += nReceived;

	// Special semantics when IntervalTimeout == MAXULONG

	if (m_Timeouts.ReadIntervalTimeout == MAXULONG)
	{

	// if both multiplier and constant are zero, return immediately,
	// even if there are no characters available

		if 	( (m_Timeouts.ReadTotalTimeoutMultiplier == 0) &&
		      (m_Timeouts.ReadTotalTimeoutConstant == 0) )
		{
			m_ReadCompleteDpc.Request((PVOID)STATUS_SUCCESS, (PVOID)count);
			return TRUE;
		}

	// otherwise, if neither multipler nor constant is MAXULONG, then
	// return immediately only if at least one character is available

		else if ( (m_Timeouts.ReadTotalTimeoutMultiplier != MAXULONG) &&
		          (m_Timeouts.ReadTotalTimeoutConstant   != MAXULONG) &&
				  (nReceived != 0) )
		{
			m_ReadCompleteDpc.Request((PVOID)STATUS_SUCCESS, (PVOID)count);
			return TRUE;
		}
	}

	// If no more data is needed to satisfy the request, complete it

	if (count == 0)
	{
		m_ReadCompleteDpc.Request((PVOID)STATUS_SUCCESS, 0);
		return TRUE;
	}

	// Otherwise, set up the read state

	else
	{
		m_ReadBuffer = buffer;
		m_ReadCount = count;

	// Queue the DPC to handle total read and interval read timeouts
	// if the m_Timeouts requires doing so.

		if ( ((m_Timeouts.ReadTotalTimeoutMultiplier != 0) ||
		      (m_Timeouts.ReadTotalTimeoutConstant != 0))
							    ||
		     ((m_Timeouts.ReadIntervalTimeout != 0) &&
		      (m_Timeouts.ReadIntervalTimeout != MAXULONG))
		   )

			m_StartReadTimerDpc.Request( (PVOID)m_ReadCount);
					
		return FALSE;
	}
}

/////////////////////////////////////////////////////////////////////////////
// ReadComplete
//
// Finish a write operation (this is a DPC)
//
// arg1 is status
// arg2 is number of bytes that remained to be read when stopped
//
// The subclass must queue data member m_ReadCompleteDpc when a
// read completes. The constructor for SerialDevice initializes
// the DPC to this member.
//
VOID SerialDevice::ReadComplete(PVOID arg1, PVOID arg2)
{
	NTSTATUS status = (NTSTATUS)arg1;

	// Cancel a total read timeout if one is still active

	if ((status != STATUS_TIMEOUT) && (m_ReadTimeout != 0))
	{
		m_ReadTimeout = 0;
		m_ReadExpiredCallback.Cancel();
	}

	m_ReadIrpQueue.CompleteCurrent(status, (ULONG)arg2);
}

/////////////////////////////////////////////////////////////////////////////
// CancelCurrentRead
//
// Cancel the current read operation. Synch up to SynchCancelRead 
// using receiver synchronization method. This is called from
// SerialReadQueue::Cancel.
//
VOID SerialDevice::CancelCurrentRead(void)
{
	SynchronizeReceiverAccess(LinkTo(SynchCancelRead), this);
}

/////////////////////////////////////////////////////////////////////////////
// SynchCancelRead
//
// Kill the current read. This is used by the timeout handlers and
// the cancel routines. This is called via SynchronizeReceiverAccess.
//
BOOLEAN SerialDevice::SynchCancelRead(void)
{
	BOOLEAN status = (m_ReadBuffer != 0);

	m_FinalReadCount = m_ReadCount;
	m_ReadBuffer = 0;
	m_ReadCount = 0;
	m_ReadCountLastInterval = 0;

	return status;
}

/////////////////////////////////////////////////////////////////////////////
// StartReadTimer
//
// Start timing a read. This is a DPC. arg1 is the character count.
//
VOID SerialDevice::StartReadTimer(PVOID arg1, PVOID arg2)
{
	LONGLONG Count = (LONGLONG)(LONG)arg1;
	LARGE_INTEGER l;

// Set up the timer for the total read. The total interval is 
// computed by adding the constant to the product of the
// multiplier and the character count.

	if (m_Timeouts.ReadTotalTimeoutMultiplier || 
	    m_Timeouts.ReadTotalTimeoutConstant)
	{
		m_ReadTimeout =
			m_Timeouts.ReadTotalTimeoutConstant + 
			(Count*m_Timeouts.ReadTotalTimeoutMultiplier);

		l.QuadPart = 10000 * (ULONGLONG)(-m_ReadTimeout);

	// Set up a callback to ReadExpired 

		m_ReadExpiredCallback.Set(l, LinkTo(ReadExpired), this);
	}

// Set up the interval timer. 

	if ((m_Timeouts.ReadIntervalTimeout != 0) &&
	    (m_Timeouts.ReadIntervalTimeout != MAXULONG))

	{
		LARGE_INTEGER Large;
		KeQuerySystemTime(&Large);

		m_ReadCountLastInterval = m_ReadCount;
		m_TimeLastInterval = Large.QuadPart;

		Large.QuadPart = m_IntervalTimerPeriod;

		m_ReadIntervalCallback.Set(
			Large,
			LinkTo(ReadIntervalExpired),
			this
			);
	}
}

/////////////////////////////////////////////////////////////////////////////
// ReadExpired
//
// Handle read total timeout. This is a DPC.
//
VOID SerialDevice::ReadExpired(PVOID arg1, PVOID arg2)
{
	GTRACE((TLEVEL,"Total read timeout\n"));
//
// Stop the current read. If it was still in progress, complete it
// 
	if (SynchronizeReceiverAccess(LinkTo(SynchCancelRead), this))
		ReadComplete( (PVOID)STATUS_TIMEOUT, (PVOID)m_FinalReadCount );
}

/////////////////////////////////////////////////////////////////////////////
// ReadIntervalExpired
//

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -