Files
.github
.vscode
Architecture
Core
Crash
Driver
Memory
Video
CPU.cpp
Debugger.cpp
Disk.cpp
InterruptsManager.cpp
Lock.cpp
PeripheralComponentInterconnect.cpp
Power.cpp
README.md
Random.cpp
StackGuard.cpp
Symbols.cpp
SystemManagementBIOS.cpp
Time.cpp
Timer.cpp
UndefinedBehaviorSanitization.c
UniversalAsynchronousReceiverTransmitter.cpp
crashhandler.hpp
smbios.hpp
ubsan.h
Execute
FileSystem
Files
GUI
Library
Network
Profiling
Recovery
SystemCalls
Tasking
Tests
include
.gitignore
DAPI.hpp
Doxyfile
Fex.hpp
KConfig.cpp
KThread.cpp
Kernel.cpp
LICENSE
Makefile
README.md
dump.sh
ipc.h
kernel.h
syscalls.h
Kernel/Core/UniversalAsynchronousReceiverTransmitter.cpp
2023-03-14 00:02:24 +02:00

155 lines
4.3 KiB
C++

#include <uart.hpp>
#include <vector.hpp>
#include <debug.h>
volatile bool serialports[8] = {false, false, false, false, false, false, false, false};
Vector<UniversalAsynchronousReceiverTransmitter::Events *> RegisteredEvents;
#if defined(a64) || defined(a32)
NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port)
{
uint8_t Result;
asm("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
}
NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data)
{
asmv("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
}
#endif
namespace UniversalAsynchronousReceiverTransmitter
{
#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
/* TODO: Serial Port implementation needs reword. https://wiki.osdev.org/Serial_Ports */
SafeFunction NIF UART::UART(SerialPorts Port)
{
#if defined(a64) || defined(a32)
if (Port == COMNULL)
return;
this->Port = Port;
int PortNumber = 0;
switch (Port)
{
case COM1:
PortNumber = 0;
break;
case COM2:
PortNumber = 1;
break;
case COM3:
PortNumber = 2;
break;
case COM4:
PortNumber = 3;
break;
case COM5:
PortNumber = 4;
break;
case COM6:
PortNumber = 5;
break;
case COM7:
PortNumber = 6;
break;
case COM8:
PortNumber = 7;
break;
default:
return;
}
if (serialports[PortNumber])
return;
// Initialize the serial port
NoProfiler_outportb(Port + 1, 0x00); // Disable all interrupts
NoProfiler_outportb(Port + 3, SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
NoProfiler_outportb(Port + 0, SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud
NoProfiler_outportb(Port + 1, SERIAL_RATE_115200_HI); // (hi byte)
NoProfiler_outportb(Port + 3, 0x03); // 8 bits, no parity, one stop bit
NoProfiler_outportb(Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
NoProfiler_outportb(Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
// Check if the serial port is faulty.
if (NoProfiler_inportb(Port + 0) != 0xAE)
{
static int once = 0;
if (!once++)
warn("Serial port %#llx is faulty.", Port);
// serialports[Port] = false; // ignore for now
// return;
}
// Set to normal operation mode.
NoProfiler_outportb(Port + 4, 0x0F);
serialports[PortNumber] = true;
#endif
}
SafeFunction NIF UART::~UART() {}
SafeFunction NIF void UART::Write(uint8_t Char)
{
#if defined(a64) || defined(a32)
while ((NoProfiler_inportb(Port + 5) & SERIAL_BUFFER_EMPTY) == 0)
;
NoProfiler_outportb(Port, Char);
#endif
foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char);
}
SafeFunction NIF uint8_t UART::Read()
{
#if defined(a64) || defined(a32)
while ((NoProfiler_inportb(Port + 5) & 1) == 0)
;
return NoProfiler_inportb(Port);
#endif
foreach (auto e in RegisteredEvents)
{
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{
#if defined(a64) || defined(a32)
e->OnReceived(NoProfiler_inportb(Port));
#endif
}
}
}
SafeFunction NIF Events::Events(SerialPorts Port)
{
this->Port = Port;
RegisteredEvents.push_back(this);
}
SafeFunction NIF Events::~Events()
{
for (uintptr_t i = 0; i < RegisteredEvents.size(); i++)
if (RegisteredEvents[i] == this)
{
RegisteredEvents.remove(i);
return;
}
}
}