예제 #1
0
VOID
UfxDevice_EvtDeviceRemoteWakeupSignal (
    _In_ UFXDEVICE UfxDevice
    )
/*++
Routine Description:

    Signals Remote Wakeup to the Host by issuing a link state change command.
    It acquires and releases the power reference to ensure a valid power state
    before accessing the device.

Arguments:

    UfxDevice - UFXDEVICE object representing the device.

--*/
{
    NTSTATUS Status;
    PUFXDEVICE_CONTEXT DeviceContext;

    PAGED_CODE();

    TraceEntry();

    DeviceContext = UfxDeviceGetContext(UfxDevice);

    //
    // Stop Idle to ensure the device is in working state
    //
    Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE);
    if (!NT_SUCCESS(Status)) {
        TraceError("Failed to stop idle %!STATUS!", Status);
        goto End;
    }

    //
    // Issue a Link State Change Request.
    //

    //
    // #### TODO: Insert code to issue a link state change on the controller ####
    //

    WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice);

End:
    UfxDeviceEventComplete(UfxDevice, Status);
    TraceExit();
}
예제 #2
0
VOID
SerialFileCloseWorker(
    IN WDFDEVICE Device
    )
{
    ULONG flushCount;

    //
    // This "timer value" is used to wait 10 character times
    // after the hardware is empty before we actually "run down"
    // all of the flow control/break junk.
    //
    LARGE_INTEGER tenCharDelay;

    //
    // Holds a character time.
    //
    LARGE_INTEGER charTime;

    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device);
    PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt);

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, "In SerialEvtFileClose %wZ\n",
                                                &extension->DeviceName);

    //
    // Acquire the interrupt state lock.
    //
    WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL);

    //
    // If the Interrupts are connected, then the hardware state has to be
    // cleaned up now. Note that the EvtFileClose callback gets called for
    // an open file object even though the interrupts have been disabled
    // possibly  due to a Surprise Remove PNP event. In such a case, the
    // Interrupt  object should not be used.
    //
    if (interruptContext->IsInterruptConnected) {

        charTime.QuadPart = -SerialGetCharTime(extension).QuadPart;

        //
        // Do this now so that if the isr gets called it won't do anything
        // to cause more chars to get sent.  We want to run down the hardware.
        //

        SetDeviceIsOpened(extension, FALSE, FALSE);

        //
        // Synchronize with the isr to turn off break if it
        // is already on.
        //

        WdfInterruptSynchronize(
            extension->WdfInterrupt,
            SerialTurnOffBreak,
            extension
            );

        //
        // Wait a reasonable amount of time (20 * fifodepth) until all characters
        // have been emptied out of the hardware.
        //

        for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
           if ((READ_LINE_STATUS(extension, extension->Controller) &
                (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
               (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {

              KeDelayExecutionThread(KernelMode, FALSE, &charTime);
          } else {
             break;
          }
        }

        if (flushCount == 0) {
           SerialMarkHardwareBroken(extension);
        }

        //
        // Synchronize with the ISR to let it know that interrupts are
        // no longer important.
        //

        WdfInterruptSynchronize(
            extension->WdfInterrupt,
            SerialMarkClose,
            extension
            );


        //
        // If the driver has automatically transmitted an Xoff in
        // the context of automatic receive flow control then we
        // should transmit an Xon.
        //

        if (extension->RXHolding & SERIAL_RX_XOFF) {

            //
            // Loop until the holding register is empty.
            //
            while (!(READ_LINE_STATUS(extension, extension->Controller) &
                     SERIAL_LSR_THRE)) {
                KeDelayExecutionThread(
                    KernelMode,
                    FALSE,
                    &charTime
                    );

            }

            WRITE_TRANSMIT_HOLDING(extension,
                extension->Controller,
                extension->SpecialChars.XonChar
                );

            //
            // Wait a reasonable amount of time for the characters
            // to be emptied out of the hardware.
            //

             for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
                if ((READ_LINE_STATUS(extension, extension->Controller) &
                     (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
                    (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
                   KeDelayExecutionThread(KernelMode, FALSE, &charTime);
                } else {
                   break;
                }
             }

             if (flushCount == 0) {
                SerialMarkHardwareBroken(extension);
             }
        }


        //
        // The hardware is empty.  Delay 10 character times before
        // shut down all the flow control.
        //

        tenCharDelay.QuadPart = charTime.QuadPart * 10;

        KeDelayExecutionThread(
            KernelMode,
            TRUE,
            &tenCharDelay
            );

#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "This warning is because we are calling interrupt synchronize routine directly.")
        SerialClrDTR(extension->WdfInterrupt, extension);

        //
        // We have to be very careful how we clear the RTS line.
        // Transmit toggling might have been on at some point.
        //
        // We know that there is nothing left that could start
        // out the "polling"  execution path.  We need to
        // check the counter that indicates that the execution
        // path is active.  If it is then we loop delaying one
        // character time.  After each delay we check to see if
        // the counter has gone to zero.  When it has we know that
        // the execution path should be just about finished.  We
        // make sure that we still aren't in the routine that
        // synchronized execution with the ISR by synchronizing
        // ourselve with the ISR.
        //

        if (extension->CountOfTryingToLowerRTS) {

            do {
#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_HIGH, "This warning is due to suppressing the previous one.")
                KeDelayExecutionThread(
                    KernelMode,
                    FALSE,
                    &charTime
                    );

            } while (extension->CountOfTryingToLowerRTS);

            //
            // The execution path should no longer exist that
            // is trying to push down the RTS.  Well just
            // make sure it's down by falling through to
            // code that forces it down.
            //

        }

#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "This warning is because we are calling interrupt synchronize routine directly.")
        SerialClrRTS(extension->WdfInterrupt, extension);

        //
        // Clean out the holding reasons (since we are closed).
        //

        extension->RXHolding = 0;
        extension->TXHolding = 0;

        //
        // Mark device as not busy for WMI
        //

        extension->WmiCommData.IsBusy = FALSE;

    }

    //
    // Release the Interrupt state lock.
    //
    WdfWaitLockRelease(interruptContext->InterruptStateLock);

    //
    // All is done.  The port has been disabled from interrupting
    // so there is no point in keeping the memory around.
    //

    extension->BufferSize = 0;
    if (extension->InterruptReadBuffer != NULL) {
       ExFreePool(extension->InterruptReadBuffer);
    }
    extension->InterruptReadBuffer = NULL;

    //
    // Make sure the wake is disabled.
    //
    ASSERT(!extension->IsWakeEnabled);

    SerialDrainTimersAndDpcs(extension);

    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_CREATE_CLOSE, "DPC's drained:\n");

    //
    // It's fine for the device to be powered off if there are no open handles.
    //
    WdfDeviceResumeIdle(Device);

    //
    // It's okay to allow the device to be stopped or removed.
    //
    // Note to anyone copying this sample as a starting point:
    //
    // This works in this driver simply because this driver supports exactly
    // one open handle at a time.  If it supported more, then it would need
    // counting logic to determine when all the reasons for failing Stop/Remove
    // were gone.
    //
    WdfDeviceSetStaticStopRemove(Device, TRUE);

    return;

}
예제 #3
0
NTSTATUS
UfxDeviceStopOrResumeIdle (
    _In_ UFXDEVICE Device,
    _In_ USBFN_DEVICE_STATE UsbState,
    _In_ USBFN_PORT_TYPE UsbPort
    )
/*++

Routine Description:

    Examines the device USB state and port type and determines
    if it needs to stop or resume idle.

Arguments:

    UfxDevice - UFXDEVICE object representing the device.

Return Value:

    STATUS_SUCCESS on success, or an appropirate NTSTATUS message on failure.

--*/
{
    PUFXDEVICE_CONTEXT DeviceContext;
    PCONTROLLER_CONTEXT ControllerContext;
    NTSTATUS Status;
    BOOLEAN NeedPower;
    DEVICE_POWER_STATE DxState = PowerDeviceD3;

    PAGED_CODE();

    TraceEntry();

    DeviceContext = UfxDeviceGetContext(Device);
    ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice);

    switch (UsbState) {

        case UsbfnDeviceStateAttached:
            __fallthrough;
        case UsbfnDeviceStateDefault:

            switch (UsbPort) {

                case UsbfnStandardDownstreamPort:
                    __fallthrough;
                case UsbfnChargingDownstreamPort:
                    __fallthrough;
                case UsbfnUnknownPort:
                    NeedPower = TRUE;
                    break;

                case UsbfnDedicatedChargingPort:
                case UsbfnProprietaryDedicatedChargingPort:
                    NeedPower = FALSE;
                    DxState = PowerDeviceD2;
                    break;

                default:
                    NeedPower = FALSE;
            }
            break;

        case UsbfnDeviceStateSuspended:
            NeedPower = FALSE;
            DxState = PowerDeviceD2;
            break;

        case UsbfnDeviceStateAddressed:
            __fallthrough;

        case UsbfnDeviceStateConfigured:
            NeedPower = TRUE;
            break;

        default:
            NeedPower = FALSE;
    }

    //
    // Determine if our lowest idle state has changed, and set it if so
    //
    if (DxState != ControllerContext->IdleSettings.DxState)
    {
        ControllerContext->IdleSettings.DxState = DxState;
        Status = WdfDeviceAssignS0IdleSettings(
            DeviceContext->FdoWdfDevice,
            &ControllerContext->IdleSettings);
        CHK_NT_MSG(Status, "Failed to update device idle settings");
    }

    if (NeedPower && DeviceContext->IsIdle) {
        //
        // We don't want to update the USB state /port until we stop idle to
        // prevent D0 -> DX path from reading the wrong state.
        //
        TraceInformation("Stopping idle");
        Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE);
        CHK_NT_MSG(Status, "Failed to stop idle");
        DeviceContext->UsbState = UsbState;
        DeviceContext->UsbPort = UsbPort;
        DeviceContext->IsIdle = FALSE;

    } else if (!NeedPower && !DeviceContext->IsIdle) {
        //
        // We need to update USB state / port before resume idle to ensure
        // D0 -> DX path reads the correct state.
        //
        DeviceContext->UsbState = UsbState;
        DeviceContext->UsbPort = UsbPort;
        DeviceContext->IsIdle = TRUE;
        TraceInformation("Resuming idle");
        WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice);

    } else {
        TraceInformation("No idle action");
        DeviceContext->UsbState = UsbState;
        DeviceContext->UsbPort = UsbPort;
    }

    Status = STATUS_SUCCESS;

End:
    TraceExit();
    return Status;
}