Ejemplo n.º 1
0
Archivo: wmi.c Proyecto: kcrazy/winekit
NTSTATUS
EvtWmiQueryPortPerfData(
    IN  WDFWMIINSTANCE WmiInstance,
    IN  ULONG OutBufferSize,
    IN  PVOID OutBuffer,
    OUT PULONG BufferUsed
    )
{
    PSERIAL_DEVICE_EXTENSION pDevExt;

    UNREFERENCED_PARAMETER(OutBufferSize);

    PAGED_CODE();

    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));

    *BufferUsed = sizeof(SERIAL_WMI_PERF_DATA);

    if (OutBufferSize < *BufferUsed) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    *(PSERIAL_WMI_PERF_DATA)OutBuffer = pDevExt->WmiPerfData;

    return STATUS_SUCCESS;
}
Ejemplo n.º 2
0
VOID
SerialTimeoutImmediate(
    IN WDFTIMER Timer
    )
{

    PSERIAL_DEVICE_EXTENSION Extension = NULL;

    Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, ">SerialTimeoutImmediate(%p)\n",
                     Extension);

    SerialTryToCompleteCurrent(
        Extension,
        SerialGrabImmediateFromIsr,
        STATUS_TIMEOUT,
        &Extension->CurrentImmediateRequest,
        NULL,
        NULL,
        Extension->ImmediateTotalTimer,
        NULL,
        SerialGetNextImmediate,
        SERIAL_REF_TOTAL_TIMER
        );

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "<SerialTimeoutImmediate\n");
}
Ejemplo n.º 3
0
Archivo: wmi.c Proyecto: ms-iot/bsp
_Use_decl_annotations_
NTSTATUS
EvtWmiQueryPortPerfData(
    WDFWMIINSTANCE WmiInstance,
    ULONG OutBufferSize,
    PVOID OutBuffer,
    PULONG BufferUsed
    )
{
    PSERIAL_DEVICE_EXTENSION devExt;
    UNREFERENCED_PARAMETER(OutBufferSize);
    NTSTATUS status;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "++EvtWmiQueryPortPerfData()\r\n");

    devExt = SerialGetDeviceExtension(WdfWmiInstanceGetDevice(WmiInstance));

    *BufferUsed = sizeof(SERIAL_WMI_PERF_DATA);

    if (OutBufferSize < *BufferUsed) {

        status = STATUS_INSUFFICIENT_RESOURCES;

    } else {

        *(PSERIAL_WMI_PERF_DATA)OutBuffer = devExt->WmiPerfData;
        status = STATUS_SUCCESS;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "--EvtWmiQueryPortPerfData()=%Xh\r\n", status);
    return status;
}
Ejemplo n.º 4
0
Archivo: wmi.c Proyecto: kcrazy/winekit
NTSTATUS
EvtWmiQueryPortPropData(
    IN  WDFWMIINSTANCE WmiInstance,
    IN  ULONG OutBufferSize,
    IN  PVOID OutBuffer,
    OUT PULONG BufferUsed
    )
{
    PSERIAL_DEVICE_EXTENSION pDevExt;

    UNREFERENCED_PARAMETER(OutBufferSize);

    PAGED_CODE();

    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));

    *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG);

    if (OutBufferSize < *BufferUsed) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    SerialGetProperties(
            pDevExt,
            (PSERIAL_COMMPROP)OutBuffer
            );

    *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0;

    return STATUS_SUCCESS;
}
Ejemplo n.º 5
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This routine is merely used to truely complete an xoff counter request.  It
    assumes that the status and the information fields of the request are
    already correctly filled in.

Arguments:

    Dpc - Not Used.

    DeferredContext - Really points to the device extension.

    SystemContext1 - Not Used.

    SystemContext2 - Not Used.

Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialCompleteXoff(
    WDFDPC Dpc
    )
{

    PSERIAL_DEVICE_EXTENSION extension = NULL;

    extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialCompleteXoff(%p)\r\n",
                     extension);

    SerialTryToCompleteCurrent(extension,
                                NULL,
                                STATUS_SUCCESS,
                                &extension->CurrentXoffRequest,
                                NULL, NULL,
                                extension->XoffCountTimer,
                                NULL, NULL,
                                SERIAL_REF_ISR);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialCompleteXoff\r\n");
}
Ejemplo n.º 6
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This routine will try to timeout the current write.

Arguments:

Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialWriteTimeout(
    WDFTIMER Timer
    )
{
    PSERIAL_DEVICE_EXTENSION extension = NULL;

    extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialWriteTimeout(%p)\r\n",
                     extension);

    SerialTryToCompleteCurrent(extension,
                                SerialGrabWriteFromIsr,
                                STATUS_TIMEOUT,
                                &extension->CurrentWriteRequest,
                                extension->WriteQueue,
                                NULL,
                                extension->WriteRequestTotalTimer,
                                SerialStartWrite,
                                SerialGetNextWrite,
                                SERIAL_REF_TOTAL_TIMER);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialWriteTimeout\r\n");
}
Ejemplo n.º 7
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This routine is merely used to complete any write.  It
    assumes that the status and the information fields of
    the request are already correctly filled in.

