boredos_mirror/src/sys/tty.c

158 lines
4.6 KiB
C

// 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 <stdbool.h>
#include <stdint.h>
#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;
}