mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
Patch by Anton Yarotsky:
[CPORTLIB]: Implement Windows' Cp (ComPort) library. See Notes in C file. Not yet used. Based on MS Whitepaper: Building Hardware and Firmware to Complement Microsoft Windows Headless Operation. svn path=/trunk/; revision=48727
This commit is contained in:
parent
228af0c797
commit
c27087c0e6
5 changed files with 420 additions and 0 deletions
108
reactos/include/reactos/drivers/serial/ns16550.h
Normal file
108
reactos/include/reactos/drivers/serial/ns16550.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* PROJECT: ReactOS ComPort Library
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: include/reactos/drivers/serial/ns16550.h
|
||||
* PURPOSE: Header for National Semiconductor 16550 UART
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Note: These definitions are the internal definitions used by Microsoft serial
|
||||
driver (see src/kernel/serial.h in Windows sources). Linux uses its own, as
|
||||
do most other OS.
|
||||
*/
|
||||
|
||||
#if !defined(SERIAL_REGISTER_STRIDE)
|
||||
#define SERIAL_REGISTER_STRIDE 1
|
||||
#endif
|
||||
|
||||
#define RECEIVE_BUFFER_REGISTER ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))
|
||||
#define TRANSMIT_HOLDING_REGISTER ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))
|
||||
#define INTERRUPT_ENABLE_REGISTER ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE))
|
||||
#define INTERRUPT_IDENT_REGISTER ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE))
|
||||
#define FIFO_CONTROL_REGISTER ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE))
|
||||
#define LINE_CONTROL_REGISTER ((ULONG)((0x03)*SERIAL_REGISTER_STRIDE))
|
||||
#define MODEM_CONTROL_REGISTER ((ULONG)((0x04)*SERIAL_REGISTER_STRIDE))
|
||||
#define LINE_STATUS_REGISTER ((ULONG)((0x05)*SERIAL_REGISTER_STRIDE))
|
||||
#define MODEM_STATUS_REGISTER ((ULONG)((0x06)*SERIAL_REGISTER_STRIDE))
|
||||
#define DIVISOR_LATCH_LSB ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))
|
||||
#define DIVISOR_LATCH_MSB ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE))
|
||||
#define SERIAL_REGISTER_SPAN ((ULONG)(7*SERIAL_REGISTER_STRIDE))
|
||||
#define SERIAL_STATUS_LENGTH ((ULONG)(1*SERIAL_REGISTER_STRIDE))
|
||||
|
||||
#define SERIAL_DATA_LENGTH_5 0x00
|
||||
#define SERIAL_DATA_LENGTH_6 0x01
|
||||
#define SERIAL_DATA_LENGTH_7 0x02
|
||||
#define SERIAL_DATA_LENGTH_8 0x03
|
||||
|
||||
#define SERIAL_IER_RDA 0x01
|
||||
#define SERIAL_IER_THR 0x02
|
||||
#define SERIAL_IER_RLS 0x04
|
||||
#define SERIAL_IER_MS 0x08
|
||||
|
||||
#define SERIAL_IIR_RLS 0x06
|
||||
#define SERIAL_IIR_RDA 0x04
|
||||
#define SERIAL_IIR_CTI 0x0c
|
||||
#define SERIAL_IIR_THR 0x02
|
||||
#define SERIAL_IIR_MS 0x00
|
||||
#define SERIAL_IIR_FIFOS_ENABLED 0xc0
|
||||
#define SERIAL_IIR_NO_INTERRUPT_PENDING 0x01
|
||||
#define SERIAL_IIR_MUST_BE_ZERO 0x30
|
||||
|
||||
#define SERIAL_FCR_ENABLE ((UCHAR)0x01)
|
||||
#define SERIAL_FCR_RCVR_RESET ((UCHAR)0x02)
|
||||
#define SERIAL_FCR_TXMT_RESET ((UCHAR)0x04)
|
||||
|
||||
#define SERIAL_1_BYTE_HIGH_WATER ((UCHAR)0x00)
|
||||
#define SERIAL_4_BYTE_HIGH_WATER ((UCHAR)0x40)
|
||||
#define SERIAL_8_BYTE_HIGH_WATER ((UCHAR)0x80)
|
||||
#define SERIAL_14_BYTE_HIGH_WATER ((UCHAR)0xc0)
|
||||
|
||||
#define SERIAL_LCR_DLAB 0x80
|
||||
#define SERIAL_LCR_BREAK 0x40
|
||||
|
||||
#define SERIAL_5_DATA ((UCHAR)0x00)
|
||||
#define SERIAL_6_DATA ((UCHAR)0x01)
|
||||
#define SERIAL_7_DATA ((UCHAR)0x02)
|
||||
#define SERIAL_8_DATA ((UCHAR)0x03)
|
||||
#define SERIAL_DATA_MASK ((UCHAR)0x03)
|
||||
|
||||
#define SERIAL_1_STOP ((UCHAR)0x00)
|
||||
#define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits
|
||||
#define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits
|
||||
#define SERIAL_STOP_MASK ((UCHAR)0x04)
|
||||
|
||||
#define SERIAL_NONE_PARITY ((UCHAR)0x00)
|
||||
#define SERIAL_ODD_PARITY ((UCHAR)0x08)
|
||||
#define SERIAL_EVEN_PARITY ((UCHAR)0x18)
|
||||
#define SERIAL_MARK_PARITY ((UCHAR)0x28)
|
||||
#define SERIAL_SPACE_PARITY ((UCHAR)0x38)
|
||||
#define SERIAL_PARITY_MASK ((UCHAR)0x38)
|
||||
|
||||
#define SERIAL_MCR_DTR 0x01
|
||||
#define SERIAL_MCR_RTS 0x02
|
||||
#define SERIAL_MCR_OUT1 0x04
|
||||
#define SERIAL_MCR_OUT2 0x08
|
||||
#define SERIAL_MCR_LOOP 0x10
|
||||
#define SERIAL_MCR_TL16C550CAFE 0x20
|
||||
|
||||
#define SERIAL_LSR_DR 0x01
|
||||
#define SERIAL_LSR_OE 0x02
|
||||
#define SERIAL_LSR_PE 0x04
|
||||
#define SERIAL_LSR_FE 0x08
|
||||
#define SERIAL_LSR_BI 0x10
|
||||
#define SERIAL_LSR_THRE 0x20
|
||||
#define SERIAL_LSR_TEMT 0x40
|
||||
#define SERIAL_LSR_FIFOERR 0x80
|
||||
|
||||
#define SERIAL_MSR_DCTS 0x01
|
||||
#define SERIAL_MSR_DDSR 0x02
|
||||
#define SERIAL_MSR_TERI 0x04
|
||||
#define SERIAL_MSR_DDCD 0x08
|
||||
#define SERIAL_MSR_CTS 0x10
|
||||
#define SERIAL_MSR_DSR 0x20
|
||||
#define SERIAL_MSR_RI 0x40
|
||||
#define SERIAL_MSR_DCD 0x80
|
74
reactos/include/reactos/libs/cportlib/cportlib.h
Normal file
74
reactos/include/reactos/libs/cportlib/cportlib.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* PROJECT: ReactOS ComPort Library
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: include/reactos/lib/cportlib/cportlib.h
|
||||
* PURPOSE: Header for the ComPort Library
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntdef.h>
|
||||
|
||||
#define CP_GET_SUCCESS 0
|
||||
#define CP_GET_NODATA 1
|
||||
#define CP_GET_ERROR 2
|
||||
|
||||
#define CPPORT_FLAG_MODEM_CONTROL 0x02
|
||||
typedef struct _CPPORT
|
||||
{
|
||||
PUCHAR Address;
|
||||
ULONG Baud;
|
||||
USHORT Flags;
|
||||
} CPPORT, *PCPPORT;
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpInitialize(
|
||||
IN PCPPORT Port,
|
||||
IN PUCHAR Address,
|
||||
IN ULONG Rate
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpEnableFifo(
|
||||
IN PUCHAR Address,
|
||||
IN BOOLEAN Enable
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CpDoesPortExist(
|
||||
IN PUCHAR Address
|
||||
);
|
||||
|
||||
UCHAR
|
||||
NTAPI
|
||||
CpReadLsr(
|
||||
IN PCPPORT Port,
|
||||
IN UCHAR ExpectedValue
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpSetBaud(
|
||||
IN PCPPORT Port,
|
||||
IN ULONG Rate
|
||||
);
|
||||
|
||||
USHORT
|
||||
NTAPI
|
||||
CpGetByte(
|
||||
IN PCPPORT Port,
|
||||
IN PUCHAR Byte,
|
||||
IN BOOLEAN Wait,
|
||||
IN BOOLEAN Poll
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpPutByte(
|
||||
IN PCPPORT Port,
|
||||
IN UCHAR Byte
|
||||
);
|
227
reactos/lib/cportlib/cport.c
Normal file
227
reactos/lib/cportlib/cport.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* PROJECT: ReactOS ComPort Library
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: lib/reactos/cportlib/cport.c
|
||||
* PURPOSE: Provides a serial port library for KDCOM, INIT, and FREELDR
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* NOTE: This library follows the precise serial port intialization steps documented
|
||||
* by Microsoft in some of their Server hardware guidance. Because they've clearly
|
||||
* documented their serial algorithms, we use the same ones to stay "compliant".
|
||||
* Do not change this code to "improve" it. It's done this way on purpose, at least on x86.
|
||||
* -- sir_richard
|
||||
*/
|
||||
|
||||
/* NOTE: This code is used by Headless Support (Ntoskrnl.exe and Osloader.exe) and
|
||||
Kdcom.dll in Windows. It may be that WinDBG depends on some of these quirks.
|
||||
*/
|
||||
|
||||
/* NOTE: The original code supports Modem Control. We currently do not */
|
||||
|
||||
/* FIXMEs:
|
||||
- Make this serial-port specific (NS16550 vs other serial port types)
|
||||
- Get x64 KDCOM, KDBG, FREELDR, and other current code to use this
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <cportlib/cportlib.h>
|
||||
#include <drivers/serial/ns16550.h>
|
||||
#include <intrin.h>
|
||||
#include <ioaccess.h>
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
UCHAR RingIndicator;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpInitialize(IN PCPPORT Port,
|
||||
IN PUCHAR Address,
|
||||
IN ULONG Rate)
|
||||
{
|
||||
/* Reset port data */
|
||||
Port->Address = Address;
|
||||
Port->Baud = 0;
|
||||
|
||||
/* Set the baud rate */
|
||||
CpSetBaud(Port, Rate);
|
||||
|
||||
/* Enable on DTR and RTS */
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
|
||||
SERIAL_MCR_DTR | SERIAL_MCR_RTS);
|
||||
|
||||
/* Disable interrupts */
|
||||
WRITE_PORT_UCHAR(Address + INTERRUPT_ENABLE_REGISTER, 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpEnableFifo(IN PUCHAR Address,
|
||||
IN BOOLEAN Enable)
|
||||
{
|
||||
/* Set FIFO */
|
||||
WRITE_PORT_UCHAR(Address + FIFO_CONTROL_REGISTER, Enable ? SERIAL_FCR_ENABLE : 0);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CpDoesPortExist(IN PUCHAR Address)
|
||||
{
|
||||
UCHAR Old;
|
||||
/*
|
||||
* See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation"
|
||||
* Out-of-Band Management Port Device Requirements:
|
||||
* The device must act as a 16550 or 16450 UART.
|
||||
* Windows Server 2003 will test this device using the following process.
|
||||
* 1. Save off the current modem status register.
|
||||
* 2. Place the UART into diagnostic mode (The UART is placed into loopback mode
|
||||
* by writing SERIAL_MCR_LOOP to the modem control register).
|
||||
* 3. The modem status register is read and the high bits are checked. This means
|
||||
* SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI and SERIAL_MSR_DCD should
|
||||
* all be clear.
|
||||
* 4. Place the UART in diagnostic mode and turn on OUTPUT (Loopback Mode and
|
||||
* OUTPUT are both turned on by writing (SERIAL_MCR_LOOP | SERIAL_MCR_OUT1)
|
||||
* to the modem control register).
|
||||
* 5. The modem status register is read and the ring indicator is checked.
|
||||
* This means SERIAL_MSR_RI should be set.
|
||||
* 6. Restore original modem status register.
|
||||
*/
|
||||
Old = READ_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER);
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP);
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP);
|
||||
if (!(READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) &
|
||||
(SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD)))
|
||||
{
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
|
||||
(SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP));
|
||||
if (READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) & SERIAL_MSR_RI)
|
||||
{
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
NTAPI
|
||||
CpReadLsr(IN PCPPORT Port,
|
||||
IN UCHAR ExpectedValue)
|
||||
{
|
||||
UCHAR Lsr, Msr;
|
||||
|
||||
/* Read the LSR and check if the expected value is present */
|
||||
Lsr = READ_PORT_UCHAR(Port->Address + LINE_STATUS_REGISTER);
|
||||
if (!(Lsr & ExpectedValue))
|
||||
{
|
||||
/* Check the MSR for ring indicator toggle */
|
||||
Msr = READ_PORT_UCHAR(Port->Address + MODEM_STATUS_REGISTER);
|
||||
|
||||
/* If the indicator reaches 3, we've seen this on/off twice */
|
||||
RingIndicator |= (Msr & SERIAL_MSR_RI) ? 1 : 2;
|
||||
if (RingIndicator == 3) Port->Flags |= CPPORT_FLAG_MODEM_CONTROL;
|
||||
}
|
||||
|
||||
return Lsr;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpSetBaud(IN PCPPORT Port,
|
||||
IN ULONG Rate)
|
||||
{
|
||||
UCHAR Lcr;
|
||||
USHORT Mode;
|
||||
|
||||
/* Add DLAB */
|
||||
Lcr = READ_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER);
|
||||
WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, Lcr | SERIAL_LCR_DLAB);
|
||||
|
||||
/* Set baud rate */
|
||||
Mode = 115200 / Rate;
|
||||
WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_MSB, (UCHAR)((Mode >> 8) & 0xff));
|
||||
WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_LSB, (UCHAR)(Mode & 0xff));
|
||||
|
||||
/* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */
|
||||
WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER,
|
||||
SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
|
||||
|
||||
/* Save baud rate in port */
|
||||
Port->Baud = Rate;
|
||||
}
|
||||
|
||||
USHORT
|
||||
NTAPI
|
||||
CpGetByte(IN PCPPORT Port,
|
||||
IN PUCHAR Byte,
|
||||
IN BOOLEAN Wait,
|
||||
IN BOOLEAN Poll)
|
||||
{
|
||||
UCHAR Lsr;
|
||||
ULONG i;
|
||||
|
||||
/* Handle early read-before-init */
|
||||
if (!Port->Address) return CP_GET_NODATA;
|
||||
|
||||
/* If "wait" mode enabled, spin many times, otherwise attempt just once */
|
||||
i = Wait ? 204800 : 1;
|
||||
while (i--)
|
||||
{
|
||||
/* Read LSR for data ready */
|
||||
Lsr = CpReadLsr(Port, SERIAL_LSR_DR);
|
||||
if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
|
||||
{
|
||||
/* If an error happened, clear the byte and fail */
|
||||
if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE))
|
||||
{
|
||||
*Byte = 0;
|
||||
return CP_GET_ERROR;
|
||||
}
|
||||
|
||||
/* If only polling was requested by caller, return now */
|
||||
if (Poll) return CP_GET_SUCCESS;
|
||||
|
||||
/* Otherwise read the byte and return it */
|
||||
*Byte = READ_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER);
|
||||
|
||||
/* Handle CD if port is in modem control mode */
|
||||
if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL)
|
||||
{
|
||||
/* Not implemented yet */
|
||||
DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
|
||||
}
|
||||
|
||||
/* Byte was read */
|
||||
return CP_GET_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset LSR, no data was found */
|
||||
CpReadLsr(Port, 0);
|
||||
return CP_GET_NODATA;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CpPutByte(IN PCPPORT Port,
|
||||
IN UCHAR Byte)
|
||||
{
|
||||
/* Check if port is in modem control to handle CD */
|
||||
while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL)
|
||||
{
|
||||
/* Not implemented yet */
|
||||
DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
|
||||
}
|
||||
|
||||
/* Wait for LSR to say we can go ahead */
|
||||
while (!(CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE));
|
||||
|
||||
/* Send the byte */
|
||||
WRITE_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER, Byte);
|
||||
}
|
8
reactos/lib/cportlib/cportlib.rbuild
Normal file
8
reactos/lib/cportlib/cportlib.rbuild
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
|
||||
<group>
|
||||
<module name="cportlib" type="staticlibrary">
|
||||
<include base="cportlib">.</include>
|
||||
<file>cport.c</file>
|
||||
</module>
|
||||
</group>
|
|
@ -13,6 +13,9 @@
|
|||
<directory name="cmlib">
|
||||
<xi:include href="cmlib/cmlib.rbuild" />
|
||||
</directory>
|
||||
<directory name="cportlib">
|
||||
<xi:include href="cportlib/cportlib.rbuild" />
|
||||
</directory>
|
||||
<directory name="debugsup">
|
||||
<xi:include href="debugsup/debugsup.rbuild" />
|
||||
</directory>
|
||||
|
|
Loading…
Reference in a new issue