www.pudn.com > 2004-01-16_SimSerial.rar > main.c
/*++
Copyright (c) 1990-2000 Changzhi Zhou All Rights Reserved
Module Name:
main.c
Abstract:
This module contains the entry points for a virtual serial driver
Author
Changzhi Zhou Jul 25, 2003
Environment:
Kernel mode
Revision History:
Changzhi Zhou Dec 5 2003
--*/
#include
#include
#include
#include "main.h"
#include "..\inc\wdmioctl.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, AddDevice)
#pragma alloc_text (PAGE, DispatchPower)
#pragma alloc_text (PAGE, Unload)
#endif
DEVICE_ARRAY gDeviceArray[ MAX_NUM_DEV ];
KSPIN_LOCK gSpinLock;
PACKET gPacketPool[ MAX_PACKET_NUM ];
LIST_ENTRY gIdleQueue;
KSPIN_LOCK gPoolSpinLock;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path,
to driver-specific key in the registry.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
//ULONG ulIndex;
ULONG i;
PDRIVER_DISPATCH * dispatch;
UNREFERENCED_PARAMETER (RegistryPath);
DebugPrint (("----------- Virtual Serial Device Build on %s %s ----------\n", __DATE__, __TIME__ ));
//
// Create dispatch points
//
/*
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;
ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
ulIndex++, dispatch++) {
*dispatch = DefaultPnpHandler;
}
*/
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
DriverObject->MajorFunction[IRP_MJ_CREATE] = RequestCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = RequestClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP ] = RequestCleanup;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RequestControl;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverUnload = Unload;
// Initialize global varible
RtlZeroMemory( gDeviceArray, sizeof( DEVICE_ARRAY ) * MAX_NUM_DEV );
KeInitializeSpinLock( &gSpinLock );
RtlZeroMemory( gPacketPool, sizeof( PACKET ) * MAX_PACKET_NUM );
InitializeListHead( &gIdleQueue );
KeInitializeSpinLock( &gPoolSpinLock );
for( i = 0; i < MAX_PACKET_NUM; i++)
{
InsertTailList( &gIdleQueue, &(gPacketPool[ i ].ListEntry) );
}
return status;
}
NTSTATUS
AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
The Plug & Play subsystem is handing us a brand new PDO, for which we
(by means of INF registration) have been asked to provide a driver.
We need to determine if we need to be in the driver stack for the device.
Create a function device object to attach to the stack
Initialize that device object
Return status success.
Remember: We can NOT actually send ANY non pnp IRPS to the given driver
stack, UNTIL we have received an IRP_MN_START_DEVICE.
Arguments:
DeviceObject - pointer to a device object.
PhysicalDeviceObject - pointer to a device object created by the
underlying bus driver.
Return Value:
NT status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
PAGED_CODE ();
//
// Create a device object.
//
status = SerialCreateDevObj(DriverObject, &deviceObject);
if (!NT_SUCCESS (status)) {
//
// Returning failure here prevents the entire stack from functioning,
// but most likely the rest of the stack will not be able to create
// device objects either, so it is still OK.
//
DebugPrint(("SerialCreateDevice failed with status %d\n", status ));
return status;
}
DebugPrint (("AddDevice PDO (0x%x) FDO (0x%x)\n", PhysicalDeviceObject, deviceObject));
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack (
deviceObject,
PhysicalDeviceObject);
//
// Failure for attachment is an indication of a broken plug & play system.
//
if(NULL == deviceExtension->NextLowerDriver) {
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
INITIALIZE_PNP_STATE(deviceExtension);
DebugPrint(("AddDevice: %x to %x->%x \n", deviceObject,
deviceExtension->NextLowerDriver,
PhysicalDeviceObject));
if( !NT_SUCCESS ( status ) ){
DebugPrint(( "AddDevice: IoRegisterDeviceInterface failed (%x) \n", status ));
IoDetachDevice( deviceExtension->NextLowerDriver );
gDeviceArray[ deviceExtension->localInstance ].deviceExtension = NULL;
IoDeleteDevice( deviceObject );
return status;
}
deviceObject->Flags |= ( DO_BUFFERED_IO | DO_POWER_PAGABLE );
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
#if 0
FilterCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
A completion routine for use when calling the lower device objects to
which our filter deviceobject is attached.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Context - Pointer to an event object
Return Value:
NT Status is returned.
--*/
{
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
//
// We could switch on the major and minor functions of the IRP to perform
// different functions, but we know that Context is an event that needs
// to be set.
//
KeSetEvent((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
//
// Allows the caller to use the IRP after it is completed
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
#endif
NTSTATUS
DispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch routine for power irps.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
NT Status code
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PAGED_CODE ();
DebugPrint(("Enter DispatchPower routine...\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
DebugPrint(("NextLowerDriver: 0x%x\n", deviceExtension->NextLowerDriver ));
status = PoCallDriver(deviceExtension->NextLowerDriver, Irp);
DebugPrint(("-Exit Power\n") );
return status;
}
VOID
Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources in DriverEntry, etc.
Arguments:
DriverObject - pointer to a driver object.
Return Value:
VOID.
--*/
{
PAGED_CODE ();
//
// The device object(s) should be NULL now
// (since we unload, all the devices objects associated with this
// driver must be deleted.
//
DebugPrint( ("Is unloading......\n") );
ASSERT(DriverObject->DeviceObject == NULL);
//
// We should not be unloaded until all the devices we control
// have been removed from our queue.
//
DebugPrint (("Unload: unload\n"));
return;
}
NTSTATUS RequestCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
/*++
Routine Description:
Create the device
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to an IRP_MJ_CREATE
Return Value:
NT Status is return.
--*/
{ // RequestCreate
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
DbgPrint("Entering IRP_MJ_CREAT\n");
status = STATUS_SUCCESS;
deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
// 每一个设备同一时间只允许一个应用打开
if( deviceExtension->bIsOpen ){
status = STATUS_ACCESS_DENIED;
}else{
deviceExtension->bIsOpen = TRUE;
}
return CompleteRequest(Irp, status, 0);
}
NTSTATUS RequestClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
/*++
Routine Description:
Close the device
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to an IRP_MJ_CREATE
Return Value:
NT Status is returned;
--*/
{ // RequestClose
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
DbgPrint("Entering IRP_MJ_CLOSE\n");
status = STATUS_SUCCESS;
deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
if( deviceExtension->bIsOpen ){
deviceExtension->bIsOpen = FALSE;
}else{
status = STATUS_ACCESS_DENIED;
}
return CompleteRequest(Irp, status, 0);
}
NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG info)
/*++
Routine Description:
Routine to complete the requests
Arguments:
Irp - Pointer to an IRP_MJ_CREATE
status - NT status
info - Irp->IoStatus.Information
Return Value:
NT Status is returned;
--*/
{ // CompleteRequest
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
} // CompleteRequest
/*++
Routine Description:
The default dispatch routine. If this driver does not recognize the
IRP, then it should send it down, unmodified.
If the device holds iris, this IRP must be queued in the device extension
No completion routine is required.
For demonstrative purposes only, we will pass all the (non-PnP) Irps down
on the stack (as we are a filter driver). A real driver might choose to
service some of these Irps.
As we have NO idea which function we are happily passing on, we can make
NO assumptions about whether or not it will be called at raised IRQL.
For this reason, this function must be in put into non-paged pool
(aka the default location).
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code
--*/
/*
Note:
Because we call IoSkipCurrentIrpStackLocation rather than IoCopyCurrentIrpStackLocation, we need NOT
set Irp->IoStatus.Status and NOT call IoCompleteRequest. The only work is to call IoCallDriver.
*/
NTSTATUS DefaultPnpHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension;
IoSkipCurrentIrpStackLocation( Irp );
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
return IoCallDriver( deviceExtension->NextLowerDriver, Irp);
}
NTSTATUS ForwardAndWait(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
/*++
Routine Description:
The routine forwards the IRP to the underlying driver and waits for the lower layer to complete the IRP
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Return Value:
NT Status is returned.
--*/
{
KEVENT event;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext( Irp );
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE);
status = IoCallDriver( deviceExtension->NextLowerDriver, Irp);
if (status == STATUS_PENDING)
{ // wait for completion
KeWaitForSingleObject(
&event,
Executive, // Waiting for reasion of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No alert
NULL); // No timeout
status = Irp->IoStatus.Status;
} // wait for completion
return status;
} // ForwardAndWait
NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT event)
/*++
Routine Description:
A completion routine for use when calling the lower device objects to
which ourdeviceobject is attached.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
event - Pointer to event
Return Value:
NT Status is returned.
--*/
{
KeSetEvent( event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
#if DBG
PCHAR
PnPMinorFunctionString (
UCHAR MinorFunction
)
{
switch (MinorFunction)
{
case IRP_MN_START_DEVICE:
return "IRP_MN_START_DEVICE";
case IRP_MN_QUERY_REMOVE_DEVICE:
return "IRP_MN_QUERY_REMOVE_DEVICE";
case IRP_MN_REMOVE_DEVICE:
return "IRP_MN_REMOVE_DEVICE";
case IRP_MN_CANCEL_REMOVE_DEVICE:
return "IRP_MN_CANCEL_REMOVE_DEVICE";
case IRP_MN_STOP_DEVICE:
return "IRP_MN_STOP_DEVICE";
case IRP_MN_QUERY_STOP_DEVICE:
return "IRP_MN_QUERY_STOP_DEVICE";
case IRP_MN_CANCEL_STOP_DEVICE:
return "IRP_MN_CANCEL_STOP_DEVICE";
case IRP_MN_QUERY_DEVICE_RELATIONS:
return "IRP_MN_QUERY_DEVICE_RELATIONS";
case IRP_MN_QUERY_INTERFACE:
return "IRP_MN_QUERY_INTERFACE";
case IRP_MN_QUERY_CAPABILITIES:
return "IRP_MN_QUERY_CAPABILITIES";
case IRP_MN_QUERY_RESOURCES:
return "IRP_MN_QUERY_RESOURCES";
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
case IRP_MN_QUERY_DEVICE_TEXT:
return "IRP_MN_QUERY_DEVICE_TEXT";
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
case IRP_MN_READ_CONFIG:
return "IRP_MN_READ_CONFIG";
case IRP_MN_WRITE_CONFIG:
return "IRP_MN_WRITE_CONFIG";
case IRP_MN_EJECT:
return "IRP_MN_EJECT";
case IRP_MN_SET_LOCK:
return "IRP_MN_SET_LOCK";
case IRP_MN_QUERY_ID:
return "IRP_MN_QUERY_ID";
case IRP_MN_QUERY_PNP_DEVICE_STATE:
return "IRP_MN_QUERY_PNP_DEVICE_STATE";
case IRP_MN_QUERY_BUS_INFORMATION:
return "IRP_MN_QUERY_BUS_INFORMATION";
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
case IRP_MN_SURPRISE_REMOVAL:
return "IRP_MN_SURPRISE_REMOVAL";
default:
return "IRP_MN_?????";
}
}
#endif
NTSTATUS RequestCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The routine handles the IRP_MJ_CLEANUP which is sent beforce the IRP_MJ_CLOSE.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Return Value:
NT Status is returned.
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PLIST_ENTRY link;
PIRP pendingIrp;
DbgPrint("Entering IRP_MJ_Cleanup\n");
deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
status = STATUS_SUCCESS;
DebugPrint(("to cleanup pending WaitOnMask IRP\n"));
if( deviceExtension->bIsWaitOnMask ){
CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_CANCELLED, 0 );
deviceExtension->WaitOnMaskIrp = NULL;
deviceExtension->bIsWaitOnMask = FALSE;
}
DebugPrint(("to cleanup pending Read IRP\n"));
RequestPurgeIrpQueue( DeviceObject, &deviceExtension->ReadIrpQueue );
DebugPrint(("to cleanup pending Write IRP\n"));
RequestPurgeIrpQueue( DeviceObject, &deviceExtension->WriteIrpQueue );
return CompleteRequest( Irp, status, 0 );
}
#if 0
VOID
OnTimer(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension;
PLIST_ENTRY link;
PIRP IrpToComplete;
deviceExtension = ( PDEVICE_EXTENSION )Context;
if( deviceExtension->timer > 0 ){
deviceExtension->timer--;
}else{
link = NULL;
link = ExInterlockedRemoveHeadList( &deviceExtension->ReadIrpQueue, &deviceExtension->CancelSpinLock );
while( link != NULL ){
IrpToComplete = CONTAINING_RECORD( link, IRP, Tail.Overlay.ListEntry );
ASSERT( IrpToComplete );
DebugPrint(("Fing out pending ReadIrp (0x%x )\n", IrpToComplete ));
CompleteReadIrpOnTimer(deviceExtension, IrpToComplete );
link = ExInterlockedRemoveHeadList( &deviceExtension->ReadIrpQueue, &deviceExtension->CancelSpinLock );
}
deviceExtension->timer = 3;
}
}
VOID
CompleteReadIrpOnTimer(
IN PDEVICE_EXTENSION deviceExtension,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
ULONG ControlCode;
ULONG InputLength,OutputLength;
PUCHAR pOutBuf;
ULONG info;
ULONG i;
CHAR buf[ 256 ];
LARGE_INTEGER time;
DebugPrint(("Enter ReadIrpOnTimer routine ( 0x%x )\n", Irp));
IrpStack = IoGetCurrentIrpStackLocation(Irp);
DebugPrint(("GetCurrentIrpStackLocation OK\n"));
ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputLength= IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
DbgPrint("InputBufferLength: %d OutputBufferLength: %d\n", InputLength, OutputLength );
pOutBuf = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
KeQuerySystemTime(&time);
sprintf( buf, "CurrentTime: %10u-%10u\r\n", time.HighPart, time.LowPart );
memcpy(pOutBuf, buf, ( (strlen( buf ) > OutputLength ) ? OutputLength : strlen( buf ) ) );
info = (strlen( buf ) > OutputLength ) ? OutputLength : strlen( buf ) ;
CompleteRequest( Irp, STATUS_SUCCESS, info );
DebugPrint(("Exit ReadIrpOnTimer routine\n"));
}
#endif