Beispiel #1
0
/*++

Routine Description:

    This routine is used to determine if conditions are appropriate
    to satisfy a wait for transmit empty event, and if so to complete
    the request that is waiting for that event.  It also call the code
    that checks to see if we should lower the RTS line if we are
    doing transmit toggling.

    NOTE: This routine is called by WdfInterruptSynchronize.

    NOTE: This routine assumes that it is called with the cancel
          spinlock held.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/
_Use_decl_annotations_
BOOLEAN
SerialProcessEmptyTransmit(
    WDFINTERRUPT Interrupt,
    PVOID Context
    )
{
    PSERIAL_DEVICE_EXTENSION extension = Context;

    UNREFERENCED_PARAMETER(Interrupt);

    if (extension->IsrWaitMask && (extension->IsrWaitMask & SERIAL_EV_TXEMPTY) &&
        extension->EmptiedTransmit && (!extension->TransmitImmediate) &&
        (!extension->CurrentWriteRequest) && IsQueueEmpty(extension->WriteQueue)) {

        extension->HistoryMask |= SERIAL_EV_TXEMPTY;
        if (extension->IrpMaskLocation) {

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

            SerialGetRequestContext(extension->CurrentWaitRequest)->Information = sizeof(ULONG);

            SerialInsertQueueDpc(extension->CommWaitDpc);
        }

        extension->CountOfTryingToLowerRTS++;
        SerialPerhapsLowerRTS(extension->WdfInterrupt, extension);
    }

    return FALSE;
}
Beispiel #2
0
/*++

Routine Description:

    This routine is used to grab an xoff counter request from the
    isr when it is no longer masquerading as a write request.  This
    routine is called by the cancel and timeout code for the
    xoff counter ioctl.


    NOTE: This routine is being called from WdfInterruptSynchronize.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    Always false.

--*/
_Use_decl_annotations_
BOOLEAN
SerialGrabXoffFromIsr(
    WDFINTERRUPT Interrupt,
    PVOID Context
    )
{

    PSERIAL_DEVICE_EXTENSION extension = Context;

    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(extension->CurrentXoffRequest);

    if (extension->CountSinceXoff) {

        // This is only non-zero when there actually is a Xoff ioctl
        // counting down.

        extension->CountSinceXoff = 0;

        // We decrement the count since the isr no longer owns
        // the request.

        SERIAL_CLEAR_REFERENCE(reqContext, SERIAL_REF_ISR);
    }

    return FALSE;
}
Beispiel #3
0
/*++

Routine Description:


    This routine starts off the xoff counter.  It merely
    has to set the xoff count and increment the reference
    count to denote that the isr has a reference to the request.

    NOTE: This routine is called by WdfInterruptSynchronize.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/
_Use_decl_annotations_
BOOLEAN
SerialGiveXoffToIsr(
    WDFINTERRUPT Interrupt,
    PVOID Context
    )
{
    PSERIAL_DEVICE_EXTENSION extension = Context;
    PREQUEST_CONTEXT reqContext;
    PSERIAL_XOFF_COUNTER xc = NULL;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(extension->CurrentXoffRequest);
    xc = reqContext->SystemBuffer;

    // The current stack location.  This contains all of the
    // information we need to process this particular request.

    ASSERT(extension->CurrentXoffRequest);
    extension->CountSinceXoff = xc->Counter;

    // The isr now has a reference to the request.

    SERIAL_SET_REFERENCE(reqContext, SERIAL_REF_ISR);

    return FALSE;
}
VOID
SerialGetNextImmediate(
    IN WDFREQUEST *CurrentOpRequest,
    IN WDFQUEUE QueueToProcess,
    IN WDFREQUEST *NewRequest,
    IN BOOLEAN CompleteCurrent,
    IN PSERIAL_DEVICE_EXTENSION Extension
    )

/*++

Routine Description:

    This routine is used to complete the current immediate
    request.  Even though the current immediate will always
    be completed and there is no queue associated with it,
    we use this routine so that we can try to satisfy
    a wait for transmit queue empty event.

Arguments:

    CurrentOpRequest - Pointer to the pointer that points to the
                   current write request.  This should point
                   to CurrentImmediateRequest.

    QueueToProcess - Always NULL.

    NewRequest - Always NULL on exit to this routine.

    CompleteCurrent - Should always be true for this routine.


Return Value:

    None.

--*/

{
    WDFREQUEST oldRequest = *CurrentOpRequest;
    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(oldRequest);

    UNREFERENCED_PARAMETER(QueueToProcess);
    UNREFERENCED_PARAMETER(CompleteCurrent);


    ASSERT(Extension->TotalCharsQueued >= 1);
    Extension->TotalCharsQueued--;

    *CurrentOpRequest = NULL;
    *NewRequest = NULL;
     WdfInterruptSynchronize(
        Extension->WdfInterrupt,
        SerialProcessEmptyTransmit,
        Extension
        );

    SerialCompleteRequest(oldRequest, reqContext->Status, reqContext->Information);
}
Beispiel #5
0
VOID
SerialPurgeRequests(
    IN WDFQUEUE QueueToClean,
    IN WDFREQUEST *CurrentOpRequest
    )

/*++

Routine Description:

    This function is used to cancel all queued and the current irps
    for reads or for writes. Called at DPC level.

Arguments:

    QueueToClean - A pointer to the queue which we're going to clean out.

    CurrentOpRequest - Pointer to a pointer to the current request.

Return Value:

    None.

--*/

{
    NTSTATUS status;
    PREQUEST_CONTEXT reqContext;

    WdfIoQueuePurge(QueueToClean, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT);

    //
    // The queue is clean.  Now go after the current if
    // it's there.
    //

    if (*CurrentOpRequest) {

        PFN_WDF_REQUEST_CANCEL CancelRoutine;

        reqContext = SerialGetRequestContext(*CurrentOpRequest);
        CancelRoutine = reqContext->CancelRoutine;
        //
        // Clear the common cancel routine but don't clear the reference because the
        // request specific cancel routine called below will clear the reference.
        //
        status = SerialClearCancelRoutine(*CurrentOpRequest, FALSE);
        if (NT_SUCCESS(status)) {
            //
            // Let us just call the CancelRoutine to start the next request.
            //
            if(CancelRoutine) {
                CancelRoutine(*CurrentOpRequest);
            }
        }
    }
}
BOOLEAN
SerialGrabImmediateFromIsr(
    IN WDFINTERRUPT  Interrupt,
    IN PVOID         Context
    )

/*++

Routine Description:


    This routine is used to grab the current request, which could be timing
    out or canceling, from the ISR

    NOTE: This routine is being called from WdfInterruptSynchronize.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    Always false.

--*/

