ReactOS  0.4.15-dev-3720-g4cf9b79
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>
37 #include <drivers/serial/ns16550.h>
38 
39 /* GLOBALS ********************************************************************/
40 
41 // Wait timeout value
42 #define TIMEOUT_COUNT 1024 * 200
43 
45 
46 
47 /* FUNCTIONS ******************************************************************/
48 
49 VOID
50 NTAPI
53 {
54  /* Set FIFO and clear the receive/transmit buffers */
58 }
59 
60 VOID
61 NTAPI
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 
84 NTAPI
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 */
97  Port->Address = Address;
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 
126 static 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 
200 static 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 
222 BOOLEAN
223 NTAPI
225 {
226  return ( ComPortTest1(Address) || ComPortTest2(Address) );
227 }
228 
229 UCHAR
230 NTAPI
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 
251 USHORT
252 NTAPI
254  OUT PUCHAR Byte,
255  IN BOOLEAN Wait,
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 */
268  Lsr = CpReadLsr(Port, SERIAL_LSR_DR);
269  if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
270  {
271  /* If an error happened, clear the byte and fail */
272  if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE | SERIAL_LSR_OE))
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 
301 VOID
302 NTAPI
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 */
#define SCRATCH_REGISTER
Definition: ns16550.h:40
CPPORT Port[4]
Definition: headless.c:35
#define CLOCK_RATE
Definition: ns16550.h:21
#define IN
Definition: typedefs.h:39
#define LINE_STATUS_REGISTER
Definition: ns16550.h:38
USHORT NTAPI CpGetByte(IN PCPPORT Port, OUT PUCHAR Byte, IN BOOLEAN Wait, IN BOOLEAN Poll)
Definition: cport.c:253
#define SERIAL_LSR_PE
Definition: ns16550.h:133
#define CP_GET_ERROR
Definition: cportlib.h:20
#define DIVISOR_LATCH_LSB
Definition: ns16550.h:42
#define SERIAL_MSR_DSR
Definition: ns16550.h:148
static BOOLEAN ComPortTest2(IN PUCHAR Address)
Definition: cport.c:201
_In_ ULONG Mode
Definition: hubbusif.h:303
#define SERIAL_LSR_THRE
Definition: ns16550.h:136
VOID NTAPI CpEnableFifo(IN PUCHAR Address, IN BOOLEAN Enable)
Definition: cport.c:51
#define READ_PORT_UCHAR(p)
Definition: pc98vid.h:22
#define SERIAL_FCR_DISABLE
Definition: ns16550.h:81
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:167
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
#define SERIAL_MCR_OUT2
Definition: ns16550.h:124
#define SERIAL_MCR_RTS
Definition: ns16550.h:122
VOID NTAPI CpPutByte(IN PCPPORT Port, IN UCHAR Byte)
Definition: cport.c:303
#define SERIAL_1_STOP
Definition: ns16550.h:106
#define INTERRUPT_ENABLE_REGISTER
Definition: ns16550.h:33
#define SERIAL_MCR_DTR
Definition: ns16550.h:121
#define SERIAL_FCR_ENABLE
Definition: ns16550.h:82
#define SERIAL_LSR_DR
Definition: ns16550.h:131
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define RECEIVE_BUFFER_REGISTER
Definition: ns16550.h:31
static BOOLEAN ComPortTest1(IN PUCHAR Address)
Definition: cport.c:127
USHORT Flags
Definition: cportlib.h:31
#define SERIAL_8_DATA
Definition: ns16550.h:103
unsigned char BOOLEAN
static WCHAR Address[46]
Definition: ping.c:68
#define TIMEOUT_COUNT
Definition: cport.c:42
#define TRANSMIT_HOLDING_REGISTER
Definition: ns16550.h:32
UCHAR NTAPI CpReadLsr(IN PCPPORT Port, IN UCHAR ExpectedValue)
Definition: cport.c:231
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define DIVISOR_LATCH_MSB
Definition: ns16550.h:43
NTSTATUS NTAPI CpInitialize(IN PCPPORT Port, IN PUCHAR Address, IN ULONG BaudRate)
Definition: cport.c:85
VOID NTAPI CpSetBaud(IN PCPPORT Port, IN ULONG BaudRate)
Definition: cport.c:62
#define SERIAL_MCR_OUT1
Definition: ns16550.h:123
#define MODEM_STATUS_REGISTER
Definition: ns16550.h:39
unsigned char UCHAR
Definition: xmlstorage.h:181
#define SERIAL_NONE_PARITY
Definition: ns16550.h:111
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
BOOLEAN NTAPI CpDoesPortExist(IN PUCHAR Address)
Definition: cport.c:224
#define VOID
Definition: acefi.h:82
#define SERIAL_LSR_FE
Definition: ns16550.h:134
#define SERIAL_FCR_RCVR_RESET
Definition: ns16550.h:83
PUCHAR Address
Definition: cportlib.h:29
#define SERIAL_MSR_RI
Definition: ns16550.h:149
UCHAR RingIndicator
Definition: cport.c:44
#define SERIAL_MSR_DCD
Definition: ns16550.h:150
#define SERIAL_LCR_DLAB
Definition: ns16550.h:94
unsigned short USHORT
Definition: pedump.c:61
#define FIFO_CONTROL_REGISTER
Definition: ns16550.h:35
#define CPPORT_FLAG_MODEM_CONTROL
Definition: cportlib.h:25
ULONG BaudRate
Definition: cportlib.h:30
#define MODEM_CONTROL_REGISTER
Definition: ns16550.h:37
#define NULL
Definition: types.h:112
#define CP_GET_SUCCESS
Definition: cportlib.h:18
unsigned char Byte
Definition: zlib.h:37
#define SERIAL_FCR_TXMT_RESET
Definition: ns16550.h:84
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
#define SERIAL_MSR_CTS
Definition: ns16550.h:147
#define STATUS_SUCCESS
Definition: shellext.h:65
#define CP_GET_NODATA
Definition: cportlib.h:19
#define SERIAL_LSR_OE
Definition: ns16550.h:132
#define SERIAL_MCR_LOOP
Definition: ns16550.h:125
#define LINE_CONTROL_REGISTER
Definition: ns16550.h:36