/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include #include namespace UART { enum SerialPorts { COM1 = 0x3F8, COM2 = 0x2F8, COM3 = 0x3E8, COM4 = 0x2E8, COM5 = 0x5F8, COM6 = 0x4F8, COM7 = 0x5E8, COM8 = 0x4E8 }; #define SERIAL_ENABLE_DLAB 0x80 #define SERIAL_RATE_115200_LO 0x01 #define SERIAL_RATE_115200_HI 0x00 #define SERIAL_RATE_57600_LO 0x02 #define SERIAL_RATE_57600_HI 0x00 #define SERIAL_RATE_38400_LO 0x03 #define SERIAL_RATE_38400_HI 0x00 #define SERIAL_BUFFER_EMPTY 0x20 void Driver::DebugWrite(uint8_t Char) { if (!DebugAvailable) return; #if defined(__amd64__) || defined(__i386__) while ((inb(s_cst(uint16_t, COM1 + 5)) & SERIAL_BUFFER_EMPTY) == 0) ; outb(COM1, Char); #endif } uint8_t Driver::DebugRead() { if (!DebugAvailable) return 0; #if defined(__amd64__) || defined(__i386__) while ((inb(s_cst(uint16_t, COM1 + 5)) & 1) == 0) ; return inb(COM1); #else return 0; #endif } void Driver::TTYWrite(uint8_t Char) { if (!TTYAvailable) return; #if defined(__amd64__) || defined(__i386__) while ((inb(s_cst(uint16_t, COM4 + 5)) & SERIAL_BUFFER_EMPTY) == 0) ; outb(COM4, Char); #endif } uint8_t Driver::TTYRead() { if (!TTYAvailable) return 0; #if defined(__amd64__) || defined(__i386__) while ((inb(s_cst(uint16_t, COM4 + 5)) & 1) == 0) ; return inb(COM4); #else return 0; #endif } Driver::Driver() { #if defined(__amd64__) || defined(__i386__) auto initPort = [](uint16_t Port) { // Initialize the serial port outb(s_cst(uint16_t, Port + 1), 0x00); // Disable all interrupts outb(s_cst(uint16_t, Port + 3), SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor) outb(s_cst(uint16_t, Port + 0), SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud outb(s_cst(uint16_t, Port + 1), SERIAL_RATE_115200_HI); // (hi byte) outb(s_cst(uint16_t, Port + 3), 0x03); // 8 bits, no parity, one stop bit outb(s_cst(uint16_t, Port + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold outb(s_cst(uint16_t, Port + 4), 0x0B); // IRQs enabled, RTS/DSR set /* FIXME https://wiki.osdev.org/Serial_Ports */ // outb(s_cst(uint16_t, Port + 0), 0x1E); // outb(s_cst(uint16_t, Port + 0), 0xAE); // Check if the serial port is faulty. // if (inb(s_cst(uint16_t, Port + 0)) != 0xAE) // { // static int once = 0; // if (!once++) // warn("Serial port %#lx is faulty.", Port); // // serialports[Port] = false; // ignore for now // // return; // } // Set to normal operation mode. outb(s_cst(uint16_t, Port + 4), 0x0F); }; uint8_t com = inb(COM1); if (com != 0xFF) { initPort(COM1); DebugAvailable = true; } com = inb(COM4); if (com != 0xFF) { initPort(COM4); TTYAvailable = true; } #endif } Driver::~Driver() {} }