www.pudn.com > VSer.rar > readwrite.c


/*++ 
 
Copyright (c) 2005  Changzhi Zhou All Rights Reserved 
 
Module Name: 
 
    readwrite.c 
 
Abstract: 
 
    This module contains Read/Write routines. 
 
Environment: 
 
    Kernel mode 
 
Revision History: 
 
	Changzhi Zhou Dec 20  2004 
 
--*/ 
#include  
#include  
#include "main.h" 
#include "..\inc\wdmioctl.h" 
NTSTATUS 
SampleRead( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
	) 
/*++ 
 
Routine Description: 
	Read I/O request. 
	If deviceExtension->SerialStatus.AmountInInQueue, which means there are some data in RxBuffer, 
	we call CopyFromRingBuffer to copy data in RxBuffer to Irp->MdlAddress. 
	Else mark the Irp pending , return STATUS_PENDING and start a timer. The timeout is set by  
	IOCTL_SERIAL_SET_TIMEOUTS. 
 
Arguments: 
 
  DeviceObject	- pointer to device object 
  Irp			- pointer to Read I/O request. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
	PDEVICE_EXTENSION	deviceExtension; 
	NTSTATUS			status; 
	PIO_STACK_LOCATION IrpStack; 
	ULONG				OutputLength; 
	ULONG				info; 
	KIRQL				oldIrql; 
 
	PAGED_CODE(); 
	DbgPrint("--- SampleRead routine...\n"); 
	deviceExtension = DeviceObject->DeviceExtension; 
	if ( deviceExtension->DevicePnPState != Working ) 
		return CompleteRequest ( Irp, STATUS_INVALID_DEVICE_STATE, 0 ); 
	IrpStack = IoGetCurrentIrpStackLocation(Irp); 
	OutputLength = IrpStack->Parameters.Read.Length; 
	if( OutputLength == 0 ) 
		return CompleteRequest( Irp, STATUS_SUCCESS, 0 ); 
	status	= STATUS_SUCCESS; 
	info	= 0; 
	KeAcquireSpinLock( &deviceExtension->ThreadSpinLock, &oldIrql ); 
	if ( deviceExtension->PendingReadIrp == NULL ) 
	{ 
		if( deviceExtension->SerialStatus.AmountInInQueue ) 
		{ 
			info = CopyFromRingBuffer ( deviceExtension, Irp ); 
		}else 
		{	// set timeout simply. 
			LARGE_INTEGER	Timeout; 
			ULONG	tmp; 
			tmp = ( deviceExtension->Timeouts.ReadIntervalTimeout > READINTERVAL_TIMEOUT ) 
				? READINTERVAL_TIMEOUT : deviceExtension->Timeouts.ReadIntervalTimeout; 
			if ( tmp > 0 ) 
			{ 
				Timeout.LowPart = ( -1 ) * tmp; 
				Timeout.HighPart = -1; 
				DebugPrint(("Irp (%x) Set ReadTimer %d (100 nanosecond )\n", Irp, tmp )); 
				SampleIoIncrement( deviceExtension ); 
				deviceExtension->PendingReadIrp = Irp; 
				IoMarkIrpPending ( Irp ); 
				status = STATUS_PENDING; 
				KeSetTimer ( &deviceExtension->ReadTimer, Timeout, &deviceExtension->ReadDpc ); 
			} 
		} 
	}else 
	{ 
		status = STATUS_INVALID_DEVICE_REQUEST; 
	} 
	KeReleaseSpinLock ( &deviceExtension->ThreadSpinLock, oldIrql ); 
	if ( status != STATUS_PENDING ) 
		CompleteRequest( Irp, status, info ); 
	return status; 
} 
VOID 
ReadDpcRoutine( 
    IN PKDPC Dpc, 
    IN PVOID DeferredContext, 
    IN PVOID SystemArgument1, 
    IN PVOID SystemArgument2 
    ) 
/*++ 
 
Routine Description: 
 
  DPC routine. 
  It will be called by the trigger of ReadIrp timer. If there are some data, it copies the data 
  to Irp->MdlAddress and then complete the Irp. If not, it complete thr Irp directly. 
  The deviceExtension->PendingReadIrp is the Read I/O request saved by SampleRead. 
 
Arguments: 
 
	DeferredContext	- pointer to deviceExtension 
 
--*/ 
{ 
	KIRQL				oldIrql; 
	PDEVICE_EXTENSION	deviceExtension; 
	PIRP				Irp; 
	ULONG				info; 
 
	deviceExtension = ( PDEVICE_EXTENSION )DeferredContext; 
	info			= 0; 
	KeAcquireSpinLock( &deviceExtension->ThreadSpinLock, &oldIrql ); 
	if ( deviceExtension->PendingReadIrp ) 
	{ 
		Irp	= deviceExtension->PendingReadIrp; 
		DebugPrint(("Irp (%x) DpcRoutine...\n", Irp )); 
		if ( deviceExtension->SerialStatus.AmountInInQueue ) 
		{ 
			info = CopyFromRingBuffer ( deviceExtension, Irp ); 
		} 
		CompleteRequest( Irp, STATUS_SUCCESS, info ); 
		SampleIoDecrement ( deviceExtension ); 
		deviceExtension->PendingReadIrp = NULL; 
	} 
	KeReleaseSpinLock ( &deviceExtension->ThreadSpinLock, oldIrql ); 
} 
ULONG	CopyFromRingBuffer( 
	PDEVICE_EXTENSION	deviceExtension, 
	PIRP				Irp ) 
