Exemple #1
0
NTSTATUS Bus_StartFdo(__in PFDO_DEVICE_DATA FdoData, __in PIRP Irp)
{
    NTSTATUS status;
    POWER_STATE powerState;

    UNREFERENCED_PARAMETER(Irp);
    PAGED_CODE();

    status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE);

    if (!NT_SUCCESS (status))
	{
        Bus_KdPrint(("IoSetDeviceInterfaceState failed: 0x%x\n", status));
        return status;
    }

    FdoData->DevicePowerState = PowerDeviceD0;
    powerState.DeviceState    = PowerDeviceD0;

	PoSetPowerState(FdoData->Self, DevicePowerState, powerState);

    SET_NEW_PNP_STATE(FdoData, Started);

    return status;
}
//========================================================================================
// Function:	CompletionRoutineStartDevice of DispatchPnp
// Purpose:		The completion routine for plug & play irps that needs to be
//				processed first by the lower drivers.
// Return Value:
//				NT status code
//========================================================================================
NTSTATUS
CompletionRoutineStartDevice(
	IN PDEVICE_OBJECT	fido,			// fido - pointer to a device object.
	IN PIRP				irp,			// irp - pointer to an I/O Request Packet.
	IN PVOID			Context			// Context - pointer to an event object.
	)
{
	PDEVICE_EXTENSION dx;

	UNREFERENCED_PARAMETER(Context);

	dx = (PDEVICE_EXTENSION)fido->DeviceExtension;

	//Must do this if we don't return STATUS_MORE_PROCESSING_REQUIRED
	if (irp->PendingReturned)
		IoMarkIrpPending(irp);

	if (NT_SUCCESS(irp->IoStatus.Status))
	{
		//As we are successfully now back, we will
		//first set our state to Started.
		SET_NEW_PNP_STATE(dx, Started);

		//On the way up inherit FILE_REMOVABLE_MEDIA during Start.
		//This characteristic is available only after the driver stack is started!.
		if (dx->lowerdo->Characteristics & FILE_REMOVABLE_MEDIA)
		{
			fido->Characteristics |= FILE_REMOVABLE_MEDIA;
		}
	}

	IoReleaseRemoveLock(&dx->rmLock, irp);
	return STATUS_SUCCESS;
}
Exemple #3
0
NTSTATUS
Bus_StartFdo (
    PFDO_DEVICE_DATA            FdoData,
    PIRP   Irp )
{
    NTSTATUS status = STATUS_SUCCESS;
    POWER_STATE powerState;
    ACPI_STATUS AcpiStatus;

    PAGED_CODE ();

    FdoData->Common.DevicePowerState = PowerDeviceD0;
    powerState.DeviceState = PowerDeviceD0;
    PoSetPowerState ( FdoData->Common.Self, DevicePowerState, powerState );

    SET_NEW_PNP_STATE(FdoData->Common, Started);

    AcpiStatus = AcpiInitializeSubsystem();
    if(ACPI_FAILURE(AcpiStatus)){
        DPRINT1("Unable to AcpiInitializeSubsystem\n");
        return STATUS_UNSUCCESSFUL;
    }
    
    
	AcpiStatus = AcpiInitializeTables(NULL, 16, 0);
    if (ACPI_FAILURE(status)){
        DPRINT1("Unable to AcpiInitializeSubsystem\n");
		return STATUS_UNSUCCESSFUL;
    }

    AcpiStatus = AcpiLoadTables();
    if(ACPI_FAILURE(AcpiStatus)){
        DPRINT1("Unable to AcpiLoadTables\n");
        AcpiTerminate();
        return STATUS_UNSUCCESSFUL;
    }

	DPRINT("Acpi subsystem init\n");
    /* Initialize ACPI bus manager */
    AcpiStatus = acpi_init();
    if (!ACPI_SUCCESS(AcpiStatus)) {
        DPRINT1("acpi_init() failed with status 0x%X\n", AcpiStatus);
        AcpiTerminate();
        return STATUS_UNSUCCESSFUL;
    }
	status = ACPIEnumerateDevices(FdoData);

    return status;
}
Exemple #4
0
NTSTATUS
Bus_StartFdo (
    __in  PFDO_DEVICE_DATA            FdoData,
    __in  PIRP   Irp )
