ReactOS 0.4.16-dev-2473-gb34a1f1
ns16550.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ComPort Library
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: National Semiconductor 16550 UART
5 * COPYRIGHT: Copyright 2010 ReactOS Portable Systems Group
6 * Copyright 2012-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
7 *
8 * NOTE: This library follows the precise serial port intialization steps documented
9 * by Microsoft in some of their Server hardware guidance. Because they have clearly
10 * documented their serial algorithms, we use the same ones to stay "compliant".
11 * Do not change this code to "improve" it. It's done this way on purpose, at least on x86.
12 * -- sir_richard
13 *
14 * REPLY: I reworked the COM-port testing code because the original one
15 * (i.e. the Microsoft's documented one) doesn't work on Virtual PC 2007.
16 * -- hbelusca
17 *
18 * NOTE: The original code supports Modem Control. We currently do not.
19 */
20
21/* INCLUDES *******************************************************************/
22
23#include <intrin.h>
24#include <ioaccess.h>
25#include <ntstatus.h>
26#include <cportlib/cportlib.h>
28
29/* GLOBALS ********************************************************************/
30
31/* Wait timeout value */
32#define TIMEOUT_COUNT (1024 * 200)
33
35
36/* FUNCTIONS ******************************************************************/
37
38static BOOLEAN
41{
42 /*
43 * See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation"
44 * Out-of-Band Management Port Device Requirements:
45 * The device must act as a 16550 or 16450 UART.
46 * Windows Server 2003 will test this device using the following process:
47 * 1. Save off the current modem status register.
48 * 2. Place the UART into diagnostic mode (The UART is placed into loopback mode
49 * by writing SERIAL_MCR_LOOP to the modem control register).
50 * 3. The modem status register is read and the high bits are checked. This means
51 * SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI and SERIAL_MSR_DCD should
52 * all be clear.
53 * 4. Place the UART in diagnostic mode and turn on OUTPUT (Loopback Mode and
54 * OUTPUT are both turned on by writing (SERIAL_MCR_LOOP | SERIAL_MCR_OUT1)
55 * to the modem control register).
56 * 5. The modem status register is read and the ring indicator is checked.
57 * This means SERIAL_MSR_RI should be set.
58 * 6. Restore original modem status register.
59 *
60 * REMARK: Strangely enough, the Virtual PC 2007 virtual machine
61 * doesn't pass this test.
62 */
63
64 BOOLEAN RetVal = FALSE;
65 UCHAR Mcr, Msr;
66
67 /* Save the Modem Control Register */
69
70 /* Enable loop (diagnostic) mode (set Bit 4 of the MCR) */
72
73 /* Clear all modem output bits */
75
76 /* Read the Modem Status Register */
78
79 /*
80 * The upper nibble of the MSR (modem output bits) must be
81 * equal to the lower nibble of the MCR (modem input bits).
82 */
84 {
85 /* Set all modem output bits */
87 SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP); // Windows
88/* ReactOS
89 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
90 SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT1 | SERIAL_MCR_OUT2 | SERIAL_MCR_LOOP);
91*/
92
93 /* Read the Modem Status Register */
95
96 /*
97 * The upper nibble of the MSR (modem output bits) must be
98 * equal to the lower nibble of the MCR (modem input bits).
99 */
100 if (Msr & SERIAL_MSR_RI) // Windows
101 // if (Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD) == 0xF0) // ReactOS
102 {
103 RetVal = TRUE;
104 }
105 }
106
107 /* Restore the MCR */
109
110 return RetVal;
111}
112
113static BOOLEAN
116{
117 /*
118 * This test checks whether the 16450/16550 scratch register is available.
119 * If not, the serial port is considered as unexisting.
120 */
121
122 UCHAR Byte = 0;
123
124 do
125 {
127
129 return FALSE;
130
131 } while (++Byte != 0);
132
133 return TRUE;
134}
135
137NTAPI
140{
142}
143
144VOID
145NTAPI
149{
150 /* Set FIFO and clear the receive/transmit buffers */
154}
155
156VOID
157NTAPI
160 _In_ ULONG BaudRate)
161{
162 UCHAR Lcr;
163 ULONG Mode = CLOCK_RATE / BaudRate;
164
165 /* Set the DLAB on */
168
169 /* Set the baud rate */
172
173 /* Reset DLAB */
175
176 /* Save baud rate in port */
177 Port->BaudRate = BaudRate;
178}
179
181NTAPI
185 _In_ ULONG BaudRate)
186{
187 /* Validity checks */
188 if (Port == NULL || Address == NULL || BaudRate == 0)
190
192 return STATUS_NOT_FOUND;
193
194 /* Initialize port data */
196 Port->BaudRate = 0;
197 Port->Flags = 0;
198
199 /* Disable the interrupts */
202
203 /* Turn on DTR, RTS and OUT2 */
206
207 /* Set the baud rate */
208 Uart16550SetBaud(Port, BaudRate);
209
210 /* Set 8 data bits, 1 stop bit, no parity, no break */
213
214 /* Turn on FIFO */
215 // TODO: Check whether FIFO exists and turn it on in that case.
216 Uart16550EnableFifo(Address, TRUE); // for 16550
217
218 /* Read junk out of the RBR */
220
221 return STATUS_SUCCESS;
222}
223
224static UCHAR
225NTAPI
228 _In_ UCHAR ExpectedValue)
229{
230 UCHAR Lsr, Msr;
231
232 /* Read the LSR and check if the expected value is present */
234 if (!(Lsr & ExpectedValue))
235 {
236 /* Check the MSR for ring indicator toggle */
238
239 /* If the indicator reaches 3, we've seen this on/off twice */
240 RingIndicator |= (Msr & SERIAL_MSR_RI) ? 1 : 2;
241 if (RingIndicator == 3)
243 }
244
245 return Lsr;
246}
247
248USHORT
249NTAPI
254 _In_ BOOLEAN Poll)
255{
256 UCHAR Lsr;
257 ULONG LimitCount = Wait ? TIMEOUT_COUNT : 1;
258
259 /* Handle early read-before-init */
260 if (!Port->Address)
261 return CP_GET_NODATA;
262
263 /* If "wait" mode enabled, spin many times, otherwise attempt just once */
264 while (LimitCount--)
265 {
266 /* Read LSR for data ready */
268 if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
269 {
270 /* If an error happened, clear the byte and fail */
272 {
273 *Byte = 0;
274 return CP_GET_ERROR;
275 }
276
277 /* If only polling was requested by caller, return now */
278 if (Poll)
279 return CP_GET_SUCCESS;
280
281 /* Otherwise read the byte and return it */
283
284 /* Handle CD if port is in modem control mode */
286 {
287 /* Not implemented yet */
288 // DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
289 }
290
291 /* Byte was read */
292 return CP_GET_SUCCESS;
293 }
294 }
295
296 /* Reset LSR, no data was found */
298 return CP_GET_NODATA;
299}
300
301VOID
302NTAPI
306{
307 /* Check if port is in modem control to handle CD */
308 // while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // Commented for the moment.
309 if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // To be removed when this becomes implemented.
310 {
311 /* Not implemented yet */
312 // DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
313 }
314
315 /* Wait for LSR to say we can go ahead */
317 NOTHING;
318
319 /* Send the byte */
321}
322
323/* EOF */
#define VOID
Definition: acefi.h:82
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define CP_GET_SUCCESS
Definition: cportlib.h:17
#define CP_GET_NODATA
Definition: cportlib.h:18
#define CPPORT_FLAG_MODEM_CONTROL
Definition: cportlib.h:24
#define CP_GET_ERROR
Definition: cportlib.h:19
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned char Byte
Definition: zlib.h:37
CPPORT Port[4]
Definition: headless.c:38
_In_ ULONG Mode
Definition: hubbusif.h:303
#define NOTHING
Definition: input_list.c:10
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define TIMEOUT_COUNT
Definition: ns16550.c:32
VOID NTAPI Uart16550SetBaud(_Inout_ PCPPORT Port, _In_ ULONG BaudRate)
Definition: ns16550.c:158
USHORT NTAPI Uart16550GetByte(_Inout_ PCPPORT Port, _Out_ PUCHAR Byte, _In_ BOOLEAN Wait, _In_ BOOLEAN Poll)
Definition: ns16550.c:250
static BOOLEAN ComPortTest1(_In_ PUCHAR Address)
Definition: ns16550.c:39
NTSTATUS NTAPI Uart16550Initialize(_Inout_ PCPPORT Port, _In_ PUCHAR Address, _In_ ULONG BaudRate)
Definition: ns16550.c:182
VOID NTAPI Uart16550PutByte(_Inout_ PCPPORT Port, _In_ UCHAR Byte)
Definition: ns16550.c:303
static BOOLEAN ComPortTest2(_In_ PUCHAR Address)
Definition: ns16550.c:114
VOID NTAPI Uart16550EnableFifo(_In_ PUCHAR Address, _In_ BOOLEAN Enable)
Definition: ns16550.c:146
static UCHAR NTAPI Cp16550ReadLsr(_Inout_ PCPPORT Port, _In_ UCHAR ExpectedValue)
Definition: ns16550.c:226
BOOLEAN NTAPI Uart16550DoesPortExist(_In_ PUCHAR Address)
Definition: ns16550.c:138
UCHAR RingIndicator
Definition: ns16550.c:34
#define TRANSMIT_HOLDING_REGISTER
Definition: ns16550.h:32
#define SERIAL_MCR_RTS
Definition: ns16550.h:122
#define DIVISOR_LATCH_MSB
Definition: ns16550.h:43
#define INTERRUPT_ENABLE_REGISTER
Definition: ns16550.h:33
#define SERIAL_MCR_OUT1
Definition: ns16550.h:123
#define SERIAL_MSR_CTS
Definition: ns16550.h:147
#define SERIAL_FCR_ENABLE
Definition: ns16550.h:82
#define SERIAL_LSR_PE
Definition: ns16550.h:133
#define SERIAL_MCR_LOOP
Definition: ns16550.h:125
#define SERIAL_MCR_OUT2
Definition: ns16550.h:124
#define SERIAL_8_DATA
Definition: ns16550.h:103
#define CLOCK_RATE
Definition: ns16550.h:21
#define SERIAL_FCR_DISABLE
Definition: ns16550.h:81
#define FIFO_CONTROL_REGISTER
Definition: ns16550.h:35
#define SERIAL_FCR_RCVR_RESET
Definition: ns16550.h:83
#define SERIAL_MSR_DSR
Definition: ns16550.h:148
#define SERIAL_MSR_DCD
Definition: ns16550.h:150
#define SERIAL_LSR_THRE
Definition: ns16550.h:136
#define MODEM_CONTROL_REGISTER
Definition: ns16550.h:37
#define SERIAL_NONE_PARITY
Definition: ns16550.h:111
#define SERIAL_LSR_OE
Definition: ns16550.h:132
#define SERIAL_MSR_RI
Definition: ns16550.h:149
#define RECEIVE_BUFFER_REGISTER
Definition: ns16550.h:31
#define SERIAL_LSR_DR
Definition: ns16550.h:131
#define DIVISOR_LATCH_LSB
Definition: ns16550.h:42
#define SERIAL_MCR_DTR
Definition: ns16550.h:121
#define SERIAL_LCR_DLAB
Definition: ns16550.h:94
#define LINE_CONTROL_REGISTER
Definition: ns16550.h:36
#define SERIAL_LSR_FE
Definition: ns16550.h:134
#define LINE_STATUS_REGISTER
Definition: ns16550.h:38
#define SCRATCH_REGISTER
Definition: ns16550.h:40
#define SERIAL_1_STOP
Definition: ns16550.h:106
#define SERIAL_FCR_TXMT_RESET
Definition: ns16550.h:84
#define MODEM_STATUS_REGISTER
Definition: ns16550.h:39
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142
#define READ_PORT_UCHAR(p)
Definition: pc98vid.h:22
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
unsigned short USHORT
Definition: pedump.c:61
static WCHAR Address[46]
Definition: ping.c:68
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
PUCHAR Address
Definition: cportlib.h:28
ULONG BaudRate
Definition: cportlib.h:29
USHORT Flags
Definition: cportlib.h:30
#define NTAPI
Definition: typedefs.h:36
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
unsigned char UCHAR
Definition: xmlstorage.h:181