2005-04-17 02:20:36 +04:00
/*
* Belkin USB Serial Adapter Driver
*
* Copyright ( C ) 2000 William Greathouse ( wgreathouse @ smva . com )
* Copyright ( C ) 2000 - 2001 Greg Kroah - Hartman ( greg @ kroah . com )
2010-05-15 19:53:53 +04:00
* Copyright ( C ) 2010 Johan Hovold ( jhovold @ gmail . com )
2005-04-17 02:20:36 +04:00
*
* This program is largely derived from work by the linux - usb group
* and associated source files . Please see the usb / serial files for
* individual credits and copyrights .
2008-07-22 14:09:39 +04:00
*
2005-04-17 02:20:36 +04:00
* 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 .
*
2008-07-22 14:09:39 +04:00
* See Documentation / usb / usb - serial . txt for more information on using this
* driver
2005-04-17 02:20:36 +04:00
*
* TODO :
* - - Add true modem contol line query capability . Currently we track the
* states reported by the interrupt and the states we request .
* - - Add support for flush commands
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/spinlock.h>
2008-07-22 14:09:39 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2005-04-17 02:20:36 +04:00
# include "belkin_sa.h"
2012-01-13 03:02:20 +04:00
static bool debug ;
2005-04-17 02:20:36 +04:00
/*
* Version Information
*/
2010-05-15 19:53:53 +04:00
# define DRIVER_VERSION "v1.3"
2005-04-17 02:20:36 +04:00
# define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>"
# define DRIVER_DESC "USB Belkin Serial converter driver"
/* function prototypes for a Belkin USB Serial Adapter F5U103 */
2008-07-22 14:09:39 +04:00
static int belkin_sa_startup ( struct usb_serial * serial ) ;
2009-06-02 19:53:55 +04:00
static void belkin_sa_release ( struct usb_serial * serial ) ;
2008-07-22 14:09:39 +04:00
static int belkin_sa_open ( struct tty_struct * tty ,
2009-09-20 00:13:26 +04:00
struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void belkin_sa_close ( struct usb_serial_port * port ) ;
2008-07-22 14:09:39 +04:00
static void belkin_sa_read_int_callback ( struct urb * urb ) ;
2010-05-15 19:53:53 +04:00
static void belkin_sa_process_read_urb ( struct urb * urb ) ;
2008-07-22 14:09:39 +04:00
static void belkin_sa_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old ) ;
static void belkin_sa_break_ctl ( struct tty_struct * tty , int break_state ) ;
2011-02-14 19:26:14 +03:00
static int belkin_sa_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 19:26:50 +03:00
static int belkin_sa_tiocmset ( struct tty_struct * tty ,
2008-07-22 14:09:39 +04:00
unsigned int set , unsigned int clear ) ;
2005-04-17 02:20:36 +04:00
2010-01-10 17:34:24 +03:00
static const struct usb_device_id id_table_combined [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( BELKIN_SA_VID , BELKIN_SA_PID ) } ,
{ USB_DEVICE ( BELKIN_OLD_VID , BELKIN_OLD_PID ) } ,
{ USB_DEVICE ( PERACOM_VID , PERACOM_PID ) } ,
{ USB_DEVICE ( GOHUBS_VID , GOHUBS_PID ) } ,
{ USB_DEVICE ( GOHUBS_VID , HANDYLINK_PID ) } ,
{ USB_DEVICE ( BELKIN_DOCKSTATION_VID , BELKIN_DOCKSTATION_PID ) } ,
2008-07-22 14:09:39 +04:00
{ } /* Terminating entry */
2005-04-17 02:20:36 +04:00
} ;
2008-07-22 14:09:39 +04:00
MODULE_DEVICE_TABLE ( usb , id_table_combined ) ;
2005-04-17 02:20:36 +04:00
static struct usb_driver belkin_driver = {
. name = " belkin " ,
. probe = usb_serial_probe ,
. disconnect = usb_serial_disconnect ,
. id_table = id_table_combined ,
} ;
/* All of the device info needed for the serial converters */
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver belkin_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " belkin " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " Belkin / Peracom / GoHubs USB Serial Adapter " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table_combined ,
. num_ports = 1 ,
. open = belkin_sa_open ,
. close = belkin_sa_close ,
2008-07-22 14:09:39 +04:00
. read_int_callback = belkin_sa_read_int_callback ,
2010-05-15 19:53:53 +04:00
. process_read_urb = belkin_sa_process_read_urb ,
2005-04-17 02:20:36 +04:00
. set_termios = belkin_sa_set_termios ,
. break_ctl = belkin_sa_break_ctl ,
. tiocmget = belkin_sa_tiocmget ,
. tiocmset = belkin_sa_tiocmset ,
. attach = belkin_sa_startup ,
2009-06-02 19:53:55 +04:00
. release = belkin_sa_release ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-23 23:56:17 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& belkin_device , NULL
} ;
2005-04-17 02:20:36 +04:00
struct belkin_sa_private {
spinlock_t lock ;
unsigned long control_state ;
unsigned char last_lsr ;
unsigned char last_msr ;
int bad_flow_control ;
} ;
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Belkin USB Serial Adapter F5U103 specific driver functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# define WDR_TIMEOUT 5000 /* default urb timeout */
/* assumes that struct usb_serial *serial is available */
2008-07-22 14:09:39 +04:00
# define BSA_USB_CMD(c, v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
2005-04-17 02:20:36 +04:00
( c ) , BELKIN_SA_SET_REQUEST_TYPE , \
( v ) , 0 , NULL , 0 , WDR_TIMEOUT )
/* do some startup allocations not currently performed by usb_serial_probe() */
2008-07-22 14:09:39 +04:00
static int belkin_sa_startup ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
struct usb_device * dev = serial - > dev ;
struct belkin_sa_private * priv ;
/* allocate the private data structure */
priv = kmalloc ( sizeof ( struct belkin_sa_private ) , GFP_KERNEL ) ;
if ( ! priv )
2008-07-22 14:09:39 +04:00
return - 1 ; /* error */
2005-04-17 02:20:36 +04:00
/* set initial values for control structures */
spin_lock_init ( & priv - > lock ) ;
priv - > control_state = 0 ;
priv - > last_lsr = 0 ;
priv - > last_msr = 0 ;
/* see comments at top of file */
2008-07-22 14:09:39 +04:00
priv - > bad_flow_control =
( le16_to_cpu ( dev - > descriptor . bcdDevice ) < = 0x0206 ) ? 1 : 0 ;
2008-08-19 00:21:04 +04:00
dev_info ( & dev - > dev , " bcdDevice: %04x, bfc: %d \n " ,
2008-07-22 14:09:39 +04:00
le16_to_cpu ( dev - > descriptor . bcdDevice ) ,
priv - > bad_flow_control ) ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & serial - > port [ 0 ] - > write_wait ) ;
usb_set_serial_port_data ( serial - > port [ 0 ] , priv ) ;
2008-07-22 14:09:39 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-06-02 19:53:55 +04:00
static void belkin_sa_release ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-07-22 14:09:39 +04:00
dbg ( " %s " , __func__ ) ;
2005-04-17 02:20:36 +04:00
2010-05-15 19:53:51 +04:00
for ( i = 0 ; i < serial - > num_ports ; + + i )
kfree ( usb_get_serial_port_data ( serial - > port [ i ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2010-05-15 19:53:51 +04:00
static int belkin_sa_open ( struct tty_struct * tty ,
2009-09-20 00:13:26 +04:00
struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2010-05-15 19:53:52 +04:00
int retval ;
2005-04-17 02:20:36 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
retval = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
if ( retval ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " usb_submit_urb(read int) failed \n " ) ;
2010-05-15 19:53:52 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2010-05-15 19:53:52 +04:00
retval = usb_serial_generic_open ( tty , port ) ;
if ( retval )
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
return retval ;
2010-05-15 19:53:51 +04:00
}
2005-04-17 02:20:36 +04:00
2009-06-11 15:26:29 +04:00
static void belkin_sa_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2008-03-04 03:08:34 +03:00
dbg ( " %s port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2010-03-18 01:00:45 +03:00
usb_serial_generic_close ( port ) ;
2005-04-17 02:20:36 +04:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2010-05-15 19:53:51 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
static void belkin_sa_read_int_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2005-04-17 02:20:36 +04:00
struct belkin_sa_private * priv ;
unsigned char * data = urb - > transfer_buffer ;
int retval ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2007-06-16 02:44:13 +04:00
switch ( status ) {
2005-04-17 02:20:36 +04:00
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2007-06-16 02:44:13 +04:00
dbg ( " %s - urb shutting down with status: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
default :
2007-06-16 02:44:13 +04:00
dbg ( " %s - nonzero urb status received: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
2008-07-22 14:09:39 +04:00
usb_serial_debug_data ( debug , & port - > dev , __func__ ,
urb - > actual_length , data ) ;
2005-04-17 02:20:36 +04:00
/* Handle known interrupt data */
/* ignore data[0] and data[1] */
priv = usb_get_serial_port_data ( port ) ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > last_msr = data [ BELKIN_SA_MSR_INDEX ] ;
2008-07-22 14:09:39 +04:00
2005-04-17 02:20:36 +04:00
/* Record Control Line states */
if ( priv - > last_msr & BELKIN_SA_MSR_DSR )
priv - > control_state | = TIOCM_DSR ;
else
priv - > control_state & = ~ TIOCM_DSR ;
if ( priv - > last_msr & BELKIN_SA_MSR_CTS )
priv - > control_state | = TIOCM_CTS ;
else
priv - > control_state & = ~ TIOCM_CTS ;
if ( priv - > last_msr & BELKIN_SA_MSR_RI )
priv - > control_state | = TIOCM_RI ;
else
priv - > control_state & = ~ TIOCM_RI ;
if ( priv - > last_msr & BELKIN_SA_MSR_CD )
priv - > control_state | = TIOCM_CD ;
else
priv - > control_state & = ~ TIOCM_CD ;
priv - > last_lsr = data [ BELKIN_SA_LSR_INDEX ] ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
exit :
2008-07-22 14:09:39 +04:00
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " %s - usb_submit_urb failed with "
" result %d \n " , __func__ , retval ) ;
2005-04-17 02:20:36 +04:00
}
2010-05-15 19:53:53 +04:00
static void belkin_sa_process_read_urb ( struct urb * urb )
{
struct usb_serial_port * port = urb - > context ;
struct belkin_sa_private * priv = usb_get_serial_port_data ( port ) ;
struct tty_struct * tty ;
unsigned char * data = urb - > transfer_buffer ;
unsigned long flags ;
unsigned char status ;
char tty_flag ;
/* Update line status */
tty_flag = TTY_NORMAL ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
status = priv - > last_lsr ;
priv - > last_lsr & = ~ BELKIN_SA_LSR_ERR ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
if ( ! urb - > actual_length )
return ;
tty = tty_port_tty_get ( & port - > port ) ;
if ( ! tty )
return ;
if ( status & BELKIN_SA_LSR_ERR ) {
/* Break takes precedence over parity, which takes precedence
* over framing errors . */
if ( status & BELKIN_SA_LSR_BI )
tty_flag = TTY_BREAK ;
else if ( status & BELKIN_SA_LSR_PE )
tty_flag = TTY_PARITY ;
else if ( status & BELKIN_SA_LSR_FE )
tty_flag = TTY_FRAME ;
dev_dbg ( & port - > dev , " tty_flag = %d \n " , tty_flag ) ;
/* Overrun is special, not associated with a char. */
if ( status & BELKIN_SA_LSR_OE )
tty_insert_flip_char ( tty , 0 , TTY_OVERRUN ) ;
}
tty_insert_flip_string_fixed_flag ( tty , data , tty_flag ,
urb - > actual_length ) ;
tty_flip_buffer_push ( tty ) ;
tty_kref_put ( tty ) ;
}
2008-07-22 14:09:07 +04:00
static void belkin_sa_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old_termios )
2005-04-17 02:20:36 +04:00
{
struct usb_serial * serial = port - > serial ;
struct belkin_sa_private * priv = usb_get_serial_port_data ( port ) ;
unsigned int iflag ;
unsigned int cflag ;
unsigned int old_iflag = 0 ;
unsigned int old_cflag = 0 ;
__u16 urb_value = 0 ; /* Will hold the new flags */
unsigned long flags ;
unsigned long control_state ;
int bad_flow_control ;
2007-06-22 17:40:18 +04:00
speed_t baud ;
2008-07-22 14:09:07 +04:00
struct ktermios * termios = tty - > termios ;
2008-07-22 14:09:39 +04:00
2007-12-14 03:15:26 +03:00
iflag = termios - > c_iflag ;
cflag = termios - > c_cflag ;
2005-04-17 02:20:36 +04:00
2007-12-14 03:15:26 +03:00
termios - > c_cflag & = ~ CMSPAR ;
2005-04-17 02:20:36 +04:00
/* get a local copy of the current port settings */
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
bad_flow_control = priv - > bad_flow_control ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-07-22 14:09:39 +04:00
2007-06-22 17:40:18 +04:00
old_iflag = old_termios - > c_iflag ;
old_cflag = old_termios - > c_cflag ;
2005-04-17 02:20:36 +04:00
/* Set the baud rate */
2007-12-14 03:15:26 +03:00
if ( ( cflag & CBAUD ) ! = ( old_cflag & CBAUD ) ) {
2005-04-17 02:20:36 +04:00
/* reassert DTR and (maybe) RTS on transition from B0 */
2008-07-22 14:09:39 +04:00
if ( ( old_cflag & CBAUD ) = = B0 ) {
2005-04-17 02:20:36 +04:00
control_state | = ( TIOCM_DTR | TIOCM_RTS ) ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_DTR_REQUEST , 1 ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set DTR error \n " ) ;
2005-04-17 02:20:36 +04:00
/* don't set RTS if using hardware flow control */
2007-12-14 03:15:26 +03:00
if ( ! ( old_cflag & CRTSCTS ) )
2008-07-22 14:09:39 +04:00
if ( BSA_USB_CMD ( BELKIN_SA_SET_RTS_REQUEST
, 1 ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set RTS error \n " ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-22 17:40:18 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
baud = tty_get_baud_rate ( tty ) ;
2007-12-14 03:15:26 +03:00
if ( baud ) {
urb_value = BELKIN_SA_BAUD ( baud ) ;
/* Clip to maximum speed */
if ( urb_value = = 0 )
urb_value = 1 ;
/* Turn it back into a resulting real baud rate */
baud = BELKIN_SA_BAUD ( urb_value ) ;
/* Report the actual baud rate back to the caller */
2008-07-22 14:09:07 +04:00
tty_encode_baud_rate ( tty , baud , baud ) ;
2007-06-22 17:40:18 +04:00
if ( BSA_USB_CMD ( BELKIN_SA_SET_BAUDRATE_REQUEST , urb_value ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set baudrate error \n " ) ;
2007-06-22 17:40:18 +04:00
} else {
/* Disable flow control */
2008-07-22 14:09:39 +04:00
if ( BSA_USB_CMD ( BELKIN_SA_SET_FLOW_CTRL_REQUEST ,
BELKIN_SA_FLOW_NONE ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Disable flowcontrol error \n " ) ;
2007-06-22 17:40:18 +04:00
/* Drop RTS and DTR */
control_state & = ~ ( TIOCM_DTR | TIOCM_RTS ) ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_DTR_REQUEST , 0 ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " DTR LOW error \n " ) ;
2007-06-22 17:40:18 +04:00
if ( BSA_USB_CMD ( BELKIN_SA_SET_RTS_REQUEST , 0 ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " RTS LOW error \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* set the parity */
2008-07-22 14:09:39 +04:00
if ( ( cflag ^ old_cflag ) & ( PARENB | PARODD ) ) {
2005-04-17 02:20:36 +04:00
if ( cflag & PARENB )
2008-07-22 14:09:39 +04:00
urb_value = ( cflag & PARODD ) ? BELKIN_SA_PARITY_ODD
: BELKIN_SA_PARITY_EVEN ;
2005-04-17 02:20:36 +04:00
else
urb_value = BELKIN_SA_PARITY_NONE ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_PARITY_REQUEST , urb_value ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set parity error \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* set the number of data bits */
2008-07-22 14:09:39 +04:00
if ( ( cflag & CSIZE ) ! = ( old_cflag & CSIZE ) ) {
2005-04-17 02:20:36 +04:00
switch ( cflag & CSIZE ) {
2008-07-22 14:09:39 +04:00
case CS5 :
urb_value = BELKIN_SA_DATA_BITS ( 5 ) ;
break ;
case CS6 :
urb_value = BELKIN_SA_DATA_BITS ( 6 ) ;
break ;
case CS7 :
urb_value = BELKIN_SA_DATA_BITS ( 7 ) ;
break ;
case CS8 :
urb_value = BELKIN_SA_DATA_BITS ( 8 ) ;
break ;
default : dbg ( " CSIZE was not CS5-CS8, using default of 8 " ) ;
urb_value = BELKIN_SA_DATA_BITS ( 8 ) ;
break ;
2005-04-17 02:20:36 +04:00
}
if ( BSA_USB_CMD ( BELKIN_SA_SET_DATA_BITS_REQUEST , urb_value ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set data bits error \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* set the number of stop bits */
2008-07-22 14:09:39 +04:00
if ( ( cflag & CSTOPB ) ! = ( old_cflag & CSTOPB ) ) {
urb_value = ( cflag & CSTOPB ) ? BELKIN_SA_STOP_BITS ( 2 )
: BELKIN_SA_STOP_BITS ( 1 ) ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_STOP_BITS_REQUEST ,
urb_value ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set stop bits error \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* Set flow control */
2008-07-22 14:09:39 +04:00
if ( ( ( iflag ^ old_iflag ) & ( IXOFF | IXON ) ) | |
( ( cflag ^ old_cflag ) & CRTSCTS ) ) {
2005-04-17 02:20:36 +04:00
urb_value = 0 ;
if ( ( iflag & IXOFF ) | | ( iflag & IXON ) )
urb_value | = ( BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON ) ;
else
urb_value & = ~ ( BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON ) ;
if ( cflag & CRTSCTS )
urb_value | = ( BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS ) ;
else
urb_value & = ~ ( BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS ) ;
if ( bad_flow_control )
urb_value & = ~ ( BELKIN_SA_FLOW_IRTS ) ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_FLOW_CTRL_REQUEST , urb_value ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set flow control error \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* save off the modified port settings */
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > control_state = control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2010-05-15 19:53:51 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
static void belkin_sa_break_ctl ( struct tty_struct * tty , int break_state )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
if ( BSA_USB_CMD ( BELKIN_SA_SET_BREAK_REQUEST , break_state ? 1 : 0 ) < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set break_ctl %d \n " , break_state ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-14 19:26:14 +03:00
static int belkin_sa_tiocmget ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct belkin_sa_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long control_state ;
unsigned long flags ;
2008-07-22 14:09:39 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s " , __func__ ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return control_state ;
}
2011-02-14 19:26:50 +03:00
static int belkin_sa_tiocmset ( struct tty_struct * tty ,
2005-04-17 02:20:36 +04:00
unsigned int set , unsigned int clear )
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
struct belkin_sa_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long control_state ;
unsigned long flags ;
int retval ;
int rts = 0 ;
int dtr = 0 ;
2008-07-22 14:09:39 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s " , __func__ ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
if ( set & TIOCM_RTS ) {
control_state | = TIOCM_RTS ;
rts = 1 ;
}
if ( set & TIOCM_DTR ) {
control_state | = TIOCM_DTR ;
dtr = 1 ;
}
if ( clear & TIOCM_RTS ) {
control_state & = ~ TIOCM_RTS ;
rts = 0 ;
}
if ( clear & TIOCM_DTR ) {
control_state & = ~ TIOCM_DTR ;
dtr = 0 ;
}
priv - > control_state = control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
retval = BSA_USB_CMD ( BELKIN_SA_SET_RTS_REQUEST , rts ) ;
if ( retval < 0 ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set RTS error %d \n " , retval ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
retval = BSA_USB_CMD ( BELKIN_SA_SET_DTR_REQUEST , dtr ) ;
if ( retval < 0 ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Set DTR error %d \n " , retval ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
exit :
return retval ;
}
2012-02-29 01:11:35 +04:00
module_usb_serial_driver ( belkin_driver , serial_drivers ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:39 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_VERSION ( DRIVER_VERSION ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
module_param ( debug , bool , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " Debug enabled or not " ) ;