18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * ARAnyM console driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
58c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
68c2ecf20Sopenharmony_ci * for more details.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/console.h>
128c2ecf20Sopenharmony_ci#include <linux/tty.h>
138c2ecf20Sopenharmony_ci#include <linux/tty_driver.h>
148c2ecf20Sopenharmony_ci#include <linux/tty_flip.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/natfeat.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int stderr_id;
238c2ecf20Sopenharmony_cistatic struct tty_port nfcon_tty_port;
248c2ecf20Sopenharmony_cistatic struct tty_driver *nfcon_tty_driver;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic void nfputs(const char *str, unsigned int count)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	char buf[68];
298c2ecf20Sopenharmony_ci	unsigned long phys = virt_to_phys(buf);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	buf[64] = 0;
328c2ecf20Sopenharmony_ci	while (count > 64) {
338c2ecf20Sopenharmony_ci		memcpy(buf, str, 64);
348c2ecf20Sopenharmony_ci		nf_call(stderr_id, phys);
358c2ecf20Sopenharmony_ci		str += 64;
368c2ecf20Sopenharmony_ci		count -= 64;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci	memcpy(buf, str, count);
398c2ecf20Sopenharmony_ci	buf[count] = 0;
408c2ecf20Sopenharmony_ci	nf_call(stderr_id, phys);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void nfcon_write(struct console *con, const char *str,
448c2ecf20Sopenharmony_ci			unsigned int count)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	nfputs(str, count);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct tty_driver *nfcon_device(struct console *con, int *index)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	*index = 0;
528c2ecf20Sopenharmony_ci	return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic struct console nf_console = {
568c2ecf20Sopenharmony_ci	.name	= "nfcon",
578c2ecf20Sopenharmony_ci	.write	= nfcon_write,
588c2ecf20Sopenharmony_ci	.device	= nfcon_device,
598c2ecf20Sopenharmony_ci	.flags	= CON_PRINTBUFFER,
608c2ecf20Sopenharmony_ci	.index	= -1,
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int nfcon_tty_open(struct tty_struct *tty, struct file *filp)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void nfcon_tty_close(struct tty_struct *tty, struct file *filp)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int nfcon_tty_write(struct tty_struct *tty, const unsigned char *buf,
748c2ecf20Sopenharmony_ci			   int count)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	nfputs(buf, count);
778c2ecf20Sopenharmony_ci	return count;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int nfcon_tty_put_char(struct tty_struct *tty, unsigned char ch)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	char temp[2] = { ch, 0 };
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	nf_call(stderr_id, virt_to_phys(temp));
858c2ecf20Sopenharmony_ci	return 1;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int nfcon_tty_write_room(struct tty_struct *tty)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return 64;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic const struct tty_operations nfcon_tty_ops = {
948c2ecf20Sopenharmony_ci	.open		= nfcon_tty_open,
958c2ecf20Sopenharmony_ci	.close		= nfcon_tty_close,
968c2ecf20Sopenharmony_ci	.write		= nfcon_tty_write,
978c2ecf20Sopenharmony_ci	.put_char	= nfcon_tty_put_char,
988c2ecf20Sopenharmony_ci	.write_room	= nfcon_tty_write_room,
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#ifndef MODULE
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int __init nf_debug_setup(char *arg)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	if (strcmp(arg, "nfcon"))
1068c2ecf20Sopenharmony_ci		return 0;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	stderr_id = nf_get_id("NF_STDERR");
1098c2ecf20Sopenharmony_ci	if (stderr_id) {
1108c2ecf20Sopenharmony_ci		nf_console.flags |= CON_ENABLED;
1118c2ecf20Sopenharmony_ci		register_console(&nf_console);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciearly_param("debug", nf_debug_setup);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#endif /* !MODULE */
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int __init nfcon_init(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	int res;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	stderr_id = nf_get_id("NF_STDERR");
1268c2ecf20Sopenharmony_ci	if (!stderr_id)
1278c2ecf20Sopenharmony_ci		return -ENODEV;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	nfcon_tty_driver = alloc_tty_driver(1);
1308c2ecf20Sopenharmony_ci	if (!nfcon_tty_driver)
1318c2ecf20Sopenharmony_ci		return -ENOMEM;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	tty_port_init(&nfcon_tty_port);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	nfcon_tty_driver->driver_name = "nfcon";
1368c2ecf20Sopenharmony_ci	nfcon_tty_driver->name = "nfcon";
1378c2ecf20Sopenharmony_ci	nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
1388c2ecf20Sopenharmony_ci	nfcon_tty_driver->subtype = SYSTEM_TYPE_TTY;
1398c2ecf20Sopenharmony_ci	nfcon_tty_driver->init_termios = tty_std_termios;
1408c2ecf20Sopenharmony_ci	nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
1438c2ecf20Sopenharmony_ci	tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
1448c2ecf20Sopenharmony_ci	res = tty_register_driver(nfcon_tty_driver);
1458c2ecf20Sopenharmony_ci	if (res) {
1468c2ecf20Sopenharmony_ci		pr_err("failed to register nfcon tty driver\n");
1478c2ecf20Sopenharmony_ci		put_tty_driver(nfcon_tty_driver);
1488c2ecf20Sopenharmony_ci		tty_port_destroy(&nfcon_tty_port);
1498c2ecf20Sopenharmony_ci		return res;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (!(nf_console.flags & CON_ENABLED))
1538c2ecf20Sopenharmony_ci		register_console(&nf_console);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return 0;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void __exit nfcon_exit(void)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	unregister_console(&nf_console);
1618c2ecf20Sopenharmony_ci	tty_unregister_driver(nfcon_tty_driver);
1628c2ecf20Sopenharmony_ci	put_tty_driver(nfcon_tty_driver);
1638c2ecf20Sopenharmony_ci	tty_port_destroy(&nfcon_tty_port);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cimodule_init(nfcon_init);
1678c2ecf20Sopenharmony_cimodule_exit(nfcon_exit);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
170