2005-04-17 02:20:36 +04:00
/*
* linux / drivers / char / tty_ioctl . c
*
* Copyright ( C ) 1991 , 1992 , 1993 , 1994 Linus Torvalds
*
* Modified by Fred N . van Kempen , 01 / 29 / 93 , to add line disciplines
* which can be dynamically activated and de - activated by the line
* discipline handling modules ( like SLIP ) .
*/
# include <linux/types.h>
# include <linux/termios.h>
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/major.h>
# include <linux/tty.h>
# include <linux/fcntl.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/bitops.h>
2006-09-29 13:00:43 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/uaccess.h>
# include <asm/system.h>
# undef TTY_DEBUG_WAIT_UNTIL_SENT
# undef DEBUG
/*
* Internal flag options for termios setting behavior
*/
# define TERMIOS_FLUSH 1
# define TERMIOS_WAIT 2
# define TERMIOS_TERMIO 4
2006-12-08 13:38:44 +03:00
# define TERMIOS_OLD 8
2005-04-17 02:20:36 +04:00
2006-08-27 12:24:01 +04:00
2008-10-13 13:41:42 +04:00
/**
* tty_chars_in_buffer - characters pending
* @ tty : terminal
*
* Return the number of bytes of data in the device private
* output queue . If no private method is supplied there is assumed
* to be no queue on the device .
*/
2008-04-30 11:54:13 +04:00
int tty_chars_in_buffer ( struct tty_struct * tty )
{
if ( tty - > ops - > chars_in_buffer )
return tty - > ops - > chars_in_buffer ( tty ) ;
else
return 0 ;
}
EXPORT_SYMBOL ( tty_chars_in_buffer ) ;
2008-10-13 13:41:42 +04:00
/**
* tty_write_room - write queue space
* @ tty : terminal
*
* Return the number of bytes that can be queued to this device
* at the present time . The result should be treated as a guarantee
* and the driver cannot offer a value it later shrinks by more than
* the number of bytes written . If no method is provided 2 K is always
* returned and data may be lost as there will be no flow control .
*/
2008-04-30 11:54:13 +04:00
int tty_write_room ( struct tty_struct * tty )
{
if ( tty - > ops - > write_room )
return tty - > ops - > write_room ( tty ) ;
return 2048 ;
}
EXPORT_SYMBOL ( tty_write_room ) ;
2008-10-13 13:41:42 +04:00
/**
* tty_driver_flush_buffer - discard internal buffer
* @ tty : terminal
*
* Discard the internal output buffer for this device . If no method
* is provided then either the buffer cannot be hardware flushed or
* there is no buffer driver side .
*/
2008-04-30 11:54:13 +04:00
void tty_driver_flush_buffer ( struct tty_struct * tty )
{
if ( tty - > ops - > flush_buffer )
tty - > ops - > flush_buffer ( tty ) ;
}
EXPORT_SYMBOL ( tty_driver_flush_buffer ) ;
2008-10-13 13:41:42 +04:00
/**
* tty_throttle - flow control
* @ tty : terminal
*
* Indicate that a tty should stop transmitting data down the stack .
2009-06-11 15:44:17 +04:00
* Takes the termios mutex to protect against parallel throttle / unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control .
2008-10-13 13:41:42 +04:00
*/
2008-04-30 11:54:18 +04:00
void tty_throttle ( struct tty_struct * tty )
{
2009-06-11 15:44:17 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2008-04-30 11:54:18 +04:00
/* check TTY_THROTTLED first so it indicates our state */
if ( ! test_and_set_bit ( TTY_THROTTLED , & tty - > flags ) & &
tty - > ops - > throttle )
tty - > ops - > throttle ( tty ) ;
2009-06-11 15:44:17 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2008-04-30 11:54:18 +04:00
}
EXPORT_SYMBOL ( tty_throttle ) ;
2008-10-13 13:41:42 +04:00
/**
* tty_unthrottle - flow control
* @ tty : terminal
*
* Indicate that a tty may continue transmitting data down the stack .
2009-06-11 15:44:17 +04:00
* Takes the termios mutex to protect against parallel throttle / unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control .
*
* Drivers should however remember that the stack can issue a throttle ,
* then change flow control method , then unthrottle .
2008-10-13 13:41:42 +04:00
*/
2008-04-30 11:54:18 +04:00
void tty_unthrottle ( struct tty_struct * tty )
{
2009-06-11 15:44:17 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2008-04-30 11:54:18 +04:00
if ( test_and_clear_bit ( TTY_THROTTLED , & tty - > flags ) & &
tty - > ops - > unthrottle )
tty - > ops - > unthrottle ( tty ) ;
2009-06-11 15:44:17 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2008-04-30 11:54:18 +04:00
}
EXPORT_SYMBOL ( tty_unthrottle ) ;
2008-04-30 11:54:13 +04:00
2006-08-27 12:24:01 +04:00
/**
* tty_wait_until_sent - wait for I / O to finish
* @ tty : tty we are waiting for
* @ timeout : how long we will wait
*
* Wait for characters pending in a tty driver to hit the wire , or
* for a timeout to occur ( eg due to flow control )
*
* Locking : none
*/
2008-02-08 15:18:48 +03:00
void tty_wait_until_sent ( struct tty_struct * tty , long timeout )
2005-04-17 02:20:36 +04:00
{
# ifdef TTY_DEBUG_WAIT_UNTIL_SENT
char buf [ 64 ] ;
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " %s wait until sent... \n " , tty_name ( tty , buf ) ) ;
# endif
if ( ! timeout )
timeout = MAX_SCHEDULE_TIMEOUT ;
2007-07-16 10:40:18 +04:00
if ( wait_event_interruptible_timeout ( tty - > write_wait ,
2008-04-30 11:54:13 +04:00
! tty_chars_in_buffer ( tty ) , timeout ) > = 0 ) {
if ( tty - > ops - > wait_until_sent )
tty - > ops - > wait_until_sent ( tty , timeout ) ;
2008-04-30 11:53:32 +04:00
}
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( tty_wait_until_sent ) ;
2008-10-13 13:41:42 +04:00
/*
* Termios Helper Methods
*/
2006-12-08 13:38:44 +03:00
static void unset_locked_termios ( struct ktermios * termios ,
struct ktermios * old ,
struct ktermios * locked )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-02-08 15:18:48 +03:00
# define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
2005-04-17 02:20:36 +04:00
if ( ! locked ) {
printk ( KERN_WARNING " Warning?!? termios_locked is NULL. \n " ) ;
return ;
}
NOSET_MASK ( termios - > c_iflag , old - > c_iflag , locked - > c_iflag ) ;
NOSET_MASK ( termios - > c_oflag , old - > c_oflag , locked - > c_oflag ) ;
NOSET_MASK ( termios - > c_cflag , old - > c_cflag , locked - > c_cflag ) ;
NOSET_MASK ( termios - > c_lflag , old - > c_lflag , locked - > c_lflag ) ;
termios - > c_line = locked - > c_line ? old - > c_line : termios - > c_line ;
2008-02-08 15:18:48 +03:00
for ( i = 0 ; i < NCCS ; i + + )
2005-04-17 02:20:36 +04:00
termios - > c_cc [ i ] = locked - > c_cc [ i ] ?
old - > c_cc [ i ] : termios - > c_cc [ i ] ;
2006-12-08 13:38:44 +03:00
/* FIXME: What should we do for i/ospeed */
2005-04-17 02:20:36 +04:00
}
2006-12-08 13:38:44 +03:00
/*
* Routine which returns the baud rate of the tty
*
* Note that the baud_table needs to be kept in sync with the
* include / asm / termbits . h file .
*/
static const speed_t baud_table [ ] = {
0 , 50 , 75 , 110 , 134 , 150 , 200 , 300 , 600 , 1200 , 1800 , 2400 , 4800 ,
9600 , 19200 , 38400 , 57600 , 115200 , 230400 , 460800 ,
# ifdef __sparc__
76800 , 153600 , 307200 , 614400 , 921600
# else
500000 , 576000 , 921600 , 1000000 , 1152000 , 1500000 , 2000000 ,
2500000 , 3000000 , 3500000 , 4000000
# endif
} ;
# ifndef __sparc__
static const tcflag_t baud_bits [ ] = {
B0 , B50 , B75 , B110 , B134 , B150 , B200 , B300 , B600 ,
B1200 , B1800 , B2400 , B4800 , B9600 , B19200 , B38400 ,
B57600 , B115200 , B230400 , B460800 , B500000 , B576000 ,
B921600 , B1000000 , B1152000 , B1500000 , B2000000 , B2500000 ,
B3000000 , B3500000 , B4000000
} ;
# else
static const tcflag_t baud_bits [ ] = {
B0 , B50 , B75 , B110 , B134 , B150 , B200 , B300 , B600 ,
B1200 , B1800 , B2400 , B4800 , B9600 , B19200 , B38400 ,
B57600 , B115200 , B230400 , B460800 , B76800 , B153600 ,
B307200 , B614400 , B921600
} ;
# endif
static int n_baud_table = ARRAY_SIZE ( baud_table ) ;
/**
* tty_termios_baud_rate
* @ termios : termios structure
*
* Convert termios baud rate data into a speed . This should be called
* with the termios lock held if this termios is a terminal termios
* structure . May change the termios data . Device drivers can call this
* function but should use - > c_ [ io ] speed directly as they are updated .
*
* Locking : none
*/
speed_t tty_termios_baud_rate ( struct ktermios * termios )
{
unsigned int cbaud ;
cbaud = termios - > c_cflag & CBAUD ;
# ifdef BOTHER
/* Magic token for arbitary speed via c_ispeed/c_ospeed */
if ( cbaud = = BOTHER )
return termios - > c_ospeed ;
# endif
if ( cbaud & CBAUDEX ) {
cbaud & = ~ CBAUDEX ;
if ( cbaud < 1 | | cbaud + 15 > n_baud_table )
termios - > c_cflag & = ~ CBAUDEX ;
else
cbaud + = 15 ;
}
return baud_table [ cbaud ] ;
}
EXPORT_SYMBOL ( tty_termios_baud_rate ) ;
/**
* tty_termios_input_baud_rate
* @ termios : termios structure
*
* Convert termios baud rate data into a speed . This should be called
* with the termios lock held if this termios is a terminal termios
* structure . May change the termios data . Device drivers can call this
* function but should use - > c_ [ io ] speed directly as they are updated .
*
* Locking : none
*/
speed_t tty_termios_input_baud_rate ( struct ktermios * termios )
{
# ifdef IBSHIFT
unsigned int cbaud = ( termios - > c_cflag > > IBSHIFT ) & CBAUD ;
if ( cbaud = = B0 )
return tty_termios_baud_rate ( termios ) ;
/* Magic token for arbitary speed via c_ispeed*/
if ( cbaud = = BOTHER )
return termios - > c_ispeed ;
if ( cbaud & CBAUDEX ) {
cbaud & = ~ CBAUDEX ;
if ( cbaud < 1 | | cbaud + 15 > n_baud_table )
termios - > c_cflag & = ~ ( CBAUDEX < < IBSHIFT ) ;
else
cbaud + = 15 ;
}
return baud_table [ cbaud ] ;
# else
return tty_termios_baud_rate ( termios ) ;
# endif
}
EXPORT_SYMBOL ( tty_termios_input_baud_rate ) ;
/**
* tty_termios_encode_baud_rate
2007-02-10 12:45:57 +03:00
* @ termios : ktermios structure holding user requested state
2006-12-08 13:38:44 +03:00
* @ ispeed : input speed
* @ ospeed : output speed
*
* Encode the speeds set into the passed termios structure . This is
* used as a library helper for drivers os that they can report back
* the actual speed selected when it differs from the speed requested
*
2007-02-10 12:45:57 +03:00
* For maximal back compatibility with legacy SYS5 / POSIX * nix behaviour
* we need to carefully set the bits when the user does not get the
* desired speed . We allow small margins and preserve as much of possible
2009-09-29 05:43:57 +04:00
* of the input intent to keep compatibility .
2006-12-08 13:38:44 +03:00
*
* Locking : Caller should hold termios lock . This is already held
* when calling this function from the driver termios handler .
2007-10-17 10:30:07 +04:00
*
* The ifdefs deal with platforms whose owners have yet to update them
* and will all go away once this is done .
2006-12-08 13:38:44 +03:00
*/
2007-10-18 14:04:35 +04:00
void tty_termios_encode_baud_rate ( struct ktermios * termios ,
speed_t ibaud , speed_t obaud )
2006-12-08 13:38:44 +03:00
{
int i = 0 ;
2007-02-10 12:45:57 +03:00
int ifound = - 1 , ofound = - 1 ;
int iclose = ibaud / 50 , oclose = obaud / 50 ;
int ibinput = 0 ;
2006-12-08 13:38:44 +03:00
2007-10-17 10:30:07 +04:00
if ( obaud = = 0 ) /* CD dropped */
ibaud = 0 ; /* Clear ibaud to be sure */
2006-12-08 13:38:44 +03:00
termios - > c_ispeed = ibaud ;
termios - > c_ospeed = obaud ;
2007-10-17 10:30:07 +04:00
# ifdef BOTHER
2007-02-10 12:45:57 +03:00
/* If the user asked for a precise weird speed give a precise weird
answer . If they asked for a Bfoo speed they many have problems
digesting non - exact replies so fuzz a bit */
if ( ( termios - > c_cflag & CBAUD ) = = BOTHER )
oclose = 0 ;
if ( ( ( termios - > c_cflag > > IBSHIFT ) & CBAUD ) = = BOTHER )
iclose = 0 ;
if ( ( termios - > c_cflag > > IBSHIFT ) & CBAUD )
ibinput = 1 ; /* An input speed was specified */
2007-10-17 10:30:07 +04:00
# endif
2006-12-08 13:38:44 +03:00
termios - > c_cflag & = ~ CBAUD ;
2007-10-17 10:30:07 +04:00
/*
* Our goal is to find a close match to the standard baud rate
* returned . Walk the baud rate table and if we get a very close
* match then report back the speed as a POSIX Bxxxx value by
* preference
*/
2006-12-08 13:38:44 +03:00
do {
2007-10-18 14:04:35 +04:00
if ( obaud - oclose < = baud_table [ i ] & &
obaud + oclose > = baud_table [ i ] ) {
2006-12-08 13:38:44 +03:00
termios - > c_cflag | = baud_bits [ i ] ;
2007-02-10 12:45:57 +03:00
ofound = i ;
2006-12-08 13:38:44 +03:00
}
2007-10-18 14:04:35 +04:00
if ( ibaud - iclose < = baud_table [ i ] & &
ibaud + iclose > = baud_table [ i ] ) {
/* For the case input == output don't set IBAUD bits
if the user didn ' t do so */
2007-10-17 10:30:07 +04:00
if ( ofound = = i & & ! ibinput )
ifound = i ;
# ifdef IBSHIFT
else {
ifound = i ;
2007-02-10 12:45:57 +03:00
termios - > c_cflag | = ( baud_bits [ i ] < < IBSHIFT ) ;
2007-10-17 10:30:07 +04:00
}
# endif
2006-12-08 13:38:44 +03:00
}
2007-07-16 10:40:18 +04:00
} while ( + + i < n_baud_table ) ;
2007-10-17 10:30:07 +04:00
/*
* If we found no match then use BOTHER if provided or warn
* the user their platform maintainer needs to wake up if not .
*/
# ifdef BOTHER
2007-02-10 12:45:57 +03:00
if ( ofound = = - 1 )
2006-12-08 13:38:44 +03:00
termios - > c_cflag | = BOTHER ;
2007-02-10 12:45:57 +03:00
/* Set exact input bits only if the input and output differ or the
user already did */
2007-07-16 10:40:18 +04:00
if ( ifound = = - 1 & & ( ibaud ! = obaud | | ibinput ) )
2006-12-08 13:38:44 +03:00
termios - > c_cflag | = ( BOTHER < < IBSHIFT ) ;
2007-10-17 10:30:07 +04:00
# else
if ( ifound = = - 1 | | ofound = = - 1 ) {
2009-08-09 23:54:03 +04:00
printk_once ( KERN_WARNING " tty: Unable to return correct "
2007-10-17 10:30:07 +04:00
" speed data as your architecture needs updating. \n " ) ;
}
# endif
2006-12-08 13:38:44 +03:00
}
EXPORT_SYMBOL_GPL ( tty_termios_encode_baud_rate ) ;
2008-10-13 13:41:42 +04:00
/**
* tty_encode_baud_rate - set baud rate of the tty
* @ ibaud : input baud rate
* @ obad : output baud rate
*
* Update the current termios data for the tty with the new speed
* settings . The caller must hold the termios_mutex for the tty in
* question .
*/
2007-10-17 10:30:07 +04:00
void tty_encode_baud_rate ( struct tty_struct * tty , speed_t ibaud , speed_t obaud )
{
tty_termios_encode_baud_rate ( tty - > termios , ibaud , obaud ) ;
}
EXPORT_SYMBOL_GPL ( tty_encode_baud_rate ) ;
2006-12-08 13:38:44 +03:00
/**
* tty_get_baud_rate - get tty bit rates
* @ tty : tty to query
*
* Returns the baud rate as an integer for this terminal . The
* termios lock must be held by the caller and the terminal bit
* flags may be updated .
*
* Locking : none
*/
speed_t tty_get_baud_rate ( struct tty_struct * tty )
{
speed_t baud = tty_termios_baud_rate ( tty - > termios ) ;
if ( baud = = 38400 & & tty - > alt_speed ) {
if ( ! tty - > warned ) {
printk ( KERN_WARNING " Use of setserial/setrocket to "
" set SPD_* flags is deprecated \n " ) ;
tty - > warned = 1 ;
}
baud = tty - > alt_speed ;
}
return baud ;
}
EXPORT_SYMBOL ( tty_get_baud_rate ) ;
2007-10-17 10:30:07 +04:00
/**
* tty_termios_copy_hw - copy hardware settings
* @ new : New termios
* @ old : Old termios
*
* Propogate the hardware specific terminal setting bits from
* the old termios structure to the new one . This is used in cases
* where the hardware does not support reconfiguration or as a helper
* in some cases where only minimal reconfiguration is supported
*/
void tty_termios_copy_hw ( struct ktermios * new , struct ktermios * old )
{
/* The bits a dumb device handles in software. Smart devices need
to always provide a set_termios method */
new - > c_cflag & = HUPCL | CREAD | CLOCAL ;
new - > c_cflag | = old - > c_cflag & ~ ( HUPCL | CREAD | CLOCAL ) ;
new - > c_ispeed = old - > c_ispeed ;
new - > c_ospeed = old - > c_ospeed ;
}
EXPORT_SYMBOL ( tty_termios_copy_hw ) ;
2008-01-08 17:55:51 +03:00
/**
* tty_termios_hw_change - check for setting change
* @ a : termios
* @ b : termios to compare
*
* Check if any of the bits that affect a dumb device have changed
* between the two termios structures , or a speed change is needed .
*/
int tty_termios_hw_change ( struct ktermios * a , struct ktermios * b )
{
if ( a - > c_ispeed ! = b - > c_ispeed | | a - > c_ospeed ! = b - > c_ospeed )
return 1 ;
if ( ( a - > c_cflag ^ b - > c_cflag ) & ~ ( HUPCL | CREAD | CLOCAL ) )
return 1 ;
return 0 ;
}
EXPORT_SYMBOL ( tty_termios_hw_change ) ;
2006-08-27 12:24:01 +04:00
/**
* change_termios - update termios values
* @ tty : tty to update
* @ new_termios : desired new value
*
* Perform updates to the termios values set on this terminal . There
* is a bit of layering violation here with n_tty in terms of the
* internal knowledge of this function .
*
2008-10-13 13:41:42 +04:00
* Locking : termios_mutex
2006-08-27 12:24:01 +04:00
*/
2008-02-08 15:18:48 +03:00
static void change_termios ( struct tty_struct * tty , struct ktermios * new_termios )
2005-04-17 02:20:36 +04:00
{
2008-04-30 11:53:59 +04:00
struct ktermios old_termios ;
2005-04-17 02:20:36 +04:00
struct tty_ldisc * ld ;
2008-04-30 11:53:29 +04:00
unsigned long flags ;
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
/*
* Perform the actual termios internal changes under lock .
*/
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
2006-09-29 13:00:43 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2008-04-30 11:53:59 +04:00
old_termios = * tty - > termios ;
2005-04-17 02:20:36 +04:00
* tty - > termios = * new_termios ;
unset_locked_termios ( tty - > termios , & old_termios , tty - > termios_locked ) ;
/* See if packet mode change of state. */
if ( tty - > link & & tty - > link - > packet ) {
int old_flow = ( ( old_termios . c_iflag & IXON ) & &
( old_termios . c_cc [ VSTOP ] = = ' \023 ' ) & &
( old_termios . c_cc [ VSTART ] = = ' \021 ' ) ) ;
int new_flow = ( I_IXON ( tty ) & &
STOP_CHAR ( tty ) = = ' \023 ' & &
START_CHAR ( tty ) = = ' \021 ' ) ;
if ( old_flow ! = new_flow ) {
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_DOSTOP | TIOCPKT_NOSTOP ) ;
if ( new_flow )
tty - > ctrl_status | = TIOCPKT_DOSTOP ;
else
tty - > ctrl_status | = TIOCPKT_NOSTOP ;
2008-04-30 11:53:29 +04:00
spin_unlock_irqrestore ( & tty - > ctrl_lock , flags ) ;
2005-04-17 02:20:36 +04:00
wake_up_interruptible ( & tty - > link - > read_wait ) ;
}
}
2008-02-08 15:18:48 +03:00
2008-04-30 11:54:13 +04:00
if ( tty - > ops - > set_termios )
( * tty - > ops - > set_termios ) ( tty , & old_termios ) ;
2007-10-17 10:30:07 +04:00
else
tty_termios_copy_hw ( tty - > termios , & old_termios ) ;
2005-04-17 02:20:36 +04:00
ld = tty_ldisc_ref ( tty ) ;
if ( ld ! = NULL ) {
2008-07-17 00:53:12 +04:00
if ( ld - > ops - > set_termios )
( ld - > ops - > set_termios ) ( tty , & old_termios ) ;
2005-04-17 02:20:36 +04:00
tty_ldisc_deref ( ld ) ;
}
2006-09-29 13:00:43 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-27 12:24:01 +04:00
/**
* set_termios - set termios values for a tty
* @ tty : terminal device
* @ arg : user data
* @ opt : option information
*
2007-10-20 01:10:43 +04:00
* Helper function to prepare termios data and run necessary other
2006-08-27 12:24:01 +04:00
* functions before using change_termios to do the actual changes .
*
* Locking :
2008-10-13 13:41:42 +04:00
* Called functions take ldisc and termios_mutex locks
2006-08-27 12:24:01 +04:00
*/
2008-02-08 15:18:48 +03:00
static int set_termios ( struct tty_struct * tty , void __user * arg , int opt )
2005-04-17 02:20:36 +04:00
{
2006-12-08 13:38:44 +03:00
struct ktermios tmp_termios ;
2005-04-17 02:20:36 +04:00
struct tty_ldisc * ld ;
int retval = tty_check_change ( tty ) ;
if ( retval )
return retval ;
2008-04-30 11:53:59 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2006-12-08 13:38:47 +03:00
memcpy ( & tmp_termios , tty - > termios , sizeof ( struct ktermios ) ) ;
2008-04-30 11:53:59 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2006-12-08 13:38:47 +03:00
2005-04-17 02:20:36 +04:00
if ( opt & TERMIOS_TERMIO ) {
if ( user_termio_to_kernel_termios ( & tmp_termios ,
( struct termio __user * ) arg ) )
return - EFAULT ;
2006-12-08 13:38:44 +03:00
# ifdef TCGETS2
} else if ( opt & TERMIOS_OLD ) {
if ( user_termios_to_kernel_termios_1 ( & tmp_termios ,
2006-12-08 13:38:47 +03:00
( struct termios __user * ) arg ) )
2006-12-08 13:38:44 +03:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
} else {
if ( user_termios_to_kernel_termios ( & tmp_termios ,
2006-12-08 13:38:47 +03:00
( struct termios2 __user * ) arg ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
2006-12-08 13:38:47 +03:00
# else
} else if ( user_termios_to_kernel_termios ( & tmp_termios ,
( struct termios __user * ) arg ) )
return - EFAULT ;
# endif
2005-04-17 02:20:36 +04:00
2008-02-08 15:18:48 +03:00
/* If old style Bfoo values are used then load c_ispeed/c_ospeed
* with the real speed so its unconditionally usable */
2006-12-08 13:38:44 +03:00
tmp_termios . c_ispeed = tty_termios_input_baud_rate ( & tmp_termios ) ;
tmp_termios . c_ospeed = tty_termios_baud_rate ( & tmp_termios ) ;
2005-04-17 02:20:36 +04:00
ld = tty_ldisc_ref ( tty ) ;
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
if ( ld ! = NULL ) {
2008-07-17 00:53:12 +04:00
if ( ( opt & TERMIOS_FLUSH ) & & ld - > ops - > flush_buffer )
ld - > ops - > flush_buffer ( tty ) ;
2005-04-17 02:20:36 +04:00
tty_ldisc_deref ( ld ) ;
}
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
if ( opt & TERMIOS_WAIT ) {
tty_wait_until_sent ( tty , 0 ) ;
if ( signal_pending ( current ) )
return - EINTR ;
}
change_termios ( tty , & tmp_termios ) ;
2007-10-17 10:30:07 +04:00
/* FIXME: Arguably if tmp_termios == tty->termios AND the
actual requested termios was not tmp_termios then we may
want to return an error as no user requested change has
succeeded */
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-06-11 17:03:13 +04:00
static void copy_termios ( struct tty_struct * tty , struct ktermios * kterm )
{
mutex_lock ( & tty - > termios_mutex ) ;
memcpy ( kterm , tty - > termios , sizeof ( struct ktermios ) ) ;
mutex_unlock ( & tty - > termios_mutex ) ;
}
static void copy_termios_locked ( struct tty_struct * tty , struct ktermios * kterm )
{
mutex_lock ( & tty - > termios_mutex ) ;
memcpy ( kterm , tty - > termios_locked , sizeof ( struct ktermios ) ) ;
mutex_unlock ( & tty - > termios_mutex ) ;
}
2008-02-08 15:18:48 +03:00
static int get_termio ( struct tty_struct * tty , struct termio __user * termio )
2005-04-17 02:20:36 +04:00
{
2009-06-11 17:03:13 +04:00
struct ktermios kterm ;
copy_termios ( tty , & kterm ) ;
if ( kernel_termios_to_user_termio ( termio , & kterm ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return 0 ;
}
2008-10-13 13:38:18 +04:00
# ifdef TCGETX
/**
* set_termiox - set termiox fields if possible
* @ tty : terminal
* @ arg : termiox structure from user
* @ opt : option flags for ioctl type
*
* Implement the device calling points for the SYS5 termiox ioctl
* interface in Linux
*/
static int set_termiox ( struct tty_struct * tty , void __user * arg , int opt )
{
struct termiox tnew ;
struct tty_ldisc * ld ;
if ( tty - > termiox = = NULL )
return - EINVAL ;
if ( copy_from_user ( & tnew , arg , sizeof ( struct termiox ) ) )
return - EFAULT ;
ld = tty_ldisc_ref ( tty ) ;
if ( ld ! = NULL ) {
if ( ( opt & TERMIOS_FLUSH ) & & ld - > ops - > flush_buffer )
ld - > ops - > flush_buffer ( tty ) ;
tty_ldisc_deref ( ld ) ;
}
if ( opt & TERMIOS_WAIT ) {
tty_wait_until_sent ( tty , 0 ) ;
if ( signal_pending ( current ) )
return - EINTR ;
}
mutex_lock ( & tty - > termios_mutex ) ;
if ( tty - > ops - > set_termiox )
tty - > ops - > set_termiox ( tty , & tnew ) ;
mutex_unlock ( & tty - > termios_mutex ) ;
return 0 ;
}
# endif
2005-04-17 02:20:36 +04:00
# ifdef TIOCGETP
/*
* These are deprecated , but there is limited support . .
*
* The " sg_flags " translation is a joke . .
*/
2008-02-08 15:18:48 +03:00
static int get_sgflags ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
int flags = 0 ;
if ( ! ( tty - > termios - > c_lflag & ICANON ) ) {
if ( tty - > termios - > c_lflag & ISIG )
flags | = 0x02 ; /* cbreak */
else
flags | = 0x20 ; /* raw */
}
if ( tty - > termios - > c_lflag & ECHO )
flags | = 0x08 ; /* echo */
if ( tty - > termios - > c_oflag & OPOST )
if ( tty - > termios - > c_oflag & ONLCR )
flags | = 0x10 ; /* crmod */
return flags ;
}
2008-02-08 15:18:48 +03:00
static int get_sgttyb ( struct tty_struct * tty , struct sgttyb __user * sgttyb )
2005-04-17 02:20:36 +04:00
{
struct sgttyb tmp ;
2006-09-29 13:00:43 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2006-12-08 13:38:45 +03:00
tmp . sg_ispeed = tty - > termios - > c_ispeed ;
tmp . sg_ospeed = tty - > termios - > c_ospeed ;
2005-04-17 02:20:36 +04:00
tmp . sg_erase = tty - > termios - > c_cc [ VERASE ] ;
tmp . sg_kill = tty - > termios - > c_cc [ VKILL ] ;
tmp . sg_flags = get_sgflags ( tty ) ;
2006-09-29 13:00:43 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
return copy_to_user ( sgttyb , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2008-02-08 15:18:48 +03:00
static void set_sgflags ( struct ktermios * termios , int flags )
2005-04-17 02:20:36 +04:00
{
termios - > c_iflag = ICRNL | IXON ;
termios - > c_oflag = 0 ;
termios - > c_lflag = ISIG | ICANON ;
if ( flags & 0x02 ) { /* cbreak */
termios - > c_iflag = 0 ;
termios - > c_lflag & = ~ ICANON ;
}
if ( flags & 0x08 ) { /* echo */
termios - > c_lflag | = ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN ;
}
if ( flags & 0x10 ) { /* crmod */
termios - > c_oflag | = OPOST | ONLCR ;
}
if ( flags & 0x20 ) { /* raw */
termios - > c_iflag = 0 ;
termios - > c_lflag & = ~ ( ISIG | ICANON ) ;
}
if ( ! ( termios - > c_lflag & ICANON ) ) {
termios - > c_cc [ VMIN ] = 1 ;
termios - > c_cc [ VTIME ] = 0 ;
}
}
2006-08-27 12:24:01 +04:00
/**
* set_sgttyb - set legacy terminal values
* @ tty : tty structure
* @ sgttyb : pointer to old style terminal structure
*
* Updates a terminal from the legacy BSD style terminal information
* structure .
*
2008-10-13 13:41:42 +04:00
* Locking : termios_mutex
2006-08-27 12:24:01 +04:00
*/
2008-02-08 15:18:48 +03:00
static int set_sgttyb ( struct tty_struct * tty , struct sgttyb __user * sgttyb )
2005-04-17 02:20:36 +04:00
{
int retval ;
struct sgttyb tmp ;
2006-12-08 13:38:44 +03:00
struct ktermios termios ;
2005-04-17 02:20:36 +04:00
retval = tty_check_change ( tty ) ;
if ( retval )
return retval ;
2008-02-08 15:18:48 +03:00
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & tmp , sgttyb , sizeof ( tmp ) ) )
return - EFAULT ;
2006-09-29 13:00:43 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2007-07-16 10:40:18 +04:00
termios = * tty - > termios ;
2005-04-17 02:20:36 +04:00
termios . c_cc [ VERASE ] = tmp . sg_erase ;
termios . c_cc [ VKILL ] = tmp . sg_kill ;
set_sgflags ( & termios , tmp . sg_flags ) ;
2006-12-08 13:38:44 +03:00
/* Try and encode into Bfoo format */
# ifdef BOTHER
2008-02-08 15:18:48 +03:00
tty_termios_encode_baud_rate ( & termios , termios . c_ispeed ,
termios . c_ospeed ) ;
2006-12-08 13:38:44 +03:00
# endif
2006-09-29 13:00:43 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
change_termios ( tty , & termios ) ;
return 0 ;
}
# endif
# ifdef TIOCGETC
2008-02-08 15:18:48 +03:00
static int get_tchars ( struct tty_struct * tty , struct tchars __user * tchars )
2005-04-17 02:20:36 +04:00
{
struct tchars tmp ;
2008-04-30 11:53:59 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
tmp . t_intrc = tty - > termios - > c_cc [ VINTR ] ;
tmp . t_quitc = tty - > termios - > c_cc [ VQUIT ] ;
tmp . t_startc = tty - > termios - > c_cc [ VSTART ] ;
tmp . t_stopc = tty - > termios - > c_cc [ VSTOP ] ;
tmp . t_eofc = tty - > termios - > c_cc [ VEOF ] ;
tmp . t_brkc = tty - > termios - > c_cc [ VEOL2 ] ; /* what is brkc anyway? */
2008-04-30 11:53:59 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
return copy_to_user ( tchars , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2008-02-08 15:18:48 +03:00
static int set_tchars ( struct tty_struct * tty , struct tchars __user * tchars )
2005-04-17 02:20:36 +04:00
{
struct tchars tmp ;
if ( copy_from_user ( & tmp , tchars , sizeof ( tmp ) ) )
return - EFAULT ;
2008-04-30 11:53:59 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
tty - > termios - > c_cc [ VINTR ] = tmp . t_intrc ;
tty - > termios - > c_cc [ VQUIT ] = tmp . t_quitc ;
tty - > termios - > c_cc [ VSTART ] = tmp . t_startc ;
tty - > termios - > c_cc [ VSTOP ] = tmp . t_stopc ;
tty - > termios - > c_cc [ VEOF ] = tmp . t_eofc ;
tty - > termios - > c_cc [ VEOL2 ] = tmp . t_brkc ; /* what is brkc anyway? */
2008-04-30 11:53:59 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif
# ifdef TIOCGLTC
2008-02-08 15:18:48 +03:00
static int get_ltchars ( struct tty_struct * tty , struct ltchars __user * ltchars )
2005-04-17 02:20:36 +04:00
{
struct ltchars tmp ;
2008-04-30 11:53:59 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
tmp . t_suspc = tty - > termios - > c_cc [ VSUSP ] ;
2008-02-08 15:18:48 +03:00
/* what is dsuspc anyway? */
tmp . t_dsuspc = tty - > termios - > c_cc [ VSUSP ] ;
2005-04-17 02:20:36 +04:00
tmp . t_rprntc = tty - > termios - > c_cc [ VREPRINT ] ;
2008-02-08 15:18:48 +03:00
/* what is flushc anyway? */
tmp . t_flushc = tty - > termios - > c_cc [ VEOL2 ] ;
2005-04-17 02:20:36 +04:00
tmp . t_werasc = tty - > termios - > c_cc [ VWERASE ] ;
tmp . t_lnextc = tty - > termios - > c_cc [ VLNEXT ] ;
2008-04-30 11:53:59 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
return copy_to_user ( ltchars , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2008-02-08 15:18:48 +03:00
static int set_ltchars ( struct tty_struct * tty , struct ltchars __user * ltchars )
2005-04-17 02:20:36 +04:00
{
struct ltchars tmp ;
if ( copy_from_user ( & tmp , ltchars , sizeof ( tmp ) ) )
return - EFAULT ;
2008-04-30 11:53:59 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
tty - > termios - > c_cc [ VSUSP ] = tmp . t_suspc ;
2008-02-08 15:18:48 +03:00
/* what is dsuspc anyway? */
tty - > termios - > c_cc [ VEOL2 ] = tmp . t_dsuspc ;
2005-04-17 02:20:36 +04:00
tty - > termios - > c_cc [ VREPRINT ] = tmp . t_rprntc ;
2008-02-08 15:18:48 +03:00
/* what is flushc anyway? */
tty - > termios - > c_cc [ VEOL2 ] = tmp . t_flushc ;
2005-04-17 02:20:36 +04:00
tty - > termios - > c_cc [ VWERASE ] = tmp . t_werasc ;
tty - > termios - > c_cc [ VLNEXT ] = tmp . t_lnextc ;
2008-04-30 11:53:59 +04:00
mutex_unlock ( & tty - > termios_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif
2006-08-27 12:24:01 +04:00
/**
* send_prio_char - send priority character
*
* Send a high priority character to the tty even if stopped
*
2006-09-29 13:01:40 +04:00
* Locking : none for xchar method , write ordering for write method .
2005-04-17 02:20:36 +04:00
*/
2006-08-27 12:24:01 +04:00
2006-09-29 13:01:40 +04:00
static int send_prio_char ( struct tty_struct * tty , char ch )
2005-04-17 02:20:36 +04:00
{
int was_stopped = tty - > stopped ;
2008-04-30 11:54:13 +04:00
if ( tty - > ops - > send_xchar ) {
tty - > ops - > send_xchar ( tty , ch ) ;
2006-09-29 13:01:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-09-29 13:01:40 +04:00
2007-07-16 10:39:43 +04:00
if ( tty_write_lock ( tty , 0 ) < 0 )
2006-09-29 13:01:40 +04:00
return - ERESTARTSYS ;
2005-04-17 02:20:36 +04:00
if ( was_stopped )
start_tty ( tty ) ;
2008-04-30 11:54:13 +04:00
tty - > ops - > write ( tty , & ch , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( was_stopped )
stop_tty ( tty ) ;
2007-07-16 10:39:43 +04:00
tty_write_unlock ( tty ) ;
2006-09-29 13:01:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-04-30 11:53:34 +04:00
/**
* tty_change_softcar - carrier change ioctl helper
* @ tty : tty to update
* @ arg : enable / disable CLOCAL
*
* Perform a change to the CLOCAL state and call into the driver
* layer to make it visible . All done with the termios mutex
*/
static int tty_change_softcar ( struct tty_struct * tty , int arg )
{
int ret = 0 ;
int bit = arg ? CLOCAL : 0 ;
2008-04-30 11:54:13 +04:00
struct ktermios old ;
2008-04-30 11:53:34 +04:00
mutex_lock ( & tty - > termios_mutex ) ;
2008-04-30 11:54:13 +04:00
old = * tty - > termios ;
2008-04-30 11:53:34 +04:00
tty - > termios - > c_cflag & = ~ CLOCAL ;
tty - > termios - > c_cflag | = bit ;
2008-04-30 11:54:13 +04:00
if ( tty - > ops - > set_termios )
tty - > ops - > set_termios ( tty , & old ) ;
2008-04-30 11:53:34 +04:00
if ( ( tty - > termios - > c_cflag & CLOCAL ) ! = bit )
ret = - EINVAL ;
mutex_unlock ( & tty - > termios_mutex ) ;
return ret ;
}
2007-11-07 12:24:56 +03:00
/**
* tty_mode_ioctl - mode related ioctls
* @ tty : tty for the ioctl
* @ file : file pointer for the tty
* @ cmd : command
* @ arg : ioctl argument
*
* Perform non line discipline specific mode control ioctls . This
* is designed to be called by line disciplines to ensure they provide
* consistent mode setting .
*/
2008-02-08 15:18:48 +03:00
int tty_mode_ioctl ( struct tty_struct * tty , struct file * file ,
2007-11-07 12:24:56 +03:00
unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:18:48 +03:00
struct tty_struct * real_tty ;
2005-04-17 02:20:36 +04:00
void __user * p = ( void __user * ) arg ;
2008-10-13 13:38:46 +04:00
int ret = 0 ;
2009-06-11 17:03:13 +04:00
struct ktermios kterm ;
2005-04-17 02:20:36 +04:00
if ( tty - > driver - > type = = TTY_DRIVER_TYPE_PTY & &
tty - > driver - > subtype = = PTY_TYPE_MASTER )
real_tty = tty - > link ;
else
real_tty = tty ;
switch ( cmd ) {
# ifdef TIOCGETP
2008-02-08 15:18:48 +03:00
case TIOCGETP :
return get_sgttyb ( real_tty , ( struct sgttyb __user * ) arg ) ;
case TIOCSETP :
case TIOCSETN :
return set_sgttyb ( real_tty , ( struct sgttyb __user * ) arg ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef TIOCGETC
2008-02-08 15:18:48 +03:00
case TIOCGETC :
return get_tchars ( real_tty , p ) ;
case TIOCSETC :
return set_tchars ( real_tty , p ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef TIOCGLTC
2008-02-08 15:18:48 +03:00
case TIOCGLTC :
return get_ltchars ( real_tty , p ) ;
case TIOCSLTC :
return set_ltchars ( real_tty , p ) ;
2005-04-17 02:20:36 +04:00
# endif
2008-02-08 15:18:48 +03:00
case TCSETSF :
return set_termios ( real_tty , p , TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD ) ;
case TCSETSW :
return set_termios ( real_tty , p , TERMIOS_WAIT | TERMIOS_OLD ) ;
case TCSETS :
return set_termios ( real_tty , p , TERMIOS_OLD ) ;
2006-12-08 13:38:44 +03:00
# ifndef TCGETS2
2008-02-08 15:18:48 +03:00
case TCGETS :
2009-06-11 17:03:13 +04:00
copy_termios ( real_tty , & kterm ) ;
if ( kernel_termios_to_user_termios ( ( struct termios __user * ) arg , & kterm ) )
2008-10-13 13:38:46 +04:00
ret = - EFAULT ;
return ret ;
2006-12-08 13:38:44 +03:00
# else
2008-02-08 15:18:48 +03:00
case TCGETS :
2009-06-11 17:03:13 +04:00
copy_termios ( real_tty , & kterm ) ;
if ( kernel_termios_to_user_termios_1 ( ( struct termios __user * ) arg , & kterm ) )
2008-10-13 13:38:46 +04:00
ret = - EFAULT ;
return ret ;
2008-02-08 15:18:48 +03:00
case TCGETS2 :
2009-06-11 17:03:13 +04:00
copy_termios ( real_tty , & kterm ) ;
if ( kernel_termios_to_user_termios ( ( struct termios2 __user * ) arg , & kterm ) )
2008-10-13 13:38:46 +04:00
ret = - EFAULT ;
return ret ;
2008-02-08 15:18:48 +03:00
case TCSETSF2 :
return set_termios ( real_tty , p , TERMIOS_FLUSH | TERMIOS_WAIT ) ;
case TCSETSW2 :
return set_termios ( real_tty , p , TERMIOS_WAIT ) ;
case TCSETS2 :
return set_termios ( real_tty , p , 0 ) ;
2006-12-08 13:38:44 +03:00
# endif
2008-02-08 15:18:48 +03:00
case TCGETA :
return get_termio ( real_tty , p ) ;
case TCSETAF :
return set_termios ( real_tty , p , TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO ) ;
case TCSETAW :
return set_termios ( real_tty , p , TERMIOS_WAIT | TERMIOS_TERMIO ) ;
case TCSETA :
return set_termios ( real_tty , p , TERMIOS_TERMIO ) ;
2007-11-07 12:24:56 +03:00
# ifndef TCGETS2
2008-02-08 15:18:48 +03:00
case TIOCGLCKTRMIOS :
2009-06-11 17:03:13 +04:00
copy_termios_locked ( real_tty , & kterm ) ;
if ( kernel_termios_to_user_termios ( ( struct termios __user * ) arg , & kterm ) )
2008-10-13 13:38:46 +04:00
ret = - EFAULT ;
return ret ;
2008-02-08 15:18:48 +03:00
case TIOCSLCKTRMIOS :
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
2009-06-11 17:03:13 +04:00
copy_termios_locked ( real_tty , & kterm ) ;
if ( user_termios_to_kernel_termios ( & kterm ,
2008-02-08 15:18:48 +03:00
( struct termios __user * ) arg ) )
2009-06-11 17:03:13 +04:00
return - EFAULT ;
mutex_lock ( & real_tty - > termios_mutex ) ;
memcpy ( real_tty - > termios_locked , & kterm , sizeof ( struct ktermios ) ) ;
2008-10-13 13:38:46 +04:00
mutex_unlock ( & real_tty - > termios_mutex ) ;
2009-06-11 17:03:13 +04:00
return 0 ;
2007-11-07 12:24:56 +03:00
# else
2008-02-08 15:18:48 +03:00
case TIOCGLCKTRMIOS :
2009-06-11 17:03:13 +04:00
copy_termios_locked ( real_tty , & kterm ) ;
if ( kernel_termios_to_user_termios_1 ( ( struct termios __user * ) arg , & kterm ) )
2008-10-13 13:38:46 +04:00
ret = - EFAULT ;
return ret ;
2008-02-08 15:18:48 +03:00
case TIOCSLCKTRMIOS :
if ( ! capable ( CAP_SYS_ADMIN ) )
2009-06-11 17:03:13 +04:00
return - EPERM ;
copy_termios_locked ( real_tty , & kterm ) ;
if ( user_termios_to_kernel_termios_1 ( & kterm ,
2008-02-08 15:18:48 +03:00
( struct termios __user * ) arg ) )
2009-06-11 17:03:13 +04:00
return - EFAULT ;
mutex_lock ( & real_tty - > termios_mutex ) ;
memcpy ( real_tty - > termios_locked , & kterm , sizeof ( struct ktermios ) ) ;
2008-10-13 13:38:46 +04:00
mutex_unlock ( & real_tty - > termios_mutex ) ;
return ret ;
2007-11-07 12:24:56 +03:00
# endif
2008-10-13 13:38:18 +04:00
# ifdef TCGETX
2009-06-16 20:01:02 +04:00
case TCGETX : {
struct termiox ktermx ;
2008-10-13 13:38:18 +04:00
if ( real_tty - > termiox = = NULL )
return - EINVAL ;
2008-10-13 13:38:46 +04:00
mutex_lock ( & real_tty - > termios_mutex ) ;
2009-06-11 17:03:13 +04:00
memcpy ( & ktermx , real_tty - > termiox , sizeof ( struct termiox ) ) ;
2008-10-13 13:38:46 +04:00
mutex_unlock ( & real_tty - > termios_mutex ) ;
2009-06-11 17:03:13 +04:00
if ( copy_to_user ( p , & ktermx , sizeof ( struct termiox ) ) )
ret = - EFAULT ;
2008-10-13 13:38:46 +04:00
return ret ;
2009-06-16 20:01:02 +04:00
}
2008-10-13 13:38:18 +04:00
case TCSETX :
return set_termiox ( real_tty , p , 0 ) ;
case TCSETXW :
return set_termiox ( real_tty , p , TERMIOS_WAIT ) ;
case TCSETXF :
return set_termiox ( real_tty , p , TERMIOS_FLUSH ) ;
# endif
2008-02-08 15:18:48 +03:00
case TIOCGSOFTCAR :
2009-06-11 17:03:13 +04:00
copy_termios ( real_tty , & kterm ) ;
ret = put_user ( ( kterm . c_cflag & CLOCAL ) ? 1 : 0 ,
2008-02-08 15:18:48 +03:00
( int __user * ) arg ) ;
2008-10-13 13:38:46 +04:00
return ret ;
2008-02-08 15:18:48 +03:00
case TIOCSSOFTCAR :
if ( get_user ( arg , ( unsigned int __user * ) arg ) )
return - EFAULT ;
2008-08-26 22:52:47 +04:00
return tty_change_softcar ( real_tty , arg ) ;
2008-02-08 15:18:48 +03:00
default :
return - ENOIOCTLCMD ;
2007-11-07 12:24:56 +03:00
}
}
EXPORT_SYMBOL_GPL ( tty_mode_ioctl ) ;
int tty_perform_flush ( struct tty_struct * tty , unsigned long arg )
{
struct tty_ldisc * ld ;
int retval = tty_check_change ( tty ) ;
if ( retval )
return retval ;
2009-01-15 16:30:25 +03:00
ld = tty_ldisc_ref_wait ( tty ) ;
2007-11-07 12:24:56 +03:00
switch ( arg ) {
case TCIFLUSH :
2008-07-17 00:53:12 +04:00
if ( ld & & ld - > ops - > flush_buffer )
ld - > ops - > flush_buffer ( tty ) ;
2007-11-07 12:24:56 +03:00
break ;
case TCIOFLUSH :
2008-07-17 00:53:12 +04:00
if ( ld & & ld - > ops - > flush_buffer )
ld - > ops - > flush_buffer ( tty ) ;
2007-11-07 12:24:56 +03:00
/* fall through */
case TCOFLUSH :
2008-04-30 11:54:13 +04:00
tty_driver_flush_buffer ( tty ) ;
2007-11-07 12:24:56 +03:00
break ;
default :
tty_ldisc_deref ( ld ) ;
return - EINVAL ;
}
tty_ldisc_deref ( ld ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( tty_perform_flush ) ;
2008-10-13 13:44:17 +04:00
int n_tty_ioctl_helper ( struct tty_struct * tty , struct file * file ,
2007-11-07 12:24:56 +03:00
unsigned int cmd , unsigned long arg )
{
2008-04-30 11:53:29 +04:00
unsigned long flags ;
2007-11-07 12:24:56 +03:00
int retval ;
switch ( cmd ) {
2008-02-08 15:18:48 +03:00
case TCXONC :
retval = tty_check_change ( tty ) ;
if ( retval )
return retval ;
switch ( arg ) {
case TCOOFF :
if ( ! tty - > flow_stopped ) {
tty - > flow_stopped = 1 ;
stop_tty ( tty ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:18:48 +03:00
break ;
case TCOON :
if ( tty - > flow_stopped ) {
tty - > flow_stopped = 0 ;
start_tty ( tty ) ;
}
break ;
case TCIOFF :
if ( STOP_CHAR ( tty ) ! = __DISABLED_CHAR )
return send_prio_char ( tty , STOP_CHAR ( tty ) ) ;
break ;
case TCION :
if ( START_CHAR ( tty ) ! = __DISABLED_CHAR )
return send_prio_char ( tty , START_CHAR ( tty ) ) ;
break ;
2005-04-17 02:20:36 +04:00
default :
2008-02-08 15:18:48 +03:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:18:48 +03:00
return 0 ;
case TCFLSH :
return tty_perform_flush ( tty , arg ) ;
case TIOCPKT :
{
int pktmode ;
if ( tty - > driver - > type ! = TTY_DRIVER_TYPE_PTY | |
tty - > driver - > subtype ! = PTY_TYPE_MASTER )
return - ENOTTY ;
if ( get_user ( pktmode , ( int __user * ) arg ) )
return - EFAULT ;
2008-04-30 11:53:29 +04:00
spin_lock_irqsave ( & tty - > ctrl_lock , flags ) ;
2008-02-08 15:18:48 +03:00
if ( pktmode ) {
if ( ! tty - > packet ) {
tty - > packet = 1 ;
tty - > link - > ctrl_status = 0 ;
}
} else
tty - > packet = 0 ;
2008-04-30 11:53:29 +04:00
spin_unlock_irqrestore ( & tty - > ctrl_lock , flags ) ;
2008-02-08 15:18:48 +03:00
return 0 ;
}
default :
/* Try the mode commands */
return tty_mode_ioctl ( tty , file , cmd , arg ) ;
}
2005-04-17 02:20:36 +04:00
}
2008-10-13 13:44:17 +04:00
EXPORT_SYMBOL ( n_tty_ioctl_helper ) ;