📄 plugplay.cpp
字号:
/*
PlugPlay.cpp
Sheldon Instruments, Inc.
Abstract:
Plug and Play processors for WDM driver. Handles calls to IRP_MJ_PNP.
Revision History:
04Dec1998 - created by Robert Updike
25Feb2000 - Added exception handling and releasing of resources for errors. Robert Updike
20Mar2000 - Added functions for handling of minor PnP calls. Robert Updike
*/
#include "driver.h"
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST list);
NTSTATUS QueryStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS CancelStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS StopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS QueryRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS CancelRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS RemoveDevice(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS SurpriseRemovalDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
VOID ReleaseResources(IN PDEVICE_EXTENSION pdx);
VOID ResetDevice(PDEVICE_EXTENSION pdx);
BOOLEAN DisableDevice(IN PDEVICE_EXTENSION pdx);
BOOLEAN EnableDevice(IN PDEVICE_EXTENSION pdx);
/*
Function name:
Sheldon_ProcessPnPIrp
Routine Description:
Handles plug and play requests. Calls to this function that are not handled by this
driver are passed down to the next level driver.
Arguments:
fdo - pointer to a functional device object
Irp - I/O request being serviced
Return Value:
STATUS_SUCCESS if successful
NTSTATUS code otherwise
*/
NTSTATUS Sheldon_ProcessPnPIrp(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG minor = IrpStack->MinorFunction;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
KdPrint(("SIWDM - Entering Sheldon_ProcessPnPIrp: IRP_MJ_PNP\n"));
switch(minor)
{
case IRP_MN_START_DEVICE:
{
PCM_PARTIAL_RESOURCE_LIST translated;
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: case IRP_MN_START_DEVICE\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardAndWait(pdx, Irp);
if(!NT_SUCCESS(ntStatus))
return CompleteRequest(Irp, ntStatus, 0);
translated = IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated
? &IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList
: NULL;
ntStatus = StartDevice(fdo, translated);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_START_DEVICE (%x)\n", ntStatus));
return CompleteRequest(Irp, ntStatus, 0);
}
case IRP_MN_QUERY_STOP_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: case IRP_MN_QUERY_STOP_DEVICE\n"));
ntStatus = QueryStopDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_QUERY_STOP_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_CANCEL_STOP_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnpIrp: case IRP_MN_CANCEL_STOP_DEVICE\n"));
ntStatus = CancelStopDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_CANCEL_STOP_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_STOP_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_STOP_DEVICE\n"));
ntStatus = StopDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_STOP_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_QUERY_REMOVE_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_QUERY_REMOVE_DEVICE\n"));
ntStatus = QueryRemoveDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_QUERY_REMOVE_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnpIrp: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
ntStatus = CancelRemoveDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_CANCEL_REMOVE_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_REMOVE_DEVICE:
{
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_REMOVE_DEVICE\n"));
ntStatus = RemoveDevice(fdo, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_REMOVE_DEVICE (%x)\n", ntStatus));
return ntStatus;
}
case IRP_MN_SURPRISE_REMOVAL:
{
KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_SURPRISE_REMOVAL\n"));
ntStatus = SurpriseRemovalDevice(pdx, Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_SURPRISE_REMOVAL (%x)\n", ntStatus));
return ntStatus;
}
default:
IoSkipCurrentIrpStackLocation(Irp);
KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: DEFAULT\n"));
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
}
/*
Function name:
StartDevice
Routine Description:
Helper function for IRP_MN_START_DEVICE.
Arguments:
fdo - pointer to a functional device object
list - pointer to a translated resource descriptor list
Return Value:
STATUS_SUCCESS if successful
NTSTATUS code otherwise
*/
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST list)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
ULONG num_of_resources = list->Count;
ULONG vector; // interrupt vector
KIRQL irql; // interrupt level
KINTERRUPT_MODE mode; // interrupt mode
KAFFINITY affinity; // processor affinity for interrupt
PHYSICAL_ADDRESS port; // port address
ULONG port_len; // length of port region
BOOLEAN error = FALSE; // TRUE if there's an error in the resource descriptions
BOOLEAN int_used = FALSE;
ULONG region_cnt = 0;
ULONG j;
KdPrint(("SIWDM - Entering StartDevice\n"));
for(j=0;j<PCI_TYPE0_ADDRESSES;j++)
{
pdx->base[j] = NULL;
pdx->Direct_Baddr[j] = NULL;
}
for(ULONG i=0;i<num_of_resources;++i, ++resource)
{
switch(resource->Type)
{
case CmResourceTypePort:
{
KdPrint(("SIWDM - StartDevice: CmResourceTypePort Iteration:%u\n", i));
port = resource->u.Port.Start;
port_len = resource->u.Port.Length;
if((resource->Flags & CM_RESOURCE_PORT_IO) == 0)
{
pdx->base[region_cnt] = (PULONG) MmMapIoSpace(port, port_len, MmNonCached);
pdx->base_len[region_cnt] = port_len;
if(!pdx->base[region_cnt])
{
for(j=0;j<=region_cnt;j++)
if(pdx->mem_mapped[j])
{
MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
pdx->mem_mapped[j] = NULL;
}
return STATUS_NO_MEMORY;
}
pdx->mem_mapped[region_cnt] = TRUE;
}
else
{
pdx->base[region_cnt] = (PULONG) port.LowPart;
pdx->base_len[region_cnt] = port_len;
pdx->mem_mapped[region_cnt] = FALSE;
}
region_cnt++;
break;
}
case CmResourceTypeInterrupt:
{
KdPrint(("SIWDM - StartDevice: CmResourceTypeInterrupt Iteration:%u\n", i));
int_used = TRUE;
irql = (KIRQL) resource->u.Interrupt.Level;
vector = resource->u.Interrupt.Vector;
affinity = resource->u.Interrupt.Affinity;
mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
? Latched : LevelSensitive;
break;
}
case CmResourceTypeMemory:
{
KdPrint(("SIWDM - StartDevice: CmResourceTypeMemory Iteration:%u\n", i));
port = resource->u.Memory.Start;
port_len = resource->u.Memory.Length;
pdx->base[region_cnt] = (PULONG) MmMapIoSpace(port, port_len, MmNonCached);
pdx->base_len[region_cnt] = (ULONG) resource->u.Memory.Length;
if(!pdx->base[region_cnt])
{
for(j=0;j<=region_cnt;j++)
if(pdx->mem_mapped[j])
{
MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
pdx->mem_mapped[j] = NULL;
}
return STATUS_NO_MEMORY;
}
pdx->mem_mapped[region_cnt] = TRUE;
region_cnt++;
break;
}
case CmResourceTypeDevicePrivate:
KdPrint(("SIWDM - StartDevice: CmResourceTypeDevicePrivate Iteration:%u\n", i));
break;
default:
KdPrint(("SIWDM - StartDevice: CmResourceTypeUnknown Iteration:%u\n", i));
error = TRUE;
break;
}
}
if(error)
{
KdPrint(("SIWDM - StartDevice: Device configuration is invalid\n"));
for(j=0;j<region_cnt;j++)
if(pdx->mem_mapped[j])
{
MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
pdx->mem_mapped[j] = NULL;
}
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
// Install the interrupt and the ISR, as well as the DPC
if(int_used)
{
// Set up a DPC object for use by interrupts later
IoInitializeDpcRequest(fdo, SheldonDpcForIsr);
// Get the Timers, for use with BusMastered Timeouts
KeInitializeDpc(&(pdx->WriteTransfer.TimerDPC), SheldonTimerRoutine, pdx);
KeInitializeTimer(&(pdx->WriteTransfer.Timer));
KeInitializeDpc(&(pdx->ReadTransfer.TimerDPC), SheldonTimerRoutine, pdx);
KeInitializeTimer(&(pdx->ReadTransfer.Timer));
DisableDevice(pdx);
ntStatus = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) SheldonIsr,
(PVOID) pdx, NULL, vector, irql, irql, mode, TRUE, affinity, FALSE);
// unable to connect to interrupt
if(!NT_SUCCESS(ntStatus))
{
KdPrint(("SIWDM - StartDevice: IoConnectInterrupt failed with ntStatus 0x%x\n", ntStatus));
for(i=0;i<region_cnt;i++)
if(pdx->mem_mapped[i])
{
MmUnmapIoSpace(pdx->base[i], pdx->base_len[i]);
pdx->mem_mapped[i] = NULL;
}
return ntStatus;
}
// can't enable device
if(!KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) EnableDevice, (PVOID) pdx))
{
KdPrint(("SIWDM - StartDevice: Unable to enable device\n"));
IoDisconnectInterrupt(pdx->InterruptObject);
for(i=0;i<region_cnt;i++)
if(pdx->mem_mapped[i])
{
MmUnmapIoSpace(pdx->base[i], pdx->base_len[i]);
pdx->mem_mapped[i] = NULL;
}
return STATUS_INVALID_DEVICE_STATE;
}
}
// Device is ready to run.
pdx->state = WORKING;
AllowRequests(&pdx->dqReadWrite);
RestartRequests(&pdx->dqReadWrite, fdo);
KdPrint(("SIWDM - Exiting StartDevice (%x)\n", ntStatus));
return ntStatus;
}
/*
Function name:
QueryStopDevice
Routine Description:
Determines if the device can handle a IRP_MN_STOP_DEVICE request.
Arguments:
pdx - pointer to the device extension
Irp - I/O request being serviced
Return Value:
STATUS_SUCCESS if successful
NTSTATUS code otherwise
*/
NTSTATUS QueryStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
if(pdx->state != WORKING)
{
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
// Stall the request and wait for the current IRP to finish
if(&pdx->dqReadWrite)
{
StallRequests(&pdx->dqReadWrite);
WaitForCurrentIrp(&pdx->dqReadWrite);
}
pdx->state = PENDINGSTOP;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
/*
Function name:
CancelStopDevice
Routine Description:
Cancels the previous query to stop the device IRP_MN_CANCEL_STOP_DEVICE.
Arguments:
pdx - pointer to the device extension
Irp - I/O request being serviced
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -