kernel: tty: implement tty input using line disciplines
This commit is contained in:
@@ -25,6 +25,10 @@ extern size_t ringbuffer_avail(struct ringbuffer *buf);
|
|||||||
extern size_t ringbuffer_read(struct ringbuffer *buf, size_t size, void *buffer, socks_flags_t flags);
|
extern size_t ringbuffer_read(struct ringbuffer *buf, size_t size, void *buffer, socks_flags_t flags);
|
||||||
extern size_t ringbuffer_write(struct ringbuffer *buf, size_t size, const void *buffer, socks_flags_t flags);
|
extern size_t ringbuffer_write(struct ringbuffer *buf, size_t size, const void *buffer, socks_flags_t flags);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
//extern size_t ringbuffer_peek(struct ringbuffer *buf, size_t at, size_t size, void *buffer);
|
||||||
|
//extern size_t ringbuffer_skip(struct ringbuffer *buf, size_t count);
|
||||||
|
|
||||||
extern int ringbuffer_write_would_block(struct ringbuffer *buf);
|
extern int ringbuffer_write_would_block(struct ringbuffer *buf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#define TTY_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? (dev)->chr.c_tty : NULL)
|
#define TTY_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? (dev)->chr.c_tty : NULL)
|
||||||
#define TTY_DRIVER(drv) ((struct tty_driver *)((char *)drv - offsetof(struct tty_driver, tty_base)))
|
#define TTY_DRIVER(drv) ((struct tty_driver *)((char *)drv - offsetof(struct tty_driver, tty_base)))
|
||||||
|
|
||||||
|
#define TTY_EVENT_QUEUE_SIZE 4
|
||||||
|
#define TTY_INPUT_QUEUE_SIZE 256
|
||||||
|
|
||||||
struct kext;
|
struct kext;
|
||||||
|
|
||||||
/* The TTY system.
|
/* The TTY system.
|
||||||
@@ -56,6 +59,13 @@ enum tty_scroll_dir {
|
|||||||
TTY_SCROLL_UP,
|
TTY_SCROLL_UP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum tty_modifier_key {
|
||||||
|
TTY_KEY_OTHER = 0x00u,
|
||||||
|
TTY_KEY_CTRL = 0x01u,
|
||||||
|
TTY_KEY_ALT = 0x02u,
|
||||||
|
TTY_KEY_SHIFT = 0x04u,
|
||||||
|
};
|
||||||
|
|
||||||
/* character attribute. this could be as simple as VGA's 16-colour palette
|
/* character attribute. this could be as simple as VGA's 16-colour palette
|
||||||
plus an extra bit for bright, or a full 24-bit RGB value with bold and underline
|
plus an extra bit for bright, or a full 24-bit RGB value with bold and underline
|
||||||
support, depending on what the driver supports. */
|
support, depending on what the driver supports. */
|
||||||
@@ -81,19 +91,35 @@ struct tty_driver {
|
|||||||
struct tty_driver_ops *tty_ops;
|
struct tty_driver_ops *tty_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tty_ldisc {
|
||||||
|
char name[OBJECT_NAME_MAX];
|
||||||
|
void(*process_events)(struct device *);
|
||||||
|
};
|
||||||
|
|
||||||
struct tty_device {
|
struct tty_device {
|
||||||
unsigned int tty_xcells, tty_ycells;
|
unsigned int tty_xcells, tty_ycells;
|
||||||
unsigned int tty_xcur, tty_ycur;
|
unsigned int tty_xcur, tty_ycur;
|
||||||
unsigned int tty_iflag, tty_oflag, tty_lflag;
|
unsigned int tty_iflag, tty_oflag, tty_lflag;
|
||||||
tty_attrib_t tty_curattrib;
|
tty_attrib_t tty_curattrib;
|
||||||
|
|
||||||
|
enum tty_modifier_key tty_modstate;
|
||||||
|
|
||||||
|
struct tty_ldisc *tty_ldisc;
|
||||||
|
|
||||||
|
/* raw input events sent to the TTY */
|
||||||
|
struct ringbuffer tty_events;
|
||||||
|
/* input characters processed from tty_events, returned by tty_read() */
|
||||||
|
struct ringbuffer tty_input;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern kern_status_t tty_bootstrap(void);
|
extern kern_status_t tty_bootstrap(void);
|
||||||
|
extern struct tty_ldisc *tty_default_line_discipline(void);
|
||||||
|
|
||||||
extern struct device *tty_device_create(void);
|
extern struct device *tty_device_create(void);
|
||||||
extern kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, struct device *parent);
|
extern kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, struct device *parent);
|
||||||
|
|
||||||
extern void tty_set_printk_output(struct device *tty);
|
extern void tty_set_foreground(struct device *tty);
|
||||||
|
extern kern_status_t tty_connect_foreground_input_device(struct device *input);
|
||||||
|
|
||||||
extern struct tty_driver *tty_driver_create(struct kext *self, const char *name);
|
extern struct tty_driver *tty_driver_create(struct kext *self, const char *name);
|
||||||
extern kern_status_t tty_driver_destroy(struct tty_driver *drv);
|
extern kern_status_t tty_driver_destroy(struct tty_driver *drv);
|
||||||
@@ -106,6 +132,7 @@ static inline struct driver *tty_driver_base(struct tty_driver *drv)
|
|||||||
|
|
||||||
extern kern_status_t tty_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags);
|
extern kern_status_t tty_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags);
|
||||||
extern kern_status_t tty_write(struct device *tty, const void *buf, size_t len, size_t *nr_written, socks_flags_t flags);
|
extern kern_status_t tty_write(struct device *tty, const void *buf, size_t len, size_t *nr_written, socks_flags_t flags);
|
||||||
|
extern kern_status_t tty_report_event(struct device *tty, const struct input_event *ev);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
143
init/main.c
143
init/main.c
@@ -21,120 +21,6 @@ extern unsigned long get_rflags(void);
|
|||||||
|
|
||||||
extern char __pstart[], __pend[];
|
extern char __pstart[], __pend[];
|
||||||
|
|
||||||
static char keycode_chars[] = {
|
|
||||||
[KEY_UNKNOWN] = ' ',
|
|
||||||
[KEY_A] = 'a',
|
|
||||||
[KEY_B] = 'b',
|
|
||||||
[KEY_C] = 'c',
|
|
||||||
[KEY_D] = 'd',
|
|
||||||
[KEY_E] = 'e',
|
|
||||||
[KEY_F] = 'f',
|
|
||||||
[KEY_G] = 'g',
|
|
||||||
[KEY_H] = 'h',
|
|
||||||
[KEY_I] = 'i',
|
|
||||||
[KEY_J] = 'j',
|
|
||||||
[KEY_K] = 'k',
|
|
||||||
[KEY_L] = 'l',
|
|
||||||
[KEY_M] = 'm',
|
|
||||||
[KEY_N] = 'n',
|
|
||||||
[KEY_O] = 'o',
|
|
||||||
[KEY_P] = 'p',
|
|
||||||
[KEY_Q] = 'q',
|
|
||||||
[KEY_R] = 'r',
|
|
||||||
[KEY_S] = 's',
|
|
||||||
[KEY_T] = 't',
|
|
||||||
[KEY_U] = 'u',
|
|
||||||
[KEY_V] = 'v',
|
|
||||||
[KEY_W] = 'w',
|
|
||||||
[KEY_X] = 'x',
|
|
||||||
[KEY_Y] = 'y',
|
|
||||||
[KEY_Z] = 'z',
|
|
||||||
[KEY_KEY_1] = '1',
|
|
||||||
[KEY_KEY_2] = '2',
|
|
||||||
[KEY_KEY_3] = '3',
|
|
||||||
[KEY_KEY_4] = '4',
|
|
||||||
[KEY_KEY_5] = '5',
|
|
||||||
[KEY_KEY_6] = '6',
|
|
||||||
[KEY_KEY_7] = '7',
|
|
||||||
[KEY_KEY_8] = '8',
|
|
||||||
[KEY_KEY_9] = '9',
|
|
||||||
[KEY_KEY_0] = '0',
|
|
||||||
[KEY_ENTER] = '\n',
|
|
||||||
[KEY_ESCAPE] = 0,
|
|
||||||
[KEY_BACKSPACE] = '\b',
|
|
||||||
[KEY_TAB] = ' ',
|
|
||||||
[KEY_SPACE] = ' ',
|
|
||||||
[KEY_MINUS] = '-',
|
|
||||||
[KEY_EQUALS] = '=',
|
|
||||||
[KEY_LEFT_BRACE] = '[',
|
|
||||||
[KEY_RIGHT_BRACE] = ']',
|
|
||||||
[KEY_BACKSLASH] = '\\',
|
|
||||||
[KEY_NON_US_HASH] = 0,
|
|
||||||
[KEY_SEMICOLON] = ';',
|
|
||||||
[KEY_APOSTROPHE] = '\'',
|
|
||||||
[KEY_GRAVE_ACCENT] = 0,
|
|
||||||
[KEY_COMMA] = ',',
|
|
||||||
[KEY_DOT] = '.',
|
|
||||||
[KEY_SLASH] = '/',
|
|
||||||
[KEY_CAPS_LOCK] = 0,
|
|
||||||
[KEY_F1] = 0,
|
|
||||||
[KEY_F2] = 0,
|
|
||||||
[KEY_F3] = 0,
|
|
||||||
[KEY_F4] = 0,
|
|
||||||
[KEY_F5] = 0,
|
|
||||||
[KEY_F6] = 0,
|
|
||||||
[KEY_F7] = 0,
|
|
||||||
[KEY_F8] = 0,
|
|
||||||
[KEY_F9] = 0,
|
|
||||||
[KEY_F10] = 0,
|
|
||||||
[KEY_F11] = 0,
|
|
||||||
[KEY_F12] = 0,
|
|
||||||
[KEY_PRINT_SCREEN] = 0,
|
|
||||||
[KEY_SCROLL_LOCK] = 0,
|
|
||||||
[KEY_PAUSE] = 0,
|
|
||||||
[KEY_INSERT] = 0,
|
|
||||||
[KEY_HOME] = 0,
|
|
||||||
[KEY_PAGE_UP] = 0,
|
|
||||||
[KEY_DELETE] = 0,
|
|
||||||
[KEY_END] = 0,
|
|
||||||
[KEY_PAGE_DOWN] = 0,
|
|
||||||
[KEY_RIGHT] = 0,
|
|
||||||
[KEY_LEFT] = 0,
|
|
||||||
[KEY_DOWN] = 0,
|
|
||||||
[KEY_UP] = 0,
|
|
||||||
[KEY_NUM_LOCK] = 0,
|
|
||||||
[KEY_KEYPAD_SLASH] = '/',
|
|
||||||
[KEY_KEYPAD_ASTERISK] = '*',
|
|
||||||
[KEY_KEYPAD_MINUS] = '-',
|
|
||||||
[KEY_KEYPAD_PLUS] = '+',
|
|
||||||
[KEY_KEYPAD_ENTER] = '\n',
|
|
||||||
[KEY_KEYPAD_1] = '1',
|
|
||||||
[KEY_KEYPAD_2] = '2',
|
|
||||||
[KEY_KEYPAD_3] = '3',
|
|
||||||
[KEY_KEYPAD_4] = '4',
|
|
||||||
[KEY_KEYPAD_5] = '5',
|
|
||||||
[KEY_KEYPAD_6] = '6',
|
|
||||||
[KEY_KEYPAD_7] = '7',
|
|
||||||
[KEY_KEYPAD_8] = '8',
|
|
||||||
[KEY_KEYPAD_9] = '9',
|
|
||||||
[KEY_KEYPAD_0] = '0',
|
|
||||||
[KEY_KEYPAD_DOT] = '.',
|
|
||||||
[KEY_NON_US_BACKSLASH] = 0,
|
|
||||||
[KEY_KEYPAD_EQUALS] = '=',
|
|
||||||
[KEY_MENU] = 0,
|
|
||||||
[KEY_LEFT_CTRL] = 0,
|
|
||||||
[KEY_LEFT_SHIFT] = 0,
|
|
||||||
[KEY_LEFT_ALT] = 0,
|
|
||||||
[KEY_LEFT_META] = 0,
|
|
||||||
[KEY_RIGHT_CTRL] = 0,
|
|
||||||
[KEY_RIGHT_SHIFT] = 0,
|
|
||||||
[KEY_RIGHT_ALT] = 0,
|
|
||||||
[KEY_RIGHT_META] = 0,
|
|
||||||
[KEY_MEDIA_MUTE] = 0,
|
|
||||||
[KEY_MEDIA_VOLUME_INCREMENT] = 0,
|
|
||||||
[KEY_MEDIA_VOLUME_DECREMENT] = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
void print_kernel_banner(void)
|
void print_kernel_banner(void)
|
||||||
{
|
{
|
||||||
printk("Socks kernel version " BUILD_ID);
|
printk("Socks kernel version " BUILD_ID);
|
||||||
@@ -210,7 +96,7 @@ void kernel_init(uintptr_t arg)
|
|||||||
struct object *tty0;
|
struct object *tty0;
|
||||||
status = object_get("/dev/tty/tty0", &tty0);
|
status = object_get("/dev/tty/tty0", &tty0);
|
||||||
if (status == KERN_OK) {
|
if (status == KERN_OK) {
|
||||||
tty_set_printk_output(cast_to_device(tty0));
|
tty_set_foreground(cast_to_device(tty0));
|
||||||
}
|
}
|
||||||
|
|
||||||
create_kernel_thread(background_thread);
|
create_kernel_thread(background_thread);
|
||||||
@@ -220,31 +106,8 @@ void kernel_init(uintptr_t arg)
|
|||||||
run_all_tests();
|
run_all_tests();
|
||||||
|
|
||||||
status = object_get("/dev/input/input0", &kbd);
|
status = object_get("/dev/input/input0", &kbd);
|
||||||
if (status != KERN_OK) {
|
if (status == KERN_OK) {
|
||||||
printk("no keyboard available");
|
tty_connect_foreground_input_device(cast_to_device(kbd));
|
||||||
hang();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct input_event ev;
|
|
||||||
size_t r;
|
|
||||||
status = object_read(kbd, &ev, sizeof ev, &r, 0);
|
|
||||||
|
|
||||||
if (status != KERN_OK || r != sizeof ev) {
|
|
||||||
printk("keyboard read error: %s", kern_status_string(status));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev.ev_type != INPUT_TYPE_KEY || ev.ev_key.state != INPUT_KEYSTATE_DOWN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = keycode_chars[ev.ev_key.key];
|
|
||||||
if (c == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
putchar(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hang();
|
hang();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <socks/tty.h>
|
#include <socks/tty.h>
|
||||||
#include <socks/device.h>
|
#include <socks/device.h>
|
||||||
#include <socks/console.h>
|
#include <socks/console.h>
|
||||||
|
#include <socks/input.h>
|
||||||
#include <socks/libc/stdio.h>
|
#include <socks/libc/stdio.h>
|
||||||
|
|
||||||
static struct char_device_ops tty_ops = {
|
static struct char_device_ops tty_ops = {
|
||||||
@@ -8,12 +9,32 @@ static struct char_device_ops tty_ops = {
|
|||||||
.write = tty_write,
|
.write = tty_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct device *tty_printk_output = NULL;
|
static spin_lock_t foreground_lock;
|
||||||
|
static struct device *foreground = NULL;
|
||||||
|
static struct device *foreground_input = NULL;
|
||||||
|
|
||||||
|
static void tty_input_hook_callback(struct device *dev, struct input_event *ev, enum input_event_hook_flags *flags, void *arg)
|
||||||
|
{
|
||||||
|
struct device *fg_tty = foreground;
|
||||||
|
|
||||||
|
if (!fg_tty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tty_report_event(fg_tty, ev);
|
||||||
|
*flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct input_event_hook foreground_input_hook = {
|
||||||
|
.hook_callback = tty_input_hook_callback,
|
||||||
|
};
|
||||||
|
|
||||||
static void tty_console_write(struct console *con, const char *s, unsigned int len)
|
static void tty_console_write(struct console *con, const char *s, unsigned int len)
|
||||||
{
|
{
|
||||||
size_t nr_written;
|
if (foreground) {
|
||||||
tty_write(tty_printk_output, s, len, &nr_written, 0);
|
size_t nr_written;
|
||||||
|
tty_write(foreground, s, len, &nr_written, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct console tty_console = {
|
static struct console tty_console = {
|
||||||
@@ -30,10 +51,27 @@ struct device *tty_device_create(void)
|
|||||||
|
|
||||||
struct tty_device *tty_dev = kmalloc(sizeof *tty_dev, VM_NORMAL);
|
struct tty_device *tty_dev = kmalloc(sizeof *tty_dev, VM_NORMAL);
|
||||||
if (!tty_dev) {
|
if (!tty_dev) {
|
||||||
/* TODO destroy cdev */
|
object_deref(char_device_object(cdev));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kern_status_t status = ringbuffer_init(&tty_dev->tty_events, TTY_EVENT_QUEUE_SIZE * sizeof(struct input_event));
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
kfree(tty_dev);
|
||||||
|
object_deref(char_device_object(cdev));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ringbuffer_init(&tty_dev->tty_input, TTY_INPUT_QUEUE_SIZE * sizeof(char));
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
ringbuffer_deinit(&tty_dev->tty_events);
|
||||||
|
kfree(tty_dev);
|
||||||
|
object_deref(char_device_object(cdev));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tty_dev->tty_ldisc = tty_default_line_discipline();
|
||||||
|
|
||||||
cdev->c_ops = &tty_ops;
|
cdev->c_ops = &tty_ops;
|
||||||
cdev->c_tty = tty_dev;
|
cdev->c_tty = tty_dev;
|
||||||
|
|
||||||
@@ -62,16 +100,47 @@ kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner,
|
|||||||
return object_namespace_create_link(global_namespace(), link_path, &dev->dev_base);
|
return object_namespace_create_link(global_namespace(), link_path, &dev->dev_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_set_printk_output(struct device *tty)
|
void tty_set_foreground(struct device *tty)
|
||||||
{
|
{
|
||||||
bool console_init = false;
|
bool console_init = false;
|
||||||
if (tty_printk_output) {
|
if (foreground) {
|
||||||
console_init = true;
|
console_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_printk_output = tty;
|
foreground = tty;
|
||||||
|
|
||||||
if (!console_init) {
|
if (!console_init) {
|
||||||
console_register(&tty_console);
|
console_register(&tty_console);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kern_status_t tty_connect_foreground_input_device(struct device *input)
|
||||||
|
{
|
||||||
|
struct input_device *inputdev = INPUT_DEVICE(input);
|
||||||
|
if (!inputdev) {
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&foreground_lock, &flags);
|
||||||
|
|
||||||
|
if (foreground_input) {
|
||||||
|
struct device *prev = foreground_input;
|
||||||
|
foreground_input = NULL;
|
||||||
|
|
||||||
|
device_lock(prev);
|
||||||
|
input_device_remove_hook(prev, &foreground_input_hook);
|
||||||
|
device_unlock(prev);
|
||||||
|
object_deref(&prev->dev_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(&input->dev_base);
|
||||||
|
foreground_input = input;
|
||||||
|
device_lock(input);
|
||||||
|
input_device_add_hook(input, &foreground_input_hook);
|
||||||
|
device_unlock(input);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&foreground_lock, flags);
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|||||||
339
kernel/tty/ldisc.c
Normal file
339
kernel/tty/ldisc.c
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
#include <socks/tty.h>
|
||||||
|
#include <socks/input.h>
|
||||||
|
#include <socks/libc/ctype.h>
|
||||||
|
|
||||||
|
static void process_events(struct device *tty);
|
||||||
|
|
||||||
|
static char keycode_chars[] = {
|
||||||
|
[KEY_UNKNOWN] = ' ',
|
||||||
|
[KEY_A] = 'a',
|
||||||
|
[KEY_B] = 'b',
|
||||||
|
[KEY_C] = 'c',
|
||||||
|
[KEY_D] = 'd',
|
||||||
|
[KEY_E] = 'e',
|
||||||
|
[KEY_F] = 'f',
|
||||||
|
[KEY_G] = 'g',
|
||||||
|
[KEY_H] = 'h',
|
||||||
|
[KEY_I] = 'i',
|
||||||
|
[KEY_J] = 'j',
|
||||||
|
[KEY_K] = 'k',
|
||||||
|
[KEY_L] = 'l',
|
||||||
|
[KEY_M] = 'm',
|
||||||
|
[KEY_N] = 'n',
|
||||||
|
[KEY_O] = 'o',
|
||||||
|
[KEY_P] = 'p',
|
||||||
|
[KEY_Q] = 'q',
|
||||||
|
[KEY_R] = 'r',
|
||||||
|
[KEY_S] = 's',
|
||||||
|
[KEY_T] = 't',
|
||||||
|
[KEY_U] = 'u',
|
||||||
|
[KEY_V] = 'v',
|
||||||
|
[KEY_W] = 'w',
|
||||||
|
[KEY_X] = 'x',
|
||||||
|
[KEY_Y] = 'y',
|
||||||
|
[KEY_Z] = 'z',
|
||||||
|
[KEY_KEY_1] = '1',
|
||||||
|
[KEY_KEY_2] = '2',
|
||||||
|
[KEY_KEY_3] = '3',
|
||||||
|
[KEY_KEY_4] = '4',
|
||||||
|
[KEY_KEY_5] = '5',
|
||||||
|
[KEY_KEY_6] = '6',
|
||||||
|
[KEY_KEY_7] = '7',
|
||||||
|
[KEY_KEY_8] = '8',
|
||||||
|
[KEY_KEY_9] = '9',
|
||||||
|
[KEY_KEY_0] = '0',
|
||||||
|
[KEY_ENTER] = '\n',
|
||||||
|
[KEY_ESCAPE] = 0,
|
||||||
|
[KEY_BACKSPACE] = '\b',
|
||||||
|
[KEY_TAB] = ' ',
|
||||||
|
[KEY_SPACE] = ' ',
|
||||||
|
[KEY_MINUS] = '-',
|
||||||
|
[KEY_EQUALS] = '=',
|
||||||
|
[KEY_LEFT_BRACE] = '[',
|
||||||
|
[KEY_RIGHT_BRACE] = ']',
|
||||||
|
[KEY_BACKSLASH] = '\\',
|
||||||
|
[KEY_NON_US_HASH] = 0,
|
||||||
|
[KEY_SEMICOLON] = ';',
|
||||||
|
[KEY_APOSTROPHE] = '\'',
|
||||||
|
[KEY_GRAVE_ACCENT] = 0,
|
||||||
|
[KEY_COMMA] = ',',
|
||||||
|
[KEY_DOT] = '.',
|
||||||
|
[KEY_SLASH] = '/',
|
||||||
|
[KEY_CAPS_LOCK] = 0,
|
||||||
|
[KEY_F1] = 0,
|
||||||
|
[KEY_F2] = 0,
|
||||||
|
[KEY_F3] = 0,
|
||||||
|
[KEY_F4] = 0,
|
||||||
|
[KEY_F5] = 0,
|
||||||
|
[KEY_F6] = 0,
|
||||||
|
[KEY_F7] = 0,
|
||||||
|
[KEY_F8] = 0,
|
||||||
|
[KEY_F9] = 0,
|
||||||
|
[KEY_F10] = 0,
|
||||||
|
[KEY_F11] = 0,
|
||||||
|
[KEY_F12] = 0,
|
||||||
|
[KEY_PRINT_SCREEN] = 0,
|
||||||
|
[KEY_SCROLL_LOCK] = 0,
|
||||||
|
[KEY_PAUSE] = 0,
|
||||||
|
[KEY_INSERT] = 0,
|
||||||
|
[KEY_HOME] = 0,
|
||||||
|
[KEY_PAGE_UP] = 0,
|
||||||
|
[KEY_DELETE] = 0,
|
||||||
|
[KEY_END] = 0,
|
||||||
|
[KEY_PAGE_DOWN] = 0,
|
||||||
|
[KEY_RIGHT] = 0,
|
||||||
|
[KEY_LEFT] = 0,
|
||||||
|
[KEY_DOWN] = 0,
|
||||||
|
[KEY_UP] = 0,
|
||||||
|
[KEY_NUM_LOCK] = 0,
|
||||||
|
[KEY_KEYPAD_SLASH] = '/',
|
||||||
|
[KEY_KEYPAD_ASTERISK] = '*',
|
||||||
|
[KEY_KEYPAD_MINUS] = '-',
|
||||||
|
[KEY_KEYPAD_PLUS] = '+',
|
||||||
|
[KEY_KEYPAD_ENTER] = '\n',
|
||||||
|
[KEY_KEYPAD_1] = '1',
|
||||||
|
[KEY_KEYPAD_2] = '2',
|
||||||
|
[KEY_KEYPAD_3] = '3',
|
||||||
|
[KEY_KEYPAD_4] = '4',
|
||||||
|
[KEY_KEYPAD_5] = '5',
|
||||||
|
[KEY_KEYPAD_6] = '6',
|
||||||
|
[KEY_KEYPAD_7] = '7',
|
||||||
|
[KEY_KEYPAD_8] = '8',
|
||||||
|
[KEY_KEYPAD_9] = '9',
|
||||||
|
[KEY_KEYPAD_0] = '0',
|
||||||
|
[KEY_KEYPAD_DOT] = '.',
|
||||||
|
[KEY_NON_US_BACKSLASH] = 0,
|
||||||
|
[KEY_KEYPAD_EQUALS] = '=',
|
||||||
|
[KEY_MENU] = 0,
|
||||||
|
[KEY_LEFT_CTRL] = 0,
|
||||||
|
[KEY_LEFT_SHIFT] = 0,
|
||||||
|
[KEY_LEFT_ALT] = 0,
|
||||||
|
[KEY_LEFT_META] = 0,
|
||||||
|
[KEY_RIGHT_CTRL] = 0,
|
||||||
|
[KEY_RIGHT_SHIFT] = 0,
|
||||||
|
[KEY_RIGHT_ALT] = 0,
|
||||||
|
[KEY_RIGHT_META] = 0,
|
||||||
|
[KEY_MEDIA_MUTE] = 0,
|
||||||
|
[KEY_MEDIA_VOLUME_INCREMENT] = 0,
|
||||||
|
[KEY_MEDIA_VOLUME_DECREMENT] = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char keycode_chars_shift[] = {
|
||||||
|
[KEY_UNKNOWN] = ' ',
|
||||||
|
[KEY_A] = 'A',
|
||||||
|
[KEY_B] = 'B',
|
||||||
|
[KEY_C] = 'C',
|
||||||
|
[KEY_D] = 'D',
|
||||||
|
[KEY_E] = 'E',
|
||||||
|
[KEY_F] = 'F',
|
||||||
|
[KEY_G] = 'G',
|
||||||
|
[KEY_H] = 'H',
|
||||||
|
[KEY_I] = 'I',
|
||||||
|
[KEY_J] = 'J',
|
||||||
|
[KEY_K] = 'K',
|
||||||
|
[KEY_L] = 'L',
|
||||||
|
[KEY_M] = 'M',
|
||||||
|
[KEY_N] = 'N',
|
||||||
|
[KEY_O] = 'O',
|
||||||
|
[KEY_P] = 'P',
|
||||||
|
[KEY_Q] = 'Q',
|
||||||
|
[KEY_R] = 'R',
|
||||||
|
[KEY_S] = 'S',
|
||||||
|
[KEY_T] = 'T',
|
||||||
|
[KEY_U] = 'U',
|
||||||
|
[KEY_V] = 'V',
|
||||||
|
[KEY_W] = 'W',
|
||||||
|
[KEY_X] = 'X',
|
||||||
|
[KEY_Y] = 'Y',
|
||||||
|
[KEY_Z] = 'Z',
|
||||||
|
[KEY_KEY_1] = '!',
|
||||||
|
[KEY_KEY_2] = '"',
|
||||||
|
[KEY_KEY_3] = 0,
|
||||||
|
[KEY_KEY_4] = '$',
|
||||||
|
[KEY_KEY_5] = '%',
|
||||||
|
[KEY_KEY_6] = '^',
|
||||||
|
[KEY_KEY_7] = '&',
|
||||||
|
[KEY_KEY_8] = '*',
|
||||||
|
[KEY_KEY_9] = '(',
|
||||||
|
[KEY_KEY_0] = ')',
|
||||||
|
[KEY_ENTER] = '\n',
|
||||||
|
[KEY_ESCAPE] = 0,
|
||||||
|
[KEY_BACKSPACE] = '\b',
|
||||||
|
[KEY_TAB] = ' ',
|
||||||
|
[KEY_SPACE] = ' ',
|
||||||
|
[KEY_MINUS] = '_',
|
||||||
|
[KEY_EQUALS] = '+',
|
||||||
|
[KEY_LEFT_BRACE] = '{',
|
||||||
|
[KEY_RIGHT_BRACE] = '}',
|
||||||
|
[KEY_BACKSLASH] = '|',
|
||||||
|
[KEY_NON_US_HASH] = 0,
|
||||||
|
[KEY_SEMICOLON] = ':',
|
||||||
|
[KEY_APOSTROPHE] = '@',
|
||||||
|
[KEY_GRAVE_ACCENT] = 0,
|
||||||
|
[KEY_COMMA] = '<',
|
||||||
|
[KEY_DOT] = '>',
|
||||||
|
[KEY_SLASH] = '?',
|
||||||
|
[KEY_CAPS_LOCK] = 0,
|
||||||
|
[KEY_F1] = 0,
|
||||||
|
[KEY_F2] = 0,
|
||||||
|
[KEY_F3] = 0,
|
||||||
|
[KEY_F4] = 0,
|
||||||
|
[KEY_F5] = 0,
|
||||||
|
[KEY_F6] = 0,
|
||||||
|
[KEY_F7] = 0,
|
||||||
|
[KEY_F8] = 0,
|
||||||
|
[KEY_F9] = 0,
|
||||||
|
[KEY_F10] = 0,
|
||||||
|
[KEY_F11] = 0,
|
||||||
|
[KEY_F12] = 0,
|
||||||
|
[KEY_PRINT_SCREEN] = 0,
|
||||||
|
[KEY_SCROLL_LOCK] = 0,
|
||||||
|
[KEY_PAUSE] = 0,
|
||||||
|
[KEY_INSERT] = 0,
|
||||||
|
[KEY_HOME] = 0,
|
||||||
|
[KEY_PAGE_UP] = 0,
|
||||||
|
[KEY_DELETE] = 0,
|
||||||
|
[KEY_END] = 0,
|
||||||
|
[KEY_PAGE_DOWN] = 0,
|
||||||
|
[KEY_RIGHT] = 0,
|
||||||
|
[KEY_LEFT] = 0,
|
||||||
|
[KEY_DOWN] = 0,
|
||||||
|
[KEY_UP] = 0,
|
||||||
|
[KEY_NUM_LOCK] = 0,
|
||||||
|
[KEY_KEYPAD_SLASH] = '/',
|
||||||
|
[KEY_KEYPAD_ASTERISK] = '*',
|
||||||
|
[KEY_KEYPAD_MINUS] = '-',
|
||||||
|
[KEY_KEYPAD_PLUS] = '+',
|
||||||
|
[KEY_KEYPAD_ENTER] = '\n',
|
||||||
|
[KEY_KEYPAD_1] = '1',
|
||||||
|
[KEY_KEYPAD_2] = '2',
|
||||||
|
[KEY_KEYPAD_3] = '3',
|
||||||
|
[KEY_KEYPAD_4] = '4',
|
||||||
|
[KEY_KEYPAD_5] = '5',
|
||||||
|
[KEY_KEYPAD_6] = '6',
|
||||||
|
[KEY_KEYPAD_7] = '7',
|
||||||
|
[KEY_KEYPAD_8] = '8',
|
||||||
|
[KEY_KEYPAD_9] = '9',
|
||||||
|
[KEY_KEYPAD_0] = '0',
|
||||||
|
[KEY_KEYPAD_DOT] = '.',
|
||||||
|
[KEY_NON_US_BACKSLASH] = 0,
|
||||||
|
[KEY_KEYPAD_EQUALS] = '=',
|
||||||
|
[KEY_MENU] = 0,
|
||||||
|
[KEY_LEFT_CTRL] = 0,
|
||||||
|
[KEY_LEFT_SHIFT] = 0,
|
||||||
|
[KEY_LEFT_ALT] = 0,
|
||||||
|
[KEY_LEFT_META] = 0,
|
||||||
|
[KEY_RIGHT_CTRL] = 0,
|
||||||
|
[KEY_RIGHT_SHIFT] = 0,
|
||||||
|
[KEY_RIGHT_ALT] = 0,
|
||||||
|
[KEY_RIGHT_META] = 0,
|
||||||
|
[KEY_MEDIA_MUTE] = 0,
|
||||||
|
[KEY_MEDIA_VOLUME_INCREMENT] = 0,
|
||||||
|
[KEY_MEDIA_VOLUME_DECREMENT] = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct tty_ldisc default_ldisc = {
|
||||||
|
.name = "n_tty",
|
||||||
|
.process_events = process_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum tty_modifier_key get_modifier_key(struct input_event *ev)
|
||||||
|
{
|
||||||
|
switch (ev->ev_key.key) {
|
||||||
|
case KEY_LEFT_CTRL:
|
||||||
|
case KEY_RIGHT_CTRL:
|
||||||
|
return TTY_KEY_CTRL;
|
||||||
|
case KEY_LEFT_ALT:
|
||||||
|
case KEY_RIGHT_ALT:
|
||||||
|
return TTY_KEY_ALT;
|
||||||
|
case KEY_LEFT_SHIFT:
|
||||||
|
case KEY_RIGHT_SHIFT:
|
||||||
|
return TTY_KEY_SHIFT;
|
||||||
|
default:
|
||||||
|
return TTY_KEY_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_modifier_keys(struct device *tty, enum tty_modifier_key modkey, struct input_event *ev)
|
||||||
|
{
|
||||||
|
struct tty_device *ttydev = TTY_DEVICE(tty);
|
||||||
|
|
||||||
|
if (ev->ev_key.state == INPUT_KEYSTATE_DOWN) {
|
||||||
|
ttydev->tty_modstate |= modkey;
|
||||||
|
} else {
|
||||||
|
ttydev->tty_modstate &= ~modkey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_ev_to_chars(struct device *tty, struct input_event *ev)
|
||||||
|
{
|
||||||
|
if (ev->ev_key.state == INPUT_KEYSTATE_UP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tty_device *ttydev = TTY_DEVICE(tty);
|
||||||
|
|
||||||
|
char echo[2];
|
||||||
|
int echo_len = 0;
|
||||||
|
|
||||||
|
char c = keycode_chars[ev->ev_key.key];
|
||||||
|
if (c == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ttydev->tty_modstate & TTY_KEY_CTRL) {
|
||||||
|
if (!isalpha(c)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo[0] = '^';
|
||||||
|
echo[1] = toupper(c);
|
||||||
|
echo_len = 2;
|
||||||
|
|
||||||
|
c = tolower(c);
|
||||||
|
c -= 97;
|
||||||
|
c++;
|
||||||
|
} else if (ttydev->tty_modstate & TTY_KEY_SHIFT) {
|
||||||
|
c = keycode_chars_shift[ev->ev_key.key];
|
||||||
|
echo[0] = c;
|
||||||
|
echo_len = 1;
|
||||||
|
} else {
|
||||||
|
echo[0] = c;
|
||||||
|
echo_len = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ringbuffer_write(&ttydev->tty_input, sizeof c, &c, S_NOBLOCK);
|
||||||
|
size_t nr_written;
|
||||||
|
tty_write(tty, echo, echo_len, &nr_written, S_NOBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_events(struct device *tty)
|
||||||
|
{
|
||||||
|
struct tty_device *ttydev = TTY_DEVICE(tty);
|
||||||
|
struct ringbuffer *events = &ttydev->tty_events;
|
||||||
|
|
||||||
|
struct input_event ev;
|
||||||
|
|
||||||
|
size_t w = ringbuffer_read(events, sizeof ev, &ev, S_NOBLOCK);
|
||||||
|
|
||||||
|
if (w != sizeof ev || ev.ev_type != INPUT_TYPE_KEY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum tty_modifier_key modkeys = get_modifier_key(&ev);
|
||||||
|
|
||||||
|
if (modkeys != TTY_KEY_OTHER) {
|
||||||
|
handle_modifier_keys(tty, modkeys, &ev);
|
||||||
|
} else {
|
||||||
|
convert_ev_to_chars(tty, &ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tty_ldisc *tty_default_line_discipline(void)
|
||||||
|
{
|
||||||
|
return &default_ldisc;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <socks/tty.h>
|
#include <socks/tty.h>
|
||||||
|
#include <socks/input.h>
|
||||||
#include <socks/printk.h>
|
#include <socks/printk.h>
|
||||||
|
|
||||||
static void newline(struct device *tty)
|
static void newline(struct device *tty)
|
||||||
@@ -90,3 +91,36 @@ kern_status_t tty_write(struct device *tty, const void *buf, size_t len, size_t
|
|||||||
*nr_written = r;
|
*nr_written = r;
|
||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_events(struct device *tty)
|
||||||
|
{
|
||||||
|
struct tty_device *ttydev = TTY_DEVICE(tty);
|
||||||
|
|
||||||
|
if (!ttydev->tty_ldisc || !ttydev->tty_ldisc->process_events) {
|
||||||
|
struct input_event ev;
|
||||||
|
while (ringbuffer_unread(&ttydev->tty_events)) {
|
||||||
|
ringbuffer_read(&ttydev->tty_events, sizeof ev, &ev, S_NOBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ttydev->tty_ldisc->process_events(tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t tty_report_event(struct device *tty, const struct input_event *ev)
|
||||||
|
{
|
||||||
|
struct tty_device *ttydev = TTY_DEVICE(tty);
|
||||||
|
size_t w = ringbuffer_write(&ttydev->tty_events, sizeof *ev, ev, S_NOBLOCK);
|
||||||
|
|
||||||
|
if (w != sizeof *ev) {
|
||||||
|
return KERN_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ringbuffer_unread(&ttydev->tty_events) > 0) {
|
||||||
|
process_events(tty);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user