Vhex-kernel/src/kernel/devices/tty/operations/write.c

179 lines
3.8 KiB
C

#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/util/atomic.h>
#include <lib/string.h>
/* tty_vertical_update() - Check / update TTY vertical cursor */
static void tty_vertical_update(struct tty_s *tty)
{
// Get next line.
if (tty->cursor.y + 1 <= tty->cursor.max.y)
tty->cursor.y = tty->cursor.y + 1;
else
tty->cursor.y = 0;
// Wipe new line.
memset(tty->buffers.output[tty->cursor.y], '\0', tty->cursor.max.x);
}
/* tty_horizontal_update() - Check / update TTY horizotal cursor */
static int tty_horizontal_update(struct tty_s *tty)
{
tty->cursor.x = tty->cursor.x + 1;
if (tty->cursor.x >= tty->cursor.max.x)
{
tty_vertical_update(tty);
tty->cursor.x = 0;
return (1);
}
return (0);
}
/* tty_buffer_update() - Line discipline */
static ssize_t tty_buffer_update(struct tty_s *tty, const uint8_t *buffer, size_t count)
{
int16_t offset;
ssize_t i;
i = -1;
while (++i < (ssize_t)count)
{
// Check bell char.
if (buffer[i] == '\a')
{
// TODO
continue;
}
// Check backspace.
if (buffer[i] == '\b')
{
if (tty->cursor.x > 0)
tty->cursor.x = tty->cursor.x - 1;
tty->buffers.output[tty->cursor.y][tty->cursor.x] = '\0';
continue;
}
// Check horizotal tab.
if (buffer[i] == '\t')
{
// Check if we need a new line or not.
offset = 5 - (tty->cursor.x - ((tty->cursor.x / 5) * 5));
if (tty->cursor.x + offset < tty->cursor.max.x)
{
memset(&tty->buffers.output[tty->cursor.y][tty->cursor.x], ' ', offset);
tty->cursor.x = tty->cursor.x + offset;
continue;
}
// If a new line is required char.
// Generate a new line.
tty->cursor.x = 0;
tty_vertical_update(tty);
continue;
}
// Check new line char.
if (buffer[i] == '\n')
{
tty->cursor.x = 0;
tty_vertical_update(tty);
continue;
}
// Check 'form feed' and 'vertical tab' char.
// @note: for now this character is interpreted like '\v'
if (buffer[i] == '\f' || buffer[i] == '\v')
{
tty_vertical_update(tty);
memset(tty->buffers.output[tty->cursor.y], ' ', tty->cursor.x);
continue;
}
// Check carriage return.
if (buffer[i] == '\r') { tty->cursor.x = 0; continue;}
// Update TTY buffer char.
tty->buffers.output[tty->cursor.y][tty->cursor.x] = buffer[i];
tty_horizontal_update(tty);
}
return (i);
}
// FIXME: this function is device-specific !
// TODO: Update me ?
static void tty_display(struct tty_s *tty)
{
int saved_start;
int line_len;
int line;
int start;
int y;
// Start atomic operation.
atomic_start();
// Get the "first" line and number of line.
// @note: circular buffer.
line = 0;
start = tty->cursor.y;
while (++line < tty->cursor.max.y)
{
// Update check line.
saved_start = start;
start = (start - 1 < 0) ? tty->cursor.max.y - 1 : start - 1;
// Check if the line existe.
if (tty->buffers.output[start][0] == '\0')
{
start = saved_start;
break;
}
}
// clear screen
dclear(&tty->disp);
// Display "on-screen" string lines.
y = -1;
while (++y < line)
{
// Display line
line_len = -1;
while (tty->buffers.output[start][++line_len] != '\0')
dascii(&tty->disp, line_len, y, tty->buffers.output[start][line_len]);
// Update row index
start = (start + 1 < tty->cursor.max.y) ? start + 1 : 0;
}
// Display on screen.
(*screen_update)(tty->disp.vram);
// Stop atomic operation
atomic_stop();
}
/* tty_write() - TTY write primitive ! */
ssize_t tty_write(void *inode, const void *buffer, size_t count)
{
ssize_t written;
// Start atomic operation.
atomic_start();
// Update internal buffer and display
// TTY on the screen.
written = tty_buffer_update(inode, buffer, count);
// TODO: Monotonic display ?
tty_display(inode);
// Stop atomic operation
atomic_stop();
// Return the number of char written into
// TTY's internal buffer.
return (written);
}