* Copyright 2004-2008, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "serial.h"
#include <boot/platform.h>
#include <arch/cpu.h>
#include <boot/stage2.h>
#include <string.h>
enum serial_register_offsets {
SERIAL_TRANSMIT_BUFFER = 0,
SERIAL_RECEIVE_BUFFER = 0,
SERIAL_DIVISOR_LATCH_LOW = 0,
SERIAL_DIVISOR_LATCH_HIGH = 1,
SERIAL_FIFO_CONTROL = 2,
SERIAL_LINE_CONTROL = 3,
SERIAL_MODEM_CONTROL = 4,
SERIAL_LINE_STATUS = 5,
SERIAL_MODEM_STATUS = 6,
};
static const uint32 kSerialBaudRate = 115200;
static int32 sSerialEnabled = 0;
static uint16 sSerialBasePort = 0x3f8;
static void
serial_putc(char c)
{
int32 timeout = 256 * 1024;
while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0) {
if (--timeout == 0) {
sSerialEnabled = 0;
return;
}
asm volatile ("pause");
}
out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
}
extern "C" void
serial_puts(const char* string, size_t size)
{
if (sSerialEnabled <= 0)
return;
while (size-- != 0) {
char c = string[0];
if (c == '\n') {
serial_putc('\r');
serial_putc('\n');
} else if (c != '\r')
serial_putc(c);
string++;
}
}
extern "C" void
serial_disable(void)
{
#ifdef ENABLE_SERIAL
sSerialEnabled = 0;
#else
sSerialEnabled--;
#endif
}
extern "C" void
serial_enable(void)
{
sSerialEnabled++;
}
extern "C" void
serial_init(void)
{
uint16* ports = (uint16*)0x400;
memcpy(gKernelArgs.platform_args.serial_base_ports, ports,
sizeof(uint16) * MAX_SERIAL_PORTS);
if (gKernelArgs.platform_args.serial_base_ports[0] != 0)
sSerialBasePort = gKernelArgs.platform_args.serial_base_ports[0];
uint16 divisor = uint16(115200 / kSerialBaudRate);
out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);
out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);
#ifdef ENABLE_SERIAL
serial_enable();
#endif
}