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