示例#1
0
VOID CancelSelectSuspend(IN PTDeviceExtension DeviceExtension)
{
    PIRP  irp;
    KIRQL oldIrql;

    irp = NULL;
    BulkUsb_DbgPrint(3, ("file bulkdev: CancelSelectSuspend - begins\n"));
    KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
    if(!CanDeviceSuspend(DeviceExtension))
    {
        BulkUsb_DbgPrint(3, ("file bulkdev: Device is not idle\n"));
        irp = (PIRP)InterlockedExchangePointer(&DeviceExtension->PendingIdleIrp, NULL);
    }

    KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
    if(irp) 
	{
		IoCancelIrp(irp);
        if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) 
		{
            BulkUsb_DbgPrint(3, ("file bulkdev: CancelSelectSuspend frees the irp\n"));
            IoFreeIrp(irp);
            KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
        }
    }

    BulkUsb_DbgPrint(3, ("file bulkdev: CancelSelectSuspend - ends\n"));
    return;
}
示例#2
0
文件: bulkdev.c 项目: caidongyun/libs
NTSTATUS
SubmitIdleRequestIrp(
    IN PDEVICE_EXTENSION DeviceExtension
    )
/*++
 
Routine Description:

    This routine builds an idle request irp with an associated callback routine
    and a completion routine in the driver and passes the irp down the stack.

Arguments:

    DeviceExtension - pointer to device extension

Return Value:

    NT status value

--*/
{
    PIRP                    irp;
    NTSTATUS                ntStatus;
    KIRQL                   oldIrql;
    PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
    PIO_STACK_LOCATION      nextStack;

    //
    // initialize variables
    //
    
    irp = NULL;
    idleCallbackInfo = NULL;

    BulkUsb_DbgPrint(3, ("SubmitIdleRequest - begins\n"));

    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    if(PowerDeviceD0 != DeviceExtension->DevPower) {

        ntStatus = STATUS_POWER_STATE_INVALID;

        goto SubmitIdleRequestIrp_Exit;
    }

    KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);

    if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {

        BulkUsb_DbgPrint(1, ("Idle request pending..\n"));

        KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

        ntStatus = STATUS_DEVICE_BUSY;

        goto SubmitIdleRequestIrp_Exit;
    }

    //
    // clear the NoIdleReqPendEvent because we are about 
    // to submit an idle request. Since we are so early
    // to clear this event, make sure that if we fail this
    // request we set back the event.
    //
    KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);

    idleCallbackInfo = ExAllocatePool(NonPagedPool, 
                                      sizeof(struct _USB_IDLE_CALLBACK_INFO));

    if(idleCallbackInfo) {

        idleCallbackInfo->IdleCallback = IdleNotificationCallback;

        idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;

        ASSERT(DeviceExtension->IdleCallbackInfo == NULL);

        DeviceExtension->IdleCallbackInfo = idleCallbackInfo;

        //
        // we use IoAllocateIrp to create an irp to selectively suspend the 
        // device. This irp lies pending with the hub driver. When appropriate
        // the hub driver will invoked callback, where we power down. The completion
        // routine is invoked when we power back.
        //
        irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
                            FALSE);

        if(irp == NULL) {

            BulkUsb_DbgPrint(1, ("cannot build idle request irp\n"));

            KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
                       IO_NO_INCREMENT,
                       FALSE);

            InterlockedExchange(&DeviceExtension->IdleReqPend, 0);

            KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

            ExFreePool(idleCallbackInfo);

            ntStatus = STATUS_INSUFFICIENT_RESOURCES;

            goto SubmitIdleRequestIrp_Exit;
        }

        nextStack = IoGetNextIrpStackLocation(irp);

        nextStack->MajorFunction = 
                    IRP_MJ_INTERNAL_DEVICE_CONTROL;

        nextStack->Parameters.DeviceIoControl.IoControlCode = 
                    IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;

        nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
                    idleCallbackInfo;

        nextStack->Parameters.DeviceIoControl.InputBufferLength =
                    sizeof(struct _USB_IDLE_CALLBACK_INFO);


        IoSetCompletionRoutine(irp, 
                               IdleNotificationRequestComplete,
                               DeviceExtension, 
                               TRUE, 
                               TRUE, 
                               TRUE);

        DeviceExtension->PendingIdleIrp = irp;

        //
        // we initialize the count to 2.
        // The reason is, if the CancelSelectSuspend routine manages
        // to grab the irp from the device extension, then the last of the
        // CancelSelectSuspend routine/IdleNotificationRequestComplete routine 
        // to execute will free this irp. We need to have this schema so that
        // 1. completion routine does not attempt to touch the irp freed by 
        //    CancelSelectSuspend routine.
        // 2. CancelSelectSuspend routine doesnt wait for ever for the completion
        //    routine to complete!
        //
        DeviceExtension->FreeIdleIrpCount = 2;

        KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

        //
        // check if the device is idle.
        // A check here ensures that a race condition did not 
        // completely reverse the call sequence of SubmitIdleRequestIrp
        // and CancelSelectiveSuspend
        //

        if(!CanDeviceSuspend(DeviceExtension) ||
           PowerDeviceD0 != DeviceExtension->DevPower) {

            //
            // IRPs created using IoBuildDeviceIoControlRequest should be
            // completed by calling IoCompleteRequest and not merely 
            // deallocated.
            //
     
            BulkUsb_DbgPrint(1, ("Device is not idle\n"));

            KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);

            DeviceExtension->IdleCallbackInfo = NULL;

            DeviceExtension->PendingIdleIrp = NULL;

            KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
                       IO_NO_INCREMENT,
                       FALSE);

            InterlockedExchange(&DeviceExtension->IdleReqPend, 0);

            KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

            if(idleCallbackInfo) {

                ExFreePool(idleCallbackInfo);
            }

            //
            // it is still safe to touch the local variable "irp" here.
            // the irp has not been passed down the stack, the irp has
            // no cancellation routine. The worse position is that the
            // CancelSelectSuspend has run after we released the spin 
            // lock above. It is still essential to free the irp.
            //
            if(irp) {

                IoFreeIrp(irp);
            }

            goto SubmitIdleRequestIrp_Exit;
        }

        BulkUsb_DbgPrint(3, ("Cancel the timers\n"));
        //
        // Cancel the timer so that the DPCs are no longer fired.
        // Thus, we are making judicious usage of our resources.
        // we do not need DPCs because we already have an idle irp pending.
        // The timers are re-initialized in the completion routine.
        //
        KeCancelTimer(&DeviceExtension->Timer);

        ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);

        if(!NT_SUCCESS(ntStatus)) {

            BulkUsb_DbgPrint(1, ("IoCallDriver failed\n"));

            goto SubmitIdleRequestIrp_Exit;
        }
    }
    else {

        BulkUsb_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));

        KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
                   IO_NO_INCREMENT,
                   FALSE);

        InterlockedExchange(&DeviceExtension->IdleReqPend, 0);

        KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }

