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 20enum 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 32static const uint32 kSerialBaudRate = 115200; 33 34static int32 sSerialEnabled = 0; 35static uint16 sSerialBasePort = 0x3f8; 36 37static void 38serial_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 48extern "C" void 49serial_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 68extern "C" void 69serial_disable(void) 70{ 71#ifdef ENABLE_SERIAL 72 sSerialEnabled = 0; 73#else 74 sSerialEnabled--; 75#endif 76} 77 78 79extern "C" void 80serial_enable(void) 81{ 82 sSerialEnabled++; 83} 84 85 86extern "C" void 87serial_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