aboutsummaryrefslogtreecommitdiff
path: root/src/drv/ps1/sio
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-07-07 13:22:53 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-11 00:08:15 +0100
commit7861a52adf92a083bb2aed4c35f98d8035dce032 (patch)
tree28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /src/drv/ps1/sio
parent7fc48e9216ff809da5f8055a50b0be17628ef1df (diff)
downloadwnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz
Setup project skeleton
Diffstat (limited to 'src/drv/ps1/sio')
-rw-r--r--src/drv/ps1/sio/CMakeLists.txt22
-rw-r--r--src/drv/ps1/sio/include/drv/ps1/sio.h28
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h31
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h136
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h27
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/types.h65
-rw-r--r--src/drv/ps1/sio/src/CMakeLists.txt29
-rw-r--r--src/drv/ps1/sio/src/free.c23
-rw-r--r--src/drv/ps1/sio/src/globals.c21
-rw-r--r--src/drv/ps1/sio/src/init.c70
-rw-r--r--src/drv/ps1/sio/src/irq.c71
-rw-r--r--src/drv/ps1/sio/src/next.c34
-rw-r--r--src/drv/ps1/sio/src/read.c125
-rw-r--r--src/drv/ps1/sio/src/read_nb.c61
-rw-r--r--src/drv/ps1/sio/src/update.c98
-rw-r--r--src/drv/ps1/sio/src/write.c117
16 files changed, 958 insertions, 0 deletions
diff --git a/src/drv/ps1/sio/CMakeLists.txt b/src/drv/ps1/sio/CMakeLists.txt
new file mode 100644
index 0000000..f382e08
--- /dev/null
+++ b/src/drv/ps1/sio/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_sio)
+add_subdirectory(src)
+target_include_directories(drv_ps1_sio PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_sio
+ PUBLIC c
+ PRIVATE drv drv_ps1_bios drv_ps1_cpu drv_ps1_irq)
diff --git a/src/drv/ps1/sio/include/drv/ps1/sio.h b/src/drv/ps1/sio/include/drv/ps1/sio.h
new file mode 100644
index 0000000..3fabadd
--- /dev/null
+++ b/src/drv/ps1/sio/include/drv/ps1/sio.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_H
+#define DRV_PS1_SIO_H
+
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *ev);
+int drv_ps1_sio_update(struct drv_ps1_sio *sio);
+void drv_ps1_sio_free(struct drv_ps1_sio *sio);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
new file mode 100644
index 0000000..a481fa9
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_OPS_H
+#define DRV_PS1_SIO_OPS_H
+
+#include <drv/event.h>
+#include <sys/types.h>
+
+int drv_ps1_sio_read(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_sio_read_nb(void *buf, size_t n, void *args);
+int drv_ps1_sio_write(const void *buf, size_t n,
+ const struct drv_event_done *done, void *args);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
new file mode 100644
index 0000000..16b2bca
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
@@ -0,0 +1,136 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_REGS_H
+#define DRV_PS1_SIO_REGS_H
+
+#include <stdint.h>
+
+struct sio_tx_data
+{
+ uint32_t value :8, :24;
+};
+
+struct sio_rx_data
+{
+ uint8_t values[4];
+};
+
+union sio_stat
+{
+ struct
+ {
+ uint32_t
+ tx_ready_started :1,
+ rx_fifo_not_empty :1,
+ tx_ready_finished :1,
+ rx_parity_error :1,
+ rx_fifo_overrun :1,
+ rx_bad_stp :1,
+ rx_inverted :1,
+ dsr :1,
+ cts :1,
+ irqreq :1,
+ :1,
+ baudrate :15, :6;
+ } bits;
+
+ uint32_t mask;
+};
+
+union sio_mode
+{
+ struct
+ {
+ uint16_t
+ baudrate_mul :2,
+ len :2,
+ parity_en :1,
+ parity_odd :1,
+ stplen :2,
+ :8;
+ } bits;
+
+ uint16_t mask;
+};
+
+union sio_ctrl
+{
+ struct
+ {
+ uint16_t
+ tx_en :1,
+ dtr :1,
+ rx_en :1,
+ tx_invert :1,
+ ack :1,
+ rts :1,
+ reset :1,
+ :1,
+ rx_int_mode :2,
+ tx_int_en :1,
+ rx_int_en :1,
+ dsr_int_en :1,
+ :3;
+ } bits;
+
+ uint16_t mask;
+};
+
+enum
+{
+ SIO_CTRL_RX_INT_1,
+ SIO_CTRL_RX_INT_2,
+ SIO_CTRL_RX_INT_3,
+ SIO_CTRL_RX_INT_4
+};
+
+enum
+{
+ SIO_MODE_FACTOR_STOP,
+ SIO_MODE_FACTOR_MUL1,
+ SIO_MODE_FACTOR_MUL16,
+ SIO_MODE_FACTOR_MUL64
+};
+
+enum
+{
+ SIO_MODE_LEN_5,
+ SIO_MODE_LEN_6,
+ SIO_MODE_LEN_7,
+ SIO_MODE_LEN_8
+};
+
+enum
+{
+ SIO_MODE_STP_RESERVED,
+ SIO_MODE_STP_1,
+ SIO_MODE_STP_1_5,
+ SIO_MODE_STP_2,
+};
+
+#define SIO_BASE 0x1f801050
+#define SIO_REG(n) (SIO_BASE + n)
+#define SIO_TX_DATA ((volatile struct sio_tx_data *)SIO_REG(0))
+#define SIO_RX_DATA ((const volatile struct sio_rx_data *)SIO_REG(0))
+#define SIO_STAT ((const volatile union sio_stat *)SIO_REG(4))
+#define SIO_MODE ((volatile union sio_mode *)SIO_REG(8))
+#define SIO_CTRL ((volatile union sio_ctrl *)SIO_REG(10))
+#define SIO_BAUD (*(volatile uint16_t *)SIO_REG(14))
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
new file mode 100644
index 0000000..f5b97da
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_ROUTINES_H
+#define DRV_PS1_SIO_ROUTINES_H
+
+#include <drv/ps1/sio/types.h>
+
+int drv_ps1_sio_irq(void);
+int drv_ps1_sio_next(struct sio_fifo *f);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
new file mode 100644
index 0000000..87dd412
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
@@ -0,0 +1,65 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_TYPES_H
+#define DRV_PS1_SIO_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+
+struct sio_req
+{
+ union
+ {
+ struct sio_req_r
+ {
+ void *buf;
+ size_t n;
+ } r;
+
+ struct sio_req_w
+ {
+ const void *buf;
+ size_t n;
+ } w;
+ } u;
+
+ int (*f)(void);
+ struct drv_event_done done;
+ struct sio_req *next;
+};
+
+struct sio_fifo
+{
+ char buf[192];
+ size_t proc, pend;
+ struct sio_req *head, *tail;
+ int (*next)(void);
+};
+
+struct drv_ps1_sio
+{
+ bool init;
+ int event;
+ struct sio_fifo rx, tx;
+ struct drv_event ev;
+};
+
+extern struct drv_ps1_sio drv_ps1_sio;
+
+#endif
diff --git a/src/drv/ps1/sio/src/CMakeLists.txt b/src/drv/ps1/sio/src/CMakeLists.txt
new file mode 100644
index 0000000..1bcf5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/CMakeLists.txt
@@ -0,0 +1,29 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_sio PRIVATE
+ free.c
+ globals.c
+ init.c
+ irq.c
+ next.c
+ read.c
+ read_nb.c
+ update.c
+ write.c
+)
+
+target_link_libraries(drv_ps1_sio PRIVATE kprintf)
diff --git a/src/drv/ps1/sio/src/free.c b/src/drv/ps1/sio/src/free.c
new file mode 100644
index 0000000..5c506d0
--- /dev/null
+++ b/src/drv/ps1/sio/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+
+void drv_ps1_sio_free(struct drv_ps1_sio *const sio)
+{
+}
diff --git a/src/drv/ps1/sio/src/globals.c b/src/drv/ps1/sio/src/globals.c
new file mode 100644
index 0000000..35c72b8
--- /dev/null
+++ b/src/drv/ps1/sio/src/globals.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/types.h>
+
+struct drv_ps1_sio drv_ps1_sio;
diff --git a/src/drv/ps1/sio/src/init.c b/src/drv/ps1/sio/src/init.c
new file mode 100644
index 0000000..6bf44fc
--- /dev/null
+++ b/src/drv/ps1/sio/src/init.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *const ev)
+{
+ const unsigned long baudrate = 115200ul;
+
+ SIO_CTRL->bits.reset = 1;
+ SIO_BAUD = DRV_PS1_CPU_F / (16 * baudrate);
+ SIO_MODE->mask = (const union sio_mode)
+ {
+ .bits =
+ {
+ .baudrate_mul = SIO_MODE_FACTOR_MUL16,
+ .stplen = SIO_MODE_STP_1,
+ .len = SIO_MODE_LEN_8
+ }
+ }.mask;
+
+ SIO_CTRL->mask = (const union sio_ctrl)
+ {
+ .bits =
+ {
+ .rx_int_mode = SIO_CTRL_RX_INT_1,
+ .rx_int_en = 1,
+ .tx_en = 1,
+ .rx_en = 1,
+ .rts = 1,
+ .dtr = 1
+ }
+ }.mask;
+
+ static struct drv_ps1_irq_src src =
+ {
+ .mask = 1 << IRQ_SIO,
+ .fn = drv_ps1_sio_irq
+ };
+
+ if (drv_ps1_irq_set(&src))
+ return NULL;
+
+ I_MASK->bits.sio = 1;
+ drv_ps1_sio.ev = *ev;
+ return &drv_ps1_sio;
+}
diff --git a/src/drv/ps1/sio/src/irq.c b/src/drv/ps1/sio/src/irq.c
new file mode 100644
index 0000000..5a19d83
--- /dev/null
+++ b/src/drv/ps1/sio/src/irq.c
@@ -0,0 +1,71 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+int irq_sio_overrun;
+
+static int read_rx(struct sio_fifo *const f)
+{
+ const unsigned char v = *SIO_RX_DATA->values;
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ if (n == f->proc)
+ {
+ irq_sio_overrun = 1;
+ return -1;
+ }
+
+ f->buf[f->pend = n] = v;
+ return 0;
+}
+
+volatile unsigned sio_read;
+volatile int sw_overrun;
+
+int drv_ps1_sio_irq(void)
+{
+ SIO_CTRL->bits.rts = 0;
+
+ while (SIO_STAT->bits.rx_fifo_not_empty)
+ {
+ if (read_rx(&drv_ps1_sio.rx))
+ {
+ sw_overrun = 1;
+ break;
+ }
+
+ sio_read++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_STAT->bits.sio = 0;
+ SIO_CTRL->bits.ack = 1;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/next.c b/src/drv/ps1/sio/src/next.c
new file mode 100644
index 0000000..4c330ab
--- /dev/null
+++ b/src/drv/ps1/sio/src/next.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int drv_ps1_sio_next(struct sio_fifo *const f)
+{
+ struct sio_req *const next = f->head->next;
+
+ free(f->head);
+
+ f->next = next ? next->f : NULL;
+ f->head = next;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read.c b/src/drv/ps1/sio/src/read.c
new file mode 100644
index 0000000..e13ad29
--- /dev/null
+++ b/src/drv/ps1/sio/src/read.c
@@ -0,0 +1,125 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int load(void);
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+
+ if (!r->n)
+ {
+ const struct drv_event_done *const d = &req->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = load;
+ return 0;
+}
+
+static void read_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+ char *p = r->buf;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (r->n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ *p++ = f->buf[f->proc = n];
+ r->buf = p;
+ r->n--;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+}
+
+static int load(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req_r *const r = &f->head->u.r;
+
+ read_fifo(s);
+
+ if (!r->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = load,
+ .done = *done,
+ .u.r =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read_nb.c b/src/drv/ps1/sio/src/read_nb.c
new file mode 100644
index 0000000..755c5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/read_nb.c
@@ -0,0 +1,61 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/irq.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+
+static int read_fifo(char *buf, size_t n)
+{
+ int ret = 0;
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t m = f->proc + 1;
+
+ if (m >= sizeof f->buf)
+ m = 0;
+
+ *buf++ = f->buf[f->proc = m];
+ n--;
+ ret++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+ return ret;
+}
+
+int drv_ps1_sio_read_nb(void *const buf, const size_t n, void *const args)
+{
+ return read_fifo(buf, n);
+}
diff --git a/src/drv/ps1/sio/src/update.c b/src/drv/ps1/sio/src/update.c
new file mode 100644
index 0000000..eac875c
--- /dev/null
+++ b/src/drv/ps1/sio/src/update.c
@@ -0,0 +1,98 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+static int init(struct drv_ps1_sio *const s)
+{
+ if (s->init)
+ return 0;
+
+ const struct drv_event *const ev = &s->ev;
+ static const struct drv_event_ops ops =
+ {
+ .read = drv_ps1_sio_read,
+ .read_nb = drv_ps1_sio_read_nb,
+ .write = drv_ps1_sio_write
+ };
+
+ if (ev->status("ttyS0", &ops, true, 0660, ev->args))
+ return -1;
+
+ s->init = true;
+ return 0;
+}
+
+static int rx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+static void write_tx(struct sio_fifo *const f)
+{
+ if (f->proc == f->pend)
+ return;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ SIO_TX_DATA->value = f->buf[f->proc = n];
+}
+
+static int tx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+
+ if (SIO_STAT->bits.tx_ready_started)
+ write_tx(f);
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+int drv_ps1_sio_update(struct drv_ps1_sio *const s)
+{
+ if (SIO_STAT->bits.rx_fifo_overrun)
+ SIO_CTRL->bits.ack = 1;
+
+ if (init(s) || rx(s) || tx(s))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/write.c b/src/drv/ps1/sio/src/write.c
new file mode 100644
index 0000000..942456f
--- /dev/null
+++ b/src/drv/ps1/sio/src/write.c
@@ -0,0 +1,117 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+static int store(void);
+
+static void write_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+ const char *p = w->buf;
+
+ while (w->n)
+ {
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+ else if (n == f->proc)
+ break;
+
+ f->buf[f->pend = n] = *p++;
+ w->buf = p;
+ w->n--;
+ }
+}
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+
+ if (!w->n)
+ {
+ const struct drv_event_done *const d = &r->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = store;
+ return 0;
+}
+
+static int store(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req_w *const w = &f->head->u.w;
+
+ write_fifo(s);
+
+ if (!w->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = store,
+ .done = *done,
+ .u.w =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}