NTSTATUS Bus_DestroyPdo(PDEVICE_OBJECT Device, PPDO_DEVICE_DATA PdoData) { PFDO_DEVICE_DATA fdoData; PAGED_CODE(); fdoData = FDO_FROM_PDO(PdoData); fdoData->NumPDOs--; if (PdoData->InterfaceName.Buffer != NULL) { ExFreePool(PdoData->InterfaceName.Buffer); RtlZeroMemory(&PdoData->InterfaceName, sizeof(UNICODE_STRING)); } if (PdoData->HardwareIDs) { ExFreePool(PdoData->HardwareIDs); PdoData->HardwareIDs = NULL; } Bus_KdPrint(("\tDeleting PDO: 0x%p\n", Device)); IoDeleteDevice(Device); return STATUS_SUCCESS; }
NTSTATUS Bus_PDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PPDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the devices on the BUS --*/ { NTSTATUS status; PAGED_CODE (); // // NB: Because we are a bus enumerator, we have no one to whom we could // defer these irps. Therefore we do not pass them down but merely // return them. // switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Here we do what ever initialization and ``turning on'' that is // required to allow others to access this device. // Power up the device. // DeviceData->DevicePowerState = PowerDeviceD0; SET_NEW_PNP_STATE(DeviceData, Started); status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: // // Here we shut down the device and give up and unmap any resources // we acquired for the device. // SET_NEW_PNP_STATE(DeviceData, Stopped); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_STOP_DEVICE: // // No reason here why we can't stop the device. // If there were a reason we should speak now, because answering success // here may result in a stop device irp. // SET_NEW_PNP_STATE(DeviceData, StopPending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // The stop was canceled. Whatever state we set, or resources we put // on hold in anticipation of the forthcoming STOP device IRP should be // put back to normal. Someone, in the long list of concerned parties, // has failed the stop device query. // // // 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); } status = STATUS_SUCCESS;// We must not fail this IRP. break; case IRP_MN_QUERY_REMOVE_DEVICE: // // Check to see whether the device can be removed safely. // If not fail this request. This is the last opportunity // to do so. // if (DeviceData->ToasterInterfaceRefCount){ // // Somebody is still using our interface. // We must fail remove. // status = STATUS_UNSUCCESSFUL; break; } SET_NEW_PNP_STATE(DeviceData, RemovePending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // Clean up a remove that did not go through. // // // 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); } status = STATUS_SUCCESS; // We must not fail this IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // We should stop all access to the device and relinquish all the // resources. Let's just mark that it happened and we will do // the cleanup later in IRP_MN_REMOVE_DEVICE. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: // // Present is set to true when the pdo is exposed via PlugIn IOCTL. // It is set to FALSE when a UnPlug IOCTL is received. // We will delete the PDO only after we have reported to the // Plug and Play manager that it's missing. // if (DeviceData->ReportedMissing) { PFDO_DEVICE_DATA fdoData; SET_NEW_PNP_STATE(DeviceData, Deleted); // // Remove the PDO from the list and decrement the count of PDO. // Don't forget to synchronize access to the FDO data. // If the parent FDO is deleted before child PDOs, the ParentFdo // pointer will be NULL. This could happen if the child PDO // is in a SurpriseRemovePending state when the parent FDO // is removed. // if (DeviceData->ParentFdo) { fdoData = FDO_FROM_PDO(DeviceData); ExAcquireFastMutex (&fdoData->Mutex); RemoveEntryList (&DeviceData->Link); fdoData->NumPDOs--; ExReleaseFastMutex (&fdoData->Mutex); } // // Free up resources associated with PDO and delete it. // status = Bus_DestroyPdo(DeviceObject, DeviceData); break; } if (DeviceData->Present) { // // When the device is disabled, the PDO transitions from // RemovePending to NotStarted. We shouldn't delete // the PDO because a) the device is still present on the bus, // b) we haven't reported missing to the PnP manager. // SET_NEW_PNP_STATE(DeviceData, NotStarted); status = STATUS_SUCCESS; } else { ASSERT(DeviceData->Present); status = STATUS_SUCCESS; } break; case IRP_MN_QUERY_CAPABILITIES: // // Return the capabilities of a device, such as whether the device // can be locked or ejected..etc // status = Bus_PDO_QueryDeviceCaps(DeviceData, Irp); break; case IRP_MN_QUERY_ID: // Query the IDs of the device Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryId Type: %s\n", DbgDeviceIDString(IrpStack->Parameters.QueryId.IdType))); status = Bus_PDO_QueryDeviceId(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n",DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); status = Bus_PDO_QueryDeviceRelations(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_TEXT: status = Bus_PDO_QueryDeviceText(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCES: status = Bus_PDO_QueryResources(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: status = Bus_PDO_QueryResourceRequirements(DeviceData, Irp); break; case IRP_MN_QUERY_BUS_INFORMATION: status = Bus_PDO_QueryBusInformation(DeviceData, Irp); break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: // // OPTIONAL for bus drivers. // This bus drivers any of the bus's descendants // (child device, child of a child device, etc.) do not // contain a memory file namely paging file, dump file, // or hibernation file. So we fail this Irp. // status = STATUS_UNSUCCESSFUL; break; case IRP_MN_EJECT: // // For the device to be ejected, the device must be in the D3 // device power state (off) and must be unlocked // (if the device supports locking). Any driver that returns success // for this IRP must wait until the device has been ejected before // completing the IRP. // DeviceData->Present = FALSE; status = STATUS_SUCCESS; break; case IRP_MN_QUERY_INTERFACE: // // This request enables a driver to export a direct-call // interface to other drivers. A bus driver that exports // an interface must handle this request for its child // devices (child PDOs). // status = Bus_PDO_QueryInterface(DeviceData, Irp); break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP to a device // stack so filter and function drivers can adjust the // resources required by the device, if appropriate. // //break; //case IRP_MN_QUERY_PNP_DEVICE_STATE: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP after the drivers for // a device return success from the IRP_MN_START_DEVICE // request. The PnP Manager also sends this IRP when a // driver for the device calls IoInvalidateDeviceState. // // break; //case IRP_MN_READ_CONFIG: //case IRP_MN_WRITE_CONFIG: // // Bus drivers for buses with configuration space must handle // this request for their child devices. Our devices don't // have a config space. // // break; //case IRP_MN_SET_LOCK: // // Our device is not a lockable device // so we don't support this Irp. // // break; default: // //Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE,("\t Not handled\n")); // For PnP requests to the PDO that we do not understand we should // return the IRP WITHOUT setting the status or information fields. // These fields may have already been set by a filter (eg acpi). status = Irp->IoStatus.Status; break; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
NTSTATUS Bus_PDO_QueryDeviceCaps( __in PPDO_DEVICE_DATA DeviceData, __in PIRP Irp ) /*++ Routine Description: When a device is enumerated, but before the function and filter drivers are loaded for the device, the PnP Manager sends an IRP_MN_QUERY_CAPABILITIES request to the parent bus driver for the device. The bus driver must set any relevant values in the DEVICE_CAPABILITIES structure and return it to the PnP Manager. Arguments: DeviceData - Pointer to the PDO's device extension. Irp - Pointer to the irp. Return Value: NT STATUS --*/ { PIO_STACK_LOCATION stack; PDEVICE_CAPABILITIES deviceCapabilities; DEVICE_CAPABILITIES parentCapabilities; NTSTATUS status; PAGED_CODE (); stack = IoGetCurrentIrpStackLocation (Irp); // // Get the packet. // deviceCapabilities=stack->Parameters.DeviceCapabilities.Capabilities; // // Set the capabilities. // if (deviceCapabilities->Version != 1 || deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) { return STATUS_UNSUCCESSFUL; } // // Get the device capabilities of the parent // status = Bus_GetDeviceCapabilities( FDO_FROM_PDO(DeviceData)->NextLowerDriver, &parentCapabilities); if (!NT_SUCCESS(status)) { Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceCaps failed\n")); return status; } // // The entries in the DeviceState array are based on the capabilities // of the parent devnode. These entries signify the highest-powered // state that the device can support for the corresponding system // state. A driver can specify a lower (less-powered) state than the // bus driver. For eg: Suppose the toaster bus controller supports // D0, D2, and D3; and the Toaster Device supports D0, D1, D2, and D3. // Following the above rule, the device cannot specify D1 as one of // it's power state. A driver can make the rules more restrictive // but cannot loosen them. // First copy the parent's S to D state mapping // RtlCopyMemory( deviceCapabilities->DeviceState, parentCapabilities.DeviceState, (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE) ); // // Adjust the caps to what your device supports. // Our device just supports D0 and D3. // deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; if (deviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1; if (deviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; if (deviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; // We can wake the system from D1 deviceCapabilities->DeviceWake = PowerDeviceD1; // // Specifies whether the device hardware supports the D1 and D2 // power state. Set these bits explicitly. // deviceCapabilities->DeviceD1 = TRUE; // Yes we can deviceCapabilities->DeviceD2 = FALSE; // // Specifies whether the device can respond to an external wake // signal while in the D0, D1, D2, and D3 state. // Set these bits explicitly. // deviceCapabilities->WakeFromD0 = FALSE; deviceCapabilities->WakeFromD1 = TRUE; //Yes we can deviceCapabilities->WakeFromD2 = FALSE; deviceCapabilities->WakeFromD3 = FALSE; // We have no latencies deviceCapabilities->D1Latency = 0; deviceCapabilities->D2Latency = 0; deviceCapabilities->D3Latency = 0; // Ejection supported deviceCapabilities->EjectSupported = TRUE; // // This flag specifies whether the device's hardware is disabled. // The PnP Manager only checks this bit right after the device is // enumerated. Once the device is started, this bit is ignored. // deviceCapabilities->HardwareDisabled = FALSE; // // Out simulated device can be physically removed. // deviceCapabilities->Removable = TRUE; // // Setting it to TURE prevents the warning dialog from appearing // whenever the device is surprise removed. // deviceCapabilities->SurpriseRemovalOK = TRUE; // We don't support system-wide unique IDs. deviceCapabilities->UniqueID = FALSE; // // Specify whether the Device Manager should suppress all // installation pop-ups except required pop-ups such as // "no compatible drivers found." // deviceCapabilities->SilentInstall = FALSE; // // Specifies an address indicating where the device is located // on its underlying bus. The interpretation of this number is // bus-specific. If the address is unknown or the bus driver // does not support an address, the bus driver leaves this // member at its default value of 0xFFFFFFFF. In this example // the location address is same as instance id. // deviceCapabilities->Address = DeviceData->SerialNo; // // UINumber specifies a number associated with the device that can // be displayed in the user interface. // deviceCapabilities->UINumber = DeviceData->SerialNo; return STATUS_SUCCESS; }