2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 2000 , 2001 Jeff Dike ( jdike @ karaya . com )
* Licensed under the GPL
*/
# include "linux/posix_types.h"
# include "linux/tty.h"
# include "linux/tty_flip.h"
# include "linux/types.h"
# include "linux/major.h"
# include "linux/kdev_t.h"
# include "linux/console.h"
# include "linux/string.h"
# include "linux/sched.h"
# include "linux/list.h"
# include "linux/init.h"
# include "linux/interrupt.h"
# include "linux/slab.h"
# include "linux/hardirq.h"
# include "asm/current.h"
# include "asm/irq.h"
# include "stdio_console.h"
# include "line.h"
# include "chan_kern.h"
# include "irq_user.h"
# include "mconsole_kern.h"
# include "init.h"
# define MAX_TTYS (16)
/* Referenced only by tty_driver below - presumably it's locked correctly
* by the tty driver .
*/
static struct tty_driver * console_driver ;
2008-04-28 02:13:57 -07:00
static void stdio_announce ( char * dev_name , int dev )
2005-04-16 15:20:36 -07:00
{
printk ( KERN_INFO " Virtual console %d assigned device '%s' \n " , dev ,
dev_name ) ;
}
2007-02-10 01:44:06 -08:00
/* Almost const, except that xterm_title may be changed in an initcall */
2005-04-16 15:20:36 -07:00
static struct chan_opts opts = {
. announce = stdio_announce ,
. xterm_title = " Virtual Console #%d " ,
. raw = 1 ,
} ;
2007-02-10 01:43:53 -08:00
static int con_config ( char * str , char * * error_out ) ;
2005-04-16 15:20:36 -07:00
static int con_get_config ( char * dev , char * str , int size , char * * error_out ) ;
2007-02-10 01:43:53 -08:00
static int con_remove ( int n , char * * con_remove ) ;
2005-04-16 15:20:36 -07:00
2007-02-10 01:44:08 -08:00
/* Const, except for .mc.list */
2005-04-16 15:20:36 -07:00
static struct line_driver driver = {
. name = " UML console " ,
. device_name = " tty " ,
. major = TTY_MAJOR ,
. minor_start = 0 ,
. type = TTY_DRIVER_TYPE_CONSOLE ,
. subtype = SYSTEM_TYPE_CONSOLE ,
. read_irq = CONSOLE_IRQ ,
. read_irq_name = " console " ,
. write_irq = CONSOLE_WRITE_IRQ ,
. write_irq_name = " console-write " ,
. mc = {
2007-02-10 01:44:11 -08:00
. list = LIST_HEAD_INIT ( driver . mc . list ) ,
2005-04-16 15:20:36 -07:00
. name = " con " ,
. config = con_config ,
. get_config = con_get_config ,
2006-01-06 00:18:50 -08:00
. id = line_id ,
2005-04-16 15:20:36 -07:00
. remove = con_remove ,
} ,
} ;
2007-02-10 01:44:08 -08:00
/* The array is initialized by line_init, at initcall time. The
* elements are locked individually as needed .
2005-04-16 15:20:36 -07:00
*/
2007-02-10 01:43:52 -08:00
static struct line vts [ MAX_TTYS ] = { LINE_INIT ( CONFIG_CON_ZERO_CHAN , & driver ) ,
[ 1 . . . MAX_TTYS - 1 ] =
LINE_INIT ( CONFIG_CON_CHAN , & driver ) } ;
2005-04-16 15:20:36 -07:00
2007-02-10 01:43:53 -08:00
static int con_config ( char * str , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2007-02-10 01:43:53 -08:00
return line_config ( vts , ARRAY_SIZE ( vts ) , str , & opts , error_out ) ;
2005-04-16 15:20:36 -07:00
}
static int con_get_config ( char * dev , char * str , int size , char * * error_out )
{
2006-01-06 00:18:51 -08:00
return line_get_config ( dev , vts , ARRAY_SIZE ( vts ) , str , size , error_out ) ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
static int con_remove ( int n , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2007-02-10 01:43:53 -08:00
return line_remove ( vts , ARRAY_SIZE ( vts ) , n , error_out ) ;
2005-04-16 15:20:36 -07:00
}
static int con_open ( struct tty_struct * tty , struct file * filp )
{
2007-07-15 23:38:54 -07:00
int err = line_open ( vts , tty ) ;
if ( err )
printk ( KERN_ERR " Failed to open console %d, err = %d \n " ,
tty - > index , err ) ;
return err ;
2005-04-16 15:20:36 -07:00
}
2006-09-29 01:58:50 -07:00
/* Set in an initcall, checked in an exitcall */
2005-04-16 15:20:36 -07:00
static int con_init_done = 0 ;
2006-09-27 01:50:33 -07:00
static const struct tty_operations console_ops = {
2005-04-16 15:20:36 -07:00
. open = con_open ,
. close = line_close ,
. write = line_write ,
2005-05-01 08:58:56 -07:00
. put_char = line_put_char ,
2006-01-06 00:18:50 -08:00
. write_room = line_write_room ,
2005-04-16 15:20:36 -07:00
. chars_in_buffer = line_chars_in_buffer ,
2005-05-01 08:58:56 -07:00
. flush_buffer = line_flush_buffer ,
. flush_chars = line_flush_chars ,
2005-04-16 15:20:36 -07:00
. set_termios = line_set_termios ,
. ioctl = line_ioctl ,
2006-01-06 00:18:58 -08:00
. throttle = line_throttle ,
. unthrottle = line_unthrottle ,
2005-04-16 15:20:36 -07:00
} ;
static void uml_console_write ( struct console * console , const char * string ,
2006-01-06 00:18:50 -08:00
unsigned len )
2005-04-16 15:20:36 -07:00
{
struct line * line = & vts [ console - > index ] ;
2005-05-01 08:58:56 -07:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2005-05-01 08:58:56 -07:00
spin_lock_irqsave ( & line - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
console_write_chan ( & line - > chan_list , string , len ) ;
2005-05-01 08:58:56 -07:00
spin_unlock_irqrestore ( & line - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
}
static struct tty_driver * uml_console_device ( struct console * c , int * index )
{
* index = c - > index ;
return console_driver ;
}
static int uml_console_setup ( struct console * co , char * options )
{
struct line * line = & vts [ co - > index ] ;
2007-02-10 01:44:06 -08:00
return console_open_chan ( line , co ) ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:44:08 -08:00
/* No locking for register_console call - relies on single-threaded initcalls */
2005-04-16 15:20:36 -07:00
static struct console stdiocons = {
. name = " tty " ,
. write = uml_console_write ,
. device = uml_console_device ,
. setup = uml_console_setup ,
2007-03-07 20:41:11 -08:00
. flags = CON_PRINTBUFFER | CON_ANYTIME ,
2005-04-16 15:20:36 -07:00
. index = - 1 ,
} ;
2008-04-28 02:13:57 -07:00
static int stdio_init ( void )
2005-04-16 15:20:36 -07:00
{
char * new_title ;
2007-02-10 01:44:08 -08:00
console_driver = register_lines ( & driver , & console_ops , vts ,
ARRAY_SIZE ( vts ) ) ;
2006-01-06 00:18:50 -08:00
if ( console_driver = = NULL )
2005-04-16 15:20:36 -07:00
return - 1 ;
printk ( KERN_INFO " Initialized stdio console driver \n " ) ;
new_title = add_xterm_umid ( opts . xterm_title ) ;
if ( new_title ! = NULL )
opts . xterm_title = new_title ;
2007-05-06 14:51:16 -07:00
lines_init ( vts , ARRAY_SIZE ( vts ) , & opts ) ;
2005-04-16 15:20:36 -07:00
con_init_done = 1 ;
register_console ( & stdiocons ) ;
2006-01-06 00:18:50 -08:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
late_initcall ( stdio_init ) ;
static void console_exit ( void )
{
if ( ! con_init_done )
return ;
2006-01-06 00:18:51 -08:00
close_lines ( vts , ARRAY_SIZE ( vts ) ) ;
2005-04-16 15:20:36 -07:00
}
__uml_exitcall ( console_exit ) ;
static int console_chan_setup ( char * str )
{
2007-02-10 01:43:53 -08:00
char * error ;
int ret ;
ret = line_setup ( vts , ARRAY_SIZE ( vts ) , str , & error ) ;
if ( ret < 0 )
printk ( KERN_ERR " Failed to set up console with "
" configuration string \" %s \" : %s \n " , str , error ) ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
__setup ( " con " , console_chan_setup ) ;
__channel_help ( console_chan_setup , " con " ) ;