📄 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 <ntddk.h>
#include <initguid.h>
#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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -