xref: /openbmc/linux/drivers/tty/ttynull.c (revision 7e60e389)
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