aboutsummaryrefslogtreecommitdiff
path: root/devices/uart/uart_16550.c
diff options
context:
space:
mode:
authoraqua <aqua@iserlohn-fortress.net>2023-03-12 14:53:27 +0200
committeraqua <aqua@iserlohn-fortress.net>2023-03-12 14:53:27 +0200
commit92e4b6d5522e53e6868b9b0c52b8e54d10bbf606 (patch)
treea23bd7054b6d0fdd9703e69035cd303d6b448e35 /devices/uart/uart_16550.c
parentMove all tests next to the code they're testing (diff)
downloadkernel-92e4b6d5522e53e6868b9b0c52b8e54d10bbf606.tar.xz
Add unit tests for C drivers
Diffstat (limited to 'devices/uart/uart_16550.c')
-rw-r--r--devices/uart/uart_16550.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/devices/uart/uart_16550.c b/devices/uart/uart_16550.c
new file mode 100644
index 0000000..61c349f
--- /dev/null
+++ b/devices/uart/uart_16550.c
@@ -0,0 +1,82 @@
+#include "uart_16550.h"
+#include <stddef.h>
+
+#ifdef __ARCH__
+#include <sys/io.h>
+#else
+unsigned char inb(unsigned short);
+void outb(unsigned char, unsigned short);
+#endif
+
+int
+uart_thre(enum UART port)
+{
+ return inb(port + LineStatus) & THRE;
+}
+
+void
+uart_putc(const FILE *self, char a)
+{
+ while (uart_thre((enum UART)self->id) == 0) {}
+ outb(a, self->id);
+
+ if (a == '\n') {
+ while (uart_thre((enum UART)self->id) == 0) {}
+ outb('\r', self->id);
+ }
+}
+
+int
+uart_puts(const FILE *self, const char *string, int length)
+{
+ int written = 0;
+
+ if (length == -1)
+ while (*string != '\0') {
+ uart_putc(self, *string);
+ ++string;
+ ++written;
+ }
+
+ else
+ for (int i = 0; i < length; ++i) {
+ uart_putc(self, string[i]);
+ ++written;
+ }
+
+ return written;
+}
+
+void
+uart_flush(__attribute__((unused)) const FILE *self)
+{
+}
+
+FILE uart_stream;
+
+FILE *
+uart_init(enum UART port)
+{
+ outb(0x00, port + 1); // Disable all interrupts
+ outb(0x80, port + 3); // Enable DLAB (set baud rate divisor)
+ outb(0x03, port + 0); // Set divisor to 3 (lo byte) 38400 baud
+ outb(0x00, port + 1); // (hi byte)
+ outb(0x03, port + 3); // 8 bits, no parity, one stop bit
+ outb(0xc7, port + 2); // Enable FIFO, clear them, with 14-byte threshold
+ outb(0x0b, port + 4); // IRQs enabled, RTS/DSR set
+ outb(0x1e, port + 4); // Set in loopback mode, test the serial chip
+ outb(0xae, port + 0); // Test serial chip (send byte 0xAE and check if serial
+ // returns same byte)
+
+ // Check if serial is faulty (i.e: not same byte as sent)
+ if (inb(port + 0) != 0xae) { return NULL; }
+
+ // If serial is not faulty set it in normal operation mode
+ // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
+ outb(0x0f, port + 4);
+ uart_stream.id = port;
+ // uart_stream.putc = &uart_putc;
+ // uart_stream.puts = &uart_puts;
+ // uart_stream.flush = &uart_flush;
+ return &uart_stream;
+}