NTSTATUS Bus_FDO_PnP ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpStack, PFDO_DEVICE_DATA DeviceData ) { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = Bus_StartFdo (DeviceData, Irp); // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. // SET_NEW_PNP_STATE(DeviceData->Common, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if // someone above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->Common.DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common); ASSERT(DeviceData->Common.DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_QUERY_DEVICE_RELATIONS: DPRINT("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type)); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + (((numPdosPresent + prevcount) - 1) * sizeof (PDEVICE_OBJECT)); relations = ExAllocatePoolWithTag(PagedPool, length, 'IpcA'); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); relations->Objects[prevcount] = pdoData->Common.Self; ObReferenceObject (pdoData->Common.Self); prevcount++; } DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePoolWithTag(oldRelations, 0); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); return STATUS_SUCCESS; }
NTSTATUS Bus_FDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the BUS itself --*/ { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); Bus_IncIoCount (DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Send the Irp down and wait for it to come back. // Do not touch the hardware until then. // status = Bus_SendIrpSynchronously (DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { // // Initialize your device with the resources provided // by the PnP manager to your device. // status = Bus_StartFdo (DeviceData, Irp); } // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. Fail this now if you // cannot stop the device in response to STOP_DEVICE. // SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if // someone above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_STOP_DEVICE: // // Stop device means that the resources given during Start device // are now revoked. Note: You must not fail this Irp. // But before you relieve resources make sure there are no I/O in // progress. Wait for the existing ones to be finished. // To do that, first we will decrement this very operation. // When the counter goes to 1, Stop event is set. // Bus_DecIoCount(DeviceData); KeWaitForSingleObject( &DeviceData->StopEvent, Executive, // Waiting reason of a driver KernelMode, // Waiting in kernel mode FALSE, // No allert NULL); // No timeout // // Increment the counter back because this IRP has to // be sent down to the lower stack. // Bus_IncIoCount (DeviceData); // // Free resources given by start device. // SET_NEW_PNP_STATE(DeviceData, Stopped); // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // // // First check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if (RemovePending == DeviceData->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } Irp->IoStatus.Status = STATUS_SUCCESS;// You must not fail the IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // The device has been unexpectedly removed from the machine // and is no longer available for I/O. Bus_RemoveFdo clears // all the resources, frees the interface and de-registers // with WMI, but it doesn't delete the FDO. That's done // later in Remove device query. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_REMOVE_DEVICE: // // The Plug & Play system has dictated the removal of this device. // We have no choice but to detach and delete the device object. // // // Check the state flag to see whether you are surprise removed // if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); // // Wait for all outstanding requests to complete. // We need two decrements here, one for the increment in // the beginning of this function, the other for the 1-biased value of // OutstandingIO. // Bus_DecIoCount (DeviceData); // // The requestCount is at least one here (is 1-biased) // Bus_DecIoCount (DeviceData); KeWaitForSingleObject ( &DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); // // Typically the system removes all the children before // removing the parent FDO. If for any reason child Pdos are // still present we will destroy them explicitly, with one exception - // we will not delete the PDOs that are in SurpriseRemovePending state. // ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); if (SurpriseRemovePending == pdoData->DevicePnPState) { // // We will reinitialize the list head so that we // wouldn't barf when we try to delink this PDO from // the parent's PDOs list, when the system finally // removes the PDO. Let's also not forget to set the // ReportedMissing flag to cause the deletion of the PDO. // Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } DeviceData->NumPDOs--; Bus_DestroyPdo (pdoData->Self, pdoData); } ExReleaseFastMutex (&DeviceData->Mutex); // // We need to send the remove down the stack before we detach, // but we don't need to wait for the completion of this operation // (and to register a completion routine). // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); // // Detach from the underlying devices. // IoDetachDevice (DeviceData->NextLowerDriver); Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice (DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } // // Tell the plug and play system about all the PDOs. // // There might also be device relations below and above this FDO, // so, be sure to propagate the relations from the upper drivers. // // No Completion routine is needed so long as the status is preset // to success. (PDOs complete plug and play irps with the current // IoStatus.Status and IoStatus.Information as the default.) // ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject (pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; } } Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\t#PDOS present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count)); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePool (oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); Bus_DecIoCount (DeviceData); return status; }
NTSTATUS Bus_FDO_PnP(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData) { NTSTATUS status; ULONG length, prevcount, numPdosPresent, numPdosMissing; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE(); Bus_IncIoCount(DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = Bus_SendIrpSynchronously(DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { status = Bus_StartFdo (DeviceData, Irp); } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount(DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: if (StopPending == DeviceData->DevicePnPState) { RESTORE_PREVIOUS_PNP_STATE(DeviceData); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: Bus_DecIoCount(DeviceData); KeWaitForSingleObject(&DeviceData->StopEvent, Executive, KernelMode, FALSE, NULL); Bus_IncIoCount(DeviceData); SET_NEW_PNP_STATE(DeviceData, Stopped); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: if (DeviceData->DevicePnPState == RemovePending) { RESTORE_PREVIOUS_PNP_STATE(DeviceData); } Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex(&DeviceData->Mutex); { listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry, nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); RemoveEntryList(&pdoData->Link); InitializeListHead(&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } } ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); Bus_DecIoCount(DeviceData); Bus_DecIoCount(DeviceData); KeWaitForSingleObject(&DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); ExAcquireFastMutex(&DeviceData->Mutex); { listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry, nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); RemoveEntryList(&pdoData->Link); if (pdoData->DevicePnPState == SurpriseRemovePending) { Bus_KdPrint(("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead(&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } Bus_DestroyPdo(pdoData->Self, pdoData); } } ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->NextLowerDriver, Irp); IoDetachDevice(DeviceData->NextLowerDriver); Bus_KdPrint(("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice(DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint(("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(IrpStack->Parameters.QueryDeviceRelations.Type))); if (IrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) { break; } ExAcquireFastMutex(&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { ExReleaseFastMutex(&DeviceData->Mutex); break; } } else { prevcount = 0; } numPdosPresent = 0; numPdosMissing = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) - 1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag(PagedPool, length, BUSENUM_POOL_TAG); if (relations == NULL) { ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); Bus_DecIoCount(DeviceData); return status; } if (prevcount) { RtlCopyMemory(relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject(pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; numPdosMissing++; } } Bus_KdPrint(("#PDOS Present = %d, Reported = %d, Missing = %d, Listed = %d", numPdosPresent, relations->Count, numPdosMissing, DeviceData->NumPDOs)); if (oldRelations) { ExFreePool(oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; break; default: break; } IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->NextLowerDriver, Irp); Bus_DecIoCount(DeviceData); return status; }