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