2005-04-17 02:20:36 +04:00
/*
* KLSI KL5KUSB105 chip RS232 converter driver
*
2010-05-19 02:01:40 +04:00
* Copyright ( C ) 2010 Johan Hovold < jhovold @ gmail . com >
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 2001 Utz - Uwe Haus < haus @ uuhaus . 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 .
*
* All information about the device was acquired using SniffUSB ans snoopUSB
* on Windows98 .
* It was written out of frustration with the PalmConnect USB Serial adapter
* sold by Palm Inc .
* Neither Palm , nor their contractor ( MCCI ) or their supplier ( KLSI ) provided
* information that was not already available .
*
2008-07-22 14:14:00 +04:00
* It seems that KLSI bought some silicon - design information from ScanLogic ,
2005-04-17 02:20:36 +04:00
* whose SL11R processor is at the core of the KL5KUSB chipset from KLSI .
* KLSI has firmware available for their devices ; it is probable that the
* firmware differs from that used by KLSI in their products . If you have an
2008-07-22 14:14:00 +04:00
* original KLSI device and can provide some information on it , I would be
* most interested in adding support for it here . If you have any information
2005-04-17 02:20:36 +04:00
* on the protocol used ( or find errors in my reverse - engineered stuff ) , please
* let me know .
*
* The code was only tested with a PalmConnect USB adapter ; if you
* are adventurous , try it with any KLSI - based device and let me know how it
* breaks so that I can fix it !
*/
/* TODO:
* check modem line signals
* implement handshaking or decide that we do not support it
*/
# 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>
2008-07-22 14:14:00 +04:00
# include <linux/uaccess.h>
2008-04-28 10:00:16 +04:00
# include <asm/unaligned.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 "kl5kusb105.h"
2010-05-19 02:01:40 +04:00
# define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
2005-04-17 02:20:36 +04:00
# define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
/*
* Function prototypes
*/
2012-10-17 15:35:01 +04:00
static int klsi_105_port_probe ( struct usb_serial_port * port ) ;
static int klsi_105_port_remove ( struct usb_serial_port * port ) ;
2009-09-20 00:13:26 +04:00
static int klsi_105_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void klsi_105_close ( struct usb_serial_port * port ) ;
2008-07-22 14:14:00 +04:00
static void klsi_105_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old ) ;
2011-02-14 19:26:14 +03:00
static int klsi_105_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 19:26:50 +03:00
static int klsi_105_tiocmset ( struct tty_struct * tty ,
2008-07-22 14:14:00 +04:00
unsigned int set , unsigned int clear ) ;
2010-05-19 02:01:40 +04:00
static void klsi_105_process_read_urb ( struct urb * urb ) ;
static int klsi_105_prepare_write_buffer ( struct usb_serial_port * port ,
void * dest , size_t size ) ;
2005-04-17 02:20:36 +04:00
/*
* All of the device info needed for the KLSI converters .
*/
2010-01-10 17:34:24 +03:00
static const struct usb_device_id id_table [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( PALMCONNECT_VID , PALMCONNECT_PID ) } ,
{ USB_DEVICE ( KLSI_VID , KLSI_KL5KUSB105D_PID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 14:14:00 +04:00
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2005-04-17 02:20:36 +04:00
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver kl5kusb105d_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " kl5kusb105d " ,
2005-06-21 08:15:16 +04:00
} ,
2010-05-19 02:01:39 +04:00
. description = " KL5KUSB105D / PalmConnect " ,
. id_table = id_table ,
. num_ports = 1 ,
2010-05-19 02:01:40 +04:00
. bulk_out_size = 64 ,
2010-05-19 02:01:39 +04:00
. open = klsi_105_open ,
. close = klsi_105_close ,
. set_termios = klsi_105_set_termios ,
/*.break_ctl = klsi_105_break_ctl,*/
. tiocmget = klsi_105_tiocmget ,
. tiocmset = klsi_105_tiocmset ,
2012-10-17 15:35:01 +04:00
. port_probe = klsi_105_port_probe ,
. port_remove = klsi_105_port_remove ,
2010-05-19 02:01:40 +04:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
. process_read_urb = klsi_105_process_read_urb ,
. prepare_write_buffer = klsi_105_prepare_write_buffer ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-23 23:57:09 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& kl5kusb105d_device , NULL
} ;
2005-04-17 02:20:36 +04:00
struct klsi_105_port_settings {
__u8 pktlen ; /* always 5, it seems */
__u8 baudrate ;
__u8 databits ;
__u8 unknown1 ;
__u8 unknown2 ;
} __attribute__ ( ( packed ) ) ;
struct klsi_105_private {
struct klsi_105_port_settings cfg ;
2006-12-08 13:38:45 +03:00
struct ktermios termios ;
2005-04-17 02:20:36 +04:00
unsigned long line_state ; /* modem line settings */
spinlock_t lock ;
} ;
/*
* Handle vendor specific USB requests
*/
# define KLSI_TIMEOUT 5000 /* default urb timeout */
static int klsi_105_chg_port_settings ( struct usb_serial_port * port ,
struct klsi_105_port_settings * settings )
{
int rc ;
2008-07-22 14:14:00 +04:00
rc = usb_control_msg ( port - > serial - > dev ,
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
KL5KUSB105A_SIO_SET_DATA ,
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE ,
0 , /* value */
0 , /* index */
settings ,
sizeof ( struct klsi_105_port_settings ) ,
KLSI_TIMEOUT ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" Change port settings failed (error = %d) \n " , rc ) ;
2008-08-19 00:21:04 +04:00
dev_info ( & port - > serial - > dev - > dev ,
" %d byte block, baudrate %x, databits %d, u1 %d, u2 %d \n " ,
settings - > pktlen , settings - > baudrate , settings - > databits ,
settings - > unknown1 , settings - > unknown2 ) ;
2008-07-22 14:14:00 +04:00
return rc ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
/* translate a 16-bit status value from the device to linux's TIO bits */
static unsigned long klsi_105_status2linestate ( const __u16 status )
{
unsigned long res = 0 ;
res = ( ( status & KL5KUSB105A_DSR ) ? TIOCM_DSR : 0 )
| ( ( status & KL5KUSB105A_CTS ) ? TIOCM_CTS : 0 )
;
return res ;
}
2010-05-19 02:01:39 +04:00
2008-07-22 14:14:00 +04:00
/*
2005-04-17 02:20:36 +04:00
* Read line control via vendor command and return result through
2008-07-22 14:14:00 +04:00
* * line_state_p
2005-04-17 02:20:36 +04:00
*/
/* It seems that the status buffer has always only 2 bytes length */
# define KLSI_STATUSBUF_LEN 2
static int klsi_105_get_line_state ( struct usb_serial_port * port ,
unsigned long * line_state_p )
{
int rc ;
2009-12-29 01:01:52 +03:00
u8 * status_buf ;
2005-04-17 02:20:36 +04:00
__u16 status ;
2008-08-19 00:21:04 +04:00
dev_info ( & port - > serial - > dev - > dev , " sending SIO Poll request \n " ) ;
2009-12-29 01:01:52 +03:00
status_buf = kmalloc ( KLSI_STATUSBUF_LEN , GFP_KERNEL ) ;
if ( ! status_buf ) {
dev_err ( & port - > dev , " %s - out of memory for status buffer. \n " ,
__func__ ) ;
return - ENOMEM ;
}
status_buf [ 0 ] = 0xff ;
status_buf [ 1 ] = 0xff ;
2008-07-22 14:14:00 +04:00
rc = usb_control_msg ( port - > serial - > dev ,
2005-04-17 02:20:36 +04:00
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
KL5KUSB105A_SIO_POLL ,
2008-07-22 14:14:00 +04:00
USB_TYPE_VENDOR | USB_DIR_IN ,
2005-04-17 02:20:36 +04:00
0 , /* value */
0 , /* index */
status_buf , KLSI_STATUSBUF_LEN ,
10000
) ;
if ( rc < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Reading line status failed (error = %d) \n " ,
rc ) ;
2005-04-17 02:20:36 +04:00
else {
2008-05-02 07:52:57 +04:00
status = get_unaligned_le16 ( status_buf ) ;
2005-04-17 02:20:36 +04:00
2008-08-19 00:21:04 +04:00
dev_info ( & port - > serial - > dev - > dev , " read status %x %x " ,
status_buf [ 0 ] , status_buf [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
* line_state_p = klsi_105_status2linestate ( status ) ;
}
2009-12-29 01:01:52 +03:00
kfree ( status_buf ) ;
2008-07-22 14:14:00 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
/*
* Driver ' s tty interface functions
*/
2012-10-17 15:35:01 +04:00
static int klsi_105_port_probe ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct klsi_105_private * priv ;
2012-10-17 15:35:01 +04:00
priv = kmalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
/* set initial values for control structures */
priv - > cfg . pktlen = 5 ;
priv - > cfg . baudrate = kl5kusb105a_sio_b9600 ;
priv - > cfg . databits = kl5kusb105a_dtb_8 ;
priv - > cfg . unknown1 = 0 ;
priv - > cfg . unknown2 = 1 ;
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
priv - > line_state = 0 ;
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
spin_lock_init ( & priv - > lock ) ;
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
/* priv->termios is left uninitialized until port opening */
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
usb_set_serial_port_data ( port , priv ) ;
2008-07-22 14:14:00 +04:00
2007-03-29 13:23:54 +04:00
return 0 ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:01 +04:00
static int klsi_105_port_remove ( struct usb_serial_port * port )
2009-06-02 19:53:55 +04:00
{
2012-10-17 15:35:01 +04:00
struct klsi_105_private * priv ;
2009-06-02 19:53:55 +04:00
2012-10-17 15:35:01 +04:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
2009-09-20 00:13:26 +04:00
static int klsi_105_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct klsi_105_private * priv = usb_get_serial_port_data ( port ) ;
int retval = 0 ;
int rc ;
int i ;
unsigned long line_state ;
2009-12-29 01:01:52 +03:00
struct klsi_105_port_settings * cfg ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
/* Do a defined restart:
* Set up sane default baud rate and send the ' READ_ON '
2008-07-22 14:14:00 +04:00
* vendor command .
2005-04-17 02:20:36 +04:00
* FIXME : set modem line control ( how ? )
* Then read the modem line control and store values in
* priv - > line_state .
*/
2009-12-29 01:01:52 +03:00
cfg = kmalloc ( sizeof ( * cfg ) , GFP_KERNEL ) ;
if ( ! cfg ) {
dev_err ( & port - > dev , " %s - out of memory for config buffer. \n " ,
__func__ ) ;
return - ENOMEM ;
}
cfg - > pktlen = 5 ;
cfg - > baudrate = kl5kusb105a_sio_b9600 ;
cfg - > databits = kl5kusb105a_dtb_8 ;
cfg - > unknown1 = 0 ;
cfg - > unknown2 = 1 ;
klsi_105_chg_port_settings ( port , cfg ) ;
2008-07-22 14:14:00 +04:00
2005-04-17 02:20:36 +04:00
/* set up termios structure */
2008-07-22 14:14:00 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2012-07-14 18:31:47 +04:00
priv - > termios . c_iflag = tty - > termios . c_iflag ;
priv - > termios . c_oflag = tty - > termios . c_oflag ;
priv - > termios . c_cflag = tty - > termios . c_cflag ;
priv - > termios . c_lflag = tty - > termios . c_lflag ;
2008-07-22 14:14:00 +04:00
for ( i = 0 ; i < NCCS ; i + + )
2012-07-14 18:31:47 +04:00
priv - > termios . c_cc [ i ] = tty - > termios . c_cc [ i ] ;
2009-12-29 01:01:52 +03:00
priv - > cfg . pktlen = cfg - > pktlen ;
priv - > cfg . baudrate = cfg - > baudrate ;
priv - > cfg . databits = cfg - > databits ;
priv - > cfg . unknown1 = cfg - > unknown1 ;
priv - > cfg . unknown2 = cfg - > unknown2 ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* READ_ON and urb submission */
2010-05-19 02:01:40 +04:00
rc = usb_serial_generic_open ( tty , port ) ;
2005-04-17 02:20:36 +04:00
if ( rc ) {
retval = rc ;
goto exit ;
}
rc = usb_control_msg ( port - > serial - > dev ,
2008-07-22 14:14:00 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2005-04-17 02:20:36 +04:00
KL5KUSB105A_SIO_CONFIGURE ,
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE ,
KL5KUSB105A_SIO_CONFIGURE_READ_ON ,
0 , /* index */
NULL ,
0 ,
KLSI_TIMEOUT ) ;
if ( rc < 0 ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " Enabling read failed (error = %d) \n " , rc ) ;
2005-04-17 02:20:36 +04:00
retval = rc ;
2008-07-22 14:14:00 +04:00
} else
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - enabled reading \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
rc = klsi_105_get_line_state ( port , & line_state ) ;
if ( rc > = 0 ) {
2008-07-22 14:14:00 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
priv - > line_state = line_state ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - read line state 0x%lx \n " , __func__ , line_state ) ;
2005-04-17 02:20:36 +04:00
retval = 0 ;
} else
retval = rc ;
exit :
2009-12-29 01:01:52 +03:00
kfree ( cfg ) ;
2005-04-17 02:20:36 +04:00
return retval ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
2009-06-11 15:26:29 +04:00
static void klsi_105_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
int rc ;
2008-01-22 14:47:15 +03:00
mutex_lock ( & port - > serial - > disc_mutex ) ;
if ( ! port - > serial - > disconnected ) {
/* send READ_OFF */
2008-07-22 14:14:00 +04:00
rc = usb_control_msg ( port - > serial - > dev ,
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
KL5KUSB105A_SIO_CONFIGURE ,
USB_TYPE_VENDOR | USB_DIR_OUT ,
KL5KUSB105A_SIO_CONFIGURE_READ_OFF ,
0 , /* index */
NULL , 0 ,
KLSI_TIMEOUT ) ;
2008-01-22 14:47:15 +03:00
if ( rc < 0 )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" Disabling read failed (error = %d) \n " , rc ) ;
2008-01-22 14:47:15 +03:00
}
mutex_unlock ( & port - > serial - > disc_mutex ) ;
2005-04-17 02:20:36 +04:00
/* shutdown our bulk reads and writes */
2010-05-19 02:01:40 +04:00
usb_serial_generic_close ( port ) ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
/* We need to write a complete 64-byte data block and encode the
2008-07-22 14:14:00 +04:00
* number actually sent in the first double - byte , LSB - order . That
2005-04-17 02:20:36 +04:00
* leaves at most 62 bytes of payload .
*/
2010-05-19 02:01:40 +04:00
# define KLSI_HDR_LEN 2
static int klsi_105_prepare_write_buffer ( struct usb_serial_port * port ,
void * dest , size_t size )
2005-04-17 02:20:36 +04:00
{
2010-05-19 02:01:40 +04:00
unsigned char * buf = dest ;
int count ;
2007-06-16 02:44:13 +04:00
2010-05-19 02:01:40 +04:00
count = kfifo_out_locked ( & port - > write_fifo , buf + KLSI_HDR_LEN , size ,
& port - > lock ) ;
put_unaligned_le16 ( count , buf ) ;
2005-04-17 02:20:36 +04:00
2010-05-19 02:01:40 +04:00
return count + KLSI_HDR_LEN ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
2010-05-19 02:01:40 +04:00
/* The data received is preceded by a length double-byte in LSB-first order.
*/
static void klsi_105_process_read_urb ( 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
unsigned char * data = urb - > transfer_buffer ;
2010-05-19 02:01:40 +04:00
unsigned len ;
2005-04-17 02:20:36 +04:00
2010-05-19 02:01:40 +04:00
/* empty urbs seem to happen, we ignore them */
if ( ! urb - > actual_length )
return ;
2005-04-17 02:20:36 +04:00
2010-05-19 02:01:40 +04:00
if ( urb - > actual_length < = KLSI_HDR_LEN ) {
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - malformed packet \n " , __func__ ) ;
2007-06-16 02:44:13 +04:00
return ;
}
2010-05-19 02:01:40 +04:00
len = get_unaligned_le16 ( data ) ;
if ( len > urb - > actual_length - KLSI_HDR_LEN ) {
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - packet length mismatch \n " , __func__ ) ;
2010-05-19 02:01:40 +04:00
len = urb - > actual_length - KLSI_HDR_LEN ;
2005-04-17 02:20:36 +04:00
}
2010-05-19 02:01:40 +04:00
2013-01-03 18:53:04 +04:00
tty_insert_flip_string ( & port - > port , data + KLSI_HDR_LEN , len ) ;
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > port ) ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:14:00 +04:00
static void klsi_105_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port ,
struct ktermios * old_termios )
2005-04-17 02:20:36 +04:00
{
struct klsi_105_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-14 20:47:43 +04:00
struct device * dev = & port - > dev ;
2012-07-14 18:31:47 +04:00
unsigned int iflag = tty - > termios . c_iflag ;
2005-04-17 02:20:36 +04:00
unsigned int old_iflag = old_termios - > c_iflag ;
2012-07-14 18:31:47 +04:00
unsigned int cflag = tty - > termios . c_cflag ;
2005-04-17 02:20:36 +04:00
unsigned int old_cflag = old_termios - > c_cflag ;
2009-12-29 01:01:52 +03:00
struct klsi_105_port_settings * cfg ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2008-04-08 20:16:06 +04:00
speed_t baud ;
2008-07-22 14:14:00 +04:00
2009-12-29 01:01:52 +03:00
cfg = kmalloc ( sizeof ( * cfg ) , GFP_KERNEL ) ;
if ( ! cfg ) {
2012-09-14 20:47:43 +04:00
dev_err ( dev , " %s - out of memory for config buffer. \n " , __func__ ) ;
2009-12-29 01:01:52 +03:00
return ;
}
2005-04-17 02:20:36 +04:00
/* lock while we are modifying the settings */
2008-07-22 14:14:00 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/*
* Update baud rate
*/
2008-04-08 20:16:06 +04:00
baud = tty_get_baud_rate ( tty ) ;
2008-07-22 14:14:00 +04:00
if ( ( cflag & CBAUD ) ! = ( old_cflag & CBAUD ) ) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if ( ( old_cflag & CBAUD ) = = B0 ) {
2012-09-14 20:47:43 +04:00
dev_dbg ( dev , " %s: baud was B0 \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
#if 0
priv - > control_state | = TIOCM_DTR ;
/* don't set RTS if using hardware flow control */
2008-07-22 14:14:00 +04:00
if ( ! ( old_cflag & CRTSCTS ) )
2005-04-17 02:20:36 +04:00
priv - > control_state | = TIOCM_RTS ;
mct_u232_set_modem_ctrl ( serial , priv - > control_state ) ;
# endif
}
2008-04-08 20:16:06 +04:00
}
2008-07-22 14:14:00 +04:00
switch ( baud ) {
case 0 : /* handled below */
break ;
case 1200 :
priv - > cfg . baudrate = kl5kusb105a_sio_b1200 ;
break ;
case 2400 :
priv - > cfg . baudrate = kl5kusb105a_sio_b2400 ;
break ;
case 4800 :
priv - > cfg . baudrate = kl5kusb105a_sio_b4800 ;
break ;
case 9600 :
priv - > cfg . baudrate = kl5kusb105a_sio_b9600 ;
break ;
case 19200 :
priv - > cfg . baudrate = kl5kusb105a_sio_b19200 ;
break ;
case 38400 :
priv - > cfg . baudrate = kl5kusb105a_sio_b38400 ;
break ;
case 57600 :
priv - > cfg . baudrate = kl5kusb105a_sio_b57600 ;
break ;
case 115200 :
priv - > cfg . baudrate = kl5kusb105a_sio_b115200 ;
break ;
default :
2012-09-14 20:47:43 +04:00
dev_dbg ( dev , " KLSI USB->Serial converter: unsupported baudrate request, using default of 9600 " ) ;
priv - > cfg . baudrate = kl5kusb105a_sio_b9600 ;
2008-07-22 14:14:00 +04:00
baud = 9600 ;
break ;
2008-04-08 20:16:06 +04:00
}
2008-07-22 14:14:00 +04:00
if ( ( cflag & CBAUD ) = = B0 ) {
2012-09-14 20:47:43 +04:00
dev_dbg ( dev , " %s: baud is B0 \n " , __func__ ) ;
2008-04-08 20:16:06 +04:00
/* Drop RTS and DTR */
/* maybe this should be simulated by sending read
* disable and read enable messages ?
*/
;
2005-04-17 02:20:36 +04:00
#if 0
2008-04-08 20:16:06 +04:00
priv - > control_state & = ~ ( TIOCM_DTR | TIOCM_RTS ) ;
2008-07-22 14:14:00 +04:00
mct_u232_set_modem_ctrl ( serial , priv - > control_state ) ;
2005-04-17 02:20:36 +04:00
# endif
}
2008-04-08 20:16:06 +04:00
tty_encode_baud_rate ( tty , baud , baud ) ;
2005-04-17 02:20:36 +04:00
if ( ( cflag & CSIZE ) ! = ( old_cflag & CSIZE ) ) {
/* set the number of data bits */
switch ( cflag & CSIZE ) {
case CS5 :
2012-09-14 20:47:43 +04:00
dev_dbg ( dev , " %s - 5 bits/byte not supported \n " , __func__ ) ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2009-12-29 01:01:52 +03:00
goto err ;
2005-04-17 02:20:36 +04:00
case CS6 :
2012-09-14 20:47:43 +04:00
dev_dbg ( dev , " %s - 6 bits/byte not supported \n " , __func__ ) ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2009-12-29 01:01:52 +03:00
goto err ;
2005-04-17 02:20:36 +04:00
case CS7 :
priv - > cfg . databits = kl5kusb105a_dtb_7 ;
break ;
case CS8 :
priv - > cfg . databits = kl5kusb105a_dtb_8 ;
break ;
default :
2012-09-14 20:47:43 +04:00
dev_err ( dev , " CSIZE was not CS5-CS8, using default of 8 \n " ) ;
2005-04-17 02:20:36 +04:00
priv - > cfg . databits = kl5kusb105a_dtb_8 ;
break ;
}
}
/*
* Update line control register ( LCR )
*/
if ( ( cflag & ( PARENB | PARODD ) ) ! = ( old_cflag & ( PARENB | PARODD ) )
2008-07-22 14:14:00 +04:00
| | ( cflag & CSTOPB ) ! = ( old_cflag & CSTOPB ) ) {
2008-04-08 20:16:06 +04:00
/* Not currently supported */
2012-07-14 18:31:47 +04:00
tty - > termios . c_cflag & = ~ ( PARENB | PARODD | CSTOPB ) ;
2005-04-17 02:20:36 +04:00
#if 0
priv - > last_lcr = 0 ;
/* set the parity */
if ( cflag & PARENB )
priv - > last_lcr | = ( cflag & PARODD ) ?
MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN ;
else
priv - > last_lcr | = MCT_U232_PARITY_NONE ;
/* set the number of stop bits */
priv - > last_lcr | = ( cflag & CSTOPB ) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1 ;
mct_u232_set_line_ctrl ( serial , priv - > last_lcr ) ;
# endif
;
}
/*
* Set flow control : well , I do not really now how to handle DTR / RTS .
* Just do what we have seen with SniffUSB on Win98 .
*/
2008-07-22 14:14:00 +04:00
if ( ( iflag & IXOFF ) ! = ( old_iflag & IXOFF )
2005-04-17 02:20:36 +04:00
| | ( iflag & IXON ) ! = ( old_iflag & IXON )
2008-07-22 14:14:00 +04:00
| | ( cflag & CRTSCTS ) ! = ( old_cflag & CRTSCTS ) ) {
2008-04-08 20:16:06 +04:00
/* Not currently supported */
2012-07-14 18:31:47 +04:00
tty - > termios . c_cflag & = ~ CRTSCTS ;
2005-04-17 02:20:36 +04:00
/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
2008-07-22 14:14:00 +04:00
if ( ( iflag & IXOFF ) | | ( iflag & IXON ) | | ( cflag & CRTSCTS ) )
2005-04-17 02:20:36 +04:00
priv - > control_state | = TIOCM_DTR | TIOCM_RTS ;
else
priv - > control_state & = ~ ( TIOCM_DTR | TIOCM_RTS ) ;
mct_u232_set_modem_ctrl ( serial , priv - > control_state ) ;
# endif
;
}
2009-12-29 01:01:52 +03:00
memcpy ( cfg , & priv - > cfg , sizeof ( * cfg ) ) ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* now commit changes to device */
2009-12-29 01:01:52 +03:00
klsi_105_chg_port_settings ( port , cfg ) ;
err :
kfree ( cfg ) ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
#if 0
2008-07-22 14:14:00 +04:00
static void mct_u232_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 ;
2008-07-22 14:14:00 +04:00
struct mct_u232_private * priv =
( struct mct_u232_private * ) port - > private ;
2005-04-17 02:20:36 +04:00
unsigned char lcr = priv - > last_lcr ;
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - state=%d \n " , __func__ , break_state ) ;
2005-04-17 02:20:36 +04:00
2009-01-02 16:48:56 +03:00
/* LOCKING */
2005-04-17 02:20:36 +04:00
if ( break_state )
lcr | = MCT_U232_SET_BREAK ;
mct_u232_set_line_ctrl ( serial , lcr ) ;
2010-05-19 02:01:39 +04:00
}
2005-04-17 02:20:36 +04:00
# endif
2011-02-14 19:26:14 +03:00
static int klsi_105_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 klsi_105_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
int rc ;
unsigned long line_state ;
rc = klsi_105_get_line_state ( port , & line_state ) ;
if ( rc < 0 ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" Reading line control failed (error = %d) \n " , rc ) ;
2005-04-17 02:20:36 +04:00
/* better return value? EAGAIN? */
return rc ;
}
2008-07-22 14:14:00 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
priv - > line_state = line_state ;
2008-07-22 14:14:00 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-09-14 20:47:43 +04:00
dev_dbg ( & port - > dev , " %s - read line state 0x%lx \n " , __func__ , line_state ) ;
2005-04-17 02:20:36 +04:00
return ( int ) line_state ;
}
2011-02-14 19:26:50 +03:00
static int klsi_105_tiocmset ( struct tty_struct * tty ,
2008-07-22 14:14:00 +04:00
unsigned int set , unsigned int clear )
2005-04-17 02:20:36 +04:00
{
int retval = - EINVAL ;
2008-07-22 14:14:00 +04:00
2005-04-17 02:20:36 +04:00
/* if this ever gets implemented, it should be done something like this:
struct usb_serial * serial = port - > serial ;
struct klsi_105_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
int control ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( set & TIOCM_RTS )
priv - > control_state | = TIOCM_RTS ;
if ( set & TIOCM_DTR )
priv - > control_state | = TIOCM_DTR ;
if ( clear & TIOCM_RTS )
priv - > control_state & = ~ TIOCM_RTS ;
if ( clear & TIOCM_DTR )
priv - > control_state & = ~ TIOCM_DTR ;
control = priv - > control_state ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
retval = mct_u232_set_modem_ctrl ( serial , control ) ;
*/
return retval ;
}
2012-05-09 02:46:14 +04:00
module_usb_serial_driver ( serial_drivers , id_table ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:14:00 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;