Reactos
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@reactos.org)
7 */
8
9#include "kddll.h"
10
11#include <cportlib/cportlib.h>
12#include <arc/arc.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <ndk/halfuncs.h>
16
17/* Serial debug connection */
18#if defined(SARCH_PC98)
19#define DEFAULT_DEBUG_PORT 2 /* COM2 */
20#define DEFAULT_DEBUG_COM1_IRQ 4
21#define DEFAULT_DEBUG_COM2_IRQ 5
22#define DEFAULT_DEBUG_BAUD_RATE 9600
23#define DEFAULT_BAUD_RATE 9600
24#else
25#define DEFAULT_DEBUG_PORT 2 /* COM2 */
26#define DEFAULT_DEBUG_COM1_IRQ 4
27#define DEFAULT_DEBUG_COM2_IRQ 3
28#define DEFAULT_DEBUG_BAUD_RATE 115200
29#define DEFAULT_BAUD_RATE 19200
30#endif
31
32#if defined(_M_IX86) || defined(_M_AMD64)
33#if defined(SARCH_PC98)
34const ULONG BaseArray[] = {0, 0x30, 0x238};
35#else
36const ULONG BaseArray[] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
37#endif
38#elif defined(_M_PPC)
39const ULONG BaseArray[] = {0, 0x800003F8};
40#elif defined(_M_MIPS)
41const ULONG BaseArray[] = {0, 0x80006000, 0x80007000};
42#elif defined(_M_ARM)
43const ULONG BaseArray[] = {0, 0xF1012000};
44#else
45#error Unknown architecture
46#endif
47
48#define MAX_COM_PORTS (sizeof(BaseArray) / sizeof(BaseArray[0]) - 1)
49
50/* GLOBALS ********************************************************************/
51
52CPPORT KdComPort;
53ULONG KdComPortIrq = 0; // Not used at the moment.
54#ifdef KDDEBUG
55CPPORT KdDebugComPort;
56#endif
57
58/* DEBUGGING ******************************************************************/
59
60#ifdef KDDEBUG
61ULONG KdpDbgPrint(const char *Format, ...)
62{
63 va_list ap;
64 int Length;
65 char* ptr;
66 CHAR Buffer[512];
67
68 va_start(ap, Format);
69 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
70 va_end(ap);
71
72 /* Check if we went past the buffer */
73 if (Length == -1)
74 {
75 /* Terminate it if we went over-board */
76 Buffer[sizeof(Buffer) - 1] = '\n';
77
78 /* Put maximum */
79 Length = sizeof(Buffer);
80 }
81
82 ptr = Buffer;
83 while (Length--)
84 {
85 if (*ptr == '\n')
86 CpPutByte(&KdDebugComPort, '\r');
87
88 CpPutByte(&KdDebugComPort, *ptr++);
89 }
90
91 return 0;
92}
93#endif
94
95/* FUNCTIONS ******************************************************************/
96
97NTSTATUS
98NTAPI
99KdD0Transition(VOID)
100{
101 return STATUS_SUCCESS;
102}
103
104NTSTATUS
105NTAPI
106KdD3Transition(VOID)
107{
108 return STATUS_SUCCESS;
109}
110
111NTSTATUS
112NTAPI
113KdSave(IN BOOLEAN SleepTransition)
114{
115 /* Nothing to do on COM ports */
116 return STATUS_SUCCESS;
117}
118
119NTSTATUS
120NTAPI
121KdRestore(IN BOOLEAN SleepTransition)
122{
123 /* Nothing to do on COM ports */
124 return STATUS_SUCCESS;
125}
126
127NTSTATUS
128NTAPI
129KdpPortInitialize(IN ULONG ComPortNumber,
130 IN ULONG ComPortBaudRate)
131{
132 NTSTATUS Status;
133
134 KDDBGPRINT("KdpPortInitialize, Port = COM%ld\n", ComPortNumber);
135
136 Status = CpInitialize(&KdComPort,
137 UlongToPtr(BaseArray[ComPortNumber]),
138 ComPortBaudRate);
139 if (!NT_SUCCESS(Status))
140 {
141 return STATUS_INVALID_PARAMETER;
142 }
143 else
144 {
145 KdComPortInUse = KdComPort.Address;
146 return STATUS_SUCCESS;
147 }
148}
149
150/******************************************************************************
151 * \name KdDebuggerInitialize0
152 * \brief Phase 0 initialization.
153 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
154 * \return Status
155 */
156NTSTATUS
157NTAPI
158KdDebuggerInitialize0(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
159{
160 ULONG ComPortNumber = DEFAULT_DEBUG_PORT;
161 ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE;
162
163 PCHAR CommandLine, PortString, BaudString, IrqString;
164 ULONG Value;
165
166 /* Check if we have a LoaderBlock */
167 if (LoaderBlock)
168 {
169 /* Get the Command Line */
170 CommandLine = LoaderBlock->LoadOptions;
171
172 /* Upcase it */
173 _strupr(CommandLine);
174
175 /* Get the port and baud rate */
176 PortString = strstr(CommandLine, "DEBUGPORT");
177 BaudString = strstr(CommandLine, "BAUDRATE");
178 IrqString = strstr(CommandLine, "IRQ");
179
180 /* Check if we got the /DEBUGPORT parameter */
181 if (PortString)
182 {
183 /* Move past the actual string, to reach the port*/
184 PortString += strlen("DEBUGPORT");
185
186 /* Now get past any spaces and skip the equal sign */
187 while (*PortString == ' ') PortString++;
188 PortString++;
189
190 /* Do we have a serial port? */
191 if (strncmp(PortString, "COM", 3) != 0)
192 {
193 return STATUS_INVALID_PARAMETER;
194 }
195
196 /* Check for a valid Serial Port */
197 PortString += 3;
198 Value = atol(PortString);
199 if (Value >= sizeof(BaseArray) / sizeof(BaseArray[0]))
200 {
201 return STATUS_INVALID_PARAMETER;
202 }
203
204 /* Set the port to use */
205 ComPortNumber = Value;
206 }
207
208 /* Check if we got a baud rate */
209 if (BaudString)
210 {
211 /* Move past the actual string, to reach the rate */
212 BaudString += strlen("BAUDRATE");
213
214 /* Now get past any spaces */
215 while (*BaudString == ' ') BaudString++;
216
217 /* And make sure we have a rate */
218 if (*BaudString)
219 {
220 /* Read and set it */
221 Value = atol(BaudString + 1);
222 if (Value) ComPortBaudRate = Value;
223 }
224 }
225
226 /* Check Serial Port Settings [IRQ] */
227 if (IrqString)
228 {
229 /* Move past the actual string, to reach the rate */
230 IrqString += strlen("IRQ");
231
232 /* Now get past any spaces */
233 while (*IrqString == ' ') IrqString++;
234
235 /* And make sure we have an IRQ */
236 if (*IrqString)
237 {
238 /* Read and set it */
239 Value = atol(IrqString + 1);
240 if (Value) KdComPortIrq = Value;
241 }
242 }
243 }
244
245#ifdef KDDEBUG
246 /*
247 * Try to find a free COM port and use it as the KD debugging port.
248 * NOTE: Inspired by reactos/boot/freeldr/freeldr/comm/rs232.c, Rs232PortInitialize(...)
249 */
250 {
251 /*
252 * Start enumerating COM ports from the last one to the first one,
253 * and break when we find a valid port.
254 * If we reach the first element of the list, the invalid COM port,
255 * then it means that no valid port was found.
256 */
257 ULONG ComPort;
258 for (ComPort = MAX_COM_PORTS; ComPort > 0; ComPort--)
259 {
260 /* Check if the port exist; skip the KD port */
261 if ((ComPort != ComPortNumber) && CpDoesPortExist(UlongToPtr(BaseArray[ComPort])))
262 break;
263 }
264 if (ComPort != 0)
265 CpInitialize(&KdDebugComPort, UlongToPtr(BaseArray[ComPort]), DEFAULT_BAUD_RATE);
266 }
267#endif
268
269 KDDBGPRINT("KdDebuggerInitialize0\n");
270
271 /* Initialize the port */
272 return KdpPortInitialize(ComPortNumber, ComPortBaudRate);
273}
274
275/******************************************************************************
276 * \name KdDebuggerInitialize1
277 * \brief Phase 1 initialization.
278 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
279 * \return Status
280 */
281NTSTATUS
282NTAPI
283KdDebuggerInitialize1(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
284{
285 return STATUS_SUCCESS;
286}
287
288
289VOID
290NTAPI
291KdpSendByte(IN UCHAR Byte)
292{
293 /* Send the byte */
294 CpPutByte(&KdComPort, Byte);
295}
296
297KDP_STATUS
298NTAPI
299KdpPollByte(OUT PUCHAR OutByte)
300{
301 USHORT Status;
302
303 /* Poll the byte */
304 Status = CpGetByte(&KdComPort, OutByte, FALSE, FALSE);
305 switch (Status)
306 {
307 case CP_GET_SUCCESS:
308 return KDP_PACKET_RECEIVED;
309
310 case CP_GET_NODATA:
311 return KDP_PACKET_TIMEOUT;
312
313 case CP_GET_ERROR:
314 default:
315 return KDP_PACKET_RESEND;
316 }
317}
318
319KDP_STATUS
320NTAPI
321KdpReceiveByte(OUT PUCHAR OutByte)
322{
323 USHORT Status;
324
325 /* Get the byte */
326 Status = CpGetByte(&KdComPort, OutByte, TRUE, FALSE);
327 switch (Status)
328 {
329 case CP_GET_SUCCESS:
330 return KDP_PACKET_RECEIVED;
331
332 case CP_GET_NODATA:
333 return KDP_PACKET_TIMEOUT;
334
335 case CP_GET_ERROR:
336 default:
337 return KDP_PACKET_RESEND;
338 }
339}
340
341KDP_STATUS
342NTAPI
343KdpPollBreakIn(VOID)
344{
345 KDP_STATUS KdStatus;
346 UCHAR Byte;
347
348 KdStatus = KdpPollByte(&Byte);
349 if ((KdStatus == KDP_PACKET_RECEIVED) && (Byte == BREAKIN_PACKET_BYTE))
350 {
351 return KDP_PACKET_RECEIVED;
352 }
353 return KDP_PACKET_TIMEOUT;
354}
355
356/* EOF */