Arguments:

    Dpc - Not Used.

    DeferredContext - Really points to the device extension.

    SystemContext1 - Not Used.

    SystemContext2 - Not Used.

Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialCompleteWrite(
    WDFDPC Dpc
    )
{
    PSERIAL_DEVICE_EXTENSION Extension = NULL;

    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialCompleteWrite(%p) DPC\r\n",
                     Extension);

    SerialTryToCompleteCurrent(Extension,
                               NULL,
                               STATUS_SUCCESS,
                               &Extension->CurrentWriteRequest,
                               Extension->WriteQueue,
                               NULL,
                               Extension->WriteRequestTotalTimer,
                               SerialStartWrite,
                               SerialGetNextWrite,
                               SERIAL_REF_ISR);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialCompleteWrite DPC\r\n");
}
Ejemplo n.º 8
0
VOID
SerialCompleteImmediate(
    IN WDFDPC Dpc
    )

{

    PSERIAL_DEVICE_EXTENSION Extension = NULL;

    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, ">SerialCompleteImmediate(%p)\n",
                     Extension);

    SerialTryToCompleteCurrent(
        Extension,
        NULL,
        STATUS_SUCCESS,
        &Extension->CurrentImmediateRequest,
        NULL,
        NULL,
        Extension->ImmediateTotalTimer,
        NULL,
        SerialGetNextImmediate,
        SERIAL_REF_ISR
        );

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "<SerialCompleteImmediate\n");

}
Ejemplo n.º 9
0
Archivo: flush.c Proyecto: MHesham/bsp
_Use_decl_annotations_
NTSTATUS
SerialFlush(
    WDFDEVICE Device,
    PIRP Irp
    )

/*++

Routine Description:

    This is the dispatch routine for flush.  Flushing works by placing
    this request in the write queue.  When this request reaches the
    front of the write queue we simply complete it since this implies
    that all previous writes have completed.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP for the current request

Return Value:

    Could return status success, cancelled, or pending.

--*/

{

    PSERIAL_DEVICE_EXTENSION extension;

    extension = SerialGetDeviceExtension(Device);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, ">SerialFlush(%p, %p)\n", Device, Irp);

    PAGED_CODE();

    WdfIoQueueStopSynchronously(extension->WriteQueue);
    //
    // Flush is done - restart the queue
    //
    WdfIoQueueStart(extension->WriteQueue);

    Irp->IoStatus.Information = 0L;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);


    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "<SerialFlush\n");

    return STATUS_SUCCESS;
 }
Ejemplo n.º 10
0
VOID
SerialEvtDeviceFileCreate (
    IN WDFDEVICE     Device,
    IN WDFREQUEST    Request,
    IN WDFFILEOBJECT FileObject
    )
/*++

Routine Description:

    The framework calls a driver's EvtDeviceFileCreate callback
    when the framework receives an IRP_MJ_CREATE request.
    The system sends this request when a user application opens the
    device to perform an I/O operation, such as reading or writing a file.
    This callback is called synchronously, in the context of the thread
    that created the IRP_MJ_CREATE request.

Arguments:

    Device - Handle to a framework device object.
    FileObject - Pointer to fileobject that represents the open handle.
    CreateParams - Copy of the Create IO_STACK_LOCATION

Return Value:

   VOID.

--*/
{
    NTSTATUS status;
    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);

    UNREFERENCED_PARAMETER(FileObject);

    PAGED_CODE();

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

    status = SerialDeviceFileCreateWorker(Device);

    //
    // Complete the WDF request.
    //
    WdfRequestComplete(Request, status);

    return;

}
Ejemplo n.º 11
0
VOID
SerialCancelImmediate(
    IN WDFREQUEST Request
    )

/*++

Routine Description:

    This routine is used to cancel a request that is waiting on
    a comm event.

Arguments:

    Request - Pointer to the WDFREQUEST for the current request

Return Value:

    None.

--*/

{
    PSERIAL_DEVICE_EXTENSION Extension = NULL;
    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));

    UNREFERENCED_PARAMETER(Request);

    Extension = SerialGetDeviceExtension(device);

    SerialTryToCompleteCurrent(
        Extension,
        SerialGrabImmediateFromIsr,
        STATUS_CANCELLED,
        &Extension->CurrentImmediateRequest,
        NULL,
        NULL,
        Extension->ImmediateTotalTimer,
        NULL,
        SerialGetNextImmediate,
        SERIAL_REF_CANCEL
        );

}
Ejemplo n.º 12
0
NTSTATUS
SerialWdmDeviceFileCreate (
    IN WDFDEVICE Device,
    IN PIRP Irp
    )
/*++

Routine Description:

    This is the dispatch routine for IRP_MJ_CREATE. The system sends this
    request when a user application opens the device to perform an I/O
    operation, such as reading or writing a file.

Arguments:

    DeviceObject - Pointer to the device object for this device
    Irp - Pointer to the IRP for the current request

Return Value:

   NT status code

--*/
{
    NTSTATUS status;
    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);

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

    status = SerialDeviceFileCreateWorker(Device);

    //
    // Complete the WDM request.
    //
    Irp->IoStatus.Information = 0L;
    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return status;
}
Ejemplo n.º 13
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This routine is merely used to truely complete an xoff counter request,
    if its timer has run out.