{
    PSERIAL_DEVICE_EXTENSION Extension = Context;
    PREQUEST_CONTEXT         reqContext;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);

    if (Extension->TransmitImmediate) {

        Extension->TransmitImmediate = FALSE;

        //
        // Since the isr no longer references this request, we can
        // decrement it's reference count.
        //

        SERIAL_CLEAR_REFERENCE(
            reqContext,
            SERIAL_REF_ISR
            );

    }

    return FALSE;

}
Beispiel #7
0
/*++

Routine Description:

    This routine is used to grab the current request, which could be timing
    out or canceling, from the ISR

    NOTE: This routine is being called from WdfInterruptSynchronize.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    Always false.

--*/
_Use_decl_annotations_
BOOLEAN
SerialGrabWriteFromIsr(
    WDFINTERRUPT Interrupt,
    PVOID Context
    )
{

    PSERIAL_DEVICE_EXTENSION extension = Context;

    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(extension->CurrentWriteRequest);

    // Check if the write length is non-zero.  If it is non-zero
    // then the ISR still owns the request. We calculate the the number
    // of characters written and update the information field of the
    // request with the characters written.  We then clear the write length
    // the isr sees.

    if (extension->WriteLength) {

        // We could have an xoff counter masquerading as a
        // write request.  If so, don't update the write length.

        if (reqContext->MajorFunction == IRP_MJ_WRITE) {

            reqContext->Information = reqContext->Length -extension->WriteLength;

        } else {

            reqContext->Information = 0;
        }

        // Since the isr no longer references this request, we can
        // decrement it's reference count.

        SERIAL_CLEAR_REFERENCE(reqContext, SERIAL_REF_ISR);

        extension->WriteLength = 0;
    }

    return FALSE;

}
Beispiel #8
0
VOID
SerialEvtIoResume(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request
    )
/*++

Routine Description:

     This callback is invoked for every request pending in the driver - in-flight
     request - to notify that the hardware is ready for contiuing the processing
     of the request.

Arguments:

    Queue - Queue the request currently belongs to
    Request - Request that is currently out of queue and being processed by the driver

Return Value:

    None.

--*/
{
    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Queue);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
            "--> SerialEvtIoResume %p \n", Request);

    reqContext = SerialGetRequestContext(Request);

    //
    // If we unmarked cancelable on suspend, let us mark it cancelable again.
    //
    if (reqContext->MarkCancelableOnResume) {
        SerialSetCancelRoutine(Request, reqContext->CancelRoutine);
        reqContext->MarkCancelableOnResume = FALSE;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
        "<-- SerialEvtIoResume \n");
}
Beispiel #9
0
VOID
SerialEvtIoStop(
    IN WDFQUEUE                 Queue,
    IN WDFREQUEST               Request,
    IN ULONG                    ActionFlags
    )
/*++

Routine Description:

     This callback is invoked for every request pending in the driver (not queue) -
     in-flight request. The Action parameter tells us why the callback is invoked -
     because the device is being stopped, removed or suspended. In this
     driver, we have told the framework not to stop or remove when there
     are pending requests, so only reason for this callback is when the system is
     suspending.

Arguments:

    Queue - Queue the request currently belongs to
    Request - Request that is currently out of queue and being processed by the driver
    Action - Reason for this callback

Return Value:

    None. Acknowledge the request so that framework can contiue suspending the
    device.

--*/
{
    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Queue);

    reqContext = SerialGetRequestContext(Request);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
                    "--> SerialEvtIoStop %x %p\n", ActionFlags, Request);

    //
    // System suspends all the timers before asking the driver to goto
    // sleep. So let us not worry about cancelling the timers. Also the
    // framework will disconnect the interrupt before calling our
    // D0Exit handler so we can be sure that nobody will touch the hardware.
    // So just acknowledge callback to say that we are okay to stop due to
    // system suspend. Please note that since we have taken a power reference
    // we will never idle out when there is an open handle. Also we have told
    // the framework to not stop for resource rebalancing or remove when there are
    // open handles, so let us not worry about that either.
    //
    if (ActionFlags & WdfRequestStopRequestCancelable) {
        PFN_WDF_REQUEST_CANCEL cancelRoutine;

        //
        // Request is in a cancelable state. So unmark cancelable before you
        // acknowledge. We will mark the request cancelable when we resume.
        //
        cancelRoutine = reqContext->CancelRoutine;

        SerialClearCancelRoutine(Request, TRUE);

        //
        // SerialClearCancelRoutine clears the cancel-routine. So set it back
        // in the context. We will need that when we resume.
        //
        reqContext->CancelRoutine = cancelRoutine;

        reqContext->MarkCancelableOnResume = TRUE;

        ActionFlags &= ~WdfRequestStopRequestCancelable;
    }

    ASSERT(ActionFlags == WdfRequestStopActionSuspend);

    WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue the request

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE,
                        "<-- SerialEvtIoStop \n");
}
Beispiel #10
0
VOID
SerialTryToCompleteCurrent(
    IN PSERIAL_DEVICE_EXTENSION Extension,
    IN PFN_WDF_INTERRUPT_SYNCHRONIZE  SynchRoutine OPTIONAL,
    IN NTSTATUS StatusToUse,
    IN WDFREQUEST *CurrentOpRequest,
    IN WDFQUEUE QueueToProcess OPTIONAL,
    IN WDFTIMER IntervalTimer OPTIONAL,
    IN WDFTIMER TotalTimer OPTIONAL,
    IN PSERIAL_START_ROUTINE Starter OPTIONAL,
    IN PSERIAL_GET_NEXT_ROUTINE GetNextRequest OPTIONAL,
    IN LONG RefType
    )

/*++

Routine Description:

    This routine attempts to remove all of the reasons there are
    references on the current read/write.  If everything can be completed
    it will complete this read/write and try to start another.

    NOTE: This routine assumes that it is called with the cancel
          spinlock held.

Arguments:

    Extension - Simply a pointer to the device extension.

    SynchRoutine - A routine that will synchronize with the isr
                   and attempt to remove the knowledge of the
                   current request from the isr.  NOTE: This pointer
                   can be null.

    IrqlForRelease - This routine is called with the cancel spinlock held.
                     This is the irql that was current when the cancel
                     spinlock was acquired.

    StatusToUse - The request's status field will be set to this value, if
                  this routine can complete the request.


Return Value:

    None.

--*/

