2005-04-17 02:20:36 +04:00
/*
* linux / drivers / char / pty . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* Added support for a Unix98 - style ptmx device .
* - - C . Scott Ananian < cananian @ alumni . princeton . edu > , 14 - Jan - 1998
*
2008-10-13 13:43:38 +04:00
* When reading this code see also fs / devpts . In particular note that the
* driver_data field is used by the devpts side as a binding to the devpts
* inode .
2005-04-17 02:20:36 +04:00
*/
2008-10-13 13:43:38 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/fcntl.h>
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/string.h>
# include <linux/major.h>
# include <linux/mm.h>
# include <linux/init.h>
2009-07-11 22:08:37 +04:00
# include <linux/smp_lock.h>
2005-04-17 02:20:36 +04:00
# include <linux/sysctl.h>
2008-10-13 13:41:42 +04:00
# include <linux/device.h>
2008-10-13 13:43:38 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/bitops.h>
# include <linux/devpts_fs.h>
2008-10-13 13:43:38 +04:00
# include <asm/system.h>
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_UNIX98_PTYS
2009-01-08 05:09:15 +03:00
static struct tty_driver * ptm_driver ;
2005-04-17 02:20:36 +04:00
static struct tty_driver * pts_driver ;
# endif
2008-10-13 13:43:38 +04:00
static void pty_close ( struct tty_struct * tty , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2008-10-13 13:43:38 +04:00
BUG_ON ( ! tty ) ;
if ( tty - > driver - > subtype = = PTY_TYPE_MASTER )
WARN_ON ( tty - > count > 1 ) ;
else {
2005-04-17 02:20:36 +04:00
if ( tty - > count > 2 )
return ;
}
wake_up_interruptible ( & tty - > read_wait ) ;
wake_up_interruptible ( & tty - > write_wait ) ;
tty - > packet = 0 ;
if ( ! tty - > link )
return ;
tty - > link - > packet = 0 ;
set_bit ( TTY_OTHER_CLOSED , & tty - > link - > flags ) ;
wake_up_interruptible ( & tty - > link - > read_wait ) ;
wake_up_interruptible ( & tty - > link - > write_wait ) ;
if ( tty - > driver - > subtype = = PTY_TYPE_MASTER ) {
set_bit ( TTY_OTHER_CLOSED , & tty - > flags ) ;
# ifdef CONFIG_UNIX98_PTYS
if ( tty - > driver = = ptm_driver )
2008-10-13 13:42:59 +04:00
devpts_pty_kill ( tty - > link ) ;
2005-04-17 02:20:36 +04:00
# endif
tty_vhangup ( tty - > link ) ;
}
}
/*
* The unthrottle routine is called by the line discipline to signal
* that it can receive more characters . For PTY ' s , the TTY_THROTTLED
* flag is always set , to force the line discipline to always call the
2008-10-13 13:43:38 +04:00
* unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
2005-04-17 02:20:36 +04:00
* characters in the queue . This is necessary since each time this
* happens , we need to wake up any sleeping processes that could be
* ( 1 ) trying to send data to the pty , or ( 2 ) waiting in wait_until_sent ( )
* for the pty buffer to be drained .
*/
2008-10-13 13:43:38 +04:00
static void pty_unthrottle ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2009-07-07 19:39:41 +04:00
tty_wakeup ( tty - > link ) ;
2005-04-17 02:20:36 +04:00
set_bit ( TTY_THROTTLED , & tty - > flags ) ;
}
2009-07-07 19:39:41 +04:00
/**
* pty_space - report space left for writing
* @ to : tty we are writing into
2005-04-17 02:20:36 +04:00
*
2009-07-07 19:39:41 +04:00
* The tty buffers allow 64 K but we sneak a peak and clip at 8 K this
* allows a lot of overspill room for echo and other fun messes to
* be handled properly
*/
static int pty_space ( struct tty_struct * to )
{
int n = 8192 - to - > buf . memory_used ;
if ( n < 0 )
return 0 ;
return n ;
}
/**
* pty_write - write to a pty
* @ tty : the tty we write from
* @ buf : kernel buffer of data
* @ count : bytes to write
2009-06-16 20:01:13 +04:00
*
2009-07-07 19:39:41 +04:00
* Our " hardware " write method . Data is coming from the ldisc which
* may be in a non sleeping state . We simply throw this at the other
* end of the link as if we were an IRQ handler receiving stuff for
* the other side of the pty / tty pair .
2005-04-17 02:20:36 +04:00
*/
2009-07-07 19:39:41 +04:00
2009-09-06 00:27:10 +04:00
static int pty_write ( struct tty_struct * tty , const unsigned char * buf , int c )
2005-04-17 02:20:36 +04:00
{
struct tty_struct * to = tty - > link ;
2009-07-07 19:39:41 +04:00
if ( tty - > stopped )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-07-07 19:39:41 +04:00
if ( c > 0 ) {
/* Stuff the data into the input queue of the other end */
c = tty_insert_flip_string ( to , buf , c ) ;
/* And shovel */
2009-09-18 18:05:58 +04:00
if ( c ) {
tty_flip_buffer_push ( to ) ;
tty_wakeup ( tty ) ;
}
2009-06-16 20:01:13 +04:00
}
2005-04-17 02:20:36 +04:00
return c ;
}
2009-07-07 19:39:41 +04:00
/**
* pty_write_room - write space
* @ tty : tty we are writing from
*
* Report how many bytes the ldisc can send into the queue for
* the other device .
*/
2005-04-17 02:20:36 +04:00
static int pty_write_room ( struct tty_struct * tty )
{
2009-08-11 00:21:19 +04:00
if ( tty - > stopped )
return 0 ;
2009-07-07 19:39:41 +04:00
return pty_space ( tty - > link ) ;
2005-04-17 02:20:36 +04:00
}
2009-07-07 19:39:41 +04:00
/**
* pty_chars_in_buffer - characters currently in our tx queue
* @ tty : our tty
2008-10-13 13:43:38 +04:00
*
2009-07-07 19:39:41 +04:00
* Report how much we have in the transmit queue . As everything is
* instantly at the other end this is easy to implement .
2005-04-17 02:20:36 +04:00
*/
2009-07-07 19:39:41 +04:00
2005-04-17 02:20:36 +04:00
static int pty_chars_in_buffer ( struct tty_struct * tty )
{
2009-07-07 19:39:41 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* Set the lock flag on a pty */
2008-10-13 13:43:38 +04:00
static int pty_set_lock ( struct tty_struct * tty , int __user * arg )
2005-04-17 02:20:36 +04:00
{
int val ;
2008-10-13 13:43:38 +04:00
if ( get_user ( val , arg ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
if ( val )
set_bit ( TTY_PTY_LOCK , & tty - > flags ) ;
else
clear_bit ( TTY_PTY_LOCK , & tty - > flags ) ;
return 0 ;
}
static void pty_flush_buffer ( struct tty_struct * tty )
{
struct tty_struct * to = tty - > link ;
2008-04-30 11:53:29 +04:00
unsigned long flags ;
2008-10-13 13:43:38 +04:00
2005-04-17 02:20:36 +04:00
if ( ! to )
return ;
2009-07-07 19:39:41 +04:00
/* tty_buffer_flush(to); FIXME */
2005-04-17 02:20:36 +04:00
if ( to - > packet ) {
2008-04-30 11:53:29 +04:00
spin_lock_irqsave ( & tty - > ctrl_lock , flags ) ;
2005-04-17 02:20:36 +04:00
tty - > ctrl_status | = TIOCPKT_FLUSHWRITE ;
wake_up_interruptible ( & to - > read_wait ) ;
2008-04-30 11:53:29 +04:00
spin_unlock_irqrestore ( & tty - > ctrl_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-10-13 13:43:38 +04:00
static int pty_open ( struct tty_struct * tty , struct file * filp )
2005-04-17 02:20:36 +04:00
{
int retval = - ENODEV ;
if ( ! tty | | ! tty - > link )
goto out ;
retval = - EIO ;
if ( test_bit ( TTY_OTHER_CLOSED , & tty - > flags ) )
goto out ;
if ( test_bit ( TTY_PTY_LOCK , & tty - > link - > flags ) )
goto out ;
if ( tty - > link - > count ! = 1 )
goto out ;
clear_bit ( TTY_OTHER_CLOSED , & tty - > link - > flags ) ;
set_bit ( TTY_THROTTLED , & tty - > flags ) ;
retval = 0 ;
out :
return retval ;
}
2008-10-13 13:43:38 +04:00
static void pty_set_termios ( struct tty_struct * tty ,
struct ktermios * old_termios )
2005-04-17 02:20:36 +04:00
{
2008-10-13 13:43:38 +04:00
tty - > termios - > c_cflag & = ~ ( CSIZE | PARENB ) ;
tty - > termios - > c_cflag | = ( CS8 | CREAD ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-02 16:43:17 +03:00
/**
* pty_do_resize - resize event
* @ tty : tty being resized
2009-01-11 22:46:49 +03:00
* @ ws : window size being set .
2009-01-02 16:43:17 +03:00
*
* Update the termios variables and send the neccessary signals to
* peform a terminal resize correctly
*/
int pty_resize ( struct tty_struct * tty , struct winsize * ws )
{
struct pid * pgrp , * rpgrp ;
unsigned long flags ;
struct tty_struct * pty = tty - > link ;
/* For a PTY we need to lock the tty side */
mutex_lock ( & tty - > termios_mutex ) ;
if ( ! memcmp ( ws , & tty - > winsize , sizeof ( * ws ) ) )
goto done ;
/* Get the PID values and reference them so we can
avoid holding the tty ctrl lock while sending signals .
We need to lock these individually however . */
spin_lock_irqsave ( & tty - > ctrl_lock , flags ) ;
pgrp = get_pid ( tty - > pgrp ) ;
spin_unlock_irqrestore ( & tty - > ctrl_lock , flags ) ;
spin_lock_irqsave ( & pty - > ctrl_lock , flags ) ;
rpgrp = get_pid ( pty - > pgrp ) ;
spin_unlock_irqrestore ( & pty - > ctrl_lock , flags ) ;
if ( pgrp )
kill_pgrp ( pgrp , SIGWINCH , 1 ) ;
if ( rpgrp ! = pgrp & & rpgrp )
kill_pgrp ( rpgrp , SIGWINCH , 1 ) ;
put_pid ( pgrp ) ;
put_pid ( rpgrp ) ;
tty - > winsize = * ws ;
pty - > winsize = * ws ; /* Never used so will go away soon */
done :
mutex_unlock ( & tty - > termios_mutex ) ;
return 0 ;
}
2009-09-30 18:49:40 +04:00
/* Traditional BSD devices */
# ifdef CONFIG_LEGACY_PTYS
2008-10-13 13:42:39 +04:00
static int pty_install ( struct tty_driver * driver , struct tty_struct * tty )
{
struct tty_struct * o_tty ;
int idx = tty - > index ;
int retval ;
o_tty = alloc_tty_struct ( ) ;
if ( ! o_tty )
return - ENOMEM ;
if ( ! try_module_get ( driver - > other - > owner ) ) {
/* This cannot in fact currently happen */
free_tty_struct ( o_tty ) ;
return - ENOMEM ;
}
initialize_tty_struct ( o_tty , driver - > other , idx ) ;
/* We always use new tty termios data so we can do this
the easy way . . */
retval = tty_init_termios ( tty ) ;
if ( retval )
goto free_mem_out ;
retval = tty_init_termios ( o_tty ) ;
if ( retval ) {
tty_free_termios ( tty ) ;
goto free_mem_out ;
}
2008-10-13 13:43:38 +04:00
2008-10-13 13:42:39 +04:00
/*
* Everything allocated . . . set up the o_tty structure .
*/
driver - > other - > ttys [ idx ] = o_tty ;
tty_driver_kref_get ( driver - > other ) ;
if ( driver - > subtype = = PTY_TYPE_MASTER )
o_tty - > count + + ;
/* Establish the links in both directions */
tty - > link = o_tty ;
o_tty - > link = tty ;
tty_driver_kref_get ( driver ) ;
tty - > count + + ;
driver - > ttys [ idx ] = tty ;
return 0 ;
free_mem_out :
module_put ( o_tty - > driver - > owner ) ;
free_tty_struct ( o_tty ) ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
static int pty_bsd_ioctl ( struct tty_struct * tty , struct file * file ,
unsigned int cmd , unsigned long arg )
{
switch ( cmd ) {
case TIOCSPTLCK : /* Set PT Lock (disallow slave open) */
return pty_set_lock ( tty , ( int __user * ) arg ) ;
}
return - ENOIOCTLCMD ;
}
2007-08-15 14:25:38 +04:00
static int legacy_count = CONFIG_LEGACY_PTY_COUNT ;
module_param ( legacy_count , int , 0 ) ;
2009-09-30 18:49:40 +04:00
/*
* The master side of a pty can do TIOCSPTLCK and thus
* has pty_bsd_ioctl .
*/
static const struct tty_operations master_pty_ops_bsd = {
. install = pty_install ,
2008-04-30 11:54:10 +04:00
. open = pty_open ,
. close = pty_close ,
. write = pty_write ,
. write_room = pty_write_room ,
. flush_buffer = pty_flush_buffer ,
. chars_in_buffer = pty_chars_in_buffer ,
. unthrottle = pty_unthrottle ,
. set_termios = pty_set_termios ,
. ioctl = pty_bsd_ioctl ,
2009-01-02 16:43:17 +03:00
. resize = pty_resize
2008-04-30 11:54:10 +04:00
} ;
2009-09-30 18:49:40 +04:00
static const struct tty_operations slave_pty_ops_bsd = {
. install = pty_install ,
. open = pty_open ,
. close = pty_close ,
. write = pty_write ,
. write_room = pty_write_room ,
. flush_buffer = pty_flush_buffer ,
. chars_in_buffer = pty_chars_in_buffer ,
. unthrottle = pty_unthrottle ,
. set_termios = pty_set_termios ,
. resize = pty_resize
} ;
2005-04-17 02:20:36 +04:00
static void __init legacy_pty_init ( void )
{
2009-09-30 18:49:40 +04:00
struct tty_driver * pty_driver , * pty_slave_driver ;
2007-08-15 14:25:38 +04:00
if ( legacy_count < = 0 )
return ;
2005-04-17 02:20:36 +04:00
2007-08-15 14:25:38 +04:00
pty_driver = alloc_tty_driver ( legacy_count ) ;
2005-04-17 02:20:36 +04:00
if ( ! pty_driver )
panic ( " Couldn't allocate pty driver " ) ;
2007-08-15 14:25:38 +04:00
pty_slave_driver = alloc_tty_driver ( legacy_count ) ;
2005-04-17 02:20:36 +04:00
if ( ! pty_slave_driver )
panic ( " Couldn't allocate pty slave driver " ) ;
pty_driver - > owner = THIS_MODULE ;
pty_driver - > driver_name = " pty_master " ;
pty_driver - > name = " pty " ;
pty_driver - > major = PTY_MASTER_MAJOR ;
pty_driver - > minor_start = 0 ;
pty_driver - > type = TTY_DRIVER_TYPE_PTY ;
pty_driver - > subtype = PTY_TYPE_MASTER ;
pty_driver - > init_termios = tty_std_termios ;
pty_driver - > init_termios . c_iflag = 0 ;
pty_driver - > init_termios . c_oflag = 0 ;
pty_driver - > init_termios . c_cflag = B38400 | CS8 | CREAD ;
pty_driver - > init_termios . c_lflag = 0 ;
2006-12-08 13:38:45 +03:00
pty_driver - > init_termios . c_ispeed = 38400 ;
pty_driver - > init_termios . c_ospeed = 38400 ;
2005-04-17 02:20:36 +04:00
pty_driver - > flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW ;
pty_driver - > other = pty_slave_driver ;
2009-09-30 18:49:40 +04:00
tty_set_operations ( pty_driver , & master_pty_ops_bsd ) ;
2005-04-17 02:20:36 +04:00
pty_slave_driver - > owner = THIS_MODULE ;
pty_slave_driver - > driver_name = " pty_slave " ;
pty_slave_driver - > name = " ttyp " ;
pty_slave_driver - > major = PTY_SLAVE_MAJOR ;
pty_slave_driver - > minor_start = 0 ;
pty_slave_driver - > type = TTY_DRIVER_TYPE_PTY ;
pty_slave_driver - > subtype = PTY_TYPE_SLAVE ;
pty_slave_driver - > init_termios = tty_std_termios ;
pty_slave_driver - > init_termios . c_cflag = B38400 | CS8 | CREAD ;
2006-12-08 13:38:45 +03:00
pty_slave_driver - > init_termios . c_ispeed = 38400 ;
pty_slave_driver - > init_termios . c_ospeed = 38400 ;
2005-04-17 02:20:36 +04:00
pty_slave_driver - > flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW ;
pty_slave_driver - > other = pty_driver ;
2009-09-30 18:49:40 +04:00
tty_set_operations ( pty_slave_driver , & slave_pty_ops_bsd ) ;
2005-04-17 02:20:36 +04:00
if ( tty_register_driver ( pty_driver ) )
panic ( " Couldn't register pty driver " ) ;
if ( tty_register_driver ( pty_slave_driver ) )
panic ( " Couldn't register pty slave driver " ) ;
}
# else
static inline void legacy_pty_init ( void ) { }
# endif
/* Unix98 devices */
# ifdef CONFIG_UNIX98_PTYS
/*
* sysctl support for setting limits on the number of Unix98 ptys allocated .
* Otherwise one can eat up all kernel memory by opening / dev / ptmx repeatedly .
*/
int pty_limit = NR_UNIX98_PTY_DEFAULT ;
2008-10-13 13:43:38 +04:00
static int pty_limit_min ;
2005-04-17 02:20:36 +04:00
static int pty_limit_max = NR_UNIX98_PTY_MAX ;
2008-10-13 13:43:38 +04:00
static int pty_count ;
2005-04-17 02:20:36 +04:00
2008-10-13 13:41:42 +04:00
static struct cdev ptmx_cdev ;
2007-10-18 14:05:31 +04:00
static struct ctl_table pty_table [ ] = {
2005-04-17 02:20:36 +04:00
{
. procname = " max " ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
. data = & pty_limit ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & pty_limit_min ,
. extra2 = & pty_limit_max ,
} , {
. procname = " nr " ,
. maxlen = sizeof ( int ) ,
. mode = 0444 ,
2008-10-13 13:42:39 +04:00
. data = & pty_count ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2009-11-06 01:34:02 +03:00
} ,
{ }
2005-04-17 02:20:36 +04:00
} ;
2007-10-18 14:05:31 +04:00
static struct ctl_table pty_kern_table [ ] = {
{
. procname = " pty " ,
. mode = 0555 ,
. child = pty_table ,
} ,
{ }
} ;
static struct ctl_table pty_root_table [ ] = {
{
. procname = " kernel " ,
. mode = 0555 ,
. child = pty_kern_table ,
} ,
{ }
} ;
2005-04-17 02:20:36 +04:00
static int pty_unix98_ioctl ( struct tty_struct * tty , struct file * file ,
unsigned int cmd , unsigned long arg )
{
switch ( cmd ) {
case TIOCSPTLCK : /* Set PT Lock (disallow slave open) */
return pty_set_lock ( tty , ( int __user * ) arg ) ;
case TIOCGPTN : /* Get PT Number */
return put_user ( tty - > index , ( unsigned int __user * ) arg ) ;
}
return - ENOIOCTLCMD ;
}
2008-10-13 13:42:00 +04:00
/**
* ptm_unix98_lookup - find a pty master
* @ driver : ptm driver
* @ idx : tty index
*
* Look up a pty master device . Called under the tty_mutex for now .
* This provides our locking .
*/
2008-10-13 13:42:59 +04:00
static struct tty_struct * ptm_unix98_lookup ( struct tty_driver * driver ,
struct inode * ptm_inode , int idx )
2008-10-13 13:42:00 +04:00
{
2008-10-13 13:42:59 +04:00
struct tty_struct * tty = devpts_get_tty ( ptm_inode , idx ) ;
2008-10-13 13:42:00 +04:00
if ( tty )
tty = tty - > link ;
return tty ;
}
/**
* pts_unix98_lookup - find a pty slave
* @ driver : pts driver
* @ idx : tty index
*
* Look up a pty master device . Called under the tty_mutex for now .
* This provides our locking .
*/
2008-10-13 13:42:59 +04:00
static struct tty_struct * pts_unix98_lookup ( struct tty_driver * driver ,
struct inode * pts_inode , int idx )
2008-10-13 13:42:00 +04:00
{
2008-10-13 13:42:59 +04:00
struct tty_struct * tty = devpts_get_tty ( pts_inode , idx ) ;
2008-10-13 13:42:00 +04:00
/* Master must be open before slave */
if ( ! tty )
return ERR_PTR ( - EIO ) ;
return tty ;
}
2008-10-13 13:42:39 +04:00
static void pty_unix98_shutdown ( struct tty_struct * tty )
2008-10-13 13:41:30 +04:00
{
/* We have our own method as we don't use the tty index */
kfree ( tty - > termios ) ;
}
2008-10-13 13:42:19 +04:00
/* We have no need to install and remove our tty objects as devpts does all
the work for us */
2008-10-13 13:42:39 +04:00
static int pty_unix98_install ( struct tty_driver * driver , struct tty_struct * tty )
2008-10-13 13:42:19 +04:00
{
2008-10-13 13:42:39 +04:00
struct tty_struct * o_tty ;
int idx = tty - > index ;
o_tty = alloc_tty_struct ( ) ;
if ( ! o_tty )
return - ENOMEM ;
if ( ! try_module_get ( driver - > other - > owner ) ) {
/* This cannot in fact currently happen */
free_tty_struct ( o_tty ) ;
return - ENOMEM ;
}
initialize_tty_struct ( o_tty , driver - > other , idx ) ;
2008-10-13 13:43:58 +04:00
tty - > termios = kzalloc ( sizeof ( struct ktermios [ 2 ] ) , GFP_KERNEL ) ;
2008-10-13 13:42:39 +04:00
if ( tty - > termios = = NULL )
goto free_mem_out ;
* tty - > termios = driver - > init_termios ;
2008-10-13 13:43:58 +04:00
tty - > termios_locked = tty - > termios + 1 ;
o_tty - > termios = kzalloc ( sizeof ( struct ktermios [ 2 ] ) , GFP_KERNEL ) ;
2008-10-13 13:42:39 +04:00
if ( o_tty - > termios = = NULL )
goto free_mem_out ;
* o_tty - > termios = driver - > other - > init_termios ;
2008-10-13 13:43:58 +04:00
o_tty - > termios_locked = o_tty - > termios + 1 ;
2008-10-13 13:42:39 +04:00
tty_driver_kref_get ( driver - > other ) ;
if ( driver - > subtype = = PTY_TYPE_MASTER )
o_tty - > count + + ;
/* Establish the links in both directions */
tty - > link = o_tty ;
o_tty - > link = tty ;
/*
* All structures have been allocated , so now we install them .
* Failures after this point use release_tty to clean up , so
* there ' s no need to null out the local pointers .
*/
tty_driver_kref_get ( driver ) ;
tty - > count + + ;
pty_count + + ;
2008-10-13 13:42:19 +04:00
return 0 ;
2008-10-13 13:42:39 +04:00
free_mem_out :
2008-10-13 13:43:58 +04:00
kfree ( o_tty - > termios ) ;
2008-10-13 13:42:39 +04:00
module_put ( o_tty - > driver - > owner ) ;
free_tty_struct ( o_tty ) ;
2008-10-13 13:43:58 +04:00
kfree ( tty - > termios ) ;
2008-10-13 13:42:39 +04:00
return - ENOMEM ;
2008-10-13 13:42:19 +04:00
}
2008-10-13 13:42:39 +04:00
static void pty_unix98_remove ( struct tty_driver * driver , struct tty_struct * tty )
2008-10-13 13:42:19 +04:00
{
2008-10-13 13:42:39 +04:00
pty_count - - ;
2008-10-13 13:42:19 +04:00
}
2008-10-13 13:41:30 +04:00
static const struct tty_operations ptm_unix98_ops = {
2008-10-13 13:42:00 +04:00
. lookup = ptm_unix98_lookup ,
2008-10-13 13:42:39 +04:00
. install = pty_unix98_install ,
. remove = pty_unix98_remove ,
2008-04-30 11:54:10 +04:00
. open = pty_open ,
. close = pty_close ,
. write = pty_write ,
. write_room = pty_write_room ,
. flush_buffer = pty_flush_buffer ,
. chars_in_buffer = pty_chars_in_buffer ,
. unthrottle = pty_unthrottle ,
. set_termios = pty_set_termios ,
2008-10-13 13:41:30 +04:00
. ioctl = pty_unix98_ioctl ,
2009-01-02 16:43:17 +03:00
. shutdown = pty_unix98_shutdown ,
. resize = pty_resize
2008-04-30 11:54:10 +04:00
} ;
2008-10-13 13:42:00 +04:00
static const struct tty_operations pty_unix98_ops = {
. lookup = pts_unix98_lookup ,
2008-10-13 13:42:39 +04:00
. install = pty_unix98_install ,
. remove = pty_unix98_remove ,
2008-10-13 13:42:00 +04:00
. open = pty_open ,
. close = pty_close ,
. write = pty_write ,
. write_room = pty_write_room ,
. flush_buffer = pty_flush_buffer ,
. chars_in_buffer = pty_chars_in_buffer ,
. unthrottle = pty_unthrottle ,
. set_termios = pty_set_termios ,
2008-10-13 13:42:39 +04:00
. shutdown = pty_unix98_shutdown
2008-10-13 13:42:00 +04:00
} ;
2008-10-13 13:41:42 +04:00
/**
* ptmx_open - open a unix 98 pty master
* @ inode : inode of device file
* @ filp : file pointer to tty
*
* Allocate a unix98 pty master device from the ptmx driver .
*
* Locking : tty_mutex protects the init_dev work . tty - > count should
* protect the rest .
* allocated_ptys_lock handles the list of free pty numbers
*/
static int __ptmx_open ( struct inode * inode , struct file * filp )
{
struct tty_struct * tty ;
int retval ;
int index ;
nonseekable_open ( inode , filp ) ;
/* find a device that is not in use. */
2008-10-13 13:42:59 +04:00
index = devpts_new_index ( inode ) ;
2008-10-13 13:41:42 +04:00
if ( index < 0 )
return index ;
mutex_lock ( & tty_mutex ) ;
2008-10-13 13:42:29 +04:00
tty = tty_init_dev ( ptm_driver , index , 1 ) ;
2008-10-13 13:41:42 +04:00
mutex_unlock ( & tty_mutex ) ;
2008-10-13 13:42:29 +04:00
if ( IS_ERR ( tty ) ) {
retval = PTR_ERR ( tty ) ;
2008-10-13 13:41:42 +04:00
goto out ;
2008-10-13 13:42:29 +04:00
}
2008-10-13 13:41:42 +04:00
set_bit ( TTY_PTY_LOCK , & tty - > flags ) ; /* LOCK THE SLAVE */
filp - > private_data = tty ;
file_move ( filp , & tty - > tty_files ) ;
2008-10-13 13:42:59 +04:00
retval = devpts_pty_new ( inode , tty - > link ) ;
2008-10-13 13:41:42 +04:00
if ( retval )
goto out1 ;
retval = ptm_driver - > ops - > open ( tty , filp ) ;
if ( ! retval )
return 0 ;
out1 :
2009-11-30 16:18:29 +03:00
tty_release ( inode , filp ) ;
2008-10-13 13:41:42 +04:00
return retval ;
out :
2008-10-13 13:42:59 +04:00
devpts_kill_index ( inode , index ) ;
2008-10-13 13:41:42 +04:00
return retval ;
}
static int ptmx_open ( struct inode * inode , struct file * filp )
{
int ret ;
lock_kernel ( ) ;
ret = __ptmx_open ( inode , filp ) ;
unlock_kernel ( ) ;
return ret ;
}
static struct file_operations ptmx_fops ;
2005-04-17 02:20:36 +04:00
static void __init unix98_pty_init ( void )
{
ptm_driver = alloc_tty_driver ( NR_UNIX98_PTY_MAX ) ;
if ( ! ptm_driver )
panic ( " Couldn't allocate Unix98 ptm driver " ) ;
pts_driver = alloc_tty_driver ( NR_UNIX98_PTY_MAX ) ;
if ( ! pts_driver )
panic ( " Couldn't allocate Unix98 pts driver " ) ;
ptm_driver - > owner = THIS_MODULE ;
ptm_driver - > driver_name = " pty_master " ;
ptm_driver - > name = " ptm " ;
ptm_driver - > major = UNIX98_PTY_MASTER_MAJOR ;
ptm_driver - > minor_start = 0 ;
ptm_driver - > type = TTY_DRIVER_TYPE_PTY ;
ptm_driver - > subtype = PTY_TYPE_MASTER ;
ptm_driver - > init_termios = tty_std_termios ;
ptm_driver - > init_termios . c_iflag = 0 ;
ptm_driver - > init_termios . c_oflag = 0 ;
ptm_driver - > init_termios . c_cflag = B38400 | CS8 | CREAD ;
ptm_driver - > init_termios . c_lflag = 0 ;
2006-12-08 13:38:45 +03:00
ptm_driver - > init_termios . c_ispeed = 38400 ;
ptm_driver - > init_termios . c_ospeed = 38400 ;
2005-04-17 02:20:36 +04:00
ptm_driver - > flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
2005-06-21 08:15:16 +04:00
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM ;
2005-04-17 02:20:36 +04:00
ptm_driver - > other = pts_driver ;
2008-10-13 13:41:30 +04:00
tty_set_operations ( ptm_driver , & ptm_unix98_ops ) ;
2005-04-17 02:20:36 +04:00
pts_driver - > owner = THIS_MODULE ;
pts_driver - > driver_name = " pty_slave " ;
pts_driver - > name = " pts " ;
pts_driver - > major = UNIX98_PTY_SLAVE_MAJOR ;
pts_driver - > minor_start = 0 ;
pts_driver - > type = TTY_DRIVER_TYPE_PTY ;
pts_driver - > subtype = PTY_TYPE_SLAVE ;
pts_driver - > init_termios = tty_std_termios ;
pts_driver - > init_termios . c_cflag = B38400 | CS8 | CREAD ;
2006-12-08 13:38:45 +03:00
pts_driver - > init_termios . c_ispeed = 38400 ;
pts_driver - > init_termios . c_ospeed = 38400 ;
2005-04-17 02:20:36 +04:00
pts_driver - > flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
2005-06-21 08:15:16 +04:00
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM ;
2005-04-17 02:20:36 +04:00
pts_driver - > other = ptm_driver ;
2008-10-13 13:42:00 +04:00
tty_set_operations ( pts_driver , & pty_unix98_ops ) ;
2008-10-13 13:43:38 +04:00
2005-04-17 02:20:36 +04:00
if ( tty_register_driver ( ptm_driver ) )
panic ( " Couldn't register Unix98 ptm driver " ) ;
if ( tty_register_driver ( pts_driver ) )
panic ( " Couldn't register Unix98 pts driver " ) ;
2008-10-13 13:43:38 +04:00
register_sysctl_table ( pty_root_table ) ;
2008-10-13 13:41:42 +04:00
/* Now create the /dev/ptmx special device */
tty_default_fops ( & ptmx_fops ) ;
ptmx_fops . open = ptmx_open ;
cdev_init ( & ptmx_cdev , & ptmx_fops ) ;
if ( cdev_add ( & ptmx_cdev , MKDEV ( TTYAUX_MAJOR , 2 ) , 1 ) | |
register_chrdev_region ( MKDEV ( TTYAUX_MAJOR , 2 ) , 1 , " /dev/ptmx " ) < 0 )
panic ( " Couldn't register /dev/ptmx driver \n " ) ;
device_create ( tty_class , NULL , MKDEV ( TTYAUX_MAJOR , 2 ) , NULL , " ptmx " ) ;
2005-04-17 02:20:36 +04:00
}
2008-10-13 13:41:42 +04:00
2005-04-17 02:20:36 +04:00
# else
static inline void unix98_pty_init ( void ) { }
# endif
static int __init pty_init ( void )
{
legacy_pty_init ( ) ;
unix98_pty_init ( ) ;
return 0 ;
}
module_init ( pty_init ) ;