xref: /haiku/src/system/boot/platform/bios_ia32/serial.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
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 static void
38 serial_putc(char c)
39 {
40 	// wait until the transmitter empty bit is set
41 	while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0)
42 		asm volatile ("pause;");
43 
44 	out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
45 }
46 
47 
48 extern "C" void
49 serial_puts(const char* string, size_t size)
50 {
51 	if (sSerialEnabled <= 0)
52 		return;
53 
54 	while (size-- != 0) {
55 		char c = string[0];
56 
57 		if (c == '\n') {
58 			serial_putc('\r');
59 			serial_putc('\n');
60 		} else if (c != '\r')
61 			serial_putc(c);
62 
63 		string++;
64 	}
65 }
66 
67 
68 extern "C" void
69 serial_disable(void)
70 {
71 #ifdef ENABLE_SERIAL
72 	sSerialEnabled = 0;
73 #else
74 	sSerialEnabled--;
75 #endif
76 }
77 
78 
79 extern "C" void
80 serial_enable(void)
81 {
82 	sSerialEnabled++;
83 }
84 
85 
86 extern "C" void
87 serial_init(void)
88 {
89 	// copy the base ports of the optional 4 serial ports to the kernel args
90 	// 0x0000:0x0400 is the location of that information in the BIOS data
91 	// segment
92 	uint16* ports = (uint16*)0x400;
93 	memcpy(gKernelArgs.platform_args.serial_base_ports, ports,
94 		sizeof(uint16) * MAX_SERIAL_PORTS);
95 
96 	// only use the port if we could find one, else use the standard port
97 	if (gKernelArgs.platform_args.serial_base_ports[0] != 0)
98 		sSerialBasePort = gKernelArgs.platform_args.serial_base_ports[0];
99 
100 	uint16 divisor = uint16(115200 / kSerialBaudRate);
101 
102 	out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);
103 		// set divisor latch access bit
104 	out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
105 	out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
106 	out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);
107 		// 8N1
108 
109 #ifdef ENABLE_SERIAL
110 	serial_enable();
111 #endif
112 }
113