Beispiel #1
0
BOOLEAN
SerialSetLineControl(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine is used to set the buad rate of the device.

Arguments:

    Context - Pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;

    WRITE_LINE_CONTROL(
        Extension->Controller,
        Extension->LineControl
        );

    return FALSE;

}
Beispiel #2
0
BOOLEAN
SerialTurnOnBreak(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine will turn on break in the hardware and
    record the fact the break is on, in the extension variable
    that holds reasons that transmission is stopped.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;

    UCHAR OldLineControl;

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

        SerialSetRTS(Extension);

    }

    OldLineControl = READ_LINE_CONTROL(Extension->Controller);

    OldLineControl |= SERIAL_LCR_BREAK;

    WRITE_LINE_CONTROL(
        Extension->Controller,
        OldLineControl
        );

    Extension->TXHolding |= SERIAL_TX_BREAK;

    return FALSE;

}
Beispiel #3
0
///////////////////////////////////////////////////////////////////////////////
// Does           : Initializes the device.
// Parameters     : port           - Port of a 8250
//                  baudrate       - Baudrate to init 8250 to
//                  dataBits       - Number of data bits (5..8)
//                  stopBits       - Number of stop bits (1..2)
//                  parity         - 0 == NONE, 1 == ODD, 2 == EVEN
// Returns        : Status of the operation.
// Postcondition  : Ready to start interrupt processing when returning
//                  STATUS_SUCCESS.
///////////////////////////////////////////////////////////////////////////////
NTSTATUS Hw8250Init(PUCHAR port, ULONG baudRate, ULONG dataBits,
                        ULONG stopBits, ULONG parity)
{
    NTSTATUS result = STATUS_SUCCESS;
    ULONG divisor;
    UCHAR dataFormat;

    // disable all interrupts
    WRITE_INTERRUPT_ENABLE(port, 0x00);

    // set up baudrate
    divisor = Hw8550InternalGetDivisor(baudRate);
    WRITE_LINE_CONTROL(port, LCR_DLAB);
    WRITE_DIVISOR_LATCH(port, divisor);

    // set up data bits (defaults to 8 data bits)
    switch(dataBits) {
        case 5:
            dataFormat = LCR_DATA_5;
            break;

        case 6:
            dataFormat = LCR_DATA_6;
            break;

        case 7:
            dataFormat = LCR_DATA_7;
            break;

        case 8:
        default:
            dataFormat = LCR_DATA_8;
            break;
    }

    // set up stop bits (defaults to 1 stop bit)
    if(stopBits == 2) {
        dataFormat |= LCR_STOP_2;
    }
    else {
        dataFormat |= LCR_STOP_1;
    }

    // set up parity (defaults to none)
    switch(parity) {
        case 4:
            dataFormat |= LCR_PARITY_SPACE;
            break;
        
        case 3:
            dataFormat |= LCR_PARITY_MARK;
            break;
        
        case 2:
            dataFormat |= LCR_PARITY_EVEN;
            break;
        
        case 1:
            dataFormat |= LCR_PARITY_ODD;
            break;

        case 0:
        default:
            dataFormat |= LCR_PARITY_NONE;
            break;
    }

    WRITE_LINE_CONTROL(port, dataFormat);
    WRITE_MODEM_CONTROL(port, MCR_GPO1 | MCR_RTS | MCR_DTR);

    return result;

} // end Hw8250Init
NTSTATUS
SerialEvtDeviceD0Entry(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE PreviousState
    )
/*++

Routine Description:

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

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

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

Arguments:

    Device - Handle to a framework device object.

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

Return Value:

    NTSTATUS

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

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

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

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

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

    //
    // Set the baud rate
    //

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

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

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

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

    //
    // Restore a couple more registers
    //

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

    //
    // Clear out any stale interrupts
    //

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

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

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

       SetDeviceIsOpened(deviceExtension, TRUE, FALSE);

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

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

       //
       // Refire the state machine
       //

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

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

    return STATUS_SUCCESS;
}
Beispiel #5
0
BOOLEAN
SerialTurnOffBreak(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine will turn off break in the hardware and
    record the fact the break is off, in the extension variable
    that holds reasons that transmission is stopped.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;

    UCHAR OldLineControl;

    if (Extension->TXHolding & SERIAL_TX_BREAK) {

        //
        // We actually have a good reason for testing if transmission
        // is holding instead of blindly clearing the bit.
        //
        // If transmission actually was holding and the result of
        // clearing the bit is that we should restart transmission
        // then we will poke the interrupt enable bit, which will
        // cause an actual interrupt and transmission will then
        // restart on its own.
        //
        // If transmission wasn't holding and we poked the bit
        // then we would interrupt before a character actually made
        // it out and we could end up over writing a character in
        // the transmission hardware.

        OldLineControl = READ_LINE_CONTROL(Extension->Controller);

        OldLineControl &= ~SERIAL_LCR_BREAK;

        WRITE_LINE_CONTROL(
            Extension->Controller,
            OldLineControl
            );

        Extension->TXHolding &= ~SERIAL_TX_BREAK;

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

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

        } else {

            //
            // The following routine will lower the rts if we
            // are doing transmit toggleing and there is no
            // reason to keep it up.
            //

            Extension->CountOfTryingToLowerRTS++;
            SerialPerhapsLowerRTS(Extension);

        }

    }

    return FALSE;

}
Beispiel #6
0
//
// Internal Function: UartCtlSetLineControl
//
VOID
UartCtlSetLineControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR lineControlRegister = 0;
    PSERIAL_LINE_CONTROL pLineControl = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(SERIAL_LINE_CONTROL), 
                    (PVOID*)(& pLineControl), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        status = UartRegStructToLCR(pLineControl, &lineControlRegister);

        if (!NT_SUCCESS(status))
        {
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Failed to calculate LCR from SERIAL_LINE_CONTROL %p  - "
                "%!STATUS!",
                pLineControl,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        // Set line control, save break setting
        lineControlRegister = lineControlRegister | 
            (READ_LINE_CONTROL(pDevExt, pDevExt->Controller) & SERIAL_LCR_BREAK);
        WRITE_LINE_CONTROL(pDevExt, pDevExt->Controller, lineControlRegister);

        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}