{
    PREQUEST_CONTEXT reqContext;

    ASSERTMSG("SerialTryToCompleteCurrent: CurrentOpRequest is NULL", *CurrentOpRequest);

     reqContext = SerialGetRequestContext(*CurrentOpRequest);

    if(RefType == SERIAL_REF_ISR || RefType == SERIAL_REF_XOFF_REF) {
        //
        // We can decrement the reference to "remove" the fact
        // that the caller no longer will be accessing this request.
        //

        SERIAL_CLEAR_REFERENCE(
            reqContext,
            RefType
            );
    }

    if (SynchRoutine) {

        WdfInterruptSynchronize(
            Extension->WdfInterrupt,
            SynchRoutine,
            Extension
            );

    }

    //
    // Try to run down all other references to this request.
    //

    SerialRundownIrpRefs(
        CurrentOpRequest,
        IntervalTimer,
        TotalTimer,
        Extension,
        RefType
        );

    if(StatusToUse == STATUS_CANCELLED) {
        //
        // This function is called from a cancelroutine. So mark
        // the request as cancelled. We need to do this because
        // we may not complete the request below if somebody
        // else has a reference to it.
        // This state variable was added to avoid calling
        // WdfRequestMarkCancelable second time on a request that
        // has cancelled but wasn't completed in the cancel routine.
        //
        reqContext->Cancelled = TRUE;
    }

    //
    // See if the ref count is zero after trying to complete everybody else.
    //

    if (!SERIAL_REFERENCE_COUNT(reqContext)) {

        WDFREQUEST newRequest;


        //
        // The ref count was zero so we should complete this
        // request.
        //
        // The following call will also cause the current request to be
        // completed.
        //

        reqContext->Status = StatusToUse;

        if (StatusToUse == STATUS_CANCELLED) {

            reqContext->Information = 0;

        }

        if (GetNextRequest) {

            GetNextRequest(
                CurrentOpRequest,
                QueueToProcess,
                &newRequest,
                TRUE,
                Extension
                );

            if (newRequest) {

                Starter(Extension);

            }

        } else {

            WDFREQUEST oldRequest = *CurrentOpRequest;

            //
            // There was no get next routine.  We will simply complete
            // the request.  We should make sure that we null out the
            // pointer to the pointer to this request.
            //

            *CurrentOpRequest = NULL;

            SerialCompleteRequest(oldRequest,
                                  reqContext->Status,
                                  reqContext->Information);
        }

    } else {


    }

}
Beispiel #11
0
VOID
SerialGetNextRequest(
    IN WDFREQUEST               * CurrentOpRequest,
    IN WDFQUEUE                   QueueToProcess,
    OUT WDFREQUEST              * NextRequest,
    IN BOOLEAN                    CompleteCurrent,
    IN PSERIAL_DEVICE_EXTENSION   Extension
    )

/*++

Routine Description:

    This function is used to make the head of the particular
    queue the current request.  It also completes the what
    was the old current request if desired.

Arguments:

    CurrentOpRequest - Pointer to a pointer to the currently active
                   request for the particular work list.  Note that
                   this item is not actually part of the list.

    QueueToProcess - The list to pull the new item off of.

    NextIrp - The next Request to process.  Note that CurrentOpRequest
              will be set to this value under protection of the
              cancel spin lock.  However, if *NextIrp is NULL when
              this routine returns, it is not necessaryly true the
              what is pointed to by CurrentOpRequest will also be NULL.
              The reason for this is that if the queue is empty
              when we hold the cancel spin lock, a new request may come
              in immediately after we release the lock.

    CompleteCurrent - If TRUE then this routine will complete the
                      request pointed to by the pointer argument
                      CurrentOpRequest.

Return Value:

    None.

--*/

{
    WDFREQUEST       oldRequest = NULL;
    PREQUEST_CONTEXT reqContext;
    NTSTATUS         status;

    UNREFERENCED_PARAMETER(Extension);

    oldRequest = *CurrentOpRequest;
    *CurrentOpRequest = NULL;

    //
    // Check to see if there is a new request to start up.
    //

    status = WdfIoQueueRetrieveNextRequest(
                 QueueToProcess,
                 CurrentOpRequest
                 );

    if(!NT_SUCCESS(status)) {
        ASSERTMSG("WdfIoQueueRetrieveNextRequest failed",
                  status == STATUS_NO_MORE_ENTRIES);
    }

    *NextRequest = *CurrentOpRequest;

    if (CompleteCurrent) {

        if (oldRequest) {

            reqContext = SerialGetRequestContext(oldRequest);

            SerialCompleteRequest(oldRequest,
                                  reqContext->Status,
                                  reqContext->Information);
        }
    }
}
Beispiel #12
0
/*++

Routine Description:

    Try to start off the write by slipping it in behind
    a transmit immediate char, or if that isn't available
    and the transmit holding register is empty, "tickle"
    the UART into interrupting with a transmit buffer
    empty.

    NOTE: This routine is called by WdfInterruptSynchronize.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/
_Use_decl_annotations_
BOOLEAN
SerialGiveWriteToIsr(
    WDFINTERRUPT Interrupt,
    PVOID Context
    )
{
    PSERIAL_DEVICE_EXTENSION extension = Context;

    // The current stack location.  This contains all of the
    // information we need to process this particular request.

    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(extension->CurrentWriteRequest);

    // We might have a xoff counter request masquerading as a
    // write.  The length of these requests will always be one
    // and we can get a pointer to the actual character from
    // the data supplied by the user.

    if (reqContext->MajorFunction == IRP_MJ_WRITE) {

        extension->WriteLength = reqContext->Length;
        extension->WriteCurrentChar = reqContext->SystemBuffer;

    } else {

        extension->WriteLength = 1;
        extension->WriteCurrentChar =
            ((PUCHAR)reqContext->SystemBuffer) +
            FIELD_OFFSET(SERIAL_XOFF_COUNTER, XoffChar);
    }

    // The isr now has a reference to the request.

    SERIAL_SET_REFERENCE(reqContext, SERIAL_REF_ISR);

    // Check first to see if an immediate char is transmitting.
    // If it is then we'll just slip in behind it when its done.

    if (!extension->TransmitImmediate) {

        // If there is no immediate char transmitting then we
        // will "re-enable" the transmit holding register empty
        // interrupt.  The 16550 family of devices will always
        // signal a transmit holding register empty interrupt
        // *ANY* time this bit is set to one.  By doing things
        // this way we can simply use the normal interrupt code
        // to start off this write.
        //
        // We've been keeping track of whether the transmit holding
        // register is empty so it we only need to do this
        // if the register is empty.

        if (extension->HoldingEmpty) {

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

    // The rts line may already be up from previous writes,
    // however, it won't take much additional time to turn
    // on the RTS line if we are doing transmit toggling.

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

        SerialSetRTS(extension->WdfInterrupt, extension);
    }

    return FALSE;
}
Beispiel #13
0
VOID
SerialStartOrQueue(
    IN PSERIAL_DEVICE_EXTENSION Extension,
    IN WDFREQUEST Request,
    IN WDFQUEUE QueueToExamine,
    IN WDFREQUEST *CurrentOpRequest,
    IN PSERIAL_START_ROUTINE Starter
    )

/*++

Routine Description:

    This routine is used to either start or queue any requst
    that can be queued in the driver.

Arguments:

    Extension - Points to the serial device extension.

    Request - The request to either queue or start.  In either
          case the request will be marked pending.

    QueueToExamine - The queue the request will be place on if there
                     is already an operation in progress.

    CurrentOpRequest - Pointer to a pointer to the request the is current
                   for the queue.  The pointer pointed to will be
                   set with to Request if what CurrentOpRequest points to
                   is NULL.

    Starter - The routine to call if the queue is empty.

Return Value:


--*/