Arguments:


Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialTimeoutXoff(
    WDFTIMER Timer
    )
{

    PSERIAL_DEVICE_EXTENSION extension = NULL;

    extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialTimeoutXoff(%p)\r\n", extension);

    SerialTryToCompleteCurrent(extension,
                                SerialGrabXoffFromIsr,
                                STATUS_SERIAL_COUNTER_TIMEOUT,
                                &extension->CurrentXoffRequest,
                                NULL, NULL, NULL,
                                NULL, NULL,
                                SERIAL_REF_TOTAL_TIMER);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialTimeoutXoff\r\n");
}
Ejemplo n.º 14
0
Archivo: wmi.c Proyecto: ms-iot/bsp
_Use_decl_annotations_
NTSTATUS
EvtWmiQueryPortPropData(
    WDFWMIINSTANCE WmiInstance,
    ULONG OutBufferSize,
    PVOID OutBuffer,
    PULONG BufferUsed
    )
{
    PSERIAL_DEVICE_EXTENSION devExt;
    NTSTATUS status;
    UNREFERENCED_PARAMETER(OutBufferSize);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "++EvtWmiQueryPortPerfData()\r\n");

    devExt = SerialGetDeviceExtension(WdfWmiInstanceGetDevice(WmiInstance));

    *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG);

    if (OutBufferSize < *BufferUsed) {

        status = STATUS_INSUFFICIENT_RESOURCES;

    } else {

        SerialGetProperties(devExt,
                            (PSERIAL_COMMPROP)OutBuffer);

        *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0;
        status = STATUS_SUCCESS;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "--EvtWmiQueryPortPerfData()=%Xh\r\n", status);
    return status;
}
Ejemplo n.º 15
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This routine is used to cancel the current write.

Arguments:

    Device - Wdf handle for the device

    Request - Pointer to the WDFREQUEST to be canceled.

Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialCancelCurrentXoff(
    WDFREQUEST Request
    )
{
    PSERIAL_DEVICE_EXTENSION extension;
    WDFDEVICE device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));

    UNREFERENCED_PARAMETER(Request);

    extension = SerialGetDeviceExtension(device);

    SerialTryToCompleteCurrent(extension,
                                SerialGrabXoffFromIsr,
                                STATUS_CANCELLED,
                                &extension->CurrentXoffRequest,
                                NULL,
                                NULL,
                                extension->XoffCountTimer,
                                NULL,
                                NULL,
                                SERIAL_REF_CANCEL);
}
Ejemplo n.º 16
0
Archivo: wmi.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    Registers with WMI as a data provider for this
    instance of the device

Arguments:

    Device - Handle to the mini Uart device

Return Value:
    Status

--*/
_Use_decl_annotations_
NTSTATUS
SerialWmiRegistration(
    WDFDEVICE Device
)
{
    NTSTATUS status = STATUS_SUCCESS;
    PSERIAL_DEVICE_EXTENSION devExt;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "++SerialWmiRegistration\r\n");

    devExt = SerialGetDeviceExtension (Device);

    // Fill in wmi perf data (all zero's)

    RtlZeroMemory(&devExt->WmiPerfData, sizeof(devExt->WmiPerfData));

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_PortName_GUID,
                                       0,
                                       EvtWmiQueryPortName);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WMI,
                    "SerialWmiRegistration() SerialWmiRegisterInstance(serGUID) failed. Err=%Xh\r\n",
                    status);
        goto EndWmiReg;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_CommInfo_GUID,
                                       sizeof(SERIAL_WMI_COMM_DATA),
                                       EvtWmiQueryPortCommData);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WMI,
                    "SerialWmiRegistration() SerialWmiRegisterInstance(WMICOMDA) failed. Err=%Xh\r\n",
                    status);
        goto EndWmiReg;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_HardwareConfiguration_GUID,
                                       sizeof(SERIAL_WMI_HW_DATA),
                                       EvtWmiQueryPortHWData);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WMI,
                    "SerialWmiRegistration() SerialWmiRegisterInstance(WMIHWDAT) failed. Err=%Xh\r\n",
                    status);
        return status;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_PerformanceInformation_GUID,
                                       sizeof(SERIAL_WMI_PERF_DATA),
                                       EvtWmiQueryPortPerfData);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WMI,
                    "SerialWmiRegistration() SerialWmiRegisterInstance(WMIPERF) failed. Err=%Xh\r\n",
                    status);
        goto EndWmiReg;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_CommProperties_GUID,
                                       sizeof(SERIAL_COMMPROP) + sizeof(ULONG),
                                       EvtWmiQueryPortPropData);

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WMI,
                    "SerialWmiRegistration() SerialWmiRegisterInstance(COMMPRPOP) failed. Err=%Xh\r\n",
                    status);
    }

EndWmiReg:
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI,
                "--SerialWmiRegistration()=%Xh\r\n",
                status);
    return status;
}
Ejemplo n.º 17
0
Archivo: wmi.c Proyecto: kcrazy/winekit
NTSTATUS
SerialWmiRegistration(
    WDFDEVICE      Device
)
/*++
Routine Description

    Registers with WMI as a data provider for this
    instance of the device

--*/
{
    NTSTATUS        status = STATUS_SUCCESS;
    PSERIAL_DEVICE_EXTENSION pDevExt;

    PAGED_CODE();

    pDevExt = SerialGetDeviceExtension (Device);

    //
    // Fill in wmi perf data (all zero's)
    //
    RtlZeroMemory(&pDevExt->WmiPerfData, sizeof(pDevExt->WmiPerfData));

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_PortName_GUID,
                                       0,
                                       EvtWmiQueryPortName);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_CommInfo_GUID,
                                       sizeof(SERIAL_WMI_COMM_DATA),
                                       EvtWmiQueryPortCommData);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_HardwareConfiguration_GUID,
                                       sizeof(SERIAL_WMI_HW_DATA),
                                       EvtWmiQueryPortHWData);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_PerformanceInformation_GUID,
                                       sizeof(SERIAL_WMI_PERF_DATA),
                                       EvtWmiQueryPortPerfData);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = SerialWmiRegisterInstance(Device,
                                       &MSSerial_CommProperties_GUID,
                                       sizeof(SERIAL_COMMPROP) + sizeof(ULONG),
                                       EvtWmiQueryPortPropData);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    return status;
}
Ejemplo n.º 18
0
BOOLEAN
SerialISR(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )

/*++

Routine Description:

    This is the interrupt service routine for the serial port driver.
    It will determine whether the serial port is the source of this
    interrupt.  If it is, then this routine will do the minimum of
    processing to quiet the interrupt.  It will store any information
    necessary for later processing.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.


Return Value:

    This function will return TRUE if the serial port is the source
    of this interrupt, FALSE otherwise.

--*/

{
    //
    // Holds the information specific to handling this device.
    //
    PSERIAL_DEVICE_EXTENSION Extension = NULL;

    //
    // Holds the contents of the interrupt identification record.
    // A low bit of zero in this register indicates that there is
    // an interrupt pending on this device.
    //
    UCHAR InterruptIdReg;

    //
    // Will hold whether we've serviced any interrupt causes in this
    // routine.
    //
    BOOLEAN ServicedAnInterrupt;

    UCHAR tempLSR;
    PREQUEST_CONTEXT reqContext = NULL;

    UNREFERENCED_PARAMETER(MessageID);

    Extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt));

    //
    // Make sure we have an interrupt pending.  If we do then
    // we need to make sure that the device is open.  If the
    // device isn't open or powered down then quiet the device.  Note that
    // if the device isn't opened when we enter this routine
    // it can't open while we're in it.
    //

    InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);

    if ((InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING)) {

        ServicedAnInterrupt = FALSE;

    } else if (!Extension->DeviceIsOpened/*
               || (Extension->PowerState != PowerDeviceD0)*/) {


        //
        // We got an interrupt with the device being closed or when the
        // device is supposed to be powered down.  This
        // is not unlikely with a serial device.  We just quietly
        // keep servicing the causes until it calms down.
        //

        ServicedAnInterrupt = TRUE;
        do {

            InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
            switch (InterruptIdReg) {

                case SERIAL_IIR_RLS: {

                    READ_LINE_STATUS(Extension, Extension->Controller);

                    break;

                }

                case SERIAL_IIR_RDA:
                case SERIAL_IIR_CTI: {

                    READ_RECEIVE_BUFFER(Extension, Extension->Controller);

                    break;

                }

                case SERIAL_IIR_THR: {

                    //
                    // Alread clear from reading the iir.
                    //
                    // We want to keep close track of whether
                    // the holding register is empty.
                    //

                    Extension->HoldingEmpty = TRUE;
                    break;

                }

                case SERIAL_IIR_MS: {

                    READ_MODEM_STATUS(Extension, Extension->Controller);
                    break;

                }

                default: {

                    ASSERT(FALSE);
                    break;

                }

            }

        } while (!((InterruptIdReg =
                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))
                    & SERIAL_IIR_NO_INTERRUPT_PENDING));

    } else {

        ServicedAnInterrupt = TRUE;
        do {

            //
            // We only care about bits that can denote an interrupt.
            //

            InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA |
                              SERIAL_IIR_CTI | SERIAL_IIR_THR |
                              SERIAL_IIR_MS;

            //
            // We have an interrupt.  We look for interrupt causes
            // in priority order.  The presence of a higher interrupt
            // will mask out causes of a lower priority.  When we service
            // and quiet a higher priority interrupt we then need to check
            // the interrupt causes to see if a new interrupt cause is
            // present.
            //

            switch (InterruptIdReg) {

                case SERIAL_IIR_RLS: {

                    SerialProcessLSR(Extension);

                    break;

                }

                case SERIAL_IIR_RDA:
                case SERIAL_IIR_CTI:

                {

                    //
                    // Reading the receive buffer will quiet this interrupt.
                    //
                    // It may also reveal a new interrupt cause.
                    //
                    UCHAR ReceivedChar;

                    do {

                        ReceivedChar =
                            READ_RECEIVE_BUFFER(Extension, Extension->Controller);
                        Extension->PerfStats.ReceivedCount++;
                        Extension->WmiPerfData.ReceivedCount++;

                        ReceivedChar &= Extension->ValidDataMask;

                        if (!ReceivedChar &&
                            (Extension->HandFlow.FlowReplace &
                             SERIAL_NULL_STRIPPING)) {

                            //
                            // If what we got is a null character
                            // and we're doing null stripping, then
                            // we simply act as if we didn't see it.
                            //

                            goto ReceiveDoLineStatus;

                        }

                        if ((Extension->HandFlow.FlowReplace &
                             SERIAL_AUTO_TRANSMIT) &&
                            ((ReceivedChar ==
                              Extension->SpecialChars.XonChar) ||
                             (ReceivedChar ==
                              Extension->SpecialChars.XoffChar))) {

                            //
                            // No matter what happens this character
                            // will never get seen by the app.
                            //

                            if (ReceivedChar ==
                                Extension->SpecialChars.XoffChar) {

                                Extension->TXHolding |= SERIAL_TX_XOFF;

                                if ((Extension->HandFlow.FlowReplace &
                                     SERIAL_RTS_MASK) ==
                                     SERIAL_TRANSMIT_TOGGLE) {

                                    SerialInsertQueueDpc(
                                        Extension->StartTimerLowerRTSDpc
                                        )?Extension->CountOfTryingToLowerRTS++:0;

                                }


                            } else {

                                if (Extension->TXHolding & SERIAL_TX_XOFF) {

                                    //
                                    // We got the xon char **AND*** we
                                    // were being held up on transmission
                                    // by xoff.  Clear that we are holding
                                    // due to xoff.  Transmission will
                                    // automatically restart because of
                                    // the code outside the main loop that
                                    // catches problems chips like the
                                    // SMC and the Winbond.
                                    //

                                    Extension->TXHolding &= ~SERIAL_TX_XOFF;

                                }

                            }

                            goto ReceiveDoLineStatus;

                        }

                        //
                        // Check to see if we should note
                        // the receive character or special
                        // character event.
                        //

                        if (Extension->IsrWaitMask) {

                            if (Extension->IsrWaitMask &
                                SERIAL_EV_RXCHAR) {

                                Extension->HistoryMask |= SERIAL_EV_RXCHAR;

                            }

                            if ((Extension->IsrWaitMask &
                                 SERIAL_EV_RXFLAG) &&
                                (Extension->SpecialChars.EventChar ==
                                 ReceivedChar)) {

                                Extension->HistoryMask |= SERIAL_EV_RXFLAG;

                            }

                            if (Extension->IrpMaskLocation &&
                                Extension->HistoryMask) {

                                *Extension->IrpMaskLocation =
                                 Extension->HistoryMask;
                                Extension->IrpMaskLocation = NULL;
                                Extension->HistoryMask = 0;
                                reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);
                                reqContext->Information = sizeof(ULONG);
                                SerialInsertQueueDpc(
                                    Extension->CommWaitDpc
                                    );

                            }

                        }

                        SerialPutChar(
                            Extension,
                            ReceivedChar
                            );

                        //
                        // If we're doing line status and modem
                        // status insertion then we need to insert
                        // a zero following the character we just
                        // placed into the buffer to mark that this
                        // was reception of what we are using to
                        // escape.
                        //

                        if (Extension->EscapeChar &&
                            (Extension->EscapeChar ==
                             ReceivedChar)) {

                            SerialPutChar(
                                Extension,
                                SERIAL_LSRMST_ESCAPE
                                );

                        }


ReceiveDoLineStatus:    ;
                        //
                        // This reads the interrupt ID register and detemines if bits are 0
                        // If either of the reserved bits are 1, we stop servicing interrupts
                        // Since this detection method is not guarenteed this is enabled via
                        // a registry entry "UartDetectRemoval" and intialized on DriverEntry.
                        // This is disabled by default and will only be enabled on Stratus systems
                        // that allow hot replacement of serial cards
                        //
                        if(Extension->UartRemovalDetect)
                        {
                           UCHAR DetectRemoval;

                           DetectRemoval = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);

                           if(DetectRemoval & SERIAL_IIR_MUST_BE_ZERO)
                           {
                               // break out of this loop and stop processing interrupts
                               break;
                           }
                        }

                        if (!((tempLSR = SerialProcessLSR(Extension)) &
                              SERIAL_LSR_DR)) {

                            //
                            // No more characters, get out of the
                            // loop.
                            //

                            break;

                        }

                        if ((tempLSR & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT |
                                         SERIAL_LSR_DR)) &&
                            Extension->EscapeChar) {

                           //
                           // An error was indicated and inserted into the
                           // stream, get out of the loop.
                           //

                           break;
                        }

                    } WHILE (TRUE);

                    break;

                }

                case SERIAL_IIR_THR: {

doTrasmitStuff:;
                    Extension->HoldingEmpty = TRUE;

                    if (Extension->WriteLength ||
                        Extension->TransmitImmediate ||
                        Extension->SendXoffChar ||
                        Extension->SendXonChar) {

                        //
                        // Even though all of the characters being
                        // sent haven't all been sent, this variable
                        // will be checked when the transmit queue is
                        // empty.  If it is still true and there is a
                        // wait on the transmit queue being empty then
                        // we know we finished transmitting all characters
                        // following the initiation of the wait since
                        // the code that initiates the wait will set
                        // this variable to false.
                        //
                        // One reason it could be false is that
                        // the writes were cancelled before they
                        // actually started, or that the writes
                        // failed due to timeouts.  This variable
                        // basically says a character was written
                        // by the isr at some point following the
                        // initiation of the wait.
                        //

                        Extension->EmptiedTransmit = TRUE;

                        //
                        // If we have output flow control based on
                        // the modem status lines, then we have to do
                        // all the modem work before we output each
                        // character. (Otherwise we might miss a
                        // status line change.)
                        //

                        if (Extension->HandFlow.ControlHandShake &
                            SERIAL_OUT_HANDSHAKEMASK) {

                            SerialHandleModemUpdate(
                                Extension,
                                TRUE
                                );

                        }

                        //
                        // We can only send the xon character if
                        // the only reason we are holding is because
                        // of the xoff.  (Hardware flow control or
                        // sending break preclude putting a new character
                        // on the wire.)
                        //

                        if (Extension->SendXonChar &&
                            !(Extension->TXHolding & ~SERIAL_TX_XOFF)) {

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;

                                WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller,
                                                                Extension->SpecialChars.XonChar);
                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;


                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;

                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XonChar);
                            }


                            Extension->SendXonChar = FALSE;
                            Extension->HoldingEmpty = FALSE;

                            //
                            // If we send an xon, by definition we
                            // can't be holding by Xoff.
                            //

                            Extension->TXHolding &= ~SERIAL_TX_XOFF;

                            //
                            // If we are sending an xon char then
                            // by definition we can't be "holding"
                            // up reception by Xoff.
                            //

                            Extension->RXHolding &= ~SERIAL_RX_XOFF;

                        } else if (Extension->SendXoffChar &&
                              !Extension->TXHolding) {

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XoffChar);

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XoffChar);

                            }

                            //
                            // We can't be sending an Xoff character
                            // if the transmission is already held
                            // up because of Xoff.  Therefore, if we
                            // are holding then we can't send the char.
                            //

                            //
                            // If the application has set xoff continue
                            // mode then we don't actually stop sending
                            // characters if we send an xoff to the other
                            // side.
                            //

                            if (!(Extension->HandFlow.FlowReplace &
                                  SERIAL_XOFF_CONTINUE)) {

                                Extension->TXHolding |= SERIAL_TX_XOFF;

                                if ((Extension->HandFlow.FlowReplace &
                                     SERIAL_RTS_MASK) ==
                                     SERIAL_TRANSMIT_TOGGLE) {

                                    SerialInsertQueueDpc(
                                        Extension->StartTimerLowerRTSDpc
                                        )?Extension->CountOfTryingToLowerRTS++:0;

                                }

                            }

                            Extension->SendXoffChar = FALSE;
                            Extension->HoldingEmpty = FALSE;

                        //
                        // Even if transmission is being held
                        // up, we should still transmit an immediate
                        // character if all that is holding us
                        // up is xon/xoff (OS/2 rules).
                        //

                        } else if (Extension->TransmitImmediate &&
                            (!Extension->TXHolding ||
                             (Extension->TXHolding == SERIAL_TX_XOFF)
                            )) {

                            Extension->TransmitImmediate = FALSE;

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->ImmediateChar);

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->ImmediateChar);

                            }

                            Extension->HoldingEmpty = FALSE;

                            SerialInsertQueueDpc(
                                Extension->CompleteImmediateDpc
                                );

                        } else if (!Extension->TXHolding) {

                            ULONG amountToWrite;

                            if (Extension->FifoPresent) {

                                amountToWrite = (Extension->TxFifoAmount <
                                                 Extension->WriteLength)?
                                                Extension->TxFifoAmount:
                                                Extension->WriteLength;

                            } else {

                                amountToWrite = 1;

                            }
                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                if (amountToWrite == 1) {

                                    Extension->PerfStats.TransmittedCount++;
                                    Extension->WmiPerfData.TransmittedCount++;
                                    WRITE_TRANSMIT_HOLDING(Extension,
                                        Extension->Controller,
                                        *(Extension->WriteCurrentChar));

                                } else {

                                    Extension->PerfStats.TransmittedCount +=
                                        amountToWrite;
                                    Extension->WmiPerfData.TransmittedCount +=
                                       amountToWrite;
                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,
                                        Extension->Controller,
                                        Extension->WriteCurrentChar,
                                        amountToWrite);
                                }

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                if (amountToWrite == 1) {

                                    Extension->PerfStats.TransmittedCount++;
                                    Extension->WmiPerfData.TransmittedCount++;
                                    WRITE_TRANSMIT_HOLDING(Extension,
                                        Extension->Controller,
                                        *(Extension->WriteCurrentChar));

                                } else {

                                    Extension->PerfStats.TransmittedCount +=
                                        amountToWrite;
                                    Extension->WmiPerfData.TransmittedCount +=
                                        amountToWrite;
                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,
                                        Extension->Controller,
                                        Extension->WriteCurrentChar,
                                        amountToWrite);

                                }

                            }

                            Extension->HoldingEmpty = FALSE;
                            Extension->WriteCurrentChar += amountToWrite;
                            Extension->WriteLength -= amountToWrite;

                            if (!Extension->WriteLength) {

                                //
                                // No More characters left.  This
                                // write is complete.  Take care
                                // when updating the information field,
                                // we could have an xoff counter masquerading
                                // as a write request.
                                //
                                reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);

                                reqContext->Information =
                                    (reqContext->MajorFunction == IRP_MJ_WRITE)?
                                        (reqContext->Length): (1);

                                SerialInsertQueueDpc(
                                    Extension->CompleteWriteDpc
                                    );

                            }

                        }

                    }

                    break;

                }

                case SERIAL_IIR_MS: {

                    SerialHandleModemUpdate(
                        Extension,
                        FALSE
                        );

                    break;

                }

            }

        } while (!((InterruptIdReg =
                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))
                    & SERIAL_IIR_NO_INTERRUPT_PENDING));

        //
        // Besides catching the WINBOND and SMC chip problems this
        // will also cause transmission to restart incase of an xon
        // char being received.  Don't remove.
        //

        if (SerialProcessLSR(Extension) & SERIAL_LSR_THRE) {

            if (!Extension->TXHolding &&
                (Extension->WriteLength ||
                 Extension->TransmitImmediate)) {

                goto doTrasmitStuff;

            }

        }

    }

    return ServicedAnInterrupt;

}
Ejemplo n.º 19
0
NTSTATUS
SerialEvtDeviceD0Entry(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE PreviousState
    )