SubmitIdleRequestIrp_Exit:

    BulkUsb_DbgPrint(3, ("SubmitIdleRequest - ends\n"));

    return ntStatus;
}
示例#3
0
NTSTATUS SubmitIdleRequestIrp(IN PTDeviceExtension DeviceExtension)
{
	PIRP                    irp;
	NTSTATUS                ntStatus;
	KIRQL                   oldIrql;
	PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
	PIO_STACK_LOCATION      nextStack;

	irp = NULL;
	idleCallbackInfo = NULL;
	BulkUsb_DbgPrint(3, ("file bulkdev: SubmitIdleRequest - process\n"));
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
	if(PowerDeviceD0 != DeviceExtension->DevPower) 
	{
//		ntStatus = STATUS_POWER_STATE_INVALID;
//		goto SubmitIdleRequestIrp_Exit;
		return STATUS_POWER_STATE_INVALID;
	}

	KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
	if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) 
	{
		BulkUsb_DbgPrint(1, ("file bulkdev: Idle request pending..\n"));
		KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
//		ntStatus = STATUS_DEVICE_BUSY;
//		goto SubmitIdleRequestIrp_Exit;
		return STATUS_DEVICE_BUSY;
	}

	KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
	idleCallbackInfo = ExAllocatePool(NonPagedPool, sizeof(struct _USB_IDLE_CALLBACK_INFO));
	if(idleCallbackInfo) 
	{
		idleCallbackInfo->IdleCallback = IdleNotificationCallback;
		idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
		ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
		DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
		irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize, FALSE);
		if(irp == NULL) 
		{
			BulkUsb_DbgPrint(1, ("file bulkdev: cannot build idle request irp\n"));
			KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
			InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
			KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
			ExFreePool(idleCallbackInfo);
//			ntStatus = STATUS_INSUFFICIENT_RESOURCES;
//			goto SubmitIdleRequestIrp_Exit;
			return STATUS_INSUFFICIENT_RESOURCES;
		}

		nextStack = IoGetNextIrpStackLocation(irp);
		nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
		nextStack->Parameters.DeviceIoControl.IoControlCode = 
					IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
		nextStack->Parameters.DeviceIoControl.Type3InputBuffer = idleCallbackInfo;
		nextStack->Parameters.DeviceIoControl.InputBufferLength = 
					sizeof(struct _USB_IDLE_CALLBACK_INFO);
		IoSetCompletionRoutine(irp, 
					IdleNotificationRequestComplete, 
					DeviceExtension, 
					TRUE, 
					TRUE, 
					TRUE);

		DeviceExtension->PendingIdleIrp = irp;
		DeviceExtension->FreeIdleIrpCount = 2;
		KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
		if(!CanDeviceSuspend(DeviceExtension) || PowerDeviceD0 != DeviceExtension->DevPower) 
		{
			BulkUsb_DbgPrint(1, ("file bulkdev: Device is not idle\n"));
			KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
			DeviceExtension->IdleCallbackInfo = NULL;
			DeviceExtension->PendingIdleIrp = NULL;
			KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
			InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
			KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
			if(idleCallbackInfo) 
			{
				ExFreePool(idleCallbackInfo);
			}
			if(irp) 
			{
				IoFreeIrp(irp);
			}
//			ntStatus = STATUS_UNSUCCESSFUL;
//			goto SubmitIdleRequestIrp_Exit;
			return STATUS_UNSUCCESSFUL;
		}

		BulkUsb_DbgPrint(3, ("file bulkdev: Cancel the timers\n"));
		KeCancelTimer(&DeviceExtension->Timer);
		ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
		if(!NT_SUCCESS(ntStatus)) 
		{
//			BulkUsb_DbgPrint(1, ("file bulkdev: IoCallDriver failed\n"));
//			goto SubmitIdleRequestIrp_Exit;
			return ntStatus;
		}
	}
	else 
	{
		BulkUsb_DbgPrint(1, ("file bulkdev: Memory allocation for idleCallbackInfo failed\n"));
		KeSetEvent(&DeviceExtension->NoIdleReqPendEvent, IO_NO_INCREMENT, FALSE);
		InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
		KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
		ntStatus = STATUS_INSUFFICIENT_RESOURCES;
	}

