/*
* Copyright (c) 2017 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define ATCONS_ESC_SEQ_MAX_SIZE 8
static struct console atcons_console;
typedef void (*atcons_esc_seq_fn_t)(void);
struct atcons_esc_seq {
const char *str;
atcons_esc_seq_fn_t fn;
};
static bool atcons_escape;
static char atcons_esc_seq[ATCONS_ESC_SEQ_MAX_SIZE];
static unsigned int atcons_esc_seq_index;
static void
atcons_process_left(void)
{
cga_cursor_left();
}
static void
atcons_process_right(void)
{
cga_cursor_right();
}
static const struct atcons_esc_seq atcons_esc_seqs[] = {
{ "[1D", atcons_process_left },
{ "[1C", atcons_process_right },
};
static void
atcons_reset_esc_seq(void)
{
atcons_escape = false;
}
static int
atcons_esc_seq_lookup(const struct atcons_esc_seq **seqp)
{
const struct atcons_esc_seq *seq;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(atcons_esc_seqs); i++) {
seq = &atcons_esc_seqs[i];
if (strncmp(seq->str, atcons_esc_seq, atcons_esc_seq_index) == 0) {
if (strlen(seq->str) == atcons_esc_seq_index) {
*seqp = seq;
return 0;
} else {
return EAGAIN;
}
}
}
return ESRCH;
}
static void
atcons_process_esc_seq(char c)
{
const struct atcons_esc_seq *seq;
int error;
if (atcons_esc_seq_index >= sizeof(atcons_esc_seq)) {
atcons_reset_esc_seq();
return;
}
atcons_esc_seq[atcons_esc_seq_index] = c;
atcons_esc_seq_index++;
error = atcons_esc_seq_lookup(&seq);
if (error) {
if (error != EAGAIN) {
atcons_reset_esc_seq();
}
} else {
seq->fn();
atcons_reset_esc_seq();
}
}
static void
atcons_putc(struct console *console, char c)
{
(void)console;
if (c == '\e') {
atcons_escape = true;
atcons_esc_seq_index = 0;
} else if (atcons_escape) {
atcons_process_esc_seq(c);
} else {
cga_putc(c);
}
}
static const struct console_ops atcons_ops = {
.putc = atcons_putc,
};
static int __init
atcons_bootstrap(void)
{
console_init(&atcons_console, "atcons", &atcons_ops);
console_register(&atcons_console);
return 0;
}
INIT_OP_DEFINE(atcons_bootstrap,
INIT_OP_DEP(cga_setup, true),
INIT_OP_DEP(console_bootstrap, true));
static int __init
atcons_setup(void)
{
return 0;
}
INIT_OP_DEFINE(atcons_setup,
INIT_OP_DEP(atcons_bootstrap, true),
INIT_OP_DEP(atkbd_setup, true));
void
atcons_intr(const char *s)
{
console_intr(&atcons_console, s);
}
void
atcons_left(void)
{
atcons_intr("\e[D");
}
void
atcons_bottom(void)
{
atcons_intr("\e[B");
}
void
atcons_right(void)
{
atcons_intr("\e[C");
}
void
atcons_up(void)
{
atcons_intr("\e[A");
}