/*++

Routine Description:

    EvtDeviceD0Entry event callback must perform any operations that are
    necessary before the specified device is used.  It will be called every
    time the hardware needs to be (re-)initialized.  This includes after
    IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE,
    IRP_MN_SET_POWER-D0.

    This function is not marked pageable because this function is in the
    device power up path. When a function is marked pagable and the code
    section is paged out, it will generate a page fault which could impact
    the fast resume behavior because the client driver will have to wait
    until the system drivers can service this page fault.

    This function runs at PASSIVE_LEVEL, even though it is not paged.  A
    driver can optionally make this function pageable if DO_POWER_PAGABLE
    is set.  Even if DO_POWER_PAGABLE isn't set, this function still runs
    at PASSIVE_LEVEL.  In this case, though, the function absolutely must
    not do anything that will cause a page fault.

Arguments:

    Device - Handle to a framework device object.

    PreviousState - Device power state which the device was in most recently.
        If the device is being newly started, this will be
        PowerDeviceUnspecified.

Return Value:

    NTSTATUS

--*/
{
    PSERIAL_DEVICE_EXTENSION deviceExtension;
    PSERIAL_DEVICE_STATE pDevState;
    SHORT divisor;
    SERIAL_IOCTL_SYNC S;

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER,
                "-->SerialEvtDeviceD0Entry - coming from %s\n", DbgDevicePowerString(PreviousState));

    deviceExtension = SerialGetDeviceExtension (Device);
    pDevState = &deviceExtension->DeviceState;

    //
    // Restore the state of the UART.  First, that involves disabling
    // interrupts both via OUT2 and IER.
    //

    WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, 0);
    DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);

    //
    // Set the baud rate
    //

    SerialGetDivisorFromBaud(deviceExtension->ClockRate, deviceExtension->CurrentBaud, &divisor);
    S.Extension = deviceExtension;
    S.Data = (PVOID) (ULONG_PTR) divisor;

