// Copyright (c) 2023-2026 Chris (boreddevnl) // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. #include "tty.h" #include "spinlock.h" #include #include #define TTY_MAX 8 #define TTY_OUT_SIZE 16384 #define TTY_IN_SIZE 4096 typedef struct { bool used; int id; char out_buf[TTY_OUT_SIZE]; uint32_t out_head; uint32_t out_tail; char in_buf[TTY_IN_SIZE]; uint32_t in_head; uint32_t in_tail; int fg_pid; spinlock_t lock; } tty_t; static tty_t ttys[TTY_MAX] = {0}; extern void mem_memset(void *dest, int val, size_t len); static tty_t *tty_get(int tty_id) { if (tty_id < 0 || tty_id >= TTY_MAX) return NULL; if (!ttys[tty_id].used) return NULL; return &ttys[tty_id]; } int tty_create(void) { for (int i = 0; i < TTY_MAX; i++) { if (!ttys[i].used) { ttys[i].used = true; ttys[i].id = i; ttys[i].out_head = 0; ttys[i].out_tail = 0; ttys[i].in_head = 0; ttys[i].in_tail = 0; ttys[i].fg_pid = -1; ttys[i].lock = SPINLOCK_INIT; mem_memset(ttys[i].out_buf, 0, sizeof(ttys[i].out_buf)); mem_memset(ttys[i].in_buf, 0, sizeof(ttys[i].in_buf)); return i; } } return -1; } int tty_destroy(int tty_id) { if (tty_id < 0 || tty_id >= TTY_MAX) return -1; tty_t *tty = &ttys[tty_id]; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); if (!tty->used) { spinlock_release_irqrestore(&tty->lock, rflags); return -1; } tty->used = false; tty->id = -1; tty->out_head = 0; tty->out_tail = 0; tty->in_head = 0; tty->in_tail = 0; tty->fg_pid = -1; mem_memset(tty->out_buf, 0, sizeof(tty->out_buf)); mem_memset(tty->in_buf, 0, sizeof(tty->in_buf)); spinlock_release_irqrestore(&tty->lock, rflags); return 0; } static int tty_write_ring(char *buf, uint32_t size, uint32_t *head, uint32_t *tail, const char *data, size_t len) { int written = 0; for (size_t i = 0; i < len; i++) { uint32_t next = (*head + 1) % size; if (next == *tail) break; buf[*head] = data[i]; *head = next; written++; } return written; } static int tty_read_ring(char *buf, uint32_t size, uint32_t *head, uint32_t *tail, char *out, size_t max_len) { int read = 0; while (*tail != *head && (size_t)read < max_len) { out[read++] = buf[*tail]; *tail = (*tail + 1) % size; } return read; } int tty_write_output(int tty_id, const char *data, size_t len) { tty_t *tty = tty_get(tty_id); if (!tty || !data || len == 0) return 0; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); int written = tty_write_ring(tty->out_buf, TTY_OUT_SIZE, &tty->out_head, &tty->out_tail, data, len); spinlock_release_irqrestore(&tty->lock, rflags); return written; } int tty_read_output(int tty_id, char *buf, size_t max_len) { tty_t *tty = tty_get(tty_id); if (!tty || !buf || max_len == 0) return 0; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); int read = tty_read_ring(tty->out_buf, TTY_OUT_SIZE, &tty->out_head, &tty->out_tail, buf, max_len); spinlock_release_irqrestore(&tty->lock, rflags); return read; } int tty_write_input(int tty_id, const char *data, size_t len) { tty_t *tty = tty_get(tty_id); if (!tty || !data || len == 0) return 0; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); int written = tty_write_ring(tty->in_buf, TTY_IN_SIZE, &tty->in_head, &tty->in_tail, data, len); spinlock_release_irqrestore(&tty->lock, rflags); return written; } int tty_read_input(int tty_id, char *buf, size_t max_len) { tty_t *tty = tty_get(tty_id); if (!tty || !buf || max_len == 0) return 0; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); int read = tty_read_ring(tty->in_buf, TTY_IN_SIZE, &tty->in_head, &tty->in_tail, buf, max_len); spinlock_release_irqrestore(&tty->lock, rflags); return read; } int tty_set_foreground(int tty_id, int pid) { tty_t *tty = tty_get(tty_id); if (!tty) return -1; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); tty->fg_pid = pid; spinlock_release_irqrestore(&tty->lock, rflags); return 0; } int tty_get_foreground(int tty_id) { tty_t *tty = tty_get(tty_id); if (!tty) return -1; uint64_t rflags = spinlock_acquire_irqsave(&tty->lock); int pid = tty->fg_pid; spinlock_release_irqrestore(&tty->lock, rflags); return pid; }