/*++ 
 
Routine Description: 
 
	It copies RingBuffer, that is RxBuffer, to Irp->MdlAddress. 
	It must be running at IRQL = DISPATCH_LEVEL within the scope of Spinlock. 
Arguments: 
 
	deviceExtension	- pointer to device object extension 
	Irp				- Read I/O request packet 
Return Value: 
 
    the actual number of data copied from ringbuffer. 
 
--*/ 
{ 
	PIO_STACK_LOCATION IrpStack; 
	ULONG				OutputLength; 
	ULONG				BytesToCopy; 
	PUCHAR				buf; 
	ULONG				stageSize; 
 
	ASSERT ( deviceExtension->SerialStatus.AmountInInQueue ); 
	IrpStack = IoGetCurrentIrpStackLocation(Irp); 
	OutputLength = IrpStack->Parameters.Read.Length; 
	buf = (PUCHAR)MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority ); 
	ASSERT ( buf ); 
	BytesToCopy = ( deviceExtension->SerialStatus.AmountInInQueue > OutputLength ) ? OutputLength : deviceExtension->SerialStatus.AmountInInQueue; 
	stageSize = deviceExtension->RxBuffer + RINGBUFFER_SIZE - deviceExtension->lpRead; 
	if ( BytesToCopy <= stageSize ) 
		RtlCopyMemory ( buf, deviceExtension->lpRead, BytesToCopy ); 
	else 
	{ 
		RtlCopyMemory ( buf, deviceExtension->lpRead, stageSize ); 
		RtlCopyMemory ( buf + stageSize, deviceExtension->RxBuffer, ( BytesToCopy - stageSize ) ); 
	} 
	deviceExtension->lpRead = deviceExtension->RxBuffer + 
		( ( deviceExtension->lpRead + BytesToCopy - deviceExtension->RxBuffer ) % RINGBUFFER_SIZE ); 
	deviceExtension->SerialStatus.AmountInInQueue -= BytesToCopy; 
	return BytesToCopy; 
} 
NTSTATUS 
SampleWrite( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
	) 
/*++ 
 
Routine Description: 
 
	It calls TdiSendDatagram to send data to remote peer, which is indicated  
	by deviceExtension->RemoteAddress and deviceExtension->RemotePort. 
 
Arguments: 
 
	DeviceObject	- pointer to device object. 
	Irp				- Read I/O request packet 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
	PIO_STACK_LOCATION IrpStack; 
	PDEVICE_EXTENSION	deviceExtension; 
	NTSTATUS			status; 
 
	ULONG				InputLength; 
	ULONG				info; 
	PAGED_CODE(); 
 
	DbgPrint("--- SampleWrite routine...\n"); 
	deviceExtension = DeviceObject->DeviceExtension; 
 
	if ( deviceExtension->DevicePnPState != Working ) 
		return CompleteRequest ( Irp, STATUS_INVALID_DEVICE_STATE, 0 ); 
	IrpStack = IoGetCurrentIrpStackLocation(Irp); 
	InputLength = IrpStack->Parameters.Write.Length; 
	if( InputLength == 0 ) 
		return CompleteRequest( Irp, STATUS_SUCCESS, 0 ); 
	SampleIoIncrement( deviceExtension ); 
	status	= TDISendDatagram( DeviceObject, Irp ); 
	info	= Irp->IoStatus.Information; 
	status = CompleteRequest( Irp, status, info ); 
	SampleIoDecrement( deviceExtension ); 
	return status; 
}