#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "PFD warning that we are calling interrupt synchronize routine directly. Suppress it because interrupt is disabled above.")
    SerialSetBaud(deviceExtension->WdfInterrupt, &S);

    //
    // Reset / Re-enable the FIFO's
    //

    if (deviceExtension->FifoPresent) {
       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0);
       READ_RECEIVE_BUFFER(deviceExtension, deviceExtension->Controller);
       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller,
                          (UCHAR)(SERIAL_FCR_ENABLE | deviceExtension->RxFifoTrigger
                                  | SERIAL_FCR_RCVR_RESET
                                  | SERIAL_FCR_TXMT_RESET));
    } else {
       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0);
    }

    //
    // Restore a couple more registers
    //

    WRITE_INTERRUPT_ENABLE(deviceExtension, deviceExtension->Controller, pDevState->IER);
    WRITE_LINE_CONTROL(deviceExtension, deviceExtension->Controller, pDevState->LCR);

    //
    // Clear out any stale interrupts
    //

    READ_INTERRUPT_ID_REG(deviceExtension, deviceExtension->Controller);
    READ_LINE_STATUS(deviceExtension, deviceExtension->Controller);
    READ_MODEM_STATUS(deviceExtension, deviceExtension->Controller);

    //
    // TODO:  move this code to EvtInterruptEnable.
    //

    if (deviceExtension->DeviceState.Reopen == TRUE) {
       SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Reopening device\n");

       SetDeviceIsOpened(deviceExtension, TRUE, FALSE);

       //
       // This enables interrupts on the device!
       //

       WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller,
                           (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2));

       //
       // Refire the state machine
       //

       DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);
       ENABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);
    }

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--SerialEvtDeviceD0Entry\n");

    return STATUS_SUCCESS;
}
Ejemplo n.º 20
0
NTSTATUS
SerialEvtDeviceD0Exit(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE TargetState
    )