{

    NTSTATUS status;
    PREQUEST_CONTEXT reqContext;
    WDF_REQUEST_PARAMETERS  params;

    reqContext = SerialGetRequestContext(Request);

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(
             Request,
             &params);

    //
    // If this is a write request then take the amount of characters
    // to write and add it to the count of characters to write.
    //

    if (params.Type == WdfRequestTypeWrite) {

        Extension->TotalCharsQueued += reqContext->Length;

    } else if ((params.Type == WdfRequestTypeDeviceControl) &&
               ((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) ||
                (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) {

        reqContext->IoctlCode = params.Parameters.DeviceIoControl.IoControlCode; // We need this in the destroy callback

        Extension->TotalCharsQueued++;

    }

    if (IsQueueEmpty(QueueToExamine) &&  !(*CurrentOpRequest)) {

        //
        // There were no current operation.  Mark this one as
        // current and start it up.
        //

        *CurrentOpRequest = Request;

        Starter(Extension);

        return;

    } else {

        //
        // We don't know how long the request will be in the
        // queue.  If it gets cancelled while waiting in the queue, we will
        // be notified by EvtCanceledOnQueue callback so that we can readjust
        // the lenght or free the buffer.
        //
        reqContext->Extension = Extension; // We need this in the destroy callback

        status = WdfRequestForwardToIoQueue(Request,  QueueToExamine);
        if(!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestForwardToIoQueue failed%X\n", status);
            ASSERTMSG("WdfRequestForwardToIoQueue failed ", FALSE);
            SerialCompleteRequest(Request, status, 0);
        }

        return;
    }
}
Beispiel #14
0
/*++

Routine Description:

    This routine is used to start off any write.  It initializes
    the Iostatus fields of the request.  It will set up any timers
    that are used to control the write.

Arguments:

    Extension - Points to the serial device extension

Return Value:

--*/
_Use_decl_annotations_
VOID
SerialStartWrite(
    PSERIAL_DEVICE_EXTENSION Extension
    )
{

    LARGE_INTEGER    totalTime;
    BOOLEAN          useAtimer;
    SERIAL_TIMEOUTS  timeouts;
    PREQUEST_CONTEXT reqContext;
    PREQUEST_CONTEXT reqContextXoff;

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

    totalTime.QuadPart = 0;

    do {

        reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);

        // If there is an xoff counter then complete it.

        // We see if there is a actually an Xoff counter request.
        //
        // If there is, we put the write request back on the head
        // of the write list.  We then complete the xoff counter.
        // The xoff counter completing code will actually make the
        // xoff counter back into the current write request, and
        // in the course of completing the xoff (which is now
        // the current write) we will restart this request.

        if (Extension->CurrentXoffRequest) {

            reqContextXoff =
                SerialGetRequestContext(Extension->CurrentXoffRequest);

            if (SERIAL_REFERENCE_COUNT(reqContextXoff)) {

                // The reference count is non-zero.  This implies that
                // the xoff request has not made it through the completion
                // path yet.  We will increment the reference count
                // and attempt to complete it ourseleves.

                SERIAL_SET_REFERENCE(reqContextXoff, SERIAL_REF_XOFF_REF);

                reqContextXoff->Information = 0;

                // The following call will actually release the
                // cancel spin lock.

                SerialTryToCompleteCurrent(Extension,
                                            SerialGrabXoffFromIsr,
                                            STATUS_SERIAL_MORE_WRITES,
                                            &Extension->CurrentXoffRequest,
                                            NULL,
                                            NULL,
                                            Extension->XoffCountTimer,
                                            NULL,
                                            NULL,
                                            SERIAL_REF_XOFF_REF);

            } else {

                // The request is well on its way to being finished.
                // We can let the regular completion code do the
                // work.  Just release the spin lock.

            }

        }

        useAtimer = FALSE;

        // Calculate the timeout value needed for the
        // request.  Note that the values stored in the
        // timeout record are in milliseconds.  Note that
        // if the timeout values are zero then we won't start
        // the timer.

        timeouts = Extension->timeouts;

        if (timeouts.WriteTotalTimeoutConstant ||
            timeouts.WriteTotalTimeoutMultiplier) {

            useAtimer = TRUE;

            // We have some timer values to calculate.
            //
            // Take care, we might have an xoff counter masquerading
            // as a write.

            totalTime.QuadPart =((LONGLONG)((UInt32x32To64((reqContext->MajorFunction == IRP_MJ_WRITE)?
                                                    (reqContext->Length) : (1),
                                                    timeouts.WriteTotalTimeoutMultiplier)
                                                    + timeouts.WriteTotalTimeoutConstant)))
                                                    * -10000;
        }

        // The request may be going to the isr shortly.  Now
        // is a good time to initialize its reference counts.

        SERIAL_INIT_REFERENCE(reqContext);

         // We give the request to to the isr to write out.
         // We set a cancel routine that knows how to
         // grab the current write away from the isr.

         SerialSetCancelRoutine(Extension->CurrentWriteRequest,
                                 SerialCancelCurrentWrite);

        if (useAtimer) {
            BOOLEAN result;

            result = SerialSetTimer(Extension->WriteRequestTotalTimer,
                                    totalTime);

            if(result == FALSE) {
                
                // This timer now has a reference to the request.

                SERIAL_SET_REFERENCE(reqContext, SERIAL_REF_TOTAL_TIMER );
            }
        }

        WdfInterruptSynchronize(Extension->WdfInterrupt,
                                SerialGiveWriteToIsr,
                                Extension);

    } while (FALSE);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialStartWrite\r\n");
    return;
}
Beispiel #15
0
VOID
SerialPutChar(
    IN PSERIAL_DEVICE_EXTENSION Extension,
    IN UCHAR CharToPut
    )

/*++

Routine Description:

    This routine, which only runs at device level, takes care of
    placing a character into the typeahead (receive) buffer.

Arguments:

    Extension - The serial device extension.

Return Value:

    None.

--*/

{
    PREQUEST_CONTEXT reqContext = NULL;

    //
    // If we have dsr sensitivity enabled then
    // we need to check the modem status register
    // to see if it has changed.
    //

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

        SerialHandleModemUpdate(
            Extension,
            FALSE
            );

        if (Extension->RXHolding & SERIAL_RX_DSR) {

            //
            // We simply act as if we haven't
            // seen the character if we have dsr
            // sensitivity and the dsr line is low.
            //

            return;

        }

    }

    //
    // If the xoff counter is non-zero then decrement it.
    // If the counter then goes to zero, complete that request.
    //

    if (Extension->CountSinceXoff) {

        Extension->CountSinceXoff--;

        if (!Extension->CountSinceXoff) {
            reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest);
            reqContext->Status = STATUS_SUCCESS;
            reqContext->Information = 0;
            SerialInsertQueueDpc(
                Extension->XoffCountCompleteDpc
                );

        }

    }

    //
    // Check to see if we are copying into the
    // users buffer or into the interrupt buffer.
    //
    // If we are copying into the user buffer
    // then we know there is always room for one more.
    // (We know this because if there wasn't room
    // then that read would have completed and we
    // would be using the interrupt buffer.)
    //
    // If we are copying into the interrupt buffer
    // then we will need to check if we have enough
    // room.
    //

    if (Extension->ReadBufferBase !=
        Extension->InterruptReadBuffer) {

        //
        // Increment the following value so
        // that the interval timer (if one exists
        // for this read) can know that a character
        // has been read.
        //

        Extension->ReadByIsr++;

        //
        // We are in the user buffer.  Place the
        // character into the buffer.  See if the
        // read is complete.
        //

        *Extension->CurrentCharSlot = CharToPut;

        if (Extension->CurrentCharSlot ==
            Extension->LastCharSlot) {

            //
            // We've filled up the users buffer.
            // Switch back to the interrupt buffer
            // and send off a DPC to Complete the read.
            //
            // It is inherent that when we were using
            // a user buffer that the interrupt buffer
            // was empty.
            //

            Extension->ReadBufferBase =
                Extension->InterruptReadBuffer;
            Extension->CurrentCharSlot =
                Extension->InterruptReadBuffer;
            Extension->FirstReadableChar =
                Extension->InterruptReadBuffer;
            Extension->LastCharSlot =
                Extension->InterruptReadBuffer +
                (Extension->BufferSize - 1);
            Extension->CharsInInterruptBuffer = 0;
            reqContext = SerialGetRequestContext(Extension->CurrentReadRequest);
            reqContext->Information = reqContext->Length;

            SerialInsertQueueDpc(
                Extension->CompleteReadDpc
                );

        } else {

            //
            // Not done with the users read.
            //

            Extension->CurrentCharSlot++;

        }

    } else {

        //
        // We need to see if we reached our flow
        // control threshold.  If we have then
        // we turn on whatever flow control the
        // owner has specified.  If no flow
        // control was specified, well..., we keep
        // trying to receive characters and hope that
        // we have enough room.  Note that no matter
        // what flow control protocol we are using, it
        // will not prevent us from reading whatever
        // characters are available.
        //

        if ((Extension->HandFlow.ControlHandShake
             & SERIAL_DTR_MASK) ==
            SERIAL_DTR_HANDSHAKE) {

            //
            // If we are already doing a
            // dtr hold then we don't have
            // to do anything else.
            //

            if (!(Extension->RXHolding &
                  SERIAL_RX_DTR)) {

                if ((Extension->BufferSize -
                     Extension->HandFlow.XoffLimit)
                    <= (Extension->CharsInInterruptBuffer+1)) {

                    Extension->RXHolding |= SERIAL_RX_DTR;

                    SerialClrDTR(Extension->WdfInterrupt, Extension);

                }

            }

        }

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

            //
            // If we are already doing a
            // rts hold then we don't have
            // to do anything else.
            //

            if (!(Extension->RXHolding &
                  SERIAL_RX_RTS)) {

                if ((Extension->BufferSize -
                     Extension->HandFlow.XoffLimit)
                    <= (Extension->CharsInInterruptBuffer+1)) {

                    Extension->RXHolding |= SERIAL_RX_RTS;

                    SerialClrRTS(Extension->WdfInterrupt, Extension);

                }

            }

        }

        if (Extension->HandFlow.FlowReplace &
            SERIAL_AUTO_RECEIVE) {

            //
            // If we are already doing a
            // xoff hold then we don't have
            // to do anything else.
            //

            if (!(Extension->RXHolding &
                  SERIAL_RX_XOFF)) {

                if ((Extension->BufferSize -
                     Extension->HandFlow.XoffLimit)
                    <= (Extension->CharsInInterruptBuffer+1)) {

                    Extension->RXHolding |= SERIAL_RX_XOFF;

                    //
                    // If necessary cause an
                    // off to be sent.
                    //

                    SerialProdXonXoff(
                        Extension,
                        FALSE
                        );

                }

            }

        }

        if (Extension->CharsInInterruptBuffer <
            Extension->BufferSize) {

            *Extension->CurrentCharSlot = CharToPut;
            Extension->CharsInInterruptBuffer++;

            //
            // If we've become 80% full on this character
            // and this is an interesting event, note it.
            //

            if (Extension->CharsInInterruptBuffer ==
                Extension->BufferSizePt8) {

                if (Extension->IsrWaitMask &
                    SERIAL_EV_RX80FULL) {

                    Extension->HistoryMask |= SERIAL_EV_RX80FULL;

                    if (Extension->IrpMaskLocation) {

                        *Extension->IrpMaskLocation =
                         Extension->HistoryMask;
                        Extension->IrpMaskLocation = NULL;
                        Extension->HistoryMask = 0;

                        reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);
                        reqContext->Information =  sizeof(ULONG);
                        SerialInsertQueueDpc(
                            Extension->CommWaitDpc
                            );

                    }

                }

            }

            //
            // Point to the next available space
            // for a received character.  Make sure
            // that we wrap around to the beginning
            // of the buffer if this last character
            // received was placed at the last slot
            // in the buffer.
            //

            if (Extension->CurrentCharSlot ==
                Extension->LastCharSlot) {

                Extension->CurrentCharSlot =
                    Extension->InterruptReadBuffer;

            } else {

                Extension->CurrentCharSlot++;

            }

        } else {

            //
            // We have a new character but no room for it.
            //

            Extension->PerfStats.BufferOverrunErrorCount++;
            Extension->WmiPerfData.BufferOverrunErrorCount++;
            Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;

            if (Extension->HandFlow.FlowReplace &
                SERIAL_ERROR_CHAR) {

                //
                // Place the error character into the last
                // valid place for a character.  Be careful!,
                // that place might not be the previous location!
                //

                if (Extension->CurrentCharSlot ==
                    Extension->InterruptReadBuffer) {

                    *(Extension->InterruptReadBuffer+
                      (Extension->BufferSize-1)) =
                      Extension->SpecialChars.ErrorChar;

                } else {

                    *(Extension->CurrentCharSlot-1) =
                     Extension->SpecialChars.ErrorChar;

                }

            }

            //
            // If the application has requested it, abort all reads
            // and writes on an error.
            //

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

                SerialInsertQueueDpc(
                    Extension->CommErrorDpc
                    );

            }

        }

    }

}
Beispiel #16
0
UCHAR
SerialProcessLSR(
    IN PSERIAL_DEVICE_EXTENSION Extension
    )

