xref: /reactos/drivers/base/kdcom/kdcom.c (revision 463784c5)
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)
34 const ULONG BaseArray[] = {0, 0x30, 0x238};
35 #else
36 const ULONG BaseArray[] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
37 #endif
38 #elif defined(_M_PPC)
39 const ULONG BaseArray[] = {0, 0x800003F8};
40 #elif defined(_M_MIPS)
41 const ULONG BaseArray[] = {0, 0x80006000, 0x80007000};
42 #elif defined(_M_ARM)
43 const 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 
52 CPPORT KdComPort;
53 ULONG  KdComPortIrq = 0; // Not used at the moment.
54 #ifdef KDDEBUG
55 CPPORT KdDebugComPort;
56 #endif
57 
58 /* DEBUGGING ******************************************************************/
59 
60 #ifdef KDDEBUG
61 ULONG 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 
97 NTSTATUS
98 NTAPI
99 KdD0Transition(VOID)
100 {
101     return STATUS_SUCCESS;
102 }
103 
104 NTSTATUS
105 NTAPI
106 KdD3Transition(VOID)
107 {
108     return STATUS_SUCCESS;
109 }
110 
111 NTSTATUS
112 NTAPI
113 KdSave(IN BOOLEAN SleepTransition)
114 {
115     /* Nothing to do on COM ports */
116     return STATUS_SUCCESS;
117 }
118 
119 NTSTATUS
120 NTAPI
121 KdRestore(IN BOOLEAN SleepTransition)
122 {
123     /* Nothing to do on COM ports */
124     return STATUS_SUCCESS;
125 }
126 
127 NTSTATUS
128 NTAPI
129 KdpPortInitialize(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  */
156 NTSTATUS
157 NTAPI
158 KdDebuggerInitialize0(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  */
281 NTSTATUS
282 NTAPI
283 KdDebuggerInitialize1(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
284 {
285     return STATUS_SUCCESS;
286 }
287 
288 
289 VOID
290 NTAPI
291 KdpSendByte(IN UCHAR Byte)
292 {
293     /* Send the byte */
294     CpPutByte(&KdComPort, Byte);
295 }
296 
297 KDP_STATUS
298 NTAPI
299 KdpPollByte(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 
319 KDP_STATUS
320 NTAPI
321 KdpReceiveByte(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 
341 KDP_STATUS
342 NTAPI
343 KdpPollBreakIn(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 */
357