Merge from amd64 branch:
[reactos.git] / reactos / drivers / base / kdcom / i386 / kdbg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kdcom/kdbg.c
5 * PURPOSE: Serial i/o functions for the kernel debugger.
6 * PROGRAMMER: Alex Ionescu
7 * Hervé Poussineau
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #define NOEXTAPI
13 #include <ntddk.h>
14 #define NDEBUG
15 #include <halfuncs.h>
16 #include <stdio.h>
17 #include <debug.h>
18 #include "arc/arc.h"
19 #include "windbgkd.h"
20 #include <kddll.h>
21 #include <ioaccess.h> /* port intrinsics */
22
23 typedef struct _KD_PORT_INFORMATION
24 {
25 ULONG ComPort;
26 ULONG BaudRate;
27 ULONG BaseAddress;
28 } KD_PORT_INFORMATION, *PKD_PORT_INFORMATION;
29
30 BOOLEAN
31 NTAPI
32 KdPortInitializeEx(
33 IN PKD_PORT_INFORMATION PortInformation,
34 IN ULONG Unknown1,
35 IN ULONG Unknown2);
36
37 BOOLEAN
38 NTAPI
39 KdPortGetByteEx(
40 IN PKD_PORT_INFORMATION PortInformation,
41 OUT PUCHAR ByteReceived);
42
43 BOOLEAN
44 NTAPI
45 KdPortPollByteEx(
46 IN PKD_PORT_INFORMATION PortInformation,
47 OUT PUCHAR ByteReceived);
48
49 VOID
50 NTAPI
51 KdPortPutByteEx(
52 IN PKD_PORT_INFORMATION PortInformation,
53 IN UCHAR ByteToSend);
54
55 #define DEFAULT_BAUD_RATE 19200
56
57 #ifdef _M_IX86
58 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
59 #elif defined(_M_PPC)
60 const ULONG BaseArray[2] = {0, 0x800003f8};
61 #elif defined(_M_MIPS)
62 const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
63 #elif defined(_M_ARM)
64 const ULONG BaseArray[2] = {0, 0xF1012000};
65 #else
66 #error Unknown architecture
67 #endif
68
69 /* MACROS *******************************************************************/
70
71 #define SER_RBR(x) ((PUCHAR)(x)+0)
72 #define SER_THR(x) ((PUCHAR)(x)+0)
73 #define SER_DLL(x) ((PUCHAR)(x)+0)
74 #define SER_IER(x) ((PUCHAR)(x)+1)
75 #define SR_IER_ERDA 0x01
76 #define SR_IER_ETHRE 0x02
77 #define SR_IER_ERLSI 0x04
78 #define SR_IER_EMS 0x08
79 #define SR_IER_ALL 0x0F
80 #define SER_DLM(x) ((PUCHAR)(x)+1)
81 #define SER_IIR(x) ((PUCHAR)(x)+2)
82 #define SER_FCR(x) ((PUCHAR)(x)+2)
83 #define SR_FCR_ENABLE_FIFO 0x01
84 #define SR_FCR_CLEAR_RCVR 0x02
85 #define SR_FCR_CLEAR_XMIT 0x04
86 #define SER_LCR(x) ((PUCHAR)(x)+3)
87 #define SR_LCR_CS5 0x00
88 #define SR_LCR_CS6 0x01
89 #define SR_LCR_CS7 0x02
90 #define SR_LCR_CS8 0x03
91 #define SR_LCR_ST1 0x00
92 #define SR_LCR_ST2 0x04
93 #define SR_LCR_PNO 0x00
94 #define SR_LCR_POD 0x08
95 #define SR_LCR_PEV 0x18
96 #define SR_LCR_PMK 0x28
97 #define SR_LCR_PSP 0x38
98 #define SR_LCR_BRK 0x40
99 #define SR_LCR_DLAB 0x80
100 #define SER_MCR(x) ((PUCHAR)(x)+4)
101 #define SR_MCR_DTR 0x01
102 #define SR_MCR_RTS 0x02
103 #define SR_MCR_OUT1 0x04
104 #define SR_MCR_OUT2 0x08
105 #define SR_MCR_LOOP 0x10
106 #define SER_LSR(x) ((PUCHAR)(x)+5)
107 #define SR_LSR_DR 0x01
108 #define SR_LSR_TBE 0x20
109 #define SER_MSR(x) ((PUCHAR)(x)+6)
110 #define SR_MSR_CTS 0x10
111 #define SR_MSR_DSR 0x20
112 #define SER_SCR(x) ((PUCHAR)(x)+7)
113
114
115 /* GLOBAL VARIABLES *********************************************************/
116
117 /* STATIC VARIABLES *********************************************************/
118
119 static KD_PORT_INFORMATION DefaultPort = { 0, 0, 0 };
120
121 /* The com port must only be initialized once! */
122 static BOOLEAN PortInitialized = FALSE;
123
124
125 /* STATIC FUNCTIONS *********************************************************/
126
127 static BOOLEAN
128 KdpDoesComPortExist(
129 IN ULONG BaseAddress)
130 {
131 BOOLEAN found;
132 UCHAR mcr;
133 UCHAR msr;
134
135 found = FALSE;
136
137 /* save Modem Control Register (MCR) */
138 mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
139
140 /* enable loop mode (set Bit 4 of the MCR) */
141 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
142
143 /* clear all modem output bits */
144 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
145
146 /* read the Modem Status Register */
147 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
148
149 /*
150 * the upper nibble of the MSR (modem output bits) must be
151 * equal to the lower nibble of the MCR (modem input bits)
152 */
153 if ((msr & 0xF0) == 0x00)
154 {
155 /* set all modem output bits */
156 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_DTR | SR_MCR_RTS | SR_MCR_OUT1 | SR_MCR_OUT2 | SR_MCR_LOOP);
157
158 /* read the Modem Status Register */
159 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
160
161 /*
162 * the upper nibble of the MSR (modem output bits) must be
163 * equal to the lower nibble of the MCR (modem input bits)
164 */
165 if ((msr & 0xF0) == 0xF0)
166 {
167 /*
168 * setup a resonable state for the port:
169 * enable fifo and clear recieve/transmit buffers
170 */
171 WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
172 (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
173 WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
174 READ_PORT_UCHAR(SER_RBR(BaseAddress));
175 WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
176 found = TRUE;
177 }
178 }
179
180 /* restore MCR */
181 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), mcr);
182
183 return found;
184 }
185
186
187 /* FUNCTIONS ****************************************************************/
188
189 /* HAL.KdPortInitialize */
190 BOOLEAN
191 NTAPI
192 KdPortInitialize(
193 IN PKD_PORT_INFORMATION PortInformation,
194 IN ULONG Unknown1,
195 IN ULONG Unknown2)
196 {
197 SIZE_T i;
198 CHAR buffer[80];
199
200 if (!PortInitialized)
201 {
202 DefaultPort.BaudRate = PortInformation->BaudRate;
203
204 if (PortInformation->ComPort == 0)
205 {
206 for (i = sizeof(BaseArray) / sizeof(BaseArray[0]) - 1; i > 0; i--)
207 {
208 if (KdpDoesComPortExist(BaseArray[i]))
209 {
210 DefaultPort.BaseAddress = BaseArray[i];
211 DefaultPort.ComPort = i;
212 PortInformation->BaseAddress = DefaultPort.BaseAddress;
213 PortInformation->ComPort = DefaultPort.ComPort;
214 break;
215 }
216 }
217 if (i == 0)
218 {
219 sprintf(buffer,
220 "\nKernel Debugger: No COM port found!\n\n");
221 HalDisplayString(buffer);
222 return FALSE;
223 }
224 }
225
226 PortInitialized = TRUE;
227 }
228
229 /* initialize port */
230 if (!KdPortInitializeEx(&DefaultPort, Unknown1, Unknown2))
231 return FALSE;
232
233 /* set global info */
234 KdComPortInUse = (PUCHAR)DefaultPort.BaseAddress;
235
236 return TRUE;
237 }
238
239
240 /* HAL.KdPortInitializeEx */
241 BOOLEAN
242 NTAPI
243 KdPortInitializeEx(
244 IN PKD_PORT_INFORMATION PortInformation,
245 IN ULONG Unknown1,
246 IN ULONG Unknown2)
247 {
248 ULONG ComPortBase;
249 CHAR buffer[80];
250 ULONG divisor;
251 UCHAR lcr;
252
253 #ifdef _ARM_
254 UNIMPLEMENTED;
255 return FALSE;
256 #endif
257
258 if (PortInformation->BaudRate == 0)
259 PortInformation->BaudRate = DEFAULT_BAUD_RATE;
260
261 if (PortInformation->ComPort == 0)
262 return FALSE;
263
264 if (!KdpDoesComPortExist(BaseArray[PortInformation->ComPort]))
265 {
266 sprintf(buffer,
267 "\nKernel Debugger: Serial port not found!\n\n");
268 HalDisplayString(buffer);
269 return FALSE;
270 }
271
272 ComPortBase = BaseArray[PortInformation->ComPort];
273 PortInformation->BaseAddress = ComPortBase;
274 #ifndef NDEBUG
275 sprintf(buffer,
276 "\nSerial port COM%ld found at 0x%lx\n",
277 PortInformation->ComPort,
278 ComPortBase);
279 HalDisplayString(buffer);
280 #endif /* NDEBUG */
281
282 /* set baud rate and data format (8N1) */
283
284 /* turn on DTR and RTS */
285 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), SR_MCR_DTR | SR_MCR_RTS);
286
287 /* set DLAB */
288 lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)) | SR_LCR_DLAB;
289 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), lcr);
290
291 /* set baud rate */
292 divisor = 115200 / PortInformation->BaudRate;
293 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), (UCHAR)(divisor & 0xff));
294 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), (UCHAR)((divisor >> 8) & 0xff));
295
296 /* reset DLAB and set 8N1 format */
297 WRITE_PORT_UCHAR(SER_LCR(ComPortBase),
298 SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO);
299
300 /* read junk out of the RBR */
301 lcr = READ_PORT_UCHAR(SER_RBR(ComPortBase));
302
303 #ifndef NDEBUG
304 /* print message to blue screen */
305 sprintf(buffer,
306 "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n",
307 PortInformation->ComPort,
308 ComPortBase,
309 PortInformation->BaudRate);
310
311 HalDisplayString(buffer);
312 #endif /* NDEBUG */
313
314 return TRUE;
315 }
316
317
318 /* HAL.KdPortGetByte */
319 BOOLEAN
320 NTAPI
321 KdPortGetByte(
322 OUT PUCHAR ByteReceived)
323 {
324 if (!PortInitialized)
325 return FALSE;
326 return KdPortGetByteEx(&DefaultPort, ByteReceived);
327 }
328
329
330 /* HAL.KdPortGetByteEx */
331 BOOLEAN
332 NTAPI
333 KdPortGetByteEx(
334 IN PKD_PORT_INFORMATION PortInformation,
335 OUT PUCHAR ByteReceived)
336 {
337 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
338
339 if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR))
340 {
341 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
342 return TRUE;
343 }
344
345 return FALSE;
346 }
347
348
349 /* HAL.KdPortPollByte */
350 BOOLEAN
351 NTAPI
352 KdPortPollByte(
353 OUT PUCHAR ByteReceived)
354 {
355 if (!PortInitialized)
356 return FALSE;
357 return KdPortPollByteEx(&DefaultPort, ByteReceived);
358 }
359
360
361 /* HAL.KdPortPollByteEx */
362 BOOLEAN
363 NTAPI
364 KdPortPollByteEx(
365 IN PKD_PORT_INFORMATION PortInformation,
366 OUT PUCHAR ByteReceived)
367 {
368 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
369
370 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
371 ;
372
373 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
374
375 return TRUE;
376 }
377
378
379 /* HAL.KdPortPutByte */
380 VOID
381 NTAPI
382 KdPortPutByte(
383 IN UCHAR ByteToSend)
384 {
385 if (!PortInitialized)
386 return;
387 KdPortPutByteEx(&DefaultPort, ByteToSend);
388 }
389
390 /* HAL.KdPortPutByteEx */
391 VOID
392 NTAPI
393 KdPortPutByteEx(
394 IN PKD_PORT_INFORMATION PortInformation,
395 IN UCHAR ByteToSend)
396 {
397 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
398
399 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0)
400 ;
401
402 WRITE_PORT_UCHAR(SER_THR(ComPortBase), ByteToSend);
403 }
404
405
406 /* HAL.KdPortRestore */
407 VOID
408 NTAPI
409 KdPortRestore(VOID)
410 {
411 UNIMPLEMENTED;
412 }
413
414
415 /* HAL.KdPortSave */
416 VOID
417 NTAPI
418 KdPortSave(VOID)
419 {
420 UNIMPLEMENTED;
421 }
422
423
424 /* HAL.KdPortDisableInterrupts */
425 BOOLEAN
426 NTAPI
427 KdPortDisableInterrupts(VOID)
428 {
429 UCHAR ch;
430
431 if (!PortInitialized)
432 return FALSE;
433
434 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
435 ch &= (~(SR_MCR_OUT1 | SR_MCR_OUT2));
436 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
437
438 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
439 ch &= (~SR_IER_ALL);
440 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
441
442 return TRUE;
443 }
444
445
446 /* HAL.KdPortEnableInterrupts */
447 BOOLEAN
448 NTAPI
449 KdPortEnableInterrupts(VOID)
450 {
451 UCHAR ch;
452
453 if (PortInitialized == FALSE)
454 return FALSE;
455
456 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
457 ch &= (~SR_IER_ALL);
458 ch |= SR_IER_ERDA;
459 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
460
461 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
462 ch &= (~SR_MCR_LOOP);
463 ch |= (SR_MCR_OUT1 | SR_MCR_OUT2);
464 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
465
466 return TRUE;
467 }
468
469 /*
470 * @unimplemented
471 */
472 NTSTATUS
473 NTAPI
474 KdDebuggerInitialize0(
475 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
476 {
477 return STATUS_NOT_IMPLEMENTED;
478 }
479
480 /*
481 * @unimplemented
482 */
483 NTSTATUS
484 NTAPI
485 KdDebuggerInitialize1(
486 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
487 {
488 return STATUS_NOT_IMPLEMENTED;
489 }
490
491 /*
492 * @implemented
493 */
494 NTSTATUS
495 NTAPI
496 KdSave(
497 IN BOOLEAN SleepTransition)
498 {
499 /* Nothing to do on COM ports */
500 return STATUS_SUCCESS;
501 }
502
503 /*
504 * @implemented
505 */
506 NTSTATUS
507 NTAPI
508 KdRestore(
509 IN BOOLEAN SleepTransition)
510 {
511 /* Nothing to do on COM ports */
512 return STATUS_SUCCESS;
513 }
514
515 /*
516 * @unimplemented
517 */
518 VOID
519 NTAPI
520 KdSendPacket(
521 IN ULONG PacketType,
522 IN PSTRING MessageHeader,
523 IN PSTRING MessageData,
524 IN OUT PKD_CONTEXT Context)
525 {
526 UNIMPLEMENTED;
527 return;
528 }
529
530 /*
531 * @unimplemented
532 */
533 KDSTATUS
534 NTAPI
535 KdReceivePacket(
536 IN ULONG PacketType,
537 OUT PSTRING MessageHeader,
538 OUT PSTRING MessageData,
539 OUT PULONG DataLength,
540 IN OUT PKD_CONTEXT Context)
541 {
542 UNIMPLEMENTED;
543 return 0;
544 }
545
546 /* EOF */