| /* | |
| * ARAnyM console driver | |
| * | |
| * This file is subject to the terms and conditions of the GNU General Public | |
| * License. See the file COPYING in the main directory of this archive | |
| * for more details. | |
| */ | |
| #include <linux/module.h> | |
| #include <linux/init.h> | |
| #include <linux/console.h> | |
| #include <linux/tty.h> | |
| #include <linux/tty_driver.h> | |
| #include <linux/tty_flip.h> | |
| #include <linux/slab.h> | |
| #include <linux/err.h> | |
| #include <linux/uaccess.h> | |
| #include <linux/io.h> | |
| #include <asm/natfeat.h> | |
| static int stderr_id; | |
| static struct tty_port nfcon_tty_port; | |
| static struct tty_driver *nfcon_tty_driver; | |
| static void nfputs(const char *str, unsigned int count) | |
| { | |
| char buf[68]; | |
| unsigned long phys = virt_to_phys(buf); | |
| buf[64] = 0; | |
| while (count > 64) { | |
| memcpy(buf, str, 64); | |
| nf_call(stderr_id, phys); | |
| str += 64; | |
| count -= 64; | |
| } | |
| memcpy(buf, str, count); | |
| buf[count] = 0; | |
| nf_call(stderr_id, phys); | |
| } | |
| static void nfcon_write(struct console *con, const char *str, | |
| unsigned int count) | |
| { | |
| nfputs(str, count); | |
| } | |
| static struct tty_driver *nfcon_device(struct console *con, int *index) | |
| { | |
| *index = 0; | |
| return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL; | |
| } | |
| static struct console nf_console = { | |
| .name = "nfcon", | |
| .write = nfcon_write, | |
| .device = nfcon_device, | |
| .flags = CON_PRINTBUFFER, | |
| .index = -1, | |
| }; | |
| static int nfcon_tty_open(struct tty_struct *tty, struct file *filp) | |
| { | |
| return 0; | |
| } | |
| static void nfcon_tty_close(struct tty_struct *tty, struct file *filp) | |
| { | |
| } | |
| static int nfcon_tty_write(struct tty_struct *tty, const unsigned char *buf, | |
| int count) | |
| { | |
| nfputs(buf, count); | |
| return count; | |
| } | |
| static int nfcon_tty_put_char(struct tty_struct *tty, unsigned char ch) | |
| { | |
| char temp[2] = { ch, 0 }; | |
| nf_call(stderr_id, virt_to_phys(temp)); | |
| return 1; | |
| } | |
| static unsigned int nfcon_tty_write_room(struct tty_struct *tty) | |
| { | |
| return 64; | |
| } | |
| static const struct tty_operations nfcon_tty_ops = { | |
| .open = nfcon_tty_open, | |
| .close = nfcon_tty_close, | |
| .write = nfcon_tty_write, | |
| .put_char = nfcon_tty_put_char, | |
| .write_room = nfcon_tty_write_room, | |
| }; | |
| #ifndef MODULE | |
| static int __init nf_debug_setup(char *arg) | |
| { | |
| if (strcmp(arg, "nfcon")) | |
| return 0; | |
| stderr_id = nf_get_id("NF_STDERR"); | |
| if (stderr_id) { | |
| nf_console.flags |= CON_ENABLED; | |
| register_console(&nf_console); | |
| } | |
| return 0; | |
| } | |
| early_param("debug", nf_debug_setup); | |
| #endif /* !MODULE */ | |
| static int __init nfcon_init(void) | |
| { | |
| struct tty_driver *driver; | |
| int res; | |
| stderr_id = nf_get_id("NF_STDERR"); | |
| if (!stderr_id) | |
| return -ENODEV; | |
| driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); | |
| if (IS_ERR(driver)) | |
| return PTR_ERR(driver); | |
| tty_port_init(&nfcon_tty_port); | |
| driver->driver_name = "nfcon"; | |
| driver->name = "nfcon"; | |
| driver->type = TTY_DRIVER_TYPE_SYSTEM; | |
| driver->subtype = SYSTEM_TYPE_TTY; | |
| driver->init_termios = tty_std_termios; | |
| tty_set_operations(driver, &nfcon_tty_ops); | |
| tty_port_link_device(&nfcon_tty_port, driver, 0); | |
| res = tty_register_driver(driver); | |
| if (res) { | |
| pr_err("failed to register nfcon tty driver\n"); | |
| tty_driver_kref_put(driver); | |
| tty_port_destroy(&nfcon_tty_port); | |
| return res; | |
| } | |
| nfcon_tty_driver = driver; | |
| if (!(nf_console.flags & CON_ENABLED)) | |
| register_console(&nf_console); | |
| return 0; | |
| } | |
| static void __exit nfcon_exit(void) | |
| { | |
| unregister_console(&nf_console); | |
| tty_unregister_driver(nfcon_tty_driver); | |
| tty_driver_kref_put(nfcon_tty_driver); | |
| tty_port_destroy(&nfcon_tty_port); | |
| } | |
| module_init(nfcon_init); | |
| module_exit(nfcon_exit); | |
| MODULE_LICENSE("GPL"); |