ReactOS  0.4.14-dev-317-g96040ec
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 <cportlib/cportlib.h>
34 #include <drivers/serial/ns16550.h>
35 #include <intrin.h>
36 #include <ioaccess.h>
37 #include <ntstatus.h>
38 
39 #define NDEBUG
40 #include <debug.h>
41 
42 /* GLOBALS ********************************************************************/
43 
44 // Wait timeout value
45 #define TIMEOUT_COUNT 1024 * 200
46 
48 
49 
50 /* FUNCTIONS ******************************************************************/
51 
52 VOID
53 NTAPI
56 {
57  /* Set FIFO and clear the receive/transmit buffers */
61 }
62 
63 VOID
64 NTAPI
66  IN ULONG BaudRate)
67 {
68  UCHAR Lcr;
69  ULONG Mode = CLOCK_RATE / BaudRate;
70 
71  /* Set the DLAB on */
74 
75  /* Set the baud rate */
78 
79  /* Reset DLAB */
81 
82  /* Save baud rate in port */
83  Port->BaudRate = BaudRate;
84 }
85 
87 NTAPI
90  IN ULONG BaudRate)
91 {
92  /* Validity checks */
93  if (Port == NULL || Address == NULL || BaudRate == 0)
95 
97  return STATUS_NOT_FOUND;
98 
99  /* Initialize port data */
100  Port->Address = Address;
101  Port->BaudRate = 0;
102  Port->Flags = 0;
103 
104  /* Disable the interrupts */
107 
108  /* Turn on DTR, RTS and OUT2 */
111 
112  /* Set the baud rate */
113  CpSetBaud(Port, BaudRate);
114 
115  /* Set 8 data bits, 1 stop bit, no parity, no break */
118 
119  /* Turn on FIFO */
120  // TODO: Check whether FIFO exists and turn it on in that case.
121  CpEnableFifo(Address, TRUE); // for 16550
122 
123  /* Read junk out of the RBR */
125 
126  return STATUS_SUCCESS;
127 }
128 
129 static BOOLEAN
131 {
132  /*
133  * See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation"
134  * Out-of-Band Management Port Device Requirements:
135  * The device must act as a 16550 or 16450 UART.
136  * Windows Server 2003 will test this device using the following process:
137  * 1. Save off the current modem status register.
138  * 2. Place the UART into diagnostic mode (The UART is placed into loopback mode
139  * by writing SERIAL_MCR_LOOP to the modem control register).
140  * 3. The modem status register is read and the high bits are checked. This means
141  * SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI and SERIAL_MSR_DCD should
142  * all be clear.
143  * 4. Place the UART in diagnostic mode and turn on OUTPUT (Loopback Mode and
144  * OUTPUT are both turned on by writing (SERIAL_MCR_LOOP | SERIAL_MCR_OUT1)
145  * to the modem control register).
146  * 5. The modem status register is read and the ring indicator is checked.
147  * This means SERIAL_MSR_RI should be set.
148  * 6. Restore original modem status register.
149  *
150  * REMARK: Strangely enough, the Virtual PC 2007 virtual machine
151  * doesn't pass this test.
152  */
153 
154  BOOLEAN RetVal = FALSE;
155  UCHAR Mcr, Msr;
156 
157  /* Save the Modem Control Register */
159 
160  /* Enable loop (diagnostic) mode (set Bit 4 of the MCR) */
162 
163  /* Clear all modem output bits */
165 
166  /* Read the Modem Status Register */
168 
169  /*
170  * The upper nibble of the MSR (modem output bits) must be
171  * equal to the lower nibble of the MCR (modem input bits).
172  */
173  if ((Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD)) == 0x00)
174  {
175  /* Set all modem output bits */
177  SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP); // Windows
178 /* ReactOS
179  WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
180  SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT1 | SERIAL_MCR_OUT2 | SERIAL_MCR_LOOP);
181 */
182 
183  /* Read the Modem Status Register */
185 
186  /*
187  * The upper nibble of the MSR (modem output bits) must be
188  * equal to the lower nibble of the MCR (modem input bits).
189  */
190  if (Msr & SERIAL_MSR_RI) // Windows
191  // if (Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD) == 0xF0) // ReactOS
192  {
193  RetVal = TRUE;
194  }
195  }
196 
197  /* Restore the MCR */
199 
200  return RetVal;
201 }
202 
203 static BOOLEAN
205 {
206  /*
207  * This test checks whether the 16450/16550 scratch register is available.
208  * If not, the serial port is considered as unexisting.
209  */
210 
211  UCHAR Byte = 0;
212 
213  do
214  {
216 
218  return FALSE;
219 
220  } while (++Byte != 0);
221 
222  return TRUE;
223 }
224 
225 BOOLEAN
226 NTAPI
228 {
229  return ( ComPortTest1(Address) || ComPortTest2(Address) );
230 }
231 
232 UCHAR
233 NTAPI
235  IN UCHAR ExpectedValue)
236 {
237  UCHAR Lsr, Msr;
238 
239  /* Read the LSR and check if the expected value is present */
241  if (!(Lsr & ExpectedValue))
242  {
243  /* Check the MSR for ring indicator toggle */
245 
246  /* If the indicator reaches 3, we've seen this on/off twice */
247  RingIndicator |= (Msr & SERIAL_MSR_RI) ? 1 : 2;
249  }
250 
251  return Lsr;
252 }
253 
254 USHORT
255 NTAPI
257  OUT PUCHAR Byte,
258  IN BOOLEAN Wait,
259  IN BOOLEAN Poll)
260 {
261  UCHAR Lsr;
262  ULONG LimitCount = Wait ? TIMEOUT_COUNT : 1;
263 
264  /* Handle early read-before-init */
265  if (!Port->Address) return CP_GET_NODATA;
266 
267  /* If "wait" mode enabled, spin many times, otherwise attempt just once */
268  while (LimitCount--)
269  {
270  /* Read LSR for data ready */
271  Lsr = CpReadLsr(Port, SERIAL_LSR_DR);
272  if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
273  {
274  /* If an error happened, clear the byte and fail */
275  if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE | SERIAL_LSR_OE))
276  {
277  *Byte = 0;
278  return CP_GET_ERROR;
279  }
280 
281  /* If only polling was requested by caller, return now */
282  if (Poll) return CP_GET_SUCCESS;
283 
284  /* Otherwise read the byte and return it */
286 
287  /* Handle CD if port is in modem control mode */
289  {
290  /* Not implemented yet */
291  // DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
292  }
293 
294  /* Byte was read */
295  return CP_GET_SUCCESS;
296  }
297  }
298 
299  /* Reset LSR, no data was found */
300  CpReadLsr(Port, 0);
301  return CP_GET_NODATA;
302 }
303 
304 VOID
305 NTAPI
307  IN UCHAR Byte)
308 {
309  /* Check if port is in modem control to handle CD */
310  // while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // Commented for the moment.
311  if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // To be removed when this becomes implemented.
312  {
313  /* Not implemented yet */
314  // DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
315  }
316 
317  /* Wait for LSR to say we can go ahead */
318  while ((CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE) == 0x00);
319 
320  /* Send the byte */
322 }
323 
324 /* EOF */
#define SCRATCH_REGISTER
Definition: ns16550.h:40
CPPORT Port[4]
Definition: headless.c:34
#define CLOCK_RATE
Definition: ns16550.h:21
#define IN
Definition: typedefs.h:38
#define LINE_STATUS_REGISTER
Definition: ns16550.h:38
#define TRUE
Definition: types.h:120
USHORT NTAPI CpGetByte(IN PCPPORT Port, OUT PUCHAR Byte, IN BOOLEAN Wait, IN BOOLEAN Poll)
Definition: cport.c:256
#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:204
_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:54
unsigned char Byte
Definition: zconf.h:391
#define SERIAL_FCR_DISABLE
Definition: ns16550.h:81
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
unsigned char * PUCHAR
Definition: retypes.h:3
UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address)
Definition: mach.c:528
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:306
#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 RECEIVE_BUFFER_REGISTER
Definition: ns16550.h:31
static BOOLEAN ComPortTest1(IN PUCHAR Address)
Definition: cport.c:130
USHORT Flags
Definition: cportlib.h:31
#define SERIAL_8_DATA
Definition: ns16550.h:103
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
#define TIMEOUT_COUNT
Definition: cport.c:45
#define TRANSMIT_HOLDING_REGISTER
Definition: ns16550.h:32
UCHAR NTAPI CpReadLsr(IN PCPPORT Port, IN UCHAR ExpectedValue)
Definition: cport.c:234
#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:88
VOID NTAPI CpSetBaud(IN PCPPORT Port, IN ULONG BaudRate)
Definition: cport.c:65
#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
BOOLEAN NTAPI CpDoesPortExist(IN PUCHAR Address)
Definition: cport.c:227
#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:47
#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 CP_GET_SUCCESS
Definition: cportlib.h:18
#define SERIAL_FCR_TXMT_RESET
Definition: ns16550.h:84
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
#define SERIAL_MSR_CTS
Definition: ns16550.h:147
void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value)
Definition: mach.c:532
#define CP_GET_NODATA
Definition: cportlib.h:19
return STATUS_SUCCESS
Definition: btrfs.c:2938
#define SERIAL_LSR_OE
Definition: ns16550.h:132
#define SERIAL_MCR_LOOP
Definition: ns16550.h:125
#define LINE_CONTROL_REGISTER
Definition: ns16550.h:36
IN BOOLEAN Wait
Definition: fatprocs.h:1529