2005-04-16 15:20:36 -07:00
/*
* REINER SCT cyberJack pinpad / e - com USB Chipcard Reader Driver
*
* Copyright ( C ) 2001 REINER SCT
* Author : Matthias Bruestle
*
* Contact : support @ reiner - sct . com ( see MAINTAINERS )
*
* 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 .
*
* In case of problems , please write to the contact e - mail address
* mentioned above .
*
* Please note that later models of the cyberjack reader family are
* supported by a libusb - based userspace device driver .
*
* Homepage : http : //www.reiner-sct.de/support/treiber_cyberjack.php#linux
*/
# 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:10:27 +01:00
# include <linux/uaccess.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>
2005-04-16 15:20:36 -07:00
# define CYBERJACK_LOCAL_BUF_SIZE 32
# define DRIVER_AUTHOR "Matthias Bruestle"
# define DRIVER_DESC "REINER SCT cyberJack pinpad / e-com USB Chipcard Reader Driver"
# define CYBERJACK_VENDOR_ID 0x0C4B
# define CYBERJACK_PRODUCT_ID 0x0100
/* Function prototypes */
2012-10-15 18:20:54 +02:00
static int cyberjack_port_probe ( struct usb_serial_port * port ) ;
static int cyberjack_port_remove ( struct usb_serial_port * port ) ;
2008-07-22 11:09:07 +01:00
static int cyberjack_open ( struct tty_struct * tty ,
2009-09-19 13:13:26 -07:00
struct usb_serial_port * port ) ;
2009-06-11 12:26:29 +01:00
static void cyberjack_close ( struct usb_serial_port * port ) ;
2008-07-22 11:09:07 +01:00
static int cyberjack_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count ) ;
2008-07-22 11:10:27 +01:00
static int cyberjack_write_room ( struct tty_struct * tty ) ;
2008-07-22 11:09:07 +01:00
static void cyberjack_read_int_callback ( struct urb * urb ) ;
static void cyberjack_read_bulk_callback ( struct urb * urb ) ;
static void cyberjack_write_bulk_callback ( struct urb * urb ) ;
2005-04-16 15:20:36 -07:00
2010-01-10 15:34:24 +01:00
static const struct usb_device_id id_table [ ] = {
2005-04-16 15:20:36 -07:00
{ USB_DEVICE ( CYBERJACK_VENDOR_ID , CYBERJACK_PRODUCT_ID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 11:10:27 +01: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 cyberjack_device = {
2005-06-20 21:15:16 -07:00
. driver = {
. owner = THIS_MODULE ,
2005-06-20 21:15:16 -07:00
. name = " cyberjack " ,
2005-06-20 21:15:16 -07:00
} ,
2005-06-20 21:15:16 -07:00
. description = " Reiner SCT Cyberjack USB card reader " ,
2005-04-16 15:20:36 -07:00
. id_table = id_table ,
. num_ports = 1 ,
2012-10-15 18:20:54 +02:00
. port_probe = cyberjack_port_probe ,
. port_remove = cyberjack_port_remove ,
2005-04-16 15:20:36 -07:00
. open = cyberjack_open ,
. close = cyberjack_close ,
. write = cyberjack_write ,
2006-12-17 21:50:24 +01:00
. write_room = cyberjack_write_room ,
2005-04-16 15:20:36 -07:00
. read_int_callback = cyberjack_read_int_callback ,
. read_bulk_callback = cyberjack_read_bulk_callback ,
. write_bulk_callback = cyberjack_write_bulk_callback ,
} ;
2012-02-23 14:56:17 -05:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& cyberjack_device , NULL
} ;
2005-04-16 15:20:36 -07:00
struct cyberjack_private {
spinlock_t lock ; /* Lock for SMP */
short rdtodo ; /* Bytes still to read */
unsigned char wrbuf [ 5 * 64 ] ; /* Buffer for collecting data to write */
short wrfilled ; /* Overall data size we already got */
short wrsent ; /* Data already sent */
} ;
2012-10-15 18:20:54 +02:00
static int cyberjack_port_probe ( struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
struct cyberjack_private * priv ;
2012-10-15 18:20:54 +02:00
int result ;
2005-04-16 15:20:36 -07:00
priv = kmalloc ( sizeof ( struct cyberjack_private ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
spin_lock_init ( & priv - > lock ) ;
priv - > rdtodo = 0 ;
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2012-10-15 18:20:54 +02:00
usb_set_serial_port_data ( port , priv ) ;
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
if ( result )
dev_err ( & port - > dev , " usb_submit_urb(read int) failed \n " ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:10:27 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2012-10-15 18:20:54 +02:00
static int cyberjack_port_remove ( struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
2012-10-15 18:20:54 +02:00
struct cyberjack_private * priv ;
2008-07-22 11:10:27 +01:00
2013-03-21 12:36:45 +01:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2012-10-15 18:20:54 +02:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
2009-06-02 11:53:55 -04:00
}
2008-07-22 11:09:07 +01:00
static int cyberjack_open ( struct tty_struct * tty ,
2009-09-19 13:13:26 -07:00
struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
struct cyberjack_private * priv ;
unsigned long flags ;
int result = 0 ;
2012-09-13 17:18:14 -07:00
dev_dbg ( & port - > dev , " %s - usb_clear_halt \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
usb_clear_halt ( port - > serial - > dev , port - > write_urb - > pipe ) ;
priv = usb_get_serial_port_data ( port ) ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > rdtodo = 0 ;
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return result ;
}
2009-06-11 12:26:29 +01:00
static void cyberjack_close ( struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
2013-03-21 12:36:29 +01:00
usb_kill_urb ( port - > write_urb ) ;
usb_kill_urb ( port - > read_urb ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-22 11:09:07 +01:00
static int cyberjack_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count )
2005-04-16 15:20:36 -07:00
{
2012-09-13 17:18:14 -07:00
struct device * dev = & port - > dev ;
2005-04-16 15:20:36 -07:00
struct cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
int result ;
int wrexpected ;
if ( count = = 0 ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - write request of 0 bytes \n " , __func__ ) ;
2008-04-08 17:16:06 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-11-06 19:06:23 +01:00
if ( ! test_and_clear_bit ( 0 , & port - > write_urbs_free ) ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - already writing \n " , __func__ ) ;
2005-04-23 12:49:16 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-07-22 11:10:27 +01:00
if ( count + priv - > wrfilled > sizeof ( priv - > wrbuf ) ) {
2005-04-16 15:20:36 -07:00
/* To much data for buffer. Reset buffer. */
2008-04-08 17:16:06 +01:00
priv - > wrfilled = 0 ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2011-11-06 19:06:23 +01:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2008-04-08 17:16:06 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
/* Copy data */
2008-07-22 11:10:27 +01:00
memcpy ( priv - > wrbuf + priv - > wrfilled , buf , count ) ;
2005-04-16 15:20:36 -07:00
2012-09-18 09:58:57 +01:00
usb_serial_debug_data ( dev , __func__ , count , priv - > wrbuf + priv - > wrfilled ) ;
2005-04-16 15:20:36 -07:00
priv - > wrfilled + = count ;
2008-07-22 11:10:27 +01:00
if ( priv - > wrfilled > = 3 ) {
2005-04-16 15:20:36 -07:00
wrexpected = ( ( int ) priv - > wrbuf [ 2 ] < < 8 ) + priv - > wrbuf [ 1 ] + 3 ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - expected data: %d \n " , __func__ , wrexpected ) ;
2008-07-22 11:10:27 +01:00
} else
2005-04-16 15:20:36 -07:00
wrexpected = sizeof ( priv - > wrbuf ) ;
2008-07-22 11:10:27 +01:00
if ( priv - > wrfilled > = wrexpected ) {
2005-04-16 15:20:36 -07:00
/* We have enough data to begin transmission */
int length ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - transmitting data (frame 1) \n " , __func__ ) ;
2008-07-22 11:10:27 +01:00
length = ( wrexpected > port - > bulk_out_size ) ?
port - > bulk_out_size : wrexpected ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:10:27 +01:00
memcpy ( port - > write_urb - > transfer_buffer , priv - > wrbuf , length ) ;
priv - > wrsent = length ;
2005-04-16 15:20:36 -07:00
/* set up our urb */
2011-11-06 19:06:30 +01:00
port - > write_urb - > transfer_buffer_length = length ;
2005-04-16 15:20:36 -07:00
/* send the data out the bulk port */
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
if ( result ) {
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev ,
2014-03-12 19:09:42 +01:00
" %s - failed submitting write urb, error %d \n " ,
2008-08-20 16:56:34 -07:00
__func__ , result ) ;
2005-04-16 15:20:36 -07:00
/* Throw away data. No better idea what to do with it. */
2008-04-08 17:16:06 +01:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2011-11-06 19:06:23 +01:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - priv->wrsent=%d \n " , __func__ , priv - > wrsent ) ;
dev_dbg ( dev , " %s - priv->wrfilled=%d \n " , __func__ , priv - > wrfilled ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:10:27 +01:00
if ( priv - > wrsent > = priv - > wrfilled ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - buffer cleaned \n " , __func__ ) ;
2008-07-22 11:10:27 +01:00
memset ( priv - > wrbuf , 0 , sizeof ( priv - > wrbuf ) ) ;
2008-04-08 17:16:06 +01:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-16 15:20:36 -07:00
}
}
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-07-22 11:10:27 +01:00
return count ;
}
2005-04-16 15:20:36 -07:00
2008-07-22 11:09:07 +01:00
static int cyberjack_write_room ( struct tty_struct * tty )
2005-04-16 15:20:36 -07:00
{
2008-04-08 17:16:06 +01:00
/* FIXME: .... */
2005-04-16 15:20:36 -07:00
return CYBERJACK_LOCAL_BUF_SIZE ;
}
2008-07-22 11:09:07 +01:00
static void cyberjack_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 cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-13 17:18:14 -07:00
struct device * dev = & port - > dev ;
2005-04-16 15:20:36 -07:00
unsigned char * data = urb - > transfer_buffer ;
2007-06-15 15:44:13 -07:00
int status = urb - > status ;
2005-04-16 15:20:36 -07:00
int result ;
/* the urb might have been killed. */
2007-06-15 15:44:13 -07:00
if ( status )
2005-04-16 15:20:36 -07:00
return ;
2012-09-18 09:58:57 +01:00
usb_serial_debug_data ( dev , __func__ , urb - > actual_length , data ) ;
2005-04-16 15:20:36 -07:00
/* React only to interrupts signaling a bulk_in transfer */
2008-07-22 11:10:27 +01:00
if ( urb - > actual_length = = 4 & & data [ 0 ] = = 0x01 ) {
2005-04-16 15:20:36 -07:00
short old_rdtodo ;
/* This is a announcement of coming bulk_ins. */
unsigned short size = ( ( unsigned short ) data [ 3 ] < < 8 ) + data [ 2 ] + 3 ;
spin_lock ( & priv - > lock ) ;
old_rdtodo = priv - > rdtodo ;
2013-10-06 03:32:53 +03:00
if ( old_rdtodo > SHRT_MAX - size ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " To many bulk_in urbs to do. \n " ) ;
2005-04-16 15:20:36 -07:00
spin_unlock ( & priv - > lock ) ;
goto resubmit ;
}
2014-01-02 19:29:24 +05:30
/* "+=" is probably more fault tolerant than "=" */
2005-04-16 15:20:36 -07:00
priv - > rdtodo + = size ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - rdtodo: %d \n " , __func__ , priv - > rdtodo ) ;
2005-04-16 15:20:36 -07:00
spin_unlock ( & priv - > lock ) ;
2008-07-22 11:10:27 +01:00
if ( ! old_rdtodo ) {
2005-04-16 15:20:36 -07:00
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
2008-07-22 11:10:27 +01:00
if ( result )
2012-09-13 17:18:14 -07:00
dev_err ( dev , " %s - failed resubmitting read urb, error %d \n " ,
2008-08-20 16:56:34 -07:00
__func__ , result ) ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - usb_submit_urb(read urb) \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
}
}
resubmit :
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_ATOMIC ) ;
if ( result )
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " usb_submit_urb(read int) failed \n " ) ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - usb_submit_urb(int urb) \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-22 11:09:07 +01:00
static void cyberjack_read_bulk_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 cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-13 17:18:14 -07:00
struct device * dev = & port - > dev ;
2005-04-16 15:20:36 -07:00
unsigned char * data = urb - > transfer_buffer ;
short todo ;
int result ;
2007-06-15 15:44:13 -07:00
int status = urb - > status ;
2005-04-16 15:20:36 -07:00
2012-09-18 09:58:57 +01:00
usb_serial_debug_data ( dev , __func__ , urb - > actual_length , data ) ;
2007-06-15 15:44:13 -07:00
if ( status ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - nonzero read bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-16 15:20:36 -07:00
return ;
}
if ( urb - > actual_length ) {
2013-01-03 15:53:04 +01:00
tty_insert_flip_string ( & port - > port , data , urb - > actual_length ) ;
2013-01-03 15:53:06 +01:00
tty_flip_buffer_push ( & port - > port ) ;
2005-04-16 15:20:36 -07:00
}
spin_lock ( & priv - > lock ) ;
/* Reduce urbs to do by one. */
2008-07-22 11:10:27 +01:00
priv - > rdtodo - = urb - > actual_length ;
2005-04-16 15:20:36 -07:00
/* Just to be sure */
2008-07-22 11:10:27 +01:00
if ( priv - > rdtodo < 0 )
priv - > rdtodo = 0 ;
2005-04-16 15:20:36 -07:00
todo = priv - > rdtodo ;
spin_unlock ( & priv - > lock ) ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - rdtodo: %d \n " , __func__ , todo ) ;
2005-04-16 15:20:36 -07:00
/* Continue to read if we have still urbs to do. */
2008-07-22 11:10:27 +01:00
if ( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
2005-04-16 15:20:36 -07:00
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
if ( result )
2012-09-13 17:18:14 -07:00
dev_err ( dev , " %s - failed resubmitting read urb, error %d \n " ,
__func__ , result ) ;
dev_dbg ( dev , " %s - usb_submit_urb(read urb) \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
}
}
2008-07-22 11:09:07 +01:00
static void cyberjack_write_bulk_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 cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-13 17:18:14 -07:00
struct device * dev = & port - > dev ;
2007-06-15 15:44:13 -07:00
int status = urb - > status ;
2005-04-16 15:20:36 -07:00
2011-11-06 19:06:23 +01:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2007-06-15 15:44:13 -07:00
if ( status ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - nonzero write bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-16 15:20:36 -07:00
return ;
}
spin_lock ( & priv - > lock ) ;
/* only do something if we have more data to send */
2008-07-22 11:10:27 +01:00
if ( priv - > wrfilled ) {
2005-04-16 15:20:36 -07:00
int length , blksize , result ;
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - transmitting data (frame n) \n " , __func__ ) ;
2005-04-16 15:20:36 -07:00
length = ( ( priv - > wrfilled - priv - > wrsent ) > port - > bulk_out_size ) ?
port - > bulk_out_size : ( priv - > wrfilled - priv - > wrsent ) ;
2008-07-22 11:10:27 +01:00
memcpy ( port - > write_urb - > transfer_buffer ,
priv - > wrbuf + priv - > wrsent , length ) ;
priv - > wrsent + = length ;
2005-04-16 15:20:36 -07:00
/* set up our urb */
2011-11-06 19:06:30 +01:00
port - > write_urb - > transfer_buffer_length = length ;
2005-04-16 15:20:36 -07:00
/* send the data out the bulk port */
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
if ( result ) {
2012-09-13 17:18:14 -07:00
dev_err ( dev , " %s - failed submitting write urb, error %d \n " ,
2008-08-20 16:56:34 -07:00
__func__ , result ) ;
2005-04-16 15:20:36 -07:00
/* Throw away data. No better idea what to do with it. */
2008-04-08 17:16:06 +01:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-16 15:20:36 -07:00
goto exit ;
}
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - priv->wrsent=%d \n " , __func__ , priv - > wrsent ) ;
dev_dbg ( dev , " %s - priv->wrfilled=%d \n " , __func__ , priv - > wrfilled ) ;
2005-04-16 15:20:36 -07:00
blksize = ( ( int ) priv - > wrbuf [ 2 ] < < 8 ) + priv - > wrbuf [ 1 ] + 3 ;
2008-07-22 11:10:27 +01:00
if ( priv - > wrsent > = priv - > wrfilled | |
priv - > wrsent > = blksize ) {
2012-09-13 17:18:14 -07:00
dev_dbg ( dev , " %s - buffer cleaned \n " , __func__ ) ;
2008-07-22 11:10:27 +01:00
memset ( priv - > wrbuf , 0 , sizeof ( priv - > wrbuf ) ) ;
2008-04-08 17:16:06 +01:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-16 15:20:36 -07:00
}
}
exit :
spin_unlock ( & priv - > lock ) ;
2006-05-22 21:58:49 -07:00
usb_serial_port_softint ( port ) ;
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:10:27 +01:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;