kernel: tty: implement tty input using line disciplines
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <socks/tty.h>
|
||||
#include <socks/device.h>
|
||||
#include <socks/console.h>
|
||||
#include <socks/input.h>
|
||||
#include <socks/libc/stdio.h>
|
||||
|
||||
static struct char_device_ops tty_ops = {
|
||||
@@ -8,12 +9,32 @@ static struct char_device_ops tty_ops = {
|
||||
.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)
|
||||
{
|
||||
size_t nr_written;
|
||||
tty_write(tty_printk_output, s, len, &nr_written, 0);
|
||||
if (foreground) {
|
||||
size_t nr_written;
|
||||
tty_write(foreground, s, len, &nr_written, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (!tty_dev) {
|
||||
/* TODO destroy cdev */
|
||||
object_deref(char_device_object(cdev));
|
||||
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_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);
|
||||
}
|
||||
|
||||
void tty_set_printk_output(struct device *tty)
|
||||
void tty_set_foreground(struct device *tty)
|
||||
{
|
||||
bool console_init = false;
|
||||
if (tty_printk_output) {
|
||||
if (foreground) {
|
||||
console_init = true;
|
||||
}
|
||||
|
||||
tty_printk_output = tty;
|
||||
foreground = tty;
|
||||
|
||||
if (!console_init) {
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user