137b0b65fSRoman Zippel /* 237b0b65fSRoman Zippel * ARAnyM console driver 337b0b65fSRoman Zippel * 437b0b65fSRoman Zippel * This file is subject to the terms and conditions of the GNU General Public 537b0b65fSRoman Zippel * License. See the file COPYING in the main directory of this archive 637b0b65fSRoman Zippel * for more details. 737b0b65fSRoman Zippel */ 837b0b65fSRoman Zippel 937b0b65fSRoman Zippel #include <linux/module.h> 1037b0b65fSRoman Zippel #include <linux/init.h> 1137b0b65fSRoman Zippel #include <linux/console.h> 1237b0b65fSRoman Zippel #include <linux/tty.h> 1337b0b65fSRoman Zippel #include <linux/tty_driver.h> 1437b0b65fSRoman Zippel #include <linux/tty_flip.h> 1537b0b65fSRoman Zippel #include <linux/slab.h> 1637b0b65fSRoman Zippel #include <linux/err.h> 1737b0b65fSRoman Zippel #include <linux/uaccess.h> 1855490050SGeert Uytterhoeven #include <linux/io.h> 1937b0b65fSRoman Zippel 2037b0b65fSRoman Zippel #include <asm/natfeat.h> 2137b0b65fSRoman Zippel 2237b0b65fSRoman Zippel static int stderr_id; 235920c2c9SJiri Slaby static struct tty_port nfcon_tty_port; 2437b0b65fSRoman Zippel static struct tty_driver *nfcon_tty_driver; 2537b0b65fSRoman Zippel 2637b0b65fSRoman Zippel static void nfputs(const char *str, unsigned int count) 2737b0b65fSRoman Zippel { 2837b0b65fSRoman Zippel char buf[68]; 2955490050SGeert Uytterhoeven unsigned long phys = virt_to_phys(buf); 3037b0b65fSRoman Zippel 3137b0b65fSRoman Zippel buf[64] = 0; 3237b0b65fSRoman Zippel while (count > 64) { 3337b0b65fSRoman Zippel memcpy(buf, str, 64); 3455490050SGeert Uytterhoeven nf_call(stderr_id, phys); 3537b0b65fSRoman Zippel str += 64; 3637b0b65fSRoman Zippel count -= 64; 3737b0b65fSRoman Zippel } 3837b0b65fSRoman Zippel memcpy(buf, str, count); 3937b0b65fSRoman Zippel buf[count] = 0; 4055490050SGeert Uytterhoeven nf_call(stderr_id, phys); 4137b0b65fSRoman Zippel } 4237b0b65fSRoman Zippel 4337b0b65fSRoman Zippel static void nfcon_write(struct console *con, const char *str, 4437b0b65fSRoman Zippel unsigned int count) 4537b0b65fSRoman Zippel { 4637b0b65fSRoman Zippel nfputs(str, count); 4737b0b65fSRoman Zippel } 4837b0b65fSRoman Zippel 4937b0b65fSRoman Zippel static struct tty_driver *nfcon_device(struct console *con, int *index) 5037b0b65fSRoman Zippel { 5137b0b65fSRoman Zippel *index = 0; 5237b0b65fSRoman Zippel return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL; 5337b0b65fSRoman Zippel } 5437b0b65fSRoman Zippel 5537b0b65fSRoman Zippel static struct console nf_console = { 5637b0b65fSRoman Zippel .name = "nfcon", 5737b0b65fSRoman Zippel .write = nfcon_write, 5837b0b65fSRoman Zippel .device = nfcon_device, 5937b0b65fSRoman Zippel .flags = CON_PRINTBUFFER, 6037b0b65fSRoman Zippel .index = -1, 6137b0b65fSRoman Zippel }; 6237b0b65fSRoman Zippel 6337b0b65fSRoman Zippel 6437b0b65fSRoman Zippel static int nfcon_tty_open(struct tty_struct *tty, struct file *filp) 6537b0b65fSRoman Zippel { 6637b0b65fSRoman Zippel return 0; 6737b0b65fSRoman Zippel } 6837b0b65fSRoman Zippel 6937b0b65fSRoman Zippel static void nfcon_tty_close(struct tty_struct *tty, struct file *filp) 7037b0b65fSRoman Zippel { 7137b0b65fSRoman Zippel } 7237b0b65fSRoman Zippel 7337b0b65fSRoman Zippel static int nfcon_tty_write(struct tty_struct *tty, const unsigned char *buf, 7437b0b65fSRoman Zippel int count) 7537b0b65fSRoman Zippel { 7637b0b65fSRoman Zippel nfputs(buf, count); 7737b0b65fSRoman Zippel return count; 7837b0b65fSRoman Zippel } 7937b0b65fSRoman Zippel 8037b0b65fSRoman Zippel static int nfcon_tty_put_char(struct tty_struct *tty, unsigned char ch) 8137b0b65fSRoman Zippel { 8237b0b65fSRoman Zippel char temp[2] = { ch, 0 }; 8337b0b65fSRoman Zippel 8455490050SGeert Uytterhoeven nf_call(stderr_id, virt_to_phys(temp)); 8537b0b65fSRoman Zippel return 1; 8637b0b65fSRoman Zippel } 8737b0b65fSRoman Zippel 88*03b3b1a2SJiri Slaby static unsigned int nfcon_tty_write_room(struct tty_struct *tty) 8937b0b65fSRoman Zippel { 9037b0b65fSRoman Zippel return 64; 9137b0b65fSRoman Zippel } 9237b0b65fSRoman Zippel 9337b0b65fSRoman Zippel static const struct tty_operations nfcon_tty_ops = { 9437b0b65fSRoman Zippel .open = nfcon_tty_open, 9537b0b65fSRoman Zippel .close = nfcon_tty_close, 9637b0b65fSRoman Zippel .write = nfcon_tty_write, 9737b0b65fSRoman Zippel .put_char = nfcon_tty_put_char, 9837b0b65fSRoman Zippel .write_room = nfcon_tty_write_room, 9937b0b65fSRoman Zippel }; 10037b0b65fSRoman Zippel 10137b0b65fSRoman Zippel #ifndef MODULE 10237b0b65fSRoman Zippel 10337b0b65fSRoman Zippel static int __init nf_debug_setup(char *arg) 10437b0b65fSRoman Zippel { 10537b0b65fSRoman Zippel if (strcmp(arg, "nfcon")) 10637b0b65fSRoman Zippel return 0; 10737b0b65fSRoman Zippel 10837b0b65fSRoman Zippel stderr_id = nf_get_id("NF_STDERR"); 10937b0b65fSRoman Zippel if (stderr_id) { 11037b0b65fSRoman Zippel nf_console.flags |= CON_ENABLED; 11137b0b65fSRoman Zippel register_console(&nf_console); 11237b0b65fSRoman Zippel } 11337b0b65fSRoman Zippel 11437b0b65fSRoman Zippel return 0; 11537b0b65fSRoman Zippel } 11637b0b65fSRoman Zippel 11737b0b65fSRoman Zippel early_param("debug", nf_debug_setup); 11837b0b65fSRoman Zippel 11937b0b65fSRoman Zippel #endif /* !MODULE */ 12037b0b65fSRoman Zippel 12137b0b65fSRoman Zippel static int __init nfcon_init(void) 12237b0b65fSRoman Zippel { 12337b0b65fSRoman Zippel int res; 12437b0b65fSRoman Zippel 12537b0b65fSRoman Zippel stderr_id = nf_get_id("NF_STDERR"); 12637b0b65fSRoman Zippel if (!stderr_id) 12737b0b65fSRoman Zippel return -ENODEV; 12837b0b65fSRoman Zippel 12937b0b65fSRoman Zippel nfcon_tty_driver = alloc_tty_driver(1); 13037b0b65fSRoman Zippel if (!nfcon_tty_driver) 13137b0b65fSRoman Zippel return -ENOMEM; 13237b0b65fSRoman Zippel 133191c5f10SJiri Slaby tty_port_init(&nfcon_tty_port); 134191c5f10SJiri Slaby 13537b0b65fSRoman Zippel nfcon_tty_driver->driver_name = "nfcon"; 13637b0b65fSRoman Zippel nfcon_tty_driver->name = "nfcon"; 13737b0b65fSRoman Zippel nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; 13837b0b65fSRoman Zippel nfcon_tty_driver->subtype = SYSTEM_TYPE_TTY; 13937b0b65fSRoman Zippel nfcon_tty_driver->init_termios = tty_std_termios; 14037b0b65fSRoman Zippel nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW; 14137b0b65fSRoman Zippel 14237b0b65fSRoman Zippel tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops); 1435920c2c9SJiri Slaby tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0); 14437b0b65fSRoman Zippel res = tty_register_driver(nfcon_tty_driver); 14537b0b65fSRoman Zippel if (res) { 14637b0b65fSRoman Zippel pr_err("failed to register nfcon tty driver\n"); 14737b0b65fSRoman Zippel put_tty_driver(nfcon_tty_driver); 148191c5f10SJiri Slaby tty_port_destroy(&nfcon_tty_port); 14937b0b65fSRoman Zippel return res; 15037b0b65fSRoman Zippel } 15137b0b65fSRoman Zippel 15237b0b65fSRoman Zippel if (!(nf_console.flags & CON_ENABLED)) 15337b0b65fSRoman Zippel register_console(&nf_console); 15437b0b65fSRoman Zippel 15537b0b65fSRoman Zippel return 0; 15637b0b65fSRoman Zippel } 15737b0b65fSRoman Zippel 15837b0b65fSRoman Zippel static void __exit nfcon_exit(void) 15937b0b65fSRoman Zippel { 16037b0b65fSRoman Zippel unregister_console(&nf_console); 16137b0b65fSRoman Zippel tty_unregister_driver(nfcon_tty_driver); 16237b0b65fSRoman Zippel put_tty_driver(nfcon_tty_driver); 163191c5f10SJiri Slaby tty_port_destroy(&nfcon_tty_port); 16437b0b65fSRoman Zippel } 16537b0b65fSRoman Zippel 16637b0b65fSRoman Zippel module_init(nfcon_init); 16737b0b65fSRoman Zippel module_exit(nfcon_exit); 16837b0b65fSRoman Zippel 16937b0b65fSRoman Zippel MODULE_LICENSE("GPL"); 170