/*++

Routine Description:

    Initialize and start the bus controller. Get the resources
    by parsing the list and map them if required.

Arguments:

    DeviceData - Pointer to the FDO's device extension.
    Irp          - Pointer to the irp.

Return Value:

    NT Status is returned.

--*/
{
    NTSTATUS status;
    POWER_STATE powerState;

    PAGED_CODE ();

    //
    // Check the function driver source to learn
    // about parsing resource list.
    //

    //
    // Enable device interface. If the return status is
    // STATUS_OBJECT_NAME_EXISTS means we are enabling the interface
    // that was already enabled, which could happen if the device
    // is stopped and restarted for resource rebalancing.
    //

    status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE);
    if (!NT_SUCCESS (status)) {
        Bus_KdPrint (FdoData, BUS_DBG_PNP_TRACE,
                ("IoSetDeviceInterfaceState failed: 0x%x\n", status));
        return status;
    }

    //
    // Set the device power state to fully on. Also if this Start
    // is due to resource rebalance, you should restore the device
    // to the state it was before you stopped the device and relinquished
    // resources.
    //

    FdoData->DevicePowerState = PowerDeviceD0;
    powerState.DeviceState = PowerDeviceD0;
    PoSetPowerState ( FdoData->Self, DevicePowerState, powerState );

    SET_NEW_PNP_STATE(FdoData, Started);

    //
    // Register with WMI
    //
    status = Bus_WmiRegistration(FdoData);
    if (!NT_SUCCESS (status)) {
        Bus_KdPrint (FdoData, BUS_DBG_SS_ERROR,
        ("StartFdo: Bus_WmiRegistration failed (%x)\n", status));
    }

    return status;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