/*++

Routine Description:

    This routine, which only runs at device level, reads the
    ISR and totally processes everything that might have
    changed.

Arguments:

    Extension - The serial device extension.

Return Value:

    The value of the line status register.

--*/

{
    PREQUEST_CONTEXT reqContext = NULL;

    UCHAR LineStatus = READ_LINE_STATUS(Extension, Extension->Controller);


    Extension->HoldingEmpty = (LineStatus & SERIAL_LSR_THRE) ? TRUE : FALSE;

    //
    // If the line status register is just the fact that
    // the trasmit registers are empty or a character is
    // received then we want to reread the interrupt
    // identification register so that we just pick up that.
    //

    if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT
                       | SERIAL_LSR_DR)) {

        //
        // We have some sort of data problem in the receive.
        // For any of these errors we may abort all current
        // reads and writes.
        //
        //
        // If we are inserting the value of the line status
        // into the data stream then we should put the escape
        // character in now.
        //

        if (Extension->EscapeChar) {

            SerialPutChar(
                Extension,
                Extension->EscapeChar
                );

            SerialPutChar(
                Extension,
                (UCHAR)((LineStatus & SERIAL_LSR_DR)?
                    (SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA))
                );

            SerialPutChar(
                Extension,
                LineStatus
                );

            if (LineStatus & SERIAL_LSR_DR) {

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

            }

        }

        if (LineStatus & SERIAL_LSR_OE) {

            Extension->PerfStats.SerialOverrunErrorCount++;
            Extension->WmiPerfData.SerialOverrunErrorCount++;
            Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;

            if (Extension->HandFlow.FlowReplace &
                SERIAL_ERROR_CHAR) {

                SerialPutChar(
                    Extension,
                    Extension->SpecialChars.ErrorChar
                    );

                if (LineStatus & SERIAL_LSR_DR) {

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

                }

            } else {

                if (LineStatus & SERIAL_LSR_DR) {

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

                }

            }

        }

        if (LineStatus & SERIAL_LSR_BI) {

            Extension->ErrorWord |= SERIAL_ERROR_BREAK;

            if (Extension->HandFlow.FlowReplace &
                SERIAL_BREAK_CHAR) {

                SerialPutChar(
                    Extension,
                    Extension->SpecialChars.BreakChar
                    );

            }

        } else {

            //
            // Framing errors only count if they
            // occur exclusive of a break being
            // received.
            //

            if (LineStatus & SERIAL_LSR_PE) {

                Extension->PerfStats.ParityErrorCount++;
                Extension->WmiPerfData.ParityErrorCount++;
                Extension->ErrorWord |= SERIAL_ERROR_PARITY;

                if (Extension->HandFlow.FlowReplace &
                    SERIAL_ERROR_CHAR) {

                    SerialPutChar(
                        Extension,
                        Extension->SpecialChars.ErrorChar
                        );

                    if (LineStatus & SERIAL_LSR_DR) {

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

                    }

                }

            }

            if (LineStatus & SERIAL_LSR_FE) {

                Extension->PerfStats.FrameErrorCount++;
                Extension->WmiPerfData.FrameErrorCount++;
                Extension->ErrorWord |= SERIAL_ERROR_FRAMING;

                if (Extension->HandFlow.FlowReplace &
                    SERIAL_ERROR_CHAR) {

                    SerialPutChar(
                        Extension,
                        Extension->SpecialChars.ErrorChar
                        );
                    if (LineStatus & SERIAL_LSR_DR) {

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

                    }

                }

            }

        }

        //
        // If the application has requested it,
        // abort all the reads and writes
        // on an error.
        //

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

            SerialInsertQueueDpc(
                Extension->CommErrorDpc
                );

        }

        //
        // Check to see if we have a wait
        // pending on the comm error events.  If we
        // do then we schedule a dpc to satisfy
        // that wait.
        //

        if (Extension->IsrWaitMask) {

            if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&
                (LineStatus & (SERIAL_LSR_OE |
                               SERIAL_LSR_PE |
                               SERIAL_LSR_FE))) {

                Extension->HistoryMask |= SERIAL_EV_ERR;

            }

            if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&
                (LineStatus & SERIAL_LSR_BI)) {

                Extension->HistoryMask |= SERIAL_EV_BREAK;

            }

            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
                    );

            }

        }

        if (LineStatus & SERIAL_LSR_THRE) {

            //
            // There is a hardware bug in some versions
            // of the 16450 and 550.  If THRE interrupt
            // is pending, but a higher interrupt comes
            // in it will only return the higher and
            // *forget* about the THRE.
            //
            // A suitable workaround - whenever we
            // are *all* done reading line status
            // of the device we check to see if the
            // transmit holding register is empty.  If it is
            // AND we are currently transmitting data
            // enable the interrupts which should cause
            // an interrupt indication which we quiet
            // when we read the interrupt id register.
            //

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

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

        }

    }

    return LineStatus;
}
Beispiel #17
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;

}
Beispiel #18
0
/*++

Routine Description:

    This routine completes the old write as well as getting
    a pointer to the next write.

    The reason that we have have pointers to the current write
    queue as well as the current write request is so that this
    routine may be used in the common completion code for
    read and write.

Arguments:

    CurrentOpRequest - Pointer to the pointer that points to the
                   current write request.

    QueueToProcess - Pointer to the write queue.

    NewRequest - A pointer to a pointer to the request that will be the
             current request.  Note that this could end up pointing
             to a null pointer.  This does NOT necessaryly mean
             that there is no current write.  What could occur
             is that while the cancel lock is held the write
             queue ended up being empty, but as soon as we release
             the cancel spin lock a new request came in from
             SerialStartWrite.

    CompleteCurrent - Flag indicates whether the CurrentOpRequest should
                      be completed.

Return Value:

    None.

--*/
_Use_decl_annotations_
VOID
SerialGetNextWrite(
    WDFREQUEST* CurrentOpRequest,
    WDFQUEUE QueueToProcess,
    WDFREQUEST* NewRequest,
    BOOLEAN CompleteCurrent,
    PSERIAL_DEVICE_EXTENSION Extension
    )
{
    PREQUEST_CONTEXT reqContext;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialGetNextWrite\r\n");

    do {

        reqContext = SerialGetRequestContext(*CurrentOpRequest);

        // We could be completing a flush.

        if (reqContext->MajorFunction == IRP_MJ_WRITE) {

            ASSERT(Extension->TotalCharsQueued >= reqContext->Length);

            Extension->TotalCharsQueued -= reqContext->Length;

        } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

            WDFREQUEST request = *CurrentOpRequest;
            PSERIAL_XOFF_COUNTER xc;

            xc = reqContext->SystemBuffer;

            // We should never have a xoff counter when we
            // get to this point.

            ASSERT(!Extension->CurrentXoffRequest);

            // This could only be a xoff counter masquerading as
            // a write request.

            Extension->TotalCharsQueued--;

            // Check to see of the xoff request has been set with success.
            // This means that the write completed normally.  If that
            // is the case, and it hasn't been set to cancel in the
            // meanwhile, then go on and make it the CurrentXoffRequest.

            if (reqContext->Status != STATUS_SUCCESS || reqContext->Cancelled) {

                // If Xoff request getting abandoned due to loss of
                // Total timer - SERIAL_REF_TOTAL_TIMER
                // we can just finish it off.

            } else {

                SerialSetCancelRoutine(request, SerialCancelCurrentXoff);

                // We don't want to complete the current request now.  This
                // will now get completed by the Xoff counter code.

                CompleteCurrent = FALSE;

                // Give the counter to the isr.

                Extension->CurrentXoffRequest = request;

                WdfInterruptSynchronize(Extension->WdfInterrupt,
                                        SerialGiveXoffToIsr,
                                        Extension);

                // Start the timer for the counter and increment
                // the reference count since the timer has a
                // reference to the request.

                if (xc->Timeout) {

                    LARGE_INTEGER delta;
                    BOOLEAN result;

                    delta.QuadPart = -((LONGLONG)UInt32x32To64(1000,
                                                                xc->Timeout));

                    result = SerialSetTimer(Extension->XoffCountTimer,
                                            delta);

                    if(result == FALSE) {

                        SERIAL_SET_REFERENCE(reqContext,
                                            SERIAL_REF_TOTAL_TIMER);

                    }
                }
            }
        }

        // Note that the following call will (probably) also cause
        // the current request to be completed.

        SerialGetNextRequest(CurrentOpRequest,
                            QueueToProcess,
                            NewRequest,
                            CompleteCurrent,
                            Extension);

        if (!*NewRequest) {

            WdfInterruptSynchronize(Extension->WdfInterrupt,
                                    SerialProcessEmptyTransmit,
                                    Extension);

            break;

        } else if (SerialGetRequestContext(*NewRequest)->MajorFunction
                   == IRP_MJ_FLUSH_BUFFERS) {

            // If we encounter a flush request we just want to get
            // the next request and complete the flush.
            //
            // Note that if NewRequest is non-null then it is also
            // equal to CurrentWriteRequest.

            ASSERT((*NewRequest) == (*CurrentOpRequest));
            SerialGetRequestContext(*NewRequest)->Status = STATUS_SUCCESS;

        } else {

            break;
        }

    } while (TRUE);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialGetNextWrite\r\n");
}
BOOLEAN
SerialGiveImmediateToIsr(
    IN WDFINTERRUPT  Interrupt,
    IN PVOID         Context
    )
