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