📄 pnp.c
字号:
/*++
Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
Module Name:
pnp.c
Abstract:
This module contains the code that handles the plug and play
IRPs for the serial driver.
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
#define ALLF 0xffffffff
static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESRP0, SerialCreateDevObj)
#pragma alloc_text(PAGESRP0, SerialAddDevice)
#pragma alloc_text(PAGESRP0, SerialPnpDispatch)
#pragma alloc_text(PAGESRP0, SerialStartDevice)
#pragma alloc_text(PAGESRP0, SerialFinishStartDevice)
#pragma alloc_text(PAGESRP0, SerialGetPortInfo)
#pragma alloc_text(PAGESRP0, SerialDoExternalNaming)
#pragma alloc_text(PAGESRP0, SerialReportMaxBaudRate)
#pragma alloc_text(PAGESRP0, SerialControllerCallBack)
#pragma alloc_text(PAGESRP0, SerialItemCallBack)
#pragma alloc_text(PAGESRP0, SerialUndoExternalNaming)
#endif // ALLOC_PRAGMA
//
// Instantiate the GUID
//
#if !defined(FAR)
#define FAR
#endif // !defined(FAR)
#include <initguid.h>
DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08,
0x00, 0x3e, 0x30, 0x1f, 0x73);
#if DBG
UCHAR *SerSystemCapString[] = {
"PowerSystemUnspecified",
"PowerSystemWorking",
"PowerSystemSleeping1",
"PowerSystemSleeping2",
"PowerSystemSleeping3",
"PowerSystemHibernate",
"PowerSystemShutdown",
"PowerSystemMaximum"
};
UCHAR *SerDeviceCapString[] = {
"PowerDeviceUnspecified",
"PowerDeviceD0",
"PowerDeviceD1",
"PowerDeviceD2",
"PowerDeviceD3",
"PowerDeviceMaximum"
};
#endif // DBG
NTSTATUS
SerialSyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
IN PKEVENT SerialSyncEvent)
{
KeSetEvent(SerialSyncEvent, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SerialCreateDevObj(IN PDRIVER_OBJECT DriverObject,
OUT PDEVICE_OBJECT *NewDeviceObject)
/*++
Routine Description:
This routine will create and initialize a functional device object to
be attached to a Serial controller PDO.
Arguments:
DriverObject - a pointer to the driver object this is created under
NewDeviceObject - a location to store the pointer to the new device object
Return Value:
STATUS_SUCCESS if everything was successful
reason for failure otherwise
--*/
{
UNICODE_STRING deviceObjName;
PDEVICE_OBJECT deviceObject = NULL;
PSERIAL_DEVICE_EXTENSION pDevExt;
NTSTATUS status = STATUS_SUCCESS;
static ULONG currentInstance = 0;
UNICODE_STRING instanceStr;
WCHAR instanceNumberBuffer[20];
PAGED_CODE();
SerialDbgPrintEx(SERTRACECALLS, "EnterSerialCreateDevObj\n");
//
// Zero out allocated memory pointers so we know if they must be freed
//
RtlZeroMemory(&deviceObjName, sizeof(UNICODE_STRING));
deviceObjName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
deviceObjName.Buffer = ExAllocatePool(PagedPool, deviceObjName.MaximumLength
+ sizeof(WCHAR));
if (deviceObjName.Buffer == NULL) {
SerialLogError(DriverObject, NULL, SerialPhysicalZero, SerialPhysicalZero,
0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES,
0, NULL, 0, NULL);
SerialDbgPrintEx(SERERRORS,
"Couldn't allocate memory for device name\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(deviceObjName.Buffer, deviceObjName.MaximumLength
+ sizeof(WCHAR));
RtlAppendUnicodeToString(&deviceObjName, L"\\Device\\Serial");
RtlInitUnicodeString(&instanceStr, NULL);
instanceStr.MaximumLength = sizeof(instanceNumberBuffer);
instanceStr.Buffer = instanceNumberBuffer;
RtlIntegerToUnicodeString(currentInstance++, 10, &instanceStr);
RtlAppendUnicodeStringToString(&deviceObjName, &instanceStr);
//
// Create the device object
//
status = IoCreateDevice(DriverObject, sizeof(SERIAL_DEVICE_EXTENSION),
&deviceObjName, FILE_DEVICE_SERIAL_PORT,
FILE_DEVICE_SECURE_OPEN, TRUE, &deviceObject);
if (!NT_SUCCESS(status)) {
SerialDbgPrintEx(SERERRORS, "SerialAddDevice: Create device failed - %x "
"\n", status);
goto SerialCreateDevObjError;
}
ASSERT(deviceObject != NULL);
//
// The device object has a pointer to an area of non-paged
// pool allocated for this device. This will be the device
// extension. Zero it out.
//
pDevExt = deviceObject->DeviceExtension;
RtlZeroMemory(pDevExt, sizeof(SERIAL_DEVICE_EXTENSION));
//
// Initialize the count of IRP's pending
//
pDevExt->PendingIRPCnt = 1;
//
// Initialize the count of DPC's pending
//
pDevExt->DpcCount = 1;
//
// Allocate Pool and save the nt device name in the device extension.
//
pDevExt->DeviceName.Buffer =
ExAllocatePool(PagedPool, deviceObjName.Length + sizeof(WCHAR));
if (!pDevExt->DeviceName.Buffer) {
SerialLogError(
DriverObject,
NULL,
SerialPhysicalZero,
SerialPhysicalZero,
0,
0,
0,
19,
STATUS_SUCCESS,
SERIAL_INSUFFICIENT_RESOURCES,
0,
NULL,
0,
NULL
);
SerialDbgPrintEx(SERERRORS, "Couldn't allocate memory for DeviceName\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto SerialCreateDevObjError;
}
pDevExt->DeviceName.MaximumLength = deviceObjName.Length
+ sizeof(WCHAR);
//
// Zero fill it.
//
RtlZeroMemory(pDevExt->DeviceName.Buffer,
pDevExt->DeviceName.MaximumLength);
RtlAppendUnicodeStringToString(&pDevExt->DeviceName, &deviceObjName);
pDevExt->NtNameForPort.Buffer = ExAllocatePool(PagedPool,
deviceObjName.MaximumLength);
if (pDevExt->NtNameForPort.Buffer == NULL) {
SerialDbgPrintEx(SERERRORS, "SerialAddDevice: Cannot allocate memory for "
"NtName\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto SerialCreateDevObjError;
}
pDevExt->NtNameForPort.MaximumLength = deviceObjName.MaximumLength;
RtlAppendUnicodeStringToString(&pDevExt->NtNameForPort,
&deviceObjName);
//
// Set up the device extension.
//
pDevExt->DeviceIsOpened = FALSE;
pDevExt->DeviceObject = deviceObject;
pDevExt->DriverObject = DriverObject;
pDevExt->DeviceObject = deviceObject;
pDevExt->PowerState = PowerDeviceD0;
pDevExt->TxFifoAmount = driverDefaults.TxFIFODefault;
pDevExt->CreatedSymbolicLink = TRUE;
pDevExt->OwnsPowerPolicy = TRUE;
InitializeListHead(&pDevExt->CommonInterruptObject);
InitializeListHead(&pDevExt->TopLevelSharers);
InitializeListHead(&pDevExt->MultiportSiblings);
InitializeListHead(&pDevExt->AllDevObjs);
InitializeListHead(&pDevExt->ReadQueue);
InitializeListHead(&pDevExt->WriteQueue);
InitializeListHead(&pDevExt->MaskQueue);
InitializeListHead(&pDevExt->PurgeQueue);
InitializeListHead(&pDevExt->StalledIrpQueue);
ExInitializeFastMutex(&pDevExt->OpenMutex);
ExInitializeFastMutex(&pDevExt->CloseMutex);
//
// Initialize the spinlock associated with fields read (& set)
// by IO Control functions and the flags spinlock.
//
KeInitializeSpinLock(&pDevExt->ControlLock);
KeInitializeSpinLock(&pDevExt->FlagsLock);
KeInitializeEvent(&pDevExt->PendingIRPEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&pDevExt->PendingDpcEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&pDevExt->PowerD0Event, SynchronizationEvent, FALSE);
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
*NewDeviceObject = deviceObject;
ExFreePool(deviceObjName.Buffer);
SerialDbgPrintEx(SERTRACECALLS, "Leave SerialCreateDevObj\n");
return STATUS_SUCCESS;
SerialCreateDevObjError:
SerialDbgPrintEx(SERERRORS, "SerialCreateDevObj Error, Cleaning up\n");
//
// Free the allocated strings for the NT and symbolic names if they exist.
//
if (deviceObjName.Buffer != NULL) {
ExFreePool(deviceObjName.Buffer);
}
if (deviceObject) {
if (pDevExt->NtNameForPort.Buffer != NULL) {
ExFreePool(pDevExt->NtNameForPort.Buffer);
}
if (pDevExt->DeviceName.Buffer != NULL) {
ExFreePool(pDevExt->DeviceName.Buffer);
}
IoDeleteDevice(deviceObject);
}
*NewDeviceObject = NULL;
SerialDbgPrintEx(SERTRACECALLS, "Leave SerialCreateDevObj\n");
return status;
}
NTSTATUS
SerialAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PPdo)
/*++
Routine Description:
This routine creates a functional device object for com ports in the
system and attaches them to the physical device objects for the ports
Arguments:
DriverObject - a pointer to the object for this driver
PPdo - a pointer to the PDO in the stack we need to attach to
Return Value:
status from device creation and initialization
--*/
{
PDEVICE_OBJECT pNewDevObj = NULL;
PDEVICE_OBJECT pLowerDevObj = NULL;
NTSTATUS status;
PSERIAL_DEVICE_EXTENSION pDevExt;
PAGED_CODE();
SerialDbgPrintEx(SERTRACECALLS, "Enter SerialAddDevice with PPdo 0x%x\n",
PPdo);
if (PPdo == NULL) {
//
// Return no more devices
//
SerialDbgPrintEx(SERERRORS, "SerialAddDevice: Enumeration request, "
"returning NO_MORE_ENTRIES\n");
return (STATUS_NO_MORE_ENTRIES);
}
//
// create and initialize the new device object
//
status = SerialCreateDevObj(DriverObject, &pNewDevObj);
if (!NT_SUCCESS(status)) {
SerialDbgPrintEx(SERERRORS,
"SerialAddDevice - error creating new devobj [%#08lx]\n",
status);
return status;
}
//
// Layer our DO on top of the lower device object
// The return value is a pointer to the device object to which the
// DO is actually attached.
//
pLowerDevObj = IoAttachDeviceToDeviceStack(pNewDevObj, PPdo);
//
// No status. Do the best we can.
//
ASSERT(pLowerDevObj != NULL);
pDevExt = pNewDevObj->DeviceExtension;
pDevExt->LowerDeviceObject = pLowerDevObj;
pDevExt->Pdo = PPdo;
//
// Specify that this driver only supports buffered IO. This basically
// means that the IO system copies the users data to and from
// system supplied buffers.
//
// Also specify that we are power pagable.
//
pNewDevObj->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
SerialDbgPrintEx(SERTRACECALLS, "Leave SerialAddDevice\n");
return status;
}
NTSTATUS
SerialPnpDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This is a dispatch routine for the IRPs that come to the driver with the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -