Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
I has been tested a driver. When I attempt to disable a driver, it receives IRP_MN_QUERY_REMOVE_DEVICE but never receives IRP_MN_REMOVE_DEVICE. When I compile a same driver for Windows XP PnP signalisation works fine. IRP_MN_REMOVE_DEVICE is received. I have no clue why Windows does not send me IRP_MN_REMOVE_DEVICE.
Here is a description on Microsoft pages, but there are no explanation, why Windows 10 hangs in remove-pending state.
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/understanding-when-remove-irps-are-issued
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/images/rem-irps.png
The IRP dispatching seems workable:
static NTSTATUS DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS status; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); DEVICEDATA *deviceData = (DEVICEDATA*)DeviceObject->DeviceExtension; switch(stack->MinorFunction) { case IRP_MN_START_DEVICE: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_START_DEVICE"); if(deviceData->NumMemResources>0 || deviceData->NumIOResources>0 || deviceData->NumIRQResources>0) { DeallocateResources(deviceData); /* Double start condition!!! */ } status = PnpStart(DeviceObject, Irp); deviceData->DevicePnPState = Started; break; case IRP_MN_QUERY_STOP_DEVICE: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_QUERY_STOP_DEVICE"); deviceData->DevicePnPState = StopPending; SendIrpSynchronously(deviceData->NextLowerDriver, Irp); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: /* warning before device removing */ _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_QUERY_REMOVE_DEVICE"); deviceData->DevicePnPState = RemovePending; //IoSetDeviceInterfaceState(&deviceData->InterfaceName, FALSE); // Shutdown all outstanding interfaces. //https://github.com/teeedubb/ScpServer/blob/master/ScpVBus/bus/buspdo.c //https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/handling-an-irp-mn-query-remove-device-request //SendIrpSynchronously(deviceData->NextLowerDriver, Irp); //_DbgPrintF(DEBUGLVL_VERBOSE, "SendIrpSynchronously() finished"); //status = STATUS_SUCCESS; //break; //Irp->IoStatus.Status = STATUS_SUCCESS; //IoCompleteRequest(Irp, IO_NO_INCREMENT); //return STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(deviceData->NextLowerDriver, Irp); _DbgfprintF(DEBUGLVL_VERBOSE, "query remove IoCallDriver status = %Xh\n",status); return status; //status = SendIrpAsync(deviceData->NextLowerDriver, Irp); //_DbgfprintF(DEBUGLVL_VERBOSE, "status = %Xh\n",status); //return status; case IRP_MN_STOP_DEVICE: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_STOP_DEVICE"); deviceData->DevicePnPState = Stopped; DeallocateResources(deviceData); /* Pass the IRP down so that lower drivers can stop. */ Irp->IoStatus.Status = STATUS_SUCCESS; // A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. SendIrpAsync(deviceData->NextLowerDriver, Irp); return STATUS_SUCCESS; case IRP_MN_REMOVE_DEVICE: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_REMOVE_DEVICE"); deviceData->DevicePnPState = Deleted; /* Disable the device interface */ IoSetDeviceInterfaceState(&deviceData->InterfaceName, FALSE); DeallocateResources(deviceData); Irp->IoStatus.Status = STATUS_SUCCESS; // A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. SendIrpAsync(deviceData->NextLowerDriver, Irp); // delete our device, we have to do this after we send the request down IoDetachDevice(deviceData->NextLowerDriver); deviceData->NextLowerDriver = NULL; IoDeleteDevice(DeviceObject); return STATUS_SUCCESS; // This could allow to unload and load driver without rebooting. Not tested yet. case IRP_MN_QUERY_CAPABILITIES: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_QUERY_CAPABILITIES"); { PDEVICE_CAPABILITIES DeviceCapabilities; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); //TRACE(TL_TRACE, ("t1394VDev_Pnp: IRP_MN_QUERY_CAPABILITIES\n")); DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; if(DeviceCapabilities) DeviceCapabilities->SurpriseRemovalOK = TRUE; SendIrpSynchronously(deviceData->NextLowerDriver, Irp); status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_DEVICE_RELATIONS: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_QUERY_DEVICE_RELATIONS"); Irp->IoStatus.Status = STATUS_SUCCESS; // A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. IoSkipCurrentIrpStackLocation(Irp); return(IoCallDriver(deviceData->NextLowerDriver, Irp)); //Irp->IoStatus.Status = status; //IoCompleteRequest(Irp, IO_NO_INCREMENT); //return STATUS_SUCCESS; case IRP_MN_CANCEL_REMOVE_DEVICE: _DbgPrintF(DEBUGLVL_VERBOSE, "IRP_MN_CANCEL_REMOVE_DEVICE"); IoSkipCurrentIrpStackLocation(Irp); return(IoCallDriver(deviceData->NextLowerDriver, Irp)); default : // Asynchronous handling of unknown PnP request. _DbgfprintF(DEBUGLVL_VERBOSE, "Unknown IRP received %u\n",stack->MinorFunction); IoSkipCurrentIrpStackLocation(Irp); return(IoCallDriver(deviceData->NextLowerDriver, Irp)); //break; } /* Signal OK and complete the IRP. */ Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return(status); }
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Writing WDF Drivers | 7 Dec 2020 | LIVE ONLINE |
Internals & Software Drivers | 25 Jan 2021 | LIVE ONLINE |
Developing Minifilters | 8 March 2021 | LIVE ONLINE |
Comments
You're not completing the request, you're forwarding it to the next driver device in the stack.
Maybe the next one is failing the request ?
Microsoft exactly wants this approach:
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/handling-an-irp-mn-query-remove-device-request
Finish the IRP:
In a function or filter driver:
1. Set Irp->IoStatus.Status to STATUS_SUCCESS.
2. Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.
3. Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.
4. ** Do not complete the IRP.**
PCI device is not a bus driver:
_In a bus driver:
* Set Irp->IoStatus.Status to STATUS_SUCCESS.
_
This is all my tracelog (13=IRP_MN_FILTER_RESOURCE_REQUIREMENTS):
I put a request to stop device (I attempt to hook IRP completion request callback):
The device is marked as stopped in Windows 10. No error emitted.
And attempt to start device again fails (8 - IRP_MN_QUERY_INTERFACE):
May be that this is something new in Windows 10. As I have written this signalisation still works in Windows XP.
It is simply because previous shutdown sequence has never been completed. And Windows protects to add second device to the driver. May be that something hanged and Windows decides not to continue in shutdown sequence.
I can fix AddDevice and internally test whether previous device has been released or not.
But I still prefer to discower why the device cannot be removed and shutdown sequence hangs.
When your driver misses IRP_MN_REMOVE_DEVICE, what does setupapi.dev.log say? does the log indicate that the remove was successful? I think there is a bug in your driver, not a missing or orphanced remove device . Why? Because
a) if it is missing, then the stack would not be rebuilt. The only way a stack is rebuilt is if it is in the surprise removed or completely gracefully removed.
b) a remove device irp is a pnp state changing irp. Only one can be active at a time. While active, it holds the pnp state lock. AddDevice is also a state pnp changing operation and requires the same lock.
Are you in a device class that installs upper filters above your FDO?
I have finally found a source of problem. Thanks for support. PnP signalisation has been implemented correctly.
The problem was missing deviceObject->Flags settings. This is causing problems in Windows 10. It worked for many years without visible problems. Not setting deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; is newly causing loosing IRP_MN_REMOVE_DEVICE.
deviceObject->Flags |= deviceData->NextLowerDriver->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
deviceObject->DeviceType = deviceData->NextLowerDriver->DeviceType;
deviceObject->Characteristics = deviceData->NextLowerDriver->Characteristics;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
I, for one, want to thank you for posting the resolution. So often, we never hear what the real problem was.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
I am not sure why this flag has so big impact to further PnP behaiour. Driver works fine for now on.
It is highly unclean why Windows driver worked correctly for many years.
May be that Windows newly sets bit DO_DEVICE_INITIALIZING.
Absolutely not. I went back to my dusty copy of Walter Oney's "Programming the Windows Driver Model" from 1999, and even it stresses the importance of clearing DO_DEVICE_INITIALIZING. I went back even further to the samples in the NT 4.0 DDK, it also emphasizes this.
It has ALWAYS been an important driver responsibility to clear that bit.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Tim is correct. DO_DEVICE_INITIALIZING has been present from the start of NT (pre pnp) and it was necessary to clear to be able to create a handle to the device. In the move to pnp, that requirement is kept. I am guessing the reason you never saw an issue is that when a handle to a device interface is opened, the handle is against the PDO not your FDO, so the the bit being set on your FDO after AddDevice never affected the create handle path. It was always a latent bug in your driver and it just happened that an update to Windows 10 exposed the bug.