2005-04-17 02:20:36 +04: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/init.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:10:27 +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
# 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 20:20:54 +04:00
static int cyberjack_port_probe ( struct usb_serial_port * port ) ;
static int cyberjack_port_remove ( struct usb_serial_port * port ) ;
2008-07-22 14:09:07 +04:00
static int cyberjack_open ( struct tty_struct * tty ,
2009-09-20 00:13:26 +04:00
struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void cyberjack_close ( struct usb_serial_port * port ) ;
2008-07-22 14:09:07 +04:00
static int cyberjack_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count ) ;
2008-07-22 14:10:27 +04:00
static int cyberjack_write_room ( struct tty_struct * tty ) ;
2008-07-22 14:09:07 +04: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-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 ( CYBERJACK_VENDOR_ID , CYBERJACK_PRODUCT_ID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 14:10:27 +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 cyberjack_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " cyberjack " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " Reiner SCT Cyberjack USB card reader " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
. num_ports = 1 ,
2012-10-15 20:20:54 +04:00
. port_probe = cyberjack_port_probe ,
. port_remove = cyberjack_port_remove ,
2005-04-17 02:20:36 +04:00
. open = cyberjack_open ,
. close = cyberjack_close ,
. write = cyberjack_write ,
2006-12-17 23:50:24 +03:00
. write_room = cyberjack_write_room ,
2005-04-17 02:20:36 +04: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 23:56:17 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& cyberjack_device , NULL
} ;
2005-04-17 02:20:36 +04: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 20:20:54 +04:00
static int cyberjack_port_probe ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct cyberjack_private * priv ;
2012-10-15 20:20:54 +04:00
int result ;
2005-04-17 02:20:36 +04: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 20:20:54 +04: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-17 02:20:36 +04:00
2008-07-22 14:10:27 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2012-10-15 20:20:54 +04:00
static int cyberjack_port_remove ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2012-10-15 20:20:54 +04:00
struct cyberjack_private * priv ;
2008-07-22 14:10:27 +04:00
2013-03-21 15:36:45 +04:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2012-10-15 20:20:54 +04:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
2009-06-02 19:53:55 +04:00
}
2008-07-22 14:09:07 +04:00
static int cyberjack_open ( struct tty_struct * tty ,
2009-09-20 00:13:26 +04:00
struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct cyberjack_private * priv ;
unsigned long flags ;
int result = 0 ;
2012-09-14 04:18:14 +04:00
dev_dbg ( & port - > dev , " %s - usb_clear_halt \n " , __func__ ) ;
2005-04-17 02:20:36 +04: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 15:26:29 +04:00
static void cyberjack_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2013-03-21 15:36:29 +04:00
usb_kill_urb ( port - > write_urb ) ;
usb_kill_urb ( port - > read_urb ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:09:07 +04:00
static int cyberjack_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
2012-09-14 04:18:14 +04:00
struct device * dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
struct cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
int result ;
int wrexpected ;
if ( count = = 0 ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - write request of 0 bytes \n " , __func__ ) ;
2008-04-08 20:16:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2011-11-06 22:06:23 +04:00
if ( ! test_and_clear_bit ( 0 , & port - > write_urbs_free ) ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - already writing \n " , __func__ ) ;
2005-04-23 23:49:16 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
spin_lock_irqsave ( & priv - > lock , flags ) ;
2008-07-22 14:10:27 +04:00
if ( count + priv - > wrfilled > sizeof ( priv - > wrbuf ) ) {
2005-04-17 02:20:36 +04:00
/* To much data for buffer. Reset buffer. */
2008-04-08 20:16:06 +04:00
priv - > wrfilled = 0 ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2011-11-06 22:06:23 +04:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2008-04-08 20:16:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* Copy data */
2008-07-22 14:10:27 +04:00
memcpy ( priv - > wrbuf + priv - > wrfilled , buf , count ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , count , priv - > wrbuf + priv - > wrfilled ) ;
2005-04-17 02:20:36 +04:00
priv - > wrfilled + = count ;
2008-07-22 14:10:27 +04:00
if ( priv - > wrfilled > = 3 ) {
2005-04-17 02:20:36 +04:00
wrexpected = ( ( int ) priv - > wrbuf [ 2 ] < < 8 ) + priv - > wrbuf [ 1 ] + 3 ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - expected data: %d \n " , __func__ , wrexpected ) ;
2008-07-22 14:10:27 +04:00
} else
2005-04-17 02:20:36 +04:00
wrexpected = sizeof ( priv - > wrbuf ) ;
2008-07-22 14:10:27 +04:00
if ( priv - > wrfilled > = wrexpected ) {
2005-04-17 02:20:36 +04:00
/* We have enough data to begin transmission */
int length ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - transmitting data (frame 1) \n " , __func__ ) ;
2008-07-22 14:10:27 +04:00
length = ( wrexpected > port - > bulk_out_size ) ?
port - > bulk_out_size : wrexpected ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:10:27 +04:00
memcpy ( port - > write_urb - > transfer_buffer , priv - > wrbuf , length ) ;
priv - > wrsent = length ;
2005-04-17 02:20:36 +04:00
/* set up our urb */
2011-11-06 22:06:30 +04:00
port - > write_urb - > transfer_buffer_length = length ;
2005-04-17 02:20:36 +04:00
/* send the data out the bulk port */
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
if ( result ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" %s - failed submitting write urb, error %d " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
/* Throw away data. No better idea what to do with it. */
2008-04-08 20:16:06 +04:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2011-11-06 22:06:23 +04:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-09-14 04:18:14 +04: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-17 02:20:36 +04:00
2008-07-22 14:10:27 +04:00
if ( priv - > wrsent > = priv - > wrfilled ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - buffer cleaned \n " , __func__ ) ;
2008-07-22 14:10:27 +04:00
memset ( priv - > wrbuf , 0 , sizeof ( priv - > wrbuf ) ) ;
2008-04-08 20:16:06 +04:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-17 02:20:36 +04:00
}
}
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-07-22 14:10:27 +04:00
return count ;
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
static int cyberjack_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-04-08 20:16:06 +04:00
/* FIXME: .... */
2005-04-17 02:20:36 +04:00
return CYBERJACK_LOCAL_BUF_SIZE ;
}
2008-07-22 14:09:07 +04:00
static void cyberjack_read_int_callback ( 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
struct cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-14 04:18:14 +04:00
struct device * dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
int result ;
/* the urb might have been killed. */
2007-06-16 02:44:13 +04:00
if ( status )
2005-04-17 02:20:36 +04:00
return ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , urb - > actual_length , data ) ;
2005-04-17 02:20:36 +04:00
/* React only to interrupts signaling a bulk_in transfer */
2008-07-22 14:10:27 +04:00
if ( urb - > actual_length = = 4 & & data [ 0 ] = = 0x01 ) {
2005-04-17 02:20:36 +04: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 04:32:53 +04:00
if ( old_rdtodo > SHRT_MAX - size ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " To many bulk_in urbs to do. \n " ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & priv - > lock ) ;
goto resubmit ;
}
/* "+=" is probably more fault tollerant than "=" */
priv - > rdtodo + = size ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - rdtodo: %d \n " , __func__ , priv - > rdtodo ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & priv - > lock ) ;
2008-07-22 14:10:27 +04:00
if ( ! old_rdtodo ) {
2005-04-17 02:20:36 +04:00
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
2008-07-22 14:10:27 +04:00
if ( result )
2012-09-14 04:18:14 +04:00
dev_err ( dev , " %s - failed resubmitting read urb, error %d \n " ,
2008-08-21 03:56:34 +04:00
__func__ , result ) ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - usb_submit_urb(read urb) \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
}
resubmit :
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_ATOMIC ) ;
if ( result )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " usb_submit_urb(read int) failed \n " ) ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - usb_submit_urb(int urb) \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:09:07 +04:00
static void cyberjack_read_bulk_callback ( 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
struct cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-14 04:18:14 +04:00
struct device * dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
short todo ;
int result ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , urb - > actual_length , data ) ;
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - nonzero read bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( urb - > actual_length ) {
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
}
spin_lock ( & priv - > lock ) ;
/* Reduce urbs to do by one. */
2008-07-22 14:10:27 +04:00
priv - > rdtodo - = urb - > actual_length ;
2005-04-17 02:20:36 +04:00
/* Just to be sure */
2008-07-22 14:10:27 +04:00
if ( priv - > rdtodo < 0 )
priv - > rdtodo = 0 ;
2005-04-17 02:20:36 +04:00
todo = priv - > rdtodo ;
spin_unlock ( & priv - > lock ) ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - rdtodo: %d \n " , __func__ , todo ) ;
2005-04-17 02:20:36 +04:00
/* Continue to read if we have still urbs to do. */
2008-07-22 14:10:27 +04:00
if ( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
2005-04-17 02:20:36 +04:00
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
if ( result )
2012-09-14 04:18:14 +04: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-17 02:20:36 +04:00
}
}
2008-07-22 14:09:07 +04:00
static void cyberjack_write_bulk_callback ( 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
struct cyberjack_private * priv = usb_get_serial_port_data ( port ) ;
2012-09-14 04:18:14 +04:00
struct device * dev = & port - > dev ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2011-11-06 22:06:23 +04:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - nonzero write bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
spin_lock ( & priv - > lock ) ;
/* only do something if we have more data to send */
2008-07-22 14:10:27 +04:00
if ( priv - > wrfilled ) {
2005-04-17 02:20:36 +04:00
int length , blksize , result ;
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - transmitting data (frame n) \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
length = ( ( priv - > wrfilled - priv - > wrsent ) > port - > bulk_out_size ) ?
port - > bulk_out_size : ( priv - > wrfilled - priv - > wrsent ) ;
2008-07-22 14:10:27 +04:00
memcpy ( port - > write_urb - > transfer_buffer ,
priv - > wrbuf + priv - > wrsent , length ) ;
priv - > wrsent + = length ;
2005-04-17 02:20:36 +04:00
/* set up our urb */
2011-11-06 22:06:30 +04:00
port - > write_urb - > transfer_buffer_length = length ;
2005-04-17 02:20:36 +04:00
/* send the data out the bulk port */
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
if ( result ) {
2012-09-14 04:18:14 +04:00
dev_err ( dev , " %s - failed submitting write urb, error %d \n " ,
2008-08-21 03:56:34 +04:00
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
/* Throw away data. No better idea what to do with it. */
2008-04-08 20:16:06 +04:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
2012-09-14 04:18:14 +04: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-17 02:20:36 +04:00
blksize = ( ( int ) priv - > wrbuf [ 2 ] < < 8 ) + priv - > wrbuf [ 1 ] + 3 ;
2008-07-22 14:10:27 +04:00
if ( priv - > wrsent > = priv - > wrfilled | |
priv - > wrsent > = blksize ) {
2012-09-14 04:18:14 +04:00
dev_dbg ( dev , " %s - buffer cleaned \n " , __func__ ) ;
2008-07-22 14:10:27 +04:00
memset ( priv - > wrbuf , 0 , sizeof ( priv - > wrbuf ) ) ;
2008-04-08 20:16:06 +04:00
priv - > wrfilled = 0 ;
priv - > wrsent = 0 ;
2005-04-17 02:20:36 +04:00
}
}
exit :
spin_unlock ( & priv - > lock ) ;
2006-05-23 08:58:49 +04:00
usb_serial_port_softint ( port ) ;
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:10:27 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;