xref: /haiku/src/system/boot/platform/bios_ia32/serial.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*
2  * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "serial.h"
8 
9 #include <boot/platform.h>
10 #include <arch/cpu.h>
11 #include <boot/stage2.h>
12 
13 #include <string.h>
14 
15 
16 //#define ENABLE_SERIAL
17 	// define this to always enable serial output
18 
19 
20 enum serial_register_offsets {
21 	SERIAL_TRANSMIT_BUFFER		= 0,
22 	SERIAL_RECEIVE_BUFFER		= 0,
23 	SERIAL_DIVISOR_LATCH_LOW	= 0,
24 	SERIAL_DIVISOR_LATCH_HIGH	= 1,
25 	SERIAL_FIFO_CONTROL			= 2,
26 	SERIAL_LINE_CONTROL			= 3,
27 	SERIAL_MODEM_CONTROL		= 4,
28 	SERIAL_LINE_STATUS			= 5,
29 	SERIAL_MODEM_STATUS			= 6,
30 };
31 
32 static const uint32 kSerialBaudRate = 115200;
33 
34 static int32 sSerialEnabled = 0;
35 static uint16 sSerialBasePort = 0x3f8;
36 
37 
38 static void
39 serial_putc(char c)
40 {
41 	// wait until the transmitter empty bit is set
42 	while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0)
43 		;
44 
45 	out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
46 }
47 
48 
49 extern "C" void
50 serial_puts(const char *string, size_t size)
51 {
52 	if (sSerialEnabled <= 0)
53 		return;
54 
55 	while (size-- != 0) {
56 		char c = string[0];
57 
58 		if (c == '\n') {
59 			serial_putc('\r');
60 			serial_putc('\n');
61 		} else if (c != '\r')
62 			serial_putc(c);
63 
64 		string++;
65 	}
66 }
67 
68 
69 extern "C" void
70 serial_disable(void)
71 {
72 #ifdef ENABLE_SERIAL
73 	sSerialEnabled = 0;
74 #else
75 	sSerialEnabled--;
76 #endif
77 }
78 
79 
80 extern "C" void
81 serial_enable(void)
82 {
83 	sSerialEnabled++;
84 }
85 
86 
87 extern "C" void
88 serial_init(void)
89 {
90 	// copy the base ports of the optional 4 serial ports to the kernel args
91 	// 0x0000:0x0400 is the location of that information in the BIOS data segment
92 	uint16 *ports = (uint16 *)0x400;
93 	memcpy(gKernelArgs.platform_args.serial_base_ports, ports, sizeof(uint16) * MAX_SERIAL_PORTS);
94 
95 	// only use the port if we could find one, else use the standard port
96 	if (gKernelArgs.platform_args.serial_base_ports[0] != 0)
97 		sSerialBasePort = gKernelArgs.platform_args.serial_base_ports[0];
98 
99 	uint16 divisor = uint16(115200 / kSerialBaudRate);
100 
101 	out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);	/* set divisor latch access bit */
102 	out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
103 	out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
104 	out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);		/* 8N1 */
105 
106 #ifdef ENABLE_SERIAL
107 	serial_enable();
108 #endif
109 }
110 
111