2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2000 , 2002 Jeff Dike ( jdike @ karaya . com )
* Licensed under the GPL
*/
# include "linux/fs.h"
# include "linux/tty.h"
# include "linux/tty_driver.h"
# include "linux/major.h"
# include "linux/mm.h"
# include "linux/init.h"
# include "linux/console.h"
# include "asm/termbits.h"
# include "asm/irq.h"
# include "ssl.h"
2011-08-18 23:08:29 +04:00
# include "chan.h"
2005-04-17 02:20:36 +04:00
# include "init.h"
# include "irq_user.h"
# include "mconsole_kern.h"
2006-09-27 12:50:33 +04:00
static const int ssl_version = 1 ;
2005-04-17 02:20:36 +04:00
# define NR_PORTS 64
2006-02-01 14:06:29 +03:00
static void ssl_announce ( char * dev_name , int dev )
2005-04-17 02:20:36 +04:00
{
printk ( KERN_INFO " Serial line %d assigned device '%s' \n " , dev ,
dev_name ) ;
}
2007-02-10 12:44:06 +03:00
/* Almost const, except that xterm_title may be changed in an initcall */
2005-04-17 02:20:36 +04:00
static struct chan_opts opts = {
. announce = ssl_announce ,
. xterm_title = " Serial Line #%d " ,
. raw = 1 ,
} ;
2007-02-10 12:43:53 +03:00
static int ssl_config ( char * str , char * * error_out ) ;
2005-04-17 02:20:36 +04:00
static int ssl_get_config ( char * dev , char * str , int size , char * * error_out ) ;
2007-02-10 12:43:53 +03:00
static int ssl_remove ( int n , char * * error_out ) ;
2005-04-17 02:20:36 +04:00
2007-02-10 12:44:08 +03:00
/* Const, except for .mc.list */
2005-04-17 02:20:36 +04:00
static struct line_driver driver = {
. name = " UML serial line " ,
. device_name = " ttyS " ,
. major = TTY_MAJOR ,
. minor_start = 64 ,
. type = TTY_DRIVER_TYPE_SERIAL ,
. subtype = 0 ,
. read_irq = SSL_IRQ ,
. read_irq_name = " ssl " ,
. write_irq = SSL_WRITE_IRQ ,
. write_irq_name = " ssl-write " ,
. mc = {
2007-02-10 12:44:01 +03:00
. list = LIST_HEAD_INIT ( driver . mc . list ) ,
2005-04-17 02:20:36 +04:00
. name = " ssl " ,
. config = ssl_config ,
. get_config = ssl_get_config ,
2006-01-06 11:18:50 +03:00
. id = line_id ,
2005-04-17 02:20:36 +04:00
. remove = ssl_remove ,
} ,
} ;
2007-02-10 12:44:08 +03:00
/* The array is initialized by line_init, at initcall time. The
* elements are locked individually as needed .
2005-04-17 02:20:36 +04:00
*/
2011-09-10 01:25:00 +04:00
static char * conf [ NR_PORTS ] ;
static char * def_conf = CONFIG_SSL_CHAN ;
static struct line serial_lines [ NR_PORTS ] ;
2005-04-17 02:20:36 +04:00
2007-02-10 12:43:53 +03:00
static int ssl_config ( char * str , char * * error_out )
2005-04-17 02:20:36 +04:00
{
2007-02-10 12:43:53 +03:00
return line_config ( serial_lines , ARRAY_SIZE ( serial_lines ) , str , & opts ,
error_out ) ;
2005-04-17 02:20:36 +04:00
}
static int ssl_get_config ( char * dev , char * str , int size , char * * error_out )
{
2006-01-06 11:18:51 +03:00
return line_get_config ( dev , serial_lines , ARRAY_SIZE ( serial_lines ) , str ,
size , error_out ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-10 12:43:53 +03:00
static int ssl_remove ( int n , char * * error_out )
2005-04-17 02:20:36 +04:00
{
2007-02-10 12:43:53 +03:00
return line_remove ( serial_lines , ARRAY_SIZE ( serial_lines ) , n ,
error_out ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-01 14:06:29 +03:00
static int ssl_open ( struct tty_struct * tty , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2007-07-16 10:38:54 +04:00
int err = line_open ( serial_lines , tty ) ;
if ( err )
printk ( KERN_ERR " Failed to open serial line %d, err = %d \n " ,
tty - > index , err ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
#if 0
static void ssl_flush_buffer ( struct tty_struct * tty )
{
return ;
}
static void ssl_stop ( struct tty_struct * tty )
{
printk ( KERN_ERR " Someone should implement ssl_stop \n " ) ;
}
static void ssl_start ( struct tty_struct * tty )
{
printk ( KERN_ERR " Someone should implement ssl_start \n " ) ;
}
void ssl_hangup ( struct tty_struct * tty )
{
}
# endif
2006-09-27 12:50:33 +04:00
static const struct tty_operations ssl_ops = {
2005-04-17 02:20:36 +04:00
. open = ssl_open ,
. close = line_close ,
. write = line_write ,
. put_char = line_put_char ,
. write_room = line_write_room ,
. chars_in_buffer = line_chars_in_buffer ,
2005-05-01 19:58:56 +04:00
. flush_buffer = line_flush_buffer ,
. flush_chars = line_flush_chars ,
2005-04-17 02:20:36 +04:00
. set_termios = line_set_termios ,
. ioctl = line_ioctl ,
2006-01-06 11:18:58 +03:00
. throttle = line_throttle ,
. unthrottle = line_unthrottle ,
2005-04-17 02:20:36 +04:00
#if 0
. stop = ssl_stop ,
. start = ssl_start ,
. hangup = ssl_hangup ,
# endif
} ;
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
* by being an initcall and exitcall , respectively .
*/
static int ssl_init_done = 0 ;
static void ssl_console_write ( struct console * c , const char * string ,
unsigned len )
{
struct line * line = & serial_lines [ c - > index ] ;
2005-05-01 19:58:56 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2005-05-01 19:58:56 +04:00
spin_lock_irqsave ( & line - > lock , flags ) ;
2011-09-08 18:49:34 +04:00
console_write_chan ( line - > chan_out , string , len ) ;
2005-05-01 19:58:56 +04:00
spin_unlock_irqrestore ( & line - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
static struct tty_driver * ssl_console_device ( struct console * c , int * index )
{
* index = c - > index ;
2011-09-10 03:45:42 +04:00
return driver . driver ;
2005-04-17 02:20:36 +04:00
}
static int ssl_console_setup ( struct console * co , char * options )
{
struct line * line = & serial_lines [ co - > index ] ;
2007-02-10 12:44:06 +03:00
return console_open_chan ( line , co ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-10 12:44:08 +03:00
/* No locking for register_console call - relies on single-threaded initcalls */
2005-04-17 02:20:36 +04:00
static struct console ssl_cons = {
. name = " ttyS " ,
. write = ssl_console_write ,
. device = ssl_console_device ,
. setup = ssl_console_setup ,
2007-03-08 07:41:11 +03:00
. flags = CON_PRINTBUFFER | CON_ANYTIME ,
2005-04-17 02:20:36 +04:00
. index = - 1 ,
} ;
2006-02-01 14:06:29 +03:00
static int ssl_init ( void )
2005-04-17 02:20:36 +04:00
{
char * new_title ;
2011-09-10 03:45:42 +04:00
int err ;
2011-09-10 01:25:00 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:18:50 +03:00
printk ( KERN_INFO " Initializing software serial port version %d \n " ,
2005-04-17 02:20:36 +04:00
ssl_version ) ;
2011-09-10 01:25:00 +04:00
2011-09-10 03:45:42 +04:00
err = register_lines ( & driver , & ssl_ops , serial_lines ,
2007-02-10 12:44:08 +03:00
ARRAY_SIZE ( serial_lines ) ) ;
2011-09-10 03:45:42 +04:00
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
new_title = add_xterm_umid ( opts . xterm_title ) ;
if ( new_title ! = NULL )
opts . xterm_title = new_title ;
2011-09-10 04:07:05 +04:00
for ( i = 0 ; i < NR_PORTS ; i + + ) {
char * error ;
char * s = conf [ i ] ;
if ( ! s )
s = def_conf ;
if ( setup_one_line ( serial_lines , i , s , & opts , & error ) )
printk ( KERN_ERR " setup_one_line failed for "
" device %d : %s \n " , i , error ) ;
}
2007-05-07 01:51:16 +04:00
2005-04-17 02:20:36 +04:00
ssl_init_done = 1 ;
register_console ( & ssl_cons ) ;
2006-01-06 11:18:50 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
late_initcall ( ssl_init ) ;
static void ssl_exit ( void )
{
if ( ! ssl_init_done )
return ;
2006-01-06 11:18:51 +03:00
close_lines ( serial_lines , ARRAY_SIZE ( serial_lines ) ) ;
2005-04-17 02:20:36 +04:00
}
__uml_exitcall ( ssl_exit ) ;
static int ssl_chan_setup ( char * str )
{
2011-09-10 01:25:00 +04:00
line_setup ( conf , NR_PORTS , & def_conf , str , " serial line " ) ;
2007-02-10 12:43:53 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
__setup ( " ssl " , ssl_chan_setup ) ;
__channel_help ( ssl_chan_setup , " ssl " ) ;