#include #include #include #include static struct char_device_ops tty_ops = { .read = tty_read, .write = tty_write, }; static struct device *tty_printk_output = NULL; 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); } static struct console tty_console = { .c_name = "tty", .c_write = tty_console_write, }; struct device *tty_device_create(void) { struct char_device *cdev = char_device_create(); if (!cdev) { return NULL; } struct tty_device *tty_dev = kmalloc(sizeof *tty_dev, VM_NORMAL); if (!tty_dev) { /* TODO destroy cdev */ return NULL; } cdev->c_ops = &tty_ops; cdev->c_tty = tty_dev; return char_device_base(cdev); } static kern_status_t generate_name(struct tty_driver *owner, struct device *dev, char out[DEV_NAME_MAX]) { /* minor numbers start at 1. subtract 1 to start at 0 instead */ snprintf(out, DEV_NAME_MAX, "%s%u", owner->tty_name, dev->dev_minor - 1); return KERN_OK; } kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, struct device *parent) { kern_status_t status = device_register(dev, tty_driver_base(owner), parent); if (status != KERN_OK) { return status; } char link_name[DEV_NAME_MAX]; generate_name(owner, dev, link_name); char link_path[OBJECT_PATH_MAX]; snprintf(link_path, sizeof link_path, "/dev/tty/%s", link_name); return object_namespace_create_link(global_namespace(), link_path, &dev->dev_base); } void tty_set_printk_output(struct device *tty) { bool console_init = false; if (tty_printk_output) { console_init = true; } tty_printk_output = tty; if (!console_init) { console_register(&tty_console); } }