/*++

Routine Description:

   EvtDeviceD0Exit event callback must perform any operations that are
   necessary before the specified device is moved out of the D0 state.  If the
   driver needs to save hardware state before the device is powered down, then
   that should be done here.

   This function runs at PASSIVE_LEVEL, though it is generally not paged.  A
   driver can optionally make this function pageable if DO_POWER_PAGABLE is set.

   Even if DO_POWER_PAGABLE isn't set, this function still runs at
   PASSIVE_LEVEL.  In this case, though, the function absolutely must not do
   anything that will cause a page fault.

Arguments:

    Device - Handle to a framework device object.

    TargetState - Device power state which the device will be put in once this
        callback is complete.

Return Value:

    NTSTATUS

--*/
{
    PSERIAL_DEVICE_EXTENSION deviceExtension;

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER,
                "-->SerialEvtDeviceD0Exit - moving to %s\n", DbgDevicePowerString(TargetState));

    PAGED_CODE();

    deviceExtension = SerialGetDeviceExtension (Device);

    if (deviceExtension->DeviceIsOpened == TRUE) {
        LARGE_INTEGER charTime;

        SetDeviceIsOpened(deviceExtension, FALSE, TRUE);

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

        //
        // Shut down the chip
        //

        SerialDisableUART(deviceExtension);

        //
        // Drain the device
        //

        SerialDrainUART(deviceExtension, &charTime);

        //
        // Save the device state
        //

        SerialSaveDeviceState(deviceExtension);
    }
    else
    {
        SetDeviceIsOpened(deviceExtension, FALSE, FALSE);
    }

    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--SerialEvtDeviceD0Exit\n");

    return STATUS_SUCCESS;
}
Ejemplo n.º 21
0
NTSTATUS
SerialDeviceFileCreateWorker (
    IN WDFDEVICE Device
    )
{
    NTSTATUS status;
    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);

    //
    // Create a buffer for the RX data when no reads are outstanding.
    //

    extension->InterruptReadBuffer = NULL;
    extension->BufferSize = 0;

    switch (MmQuerySystemSize()) {

        case MmLargeSystem: {

            extension->BufferSize = 4096;
            extension->InterruptReadBuffer = ExAllocatePoolWithTag(
                                                 NonPagedPool,
                                                 extension->BufferSize,
                                                 POOL_TAG
                                                 );

            if (extension->InterruptReadBuffer) {
                break;
            }

        }

        case MmMediumSystem: {

            extension->BufferSize = 1024;
            extension->InterruptReadBuffer = ExAllocatePoolWithTag(
                                                 NonPagedPool,
                                                 extension->BufferSize,
                                                 POOL_TAG
                                                 );

            if (extension->InterruptReadBuffer) {
                break;
            }

        }

        case MmSmallSystem: {

            extension->BufferSize = 128;
            extension->InterruptReadBuffer = ExAllocatePoolWithTag(
                                                 NonPagedPool,
                                                 extension->BufferSize,
                                                 POOL_TAG
                                                 );

        }

    }

    if (!extension->InterruptReadBuffer) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // By taking a power reference by calling WdfDeviceStopIdle, we prevent the
    // framework from powering down our device due to idle timeout when there
    // is an open handle.  Power reference also moves the device to D0 if we are
    // idled out. If you fail create anywhere later in this routine, do make sure
    // drop the reference.
    //
    status = WdfDeviceStopIdle(Device, TRUE);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // wakeup is not currently enabled
    //

    extension->IsWakeEnabled = FALSE;

    //
    // On a new open we "flush" the read queue by initializing the
    // count of characters.
    //

    extension->CharsInInterruptBuffer = 0;
    extension->LastCharSlot = extension->InterruptReadBuffer +
                              (extension->BufferSize - 1);

    extension->ReadBufferBase = extension->InterruptReadBuffer;
    extension->CurrentCharSlot = extension->InterruptReadBuffer;
    extension->FirstReadableChar = extension->InterruptReadBuffer;

    extension->TotalCharsQueued = 0;

    //
    // We set up the default xon/xoff limits.
    //

    extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
    extension->HandFlow.XonLimit = extension->BufferSize >> 1;

    extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
    extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;

    extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
                                   (extension->BufferSize>>4));

    //
    // Mark the device as busy for WMI
    //

    extension->WmiCommData.IsBusy = TRUE;

    extension->IrpMaskLocation = NULL;
    extension->HistoryMask = 0;
    extension->IsrWaitMask = 0;

    extension->SendXonChar = FALSE;
    extension->SendXoffChar = FALSE;

