2006-03-26 13:38:32 +04:00
/*
* interface to user space for the gigaset driver
*
* Copyright ( c ) 2004 by Hansjoerg Lipp < hjlipp @ web . de >
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "gigaset.h"
# include <linux/gigaset_dev.h>
# include <linux/tty_flip.h>
2011-08-30 20:08:51 +04:00
# include <linux/module.h>
2006-03-26 13:38:32 +04:00
/*** our ioctls ***/
static int if_lock ( struct cardstate * cs , int * arg )
{
int cmd = * arg ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: if_lock (%d) " , cs - > minor_index , cmd ) ;
2006-03-26 13:38:32 +04:00
if ( cmd > 1 )
return - EINVAL ;
if ( cmd < 0 ) {
2008-02-06 12:38:28 +03:00
* arg = cs - > mstate = = MS_LOCKED ;
2006-03-26 13:38:32 +04:00
return 0 ;
}
2008-02-06 12:38:28 +03:00
if ( ! cmd & & cs - > mstate = = MS_LOCKED & & cs - > connected ) {
2012-02-20 07:52:38 +04:00
cs - > ops - > set_modem_ctrl ( cs , 0 , TIOCM_DTR | TIOCM_RTS ) ;
2006-03-26 13:38:32 +04:00
cs - > ops - > baud_rate ( cs , B115200 ) ;
cs - > ops - > set_line_ctrl ( cs , CS8 ) ;
2012-02-20 07:52:38 +04:00
cs - > control_state = TIOCM_DTR | TIOCM_RTS ;
2006-03-26 13:38:32 +04:00
}
cs - > waiting = 1 ;
if ( ! gigaset_add_event ( cs , & cs - > at_state , EV_IF_LOCK ,
2006-04-11 09:55:04 +04:00
NULL , cmd , NULL ) ) {
2006-03-26 13:38:32 +04:00
cs - > waiting = 0 ;
return - ENOMEM ;
}
gigaset_schedule_event ( cs ) ;
wait_event ( cs - > waitqueue , ! cs - > waiting ) ;
if ( cs - > cmd_result > = 0 ) {
* arg = cs - > cmd_result ;
return 0 ;
}
return cs - > cmd_result ;
}
static int if_version ( struct cardstate * cs , unsigned arg [ 4 ] )
{
static const unsigned version [ 4 ] = GIG_VERSION ;
static const unsigned compat [ 4 ] = GIG_COMPAT ;
unsigned cmd = arg [ 0 ] ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: if_version (%d) " , cs - > minor_index , cmd ) ;
2006-03-26 13:38:32 +04:00
switch ( cmd ) {
case GIGVER_DRIVER :
memcpy ( arg , version , sizeof version ) ;
return 0 ;
case GIGVER_COMPAT :
memcpy ( arg , compat , sizeof compat ) ;
return 0 ;
case GIGVER_FWBASE :
cs - > waiting = 1 ;
if ( ! gigaset_add_event ( cs , & cs - > at_state , EV_IF_VER ,
2006-04-11 09:55:04 +04:00
NULL , 0 , arg ) ) {
2006-03-26 13:38:32 +04:00
cs - > waiting = 0 ;
return - ENOMEM ;
}
gigaset_schedule_event ( cs ) ;
wait_event ( cs - > waitqueue , ! cs - > waiting ) ;
if ( cs - > cmd_result > = 0 )
return 0 ;
return cs - > cmd_result ;
default :
return - EINVAL ;
}
}
static int if_config ( struct cardstate * cs , int * arg )
{
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: if_config (%d) " , cs - > minor_index , * arg ) ;
2006-03-26 13:38:32 +04:00
if ( * arg ! = 1 )
return - EINVAL ;
2008-02-06 12:38:28 +03:00
if ( cs - > mstate ! = MS_LOCKED )
2006-03-26 13:38:32 +04:00
return - EBUSY ;
2006-04-11 09:55:16 +04:00
if ( ! cs - > connected ) {
2008-12-26 12:21:29 +03:00
pr_err ( " %s: not connected \n " , __func__ ) ;
2006-04-11 09:55:16 +04:00
return - ENODEV ;
}
2006-03-26 13:38:32 +04:00
* arg = 0 ;
return gigaset_enterconfigmode ( cs ) ;
}
/*** the terminal driver ***/
/* stolen from usbserial and some other tty drivers */
static int if_open ( struct tty_struct * tty , struct file * filp ) ;
static void if_close ( struct tty_struct * tty , struct file * filp ) ;
2011-02-14 19:27:22 +03:00
static int if_ioctl ( struct tty_struct * tty ,
2006-04-11 09:55:04 +04:00
unsigned int cmd , unsigned long arg ) ;
2006-03-26 13:38:32 +04:00
static int if_write_room ( struct tty_struct * tty ) ;
static int if_chars_in_buffer ( struct tty_struct * tty ) ;
static void if_throttle ( struct tty_struct * tty ) ;
static void if_unthrottle ( struct tty_struct * tty ) ;
2006-12-08 13:38:45 +03:00
static void if_set_termios ( struct tty_struct * tty , struct ktermios * old ) ;
2011-02-14 19:26:14 +03:00
static int if_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 19:26:50 +03:00
static int if_tiocmset ( struct tty_struct * tty ,
2006-04-11 09:55:04 +04:00
unsigned int set , unsigned int clear ) ;
2006-03-26 13:38:32 +04:00
static int if_write ( struct tty_struct * tty ,
2006-04-11 09:55:04 +04:00
const unsigned char * buf , int count ) ;
2006-03-26 13:38:32 +04:00
2006-10-02 13:17:18 +04:00
static const struct tty_operations if_ops = {
2006-03-26 13:38:32 +04:00
. open = if_open ,
. close = if_close ,
. ioctl = if_ioctl ,
. write = if_write ,
. write_room = if_write_room ,
. chars_in_buffer = if_chars_in_buffer ,
. set_termios = if_set_termios ,
. throttle = if_throttle ,
. unthrottle = if_unthrottle ,
. tiocmget = if_tiocmget ,
. tiocmset = if_tiocmset ,
} ;
static int if_open ( struct tty_struct * tty , struct file * filp )
{
struct cardstate * cs ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %d+%d: %s() " ,
tty - > driver - > minor_start , tty - > index , __func__ ) ;
2006-03-26 13:38:32 +04:00
cs = gigaset_get_cs_by_tty ( tty ) ;
2008-02-06 12:38:29 +03:00
if ( ! cs | | ! try_module_get ( cs - > driver - > owner ) )
2006-03-26 13:38:32 +04:00
return - ENODEV ;
2011-06-17 10:25:11 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) ) {
module_put ( cs - > driver - > owner ) ;
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2011-06-17 10:25:11 +04:00
}
2006-03-26 13:38:32 +04:00
tty - > driver_data = cs ;
2012-03-05 17:52:55 +04:00
+ + cs - > port . count ;
2006-03-26 13:38:32 +04:00
2012-03-05 17:52:55 +04:00
if ( cs - > port . count = = 1 ) {
tty_port_tty_set ( & cs - > port , tty ) ;
2009-10-25 12:30:17 +03:00
tty - > low_latency = 1 ;
2006-03-26 13:38:32 +04:00
}
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return 0 ;
}
static void if_close ( struct tty_struct * tty , struct file * filp )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
2012-03-05 17:52:54 +04:00
if ( ! cs ) { /* happens if we didn't find cs in open */
2012-03-25 21:12:37 +04:00
gig_dbg ( DEBUG_IF , " %s: no cardstate " , __func__ ) ;
2006-03-26 13:38:32 +04:00
return ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected )
gig_dbg ( DEBUG_IF , " not connected " ) ; /* nothing to do */
2012-03-05 17:52:55 +04:00
else if ( ! cs - > port . count )
2008-07-24 08:28:27 +04:00
dev_warn ( cs - > dev , " %s: device not opened \n " , __func__ ) ;
2012-03-05 17:52:55 +04:00
else if ( ! - - cs - > port . count )
tty_port_tty_set ( & cs - > port , NULL ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2008-02-06 12:38:29 +03:00
module_put ( cs - > driver - > owner ) ;
2006-03-26 13:38:32 +04:00
}
2011-02-14 19:27:22 +03:00
static int if_ioctl ( struct tty_struct * tty ,
2006-04-11 09:55:04 +04:00
unsigned int cmd , unsigned long arg )
2006-03-26 13:38:32 +04:00
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
int retval = - ENODEV ;
int int_arg ;
unsigned char buf [ 6 ] ;
unsigned version [ 4 ] ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s(0x%x) " , cs - > minor_index , __func__ , cmd ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected ) {
gig_dbg ( DEBUG_IF , " not connected " ) ;
retval = - ENODEV ;
2012-03-05 17:52:54 +04:00
} else {
2006-03-26 13:38:32 +04:00
retval = 0 ;
switch ( cmd ) {
case GIGASET_REDIR :
retval = get_user ( int_arg , ( int __user * ) arg ) ;
if ( retval > = 0 )
retval = if_lock ( cs , & int_arg ) ;
if ( retval > = 0 )
retval = put_user ( int_arg , ( int __user * ) arg ) ;
break ;
case GIGASET_CONFIG :
retval = get_user ( int_arg , ( int __user * ) arg ) ;
if ( retval > = 0 )
retval = if_config ( cs , & int_arg ) ;
if ( retval > = 0 )
retval = put_user ( int_arg , ( int __user * ) arg ) ;
break ;
case GIGASET_BRKCHARS :
retval = copy_from_user ( & buf ,
2012-02-20 07:52:38 +04:00
( const unsigned char __user * ) arg , 6 )
2006-04-11 09:55:04 +04:00
? - EFAULT : 0 ;
2006-04-11 09:55:11 +04:00
if ( retval > = 0 ) {
gigaset_dbg_buffer ( DEBUG_IF , " GIGASET_BRKCHARS " ,
2012-02-20 07:52:38 +04:00
6 , ( const unsigned char * ) arg ) ;
2006-03-26 13:38:32 +04:00
retval = cs - > ops - > brkchars ( cs , buf ) ;
2006-04-11 09:55:11 +04:00
}
2006-03-26 13:38:32 +04:00
break ;
case GIGASET_VERSION :
2006-04-11 09:55:00 +04:00
retval = copy_from_user ( version ,
2012-02-20 07:52:38 +04:00
( unsigned __user * ) arg , sizeof version )
2006-04-11 09:55:04 +04:00
? - EFAULT : 0 ;
2006-03-26 13:38:32 +04:00
if ( retval > = 0 )
retval = if_version ( cs , version ) ;
if ( retval > = 0 )
2006-04-11 09:55:00 +04:00
retval = copy_to_user ( ( unsigned __user * ) arg ,
2006-04-11 09:55:04 +04:00
version , sizeof version )
? - EFAULT : 0 ;
2006-03-26 13:38:32 +04:00
break ;
2006-04-11 09:55:04 +04:00
default :
2010-02-22 16:09:52 +03:00
gig_dbg ( DEBUG_IF , " %s: arg not supported - 0x%04x " ,
2006-04-11 09:55:04 +04:00
__func__ , cmd ) ;
2006-03-26 13:38:32 +04:00
retval = - ENOIOCTLCMD ;
}
}
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
2011-02-14 19:26:14 +03:00
static int if_tiocmget ( struct tty_struct * tty )
2006-03-26 13:38:32 +04:00
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
int retval ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2006-03-26 13:38:32 +04:00
2012-02-20 07:52:38 +04:00
retval = cs - > control_state & ( TIOCM_RTS | TIOCM_DTR ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
2011-02-14 19:26:50 +03:00
static int if_tiocmset ( struct tty_struct * tty ,
2006-04-11 09:55:04 +04:00
unsigned int set , unsigned int clear )
2006-03-26 13:38:32 +04:00
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
int retval ;
unsigned mc ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s(0x%x, 0x%x) " ,
cs - > minor_index , __func__ , set , clear ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:16 +04:00
if ( ! cs - > connected ) {
2009-04-05 10:39:33 +04:00
gig_dbg ( DEBUG_IF , " not connected " ) ;
2006-03-26 13:38:32 +04:00
retval = - ENODEV ;
} else {
2012-02-20 07:52:38 +04:00
mc = ( cs - > control_state | set ) & ~ clear & ( TIOCM_RTS | TIOCM_DTR ) ;
2006-03-26 13:38:32 +04:00
retval = cs - > ops - > set_modem_ctrl ( cs , cs - > control_state , mc ) ;
cs - > control_state = mc ;
}
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
static int if_write ( struct tty_struct * tty , const unsigned char * buf , int count )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2010-07-05 18:18:43 +04:00
struct cmdbuf_t * cb ;
int retval ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected ) {
gig_dbg ( DEBUG_IF , " not connected " ) ;
retval = - ENODEV ;
2010-07-05 18:18:43 +04:00
goto done ;
}
if ( cs - > mstate ! = MS_LOCKED ) {
2008-07-24 08:28:27 +04:00
dev_warn ( cs - > dev , " can't write to unlocked device \n " ) ;
2006-03-26 13:38:32 +04:00
retval = - EBUSY ;
2010-07-05 18:18:43 +04:00
goto done ;
}
if ( count < = 0 ) {
/* nothing to do */
retval = 0 ;
goto done ;
2006-03-26 13:38:32 +04:00
}
2010-07-05 18:18:43 +04:00
cb = kmalloc ( sizeof ( struct cmdbuf_t ) + count , GFP_KERNEL ) ;
if ( ! cb ) {
dev_err ( cs - > dev , " %s: out of memory \n " , __func__ ) ;
retval = - ENOMEM ;
goto done ;
}
2006-03-26 13:38:32 +04:00
2010-07-05 18:18:43 +04:00
memcpy ( cb - > buf , buf , count ) ;
cb - > len = count ;
cb - > offset = 0 ;
cb - > next = NULL ;
cb - > wake_tasklet = & cs - > if_wake_tasklet ;
retval = cs - > ops - > write_cmd ( cs , cb ) ;
done :
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
static int if_write_room ( struct tty_struct * tty )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
int retval = - ENODEV ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
if ( mutex_lock_interruptible ( & cs - > mutex ) )
2009-10-25 12:30:17 +03:00
return - ERESTARTSYS ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected ) {
gig_dbg ( DEBUG_IF , " not connected " ) ;
retval = - ENODEV ;
2012-03-05 17:52:54 +04:00
} else if ( cs - > mstate ! = MS_LOCKED ) {
2008-07-24 08:28:27 +04:00
dev_warn ( cs - > dev , " can't write to unlocked device \n " ) ;
2008-02-06 12:38:28 +03:00
retval = - EBUSY ;
2006-03-26 13:38:32 +04:00
} else
retval = cs - > ops - > write_room ( cs ) ;
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
static int if_chars_in_buffer ( struct tty_struct * tty )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2009-08-07 07:33:33 +04:00
int retval = 0 ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2009-08-07 07:33:33 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
2009-08-07 07:33:33 +04:00
if ( ! cs - > connected )
2009-04-05 10:39:33 +04:00
gig_dbg ( DEBUG_IF , " not connected " ) ;
2009-08-07 07:33:33 +04:00
else if ( cs - > mstate ! = MS_LOCKED )
2008-07-24 08:28:27 +04:00
dev_warn ( cs - > dev , " can't write to unlocked device \n " ) ;
2009-08-07 07:33:33 +04:00
else
2006-03-26 13:38:32 +04:00
retval = cs - > ops - > chars_in_buffer ( cs ) ;
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
return retval ;
}
static void if_throttle ( struct tty_struct * tty )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected )
gig_dbg ( DEBUG_IF , " not connected " ) ; /* nothing to do */
2009-10-25 12:30:17 +03:00
else
2010-02-22 16:09:52 +03:00
gig_dbg ( DEBUG_IF , " %s: not implemented \n " , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
}
static void if_unthrottle ( struct tty_struct * tty )
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected )
gig_dbg ( DEBUG_IF , " not connected " ) ; /* nothing to do */
2009-10-25 12:30:17 +03:00
else
2010-02-22 16:09:52 +03:00
gig_dbg ( DEBUG_IF , " %s: not implemented \n " , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
}
2006-12-08 13:38:45 +03:00
static void if_set_termios ( struct tty_struct * tty , struct ktermios * old )
2006-03-26 13:38:32 +04:00
{
2012-03-05 17:52:54 +04:00
struct cardstate * cs = tty - > driver_data ;
2006-03-26 13:38:32 +04:00
unsigned int iflag ;
unsigned int cflag ;
unsigned int old_cflag ;
unsigned int control_state , new_state ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: %s() " , cs - > minor_index , __func__ ) ;
2006-03-26 13:38:32 +04:00
2006-04-11 09:55:12 +04:00
mutex_lock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
2009-04-05 10:39:33 +04:00
if ( ! cs - > connected ) {
gig_dbg ( DEBUG_IF , " not connected " ) ;
2006-03-26 13:38:32 +04:00
goto out ;
}
2012-07-14 18:31:47 +04:00
iflag = tty - > termios . c_iflag ;
cflag = tty - > termios . c_cflag ;
2009-10-25 12:30:17 +03:00
old_cflag = old ? old - > c_cflag : cflag ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: iflag %x cflag %x old %x " ,
cs - > minor_index , iflag , cflag , old_cflag ) ;
2006-03-26 13:38:32 +04:00
/* get a local copy of the current port settings */
control_state = cs - > control_state ;
/*
* Update baud rate .
* Do not attempt to cache old rates and skip settings ,
* disconnects screw such tricks up completely .
* Premature optimization is the root of all evil .
*/
2006-04-11 09:55:04 +04:00
/* reassert DTR and (maybe) RTS on transition from B0 */
2006-03-26 13:38:32 +04:00
if ( ( old_cflag & CBAUD ) = = B0 ) {
new_state = control_state | TIOCM_DTR ;
/* don't set RTS if using hardware flow control */
if ( ! ( old_cflag & CRTSCTS ) )
new_state | = TIOCM_RTS ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: from B0 - set DTR%s " ,
cs - > minor_index ,
( new_state & TIOCM_RTS ) ? " only " : " /RTS " ) ;
2006-03-26 13:38:32 +04:00
cs - > ops - > set_modem_ctrl ( cs , control_state , new_state ) ;
control_state = new_state ;
}
cs - > ops - > baud_rate ( cs , cflag & CBAUD ) ;
if ( ( cflag & CBAUD ) = = B0 ) {
/* Drop RTS and DTR */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " %u: to B0 - drop DTR/RTS " , cs - > minor_index ) ;
2006-03-26 13:38:32 +04:00
new_state = control_state & ~ ( TIOCM_DTR | TIOCM_RTS ) ;
cs - > ops - > set_modem_ctrl ( cs , control_state , new_state ) ;
control_state = new_state ;
}
/*
* Update line control register ( LCR )
*/
cs - > ops - > set_line_ctrl ( cs , cflag ) ;
/* save off the modified port settings */
cs - > control_state = control_state ;
out :
2006-04-11 09:55:12 +04:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
}
/* wakeup tasklet for the write operation */
static void if_wake ( unsigned long data )
{
2012-03-05 17:52:55 +04:00
struct cardstate * cs = ( struct cardstate * ) data ;
struct tty_struct * tty = tty_port_tty_get ( & cs - > port ) ;
2006-03-26 13:38:32 +04:00
2012-03-05 17:52:55 +04:00
if ( tty ) {
tty_wakeup ( tty ) ;
tty_kref_put ( tty ) ;
}
2006-03-26 13:38:32 +04:00
}
/*** interface to common ***/
void gigaset_if_init ( struct cardstate * cs )
{
struct gigaset_driver * drv ;
drv = cs - > driver ;
if ( ! drv - > have_tty )
return ;
2009-11-19 12:55:53 +03:00
tasklet_init ( & cs - > if_wake_tasklet , if_wake , ( unsigned long ) cs ) ;
2007-02-12 11:52:24 +03:00
mutex_lock ( & cs - > mutex ) ;
2012-08-07 23:47:47 +04:00
cs - > tty_dev = tty_port_register_device ( & cs - > port , drv - > tty ,
cs - > minor_index , NULL ) ;
2006-04-22 20:43:00 +04:00
2006-08-08 09:19:37 +04:00
if ( ! IS_ERR ( cs - > tty_dev ) )
dev_set_drvdata ( cs - > tty_dev , cs ) ;
2006-04-22 20:43:00 +04:00
else {
2009-05-13 16:44:17 +04:00
pr_warning ( " could not register device to the tty subsystem \n " ) ;
2006-08-08 09:19:37 +04:00
cs - > tty_dev = NULL ;
2006-04-22 20:43:00 +04:00
}
2007-02-12 11:52:24 +03:00
mutex_unlock ( & cs - > mutex ) ;
2006-03-26 13:38:32 +04:00
}
void gigaset_if_free ( struct cardstate * cs )
{
struct gigaset_driver * drv ;
drv = cs - > driver ;
if ( ! drv - > have_tty )
return ;
tasklet_disable ( & cs - > if_wake_tasklet ) ;
tasklet_kill ( & cs - > if_wake_tasklet ) ;
2006-08-08 09:19:37 +04:00
cs - > tty_dev = NULL ;
2006-03-26 13:38:32 +04:00
tty_unregister_device ( drv - > tty , cs - > minor_index ) ;
}
2009-10-06 16:19:01 +04:00
/**
* gigaset_if_receive ( ) - pass a received block of data to the tty device
* @ cs : device descriptor structure .
* @ buffer : received data .
* @ len : number of bytes received .
*
* Called by asyncdata / isocdata if a block of data received from the
* device must be sent to userspace through the ttyG * device .
*/
2006-03-26 13:38:32 +04:00
void gigaset_if_receive ( struct cardstate * cs ,
2006-04-11 09:55:04 +04:00
unsigned char * buffer , size_t len )
2006-03-26 13:38:32 +04:00
{
2012-03-05 17:52:55 +04:00
struct tty_struct * tty = tty_port_tty_get ( & cs - > port ) ;
2006-03-26 13:38:32 +04:00
2012-03-05 17:52:55 +04:00
if ( tty = = NULL ) {
2010-02-22 16:09:52 +03:00
gig_dbg ( DEBUG_IF , " receive on closed device " ) ;
2012-03-05 17:52:55 +04:00
return ;
2006-03-26 13:38:32 +04:00
}
2012-03-05 17:52:55 +04:00
tty_insert_flip_string ( tty , buffer , len ) ;
tty_flip_buffer_push ( tty ) ;
tty_kref_put ( tty ) ;
2006-03-26 13:38:32 +04:00
}
EXPORT_SYMBOL_GPL ( gigaset_if_receive ) ;
/* gigaset_if_initdriver
* Initialize tty interface .
* parameters :
2006-04-11 09:55:04 +04:00
* drv Driver
* procname Name of the driver ( e . g . for / proc / tty / drivers )
* devname Name of the device files ( prefix without minor number )
2006-03-26 13:38:32 +04:00
*/
void gigaset_if_initdriver ( struct gigaset_driver * drv , const char * procname ,
2005-06-21 08:15:16 +04:00
const char * devname )
2006-03-26 13:38:32 +04:00
{
int ret ;
struct tty_driver * tty ;
drv - > have_tty = 0 ;
2012-03-05 17:51:52 +04:00
drv - > tty = tty = alloc_tty_driver ( drv - > minors ) ;
2009-10-25 12:30:17 +03:00
if ( tty = = NULL )
2006-03-26 13:38:32 +04:00
goto enomem ;
2012-02-27 23:12:07 +04:00
tty - > type = TTY_DRIVER_TYPE_SERIAL ;
tty - > subtype = SERIAL_TYPE_NORMAL ;
2005-06-21 08:15:16 +04:00
tty - > flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV ;
2006-03-26 13:38:32 +04:00
tty - > driver_name = procname ;
tty - > name = devname ;
tty - > minor_start = drv - > minor ;
2009-10-25 12:30:17 +03:00
tty - > init_termios = tty_std_termios ;
tty - > init_termios . c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL ;
2006-03-26 13:38:32 +04:00
tty_set_operations ( tty , & if_ops ) ;
ret = tty_register_driver ( tty ) ;
if ( ret < 0 ) {
2008-12-26 12:21:29 +03:00
pr_err ( " error %d registering tty driver \n " , ret ) ;
2006-03-26 13:38:32 +04:00
goto error ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_IF , " tty driver initialized " ) ;
2006-03-26 13:38:32 +04:00
drv - > have_tty = 1 ;
return ;
enomem :
2008-12-26 12:21:29 +03:00
pr_err ( " out of memory \n " ) ;
2006-03-26 13:38:32 +04:00
error :
if ( drv - > tty )
put_tty_driver ( drv - > tty ) ;
}
void gigaset_if_freedriver ( struct gigaset_driver * drv )
{
if ( ! drv - > have_tty )
return ;
drv - > have_tty = 0 ;
tty_unregister_driver ( drv - > tty ) ;
put_tty_driver ( drv - > tty ) ;
}