//========================================================================================
// Function:	DispatchPnp
// Purpose:		
// Return Value:
//				NT status code
//========================================================================================
NTSTATUS
DispatchPnp (
	IN PDEVICE_OBJECT fido,		// fido - pointer to a device object.
	IN PIRP irp					// Irp - pointer to an I/O Request Packet.
	)
{
	PDEVICE_EXTENSION dx;
	PIO_STACK_LOCATION irpStack;
	NTSTATUS ntStatus = STATUS_SUCCESS;

	PAGED_CODE();

	dx = (PDEVICE_EXTENSION)fido->DeviceExtension;
	irpStack = IoGetCurrentIrpStackLocation(irp);

	//acquire remove lock
	ntStatus = IoAcquireRemoveLock(&dx->rmLock, irp);
	if (!NT_SUCCESS(ntStatus))
	{
		//complete irp if cannot acquire remove lock
		irp->IoStatus.Status=ntStatus;
		irp->IoStatus.Information=0;
		IoCompleteRequest(irp, IO_NO_INCREMENT);
		return ntStatus;
	}

	PnPMinorFunctionString(irpStack->MinorFunction);

	switch (irpStack->MinorFunction)
	{
	case IRP_MN_START_DEVICE:
		//The device is starting.
		//We cannot touch the device (send it any non pnp irps) until a
		//start device has been passed down to the lower drivers.
		IoCopyCurrentIrpStackLocationToNext(irp);
		IoSetCompletionRoutine(irp,
			(PIO_COMPLETION_ROUTINE)CompletionRoutineStartDevice,
			NULL,
			TRUE,
			TRUE,
			TRUE);

		return IoCallDriver(dx->lowerdo, irp);

	case IRP_MN_REMOVE_DEVICE:
		IoSkipCurrentIrpStackLocation(irp);
		ntStatus = IoCallDriver(dx->lowerdo, irp);
		IoReleaseRemoveLockAndWait(&dx->rmLock, irp);

		SET_NEW_PNP_STATE(dx, Deleted);
		IoDetachDevice(dx->lowerdo);
		IoDeleteDevice(fido);
		return ntStatus;

	case IRP_MN_QUERY_STOP_DEVICE:
		SET_NEW_PNP_STATE(dx, StopPending);
		break;

	case IRP_MN_CANCEL_STOP_DEVICE:
		//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(dx->DevicePnPState == StopPending)
		{
			//We did receive a query-stop, so restore.
			RESTORE_PREVIOUS_PNP_STATE(dx);
		}
		//We must not fail this IRP.
		break;

	case IRP_MN_STOP_DEVICE:
		SET_NEW_PNP_STATE(dx, Stopped);
		break;

	case IRP_MN_QUERY_REMOVE_DEVICE:
		SET_NEW_PNP_STATE(dx, RemovePending);
		break;

	case IRP_MN_SURPRISE_REMOVAL:
		SET_NEW_PNP_STATE(dx, SurpriseRemovePending);
		break;

	case IRP_MN_CANCEL_REMOVE_DEVICE:
		//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(dx->DevicePnPState == RemovePending)
		{
			//We did receive a query-remove, so restore.
			RESTORE_PREVIOUS_PNP_STATE(dx);
		}
		//We must not fail this IRP.
		break;

	case IRP_MN_DEVICE_USAGE_NOTIFICATION:
		//On the way down, pagable might become set. Mimic the driver
		//above us. If no one is above us, just set pagable.
		if ((fido->AttachedDevice == NULL) ||
			(fido->AttachedDevice->Flags & DO_POWER_PAGABLE))
		{
			fido->Flags |= DO_POWER_PAGABLE;
		}

		IoCopyCurrentIrpStackLocationToNext(irp);
		IoSetCompletionRoutine(irp,
			CompletionRoutineDevUsgNotify,
			NULL,
			TRUE,
			TRUE,
			TRUE);

		return IoCallDriver(dx->lowerdo, irp);

	default:
		break;
	}

	IoSkipCurrentIrpStackLocation(irp);
	ntStatus = IoCallDriver(dx->lowerdo, irp);

	IoReleaseRemoveLock(&dx->rmLock, irp);
	return ntStatus;
}
NTSTATUS
bus_unplug_dev (
    int addr,
    PFDO_DEVICE_DATA            fdodata
    )
{
    PLIST_ENTRY         entry;
    PPDO_DEVICE_DATA    pdodata;
    int found=0, all;

    PAGED_CODE ();

    if(addr<0||addr>127)
	return STATUS_INVALID_PARAMETER;

    all = (0 == addr);

    ExAcquireFastMutex (&fdodata->Mutex);

    if (all) {
        Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE,
                      ("Plugging out all the devices!\n"));
    } else {
        Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE,
                      ("Plugging out %d\n", addr));
    }

    if (fdodata->NumPDOs == 0) {
        //
        // We got a 2nd plugout...somebody in user space isn't playing nice!!!
        //
        Bus_KdPrint (fdodata, BUS_DBG_IOCTL_ERROR,
                      ("BAD BAD BAD...2 removes!!! Send only one!\n"));
        ExReleaseFastMutex (&fdodata->Mutex);
        return STATUS_NO_SUCH_DEVICE;
    }

    for (entry = fdodata->ListOfPDOs.Flink;
         entry != &fdodata->ListOfPDOs;
         entry = entry->Flink) {

        pdodata = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);

        Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE,
                      ("found device %d\n", pdodata->SerialNo));

        if (all || addr == pdodata->SerialNo) {
            Bus_KdPrint (fdodata, BUS_DBG_IOCTL_INFO,
                          ("Plugging out %d\n", pdodata->SerialNo));
            pdodata->Present = FALSE;
			complete_pending_read_irp(pdodata);
            found = 1;
            if (!all) {
                break;
            }
        }
    }

    ExReleaseFastMutex (&fdodata->Mutex);

    if (found) {
        IoInvalidateDeviceRelations (fdodata->UnderlyingPDO, BusRelations);

		ExAcquireFastMutex (&fdodata->Mutex);

		for (entry = fdodata->ListOfPDOs.Flink;
			 entry != &fdodata->ListOfPDOs;
			 entry = entry->Flink) {

			pdodata = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);

			if( pdodata->Present ==FALSE){
				complete_pending_irp(pdodata);
				SET_NEW_PNP_STATE(pdodata,PNP_DEVICE_REMOVED);
				IoInvalidateDeviceState(pdodata->Self);
			}
		}
		ExReleaseFastMutex (&fdodata->Mutex);

		Bus_KdPrint (fdodata, BUS_DBG_IOCTL_ERROR,
                  ("Device %d plug out finished\n", addr));
		return  STATUS_SUCCESS;
    }


    return STATUS_INVALID_PARAMETER;
}
Exemple #9
0
NTSTATUS
FilterDispatchPnp (
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
/*++

Routine Description:

    The plug and play dispatch routines.

    Most of these the driver will completely ignore.
    In all cases it must pass on the IRP to the lower driver.

Arguments:

   DeviceObject - pointer to a device object.

   Irp - pointer to an I/O Request Packet.

Return Value:

      NT status code

--*/
{
    PDEVICE_EXTENSION           deviceExtension;
    PIO_STACK_LOCATION         irpStack;
    NTSTATUS                            status;
    KEVENT                               event;

    PAGED_CODE();

    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    DebugPrint(("FilterDO %s IRP:0x%p \n",
                PnPMinorFunctionString(irpStack->MinorFunction), Irp));

   status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
    if (!NT_SUCCESS (status)) {
        Irp->IoStatus.Status = status;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return status;
    }
    

    switch (irpStack->MinorFunction) {
    case IRP_MN_START_DEVICE:

        //
        // The device is starting.
        // We cannot touch the device (send it any non pnp irps) until a
        // start device has been passed down to the lower drivers.
        //
        KeInitializeEvent(&event, NotificationEvent, FALSE);
        IoCopyCurrentIrpStackLocationToNext(Irp);
        IoSetCompletionRoutine(Irp,
                               FilterStartCompletionRoutine,
                               &event,
                               TRUE,
                               TRUE,
                               TRUE);

        status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);
        
        //
        // Wait for lower drivers to be done with the Irp. Important thing to
        // note here is when you allocate memory for an event in the stack  
        // you must do a KernelMode wait instead of UserMode to prevent 
        // the stack from getting paged out.
        //
        if (status == STATUS_PENDING) {

           KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);          
           status = Irp->IoStatus.Status;
        }

        if (NT_SUCCESS (status)) {

            //
            // As we are successfully now back, we will
            // first set our state to Started.
            //

            SET_NEW_PNP_STATE(deviceExtension, Started);

            //
            // On the way up inherit FILE_REMOVABLE_MEDIA during Start.
            // This characteristic is available only after the driver stack is started!.
            //
            if (deviceExtension->NextLowerDriver->Characteristics & FILE_REMOVABLE_MEDIA) {

                DeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
            }

#ifdef IOCTL_INTERFACE
            //
            // If the PreviousPnPState is stopped then we are being stopped temporarily
            // and restarted for resource rebalance. 
            //
            if (Stopped != deviceExtension->PreviousPnPState) {
                //
                // Device is started for the first time.
                //
                FilterCreateControlObject(DeviceObject);
            }
#endif   
        }
        
        Irp->IoStatus.Status = status;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); 
        return status;

    case IRP_MN_REMOVE_DEVICE:

        //
        // Wait for all outstanding requests to complete
        //
        DebugPrint(("Waiting for outstanding requests\n"));
        IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);

        IoSkipCurrentIrpStackLocation(Irp);

        status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);

        SET_NEW_PNP_STATE(deviceExtension, Deleted);
        