//SubmitIdleRequestIrp_Exit:
	BulkUsb_DbgPrint(3, ("file bulkdev: SubmitIdleRequest - ends\n"));
	return ntStatus;
}
示例#4
0
文件: bulkdev.c 项目: caidongyun/libs
VOID
CancelSelectSuspend(
    IN PDEVICE_EXTENSION DeviceExtension
    )
/*++
 
Routine Description:

    This routine is invoked to cancel selective suspend request.

Arguments:

    DeviceExtension - pointer to device extension

Return Value:

    None.

--*/
{
    PIRP  irp;
    KIRQL oldIrql;

    irp = NULL;

    BulkUsb_DbgPrint(3, ("CancelSelectSuspend - begins\n"));

    KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);

    if(!CanDeviceSuspend(DeviceExtension))
    {
        BulkUsb_DbgPrint(3, ("Device is not idle\n"));
    
        irp = (PIRP) InterlockedExchangePointer(
                            &DeviceExtension->PendingIdleIrp, 
                            NULL);
    }

    KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);

    //
    // since we have a valid Irp ptr,
    // we can call IoCancelIrp on it,
    // without the fear of the irp 
    // being freed underneath us.
    //
    if(irp) {

        //
        // This routine has the irp pointer.
        // It is safe to call IoCancelIrp because we know that
        // the compleiton routine will not free this irp unless...
        // 
        //        
        if(IoCancelIrp(irp)) {

            BulkUsb_DbgPrint(3, ("IoCancelIrp returns TRUE\n"));
        }
        else {
            BulkUsb_DbgPrint(3, ("IoCancelIrp returns FALSE\n"));
        }

        //
        // ....we decrement the FreeIdleIrpCount from 2 to 1.
        // if completion routine runs ahead of us, then this routine 
        // decrements the FreeIdleIrpCount from 1 to 0 and hence shall
        // free the irp.
        //
        if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {

            BulkUsb_DbgPrint(3, ("CancelSelectSuspend frees the irp\n"));
            IoFreeIrp(irp);

            KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
                       IO_NO_INCREMENT,
                       FALSE);
        }
    }

    BulkUsb_DbgPrint(3, ("CancelSelectSuspend - ends\n"));

    return;
}