Ejemplo n.º 1
0
BOOLEAN
SerialMarkOpen(
    IN WDFINTERRUPT  Interrupt,
    IN PVOID Context
    )

/*++

Routine Description:

    This routine merely sets a boolean to true to mark the fact that
    somebody opened the device and its worthwhile to pay attention
    to interrupts.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION extension = Context;

    UNREFERENCED_PARAMETER(Interrupt);

    SerialReset(extension->WdfInterrupt, extension);

    //
    // Prepare for the opening by re-enabling interrupts.
    //
    // We do this my modifying the OUT2 line in the modem control.
    // In PC's this bit is "anded" with the interrupt line.
    //

    WRITE_MODEM_CONTROL(extension,
        extension->Controller,
        (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller) | SERIAL_MCR_OUT2)
        );

    extension->DeviceIsOpened = TRUE;
    extension->ErrorWord = 0;

    return FALSE;

}
Ejemplo n.º 2
0
//
// Internal Function: UartCtlClrRts
//
VOID
UartCtlClrRts(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR regModemControl;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    if (((pDevExt->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        SERIAL_RTS_HANDSHAKE) ||
        ((pDevExt->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        SERIAL_TRANSMIT_TOGGLE))
    {
        status = STATUS_INVALID_PARAMETER;
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "RTS cannot be cleared when automatic RTS flow control or "
            "transmit toggling is used - %!STATUS!",
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and sets the MCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller);
        regModemControl &= ~SERIAL_MCR_RTS;
        WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, regModemControl);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

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

    FuncExit(TRACE_FLAG_CONTROL);
}
Ejemplo n.º 3
0
//
// Internal Function: UartCtlSetModemControl
//
VOID
UartCtlSetModemControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PULONG pBuffer;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(ULONG), 
                    (PVOID*)(&pBuffer), 
                    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))
    {
        // Acquires the interrupt lock and writes the modem control register.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)*pBuffer);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

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

    FuncExit(TRACE_FLAG_CONTROL);
}
Ejemplo n.º 4
0
//
// Internal Function: UartCtlSetDtr
//
VOID
UartCtlSetDtr(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR regModemControl;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    if ((pDevExt->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
        SERIAL_DTR_HANDSHAKE)
    {
        status = STATUS_INVALID_PARAMETER;
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "DTR cannot be set when automatic DTR flow control is used - "
            "%!STATUS!",
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and sets the MCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller);
        regModemControl |= SERIAL_MCR_DTR;
        WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, regModemControl);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

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

    FuncExit(TRACE_FLAG_CONTROL);
}
Ejemplo n.º 5
0
BOOLEAN
SerialSetDTR(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to set the DTR in the modem control register.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION Extension = Context;
    UCHAR ModemControl;

    ModemControl = READ_MODEM_CONTROL(Extension->Controller);

    ModemControl |= SERIAL_MCR_DTR;

    SerialDump(
        SERFLOW,
        ("SERIAL: Setting DTR for %x\n",
         Extension->Controller)
        );
    WRITE_MODEM_CONTROL(
        Extension->Controller,
        ModemControl
        );

    return FALSE;

}
Ejemplo n.º 6
0
VOID
SerialDisableUART(IN PVOID Context)

/*++

Routine Description:

    This routine disables the UART and puts it in a "safe" state when
    not in use (like a close or powerdown).

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{
   PSERIAL_DEVICE_EXTENSION extension = Context;

   //
   // Prepare for the closing by stopping interrupts.
   //
   // We do this by adjusting the OUT2 line in the modem control.
   // In PC's this bit is "anded" with the interrupt line.
   //

   WRITE_MODEM_CONTROL(extension, extension->Controller,
                       (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller)
                               & ~SERIAL_MCR_OUT2));

   if (extension->FifoPresent) {
      WRITE_FIFO_CONTROL(extension, extension->Controller, (UCHAR)0);
    }
}
Ejemplo n.º 7
0
Archivo: Hw8250.c Proyecto: uri247/kmdf
///////////////////////////////////////////////////////////////////////////////
// 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
Ejemplo n.º 8
0
NTSTATUS
SerialEvtDeviceD0Entry(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE PreviousState
    )
/*++

Routine Description:

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

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

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

Arguments:

    Device - Handle to a framework device object.

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

Return Value:

    NTSTATUS

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

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

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

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

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

    //
    // Set the baud rate
    //

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

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

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

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

    //
    // Restore a couple more registers
    //

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

    //
    // Clear out any stale interrupts
    //

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

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

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

       SetDeviceIsOpened(deviceExtension, TRUE, FALSE);

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

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

       //
       // Refire the state machine
       //

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

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

    return STATUS_SUCCESS;
}