#ifdef IOCTL_INTERFACE
        FilterDeleteControlObject();
#endif 
        IoDetachDevice(deviceExtension->NextLowerDriver);
        IoDeleteDevice(DeviceObject);
        return status;


    case IRP_MN_QUERY_STOP_DEVICE:
        SET_NEW_PNP_STATE(deviceExtension, StopPending);
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_CANCEL_STOP_DEVICE:

        //
        // 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 == deviceExtension->DevicePnPState)
        {
            //
            // We did receive a query-stop, so restore.
            //
            RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
        }
        status = STATUS_SUCCESS; // We must not fail this IRP.
        break;

    case IRP_MN_STOP_DEVICE:
        SET_NEW_PNP_STATE(deviceExtension, Stopped);
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_QUERY_REMOVE_DEVICE:

        SET_NEW_PNP_STATE(deviceExtension, RemovePending);
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_SURPRISE_REMOVAL:

        SET_NEW_PNP_STATE(deviceExtension, SurpriseRemovePending);
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_CANCEL_REMOVE_DEVICE:

        //
        // 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 == deviceExtension->DevicePnPState)
        {
            //
            // We did receive a query-remove, so restore.
            //
            RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
        }

        status = STATUS_SUCCESS; // We must not fail this IRP.
        break;

    case IRP_MN_DEVICE_USAGE_NOTIFICATION:

        //
        // On the way down, pagable might become set. Mimic the driver
        // above us. If no one is above us, just set pagable.
        //
        #pragma prefast(suppress:__WARNING_INACCESSIBLE_MEMBER)
        if ((DeviceObject->AttachedDevice == NULL) ||
            (DeviceObject->AttachedDevice->Flags & DO_POWER_PAGABLE)) {

            DeviceObject->Flags |= DO_POWER_PAGABLE;
        }

        IoCopyCurrentIrpStackLocationToNext(Irp);

        IoSetCompletionRoutine(
            Irp,
            FilterDeviceUsageNotificationCompletionRoutine,
            NULL,
            TRUE,
            TRUE,
            TRUE
            );

        return IoCallDriver(deviceExtension->NextLowerDriver, Irp);

    default:
        //
        // If you don't handle any IRP you must leave the
        // status as is.
        //
        status = Irp->IoStatus.Status;

        break;
    }

    //
    // Pass the IRP down and forget it.
    //
    Irp->IoStatus.Status = status;
    IoSkipCurrentIrpStackLocation (Irp);
    status = IoCallDriver (deviceExtension->NextLowerDriver, Irp);
    IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); 
    return status;
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}