📄 testpnp.c
字号:
// ===================================================================
//
// testpnp.c
//
// rev 1.0 beta
//
// this module handles USB PnP calls.
//
// USB device driver for USB Device Example
// kernel mode driver
//
//
// to be compiled with
// - Windows 98 Beta 3 DDK
//
// ===================================================================
#include <wdm.h>
#include "test98.h"
#include "stdio.h"
// ==================================================================
NTSTATUS
Test98_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
to create and initialize our FDO, set things up...
DeviceObject - Device object representing the new FDO.
DriverObject - This very self referenced driver.
--*/
{
NTSTATUS status;
PDEVICE_OBJECT deviceObject;
PFDO_DEVICE_DATA deviceData;
UNICODE_STRING deviceNameUni;
PWCHAR deviceName;
ULONG nameLength;
UNICODE_STRING pdoUniName;
WCHAR pdoName[] = L"\\Device\\Test-0" ; // DeviceNameBuffer
WCHAR DeviceLinkBuffer[] = L"\\DosDevices\\Test-0";
UNICODE_STRING DeviceLinkUnicodeString;
RtlInitUnicodeString (&pdoUniName, pdoName);
status = IoCreateDevice (
DriverObject, // our driver object
sizeof (FDO_DEVICE_DATA), // device object extension size
&pdoUniName,
FILE_DEVICE_UNKNOWN,
0, // No special characteristics
FALSE,
&deviceObject); // The device object created
if (NT_SUCCESS (status)) {
RtlInitUnicodeString (&DeviceLinkUnicodeString,
DeviceLinkBuffer);
status = IoCreateSymbolicLink(&DeviceLinkUnicodeString,
&pdoUniName);
deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
RtlFillMemory (deviceData, sizeof (FDO_DEVICE_DATA), 0);
deviceData->IsFDO = TRUE;
deviceData->DebugLevel = TEST_DEFAULT_DEBUG_OUTPUT_LEVEL;
deviceData->Self = deviceObject;
KeInitializeSpinLock (&deviceData->Spin);
deviceData->Removed = FALSE;
InitializeListHead (&deviceData->PDOs);
// Set the PDO for use with PlugPlay functions
deviceData->UnderlyingPDO = PhysicalDeviceObject;
// Attach our driver to the device stack.
deviceData->TopOfStack = IoAttachDeviceToDeviceStack (
deviceObject,
PhysicalDeviceObject);
// Bias outstanding request to 1 so that we can look for a
// transition to zero when processing the remove device PlugPlay IRP.
deviceData->OutstandingIO = 1;
KeInitializeEvent(&deviceData->RemoveEvent,
SynchronizationEvent,
FALSE); // initialized to not signalled
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
deviceObject->Flags |= DO_POWER_PAGABLE;
// register device functionality
status = IoRegisterDeviceInterface (
PhysicalDeviceObject,
(LPGUID) &GUID_TEST_DEVICE,
NULL, // No ref string
&deviceData->DevClassAssocName);
status = IoSetDeviceInterfaceState (
&deviceData->DevClassAssocName,
TRUE);
}
return status;
}
// ==================================================================
NTSTATUS
Test98_FDO_PnPComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Pirp,
IN PVOID Context
);
// ==================================================================
NTSTATUS
Test98_PnP (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Handles Major PnP IRPS...
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PCOMMON_DEVICE_DATA commonData;
KIRQL oldIrq;
PAGED_CODE ();
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
status = Test98_FDO_PnP (
DeviceObject,
Irp,
irpStack,
(PFDO_DEVICE_DATA) commonData);
return status;
}
// ==================================================================
NTSTATUS
Test98_FDO_PnP (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpStack,
IN PFDO_DEVICE_DATA DeviceData
)
/*++
Handles requests from the PlugPlay system for the FDO
--*/
{
NTSTATUS status;
KIRQL oldIrq;
KEVENT event;
ULONG length;
ULONG i;
PLIST_ENTRY entry;
PPDO_DEVICE_DATA pdoData;
PDEVICE_RELATIONS relations;
PIO_STACK_LOCATION stack;
PAGED_CODE ();
status = Test98_IncIoCount (DeviceData);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
stack = IoGetCurrentIrpStackLocation (Irp);
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
// PnP manager send this IPR after assigning resoureces to the device;
// the device may have been recently numerate and being started
// for the first time
if (DeviceData->Started) {
status = STATUS_SUCCESS;
break;
}
Test98_KdPrint (DeviceData, TEST_DBG_PNP_TRACE, ("Start Device\n"));
KeInitializeEvent (&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext (Irp);
IoSetCompletionRoutine (Irp,
Test98_FDO_PnPComplete,
&event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver (DeviceData->TopOfStack, Irp);
if (STATUS_PENDING == status) {
// wait for it...
status = KeWaitForSingleObject (&event,
Executive,
KernelMode,
FALSE, // Not allertable
NULL); // No timeout structure
ASSERT (STATUS_SUCCESS == status);
status = Irp->IoStatus.Status;
}
if (NT_SUCCESS(status)) {
//
// Do what ever after device started
//
if ((NULL == stack->Parameters.StartDevice.AllocatedResources) ||
(NULL == stack->Parameters.StartDevice.AllocatedResourcesTranslated)) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
status = Test98_StartFdo (DeviceData,
&stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList,
&stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList);
if (NT_SUCCESS (status)) {
DeviceData->Started = TRUE;
}
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Information = 0;
break;
case IRP_MN_QUERY_STOP_DEVICE:
Test98_KdPrint (DeviceData, TEST_DBG_PNP_TRACE, ("Query Stop Device\n"));
// This occurs during shutdown when user explicitly requesting
// the service to be stopped
//
if (DeviceData->NumPDOs) {
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
}
Irp->IoStatus.Status = status;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (DeviceData->TopOfStack, Irp);
Test98_DecIoCount (DeviceData);
return status;
case IRP_MN_STOP_DEVICE:
Test98_KdPrint (DeviceData, TEST_DBG_PNP_TRACE, ("Stop Device\n"));
// PnP manager sends this IPR to stop a device so that it can reconfigure
// its resources. sends this only after IRP_MN_QUERY_STOP_DEVICE
// completed successfully
//
if (DeviceData->Started) {
//
// Free resources given by start device.
//
if (DeviceData->MappedPorts) {
MmUnmapIoSpace (DeviceData->TestPortAddress, 1);
}
}
DeviceData->Started = FALSE;
//
// don't need a completion routine so fire and forget.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (DeviceData->TopOfStack, Irp);
Test98_DecIoCount (DeviceData);
return status;
case IRP_MN_REMOVE_DEVICE:
Test98_KdPrint (DeviceData, TEST_DBG_PNP_TRACE, ("Remove Device\n"));
//
// PnP manager uses this IRP to dirct drivers to remove a device
//
DeviceData->Removed = TRUE;
//
// Complete any outstanding IRPs queued by the driver here.
//
IoSetDeviceInterfaceState (&DeviceData->DevClassAssocName, FALSE);
//
// complete any outstanding reqeusts now.
// Fire and forget
//
IoSkipCurrentIrpStackLocation (Irp);
IoCallDriver (DeviceData->TopOfStack, Irp);
//
// Wait for all outstanding requests to complete
//
i = InterlockedDecrement (&DeviceData->OutstandingIO);
ASSERT (0 < i);
if (0 != InterlockedDecrement (&DeviceData->OutstandingIO)) {
Test98_KdPrint (DeviceData, TEST_DBG_PNP_INFO,
("Remove Device waiting for request to complete\n"));
KeWaitForSingleObject (&DeviceData->RemoveEvent,
Suspended,
KernelMode,
FALSE, // Not Alertable
NULL); // No timeout
}
//
// Free the associated resources
// Detatch from the undelying devices.
//
Test98_KdPrint(DeviceData, TEST_DBG_PNP_INFO,
("IoDetachDevice: 0x%x\n", DeviceData->TopOfStack));
IoDetachDevice (DeviceData->TopOfStack);
//
// Clean up any resources here
//
if (DeviceData->Started) {
//
// Free resources given by start device.
//
if (DeviceData->MappedPorts) {
MmUnmapIoSpace (DeviceData->TestPortAddress, 1);
}
}
ExFreePool (DeviceData->DevClassAssocName.Buffer);
Test98_KdPrint(DeviceData, TEST_DBG_PNP_INFO,
("IoDeleteDevice1: 0x%x\n", DeviceObject));
IoDeleteDevice (DeviceObject);
return STATUS_SUCCESS;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// the driver indicates to system whether it can be removed
// in response to this IPR...
//
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (DeviceData->TopOfStack, Irp);
Test98_DecIoCount (DeviceData);
return status;
default:
//
// In the default case we merely call the next driver since
// we don't know what to do.
// Fire and Forget
//
IoSkipCurrentIrpStackLocation (Irp);
//
// Done, do NOT complete the IRP, it will be processed by the lower
// device object, which will complete the IRP
//
status = IoCallDriver (DeviceData->TopOfStack, Irp);
Test98_DecIoCount (DeviceData);
return status;
}
Irp->IoStatus.Status = status;
DbgRaiseIrql (DISPATCH_LEVEL, &oldIrq);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
DbgLowerIrql (oldIrq);
Test98_DecIoCount (DeviceData);
return status;
}
// ==================================================================
NTSTATUS
Test98_FDO_PnPComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
A completion routine for use when calling the lower device objects to
which our FDO is attached.
--*/
{
UNREFERENCED_PARAMETER (DeviceObject);
if (Irp->PendingReturned) {
IoMarkIrpPending( Irp );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -