|
|
/*++
Copyright (c) 1993 Microsoft Corporation Copyright (c) 1993 Logitech Inc.
Module Name:
uart.c
Abstract:
Environment:
Kernel mode only.
Notes:
Revision History:
--*/
#include "ntddk.h"
#include "uart.h"
#include "sermouse.h"
#include "debug.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,UARTSetFifo)
#pragma alloc_text(INIT,UARTGetInterruptCtrl)
#pragma alloc_text(INIT,UARTSetInterruptCtrl)
#pragma alloc_text(INIT,UARTGetLineCtrl)
#pragma alloc_text(INIT,UARTSetLineCtrl)
#pragma alloc_text(INIT,UARTGetModemCtrl)
#pragma alloc_text(INIT,UARTSetModemCtrl)
#pragma alloc_text(INIT,UARTSetDlab)
#pragma alloc_text(INIT,UARTGetBaudRate)
#pragma alloc_text(INIT,UARTSetBaudRate)
#pragma alloc_text(INIT,UARTGetState)
#pragma alloc_text(INIT,UARTSetState)
#pragma alloc_text(INIT,UARTReadChar)
#pragma alloc_text(INIT,UARTIsTransmitEmpty)
#pragma alloc_text(INIT,UARTWriteChar)
#pragma alloc_text(INIT,UARTWriteString)
#endif // ALLOC_PRAGMA
//
// Constants
//
VOID UARTSetFifo( PUCHAR Port, UCHAR Value ) /*++
Routine Description:
Set the FIFO register.
Arguments:
Port - Pointer to the serial port.
Value - The FIFO control mask.
Return Value:
None.
--*/ { WRITE_PORT_UCHAR(Port + ACE_IIDR, Value); } UCHAR UARTGetInterruptCtrl( PUCHAR Port ) /*++
Routine Description:
Get the serial port interrupt control register.
Arguments:
Port - Pointer to the serial port.
Return Value:
Serial port interrupt control register value.
--*/ { return READ_PORT_UCHAR(Port + ACE_IER); }
UCHAR UARTSetInterruptCtrl( PUCHAR Port, UCHAR Value ) /*++
Routine Description:
Set the interrupt control register.
Arguments:
Port - Pointer to the serial port.
Value - The interrupt control mask.
Return Value:
Previous interrupt control value.
--*/ { UCHAR oldValue = UARTGetInterruptCtrl(Port); WRITE_PORT_UCHAR(Port + ACE_IER, Value);
return oldValue; }
UCHAR UARTGetLineCtrl( PUCHAR Port ) /*++
Routine Description:
Get the serial port line control register.
Arguments:
Port - Pointer to the serial port.
Return Value:
Serial port line control value.
--*/ { return READ_PORT_UCHAR(Port + ACE_LCR); }
UCHAR UARTSetLineCtrl( PUCHAR Port, UCHAR Value ) /*++
Routine Description:
Set the serial port line control register.
Arguments:
Port - Pointer to the serial port.
Value - New line control value.
Return Value:
Previous serial line control register value.
--*/ { UCHAR oldValue = UARTGetLineCtrl(Port); WRITE_PORT_UCHAR(Port + ACE_LCR, Value);
return oldValue; }
UCHAR UARTGetModemCtrl( PUCHAR Port ) /*++
Routine Description:
Get the serial port modem control register.
Arguments:
Port - Pointer to the serial port.
Return Value:
Serial port modem control register value.
--*/ { return READ_PORT_UCHAR(Port + ACE_MCR); }
UCHAR UARTSetModemCtrl( PUCHAR Port, UCHAR Value ) /*++
Routine Description:
Set the serial port modem control register.
Arguments:
Port - Pointer to the serial port.
Return Value:
Previous modem control register value.
--*/ {
UCHAR oldValue = UARTGetModemCtrl(Port); WRITE_PORT_UCHAR(Port + ACE_MCR, Value);
return oldValue; }
BOOLEAN UARTSetDlab( PUCHAR Port, BOOLEAN Set ) /*++
Routine Description:
Set/reset the baud rate access bit.
Arguments:
Port - Pointer to the serial port.
Set - Set or Reset (TRUE/FALSE) the baud rate access bit.
Return Value:
The previous baud rate access bit setting.
--*/ { UCHAR lineControl = UARTGetLineCtrl(Port); UCHAR newLineControl = Set ? lineControl | ACE_DLAB : lineControl & ~ACE_DLAB;
WRITE_PORT_UCHAR(Port + ACE_LCR, newLineControl);
return lineControl & ACE_DLAB; }
ULONG UARTGetBaudRate( PUCHAR Port, ULONG BaudClock ) /*++
Routine Description:
Get the serial port baud rate setting.
Arguments:
Port - Pointer to the serial port.
BaudClock - The external frequency driving the serial chip.
Return Value:
Serial port baud rate.
--*/ { USHORT baudRateDivisor; ULONG baudRateFactor = BaudClock/BAUD_GENERATOR_DIVISOR;
//
// Set the baud rate access bit.
//
UARTSetDlab(Port, TRUE);
//
// Read the baud rate factor.
//
baudRateDivisor = READ_PORT_UCHAR(Port + ACE_DLL); baudRateDivisor |= READ_PORT_UCHAR(Port + ACE_DLM) << 8;
//
// Reset the baud rate bit for normal data access.
//
UARTSetDlab(Port, FALSE);
//
// Make sure the divisor is not zero.
//
if (baudRateDivisor == 0) { baudRateDivisor = 1; }
return baudRateFactor / baudRateDivisor; }
VOID UARTSetBaudRate( PUCHAR Port, ULONG BaudRate, ULONG BaudClock ) /*++
Routine Description:
Set the serial port baud rate.
Arguments:
Port - Pointer to the serial port.
BaudRate - New serial port baud rate.
BaudClock - The external frequency driving the serial chip.
Return Value:
None.
--*/ { ULONG baudRateFactor = BaudClock/BAUD_GENERATOR_DIVISOR; USHORT baudRateDivisor;
SerMouPrint((2, "SERMOUSE-SetBaudRate: Enter\n"));
baudRateDivisor = (USHORT) (baudRateFactor / BaudRate); UARTSetDlab(Port, TRUE); WRITE_PORT_UCHAR(Port + ACE_DLL, (UCHAR)baudRateDivisor); WRITE_PORT_UCHAR(Port + ACE_DLM, (UCHAR)(baudRateDivisor >> 8)); UARTSetDlab(Port, FALSE); SerMouPrint((2, "SERMOUSE-New BaudRate: %u\n", BaudRate));
SerMouPrint((2, "SERMOUSE-SetBaudRate: Exit\n"));
return; }
VOID UARTGetState( PUCHAR Port, PUART Uart, ULONG BaudClock ) /*++
Routine Description:
Get the complete state of the serial port. May be used for save/restore.
Arguments:
Port - Pointer to the serial port.
Uart - Pointer to a serial port structure.
BaudClock - The external frequency driving the serial chip.
Return Value:
None.
--*/ { Uart->LineCtrl = UARTGetLineCtrl(Port); Uart->ModemCtrl = UARTGetModemCtrl(Port); Uart->InterruptCtrl = UARTGetInterruptCtrl(Port); Uart->BaudRate = UARTGetBaudRate(Port, BaudClock);
return; }
VOID UARTSetState( PUCHAR Port, PUART Uart, ULONG BaudClock ) /*++
Routine Description:
Set the complete state of a serial port.
Arguments:
Port - Pointer to the serial port.
Uart - Pointer to a serial port structure.
BaudClock - The external frequency driving the serial chip.
Return Value:
None.
--*/ { UARTSetLineCtrl(Port, Uart->LineCtrl); UARTSetModemCtrl(Port, Uart->ModemCtrl); UARTSetInterruptCtrl(Port, Uart->InterruptCtrl); UARTSetBaudRate(Port, Uart->BaudRate, BaudClock);
return; }
BOOLEAN UARTIsReceiveBufferFull( PUCHAR Port ) /*++
Routine Description:
Check whether the serial port input buffer is full.
Arguments:
Port - Pointer to the serial port.
Return Value:
TRUE if a character is present in the input buffer, otherwise FALSE.
--*/ { return READ_PORT_UCHAR(Port + ACE_LSR) & ACE_DR; }
BOOLEAN UARTReadCharNoWait( PUCHAR Port, PUCHAR Value ) /*++
Routine Description:
Read a character from the serial port and return immediately.
Arguments:
Port - Pointer to the serial port.
Value - The character read from the serial port input buffer.
Return Value:
TRUE if character has been read, FALSE otherwise.
--*/ { BOOLEAN charReady = FALSE;
if ( UARTIsReceiveBufferFull(Port) ) { *Value = READ_PORT_UCHAR(Port + ACE_RBR); charReady = TRUE; }
return charReady; }
BOOLEAN UARTReadChar( PUCHAR Port, PUCHAR Value, ULONG Timeout ) /*++
Routine Description:
Read a character from the serial port. Waits until a character has been read or the timeout value is reached.
Arguments:
Port - Pointer to the serial port.
Value - The character read from the serial port input buffer.
Timeout - The timeout value in milliseconds for the read.
Return Value:
TRUE if a character has been read, FALSE if a timeout occured.
--*/ {
ULONG i, j; BOOLEAN returnValue = FALSE;
//
// Exit when a character is found or the timeout value is reached.
//
for (i = 0; i < Timeout; i++) { for (j = 0; j < MS_TO_MICROSECONDS; j++) { if ((returnValue = UARTReadCharNoWait(Port, Value)) == TRUE) { //
// Got a character.
//
break; } else { //
// Stall 1 microsecond and then try to read again.
//
KeStallExecutionProcessor(1); } } if (returnValue) { break; } }
return(returnValue); }
BOOLEAN UARTFlushReadBuffer( PUCHAR Port ) /*++
Routine Description:
Flush the serial port input buffer.
Arguments:
Port - Pointer to the serial port.
Return Value:
TRUE.
--*/ { UCHAR value;
SerMouPrint((4, "SERMOUSE-UARTFlushReadBuffer: Enter\n")); while (UARTReadCharNoWait(Port, &value)) { /* Nothing */ } SerMouPrint((4, "SERMOUSE-UARTFlushReadBuffer: Exit\n"));
return TRUE; }
BOOLEAN UARTIsTransmitEmpty( PUCHAR Port ) /*++
Routine Description:
Check whether the serial port transmit buffer is empty.
Note: We also check whether the shift register is empty. This is not critical in our case, but allows some more delay between characters sent to a device. (Safe, safe...)
Arguments:
Port - Pointer to the serial port.
Return Value:
TRUE if the serial port transmit buffer is empty.
--*/ { return ((READ_PORT_UCHAR((PUCHAR) (Port + ACE_LSR)) & (ACE_TSRE | ACE_THRE)) == (ACE_THRE | ACE_TSRE)); }
BOOLEAN UARTWriteChar( PUCHAR Port, UCHAR Value ) /*++
Routine Description:
Write a character to a serial port. Make sure the transmit buffer is empty before we write there.
Arguments:
Port - Pointer to the serial port.
Value - Value to write to the serial port.
Return Value:
TRUE.
--*/ { while (!UARTIsTransmitEmpty(Port)) { /* Nothing */ } WRITE_PORT_UCHAR(Port + ACE_THR, Value);
return TRUE; }
BOOLEAN UARTWriteString( PUCHAR Port, PSZ Buffer ) /*++
Routine Description:
Write a zero-terminated string to the serial port.
Arguments:
Port - Pointer to the serial port.
Buffer - Pointer to a zero terminated string to write to the serial port.
Return Value:
TRUE.
--*/ { PSZ current = Buffer;
while (*current) { UARTWriteChar(Port, *current++); }
return TRUE; }
|