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; 52*de61a1a3SJohn Ogness return console_is_registered(con) ? 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 8803b3b1a2SJiri 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) { 110*de61a1a3SJohn Ogness /* 111*de61a1a3SJohn Ogness * The console will be enabled when debug=nfcon is specified 112*de61a1a3SJohn Ogness * as a kernel parameter. Since this is a non-standard way 113*de61a1a3SJohn Ogness * of enabling consoles, it must be explicitly enabled. 114*de61a1a3SJohn Ogness */ 11537b0b65fSRoman Zippel nf_console.flags |= CON_ENABLED; 11637b0b65fSRoman Zippel register_console(&nf_console); 11737b0b65fSRoman Zippel } 11837b0b65fSRoman Zippel 11937b0b65fSRoman Zippel return 0; 12037b0b65fSRoman Zippel } 12137b0b65fSRoman Zippel 12237b0b65fSRoman Zippel early_param("debug", nf_debug_setup); 12337b0b65fSRoman Zippel 12437b0b65fSRoman Zippel #endif /* !MODULE */ 12537b0b65fSRoman Zippel 12637b0b65fSRoman Zippel static int __init nfcon_init(void) 12737b0b65fSRoman Zippel { 1280524513aSJiri Slaby struct tty_driver *driver; 12937b0b65fSRoman Zippel int res; 13037b0b65fSRoman Zippel 13137b0b65fSRoman Zippel stderr_id = nf_get_id("NF_STDERR"); 13237b0b65fSRoman Zippel if (!stderr_id) 13337b0b65fSRoman Zippel return -ENODEV; 13437b0b65fSRoman Zippel 13539b7b42bSJiri Slaby driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); 13639b7b42bSJiri Slaby if (IS_ERR(driver)) 13739b7b42bSJiri Slaby return PTR_ERR(driver); 13837b0b65fSRoman Zippel 139191c5f10SJiri Slaby tty_port_init(&nfcon_tty_port); 140191c5f10SJiri Slaby 1410524513aSJiri Slaby driver->driver_name = "nfcon"; 1420524513aSJiri Slaby driver->name = "nfcon"; 1430524513aSJiri Slaby driver->type = TTY_DRIVER_TYPE_SYSTEM; 1440524513aSJiri Slaby driver->subtype = SYSTEM_TYPE_TTY; 1450524513aSJiri Slaby driver->init_termios = tty_std_termios; 14637b0b65fSRoman Zippel 1470524513aSJiri Slaby tty_set_operations(driver, &nfcon_tty_ops); 1480524513aSJiri Slaby tty_port_link_device(&nfcon_tty_port, driver, 0); 1490524513aSJiri Slaby res = tty_register_driver(driver); 15037b0b65fSRoman Zippel if (res) { 15137b0b65fSRoman Zippel pr_err("failed to register nfcon tty driver\n"); 1529f90a4ddSJiri Slaby tty_driver_kref_put(driver); 153191c5f10SJiri Slaby tty_port_destroy(&nfcon_tty_port); 15437b0b65fSRoman Zippel return res; 15537b0b65fSRoman Zippel } 15637b0b65fSRoman Zippel 1570524513aSJiri Slaby nfcon_tty_driver = driver; 1580524513aSJiri Slaby 159*de61a1a3SJohn Ogness if (!console_is_registered(&nf_console)) 16037b0b65fSRoman Zippel register_console(&nf_console); 16137b0b65fSRoman Zippel 16237b0b65fSRoman Zippel return 0; 16337b0b65fSRoman Zippel } 16437b0b65fSRoman Zippel 16537b0b65fSRoman Zippel static void __exit nfcon_exit(void) 16637b0b65fSRoman Zippel { 16737b0b65fSRoman Zippel unregister_console(&nf_console); 16837b0b65fSRoman Zippel tty_unregister_driver(nfcon_tty_driver); 1699f90a4ddSJiri Slaby tty_driver_kref_put(nfcon_tty_driver); 170191c5f10SJiri Slaby tty_port_destroy(&nfcon_tty_port); 17137b0b65fSRoman Zippel } 17237b0b65fSRoman Zippel 17337b0b65fSRoman Zippel module_init(nfcon_init); 17437b0b65fSRoman Zippel module_exit(nfcon_exit); 17537b0b65fSRoman Zippel 17637b0b65fSRoman Zippel MODULE_LICENSE("GPL"); 177