#if !DBG
    //
    // Clear out the statistics.
    //

    WdfInterruptSynchronize(
        extension->WdfInterrupt,
        SerialClearStats,
        extension
        );
#endif

    //
    // The escape char replacement must be reset upon every open.
    //

    extension->EscapeChar = 0;

    //
    // We don't want the device to be removed or stopped when there is an handle
    //
    // 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, FALSE);

    //
    // Synchronize with the ISR and let it know that the device
    // has been successfully opened.
    //

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

    return STATUS_SUCCESS;

}
Ejemplo n.º 22
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;

}
Ejemplo n.º 23
0
Archivo: write.c Proyecto: ms-iot/bsp
/*++

Routine Description:

    This is the dispatch routine for write.  It validates the parameters
    for the write request and if all is ok then it places the request
    on the work queue.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - Pointer to the WDFREQUEST for the current request

    Length - Length of the IO operation
                 The default property of the queue is to not dispatch
                 zero lenght read & write requests to the driver and
                 complete is with status success. So we will never get
                 a zero length request.

Return Value:

--*/
_Use_decl_annotations_
VOID
SerialEvtIoWrite(
    WDFQUEUE Queue,
    WDFREQUEST Request,
    size_t Length
    )
{
    PSERIAL_DEVICE_EXTENSION extension;
    NTSTATUS status;
    WDFDEVICE hDevice;
    WDF_REQUEST_PARAMETERS params;
    PREQUEST_CONTEXT reqContext;
    size_t bufLen;
    UCHAR tempIER=0x00;

    hDevice = WdfIoQueueGetDevice(Queue);
    extension = SerialGetDeviceExtension(hDevice);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
                "++SerialEvtIoWrite(%p, 0x%I64x)\r\n", 
                Request,
                Length);

    if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) {

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
                    "--SerialEvtIoWrite 1 %Xh\r\n",
                    (ULONG)STATUS_CANCELLED);
        return;
    }

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(Request, &params);

    // Initialize the scratch area of the request.

    reqContext = SerialGetRequestContext(Request);
    reqContext->MajorFunction = params.Type;
    reqContext->Length = (ULONG) Length;

    status = WdfRequestRetrieveInputBuffer (Request,
                                            Length,
                                            &reqContext->SystemBuffer,
                                            &bufLen);

    if (!NT_SUCCESS (status)) {

        SerialCompleteRequest(Request , status, 0);
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
                    "--SerialEvtIoWrite 2 %Xh\r\n", 
                    status);
        return;
    }

   SerialStartOrQueue(extension,
                        Request,
                        extension->WriteQueue,
                        &extension->CurrentWriteRequest,
                        SerialStartWrite);

    // enable mini Uart Tx interrupt

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "SerialEvtIoWrite() - enable Tx interrupt\r\n");

    tempIER=READ_INTERRUPT_ENABLE(extension, extension->Controller);
    WRITE_INTERRUPT_ENABLE(extension, extension->Controller, (tempIER | SERIAL_IER_THR));

   TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialEvtIoWrite()=%X\r\n", status);
   return;
}