2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2012-05-10 15:36:02 -04:00
/*
* usb - serial driver for Quatech USB 2 devices
*
2012-05-10 16:57:39 -04:00
* Copyright ( C ) 2012 Bill Pemberton ( wfp5p @ virginia . edu )
*
2012-05-10 15:36:02 -04:00
* These devices all have only 1 bulk in and 1 bulk out that is shared
* for all serial ports .
*
*/
# include <asm/unaligned.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/serial.h>
# include <linux/usb.h>
# include <linux/usb/serial.h>
# include <linux/serial_reg.h>
# include <linux/uaccess.h>
/* default urb timeout for usb operations */
# define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
# define QT_OPEN_CLOSE_CHANNEL 0xca
# define QT_SET_GET_DEVICE 0xc2
# define QT_SET_GET_REGISTER 0xc0
# define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
# define QT_SET_ATF 0xcd
# define QT_TRANSFER_IN 0xc0
# define QT_HW_FLOW_CONTROL_MASK 0xc5
# define QT_SW_FLOW_CONTROL_MASK 0xc6
# define QT2_BREAK_CONTROL 0xc8
# define QT2_GET_SET_UART 0xc1
# define QT2_FLUSH_DEVICE 0xc4
# define QT2_GET_SET_QMCR 0xe1
# define QT2_QMCR_RS232 0x40
# define QT2_QMCR_RS422 0x10
# define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
# define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
/* status bytes for the device */
# define QT2_CONTROL_BYTE 0x1b
# define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */
# define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */
# define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */
# define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */
# define QT2_REC_FLUSH 0x04 /* no following info */
# define QT2_XMIT_FLUSH 0x05 /* no following info */
# define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */
# define MAX_BAUD_RATE 921600
# define DEFAULT_BAUD_RATE 9600
2013-08-13 13:27:38 +02:00
# define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */
2012-05-10 15:36:02 -04:00
# define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
# define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
# define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver"
# define USB_VENDOR_ID_QUATECH 0x061d
# define QUATECH_SSU2_100 0xC120 /* RS232 single port */
# define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
# define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
# define QUATECH_QSU2_100 0xC160 /* RS232 four port */
# define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
# define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
# define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
struct qt2_device_detail {
int product_id ;
int num_ports ;
} ;
# define QT_DETAILS(prod, ports) \
. product_id = ( prod ) , \
. num_ports = ( ports )
static const struct qt2_device_detail qt2_device_details [ ] = {
{ QT_DETAILS ( QUATECH_SSU2_100 , 1 ) } ,
{ QT_DETAILS ( QUATECH_DSU2_400 , 2 ) } ,
{ QT_DETAILS ( QUATECH_DSU2_100 , 2 ) } ,
{ QT_DETAILS ( QUATECH_QSU2_400 , 4 ) } ,
{ QT_DETAILS ( QUATECH_QSU2_100 , 4 ) } ,
{ QT_DETAILS ( QUATECH_ESU2_400 , 8 ) } ,
{ QT_DETAILS ( QUATECH_ESU2_100 , 8 ) } ,
{ QT_DETAILS ( 0 , 0 ) } /* Terminating entry */
} ;
static const struct usb_device_id id_table [ ] = {
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_SSU2_100 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_DSU2_100 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_DSU2_400 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_QSU2_100 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_QSU2_400 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_ESU2_100 ) } ,
{ USB_DEVICE ( USB_VENDOR_ID_QUATECH , QUATECH_ESU2_400 ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
struct qt2_serial_private {
unsigned char current_port ; /* current port for incoming data */
struct urb * read_urb ; /* shared among all ports */
2013-08-13 13:27:38 +02:00
char * read_buffer ;
2012-05-10 15:36:02 -04:00
} ;
struct qt2_port_private {
u8 device_port ;
spinlock_t urb_lock ;
bool urb_in_use ;
struct urb * write_urb ;
2013-08-13 13:27:39 +02:00
char * write_buffer ;
2012-05-10 15:36:02 -04:00
spinlock_t lock ;
u8 shadowLSR ;
u8 shadowMSR ;
struct usb_serial_port * port ;
} ;
static void qt2_update_lsr ( struct usb_serial_port * port , unsigned char * ch ) ;
static void qt2_update_msr ( struct usb_serial_port * port , unsigned char * ch ) ;
static void qt2_write_bulk_callback ( struct urb * urb ) ;
static void qt2_read_bulk_callback ( struct urb * urb ) ;
static void qt2_release ( struct usb_serial * serial )
{
2012-10-25 10:29:08 +02:00
struct qt2_serial_private * serial_priv ;
2012-05-10 15:36:02 -04:00
2012-10-25 10:29:08 +02:00
serial_priv = usb_get_serial_data ( serial ) ;
2012-05-10 15:36:02 -04:00
2016-05-08 20:08:02 +02:00
usb_kill_urb ( serial_priv - > read_urb ) ;
2012-10-25 10:29:08 +02:00
usb_free_urb ( serial_priv - > read_urb ) ;
2013-08-13 13:27:38 +02:00
kfree ( serial_priv - > read_buffer ) ;
2012-10-25 10:29:08 +02:00
kfree ( serial_priv ) ;
2012-05-10 15:36:02 -04:00
}
static inline int calc_baud_divisor ( int baudrate )
{
int divisor , rem ;
divisor = MAX_BAUD_RATE / baudrate ;
rem = MAX_BAUD_RATE % baudrate ;
/* Round to nearest divisor */
if ( ( ( rem * 2 ) > = baudrate ) & & ( baudrate ! = 110 ) )
divisor + + ;
return divisor ;
}
static inline int qt2_set_port_config ( struct usb_device * dev ,
unsigned char port_number ,
u16 baudrate , u16 lcr )
{
int divisor = calc_baud_divisor ( baudrate ) ;
u16 index = ( ( u16 ) ( lcr < < 8 ) | ( u16 ) ( port_number ) ) ;
return usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
QT2_GET_SET_UART , 0x40 ,
divisor , index , NULL , 0 , QT2_USB_TIMEOUT ) ;
}
static inline int qt2_control_msg ( struct usb_device * dev ,
u8 request , u16 data , u16 index )
{
return usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
request , 0x40 , data , index ,
NULL , 0 , QT2_USB_TIMEOUT ) ;
}
static inline int qt2_setdevice ( struct usb_device * dev , u8 * data )
{
u16 x = ( ( u16 ) ( data [ 1 ] < < 8 ) | ( u16 ) ( data [ 0 ] ) ) ;
return qt2_control_msg ( dev , QT_SET_GET_DEVICE , x , 0 ) ;
}
static inline int qt2_getregister ( struct usb_device * dev ,
u8 uart ,
u8 reg ,
u8 * data )
{
2017-01-12 14:56:20 +01:00
int ret ;
ret = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
QT_SET_GET_REGISTER , 0xc0 , reg ,
uart , data , sizeof ( * data ) , QT2_USB_TIMEOUT ) ;
2018-06-25 15:35:18 +08:00
if ( ret < ( int ) sizeof ( * data ) ) {
2017-01-12 14:56:20 +01:00
if ( ret > = 0 )
ret = - EIO ;
}
2012-05-10 15:36:02 -04:00
2017-01-12 14:56:20 +01:00
return ret ;
2012-05-10 15:36:02 -04:00
}
static inline int qt2_setregister ( struct usb_device * dev ,
u8 uart , u8 reg , u16 data )
{
u16 value = ( data < < 8 ) | reg ;
return usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
QT_SET_GET_REGISTER , 0x40 , value , uart ,
NULL , 0 , QT2_USB_TIMEOUT ) ;
}
static inline int update_mctrl ( struct qt2_port_private * port_priv ,
unsigned int set , unsigned int clear )
{
struct usb_serial_port * port = port_priv - > port ;
struct usb_device * dev = port - > serial - > dev ;
unsigned urb_value ;
int status ;
if ( ( ( set | clear ) & ( TIOCM_DTR | TIOCM_RTS ) ) = = 0 ) {
dev_dbg ( & port - > dev ,
" update_mctrl - DTR|RTS not being set|cleared \n " ) ;
return 0 ; /* no change */
}
clear & = ~ set ; /* 'set' takes precedence over 'clear' */
urb_value = 0 ;
if ( set & TIOCM_DTR )
urb_value | = UART_MCR_DTR ;
if ( set & TIOCM_RTS )
urb_value | = UART_MCR_RTS ;
status = qt2_setregister ( dev , port_priv - > device_port , UART_MCR ,
urb_value ) ;
if ( status < 0 )
dev_err ( & port - > dev ,
" update_mctrl - Error from MODEM_CTRL urb: %i \n " ,
status ) ;
return status ;
}
2017-03-16 17:13:30 +01:00
static int qt2_calc_num_ports ( struct usb_serial * serial ,
struct usb_serial_endpoints * epds )
2012-05-10 15:36:02 -04:00
{
struct qt2_device_detail d ;
int i ;
for ( i = 0 ; d = qt2_device_details [ i ] , d . product_id ! = 0 ; i + + ) {
if ( d . product_id = = le16_to_cpu ( serial - > dev - > descriptor . idProduct ) )
return d . num_ports ;
}
/* we didn't recognize the device */
dev_err ( & serial - > dev - > dev ,
" don't know the number of ports, assuming 1 \n " ) ;
return 1 ;
}
static void qt2_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port ,
struct ktermios * old_termios )
{
struct usb_device * dev = port - > serial - > dev ;
struct qt2_port_private * port_priv ;
2012-07-14 15:31:47 +01:00
struct ktermios * termios = & tty - > termios ;
2012-05-10 15:36:02 -04:00
u16 baud ;
unsigned int cflag = termios - > c_cflag ;
u16 new_lcr = 0 ;
int status ;
port_priv = usb_get_serial_port_data ( port ) ;
if ( cflag & PARENB ) {
if ( cflag & PARODD )
new_lcr | = UART_LCR_PARITY ;
else
new_lcr | = SERIAL_EVEN_PARITY ;
}
switch ( cflag & CSIZE ) {
case CS5 :
new_lcr | = UART_LCR_WLEN5 ;
break ;
case CS6 :
new_lcr | = UART_LCR_WLEN6 ;
break ;
case CS7 :
new_lcr | = UART_LCR_WLEN7 ;
break ;
default :
case CS8 :
new_lcr | = UART_LCR_WLEN8 ;
break ;
}
baud = tty_get_baud_rate ( tty ) ;
if ( ! baud )
baud = 9600 ;
status = qt2_set_port_config ( dev , port_priv - > device_port , baud ,
new_lcr ) ;
if ( status < 0 )
dev_err ( & port - > dev , " %s - qt2_set_port_config failed: %i \n " ,
__func__ , status ) ;
if ( cflag & CRTSCTS )
status = qt2_control_msg ( dev , QT_HW_FLOW_CONTROL_MASK ,
SERIAL_CRTSCTS ,
port_priv - > device_port ) ;
else
status = qt2_control_msg ( dev , QT_HW_FLOW_CONTROL_MASK ,
0 , port_priv - > device_port ) ;
if ( status < 0 )
dev_err ( & port - > dev , " %s - set HW flow control failed: %i \n " ,
__func__ , status ) ;
if ( I_IXOFF ( tty ) | | I_IXON ( tty ) ) {
u16 x = ( ( u16 ) ( START_CHAR ( tty ) < < 8 ) | ( u16 ) ( STOP_CHAR ( tty ) ) ) ;
status = qt2_control_msg ( dev , QT_SW_FLOW_CONTROL_MASK ,
x , port_priv - > device_port ) ;
} else
status = qt2_control_msg ( dev , QT_SW_FLOW_CONTROL_MASK ,
0 , port_priv - > device_port ) ;
if ( status < 0 )
dev_err ( & port - > dev , " %s - set SW flow control failed: %i \n " ,
__func__ , status ) ;
}
static int qt2_open ( struct tty_struct * tty , struct usb_serial_port * port )
{
struct usb_serial * serial ;
struct qt2_port_private * port_priv ;
u8 * data ;
u16 device_port ;
int status ;
unsigned long flags ;
2013-06-06 10:32:00 -07:00
device_port = port - > port_number ;
2012-05-10 15:36:02 -04:00
serial = port - > serial ;
port_priv = usb_get_serial_port_data ( port ) ;
/* set the port to RS232 mode */
status = qt2_control_msg ( serial - > dev , QT2_GET_SET_QMCR ,
QT2_QMCR_RS232 , device_port ) ;
if ( status < 0 ) {
dev_err ( & port - > dev ,
" %s failed to set RS232 mode for port %i error %i \n " ,
__func__ , device_port , status ) ;
return status ;
}
data = kzalloc ( 2 , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
/* open the port */
status = usb_control_msg ( serial - > dev ,
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
QT_OPEN_CLOSE_CHANNEL ,
0xc0 , 0 ,
device_port , data , 2 , QT2_USB_TIMEOUT ) ;
2017-01-12 14:56:20 +01:00
if ( status < 2 ) {
2014-03-12 19:09:42 +01:00
dev_err ( & port - > dev , " %s - open port failed %i \n " , __func__ ,
2012-05-10 15:36:02 -04:00
status ) ;
2017-01-12 14:56:20 +01:00
if ( status > = 0 )
status = - EIO ;
2012-05-10 15:36:02 -04:00
kfree ( data ) ;
return status ;
}
spin_lock_irqsave ( & port_priv - > lock , flags ) ;
port_priv - > shadowLSR = data [ 0 ] ;
port_priv - > shadowMSR = data [ 1 ] ;
spin_unlock_irqrestore ( & port_priv - > lock , flags ) ;
kfree ( data ) ;
/* set to default speed and 8bit word size */
status = qt2_set_port_config ( serial - > dev , device_port ,
DEFAULT_BAUD_RATE , UART_LCR_WLEN8 ) ;
if ( status < 0 ) {
2013-06-06 10:32:00 -07:00
dev_err ( & port - > dev , " %s - initial setup failed (%i) \n " ,
__func__ , device_port ) ;
2012-05-10 15:36:02 -04:00
return status ;
}
port_priv - > device_port = ( u8 ) device_port ;
if ( tty )
2012-07-14 15:31:47 +01:00
qt2_set_termios ( tty , port , & tty - > termios ) ;
2012-05-10 15:36:02 -04:00
return 0 ;
}
static void qt2_close ( struct usb_serial_port * port )
{
struct usb_serial * serial ;
struct qt2_port_private * port_priv ;
int i ;
serial = port - > serial ;
port_priv = usb_get_serial_port_data ( port ) ;
2012-10-25 10:29:09 +02:00
usb_kill_urb ( port_priv - > write_urb ) ;
2012-05-10 15:36:02 -04:00
/* flush the port transmit buffer */
i = usb_control_msg ( serial - > dev ,
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
QT2_FLUSH_DEVICE , 0x40 , 1 ,
port_priv - > device_port , NULL , 0 , QT2_USB_TIMEOUT ) ;
if ( i < 0 )
dev_err ( & port - > dev , " %s - transmit buffer flush failed: %i \n " ,
__func__ , i ) ;
/* flush the port receive buffer */
i = usb_control_msg ( serial - > dev ,
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
QT2_FLUSH_DEVICE , 0x40 , 0 ,
port_priv - > device_port , NULL , 0 , QT2_USB_TIMEOUT ) ;
if ( i < 0 )
dev_err ( & port - > dev , " %s - receive buffer flush failed: %i \n " ,
__func__ , i ) ;
/* close the port */
i = usb_control_msg ( serial - > dev ,
usb_sndctrlpipe ( serial - > dev , 0 ) ,
QT_OPEN_CLOSE_CHANNEL ,
0x40 , 0 ,
port_priv - > device_port , NULL , 0 , QT2_USB_TIMEOUT ) ;
if ( i < 0 )
dev_err ( & port - > dev , " %s - close port failed %i \n " ,
__func__ , i ) ;
}
static void qt2_disconnect ( struct usb_serial * serial )
{
struct qt2_serial_private * serial_priv = usb_get_serial_data ( serial ) ;
2012-10-25 10:29:09 +02:00
usb_kill_urb ( serial_priv - > read_urb ) ;
2012-05-10 15:36:02 -04:00
}
2018-09-12 07:24:37 -04:00
static int get_serial_info ( struct tty_struct * tty ,
struct serial_struct * ss )
2012-05-10 15:36:02 -04:00
{
struct usb_serial_port * port = tty - > driver_data ;
2018-09-12 07:24:37 -04:00
ss - > line = port - > minor ;
ss - > port = 0 ;
ss - > irq = 0 ;
ss - > xmit_fifo_size = port - > bulk_out_size ;
ss - > baud_base = 9600 ;
ss - > close_delay = 5 * HZ ;
ss - > closing_wait = 30 * HZ ;
return 0 ;
2012-05-10 15:36:02 -04:00
}
static void qt2_process_status ( struct usb_serial_port * port , unsigned char * ch )
{
switch ( * ch ) {
case QT2_LINE_STATUS :
qt2_update_lsr ( port , ch + 1 ) ;
break ;
case QT2_MODEM_STATUS :
qt2_update_msr ( port , ch + 1 ) ;
break ;
}
}
2013-05-13 10:35:20 +05:30
static void qt2_process_read_urb ( struct urb * urb )
2012-05-10 15:36:02 -04:00
{
struct usb_serial * serial ;
struct qt2_serial_private * serial_priv ;
struct usb_serial_port * port ;
bool escapeflag ;
unsigned char * ch ;
int i ;
unsigned char newport ;
int len = urb - > actual_length ;
if ( ! len )
return ;
ch = urb - > transfer_buffer ;
serial = urb - > context ;
serial_priv = usb_get_serial_data ( serial ) ;
port = serial - > port [ serial_priv - > current_port ] ;
for ( i = 0 ; i < urb - > actual_length ; i + + ) {
ch = ( unsigned char * ) urb - > transfer_buffer + i ;
if ( ( i < = ( len - 3 ) ) & &
( * ch = = QT2_CONTROL_BYTE ) & &
( * ( ch + 1 ) = = QT2_CONTROL_BYTE ) ) {
escapeflag = false ;
switch ( * ( ch + 2 ) ) {
case QT2_LINE_STATUS :
case QT2_MODEM_STATUS :
if ( i > ( len - 4 ) ) {
dev_warn ( & port - > dev ,
" %s - status message too short \n " ,
__func__ ) ;
break ;
}
qt2_process_status ( port , ch + 2 ) ;
i + = 3 ;
escapeflag = true ;
break ;
case QT2_XMIT_HOLD :
if ( i > ( len - 5 ) ) {
dev_warn ( & port - > dev ,
" %s - xmit_empty message too short \n " ,
__func__ ) ;
break ;
}
2020-07-01 18:53:42 +02:00
/* bytes_written = (ch[1] << 4) + ch[0]; */
2012-05-10 15:36:02 -04:00
i + = 4 ;
escapeflag = true ;
break ;
case QT2_CHANGE_PORT :
if ( i > ( len - 4 ) ) {
dev_warn ( & port - > dev ,
" %s - change_port message too short \n " ,
__func__ ) ;
break ;
}
2013-03-21 16:07:57 -07:00
tty_flip_buffer_push ( & port - > port ) ;
2012-05-10 15:36:02 -04:00
newport = * ( ch + 3 ) ;
if ( newport > serial - > num_ports ) {
dev_err ( & port - > dev ,
" %s - port change to invalid port: %i \n " ,
__func__ , newport ) ;
break ;
}
serial_priv - > current_port = newport ;
port = serial - > port [ serial_priv - > current_port ] ;
i + = 3 ;
escapeflag = true ;
break ;
case QT2_REC_FLUSH :
case QT2_XMIT_FLUSH :
i + = 2 ;
escapeflag = true ;
break ;
case QT2_CONTROL_ESCAPE :
2013-01-03 15:53:04 +01:00
tty_insert_flip_string ( & port - > port , ch , 2 ) ;
2012-05-10 15:36:02 -04:00
i + = 2 ;
escapeflag = true ;
break ;
default :
dev_warn ( & port - > dev ,
" %s - unsupported command %i \n " ,
__func__ , * ( ch + 2 ) ) ;
break ;
}
if ( escapeflag )
continue ;
}
2017-04-03 11:58:55 +02:00
tty_insert_flip_char ( & port - > port , * ch , TTY_NORMAL ) ;
2012-05-10 15:36:02 -04:00
}
2013-03-21 16:07:57 -07:00
tty_flip_buffer_push ( & port - > port ) ;
2012-05-10 15:36:02 -04:00
}
static void qt2_write_bulk_callback ( struct urb * urb )
{
struct usb_serial_port * port ;
struct qt2_port_private * port_priv ;
2018-06-24 00:32:10 +02:00
unsigned long flags ;
2012-05-10 15:36:02 -04:00
port = urb - > context ;
port_priv = usb_get_serial_port_data ( port ) ;
2018-06-24 00:32:10 +02:00
spin_lock_irqsave ( & port_priv - > urb_lock , flags ) ;
2012-05-10 15:36:02 -04:00
port_priv - > urb_in_use = false ;
usb_serial_port_softint ( port ) ;
2018-06-24 00:32:10 +02:00
spin_unlock_irqrestore ( & port_priv - > urb_lock , flags ) ;
2012-05-10 15:36:02 -04:00
}
static void qt2_read_bulk_callback ( struct urb * urb )
{
struct usb_serial * serial = urb - > context ;
int status ;
if ( urb - > status ) {
dev_warn ( & serial - > dev - > dev ,
" %s - non-zero urb status: %i \n " , __func__ ,
urb - > status ) ;
return ;
}
qt2_process_read_urb ( urb ) ;
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ! = 0 )
dev_err ( & serial - > dev - > dev ,
" %s - resubmit read urb failed: %i \n " ,
__func__ , status ) ;
}
static int qt2_setup_urbs ( struct usb_serial * serial )
{
struct usb_serial_port * port0 ;
struct qt2_serial_private * serial_priv ;
2012-10-25 10:29:08 +02:00
int status ;
2012-05-10 15:36:02 -04:00
port0 = serial - > port [ 0 ] ;
serial_priv = usb_get_serial_data ( serial ) ;
serial_priv - > read_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2013-12-29 19:22:56 +01:00
if ( ! serial_priv - > read_urb )
2012-05-10 15:36:02 -04:00
return - ENOMEM ;
usb_fill_bulk_urb ( serial_priv - > read_urb , serial - > dev ,
usb_rcvbulkpipe ( serial - > dev ,
port0 - > bulk_in_endpointAddress ) ,
serial_priv - > read_buffer ,
2013-08-13 13:27:38 +02:00
QT2_READ_BUFFER_SIZE ,
2012-05-10 15:36:02 -04:00
qt2_read_bulk_callback , serial ) ;
status = usb_submit_urb ( serial_priv - > read_urb , GFP_KERNEL ) ;
if ( status ! = 0 ) {
dev_err ( & serial - > dev - > dev ,
" %s - submit read urb failed %i \n " , __func__ , status ) ;
2012-10-25 10:29:07 +02:00
usb_free_urb ( serial_priv - > read_urb ) ;
2012-05-10 15:36:02 -04:00
return status ;
}
return 0 ;
}
static int qt2_attach ( struct usb_serial * serial )
{
struct qt2_serial_private * serial_priv ;
2012-10-25 10:29:08 +02:00
int status ;
2012-05-10 15:36:02 -04:00
/* power on unit */
status = usb_control_msg ( serial - > dev , usb_rcvctrlpipe ( serial - > dev , 0 ) ,
0xc2 , 0x40 , 0x8000 , 0 , NULL , 0 ,
QT2_USB_TIMEOUT ) ;
if ( status < 0 ) {
dev_err ( & serial - > dev - > dev ,
" %s - failed to power on unit: %i \n " , __func__ , status ) ;
return status ;
}
serial_priv = kzalloc ( sizeof ( * serial_priv ) , GFP_KERNEL ) ;
2013-12-29 19:22:56 +01:00
if ( ! serial_priv )
2012-05-10 15:36:02 -04:00
return - ENOMEM ;
2013-08-13 13:27:38 +02:00
serial_priv - > read_buffer = kmalloc ( QT2_READ_BUFFER_SIZE , GFP_KERNEL ) ;
if ( ! serial_priv - > read_buffer ) {
status = - ENOMEM ;
goto err_buf ;
}
2012-05-10 15:36:02 -04:00
usb_set_serial_data ( serial , serial_priv ) ;
status = qt2_setup_urbs ( serial ) ;
if ( status ! = 0 )
goto attach_failed ;
return 0 ;
attach_failed :
2013-08-13 13:27:38 +02:00
kfree ( serial_priv - > read_buffer ) ;
err_buf :
2012-05-10 15:36:02 -04:00
kfree ( serial_priv ) ;
return status ;
}
2012-10-25 10:29:08 +02:00
static int qt2_port_probe ( struct usb_serial_port * port )
{
struct usb_serial * serial = port - > serial ;
struct qt2_port_private * port_priv ;
u8 bEndpointAddress ;
port_priv = kzalloc ( sizeof ( * port_priv ) , GFP_KERNEL ) ;
if ( ! port_priv )
return - ENOMEM ;
spin_lock_init ( & port_priv - > lock ) ;
spin_lock_init ( & port_priv - > urb_lock ) ;
port_priv - > port = port ;
2013-08-13 13:27:39 +02:00
port_priv - > write_buffer = kmalloc ( QT2_WRITE_BUFFER_SIZE , GFP_KERNEL ) ;
if ( ! port_priv - > write_buffer )
goto err_buf ;
2012-10-25 10:29:08 +02:00
port_priv - > write_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2013-08-13 13:27:39 +02:00
if ( ! port_priv - > write_urb )
goto err_urb ;
2012-10-25 10:29:08 +02:00
bEndpointAddress = serial - > port [ 0 ] - > bulk_out_endpointAddress ;
usb_fill_bulk_urb ( port_priv - > write_urb , serial - > dev ,
usb_sndbulkpipe ( serial - > dev , bEndpointAddress ) ,
port_priv - > write_buffer ,
2013-08-13 13:27:39 +02:00
QT2_WRITE_BUFFER_SIZE ,
2012-10-25 10:29:08 +02:00
qt2_write_bulk_callback , port ) ;
usb_set_serial_port_data ( port , port_priv ) ;
return 0 ;
2013-08-13 13:27:39 +02:00
err_urb :
kfree ( port_priv - > write_buffer ) ;
err_buf :
kfree ( port_priv ) ;
return - ENOMEM ;
2012-10-25 10:29:08 +02:00
}
static int qt2_port_remove ( struct usb_serial_port * port )
{
struct qt2_port_private * port_priv ;
port_priv = usb_get_serial_port_data ( port ) ;
usb_free_urb ( port_priv - > write_urb ) ;
2013-08-13 13:27:39 +02:00
kfree ( port_priv - > write_buffer ) ;
2012-10-25 10:29:08 +02:00
kfree ( port_priv ) ;
return 0 ;
}
2012-05-10 15:36:02 -04:00
static int qt2_tiocmget ( struct tty_struct * tty )
{
struct usb_serial_port * port = tty - > driver_data ;
struct usb_device * dev = port - > serial - > dev ;
struct qt2_port_private * port_priv = usb_get_serial_port_data ( port ) ;
u8 * d ;
int r ;
d = kzalloc ( 2 , GFP_KERNEL ) ;
if ( ! d )
return - ENOMEM ;
r = qt2_getregister ( dev , port_priv - > device_port , UART_MCR , d ) ;
if ( r < 0 )
goto mget_out ;
r = qt2_getregister ( dev , port_priv - > device_port , UART_MSR , d + 1 ) ;
if ( r < 0 )
goto mget_out ;
r = ( d [ 0 ] & UART_MCR_DTR ? TIOCM_DTR : 0 ) |
( d [ 0 ] & UART_MCR_RTS ? TIOCM_RTS : 0 ) |
( d [ 1 ] & UART_MSR_CTS ? TIOCM_CTS : 0 ) |
( d [ 1 ] & UART_MSR_DCD ? TIOCM_CAR : 0 ) |
( d [ 1 ] & UART_MSR_RI ? TIOCM_RI : 0 ) |
( d [ 1 ] & UART_MSR_DSR ? TIOCM_DSR : 0 ) ;
mget_out :
kfree ( d ) ;
return r ;
}
static int qt2_tiocmset ( struct tty_struct * tty ,
unsigned int set , unsigned int clear )
{
struct qt2_port_private * port_priv ;
port_priv = usb_get_serial_port_data ( tty - > driver_data ) ;
return update_mctrl ( port_priv , set , clear ) ;
}
static void qt2_break_ctl ( struct tty_struct * tty , int break_state )
{
struct usb_serial_port * port = tty - > driver_data ;
struct qt2_port_private * port_priv ;
int status ;
u16 val ;
port_priv = usb_get_serial_port_data ( port ) ;
val = ( break_state = = - 1 ) ? 1 : 0 ;
status = qt2_control_msg ( port - > serial - > dev , QT2_BREAK_CONTROL ,
val , port_priv - > device_port ) ;
if ( status < 0 )
dev_warn ( & port - > dev ,
" %s - failed to send control message: %i \n " , __func__ ,
status ) ;
}
static void qt2_dtr_rts ( struct usb_serial_port * port , int on )
{
struct usb_device * dev = port - > serial - > dev ;
struct qt2_port_private * port_priv = usb_get_serial_port_data ( port ) ;
2013-02-13 17:53:28 +01:00
/* Disable flow control */
if ( ! on ) {
if ( qt2_setregister ( dev , port_priv - > device_port ,
2012-05-10 15:36:02 -04:00
UART_MCR , 0 ) < 0 )
dev_warn ( & port - > dev , " error from flowcontrol urb \n " ) ;
}
2013-02-13 17:53:28 +01:00
/* drop RTS and DTR */
if ( on )
update_mctrl ( port_priv , TIOCM_DTR | TIOCM_RTS , 0 ) ;
else
update_mctrl ( port_priv , 0 , TIOCM_DTR | TIOCM_RTS ) ;
2012-05-10 15:36:02 -04:00
}
static void qt2_update_msr ( struct usb_serial_port * port , unsigned char * ch )
{
struct qt2_port_private * port_priv ;
u8 newMSR = ( u8 ) * ch ;
unsigned long flags ;
2020-01-17 15:35:26 +01:00
/* May be called from qt2_process_read_urb() for an unbound port. */
2012-05-10 15:36:02 -04:00
port_priv = usb_get_serial_port_data ( port ) ;
2020-01-17 15:35:26 +01:00
if ( ! port_priv )
return ;
2012-05-10 15:36:02 -04:00
spin_lock_irqsave ( & port_priv - > lock , flags ) ;
port_priv - > shadowMSR = newMSR ;
spin_unlock_irqrestore ( & port_priv - > lock , flags ) ;
if ( newMSR & UART_MSR_ANY_DELTA ) {
/* update input line counters */
if ( newMSR & UART_MSR_DCTS )
2013-03-21 12:37:22 +01:00
port - > icount . cts + + ;
2012-05-10 15:36:02 -04:00
if ( newMSR & UART_MSR_DDSR )
2013-03-21 12:37:22 +01:00
port - > icount . dsr + + ;
2012-05-10 15:36:02 -04:00
if ( newMSR & UART_MSR_DDCD )
2013-03-21 12:37:22 +01:00
port - > icount . dcd + + ;
2012-05-10 15:36:02 -04:00
if ( newMSR & UART_MSR_TERI )
2013-03-21 12:37:22 +01:00
port - > icount . rng + + ;
2012-05-10 15:36:02 -04:00
2013-03-21 12:37:23 +01:00
wake_up_interruptible ( & port - > port . delta_msr_wait ) ;
2012-05-10 15:36:02 -04:00
}
}
static void qt2_update_lsr ( struct usb_serial_port * port , unsigned char * ch )
{
struct qt2_port_private * port_priv ;
struct async_icount * icount ;
unsigned long flags ;
u8 newLSR = ( u8 ) * ch ;
2020-01-17 15:35:26 +01:00
/* May be called from qt2_process_read_urb() for an unbound port. */
2012-05-10 15:36:02 -04:00
port_priv = usb_get_serial_port_data ( port ) ;
2020-01-17 15:35:26 +01:00
if ( ! port_priv )
return ;
2012-05-10 15:36:02 -04:00
if ( newLSR & UART_LSR_BI )
newLSR & = ( u8 ) ( UART_LSR_OE | UART_LSR_BI ) ;
spin_lock_irqsave ( & port_priv - > lock , flags ) ;
port_priv - > shadowLSR = newLSR ;
spin_unlock_irqrestore ( & port_priv - > lock , flags ) ;
2013-03-21 12:37:22 +01:00
icount = & port - > icount ;
2012-05-10 15:36:02 -04:00
if ( newLSR & UART_LSR_BRK_ERROR_BITS ) {
if ( newLSR & UART_LSR_BI )
icount - > brk + + ;
if ( newLSR & UART_LSR_OE )
icount - > overrun + + ;
if ( newLSR & UART_LSR_PE )
icount - > parity + + ;
if ( newLSR & UART_LSR_FE )
icount - > frame + + ;
}
}
static int qt2_write_room ( struct tty_struct * tty )
{
struct usb_serial_port * port = tty - > driver_data ;
struct qt2_port_private * port_priv ;
unsigned long flags = 0 ;
int r ;
port_priv = usb_get_serial_port_data ( port ) ;
spin_lock_irqsave ( & port_priv - > urb_lock , flags ) ;
if ( port_priv - > urb_in_use )
r = 0 ;
else
r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE ;
spin_unlock_irqrestore ( & port_priv - > urb_lock , flags ) ;
return r ;
}
static int qt2_write ( struct tty_struct * tty ,
struct usb_serial_port * port ,
const unsigned char * buf , int count )
{
struct qt2_port_private * port_priv ;
struct urb * write_urb ;
unsigned char * data ;
unsigned long flags ;
int status ;
int bytes_out = 0 ;
port_priv = usb_get_serial_port_data ( port ) ;
if ( port_priv - > write_urb = = NULL ) {
dev_err ( & port - > dev , " %s - no output urb \n " , __func__ ) ;
return 0 ;
}
write_urb = port_priv - > write_urb ;
count = min ( count , QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE ) ;
data = write_urb - > transfer_buffer ;
spin_lock_irqsave ( & port_priv - > urb_lock , flags ) ;
2016-02-04 19:01:29 +01:00
if ( port_priv - > urb_in_use ) {
2012-09-18 17:05:37 +01:00
dev_err ( & port - > dev , " qt2_write - urb is in use \n " ) ;
2012-05-10 15:36:02 -04:00
goto write_out ;
}
* data + + = QT2_CONTROL_BYTE ;
* data + + = QT2_CONTROL_BYTE ;
* data + + = port_priv - > device_port ;
put_unaligned_le16 ( count , data ) ;
data + = 2 ;
memcpy ( data , buf , count ) ;
write_urb - > transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE ;
status = usb_submit_urb ( write_urb , GFP_ATOMIC ) ;
if ( status = = 0 ) {
port_priv - > urb_in_use = true ;
bytes_out + = count ;
}
write_out :
spin_unlock_irqrestore ( & port_priv - > urb_lock , flags ) ;
return bytes_out ;
}
static struct usb_serial_driver qt2_device = {
. driver = {
. owner = THIS_MODULE ,
. name = " quatech-serial " ,
} ,
. description = DRIVER_DESC ,
. id_table = id_table ,
. open = qt2_open ,
. close = qt2_close ,
. write = qt2_write ,
. write_room = qt2_write_room ,
. calc_num_ports = qt2_calc_num_ports ,
. attach = qt2_attach ,
. release = qt2_release ,
. disconnect = qt2_disconnect ,
2012-10-25 10:29:08 +02:00
. port_probe = qt2_port_probe ,
. port_remove = qt2_port_remove ,
2012-05-10 15:36:02 -04:00
. dtr_rts = qt2_dtr_rts ,
. break_ctl = qt2_break_ctl ,
. tiocmget = qt2_tiocmget ,
. tiocmset = qt2_tiocmset ,
2013-03-21 12:37:23 +01:00
. tiocmiwait = usb_serial_generic_tiocmiwait ,
2013-03-21 12:37:22 +01:00
. get_icount = usb_serial_generic_get_icount ,
2018-09-12 07:24:37 -04:00
. get_serial = get_serial_info ,
2012-05-10 15:36:02 -04:00
. set_termios = qt2_set_termios ,
} ;
static struct usb_serial_driver * const serial_drivers [ ] = {
& qt2_device , NULL
} ;
module_usb_serial_driver ( serial_drivers , id_table ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2017-11-03 18:12:08 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;