2005-06-23 22:01:33 -07:00
/*
2008-12-04 09:21:20 -08:00
* arch / xtensa / platforms / iss / console . c
2005-06-23 22:01:33 -07:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2001 - 2005 Tensilica Inc .
* Authors Christian Zankel , Joe Taylor
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/console.h>
# include <linux/init.h>
# include <linux/mm.h>
# include <linux/major.h>
# include <linux/param.h>
2009-03-31 15:19:24 -07:00
# include <linux/seq_file.h>
2005-06-23 22:01:33 -07:00
# include <linux/serial.h>
2016-12-24 11:46:01 -08:00
# include <linux/uaccess.h>
2005-06-23 22:01:33 -07:00
# include <asm/irq.h>
2008-12-04 09:21:20 -08:00
# include <platform/simcall.h>
2005-06-23 22:01:33 -07:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
# define SERIAL_MAX_NUM_LINES 1
2012-09-17 05:44:46 +04:00
# define SERIAL_TIMER_VALUE (HZ / 10)
2005-06-23 22:01:33 -07:00
2021-03-02 07:22:02 +01:00
static void rs_poll ( struct timer_list * ) ;
2005-06-23 22:01:33 -07:00
static struct tty_driver * serial_driver ;
2012-03-05 14:52:07 +01:00
static struct tty_port serial_port ;
2021-03-02 07:22:02 +01:00
static DEFINE_TIMER ( serial_timer , rs_poll ) ;
2005-06-23 22:01:33 -07:00
static int rs_open ( struct tty_struct * tty , struct file * filp )
{
2021-03-02 07:22:02 +01:00
if ( tty - > count = = 1 )
2005-06-23 22:01:33 -07:00
mod_timer ( & serial_timer , jiffies + SERIAL_TIMER_VALUE ) ;
return 0 ;
}
static void rs_close ( struct tty_struct * tty , struct file * filp )
{
if ( tty - > count = = 1 )
del_timer_sync ( & serial_timer ) ;
}
static int rs_write ( struct tty_struct * tty ,
const unsigned char * buf , int count )
{
/* see drivers/char/serialX.c to reference original version */
2012-10-15 03:55:33 +04:00
simc_write ( 1 , buf , count ) ;
2005-06-23 22:01:33 -07:00
return count ;
}
2017-10-19 16:40:49 -07:00
static void rs_poll ( struct timer_list * unused )
2005-06-23 22:01:33 -07:00
{
2017-10-19 16:40:49 -07:00
struct tty_port * port = & serial_port ;
2005-06-23 22:01:33 -07:00
int i = 0 ;
2016-02-09 01:02:38 +03:00
int rd = 1 ;
2005-06-23 22:01:33 -07:00
unsigned char c ;
2013-04-15 08:39:41 +04:00
while ( simc_poll ( 0 ) ) {
2016-02-09 01:02:38 +03:00
rd = simc_read ( 0 , & c , 1 ) ;
if ( rd < = 0 )
break ;
2013-01-03 15:53:03 +01:00
tty_insert_flip_char ( port , c , TTY_NORMAL ) ;
2005-06-23 22:01:33 -07:00
i + + ;
}
if ( i )
2013-01-03 15:53:06 +01:00
tty_flip_buffer_push ( port ) ;
2016-02-09 01:02:38 +03:00
if ( rd )
mod_timer ( & serial_timer , jiffies + SERIAL_TIMER_VALUE ) ;
2005-06-23 22:01:33 -07:00
}
2009-03-10 12:55:49 -07:00
static int rs_put_char ( struct tty_struct * tty , unsigned char ch )
2005-06-23 22:01:33 -07:00
{
2012-10-15 03:55:33 +04:00
return rs_write ( tty , & ch , 1 ) ;
2005-06-23 22:01:33 -07:00
}
static void rs_flush_chars ( struct tty_struct * tty )
{
}
2021-05-05 11:19:15 +02:00
static unsigned int rs_write_room ( struct tty_struct * tty )
2005-06-23 22:01:33 -07:00
{
/* Let's say iss can always accept 2K characters.. */
return 2 * 1024 ;
}
static void rs_hangup ( struct tty_struct * tty )
{
/* Stub, once again.. */
}
static void rs_wait_until_sent ( struct tty_struct * tty , int timeout )
{
/* Stub, once again.. */
}
2009-03-31 15:19:24 -07:00
static int rs_proc_show ( struct seq_file * m , void * v )
2005-06-23 22:01:33 -07:00
{
2021-03-02 07:21:59 +01:00
seq_printf ( m , " serinfo:1.0 driver:0.1 \n " ) ;
2009-03-31 15:19:24 -07:00
return 0 ;
}
2005-06-23 22:01:33 -07:00
2009-10-03 00:12:06 +04:00
static const struct tty_operations serial_ops = {
2005-06-23 22:01:33 -07:00
. open = rs_open ,
. close = rs_close ,
. write = rs_write ,
. put_char = rs_put_char ,
. flush_chars = rs_flush_chars ,
. write_room = rs_write_room ,
. hangup = rs_hangup ,
. wait_until_sent = rs_wait_until_sent ,
2018-04-13 21:04:45 +02:00
. proc_show = rs_proc_show ,
2005-06-23 22:01:33 -07:00
} ;
2021-03-02 07:22:03 +01:00
static int __init rs_init ( void )
2005-06-23 22:01:33 -07:00
{
2021-07-23 09:43:12 +02:00
struct tty_driver * driver ;
2021-07-23 09:43:10 +02:00
int ret ;
2012-03-05 14:52:07 +01:00
2021-07-23 09:43:13 +02:00
driver = tty_alloc_driver ( SERIAL_MAX_NUM_LINES , TTY_DRIVER_REAL_RAW ) ;
if ( IS_ERR ( driver ) )
return PTR_ERR ( driver ) ;
2021-07-23 09:43:10 +02:00
tty_port_init ( & serial_port ) ;
2005-06-23 22:01:33 -07:00
/* Initialize the tty_driver structure */
2021-07-23 09:43:12 +02:00
driver - > driver_name = " iss_serial " ;
driver - > name = " ttyS " ;
driver - > major = TTY_MAJOR ;
driver - > minor_start = 64 ;
driver - > type = TTY_DRIVER_TYPE_SERIAL ;
driver - > subtype = SERIAL_TYPE_NORMAL ;
driver - > init_termios = tty_std_termios ;
driver - > init_termios . c_cflag =
2005-06-23 22:01:33 -07:00
B9600 | CS8 | CREAD | HUPCL | CLOCAL ;
2021-07-23 09:43:12 +02:00
tty_set_operations ( driver , & serial_ops ) ;
tty_port_link_device ( & serial_port , driver , 0 ) ;
2005-06-23 22:01:33 -07:00
2021-07-23 09:43:12 +02:00
ret = tty_register_driver ( driver ) ;
2021-07-23 09:43:10 +02:00
if ( ret ) {
pr_err ( " Couldn't register serial driver \n " ) ;
2021-07-23 09:43:12 +02:00
tty_driver_kref_put ( driver ) ;
2021-07-23 09:43:10 +02:00
tty_port_destroy ( & serial_port ) ;
return ret ;
}
2021-07-23 09:43:12 +02:00
serial_driver = driver ;
2005-06-23 22:01:33 -07:00
return 0 ;
}
static __exit void rs_exit ( void )
{
2021-03-02 07:22:04 +01:00
tty_unregister_driver ( serial_driver ) ;
2021-07-23 09:43:16 +02:00
tty_driver_kref_put ( serial_driver ) ;
2012-11-15 09:49:56 +01:00
tty_port_destroy ( & serial_port ) ;
2005-06-23 22:01:33 -07:00
}
/* We use `late_initcall' instead of just `__initcall' as a workaround for
* the fact that ( 1 ) simcons_tty_init can ' t be called before tty_init ,
* ( 2 ) tty_init is called via ` module_init ' , ( 3 ) if statically linked ,
* module_init = = device_init , and ( 4 ) there ' s no ordering of init lists .
* We can do this easily because simcons is always statically linked , but
* other tty drivers that depend on tty_init and which must use
* ` module_init ' to declare their init routines are likely to be broken .
*/
late_initcall ( rs_init ) ;
# ifdef CONFIG_SERIAL_CONSOLE
static void iss_console_write ( struct console * co , const char * s , unsigned count )
{
2021-08-10 16:08:06 -07:00
if ( s & & * s ! = 0 ) {
int len = strlen ( s ) ;
2013-04-15 08:39:41 +04:00
simc_write ( 1 , s , count < len ? count : len ) ;
2021-08-10 16:08:06 -07:00
}
2005-06-23 22:01:33 -07:00
}
static struct tty_driver * iss_console_device ( struct console * c , int * index )
{
* index = c - > index ;
return serial_driver ;
}
static struct console sercons = {
. name = " ttyS " ,
. write = iss_console_write ,
. device = iss_console_device ,
. flags = CON_PRINTBUFFER ,
. index = - 1
} ;
static int __init iss_console_init ( void )
{
register_console ( & sercons ) ;
return 0 ;
}
console_initcall ( iss_console_init ) ;
# endif /* CONFIG_SERIAL_CONSOLE */