示例#1
0
文件: write.c 项目: ms-iot/bsp
/*++

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

}
示例#3
0
文件: write.c 项目: ms-iot/bsp
/*++

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