We’re developping a USB bus driver that creates 3 child PDO that act as serial port with their own driver. We’re trying to gain WHQL validation and currently fail tne PnP test when it tests the IRP_MN_REMOVE_DEVICE on the serial driver. Here is the result we get fro the driver verifier:
OurSer - fdo 0x896CE8C8 - PNP Request ( IRP_MN_QUERY_REMOVE_DEVICE -> HandleQueryRemove )
OurUsb - pdo 0x89B5F5C0 - PNP Request( IRP_MN_QUERY_REMOVE_DEVICE)
PNPFILTR: FilterQueryRemove returning 0x00000002 for stack with PDO 0x89B5F5C0
PNPFILTR: Received IRP_MN_QUERY_REMOVE_DEVICE for stack with PDO 0x89D9A2C0
OurSer - fdo 0x89A8AC88 - PNP Request ( IRP_MN_QUERY_REMOVE_DEVICE -> HandleQueryRemove )
OurUsb - pdo 0x89D9A2C0 - PNP Request( IRP_MN_QUERY_REMOVE_DEVICE)
PNPFILTR: FilterQueryRemove returning 0x00000002 for stack with PDO 0x89D9A2C0
PNPFILTR: Received IRP_MN_QUERY_REMOVE_DEVICE for stack with PDO 0x89D951A8
OurUsb - fdo 0x89BA3DA8 - PNP Request (IRP_MN_QUERY_REMOVE_DEVICE)
PNPFILTR: FilterQueryRemove returning 0x00000004 for stack with PDO 0x89D951A8
PNPFILTR: Received IRP_MN_REMOVE_DEVICE for stack with PDO 0x89B012B8
OurSer - fdo 0x89724030 - PNP Request ( IRP_MN_REMOVE_DEVICE -> HandleRemoveDevice )
OurSer - fdo 0x89724030 - Disabling device interface
OurSer - fdo 0x89724030 - To REMOVED from PENDINGREMOVE
OurUsb - pdo 0x89B012B8 - PNP Request( IRP_MN_REMOVE_DEVICE)
***********************************************************************
* THIS VALIDATION BUG IS FATAL AND WILL CAUSE THE VERIFIER TO HALT *
* WINDOWS (BUGCHECK) WHEN THE MACHINE IS NOT UNDER A KERNEL DEBUGGER! *
***********************************************************************
WDM DRIVER ERROR: [ourusb.sys @ 0xAD0E17B0] An IRP dispatch handler for a
PDO has deleted it’s device object, but the hardware has
not been reported as missing in a bus relations query.
DeviceObject = 89B012B8 - Dispatch = AD0E17B0 - Irp =
8AE90F20
IRP_MJ_PNP.IRP_MN_REMOVE_DEVICE -
We’ve compared to what the toaster DDK example does and we seem to be doing the same actions, but obviously we must be missing something. In the serial driver, we do:
// This IRP must never fail
Irp->IoStatus.Status = STATUS_SUCCESS;
if( NT_SUCCESS( IoAcquireRemoveLock( &pdx->RemoveLock, Irp ) ) )
{
// Cancel any queued IRPs and start rejecting new ones
AbortRequests(&pdx->dqRead, STATUS_DELETE_PENDING);
// Disable all device interfaces. This triggers PnP notifications that will allow apps to close their handles.
DeregisterAllInterfaces( pdx );
DumpDebug( DBG_PNP, ( DRIVERNAME " - fdo 0x%X - To REMOVED from %s\n", fdo, statenames[pdx->state]) );
pdx->state = REMOVED;
// Let lower-level drivers handle this request. Ignore whatever result eventuates.
DefaultPnpHandler( fdo, Irp );
// Wait for all claims against this device to vanish before removing the device object.
IoReleaseRemoveLockAndWait( &pdx->RemoveLock, Irp );
// Remove the device object
RemoveDevice( fdo );
}
return STATUS_SUCCESS; // lower-level completed IoStatus already
The failure occurs in DefaultPnpHandler() which simply send the IRP to the lower device, which is our USB driver:
IoSkipCurrentIrpStackLocation( Irp );
PSERIAL_DEVICE_EXTENSION pdx = (PSERIAL_DEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS Status = STATUS_SUCCESS;
if( pdx->LowerDeviceObject )
Status = IoCallDriver( pdx->LowerDeviceObject, Irp );
In the USB driver, we simply succeed the IRP:
case IRP_MN_REMOVE_DEVICE:
DumpDebug( DBG_PNPPDO, (DRIVERNAME " - pdo 0x%X - PNP Request( IRP_MN_REMOVE_DEVICE)\n",pdo) );
status = PdoSucceedRequest(pdo,Irp );
And PdoSucceedRequest() does as its name implies:
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest ( Irp, IO_NO_INCREMENT );
Any help about what we are doing wrong?