2005-04-16 15:20:36 -07:00
/*
* MCT ( Magic Control Technology Corp . ) USB RS232 Converter Driver
*
* Copyright ( C ) 2000 Wolfgang Grandegger ( wolfgang @ ces . ch )
*
* 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 .
*
* This program is largely derived from the Belkin USB Serial Adapter Driver
* ( see belkin_sa . [ ch ] ) . All of the information about the device was acquired
* by using SniffUSB on Windows98 . For technical details see mct_u232 . h .
*
* William G . Greathouse and Greg Kroah - Hartman provided great help on how to
* do the reverse engineering and how to write a USB serial device driver .
*
* TO BE DONE , TO BE CHECKED :
* DTR / RTS signal handling may be incomplete or incorrect . I have mainly
* implemented what I have seen with SniffUSB or found in belkin_sa . c .
* For further TODOs check also belkin_sa . c .
*/
# include <linux/kernel.h>
# include <linux/errno.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 11:14:30 +01:00
# include <linux/uaccess.h>
2009-12-07 20:29:05 -07:00
# include <asm/unaligned.h>
2005-04-16 15:20:36 -07:00
# include <linux/usb.h>
2006-07-11 21:22:58 -07:00
# include <linux/usb/serial.h>
2011-01-09 01:00:11 -05:00
# include <linux/serial.h>
2005-04-16 15:20:36 -07:00
# include "mct_u232.h"
# define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
# define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
/*
* Function prototypes
*/
2012-10-25 10:29:13 +02:00
static int mct_u232_port_probe ( struct usb_serial_port * port ) ;
static int mct_u232_port_remove ( struct usb_serial_port * remove ) ;
2009-09-19 13:13:26 -07:00
static int mct_u232_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 12:26:29 +01:00
static void mct_u232_close ( struct usb_serial_port * port ) ;
static void mct_u232_dtr_rts ( struct usb_serial_port * port , int on ) ;
2008-07-22 11:14:30 +01:00
static void mct_u232_read_int_callback ( struct urb * urb ) ;
static void mct_u232_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old ) ;
static void mct_u232_break_ctl ( struct tty_struct * tty , int break_state ) ;
2011-02-14 16:26:14 +00:00
static int mct_u232_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 16:26:50 +00:00
static int mct_u232_tiocmset ( struct tty_struct * tty ,
2008-07-22 11:14:30 +01:00
unsigned int set , unsigned int clear ) ;
static void mct_u232_throttle ( struct tty_struct * tty ) ;
static void mct_u232_unthrottle ( struct tty_struct * tty ) ;
2007-05-08 11:00:12 -07:00
2005-04-16 15:20:36 -07:00
/*
* All of the device info needed for the MCT USB - RS232 converter .
*/
2012-05-08 15:46:14 -07:00
static const struct usb_device_id id_table [ ] = {
2005-04-16 15:20:36 -07:00
{ USB_DEVICE ( MCT_U232_VID , MCT_U232_PID ) } ,
{ USB_DEVICE ( MCT_U232_VID , MCT_U232_SITECOM_PID ) } ,
{ USB_DEVICE ( MCT_U232_VID , MCT_U232_DU_H3SP_PID ) } ,
{ USB_DEVICE ( MCT_U232_BELKIN_F5U109_VID , MCT_U232_BELKIN_F5U109_PID ) } ,
{ } /* Terminating entry */
} ;
2012-05-08 15:46:14 -07:00
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2005-04-16 15:20:36 -07:00
2005-06-20 21:15:16 -07:00
static struct usb_serial_driver mct_u232_device = {
2005-06-20 21:15:16 -07:00
. driver = {
. owner = THIS_MODULE ,
2005-06-20 21:15:16 -07:00
. name = " mct_u232 " ,
2005-06-20 21:15:16 -07:00
} ,
2005-06-20 21:15:16 -07:00
. description = " MCT U232 " ,
2012-05-08 15:46:14 -07:00
. id_table = id_table ,
2005-04-16 15:20:36 -07:00
. num_ports = 1 ,
. open = mct_u232_open ,
. close = mct_u232_close ,
2009-06-11 12:26:29 +01:00
. dtr_rts = mct_u232_dtr_rts ,
2007-05-08 11:00:12 -07:00
. throttle = mct_u232_throttle ,
. unthrottle = mct_u232_unthrottle ,
2005-04-16 15:20:36 -07:00
. read_int_callback = mct_u232_read_int_callback ,
. set_termios = mct_u232_set_termios ,
. break_ctl = mct_u232_break_ctl ,
. tiocmget = mct_u232_tiocmget ,
. tiocmset = mct_u232_tiocmset ,
2013-03-21 12:37:13 +01:00
. tiocmiwait = usb_serial_generic_tiocmiwait ,
2012-10-25 10:29:13 +02:00
. port_probe = mct_u232_port_probe ,
. port_remove = mct_u232_port_remove ,
2013-03-21 12:37:12 +01:00
. get_icount = usb_serial_generic_get_icount ,
2005-04-16 15:20:36 -07:00
} ;
2012-02-23 14:57:09 -05:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& mct_u232_device , NULL
} ;
2005-04-16 15:20:36 -07:00
struct mct_u232_private {
2013-04-16 18:01:27 +02:00
struct urb * read_urb ;
2005-04-16 15:20:36 -07:00
spinlock_t lock ;
unsigned int control_state ; /* Modem Line Setting (TIOCM) */
unsigned char last_lcr ; /* Line Control Register */
unsigned char last_lsr ; /* Line Status Register */
unsigned char last_msr ; /* Modem Status Register */
2007-05-08 11:00:12 -07:00
unsigned int rx_flags ; /* Throttling flags */
2005-04-16 15:20:36 -07:00
} ;
2007-05-08 11:00:12 -07:00
# define THROTTLED 0x01
2005-04-16 15:20:36 -07:00
/*
* Handle vendor specific USB requests
*/
# define WDR_TIMEOUT 5000 /* default urb timeout */
/*
* Later day 2.6 .0 - test kernels have new baud rates like B230400 which
* we do not know how to support . We ignore them for the moment .
*/
2008-07-22 11:14:30 +01:00
static int mct_u232_calculate_baud_rate ( struct usb_serial * serial ,
speed_t value , speed_t * result )
2005-04-16 15:20:36 -07:00
{
2007-12-13 16:15:29 -08:00
* result = value ;
2005-04-16 15:20:36 -07:00
if ( le16_to_cpu ( serial - > dev - > descriptor . idProduct ) = = MCT_U232_SITECOM_PID
2008-07-22 11:14:30 +01:00
| | le16_to_cpu ( serial - > dev - > descriptor . idProduct ) = = MCT_U232_BELKIN_F5U109_PID ) {
2005-04-16 15:20:36 -07:00
switch ( value ) {
2008-07-22 11:14:30 +01:00
case 300 :
return 0x01 ;
case 600 :
return 0x02 ; /* this one not tested */
case 1200 :
return 0x03 ;
case 2400 :
return 0x04 ;
case 4800 :
return 0x06 ;
case 9600 :
return 0x08 ;
case 19200 :
return 0x09 ;
case 38400 :
return 0x0a ;
case 57600 :
return 0x0b ;
case 115200 :
return 0x0c ;
2005-04-16 15:20:36 -07:00
default :
2007-12-13 16:15:29 -08:00
* result = 9600 ;
2005-04-16 15:20:36 -07:00
return 0x08 ;
}
} else {
2007-12-13 16:15:29 -08:00
/* FIXME: Can we use any divider - should we do
divider = 115200 / value ;
real baud = 115200 / divider */
2005-04-16 15:20:36 -07:00
switch ( value ) {
2007-08-10 14:53:35 -07:00
case 300 : break ;
case 600 : break ;
case 1200 : break ;
case 2400 : break ;
case 4800 : break ;
case 9600 : break ;
case 19200 : break ;
case 38400 : break ;
case 57600 : break ;
case 115200 : break ;
default :
value = 9600 ;
2007-12-13 16:15:29 -08:00
* result = 9600 ;
2005-04-16 15:20:36 -07:00
}
return 115200 / value ;
}
}
2008-07-22 11:09:07 +01:00
static int mct_u232_set_baud_rate ( struct tty_struct * tty ,
struct usb_serial * serial , struct usb_serial_port * port , speed_t value )
2005-04-16 15:20:36 -07:00
{
2009-12-07 20:29:05 -07:00
unsigned int divisor ;
2008-07-22 11:14:30 +01:00
int rc ;
2009-12-07 20:29:05 -07:00
unsigned char * buf ;
2008-07-22 11:14:30 +01:00
unsigned char cts_enable_byte = 0 ;
speed_t speed ;
2009-12-07 20:29:05 -07:00
buf = kmalloc ( MCT_U232_MAX_SIZE , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
2008-07-22 11:14:30 +01:00
2009-12-07 20:29:05 -07:00
divisor = mct_u232_calculate_baud_rate ( serial , value , & speed ) ;
put_unaligned_le32 ( cpu_to_le32 ( divisor ) , buf ) ;
2008-07-22 11:14:30 +01:00
rc = usb_control_msg ( serial - > dev , usb_sndctrlpipe ( serial - > dev , 0 ) ,
MCT_U232_SET_BAUD_RATE_REQUEST ,
MCT_U232_SET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_SET_BAUD_RATE_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2007-12-13 16:15:29 -08:00
if ( rc < 0 ) /*FIXME: What value speed results */
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " Set BAUD RATE %d failed (error = %d) \n " ,
value , rc ) ;
2007-12-13 16:15:29 -08:00
else
2008-07-22 11:09:07 +01:00
tty_encode_baud_rate ( tty , speed , speed ) ;
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " set_baud_rate: value: 0x%x, divisor: 0x%x \n " , value , divisor ) ;
2005-04-16 15:20:36 -07:00
/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
always sends two extra USB ' device request ' messages after the
' baud rate change ' message . The actual functionality of the
request codes in these messages is not fully understood but these
particular codes are never seen in any operation besides a baud
2007-05-08 11:00:12 -07:00
rate change . Both of these messages send a single byte of data .
In the first message , the value of this byte is always zero .
The second message has been determined experimentally to control
whether data will be transmitted to a device which is not asserting
the ' CTS ' signal . If the second message ' s data byte is zero , data
will be transmitted even if ' CTS ' is not asserted ( i . e . no hardware
2008-07-22 11:14:30 +01:00
flow control ) . if the second message ' s data byte is nonzero ( a
value of 1 is used by this driver ) , data will not be transmitted to
a device which is not asserting ' CTS ' .
2007-05-08 11:00:12 -07:00
*/
2005-04-16 15:20:36 -07:00
2009-12-07 20:29:05 -07:00
buf [ 0 ] = 0 ;
2005-04-16 15:20:36 -07:00
rc = usb_control_msg ( serial - > dev , usb_sndctrlpipe ( serial - > dev , 0 ) ,
2008-07-22 11:14:30 +01:00
MCT_U232_SET_UNKNOWN1_REQUEST ,
MCT_U232_SET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_SET_UNKNOWN1_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2005-04-16 15:20:36 -07:00
if ( rc < 0 )
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " Sending USB device request code %d "
" failed (error = %d) \n " , MCT_U232_SET_UNKNOWN1_REQUEST ,
rc ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:14:30 +01:00
if ( port & & C_CRTSCTS ( tty ) )
2007-05-08 11:00:12 -07:00
cts_enable_byte = 1 ;
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " set_baud_rate: send second control message, data = %02X \n " ,
cts_enable_byte ) ;
2009-12-07 20:29:05 -07:00
buf [ 0 ] = cts_enable_byte ;
2005-04-16 15:20:36 -07:00
rc = usb_control_msg ( serial - > dev , usb_sndctrlpipe ( serial - > dev , 0 ) ,
2008-07-22 11:14:30 +01:00
MCT_U232_SET_CTS_REQUEST ,
MCT_U232_SET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_SET_CTS_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2005-04-16 15:20:36 -07:00
if ( rc < 0 )
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " Sending USB device request code %d "
" failed (error = %d) \n " , MCT_U232_SET_CTS_REQUEST , rc ) ;
2005-04-16 15:20:36 -07:00
2009-12-07 20:29:05 -07:00
kfree ( buf ) ;
2008-07-22 11:14:30 +01:00
return rc ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_set_baud_rate */
2012-09-14 15:08:30 -07:00
static int mct_u232_set_line_ctrl ( struct usb_serial_port * port ,
unsigned char lcr )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:14:30 +01:00
int rc ;
2009-12-07 20:29:05 -07:00
unsigned char * buf ;
buf = kmalloc ( MCT_U232_MAX_SIZE , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
buf [ 0 ] = lcr ;
2012-09-14 15:08:30 -07:00
rc = usb_control_msg ( port - > serial - > dev , usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 11:14:30 +01:00
MCT_U232_SET_LINE_CTRL_REQUEST ,
MCT_U232_SET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_SET_LINE_CTRL_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2005-04-16 15:20:36 -07:00
if ( rc < 0 )
2012-09-14 15:08:30 -07:00
dev_err ( & port - > dev , " Set LINE CTRL 0x%x failed (error = %d) \n " , lcr , rc ) ;
dev_dbg ( & port - > dev , " set_line_ctrl: 0x%x \n " , lcr ) ;
2009-12-07 20:29:05 -07:00
kfree ( buf ) ;
2008-07-22 11:14:30 +01:00
return rc ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_set_line_ctrl */
2012-09-14 15:08:30 -07:00
static int mct_u232_set_modem_ctrl ( struct usb_serial_port * port ,
2005-04-16 15:20:36 -07:00
unsigned int control_state )
{
2008-07-22 11:14:30 +01:00
int rc ;
2009-12-07 20:29:05 -07:00
unsigned char mcr ;
unsigned char * buf ;
buf = kmalloc ( MCT_U232_MAX_SIZE , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
2009-12-07 20:29:05 -07:00
mcr = MCT_U232_MCR_NONE ;
2005-04-16 15:20:36 -07:00
if ( control_state & TIOCM_DTR )
mcr | = MCT_U232_MCR_DTR ;
if ( control_state & TIOCM_RTS )
mcr | = MCT_U232_MCR_RTS ;
2009-12-07 20:29:05 -07:00
buf [ 0 ] = mcr ;
2012-09-14 15:08:30 -07:00
rc = usb_control_msg ( port - > serial - > dev , usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 11:14:30 +01:00
MCT_U232_SET_MODEM_CTRL_REQUEST ,
MCT_U232_SET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_SET_MODEM_CTRL_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2012-05-22 20:45:13 +01:00
kfree ( buf ) ;
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " set_modem_ctrl: state=0x%x ==> mcr=0x%x \n " , control_state , mcr ) ;
2005-04-16 15:20:36 -07:00
2012-05-22 20:45:13 +01:00
if ( rc < 0 ) {
2012-09-14 15:08:30 -07:00
dev_err ( & port - > dev , " Set MODEM CTRL 0x%x failed (error = %d) \n " , mcr , rc ) ;
2012-05-22 20:45:13 +01:00
return rc ;
}
return 0 ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_set_modem_ctrl */
2012-09-14 15:08:30 -07:00
static int mct_u232_get_modem_stat ( struct usb_serial_port * port ,
unsigned char * msr )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:14:30 +01:00
int rc ;
2009-12-07 20:29:05 -07:00
unsigned char * buf ;
buf = kmalloc ( MCT_U232_MAX_SIZE , GFP_KERNEL ) ;
if ( buf = = NULL ) {
* msr = 0 ;
return - ENOMEM ;
}
2012-09-14 15:08:30 -07:00
rc = usb_control_msg ( port - > serial - > dev , usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 11:14:30 +01:00
MCT_U232_GET_MODEM_STAT_REQUEST ,
MCT_U232_GET_REQUEST_TYPE ,
2009-12-07 20:29:05 -07:00
0 , 0 , buf , MCT_U232_GET_MODEM_STAT_SIZE ,
2008-07-22 11:14:30 +01:00
WDR_TIMEOUT ) ;
2005-04-16 15:20:36 -07:00
if ( rc < 0 ) {
2012-09-14 15:08:30 -07:00
dev_err ( & port - > dev , " Get MODEM STATus failed (error = %d) \n " , rc ) ;
2005-04-16 15:20:36 -07:00
* msr = 0 ;
2009-12-07 20:29:05 -07:00
} else {
* msr = buf [ 0 ] ;
2005-04-16 15:20:36 -07:00
}
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " get_modem_stat: 0x%x \n " , * msr ) ;
2009-12-07 20:29:05 -07:00
kfree ( buf ) ;
2008-07-22 11:14:30 +01:00
return rc ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_get_modem_stat */
2011-01-09 01:00:11 -05:00
static void mct_u232_msr_to_icount ( struct async_icount * icount ,
unsigned char msr )
{
/* Translate Control Line states */
if ( msr & MCT_U232_MSR_DDSR )
icount - > dsr + + ;
if ( msr & MCT_U232_MSR_DCTS )
icount - > cts + + ;
if ( msr & MCT_U232_MSR_DRI )
icount - > rng + + ;
if ( msr & MCT_U232_MSR_DCD )
icount - > dcd + + ;
} /* mct_u232_msr_to_icount */
2012-09-14 15:08:30 -07:00
static void mct_u232_msr_to_state ( struct usb_serial_port * port ,
unsigned int * control_state , unsigned char msr )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:14:30 +01:00
/* Translate Control Line states */
2005-04-16 15:20:36 -07:00
if ( msr & MCT_U232_MSR_DSR )
* control_state | = TIOCM_DSR ;
else
* control_state & = ~ TIOCM_DSR ;
if ( msr & MCT_U232_MSR_CTS )
* control_state | = TIOCM_CTS ;
else
* control_state & = ~ TIOCM_CTS ;
if ( msr & MCT_U232_MSR_RI )
* control_state | = TIOCM_RI ;
else
* control_state & = ~ TIOCM_RI ;
if ( msr & MCT_U232_MSR_CD )
* control_state | = TIOCM_CD ;
else
* control_state & = ~ TIOCM_CD ;
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " msr_to_state: msr=0x%x ==> state=0x%x \n " , msr , * control_state ) ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_msr_to_state */
/*
* Driver ' s tty interface functions
*/
2012-10-25 10:29:13 +02:00
static int mct_u232_port_probe ( struct usb_serial_port * port )
{
struct mct_u232_private * priv ;
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
2013-04-16 18:01:27 +02:00
/* Use second interrupt-in endpoint for reading. */
priv - > read_urb = port - > serial - > port [ 1 ] - > interrupt_in_urb ;
priv - > read_urb - > context = port ;
2012-10-25 10:29:13 +02:00
spin_lock_init ( & priv - > lock ) ;
usb_set_serial_port_data ( port , priv ) ;
return 0 ;
}
static int mct_u232_port_remove ( struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
struct mct_u232_private * priv ;
2008-07-22 11:14:30 +01:00
2012-10-25 10:29:13 +02:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
2009-09-19 13:13:26 -07:00
static int mct_u232_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
struct usb_serial * serial = port - > serial ;
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
int retval = 0 ;
unsigned int control_state ;
unsigned long flags ;
unsigned char last_lcr ;
unsigned char last_msr ;
/* Compensate for a hardware bug: although the Sitecom U232-P25
* device reports a maximum output packet size of 32 bytes ,
* it seems to be able to accept only 16 bytes ( and that ' s what
* SniffUSB says too . . . )
*/
2008-07-22 11:14:30 +01:00
if ( le16_to_cpu ( serial - > dev - > descriptor . idProduct )
= = MCT_U232_SITECOM_PID )
2005-04-16 15:20:36 -07:00
port - > bulk_out_size = 16 ;
2008-07-22 11:14:30 +01:00
/* Do a defined restart: the normal serial device seems to
2005-04-16 15:20:36 -07:00
* always turn on DTR and RTS here , so do the same . I ' m not
* sure if this is really necessary . But it should not harm
* either .
*/
spin_lock_irqsave ( & priv - > lock , flags ) ;
2012-07-14 15:31:47 +01:00
if ( tty & & ( tty - > termios . c_cflag & CBAUD ) )
2005-04-16 15:20:36 -07:00
priv - > control_state = TIOCM_DTR | TIOCM_RTS ;
else
priv - > control_state = 0 ;
2008-07-22 11:14:30 +01:00
priv - > last_lcr = ( MCT_U232_DATA_BITS_8 |
2005-04-16 15:20:36 -07:00
MCT_U232_PARITY_NONE |
MCT_U232_STOP_BITS_1 ) ;
control_state = priv - > control_state ;
last_lcr = priv - > last_lcr ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-09-14 15:08:30 -07:00
mct_u232_set_modem_ctrl ( port , control_state ) ;
mct_u232_set_line_ctrl ( port , last_lcr ) ;
2005-04-16 15:20:36 -07:00
/* Read modem status and update control state */
2012-09-14 15:08:30 -07:00
mct_u232_get_modem_stat ( port , & last_msr ) ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > last_msr = last_msr ;
2012-09-14 15:08:30 -07:00
mct_u232_msr_to_state ( port , & priv - > control_state , priv - > last_msr ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2013-04-16 18:01:27 +02:00
retval = usb_submit_urb ( priv - > read_urb , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( retval ) {
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev ,
2013-04-16 18:01:27 +02:00
" usb_submit_urb(read) failed pipe 0x%x err %d \n " ,
2008-08-20 16:56:34 -07:00
port - > read_urb - > pipe , retval ) ;
2007-03-29 10:45:17 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
}
retval = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
2007-03-29 10:45:17 +02:00
if ( retval ) {
2013-04-16 18:01:27 +02:00
usb_kill_urb ( priv - > read_urb ) ;
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev ,
" usb_submit_urb(read int) failed pipe 0x%x err %d " ,
port - > interrupt_in_urb - > pipe , retval ) ;
2007-03-29 10:45:17 +02:00
goto error ;
}
2005-04-16 15:20:36 -07:00
return 0 ;
2007-03-29 10:45:17 +02:00
error :
return retval ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_open */
2009-06-11 12:26:29 +01:00
static void mct_u232_dtr_rts ( struct usb_serial_port * port , int on )
2005-04-16 15:20:36 -07:00
{
2007-05-08 11:00:12 -07:00
unsigned int control_state ;
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
2005-04-16 15:20:36 -07:00
2013-02-13 17:53:28 +01:00
spin_lock_irq ( & priv - > lock ) ;
if ( on )
priv - > control_state | = TIOCM_DTR | TIOCM_RTS ;
else
priv - > control_state & = ~ ( TIOCM_DTR | TIOCM_RTS ) ;
control_state = priv - > control_state ;
spin_unlock_irq ( & priv - > lock ) ;
mct_u232_set_modem_ctrl ( port , control_state ) ;
2009-06-11 12:26:29 +01:00
}
2007-05-08 11:00:12 -07:00
2009-06-11 12:26:29 +01:00
static void mct_u232_close ( struct usb_serial_port * port )
{
2013-04-16 18:01:27 +02:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
usb_kill_urb ( priv - > read_urb ) ;
2012-10-25 10:29:14 +02:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
usb_serial_generic_close ( port ) ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_close */
2008-07-22 11:14:30 +01:00
static void mct_u232_read_int_callback ( struct urb * urb )
2005-04-16 15:20:36 -07:00
{
2008-02-24 18:41:47 +08:00
struct usb_serial_port * port = urb - > context ;
2005-04-16 15:20:36 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned char * data = urb - > transfer_buffer ;
2007-06-15 15:44:13 -07:00
int retval ;
int status = urb - > status ;
2005-04-16 15:20:36 -07:00
unsigned long flags ;
2007-06-15 15:44:13 -07:00
switch ( status ) {
2005-04-16 15:20:36 -07:00
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " %s - urb shutting down with status: %d \n " ,
__func__ , status ) ;
2005-04-16 15:20:36 -07:00
return ;
default :
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " %s - nonzero urb status received: %d \n " ,
__func__ , status ) ;
2005-04-16 15:20:36 -07:00
goto exit ;
}
2012-09-18 09:58:57 +01:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length , data ) ;
2005-04-16 15:20:36 -07:00
/*
* Work - a - round : handle the ' usual ' bulk - in pipe here
*/
if ( urb - > transfer_buffer_length > 2 ) {
if ( urb - > actual_length ) {
2013-01-03 15:53:06 +01:00
tty_insert_flip_string ( & port - > port , data ,
urb - > actual_length ) ;
tty_flip_buffer_push ( & port - > port ) ;
2005-04-16 15:20:36 -07:00
}
goto exit ;
}
2008-07-22 11:14:30 +01:00
2005-04-16 15:20:36 -07:00
/*
* The interrupt - in pipe signals exceptional conditions ( modem line
* signal changes and errors ) . data [ 0 ] holds MSR , data [ 1 ] holds LSR .
*/
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > last_msr = data [ MCT_U232_MSR_INDEX ] ;
2008-07-22 11:14:30 +01:00
2005-04-16 15:20:36 -07:00
/* Record Control Line states */
2012-09-14 15:08:30 -07:00
mct_u232_msr_to_state ( port , & priv - > control_state , priv - > last_msr ) ;
2005-04-16 15:20:36 -07:00
2013-03-21 12:37:12 +01:00
mct_u232_msr_to_icount ( & port - > icount , priv - > last_msr ) ;
2011-01-09 01:00:11 -05:00
2005-04-16 15:20:36 -07:00
#if 0
2008-07-22 11:14:30 +01:00
/* Not yet handled. See belkin_sa.c for further information */
2005-04-16 15:20:36 -07:00
/* Now to report any errors */
priv - > last_lsr = data [ MCT_U232_LSR_INDEX ] ;
/*
* fill in the flip buffer here , but I do not know the relation
* to the current / next receive buffer or characters . I need
* to look in to this before committing any code .
*/
if ( priv - > last_lsr & MCT_U232_LSR_ERR ) {
2008-10-13 10:39:46 +01:00
tty = tty_port_tty_get ( & port - > port ) ;
2005-04-16 15:20:36 -07:00
/* Overrun Error */
if ( priv - > last_lsr & MCT_U232_LSR_OE ) {
}
/* Parity Error */
if ( priv - > last_lsr & MCT_U232_LSR_PE ) {
}
/* Framing Error */
if ( priv - > last_lsr & MCT_U232_LSR_FE ) {
}
/* Break Indicator */
if ( priv - > last_lsr & MCT_U232_LSR_BI ) {
}
2008-10-13 10:39:46 +01:00
tty_kref_put ( tty ) ;
2005-04-16 15:20:36 -07:00
}
# endif
2013-03-21 12:37:13 +01:00
wake_up_interruptible ( & port - > port . delta_msr_wait ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
exit :
2008-07-22 11:14:30 +01:00
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2007-06-15 15:44:13 -07:00
if ( retval )
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev ,
" %s - usb_submit_urb failed with result %d \n " ,
__func__ , retval ) ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_read_int_callback */
2008-07-22 11:14:30 +01:00
static void mct_u232_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port ,
struct ktermios * old_termios )
2005-04-16 15:20:36 -07:00
{
struct usb_serial * serial = port - > serial ;
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
2012-07-14 15:31:47 +01:00
struct ktermios * termios = & tty - > termios ;
2007-12-13 16:15:29 -08:00
unsigned int cflag = termios - > c_cflag ;
2005-04-16 15:20:36 -07:00
unsigned int old_cflag = old_termios - > c_cflag ;
unsigned long flags ;
2007-05-08 11:00:12 -07:00
unsigned int control_state ;
2005-04-16 15:20:36 -07:00
unsigned char last_lcr ;
/* get a local copy of the current port settings */
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
last_lcr = 0 ;
/*
* 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 .
*/
2008-07-22 11:14:30 +01:00
/* reassert DTR and RTS on transition from B0 */
2005-04-16 15:20:36 -07:00
if ( ( old_cflag & CBAUD ) = = B0 ) {
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " %s: baud was B0 \n " , __func__ ) ;
2007-05-08 11:00:12 -07:00
control_state | = TIOCM_DTR | TIOCM_RTS ;
2012-09-14 15:08:30 -07:00
mct_u232_set_modem_ctrl ( port , control_state ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-22 11:09:07 +01:00
mct_u232_set_baud_rate ( tty , serial , port , tty_get_baud_rate ( tty ) ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:14:30 +01:00
if ( ( cflag & CBAUD ) = = B0 ) {
2012-09-14 15:08:30 -07:00
dev_dbg ( & port - > dev , " %s: baud is B0 \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
/* Drop RTS and DTR */
control_state & = ~ ( TIOCM_DTR | TIOCM_RTS ) ;
2012-09-14 15:08:30 -07:00
mct_u232_set_modem_ctrl ( port , control_state ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Update line control register ( LCR )
*/
/* set the parity */
if ( cflag & PARENB )
last_lcr | = ( cflag & PARODD ) ?
MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN ;
else
last_lcr | = MCT_U232_PARITY_NONE ;
/* set the number of data bits */
switch ( cflag & CSIZE ) {
case CS5 :
last_lcr | = MCT_U232_DATA_BITS_5 ; break ;
case CS6 :
last_lcr | = MCT_U232_DATA_BITS_6 ; break ;
case CS7 :
last_lcr | = MCT_U232_DATA_BITS_7 ; break ;
case CS8 :
last_lcr | = MCT_U232_DATA_BITS_8 ; break ;
default :
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev ,
" CSIZE was not CS5-CS8, using default of 8 \n " ) ;
2005-04-16 15:20:36 -07:00
last_lcr | = MCT_U232_DATA_BITS_8 ;
break ;
}
2007-12-13 16:15:29 -08:00
termios - > c_cflag & = ~ CMSPAR ;
2005-04-16 15:20:36 -07:00
/* set the number of stop bits */
last_lcr | = ( cflag & CSTOPB ) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1 ;
2012-09-14 15:08:30 -07:00
mct_u232_set_line_ctrl ( port , last_lcr ) ;
2005-04-16 15:20:36 -07:00
/* save off the modified port settings */
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > control_state = control_state ;
priv - > last_lcr = last_lcr ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
} /* mct_u232_set_termios */
2008-07-22 11:09:07 +01:00
static void mct_u232_break_ctl ( struct tty_struct * tty , int break_state )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-16 15:20:36 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned char lcr ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
lcr = priv - > last_lcr ;
if ( break_state )
lcr | = MCT_U232_SET_BREAK ;
2009-01-02 13:48:56 +00:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
2012-09-14 15:08:30 -07:00
mct_u232_set_line_ctrl ( port , lcr ) ;
2005-04-16 15:20:36 -07:00
} /* mct_u232_break_ctl */
2011-02-14 16:26:14 +00:00
static int mct_u232_tiocmget ( struct tty_struct * tty )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-16 15:20:36 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned int control_state ;
unsigned long flags ;
2008-07-22 11:14:30 +01:00
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return control_state ;
}
2011-02-14 16:26:50 +00:00
static int mct_u232_tiocmset ( struct tty_struct * tty ,
2005-04-16 15:20:36 -07:00
unsigned int set , unsigned int clear )
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-16 15:20:36 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned int control_state ;
unsigned long flags ;
2008-07-22 11:14:30 +01:00
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
control_state = priv - > control_state ;
if ( set & TIOCM_RTS )
control_state | = TIOCM_RTS ;
if ( set & TIOCM_DTR )
control_state | = TIOCM_DTR ;
if ( clear & TIOCM_RTS )
control_state & = ~ TIOCM_RTS ;
if ( clear & TIOCM_DTR )
control_state & = ~ TIOCM_DTR ;
priv - > control_state = control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-09-14 15:08:30 -07:00
return mct_u232_set_modem_ctrl ( port , control_state ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-22 11:09:07 +01:00
static void mct_u232_throttle ( struct tty_struct * tty )
2007-05-08 11:00:12 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2007-05-08 11:00:12 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned int control_state ;
2009-10-07 10:50:23 +02:00
spin_lock_irq ( & priv - > lock ) ;
2007-05-08 11:00:12 -07:00
priv - > rx_flags | = THROTTLED ;
if ( C_CRTSCTS ( tty ) ) {
2008-07-22 11:09:07 +01:00
priv - > control_state & = ~ TIOCM_RTS ;
control_state = priv - > control_state ;
2009-10-07 10:50:23 +02:00
spin_unlock_irq ( & priv - > lock ) ;
2012-09-14 15:08:30 -07:00
mct_u232_set_modem_ctrl ( port , control_state ) ;
2007-05-08 11:00:12 -07:00
} else {
2009-10-07 10:50:23 +02:00
spin_unlock_irq ( & priv - > lock ) ;
2007-05-08 11:00:12 -07:00
}
}
2008-07-22 11:09:07 +01:00
static void mct_u232_unthrottle ( struct tty_struct * tty )
2007-05-08 11:00:12 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2007-05-08 11:00:12 -07:00
struct mct_u232_private * priv = usb_get_serial_port_data ( port ) ;
unsigned int control_state ;
2009-10-07 10:50:23 +02:00
spin_lock_irq ( & priv - > lock ) ;
2007-05-08 11:00:12 -07:00
if ( ( priv - > rx_flags & THROTTLED ) & & C_CRTSCTS ( tty ) ) {
2008-07-22 11:09:07 +01:00
priv - > rx_flags & = ~ THROTTLED ;
priv - > control_state | = TIOCM_RTS ;
control_state = priv - > control_state ;
2009-10-07 10:50:23 +02:00
spin_unlock_irq ( & priv - > lock ) ;
2012-09-14 15:08:30 -07:00
mct_u232_set_modem_ctrl ( port , control_state ) ;
2007-05-08 11:00:12 -07:00
} else {
2009-10-07 10:50:23 +02:00
spin_unlock_irq ( & priv - > lock ) ;
2007-05-08 11:00:12 -07:00
}
}
2005-04-16 15:20:36 -07:00
2012-05-08 15:46:14 -07:00
module_usb_serial_driver ( serial_drivers , id_table ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:14:30 +01:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;