/*++

Routine Description:

    Try to start off the write by slipping it in behind
    a transmit immediate char, or if that isn't available
    and the transmit holding register is empty, "tickle"
    the UART into interrupting with a transmit buffer
    empty.

    NOTE: This routine is called by WdfInterruptSynchronize.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/
{
    PSERIAL_DEVICE_EXTENSION Extension = Context;
    PREQUEST_CONTEXT         reqContext;

    UNREFERENCED_PARAMETER(Interrupt);

    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);

    Extension->TransmitImmediate = TRUE;
    Extension->ImmediateChar =  *((UCHAR *) (reqContext->SystemBuffer));

    //
    // The isr now has a reference to the request.
    //

    SERIAL_SET_REFERENCE(
        reqContext,
        SERIAL_REF_ISR
        );

    //
    // Check first to see if a write is going on.  If
    // there is then we'll just slip in during the write.
    //

    if (!Extension->WriteLength) {

        //
        // If there is no normal write transmitting then we
        // will "re-enable" the transmit holding register empty
        // interrupt.  The 8250 family of devices will always
        // signal a transmit holding register empty interrupt
        // *ANY* time this bit is set to one.  By doing things
        // this way we can simply use the normal interrupt code
        // to start off this write.
        //
        // We've been keeping track of whether the transmit holding
        // register is empty so it we only need to do this
        // if the register is empty.
        //

        if (Extension->HoldingEmpty) {
            DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);
            ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);

        }

    }

    return FALSE;

}
Beispiel #20
0
VOID
SerialRundownIrpRefs(
    IN WDFREQUEST *CurrentOpRequest,
    IN WDFTIMER IntervalTimer OPTIONAL,
    IN WDFTIMER TotalTimer OPTIONAL,
    IN PSERIAL_DEVICE_EXTENSION PDevExt,
    IN LONG RefType
    )

/*++

Routine Description:

    This routine runs through the various items that *could*
    have a reference to the current read/write.  It try's to remove
    the reason.  If it does succeed in removing the reason it
    will decrement the reference count on the request.

    NOTE: This routine assumes that it is called with the cancel
          spin lock held.

Arguments:

    CurrentOpRequest - Pointer to a pointer to current request for the
                   particular operation.

    IntervalTimer - Pointer to the interval timer for the operation.
                    NOTE: This could be null.

    TotalTimer - Pointer to the total timer for the operation.
                 NOTE: This could be null.

    PDevExt - Pointer to device extension

Return Value:

    None.

--*/


