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