2005-04-17 02:20:36 +04:00
/*
* KOBIL USB Smart Card Terminal Driver
*
2008-07-22 14:14:10 +04:00
* Copyright ( C ) 2002 KOBIL Systems GmbH
2005-04-17 02:20:36 +04:00
* Author : Thomas Wahrenbruch
*
* Contact : linuxusb @ kobil . de
*
* 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 .
*
* 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 .
*
* Thanks to Greg Kroah - Hartman ( greg @ kroah . com ) for his help and
* patience .
*
* Supported readers : USB TWIN , KAAN Standard Plus and SecOVID Reader Plus
* ( Adapter K ) , B1 Professional and KAAN Professional ( Adapter B )
*/
# 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 14:14:10 +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 <linux/ioctl.h>
# include "kobil_sct.h"
# define DRIVER_AUTHOR "KOBIL Systems GmbH - http: //www.kobil.com"
# define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
# define KOBIL_VENDOR_ID 0x0D46
# define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011
# define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012
# define KOBIL_USBTWIN_PRODUCT_ID 0x0078
# define KOBIL_KAAN_SIM_PRODUCT_ID 0x0081
# define KOBIL_TIMEOUT 500
# define KOBIL_BUF_LENGTH 300
/* Function prototypes */
2012-10-17 15:35:02 +04:00
static int kobil_port_probe ( struct usb_serial_port * probe ) ;
static int kobil_port_remove ( struct usb_serial_port * probe ) ;
2009-09-20 00:13:26 +04:00
static int kobil_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void kobil_close ( struct usb_serial_port * port ) ;
2008-07-22 14:14:10 +04:00
static int kobil_write ( struct tty_struct * tty , struct usb_serial_port * port ,
2005-04-17 02:20:36 +04:00
const unsigned char * buf , int count ) ;
2008-07-22 14:09:07 +04:00
static int kobil_write_room ( struct tty_struct * tty ) ;
2011-02-14 19:27:06 +03:00
static int kobil_ioctl ( struct tty_struct * tty ,
2005-04-17 02:20:36 +04:00
unsigned int cmd , unsigned long arg ) ;
2011-02-14 19:26:14 +03:00
static int kobil_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 19:26:50 +03:00
static int kobil_tiocmset ( struct tty_struct * tty ,
2005-04-17 02:20:36 +04:00
unsigned int set , unsigned int clear ) ;
2008-07-22 14:14:10 +04:00
static void kobil_read_int_callback ( struct urb * urb ) ;
2013-04-16 20:01:26 +04:00
static void kobil_write_int_callback ( struct urb * urb ) ;
2008-07-22 14:14:10 +04:00
static void kobil_set_termios ( struct tty_struct * tty ,
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port , struct ktermios * old ) ;
2009-09-20 00:13:33 +04:00
static void kobil_init_termios ( struct tty_struct * tty ) ;
2005-04-17 02:20:36 +04:00
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 ( KOBIL_VENDOR_ID , KOBIL_ADAPTER_B_PRODUCT_ID ) } ,
{ USB_DEVICE ( KOBIL_VENDOR_ID , KOBIL_ADAPTER_K_PRODUCT_ID ) } ,
{ USB_DEVICE ( KOBIL_VENDOR_ID , KOBIL_USBTWIN_PRODUCT_ID ) } ,
{ USB_DEVICE ( KOBIL_VENDOR_ID , KOBIL_KAAN_SIM_PRODUCT_ID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 14:14:10 +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 kobil_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " kobil " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " KOBIL USB smart card terminal " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
. num_ports = 1 ,
2012-10-17 15:35:02 +04:00
. port_probe = kobil_port_probe ,
. port_remove = kobil_port_remove ,
2005-04-17 02:20:36 +04:00
. ioctl = kobil_ioctl ,
2007-08-23 02:09:16 +04:00
. set_termios = kobil_set_termios ,
2009-09-20 00:13:33 +04:00
. init_termios = kobil_init_termios ,
2005-04-17 02:20:36 +04:00
. tiocmget = kobil_tiocmget ,
. tiocmset = kobil_tiocmset ,
. open = kobil_open ,
. close = kobil_close ,
. write = kobil_write ,
. write_room = kobil_write_room ,
. read_int_callback = kobil_read_int_callback ,
2013-04-16 20:01:26 +04:00
. write_int_callback = kobil_write_int_callback ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-23 23:57:09 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& kobil_device , NULL
} ;
2005-04-17 02:20:36 +04:00
struct kobil_private {
2008-07-22 14:14:10 +04:00
unsigned char buf [ KOBIL_BUF_LENGTH ] ; /* buffer for the APDU to send */
int filled ; /* index of the last char in buf */
int cur_pos ; /* index of the next char to send in buf */
2005-04-17 02:20:36 +04:00
__u16 device_type ;
} ;
2012-10-17 15:35:02 +04:00
static int kobil_port_probe ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2012-10-17 15:35:02 +04:00
struct usb_serial * serial = port - > serial ;
2005-04-17 02:20:36 +04:00
struct kobil_private * priv ;
priv = kmalloc ( sizeof ( struct kobil_private ) , GFP_KERNEL ) ;
2008-07-22 14:14:10 +04:00
if ( ! priv )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
priv - > filled = 0 ;
priv - > cur_pos = 0 ;
priv - > device_type = le16_to_cpu ( serial - > dev - > descriptor . idProduct ) ;
2008-07-22 14:14:10 +04:00
switch ( priv - > device_type ) {
2005-04-17 02:20:36 +04:00
case KOBIL_ADAPTER_B_PRODUCT_ID :
2012-09-18 20:03:31 +04:00
dev_dbg ( & serial - > dev - > dev , " KOBIL B1 PRO / KAAN PRO detected \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case KOBIL_ADAPTER_K_PRODUCT_ID :
2012-09-18 20:03:31 +04:00
dev_dbg ( & serial - > dev - > dev , " KOBIL KAAN Standard Plus / SecOVID Reader Plus detected \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case KOBIL_USBTWIN_PRODUCT_ID :
2012-09-18 20:03:31 +04:00
dev_dbg ( & serial - > dev - > dev , " KOBIL USBTWIN detected \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case KOBIL_KAAN_SIM_PRODUCT_ID :
2012-09-18 20:03:31 +04:00
dev_dbg ( & serial - > dev - > dev , " KOBIL KAAN SIM detected \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2012-10-17 15:35:02 +04:00
usb_set_serial_port_data ( port , priv ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-10-17 15:35:02 +04:00
static int kobil_port_remove ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2012-10-17 15:35:02 +04:00
struct kobil_private * priv ;
2005-04-17 02:20:36 +04:00
2012-10-17 15:35:02 +04:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-09-20 00:13:33 +04:00
static void kobil_init_termios ( struct tty_struct * tty )
{
/* Default to echo off and other sane device settings */
2012-07-14 18:31:47 +04:00
tty - > termios . c_lflag = 0 ;
2012-07-14 18:32:50 +04:00
tty - > termios . c_iflag & = ~ ( ISIG | ICANON | ECHO | IEXTEN | XCASE ) ;
tty - > termios . c_iflag | = IGNBRK | IGNPAR | IXOFF ;
2009-09-20 00:13:33 +04:00
/* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
2012-07-14 18:31:47 +04:00
tty - > termios . c_oflag & = ~ ONLCR ;
2009-09-20 00:13:33 +04:00
}
2005-04-17 02:20:36 +04:00
2009-09-20 00:13:26 +04:00
static int kobil_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2012-09-14 23:06:55 +04:00
struct device * dev = & port - > dev ;
2007-08-23 02:09:16 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
struct kobil_private * priv ;
unsigned char * transfer_buffer ;
int transfer_buffer_length = 8 ;
priv = usb_get_serial_port_data ( port ) ;
2008-07-22 14:14:10 +04:00
/* allocate memory for transfer buffer */
2006-02-27 23:29:43 +03:00
transfer_buffer = kzalloc ( transfer_buffer_length , GFP_KERNEL ) ;
2008-07-22 14:14:10 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2008-07-22 14:14:10 +04:00
/* get hardware version */
result = usb_control_msg ( port - > serial - > dev ,
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
SUSBCRequest_GetMisc ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN ,
SUSBCR_MSC_GetHWVersion ,
0 ,
transfer_buffer ,
transfer_buffer_length ,
KOBIL_TIMEOUT
) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send get_HW_version URB returns: %i \n " , __func__ , result ) ;
2014-01-07 16:58:06 +04:00
dev_dbg ( dev , " Hardware version: %i.%i.%i \n " , transfer_buffer [ 0 ] ,
2012-09-14 23:06:55 +04:00
transfer_buffer [ 1 ] , transfer_buffer [ 2 ] ) ;
2008-07-22 14:14:10 +04:00
/* get firmware version */
result = usb_control_msg ( port - > serial - > dev ,
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
SUSBCRequest_GetMisc ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN ,
SUSBCR_MSC_GetFWVersion ,
0 ,
transfer_buffer ,
transfer_buffer_length ,
KOBIL_TIMEOUT
) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send get_FW_version URB returns: %i \n " , __func__ , result ) ;
dev_dbg ( dev , " Firmware version: %i.%i.%i \n " , transfer_buffer [ 0 ] ,
transfer_buffer [ 1 ] , transfer_buffer [ 2 ] ) ;
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID | |
priv - > device_type = = KOBIL_ADAPTER_K_PRODUCT_ID ) {
/* Setting Baudrate, Parity and Stopbits */
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_SetBaudRateParityAndStopBits ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity |
SUSBCR_SPASB_1StopBit ,
0 ,
2014-05-26 21:23:35 +04:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT
2005-04-17 02:20:36 +04:00
) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send set_baudrate URB returns: %i \n " , __func__ , result ) ;
2008-07-22 14:14:10 +04:00
/* reset all queues */
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_Misc ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
SUSBCR_MSC_ResetAllQueues ,
0 ,
2014-05-26 21:23:35 +04:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT
2005-04-17 02:20:36 +04:00
) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send reset_all_queues URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_USBTWIN_PRODUCT_ID | |
priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID | |
2005-04-17 02:20:36 +04:00
priv - > device_type = = KOBIL_KAAN_SIM_PRODUCT_ID ) {
2008-07-22 14:14:10 +04:00
/* start reading (Adapter B 'cause PNP string) */
2014-10-29 11:07:32 +03:00
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send read URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
kfree ( transfer_buffer ) ;
return 0 ;
}
2009-06-11 15:26:29 +04:00
static void kobil_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2009-06-11 15:26:29 +04:00
/* FIXME: Add rts/dtr methods */
2013-04-16 20:01:26 +04:00
usb_kill_urb ( port - > interrupt_out_urb ) ;
2006-11-08 17:36:38 +03:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-16 02:44:13 +04:00
static void kobil_read_int_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
int result ;
2007-06-16 02:44:13 +04:00
struct usb_serial_port * port = urb - > context ;
unsigned char * data = urb - > transfer_buffer ;
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Read int status not zero: %d \n " , __func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-06-16 02:44:13 +04:00
2013-01-03 18:53:06 +04:00
if ( urb - > actual_length ) {
2013-04-16 20:01:24 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length ,
data ) ;
2013-01-03 18:53:04 +04:00
tty_insert_flip_string ( & port - > port , data , urb - > actual_length ) ;
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > port ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-16 02:44:13 +04:00
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_ATOMIC ) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Send read URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2013-04-16 20:01:26 +04:00
static void kobil_write_int_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
}
2008-07-22 14:14:10 +04:00
static int kobil_write ( struct tty_struct * tty , struct usb_serial_port * port ,
2005-04-17 02:20:36 +04:00
const unsigned char * buf , int count )
{
int length = 0 ;
int result = 0 ;
int todo = 0 ;
2008-07-22 14:14:10 +04:00
struct kobil_private * priv ;
2005-04-17 02:20:36 +04:00
if ( count = = 0 ) {
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - write request of 0 bytes \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
priv = usb_get_serial_port_data ( port ) ;
if ( count > ( KOBIL_BUF_LENGTH - priv - > filled ) ) {
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Error: write request bigger than buffer size \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
2008-07-22 14:14:10 +04:00
/* Copy data to buffer */
memcpy ( priv - > buf + priv - > filled , buf , count ) ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , count , priv - > buf + priv - > filled ) ;
2005-04-17 02:20:36 +04:00
priv - > filled = priv - > filled + count ;
2008-07-22 14:14:10 +04:00
/* only send complete block. TWIN, KAAN SIM and adapter K
use the same protocol . */
if ( ( ( priv - > device_type ! = KOBIL_ADAPTER_B_PRODUCT_ID ) & & ( priv - > filled > 2 ) & & ( priv - > filled > = ( priv - > buf [ 1 ] + 3 ) ) ) | |
( ( priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID ) & & ( priv - > filled > 3 ) & & ( priv - > filled > = ( priv - > buf [ 2 ] + 4 ) ) ) ) {
/* stop reading (except TWIN and KAAN SIM) */
if ( ( priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID )
| | ( priv - > device_type = = KOBIL_ADAPTER_K_PRODUCT_ID ) )
2005-04-17 02:20:36 +04:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
todo = priv - > filled - priv - > cur_pos ;
2008-07-22 14:14:10 +04:00
while ( todo > 0 ) {
/* max 8 byte in one urb (endpoint size) */
2013-04-16 20:01:26 +04:00
length = min ( todo , port - > interrupt_out_size ) ;
2008-07-22 14:14:10 +04:00
/* copy data to transfer buffer */
2013-04-16 20:01:26 +04:00
memcpy ( port - > interrupt_out_buffer ,
2008-07-22 14:14:10 +04:00
priv - > buf + priv - > cur_pos , length ) ;
2013-04-16 20:01:26 +04:00
port - > interrupt_out_urb - > transfer_buffer_length = length ;
2005-04-17 02:20:36 +04:00
priv - > cur_pos = priv - > cur_pos + length ;
2014-10-29 11:07:30 +03:00
result = usb_submit_urb ( port - > interrupt_out_urb ,
GFP_ATOMIC ) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Send write URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
todo = priv - > filled - priv - > cur_pos ;
2008-07-22 14:14:10 +04:00
if ( todo > 0 )
2005-04-17 02:20:36 +04:00
msleep ( 24 ) ;
2008-07-22 14:14:10 +04:00
}
2005-04-17 02:20:36 +04:00
priv - > filled = 0 ;
priv - > cur_pos = 0 ;
2008-07-22 14:14:10 +04:00
/* start reading (except TWIN and KAAN SIM) */
if ( priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID | |
priv - > device_type = = KOBIL_ADAPTER_K_PRODUCT_ID ) {
result = usb_submit_urb ( port - > interrupt_in_urb ,
2014-10-29 11:07:30 +03:00
GFP_ATOMIC ) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Send read URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
}
return count ;
}
2008-07-22 14:14:10 +04:00
static int kobil_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
/* FIXME */
2005-04-17 02:20:36 +04:00
return 8 ;
}
2011-02-14 19:26:14 +03:00
static int kobil_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 ;
2008-07-22 14:14:10 +04:00
struct kobil_private * priv ;
2005-04-17 02:20:36 +04:00
int result ;
unsigned char * transfer_buffer ;
int transfer_buffer_length = 8 ;
priv = usb_get_serial_port_data ( port ) ;
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_USBTWIN_PRODUCT_ID
| | priv - > device_type = = KOBIL_KAAN_SIM_PRODUCT_ID ) {
/* This device doesn't support ioctl calls */
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2008-07-22 14:14:10 +04:00
/* allocate memory for transfer buffer */
2006-02-27 23:29:43 +03:00
transfer_buffer = kzalloc ( transfer_buffer_length , GFP_KERNEL ) ;
2008-07-22 14:14:10 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2008-07-22 14:14:10 +04:00
result = usb_control_msg ( port - > serial - > dev ,
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
SUSBCRequest_GetStatusLineState ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN ,
0 ,
0 ,
transfer_buffer ,
transfer_buffer_length ,
KOBIL_TIMEOUT ) ;
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev , " %s - Send get_status_line_state URB returns: %i. Statusline: %02x \n " ,
__func__ , result , transfer_buffer [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
2008-02-21 00:40:34 +03:00
result = 0 ;
if ( ( transfer_buffer [ 0 ] & SUSBCR_GSL_DSR ) ! = 0 )
result = TIOCM_DSR ;
2005-04-17 02:20:36 +04:00
kfree ( transfer_buffer ) ;
2008-02-21 00:40:34 +03:00
return result ;
2005-04-17 02:20:36 +04:00
}
2011-02-14 19:26:50 +03:00
static int kobil_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 ;
2012-09-14 23:06:55 +04:00
struct device * dev = & port - > dev ;
2008-07-22 14:14:10 +04:00
struct kobil_private * priv ;
2005-04-17 02:20:36 +04:00
int result ;
int dtr = 0 ;
int rts = 0 ;
2008-02-21 00:40:34 +03:00
/* FIXME: locking ? */
2005-04-17 02:20:36 +04:00
priv = usb_get_serial_port_data ( port ) ;
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_USBTWIN_PRODUCT_ID
| | priv - > device_type = = KOBIL_KAAN_SIM_PRODUCT_ID ) {
/* This device doesn't support ioctl calls */
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( set & TIOCM_RTS )
rts = 1 ;
if ( set & TIOCM_DTR )
dtr = 1 ;
if ( clear & TIOCM_RTS )
rts = 0 ;
if ( clear & TIOCM_DTR )
dtr = 0 ;
if ( priv - > device_type = = KOBIL_ADAPTER_B_PRODUCT_ID ) {
if ( dtr ! = 0 )
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Setting DTR \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
else
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Clearing DTR \n " , __func__ ) ;
2008-07-22 14:14:10 +04:00
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_SetStatusLinesOrQueues ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
( ( dtr ! = 0 ) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR ) ,
0 ,
2014-05-26 21:23:35 +04:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT ) ;
2005-04-17 02:20:36 +04:00
} else {
if ( rts ! = 0 )
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Setting RTS \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
else
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Clearing RTS \n " , __func__ ) ;
2008-07-22 14:14:10 +04:00
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_SetStatusLinesOrQueues ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
( ( rts ! = 0 ) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS ) ,
0 ,
2014-05-26 21:23:35 +04:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT ) ;
2005-04-17 02:20:36 +04:00
}
2012-09-14 23:06:55 +04:00
dev_dbg ( dev , " %s - Send set_status_line URB returns: %i \n " , __func__ , result ) ;
2005-04-17 02:20:36 +04:00
return ( result < 0 ) ? result : 0 ;
}
2008-07-22 14:09:07 +04:00
static void kobil_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:14:10 +04:00
struct kobil_private * priv ;
2005-04-17 02:20:36 +04:00
int result ;
unsigned short urb_val = 0 ;
2012-07-14 18:31:47 +04:00
int c_cflag = tty - > termios . c_cflag ;
2007-08-23 02:09:16 +04:00
speed_t speed ;
2005-04-17 02:20:36 +04:00
priv = usb_get_serial_port_data ( port ) ;
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_USBTWIN_PRODUCT_ID | |
2008-07-22 14:14:22 +04:00
priv - > device_type = = KOBIL_KAAN_SIM_PRODUCT_ID ) {
2008-07-22 14:14:10 +04:00
/* This device doesn't support ioctl calls */
2012-07-14 18:32:50 +04:00
tty_termios_copy_hw ( & tty - > termios , old ) ;
2007-08-23 02:09:16 +04:00
return ;
2008-07-22 14:14:22 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:14:10 +04:00
speed = tty_get_baud_rate ( tty ) ;
switch ( speed ) {
case 1200 :
urb_val = SUSBCR_SBR_1200 ;
break ;
default :
speed = 9600 ;
case 9600 :
urb_val = SUSBCR_SBR_9600 ;
break ;
2007-08-23 02:09:16 +04:00
}
2008-07-22 14:14:10 +04:00
urb_val | = ( c_cflag & CSTOPB ) ? SUSBCR_SPASB_2StopBits :
SUSBCR_SPASB_1StopBit ;
2007-08-23 02:09:16 +04:00
if ( c_cflag & PARENB ) {
2009-12-29 01:01:58 +03:00
if ( c_cflag & PARODD )
2007-08-23 02:09:16 +04:00
urb_val | = SUSBCR_SPASB_OddParity ;
2009-12-29 01:01:58 +03:00
else
2007-08-23 02:09:16 +04:00
urb_val | = SUSBCR_SPASB_EvenParity ;
2009-12-29 01:01:58 +03:00
} else
2007-08-23 02:09:16 +04:00
urb_val | = SUSBCR_SPASB_NoParity ;
2012-07-14 18:31:47 +04:00
tty - > termios . c_cflag & = ~ CMSPAR ;
2008-07-22 14:09:07 +04:00
tty_encode_baud_rate ( tty , speed , speed ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:14:10 +04:00
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_SetBaudRateParityAndStopBits ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
urb_val ,
0 ,
2009-12-29 01:01:58 +03:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT
2007-08-23 02:09:16 +04:00
) ;
}
2005-04-17 02:20:36 +04:00
2011-02-14 19:27:06 +03:00
static int kobil_ioctl ( struct tty_struct * tty ,
2008-07-22 14:14:10 +04:00
unsigned int cmd , unsigned long arg )
2007-08-23 02:09:16 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2008-07-22 14:14:10 +04:00
struct kobil_private * priv = usb_get_serial_port_data ( port ) ;
2007-08-23 02:09:16 +04:00
int result ;
2008-07-22 14:14:10 +04:00
if ( priv - > device_type = = KOBIL_USBTWIN_PRODUCT_ID | |
priv - > device_type = = KOBIL_KAAN_SIM_PRODUCT_ID )
/* This device doesn't support ioctl calls */
2008-07-22 14:14:22 +04:00
return - ENOIOCTLCMD ;
2005-04-17 02:20:36 +04:00
2007-08-23 02:09:16 +04:00
switch ( cmd ) {
2008-07-22 14:09:07 +04:00
case TCFLSH :
2008-07-22 14:14:10 +04:00
result = usb_control_msg ( port - > serial - > dev ,
2014-05-26 21:23:35 +04:00
usb_sndctrlpipe ( port - > serial - > dev , 0 ) ,
2008-07-22 14:14:10 +04:00
SUSBCRequest_Misc ,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
SUSBCR_MSC_ResetAllQueues ,
0 ,
2014-05-26 21:23:35 +04:00
NULL ,
2008-07-22 14:14:10 +04:00
0 ,
KOBIL_TIMEOUT
2005-04-17 02:20:36 +04:00
) ;
2008-07-22 14:14:10 +04:00
2012-09-14 23:06:55 +04:00
dev_dbg ( & port - > dev ,
2014-03-12 22:09:42 +04:00
" %s - Send reset_all_queues (FLUSH) URB returns: %i \n " ,
__func__ , result ) ;
2008-07-22 14:09:07 +04:00
return ( result < 0 ) ? - EIO : 0 ;
2007-08-23 02:09:16 +04:00
default :
return - ENOIOCTLCMD ;
2005-04-17 02:20:36 +04:00
}
}
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:10 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;