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