cyberjack.c 14.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/*
 *  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>
#include <asm/uaccess.h>
#include <linux/usb.h>
42
#include <linux/usb/serial.h>
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

#define CYBERJACK_LOCAL_BUF_SIZE 32

static int debug;

/*
 * Version Information
 */
#define DRIVER_VERSION "v1.01"
#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 */
A
Alan Cox 已提交
60 61 62 63 64 65 66 67 68 69 70 71
static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_shutdown(struct usb_serial *serial);
static int  cyberjack_open(struct tty_struct *tty,
			struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct tty_struct *tty,
			struct usb_serial_port *port, struct file *filp);
static int cyberjack_write(struct tty_struct *tty,
	struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room( struct tty_struct *tty);
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);
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84

static struct usb_device_id id_table [] = {
	{ USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
	{ }			/* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, id_table);

static struct usb_driver cyberjack_driver = {
	.name =		"cyberjack",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table,
85
	.no_dynamic_id = 	1,
L
Linus Torvalds 已提交
86 87
};

88
static struct usb_serial_driver cyberjack_device = {
89 90
	.driver = {
		.owner =	THIS_MODULE,
91
		.name =		"cyberjack",
92
	},
93
	.description =		"Reiner SCT Cyberjack USB card reader",
94
	.usb_driver = 		&cyberjack_driver,
L
Linus Torvalds 已提交
95 96 97 98 99 100 101
	.id_table =		id_table,
	.num_ports =		1,
	.attach =		cyberjack_startup,
	.shutdown =		cyberjack_shutdown,
	.open =			cyberjack_open,
	.close =		cyberjack_close,
	.write =		cyberjack_write,
102
	.write_room =		cyberjack_write_room,
L
Linus Torvalds 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116
	.read_int_callback =	cyberjack_read_int_callback,
	.read_bulk_callback =	cyberjack_read_bulk_callback,
	.write_bulk_callback =	cyberjack_write_bulk_callback,
};

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 */
};

/* do some startup allocations not currently performed by usb_serial_probe() */
A
Alan Cox 已提交
117
static int cyberjack_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
118 119 120 121
{
	struct cyberjack_private *priv;
	int i;

122
	dbg("%s", __func__);
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

	/* allocate the private data structure */
	priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	/* set initial values */
	spin_lock_init(&priv->lock);
	priv->rdtodo = 0;
	priv->wrfilled = 0;
	priv->wrsent = 0;
	usb_set_serial_port_data(serial->port[0], priv);

	init_waitqueue_head(&serial->port[0]->write_wait);

	for (i = 0; i < serial->num_ports; ++i) {
		int result;
		serial->port[i]->interrupt_in_urb->dev = serial->dev;
		result = usb_submit_urb(serial->port[i]->interrupt_in_urb, 
					GFP_KERNEL);
		if (result)
			err(" usb_submit_urb(read int) failed");
145
		dbg("%s - usb_submit_urb(int urb)", __func__);
L
Linus Torvalds 已提交
146 147 148 149 150
	}

	return( 0 );
}

A
Alan Cox 已提交
151
static void cyberjack_shutdown(struct usb_serial *serial)
L
Linus Torvalds 已提交
152 153 154
{
	int i;
	
155
	dbg("%s", __func__);
L
Linus Torvalds 已提交
156

157
	for (i = 0; i < serial->num_ports; ++i) {
L
Linus Torvalds 已提交
158 159 160 161 162 163 164
		usb_kill_urb(serial->port[i]->interrupt_in_urb);
		/* My special items, the standard routines free my urbs */
		kfree(usb_get_serial_port_data(serial->port[i]));
		usb_set_serial_port_data(serial->port[i], NULL);
	}
}
	
A
Alan Cox 已提交
165 166
static int  cyberjack_open(struct tty_struct *tty,
			struct usb_serial_port *port, struct file *filp)
L
Linus Torvalds 已提交
167 168 169 170 171
{
	struct cyberjack_private *priv;
	unsigned long flags;
	int result = 0;

172
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
173

174
	dbg("%s - usb_clear_halt", __func__ );
L
Linus Torvalds 已提交
175 176 177 178 179 180
	usb_clear_halt(port->serial->dev, port->write_urb->pipe);

	/* force low_latency on so that our tty_push actually forces
	 * the data through, otherwise it is scheduled, and with high
	 * data rates (like with OHCI) data can get lost.
	 */
A
Alan Cox 已提交
181 182
	if (tty)
		tty->low_latency = 1;
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190 191 192 193

	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;
}

A
Alan Cox 已提交
194 195
static void cyberjack_close(struct tty_struct *tty,
			struct usb_serial_port *port, struct file *filp)
L
Linus Torvalds 已提交
196
{
197
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
198 199 200 201 202 203 204 205

	if (port->serial->dev) {
		/* shutdown any bulk reads that might be going on */
		usb_kill_urb(port->write_urb);
		usb_kill_urb(port->read_urb);
	}
}

A
Alan Cox 已提交
206 207
static int cyberjack_write(struct tty_struct *tty,
	struct usb_serial_port *port, const unsigned char *buf, int count)
L
Linus Torvalds 已提交
208 209 210 211 212 213 214
{
	struct usb_serial *serial = port->serial;
	struct cyberjack_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int result;
	int wrexpected;

215
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
216 217

	if (count == 0) {
218
		dbg("%s - write request of 0 bytes", __func__);
219
		return 0;
L
Linus Torvalds 已提交
220 221
	}

222
	spin_lock_bh(&port->lock);
223
	if (port->write_urb_busy) {
224
		spin_unlock_bh(&port->lock);
225
		dbg("%s - already writing", __func__);
226
		return 0;
L
Linus Torvalds 已提交
227
	}
228
	port->write_urb_busy = 1;
229
	spin_unlock_bh(&port->lock);
L
Linus Torvalds 已提交
230 231 232

	spin_lock_irqsave(&priv->lock, flags);

233
	if( (count+priv->wrfilled) > sizeof(priv->wrbuf) ) {
L
Linus Torvalds 已提交
234
		/* To much data for buffer. Reset buffer. */
235
		priv->wrfilled = 0;
236
		port->write_urb_busy = 0;
237 238
		spin_unlock_irqrestore(&priv->lock, flags);
		return 0;
L
Linus Torvalds 已提交
239 240 241 242 243
	}

	/* Copy data */
	memcpy (priv->wrbuf+priv->wrfilled, buf, count);

244
	usb_serial_debug_data(debug, &port->dev, __func__, count,
L
Linus Torvalds 已提交
245 246 247 248 249
		priv->wrbuf+priv->wrfilled);
	priv->wrfilled += count;

	if( priv->wrfilled >= 3 ) {
		wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
250
		dbg("%s - expected data: %d", __func__, wrexpected);
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258
	} else {
		wrexpected = sizeof(priv->wrbuf);
	}

	if( priv->wrfilled >= wrexpected ) {
		/* We have enough data to begin transmission */
		int length;

259
		dbg("%s - transmitting data (frame 1)", __func__);
L
Linus Torvalds 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
		length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;

		memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
		priv->wrsent=length;

		/* set up our urb */
		usb_fill_bulk_urb(port->write_urb, serial->dev, 
			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
			      port->write_urb->transfer_buffer, length,
			      ((serial->type->write_bulk_callback) ? 
			       serial->type->write_bulk_callback : 
			       cyberjack_write_bulk_callback), 
			      port);

		/* send the data out the bulk port */
		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
		if (result) {
277
			err("%s - failed submitting write urb, error %d", __func__, result);
L
Linus Torvalds 已提交
278
			/* Throw away data. No better idea what to do with it. */
279 280
			priv->wrfilled = 0;
			priv->wrsent = 0;
L
Linus Torvalds 已提交
281
			spin_unlock_irqrestore(&priv->lock, flags);
282
			port->write_urb_busy = 0;
L
Linus Torvalds 已提交
283 284 285
			return 0;
		}

286 287
		dbg("%s - priv->wrsent=%d", __func__,priv->wrsent);
		dbg("%s - priv->wrfilled=%d", __func__,priv->wrfilled);
L
Linus Torvalds 已提交
288 289

		if( priv->wrsent>=priv->wrfilled ) {
290
			dbg("%s - buffer cleaned", __func__);
L
Linus Torvalds 已提交
291
			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
292 293
			priv->wrfilled = 0;
			priv->wrsent = 0;
L
Linus Torvalds 已提交
294 295 296 297 298 299 300 301
		}
	}

	spin_unlock_irqrestore(&priv->lock, flags);

	return (count);
} 

A
Alan Cox 已提交
302
static int cyberjack_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
303
{
304
	/* FIXME: .... */
L
Linus Torvalds 已提交
305 306 307
	return CYBERJACK_LOCAL_BUF_SIZE;
}

A
Alan Cox 已提交
308
static void cyberjack_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
309
{
310
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
311 312
	struct cyberjack_private *priv = usb_get_serial_port_data(port);
	unsigned char *data = urb->transfer_buffer;
313
	int status = urb->status;
L
Linus Torvalds 已提交
314 315
	int result;

316
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
317 318

	/* the urb might have been killed. */
319
	if (status)
L
Linus Torvalds 已提交
320 321
		return;

322
	usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
L
Linus Torvalds 已提交
323 324

	/* React only to interrupts signaling a bulk_in transfer */
325
	if( (urb->actual_length == 4) && (data[0] == 0x01) ) {
L
Linus Torvalds 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
		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;

		if( (old_rdtodo+size)<(old_rdtodo) ) {
			dbg( "To many bulk_in urbs to do." );
			spin_unlock(&priv->lock);
			goto resubmit;
		}

		/* "+=" is probably more fault tollerant than "=" */
		priv->rdtodo += size;

344
		dbg("%s - rdtodo: %d", __func__, priv->rdtodo);
L
Linus Torvalds 已提交
345 346 347 348 349 350 351

		spin_unlock(&priv->lock);

		if( !old_rdtodo ) {
			port->read_urb->dev = port->serial->dev;
			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
			if( result )
352 353
				err("%s - failed resubmitting read urb, error %d", __func__, result);
			dbg("%s - usb_submit_urb(read urb)", __func__);
L
Linus Torvalds 已提交
354 355 356 357 358 359 360 361
		}
	}

resubmit:
	port->interrupt_in_urb->dev = port->serial->dev;
	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
	if (result)
		err(" usb_submit_urb(read int) failed");
362
	dbg("%s - usb_submit_urb(int urb)", __func__);
L
Linus Torvalds 已提交
363 364
}

A
Alan Cox 已提交
365
static void cyberjack_read_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
366
{
367
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
368 369 370 371 372
	struct cyberjack_private *priv = usb_get_serial_port_data(port);
	struct tty_struct *tty;
	unsigned char *data = urb->transfer_buffer;
	short todo;
	int result;
373
	int status = urb->status;
L
Linus Torvalds 已提交
374

375
	dbg("%s - port %d", __func__, port->number);
376

377
	usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
378 379
	if (status) {
		dbg("%s - nonzero read bulk status received: %d",
380
		    __func__, status);
L
Linus Torvalds 已提交
381 382 383
		return;
	}

A
Alan Cox 已提交
384
	tty = port->port.tty;
L
Linus Torvalds 已提交
385
	if (!tty) {
386
		dbg("%s - ignoring since device not open\n", __func__);
L
Linus Torvalds 已提交
387 388 389
		return;
	}
	if (urb->actual_length) {
A
Alan Cox 已提交
390 391
		tty_buffer_request_room(tty, urb->actual_length);
		tty_insert_flip_string(tty, data, urb->actual_length);
L
Linus Torvalds 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404
	  	tty_flip_buffer_push(tty);
	}

	spin_lock(&priv->lock);

	/* Reduce urbs to do by one. */
	priv->rdtodo-=urb->actual_length;
	/* Just to be sure */
	if ( priv->rdtodo<0 ) priv->rdtodo = 0;
	todo = priv->rdtodo;

	spin_unlock(&priv->lock);

405
	dbg("%s - rdtodo: %d", __func__, todo);
L
Linus Torvalds 已提交
406 407 408 409 410 411

	/* Continue to read if we have still urbs to do. */
	if( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
		port->read_urb->dev = port->serial->dev;
		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
		if (result)
412 413
			err("%s - failed resubmitting read urb, error %d", __func__, result);
		dbg("%s - usb_submit_urb(read urb)", __func__);
L
Linus Torvalds 已提交
414 415 416
	}
}

A
Alan Cox 已提交
417
static void cyberjack_write_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
418
{
419
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
420
	struct cyberjack_private *priv = usb_get_serial_port_data(port);
421
	int status = urb->status;
L
Linus Torvalds 已提交
422

423
	dbg("%s - port %d", __func__, port->number);
424 425

	port->write_urb_busy = 0;
426 427
	if (status) {
		dbg("%s - nonzero write bulk status received: %d",
428
		    __func__, status);
L
Linus Torvalds 已提交
429 430 431 432 433 434 435 436 437
		return;
	}

	spin_lock(&priv->lock);

	/* only do something if we have more data to send */
	if( priv->wrfilled ) {
		int length, blksize, result;

438
		dbg("%s - transmitting data (frame n)", __func__);
L
Linus Torvalds 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
			port->bulk_out_size : (priv->wrfilled - priv->wrsent);

		memcpy (port->write_urb->transfer_buffer, priv->wrbuf + priv->wrsent,
			length );
		priv->wrsent+=length;

		/* set up our urb */
		usb_fill_bulk_urb(port->write_urb, port->serial->dev, 
			      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
			      port->write_urb->transfer_buffer, length,
			      ((port->serial->type->write_bulk_callback) ? 
			       port->serial->type->write_bulk_callback : 
			       cyberjack_write_bulk_callback), 
			      port);

		/* send the data out the bulk port */
		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
		if (result) {
459
			err("%s - failed submitting write urb, error %d", __func__, result);
L
Linus Torvalds 已提交
460
			/* Throw away data. No better idea what to do with it. */
461 462
			priv->wrfilled = 0;
			priv->wrsent = 0;
L
Linus Torvalds 已提交
463 464 465
			goto exit;
		}

466 467
		dbg("%s - priv->wrsent=%d", __func__,priv->wrsent);
		dbg("%s - priv->wrfilled=%d", __func__,priv->wrfilled);
L
Linus Torvalds 已提交
468 469 470 471

		blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;

		if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
472
			dbg("%s - buffer cleaned", __func__);
L
Linus Torvalds 已提交
473
			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
474 475
			priv->wrfilled = 0;
			priv->wrsent = 0;
L
Linus Torvalds 已提交
476 477 478 479 480
		}
	}

exit:
	spin_unlock(&priv->lock);
481
	usb_serial_port_softint(port);
L
Linus Torvalds 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
}

static int __init cyberjack_init (void)
{
	int retval;
	retval  = usb_serial_register(&cyberjack_device);
	if (retval)
		goto failed_usb_serial_register;
	retval = usb_register(&cyberjack_driver);
	if (retval) 
		goto failed_usb_register;

	info(DRIVER_VERSION " " DRIVER_AUTHOR);
	info(DRIVER_DESC);

	return 0;
failed_usb_register:
	usb_serial_deregister(&cyberjack_device);
failed_usb_serial_register:
	return retval;
}

static void __exit cyberjack_exit (void)
{
	usb_deregister (&cyberjack_driver);
	usb_serial_deregister (&cyberjack_device);
}

module_init(cyberjack_init);
module_exit(cyberjack_exit);

MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_VERSION( DRIVER_VERSION );
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");