ReactOS 0.4.15-dev-7994-gb388cb6
cport.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 * FILE: lib/reactos/cportlib/cport.c
5 * PURPOSE: Provides a serial port library for KDCOM, INIT, and FREELDR
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9/* NOTE: This library follows the precise serial port intialization steps documented
10 * by Microsoft in some of their Server hardware guidance. Because they've clearly
11 * documented their serial algorithms, we use the same ones to stay "compliant".
12 * Do not change this code to "improve" it. It's done this way on purpose, at least on x86.
13 * -- sir_richard
14 *
15 * REPLY: I reworked the COM-port testing code because the original one
16 * (i.e. the Microsoft's documented one) doesn't work on Virtual PC 2007.
17 * -- hbelusca
18 */
19
20/* NOTE: This code is used by Headless Support (Ntoskrnl.exe and Osloader.exe) and
21 Kdcom.dll in Windows. It may be that WinDBG depends on some of these quirks.
22*/
23
24/* NOTE: The original code supports Modem Control. We currently do not */
25
26/* FIXMEs:
27 - Make this serial-port specific (NS16550 vs other serial port types)
28 - Get x64 KDCOM, KDBG, FREELDR, and other current code to use this
29*/
30
31/* INCLUDES *******************************************************************/
32
33#include <intrin.h>
34#include <ioaccess.h>
35#include <ntstatus.h>
36#include <cportlib/cportlib.h>
38
39/* GLOBALS ********************************************************************/
40
41// Wait timeout value
42#define TIMEOUT_COUNT 1024 * 200
43
45
46
47/* FUNCTIONS ******************************************************************/
48
49VOID
53{
54 /* Set FIFO and clear the receive/transmit buffers */
58}
59
60VOID
63 IN ULONG BaudRate)
64{
65 UCHAR Lcr;
66 ULONG Mode = CLOCK_RATE / BaudRate;
67
68 /* Set the DLAB on */
71
72 /* Set the baud rate */
75
76 /* Reset DLAB */
78
79 /* Save baud rate in port */
80 Port->BaudRate = BaudRate;
81}
82
87 IN ULONG BaudRate)
88{
89 /* Validity checks */
90 if (Port == NULL || Address == NULL || BaudRate == 0)
92
94 return STATUS_NOT_FOUND;
95
96 /* Initialize port data */
98 Port->BaudRate = 0;
99 Port->Flags = 0;
100
101 /* Disable the interrupts */
104
105 /* Turn on DTR, RTS and OUT2 */
108
109 /* Set the baud rate */
110 CpSetBaud(Port, BaudRate);
111
112 /* Set 8 data bits, 1 stop bit, no parity, no break */
115
116 /* Turn on FIFO */
117 // TODO: Check whether FIFO exists and turn it on in that case.
118 CpEnableFifo(Address, TRUE); // for 16550
119
120 /* Read junk out of the RBR */
122
123 return STATUS_SUCCESS;
124}
125
126static BOOLEAN
128{
129 /*
130 * See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation"
131 * Out-of-Band Management Port Device Requirements:
132 * The device must act as a 16550 or 16450 UART.
133 * Windows Server 2003 will test this device using the following process:
134 * 1. Save off the current modem status register.
135 * 2. Place the UART into diagnostic mode (The UART is placed into loopback mode
136 * by writing SERIAL_MCR_LOOP to the modem control register).
137 * 3. The modem status register is read and the high bits are checked. This means
138 * SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI and SERIAL_MSR_DCD should
139 * all be clear.
140 * 4. Place the UART in diagnostic mode and turn on OUTPUT (Loopback Mode and
141 * OUTPUT are both turned on by writing (SERIAL_MCR_LOOP | SERIAL_MCR_OUT1)
142 * to the modem control register).
143 * 5. The modem status register is read and the ring indicator is checked.
144 * This means SERIAL_MSR_RI should be set.
145 * 6. Restore original modem status register.
146 *
147 * REMARK: Strangely enough, the Virtual PC 2007 virtual machine
148 * doesn't pass this test.
149 */
150
151 BOOLEAN RetVal = FALSE;
152 UCHAR Mcr, Msr;
153
154 /* Save the Modem Control Register */
156
157 /* Enable loop (diagnostic) mode (set Bit 4 of the MCR) */
159
160 /* Clear all modem output bits */
162
163 /* Read the Modem Status Register */
165
166 /*
167 * The upper nibble of the MSR (modem output bits) must be
168 * equal to the lower nibble of the MCR (modem input bits).
169 */
170 if ((Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD)) == 0x00)
171 {
172 /* Set all modem output bits */
174 SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP); // Windows
175/* ReactOS
176 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
177 SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT1 | SERIAL_MCR_OUT2 | SERIAL_MCR_LOOP);
178*/
179
180 /* Read the Modem Status Register */
182
183 /*
184 * The upper nibble of the MSR (modem output bits) must be
185 * equal to the lower nibble of the MCR (modem input bits).
186 */
187 if (Msr & SERIAL_MSR_RI) // Windows
188 // if (Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD) == 0xF0) // ReactOS
189 {
190 RetVal = TRUE;
191 }
192 }
193
194 /* Restore the MCR */
196
197 return RetVal;
198}
199
200static BOOLEAN
202{
203 /*
204 * This test checks whether the 16450/16550 scratch register is available.
205 * If not, the serial port is considered as unexisting.
206 */
207
208 UCHAR Byte = 0;
209
210 do
211 {
213
215 return FALSE;
216
217 } while (++Byte != 0);
218
219 return TRUE;
220}
221
223NTAPI
225{
227}
228
229UCHAR
230NTAPI
232 IN UCHAR ExpectedValue)
233{
234 UCHAR Lsr, Msr;
235
236 /* Read the LSR and check if the expected value is present */
238 if (!(Lsr & ExpectedValue))
239 {
240 /* Check the MSR for ring indicator toggle */
242
243 /* If the indicator reaches 3, we've seen this on/off twice */
244 RingIndicator |= (Msr & SERIAL_MSR_RI) ? 1 : 2;
246 }
247
248 return Lsr;
249}
250
251USHORT
252NTAPI
256 IN BOOLEAN Poll)
257{
258 UCHAR Lsr;
259 ULONG LimitCount = Wait ? TIMEOUT_COUNT : 1;
260
261 /* Handle early read-before-init */
262 if (!Port->Address) return CP_GET_NODATA;
263
264 /* If "wait" mode enabled, spin many times, otherwise attempt just once */
265 while (LimitCount--)
266 {
267 /* Read LSR for data ready */
269 if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
270 {
271 /* If an error happened, clear the byte and fail */
273 {
274 *Byte = 0;
275 return CP_GET_ERROR;
276 }
277
278 /* If only polling was requested by caller, return now */
279 if (Poll) 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 */
297 CpReadLsr(Port, 0);
298 return CP_GET_NODATA;
299}
300
301VOID
302NTAPI
304 IN UCHAR Byte)
305{
306 /* Check if port is in modem control to handle CD */
307 // while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // Commented for the moment.
308 if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // To be removed when this becomes implemented.
309 {
310 /* Not implemented yet */
311 // DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
312 }
313
314 /* Wait for LSR to say we can go ahead */
315 while ((CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE) == 0x00);
316
317 /* Send the byte */
319}
320
321/* EOF */
unsigned char BOOLEAN
#define VOID
Definition: acefi.h:82
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI CpPutByte(IN PCPPORT Port, IN UCHAR Byte)
Definition: cport.c:303
#define TIMEOUT_COUNT
Definition: cport.c:42
NTSTATUS NTAPI CpInitialize(IN PCPPORT Port, IN PUCHAR Address, IN ULONG BaudRate)
Definition: cport.c:85
VOID NTAPI CpEnableFifo(IN PUCHAR Address, IN BOOLEAN Enable)
Definition: cport.c:51
USHORT NTAPI CpGetByte(IN PCPPORT Port, OUT PUCHAR Byte, IN BOOLEAN Wait, IN BOOLEAN Poll)
Definition: cport.c:253
VOID NTAPI CpSetBaud(IN PCPPORT Port, IN ULONG BaudRate)
Definition: cport.c:62
static BOOLEAN ComPortTest2(IN PUCHAR Address)
Definition: cport.c:201
static BOOLEAN ComPortTest1(IN PUCHAR Address)
Definition: cport.c:127
BOOLEAN NTAPI CpDoesPortExist(IN PUCHAR Address)
Definition: cport.c:224
UCHAR RingIndicator
Definition: cport.c:44
UCHAR NTAPI CpReadLsr(IN PCPPORT Port, IN UCHAR ExpectedValue)
Definition: cport.c:231
#define CP_GET_SUCCESS
Definition: cportlib.h:18
#define CP_GET_NODATA
Definition: cportlib.h:19
#define CPPORT_FLAG_MODEM_CONTROL
Definition: cportlib.h:25
#define CP_GET_ERROR
Definition: cportlib.h:20
#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:35
_In_ ULONG Mode
Definition: hubbusif.h:303
#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:29
ULONG BaudRate
Definition: cportlib.h:30
USHORT Flags
Definition: cportlib.h:31
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#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