From e8e9f11022fb6ff4893643ae87285a5cbbb5483c Mon Sep 17 00:00:00 2001 From: Thomas Harrison Date: Sat, 12 Sep 2026 15:42:49 -0400 Subject: [PATCH 1/3] Agent Host changes for agents/update-serial-device-read-support-68b305b0 --- src/kernel/include/drivers/serial.h | 47 ++++++++++++++- src/kernel/include/kernel/device/serial.h | 3 +- src/kernel/src/drivers/serial.c | 41 +++++++++---- src/kernel/src/kernel/device/serial.c | 73 +++++++++++++++++------ 4 files changed, 130 insertions(+), 34 deletions(-) diff --git a/src/kernel/include/drivers/serial.h b/src/kernel/include/drivers/serial.h index f7b199c..7067470 100644 --- a/src/kernel/include/drivers/serial.h +++ b/src/kernel/include/drivers/serial.h @@ -17,10 +17,51 @@ enum SERIAL_PORT { SERIAL_PORT_COM8 = 0x4E8, }; +/** + * @brief Setup the serial port for 38400 baud, 8 bits, no parity, one stop bit. + * + * The chip is tested in loopback mode before being put into normal operation. + * + * @param port serial port base address + * @return 0 for success, 1 if the chip is faulty + */ int serial_init(uint16_t port); -char serial_read(uint16_t port); -void serial_write_str(uint16_t port, const char * str); -void serial_write(uint16_t port, const char * str, size_t count); +/** + * @brief Read a single character, blocking until one is received. + * + * @param port serial port base address + * @return character read + */ +char serial_read_char(uint16_t port); + +/** + * @brief Read count characters into buff, blocking until they are received. + * + * @param port serial port base address + * @param buff buffer to read into + * @param count number of characters to read + * @return number of characters read (0 for failure) + */ +size_t serial_read(uint16_t port, char * buff, size_t count); + +/** + * @brief Write a null terminated string. + * + * @param port serial port base address + * @param str characters to write + * @return number of characters written (0 for failure) + */ +size_t serial_write_str(uint16_t port, const char * str); + +/** + * @brief Write count characters from str. + * + * @param port serial port base address + * @param str characters to write + * @param count number of characters to write + * @return number of characters written (0 for failure) + */ +size_t serial_write(uint16_t port, const char * str, size_t count); #endif // DRIVERS_SERIAL_H diff --git a/src/kernel/include/kernel/device/serial.h b/src/kernel/include/kernel/device/serial.h index d68c5f1..08b4e60 100644 --- a/src/kernel/include/kernel/device/serial.h +++ b/src/kernel/include/kernel/device/serial.h @@ -2,10 +2,11 @@ #define KERNEL_DEVICE_SERIAL_H #include +#include #include "kernel/io/device.h" -io_device_t * io_device_serial_open(); +io_device_t * io_device_serial_open(uint16_t port); int io_device_serial_write_raw(int handle, const char * buff, size_t size, size_t pos); diff --git a/src/kernel/src/drivers/serial.c b/src/kernel/src/drivers/serial.c index b78c5e1..61fdd07 100644 --- a/src/kernel/src/drivers/serial.c +++ b/src/kernel/src/drivers/serial.c @@ -8,6 +8,9 @@ // TODO might need to disable interrupts while interacting with ports? +static int serial_received(uint16_t port); +static int is_transmit_empty(uint16_t port); + int serial_init(uint16_t port) { port_byte_out(port + 1, 0x00); // Disable all interrupts port_byte_out(port + 3, 0x80); // Enable DLAB (set baud rate divisor) @@ -30,32 +33,36 @@ int serial_init(uint16_t port) { return 0; } -static int serial_received(uint16_t port) { - return port_byte_in(port + 5) & 1; -} - -char serial_read(uint16_t port) { +char serial_read_char(uint16_t port) { while (serial_received(port) == 0); return port_byte_in(port); } -static int is_transmit_empty(uint16_t port) { - return port_byte_in(port + 5) & 0x20; +size_t serial_read(uint16_t port, char * buff, size_t count) { + if (!buff) { + return 0; + } + + for (size_t i = 0; i < count; i++) { + buff[i] = serial_read_char(port); + } + + return count; } -void serial_write_str(uint16_t port, const char * str) { +size_t serial_write_str(uint16_t port, const char * str) { if (!str) { - return; + return 0; } size_t count = kstrlen(str); - serial_write(port, str, count); + return serial_write(port, str, count); } -void serial_write(uint16_t port, const char * str, size_t count) { +size_t serial_write(uint16_t port, const char * str, size_t count) { if (!str) { - return; + return 0; } while (is_transmit_empty(port) == 0); @@ -63,4 +70,14 @@ void serial_write(uint16_t port, const char * str, size_t count) { for (size_t i = 0; i < count; i++) { port_byte_out(port, *str++); } + + return count; +} + +static int serial_received(uint16_t port) { + return port_byte_in(port + 5) & 1; +} + +static int is_transmit_empty(uint16_t port) { + return port_byte_in(port + 5) & 0x20; } diff --git a/src/kernel/src/kernel/device/serial.c b/src/kernel/src/kernel/device/serial.c index 333011e..6203479 100644 --- a/src/kernel/src/kernel/device/serial.c +++ b/src/kernel/src/kernel/device/serial.c @@ -4,37 +4,74 @@ #include "kernel/memory.h" #include "libc/string.h" +// WARNING the serial device backs kernel logging, so do not log in this file or +// you will get an infinite loop. + +typedef struct _serial_device { + uint16_t port; +} serial_device_t; + static int _serial_close(void * device_data); +static size_t _serial_read(void * device_data, char * buff, size_t size, size_t pos); static size_t _serial_write(void * device_data, const char * buff, size_t size, size_t pos); -io_device_t * io_device_serial_open() { - io_device_t * dev = kmalloc(sizeof(io_device_t)); - if (dev) { - kmemset(dev, 0, sizeof(io_device_t)); +io_device_t * io_device_serial_open(uint16_t port) { + serial_device_t * serial = kmalloc(sizeof(serial_device_t)); + if (!serial) { + return 0; + } - dev->flags = IO_DEVICE_FLAG_WRITE; + serial->port = port; - dev->close_fn = _serial_close; - dev->write_fn = _serial_write; + io_device_t * dev = kmalloc(sizeof(io_device_t)); + if (!dev) { + kfree(serial); + return 0; } + + kmemset(dev, 0, sizeof(io_device_t)); + + dev->flags = IO_DEVICE_FLAG_READ | IO_DEVICE_FLAG_WRITE; + + dev->close_fn = _serial_close; + dev->read_fn = _serial_read; + dev->write_fn = _serial_write; + + dev->device_data = serial; + return dev; } +// handle and pos not used +int io_device_serial_write_raw(int handle, const char * buff, size_t size, size_t pos) { + return serial_write(SERIAL_PORT_COM1, buff, size); +} + static int _serial_close(void * device_data) { - // Nothing to free + if (!device_data) { + return 1; + } + + kfree(device_data); return 0; } -// device_data and pos not used -static size_t _serial_write(void * device_data, const char * buff, size_t size, size_t pos) { - // TODO get a return value from driver - serial_write(SERIAL_PORT_COM1, buff, size); - return size; +// pos not used +static size_t _serial_read(void * device_data, char * buff, size_t size, size_t pos) { + if (!device_data || !buff) { + return 0; + } + + serial_device_t * serial = device_data; + return serial_read(serial->port, buff, size); } -// handle and pos not used -int io_device_serial_write_raw(int handle, const char * buff, size_t size, size_t pos) { - // TODO get a return value from driver - serial_write(SERIAL_PORT_COM1, buff, size); - return size; +// pos not used +static size_t _serial_write(void * device_data, const char * buff, size_t size, size_t pos) { + if (!device_data || !buff) { + return 0; + } + + serial_device_t * serial = device_data; + return serial_write(serial->port, buff, size); } From cd56aea8c25ac9a067f1574dc06425f24e030d75 Mon Sep 17 00:00:00 2001 From: Thomas Harrison Date: Sat, 12 Sep 2026 16:26:29 -0400 Subject: [PATCH 2/3] Update serial device read support in driver code --- src/kernel/src/drivers/serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/src/drivers/serial.c b/src/kernel/src/drivers/serial.c index 61fdd07..c08113c 100644 --- a/src/kernel/src/drivers/serial.c +++ b/src/kernel/src/drivers/serial.c @@ -65,9 +65,9 @@ size_t serial_write(uint16_t port, const char * str, size_t count) { return 0; } - while (is_transmit_empty(port) == 0); - for (size_t i = 0; i < count; i++) { + while (is_transmit_empty(port) == 0); + port_byte_out(port, *str++); } From ced9a0a666c16170e906c5d46dc036d711629cd5 Mon Sep 17 00:00:00 2001 From: Thomas Harrison Date: Sat, 12 Sep 2026 16:44:06 -0400 Subject: [PATCH 3/3] Add support for reading from serial devices in driver files --- src/kernel/include/drivers/serial.h | 9 +++++++++ src/kernel/src/drivers/serial.c | 12 +++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/kernel/include/drivers/serial.h b/src/kernel/include/drivers/serial.h index 7067470..ab91f68 100644 --- a/src/kernel/include/drivers/serial.h +++ b/src/kernel/include/drivers/serial.h @@ -45,6 +45,15 @@ char serial_read_char(uint16_t port); */ size_t serial_read(uint16_t port, char * buff, size_t count); +/** + * @brief Write a single character, blocking until it can be transmitted. + * + * @param port serial port base address + * @param c character to write + * @return number of characters written (0 for failure) + */ +size_t serial_write_char(uint16_t port, char c); + /** * @brief Write a null terminated string. * diff --git a/src/kernel/src/drivers/serial.c b/src/kernel/src/drivers/serial.c index c08113c..e075c1e 100644 --- a/src/kernel/src/drivers/serial.c +++ b/src/kernel/src/drivers/serial.c @@ -51,6 +51,14 @@ size_t serial_read(uint16_t port, char * buff, size_t count) { return count; } +size_t serial_write_char(uint16_t port, char c) { + while (is_transmit_empty(port) == 0); + + port_byte_out(port, c); + + return 1; +} + size_t serial_write_str(uint16_t port, const char * str) { if (!str) { return 0; @@ -66,9 +74,7 @@ size_t serial_write(uint16_t port, const char * str, size_t count) { } for (size_t i = 0; i < count; i++) { - while (is_transmit_empty(port) == 0); - - port_byte_out(port, *str++); + serial_write_char(port, str[i]); } return count;