{
    PREQUEST_CONTEXT  reqContext;
    WDFREQUEST        request = *CurrentOpRequest;

    reqContext = SerialGetRequestContext(request);

    if(RefType == SERIAL_REF_CANCEL) {
        //
        // Caller is a cancel routine. So just clear the reference.
        //
        SERIAL_CLEAR_REFERENCE( reqContext,  SERIAL_REF_CANCEL );
        reqContext->CancelRoutine = NULL;

    } else {
        //
        // Try to clear the cancelable state.
        //
        SerialClearCancelRoutine(request, TRUE);
    }
    if (IntervalTimer) {

        //
        // Try to cancel the operations interval timer.  If the operation
        // returns true then the timer did have a reference to the
        // request.  Since we've canceled this timer that reference is
        // no longer valid and we can decrement the reference count.
        //
        // If the cancel returns false then this means either of two things:
        //
        // a) The timer has already fired.
        //
        // b) There never was an interval timer.
        //
        // In the case of "b" there is no need to decrement the reference
        // count since the "timer" never had a reference to it.
        //
        // In the case of "a", then the timer itself will be coming
        // along and decrement it's reference.  Note that the caller
        // of this routine might actually be the this timer, so
        // decrement the reference.
        //

        if (SerialCancelTimer(IntervalTimer, PDevExt)) {

            SERIAL_CLEAR_REFERENCE(
                reqContext,
                SERIAL_REF_INT_TIMER
                );

        } else if(RefType == SERIAL_REF_INT_TIMER) { // caller is the timer

            SERIAL_CLEAR_REFERENCE(
                reqContext,
                SERIAL_REF_INT_TIMER
                );
        }

    }

    if (TotalTimer) {

        //
        // Try to cancel the operations total timer.  If the operation
        // returns true then the timer did have a reference to the
        // request.  Since we've canceled this timer that reference is
        // no longer valid and we can decrement the reference count.
        //
        // If the cancel returns false then this means either of two things:
        //
        // a) The timer has already fired.
        //
        // b) There never was an total timer.
        //
        // In the case of "b" there is no need to decrement the reference
        // count since the "timer" never had a reference to it.
        //
        // In the case of "a", then the timer itself will be coming
        // along and decrement it's reference.  Note that the caller
        // of this routine might actually be the this timer, so
        // decrement the reference.
        //

        if (SerialCancelTimer(TotalTimer, PDevExt)) {

            SERIAL_CLEAR_REFERENCE(
                reqContext,
                SERIAL_REF_TOTAL_TIMER
                );

        } else if(RefType == SERIAL_REF_TOTAL_TIMER) { // caller is the timer

            SERIAL_CLEAR_REFERENCE(
                reqContext,
                SERIAL_REF_TOTAL_TIMER
                );
        }
    }
}
VOID
SerialStartImmediate(
    IN PSERIAL_DEVICE_EXTENSION Extension
    )

