1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 Axis Communications AB 4 * 5 * The console is useful for userspace applications which expect a console 6 * device to work without modifications even when no console is available 7 * or desired. 8 * 9 * In order to use this driver, you should redirect the console to this 10 * TTY, or boot the kernel with console=ttynull. 11 * 12 * Based on ttyprintk.c: 13 * Copyright (C) 2010 Samo Pogacnik 14 */ 15 16 #include <linux/console.h> 17 #include <linux/module.h> 18 #include <linux/tty.h> 19 20 static const struct tty_port_operations ttynull_port_ops; 21 static struct tty_driver *ttynull_driver; 22 static struct tty_port ttynull_port; 23 24 static int ttynull_open(struct tty_struct *tty, struct file *filp) 25 { 26 return tty_port_open(&ttynull_port, tty, filp); 27 } 28 29 static void ttynull_close(struct tty_struct *tty, struct file *filp) 30 { 31 tty_port_close(&ttynull_port, tty, filp); 32 } 33 34 static void ttynull_hangup(struct tty_struct *tty) 35 { 36 tty_port_hangup(&ttynull_port); 37 } 38 39 static int ttynull_write(struct tty_struct *tty, const unsigned char *buf, 40 int count) 41 { 42 return count; 43 } 44 45 static int ttynull_write_room(struct tty_struct *tty) 46 { 47 return 65536; 48 } 49 50 static const struct tty_operations ttynull_ops = { 51 .open = ttynull_open, 52 .close = ttynull_close, 53 .hangup = ttynull_hangup, 54 .write = ttynull_write, 55 .write_room = ttynull_write_room, 56 }; 57 58 static struct tty_driver *ttynull_device(struct console *c, int *index) 59 { 60 *index = 0; 61 return ttynull_driver; 62 } 63 64 static struct console ttynull_console = { 65 .name = "ttynull", 66 .device = ttynull_device, 67 }; 68 69 void __init register_ttynull_console(void) 70 { 71 if (!ttynull_driver) 72 return; 73 74 if (add_preferred_console(ttynull_console.name, 0, NULL)) 75 return; 76 77 register_console(&ttynull_console); 78 } 79 80 static int __init ttynull_init(void) 81 { 82 struct tty_driver *driver; 83 int ret; 84 85 driver = tty_alloc_driver(1, 86 TTY_DRIVER_RESET_TERMIOS | 87 TTY_DRIVER_REAL_RAW | 88 TTY_DRIVER_UNNUMBERED_NODE); 89 if (IS_ERR(driver)) 90 return PTR_ERR(driver); 91 92 tty_port_init(&ttynull_port); 93 ttynull_port.ops = &ttynull_port_ops; 94 95 driver->driver_name = "ttynull"; 96 driver->name = "ttynull"; 97 driver->type = TTY_DRIVER_TYPE_CONSOLE; 98 driver->init_termios = tty_std_termios; 99 driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; 100 tty_set_operations(driver, &ttynull_ops); 101 tty_port_link_device(&ttynull_port, driver, 0); 102 103 ret = tty_register_driver(driver); 104 if (ret < 0) { 105 put_tty_driver(driver); 106 tty_port_destroy(&ttynull_port); 107 return ret; 108 } 109 110 ttynull_driver = driver; 111 register_console(&ttynull_console); 112 113 return 0; 114 } 115 116 static void __exit ttynull_exit(void) 117 { 118 unregister_console(&ttynull_console); 119 tty_unregister_driver(ttynull_driver); 120 put_tty_driver(ttynull_driver); 121 tty_port_destroy(&ttynull_port); 122 } 123 124 module_init(ttynull_init); 125 module_exit(ttynull_exit); 126 127 MODULE_LICENSE("GPL v2"); 128