diff --git a/src/kernel/boot/platform/bios_ia32/console.cpp b/src/kernel/boot/platform/bios_ia32/console.cpp index c4539ecdad..90c64f709e 100644 --- a/src/kernel/boot/platform/bios_ia32/console.cpp +++ b/src/kernel/boot/platform/bios_ia32/console.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "console.h" @@ -20,16 +21,110 @@ class Console : public ConsoleNode { virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); }; +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 uint16 *sScreenBase = (uint16 *)0xb8000; static uint32 sScreenWidth = 80; static uint32 sScreenHeight = 24; static uint32 sScreenOffset = 0; static uint16 sColor = 0x0f00; +static int32 sSerialEnabled = 0; +static uint16 sSerialBasePort = 0x3f8; + static Console sInput, sOutput; FILE *stdin, *stdout, *stderr; +// serial debug output + + +static void +serial_putc(char c) +{ + // wait until the transmitter empty bit is set + while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0) + ; + + out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER); +} + + +static void +serial_puts(const char *string, size_t size) +{ + 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) +{ +#if ENABLE_SERIAL + sSerialEnabled = 0; +#else + sSerialEnabled--; +#endif +} + + +extern "C" void +serial_enable(void) +{ + sSerialEnabled++; +} + + +static void +serial_init(void) +{ + // copy the base ports of the optional 4 serial ports to the kernel args + // 0x0000:0x0400 is the location of that information in the BIOS data segment + uint16 *ports = (uint16 *)0x400; + memcpy(gKernelArgs.platform_args.serial_base_ports, ports, sizeof(uint16) * MAX_SERIAL_PORTS); + + // only use the port if we could find one, else use the standard port + 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); /* set divisor latch access bit */ + out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW); + out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH); + out8(3, sSerialBasePort + SERIAL_LINE_CONTROL); /* 8N1 */ + +#ifdef ENABLE_SERIAL + serial_enable(); +#endif +} + + +// #pragma mark - + + static void scroll_up() { @@ -65,6 +160,9 @@ Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferS { const char *string = (const char *)buffer; + if (sSerialEnabled > 0) + serial_puts(string, bufferSize); + if (gKernelArgs.frame_buffer.enabled) return bufferSize; @@ -133,6 +231,7 @@ console_init(void) { // ToDo: make screen size changeable via stage2_args + serial_init(); console_clear_screen(); // enable stdio functionality diff --git a/src/kernel/boot/platform/bios_ia32/console.h b/src/kernel/boot/platform/bios_ia32/console.h index 645b6d3a53..dc96a79acd 100644 --- a/src/kernel/boot/platform/bios_ia32/console.h +++ b/src/kernel/boot/platform/bios_ia32/console.h @@ -1,6 +1,6 @@ /* ** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. +** Distributed under the terms of the Haiku License. */ #ifndef CONSOLE_H #define CONSOLE_H @@ -42,6 +42,9 @@ extern void console_set_color(int32 foreground, int32 background); extern status_t console_init(void); +extern void serial_disable(void); +extern void serial_enable(void); + #ifdef __cplusplus } #endif diff --git a/src/kernel/boot/platform/bios_ia32/start.c b/src/kernel/boot/platform/bios_ia32/start.c index 3447db905e..db3bb8c0c0 100644 --- a/src/kernel/boot/platform/bios_ia32/start.c +++ b/src/kernel/boot/platform/bios_ia32/start.c @@ -123,6 +123,8 @@ _start(void) // reading the keyboard doesn't seem to work in graphics mode (maybe a bochs problem) sBootOptions = check_for_boot_keys(); + if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) + serial_enable(); main(&args); }