Sync with trunk (r48144)
[reactos.git] / drivers / base / kddll / kdcom.c
1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/kdcom.c
5 * PURPOSE: COM port functions for the kernel debugger.
6 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org)
7 */
8
9 #include "kddll.h"
10 #include "kdcom.h"
11
12 /* Define wait timeout value. */
13 #define REPEAT_COUNT (1000 * 1000)
14
15 /* serial debug connection */
16 #define DEFAULT_DEBUG_PORT 2 /* COM2 */
17 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
18 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
19 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
20
21 #define DEFAULT_BAUD_RATE 19200
22
23
24 #if defined(_M_IX86) || defined(_M_AMD64)
25 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
26 #elif defined(_M_PPC)
27 const ULONG BaseArray[2] = {0, 0x800003f8};
28 #elif defined(_M_MIPS)
29 const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
30 #elif defined(_M_ARM)
31 const ULONG BaseArray[2] = {0, 0xF1012000};
32 #else
33 #error Unknown architecture
34 #endif
35
36 /* GLOBALS ********************************************************************/
37
38 PUCHAR ComPortBase;
39 ULONG ComPortNumber = DEFAULT_DEBUG_PORT;
40 ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE;
41 ULONG ComPortIrq = 0;
42
43
44 NTSTATUS
45 NTAPI
46 KdpPortInitialize()
47 {
48 ULONG Mode;
49
50 KDDBGPRINT("KdpPortInitialize\n");
51
52 /* Enable loop mode (set Bit 4 of the MCR) */
53 WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP);
54
55 /* Clear all modem output bits */
56 WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP);
57
58 /* The upper nibble of the MSR (modem output bits) must be
59 * equal to the lower nibble of the MCR (modem input bits) */
60 if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0x00)
61 {
62 return STATUS_INVALID_PARAMETER;
63 }
64
65 /* Set all modem output bits */
66 WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_ALL);
67
68 /* The upper nibble of the MSR (modem output bits) must be
69 * equal to the lower nibble of the MCR (modem input bits) */
70 if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0xF0)
71 {
72 return STATUS_INVALID_PARAMETER;
73 }
74
75 /* Enable FIFO */
76 WRITE_PORT_UCHAR(ComPortBase + COM_FCR,
77 FCR_ENABLE_FIFO | FCR_CLEAR_RCVR | FCR_CLEAR_XMIT);
78
79 /* Disable interrupts */
80 WRITE_PORT_UCHAR(ComPortBase + COM_LCR, 0);
81 WRITE_PORT_UCHAR(ComPortBase + COM_IEN, 0);
82
83 /* Enable on DTR and RTS */
84 WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_DTR | MCR_RTS);
85
86 /* Set DLAB */
87 WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_DLAB);
88
89 /* Set baud rate */
90 Mode = 115200 / ComPortBaudRate;
91 WRITE_PORT_UCHAR(ComPortBase + COM_DLL, (UCHAR)(Mode & 0xff));
92 WRITE_PORT_UCHAR(ComPortBase + COM_DLM, (UCHAR)((Mode >> 8) & 0xff));
93
94 /* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */
95 WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_CS8 | LCR_ST1 | LCR_PNO);
96
97 /* Check for 16450/16550 scratch register */
98 WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0xff);
99 if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0xff)
100 {
101 return STATUS_INVALID_PARAMETER;
102 }
103 WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0x00);
104 if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0x00)
105 {
106 return STATUS_INVALID_PARAMETER;
107 }
108
109 return STATUS_SUCCESS;
110 }
111
112 /******************************************************************************
113 * \name KdDebuggerInitialize0
114 * \brief Phase 0 initialization.
115 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
116 * \return Status
117 */
118 NTSTATUS
119 NTAPI
120 KdDebuggerInitialize0(
121 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
122 {
123 PCHAR CommandLine, PortString, BaudString, IrqString;
124 ULONG Value;
125
126 /* Check if e have a LoaderBlock */
127 if (LoaderBlock)
128 {
129 /* Get the Command Line */
130 CommandLine = LoaderBlock->LoadOptions;
131
132 /* Upcase it */
133 _strupr(CommandLine);
134
135 /* Get the port and baud rate */
136 PortString = strstr(CommandLine, "DEBUGPORT");
137 BaudString = strstr(CommandLine, "BAUDRATE");
138 IrqString = strstr(CommandLine, "IRQ");
139
140 /* Check if we got the /DEBUGPORT parameter */
141 if (PortString)
142 {
143 /* Move past the actual string, to reach the port*/
144 PortString += strlen("DEBUGPORT");
145
146 /* Now get past any spaces and skip the equal sign */
147 while (*PortString == ' ') PortString++;
148 PortString++;
149
150 /* Do we have a serial port? */
151 if (strncmp(PortString, "COM", 3) != 0)
152 {
153 return STATUS_INVALID_PARAMETER;
154 }
155
156 /* Gheck for a valid Serial Port */
157 PortString += 3;
158 Value = atol(PortString);
159 if (Value > 4)
160 {
161 return STATUS_INVALID_PARAMETER;
162 }
163
164 /* Set the port to use */
165 ComPortNumber = Value;
166 }
167
168 /* Check if we got a baud rate */
169 if (BaudString)
170 {
171 /* Move past the actual string, to reach the rate */
172 BaudString += strlen("BAUDRATE");
173
174 /* Now get past any spaces */
175 while (*BaudString == ' ') BaudString++;
176
177 /* And make sure we have a rate */
178 if (*BaudString)
179 {
180 /* Read and set it */
181 Value = atol(BaudString + 1);
182 if (Value) ComPortBaudRate = Value;
183 }
184 }
185
186 /* Check Serial Port Settings [IRQ] */
187 if (IrqString)
188 {
189 /* Move past the actual string, to reach the rate */
190 IrqString += strlen("IRQ");
191
192 /* Now get past any spaces */
193 while (*IrqString == ' ') IrqString++;
194
195 /* And make sure we have an IRQ */
196 if (*IrqString)
197 {
198 /* Read and set it */
199 Value = atol(IrqString + 1);
200 if (Value) ComPortIrq = Value;
201 }
202 }
203 }
204
205 /* Get base address */
206 ComPortBase = UlongToPtr(BaseArray[ComPortNumber]);
207 KdComPortInUse = ComPortBase;
208
209 /* Initialize the port */
210 return KdpPortInitialize();
211 }
212
213 VOID
214 NTAPI
215 KdpSendByte(IN BYTE Byte)
216 {
217 /* Wait for the port to be ready */
218 while ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_TBE) == 0);
219
220 /* This is needed due to subtle timing issues */
221 READ_PORT_UCHAR(ComPortBase + COM_MSR);
222 while ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_TBE) == 0);
223 READ_PORT_UCHAR(ComPortBase + COM_MSR);
224
225 /* Send the byte */
226 WRITE_PORT_UCHAR(ComPortBase + COM_DAT, Byte);
227 }
228
229 KDP_STATUS
230 NTAPI
231 KdpPollByte(OUT PBYTE OutByte)
232 {
233 READ_PORT_UCHAR(ComPortBase + COM_MSR); // Timing
234
235 /* Check if data is available */
236 if ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_DR))
237 {
238 /* Yes, return the byte */
239 *OutByte = READ_PORT_UCHAR(ComPortBase + COM_DAT);
240 return KDP_PACKET_RECEIVED;
241 }
242
243 /* Timed out */
244 return KDP_PACKET_TIMEOUT;
245 }
246
247 KDP_STATUS
248 NTAPI
249 KdpReceiveByte(OUT PBYTE OutByte)
250 {
251 ULONG Repeats = REPEAT_COUNT;
252
253 while (Repeats--)
254 {
255 /* Check if data is available */
256 if (KdpPollByte(OutByte) == KDP_PACKET_RECEIVED)
257 {
258 /* We successfully got a byte */
259 return KDP_PACKET_RECEIVED;
260 }
261 }
262
263 /* Timed out */
264 return KDP_PACKET_TIMEOUT;
265 }
266
267 KDP_STATUS
268 NTAPI
269 KdpPollBreakIn()
270 {
271 UCHAR Byte;
272 if (KdpPollByte(&Byte) == KDP_PACKET_RECEIVED)
273 {
274 if (Byte == BREAKIN_PACKET_BYTE)
275 {
276 return KDP_PACKET_RECEIVED;
277 }
278 }
279 return KDP_PACKET_TIMEOUT;
280 }
281
282 NTSTATUS
283 NTAPI
284 KdSave(
285 IN BOOLEAN SleepTransition)
286 {
287 /* Nothing to do on COM ports */
288 return STATUS_SUCCESS;
289 }
290
291 NTSTATUS
292 NTAPI
293 KdRestore(
294 IN BOOLEAN SleepTransition)
295 {
296 /* Nothing to do on COM ports */
297 return STATUS_SUCCESS;
298 }
299