/*++

Routine Description:

    This routine will calculate the timeouts needed for the
    write.  It will then hand the request off to the isr.  It
    will need to be careful incase the request has been canceled.

Arguments:

    Extension - A pointer to the serial device extension.

Return Value:

    None.

--*/

{
    LARGE_INTEGER TotalTime = {0};
    BOOLEAN UseATimer;
    SERIAL_TIMEOUTS Timeouts;
    PREQUEST_CONTEXT reqContext;

    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);

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

    UseATimer = FALSE;
    reqContext->Status = STATUS_PENDING;

    //
    // Calculate the timeout value needed for the
    // request.  Note that the values stored in the
    // timeout record are in milliseconds.  Note that
    // if the timeout values are zero then we won't start
    // the timer.
    //

    Timeouts = Extension->Timeouts;

    if (Timeouts.WriteTotalTimeoutConstant ||
        Timeouts.WriteTotalTimeoutMultiplier) {

        UseATimer = TRUE;

        //
        // We have some timer values to calculate.
        //

        TotalTime.QuadPart
           = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);

        TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;

        TotalTime.QuadPart *= -10000;

    }

    //
    // As the request might be going to the isr, this is a good time
    // to initialize the reference count.
    //

    SERIAL_INIT_REFERENCE(reqContext);

     //
     // We give the request to to the isr to write out.
     // We set a cancel routine that knows how to
     // grab the current write away from the isr.
     //
    SerialSetCancelRoutine(Extension->CurrentImmediateRequest,
                                    SerialCancelImmediate);

    if (UseATimer) {
        BOOLEAN result;

        result = SerialSetTimer(
            Extension->ImmediateTotalTimer,
            TotalTime
            );

        if(result == FALSE) {
            //
            // Since the timer knows about the request we increment
            // the reference count.
            //

            SERIAL_SET_REFERENCE(
                reqContext,
                SERIAL_REF_TOTAL_TIMER
                );
        }
    }

    WdfInterruptSynchronize(
        Extension->WdfInterrupt,
        SerialGiveImmediateToIsr,
        Extension
        );


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

}
Beispiel #22
0
VOID
SerialEvtCanceledOnQueue(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request
    )

/*++

Routine Description:

    Called when the request is cancelled while it's waiting
    on the queue. This callback is used instead of EvtCleanupCallback
    on the request because this one will be called with the
    presentation lock held.


Arguments:

    Queue - Queue in which the request currently waiting
    Request - Request being cancelled


Return Value:

    None.

--*/

{
    PSERIAL_DEVICE_EXTENSION extension = NULL;
    PREQUEST_CONTEXT reqContext;

    UNREFERENCED_PARAMETER(Queue);

    reqContext = SerialGetRequestContext(Request);

    extension = reqContext->Extension;

    //
    // If this is a write request then take the amount of characters
    // to write and subtract it from the count of characters to write.
    //

    if (reqContext->MajorFunction == IRP_MJ_WRITE) {

        extension->TotalCharsQueued -= reqContext->Length;

    } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

        //
        // If it's an immediate then we need to decrement the
        // count of chars queued.  If it's a resize then we
        // need to deallocate the pool that we're passing on
        // to the "resizing" routine.
        //

        if (( reqContext->IoctlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) ||
            (reqContext->IoctlCode ==  IOCTL_SERIAL_XOFF_COUNTER)) {

            extension->TotalCharsQueued--;

        } else if (reqContext->IoctlCode ==  IOCTL_SERIAL_SET_QUEUE_SIZE) {

            //
            // We shoved the pointer to the memory into the
            // the type 3 buffer pointer which we KNOW we
            // never use.
            //

            ASSERT(reqContext->Type3InputBuffer);

            ExFreePool(reqContext->Type3InputBuffer);

            reqContext->Type3InputBuffer = NULL;

        }

    }

    SerialCompleteRequest(Request, WdfRequestGetStatus(Request), 0);
}
Beispiel #23
0
/*++

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;
}