Espresso 0.0.2c
This commit is contained in:
382
drivers/new_tty.c
Normal file
382
drivers/new_tty.c
Normal file
@ -0,0 +1,382 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <processes.h>
|
||||
#include <sync.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
|
||||
|
||||
static tty_t ttys[MAX_TTYS];
|
||||
static uint8_t num_ttys = 0;
|
||||
static tty_t* active_tty = NULL;
|
||||
|
||||
static inline size_t next_index(size_t index)
|
||||
{
|
||||
return (index + 1) % TTY_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
static inline bool tty_empty(tty_t* tty)
|
||||
{
|
||||
return tty->head == tty->tail;
|
||||
}
|
||||
|
||||
static inline bool tty_full(tty_t* tty)
|
||||
{
|
||||
return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail;
|
||||
}
|
||||
|
||||
static inline bool is_canonical(tty_t* tty)
|
||||
{
|
||||
return (tty->flags & TTY_CANONICAL) != 0;
|
||||
}
|
||||
|
||||
tty_t* tty_get_active(void)
|
||||
{
|
||||
return active_tty;
|
||||
}
|
||||
|
||||
void tty_backspace(tty_t* tty)
|
||||
{
|
||||
if (tty->head == tty->tail)
|
||||
{
|
||||
return; /* buffer empty */
|
||||
}
|
||||
//tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ssize_t tty_read_active(char* buf, size_t count)
|
||||
{
|
||||
return tty_read(active_tty, buf, count);
|
||||
}
|
||||
|
||||
/*ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
|
||||
while (bytes_read < count)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (!tty_empty(tty))
|
||||
{
|
||||
char c = tty->input_buffer[tty->tail];
|
||||
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
|
||||
tty->tail = next_index(tty->tail);
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE(); /* change? *//*
|
||||
|
||||
buf[bytes_read++] = c;
|
||||
|
||||
if (is_canonical(tty) && c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}*/
|
||||
|
||||
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||
{
|
||||
if (!tty || !buf)
|
||||
return -1;
|
||||
|
||||
size_t bytes = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (!tty->line_ready)
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
continue; /* spin until newline */
|
||||
}
|
||||
|
||||
while (bytes < count && tty->tail != tty->head)
|
||||
{
|
||||
char c = tty->input_buffer[tty->tail];
|
||||
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
buf[bytes++] = c;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int input_buffer_put(tty_t* tty, char c)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
size_t next = next_index(tty->head);
|
||||
|
||||
if (next == tty->tail)
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_tty(void)
|
||||
{
|
||||
if (num_ttys >= MAX_TTYS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
tty_t* t = &ttys[0];
|
||||
|
||||
memset(t, 0, sizeof(tty_t));
|
||||
|
||||
t->flags = TTY_NORMAL;
|
||||
|
||||
active_tty = t;
|
||||
num_ttys = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tty_t* get_active_tty(void)
|
||||
{
|
||||
return active_tty;
|
||||
}
|
||||
|
||||
tty_t* make_tty(uint32_t flags)
|
||||
{
|
||||
if (num_ttys >= MAX_TTYS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tty_t* t = &ttys[num_ttys];
|
||||
|
||||
memset(t, 0, sizeof(tty_t));
|
||||
t->flags = flags;
|
||||
|
||||
num_ttys++;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void tty_receive_char(char c, uint32_t kbd_mod)
|
||||
{
|
||||
if (!active_tty || c == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c = tty_translate_char(c, kbd_mod);
|
||||
|
||||
/* Handle backspace */
|
||||
if (c == '\b')
|
||||
{
|
||||
tty_backspace(active_tty);
|
||||
|
||||
if (active_tty->head == active_tty->tail)
|
||||
{
|
||||
extern void terminal_putcharat(char c, uint16_t row, uint16_t column);
|
||||
terminal_putcharat('Z', 20, 20);
|
||||
}
|
||||
|
||||
if (active_tty->flags & TTY_ECHO)
|
||||
{
|
||||
/* erase character visually */
|
||||
putc('\b');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
input_buffer_put(active_tty, c);
|
||||
|
||||
if (active_tty->flags & TTY_ECHO)
|
||||
{
|
||||
if ((active_tty->flags & TTY_PASSWORD) == 0)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
putc('*');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tty_input_char(tty_t* tty, char c)
|
||||
{
|
||||
if (!tty || c == 0)
|
||||
return;
|
||||
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
/* backspace */
|
||||
if (c == '\b')
|
||||
{
|
||||
if (tty->head != tty->tail)
|
||||
{
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc('\b');/*
|
||||
putc(' ');
|
||||
putc('\b');*/
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t next = (tty->head + 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
if (next != tty->tail)
|
||||
{
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
}
|
||||
|
||||
char tty_translate_char(char c, uint32_t modifiers)
|
||||
{
|
||||
bool caps = (modifiers & MODIFIER_CAPS) != 0;
|
||||
bool shift = (modifiers & MODIFIER_SHIFT) != 0;
|
||||
bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0;
|
||||
|
||||
/* handle alphabetic characters */
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
if (caps ^ shift) /* XOR logic */
|
||||
{
|
||||
return c - 32; /* to uppercase */
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
if (caps ^ shift)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
return c + 32; /* to lowercase */
|
||||
}
|
||||
|
||||
/* handle ctrl (should later include control mapping/sending messages to processes via these) */
|
||||
if (ctrl)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
return c - 'a' + 1; /* Ctrl+A → 1 */
|
||||
}
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
return c - 'A' + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* shifted symbols (US layout) */
|
||||
if (shift)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '1':
|
||||
return '!';
|
||||
case '2':
|
||||
return '@';
|
||||
case '3':
|
||||
return '#';
|
||||
case '4':
|
||||
return '$';
|
||||
case '5':
|
||||
return '%';
|
||||
case '6':
|
||||
return '^';
|
||||
case '7':
|
||||
return '&';
|
||||
case '8':
|
||||
return '*';
|
||||
case '9':
|
||||
return '(';
|
||||
case '0':
|
||||
return ')';
|
||||
case '-':
|
||||
return '_';
|
||||
case '=':
|
||||
return '+';
|
||||
case '[':
|
||||
return '{';
|
||||
case ']':
|
||||
return '}';
|
||||
case ';':
|
||||
return ':';
|
||||
case '\'':
|
||||
return '"';
|
||||
case ',':
|
||||
return '<';
|
||||
case '.':
|
||||
return '>';
|
||||
case '/':
|
||||
return '?';
|
||||
case '\\':
|
||||
return '|';
|
||||
case '`':
|
||||
return '~';
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
Reference in New Issue
Block a user