cregit-Linux how code gets into the kernel

Release 4.7 drivers/usb/serial/cyberjack.c

/*
 *  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>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>


#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 */
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static int  cyberjack_open(struct tty_struct *tty,
	struct usb_serial_port *port);
static void cyberjack_close(struct usb_serial_port *port);
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);


static const 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_serial_driver cyberjack_device = {
	.driver = {
		.owner =	THIS_MODULE,
		.name =		"cyberjack",
        },
	.description =		"Reiner SCT Cyberjack USB card reader",
	.id_table =		id_table,
	.num_ports =		1,
	.port_probe =		cyberjack_port_probe,
	.port_remove =		cyberjack_port_remove,
	.open =			cyberjack_open,
	.close =		cyberjack_close,
	.write =		cyberjack_write,
	.write_room =		cyberjack_write_room,
	.read_int_callback =	cyberjack_read_int_callback,
	.read_bulk_callback =	cyberjack_read_bulk_callback,
	.write_bulk_callback =	cyberjack_write_bulk_callback,
};


static struct usb_serial_driver * const serial_drivers[] = {
	&cyberjack_device, NULL
};


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


static int cyberjack_port_probe(struct usb_serial_port *port) { struct cyberjack_private *priv; int result; 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; 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"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds5351.96%114.29%
greg kroah-hartmangreg kroah-hartman1817.65%342.86%
harald welteharald welte1817.65%114.29%
matthias bruestlematthias bruestle87.84%114.29%
johan hovoldjohan hovold54.90%114.29%
Total102100.00%7100.00%


static int cyberjack_port_remove(struct usb_serial_port *port) { struct cyberjack_private *priv; usb_kill_urb(port->interrupt_in_urb); priv = usb_get_serial_port_data(port); kfree(priv); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
johan hovoldjohan hovold2565.79%240.00%
linus torvaldslinus torvalds821.05%120.00%
harald welteharald welte410.53%120.00%
alan sternalan stern12.63%120.00%
Total38100.00%5100.00%


static int cyberjack_open(struct tty_struct *tty, struct usb_serial_port *port) { struct cyberjack_private *priv; unsigned long flags; dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__); 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 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthias bruestlematthias bruestle4242.00%225.00%
linus torvaldslinus torvalds4141.00%112.50%
greg kroah-hartmangreg kroah-hartman1010.00%225.00%
alan coxalan cox55.00%112.50%
harvey harrisonharvey harrison11.00%112.50%
mathieu othacehemathieu othacehe11.00%112.50%
Total100100.00%8100.00%


static void cyberjack_close(struct usb_serial_port *port) { usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds2392.00%266.67%
greg kroah-hartmangreg kroah-hartman28.00%133.33%
Total25100.00%3100.00%


static int cyberjack_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { struct device *dev = &port->dev; struct cyberjack_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result; int wrexpected; if (count == 0) { dev_dbg(dev, "%s - write request of 0 bytes\n", __func__); return 0; } if (!test_and_clear_bit(0, &port->write_urbs_free)) { dev_dbg(dev, "%s - already writing\n", __func__); return 0; } spin_lock_irqsave(&priv->lock, flags); if (count+priv->wrfilled > sizeof(priv->wrbuf)) { /* To much data for buffer. Reset buffer. */ priv->wrfilled = 0; spin_unlock_irqrestore(&priv->lock, flags); set_bit(0, &port->write_urbs_free); return 0; } /* Copy data */ memcpy(priv->wrbuf + priv->wrfilled, buf, count); usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled); priv->wrfilled += count; if (priv->wrfilled >= 3) { wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected); } else wrexpected = sizeof(priv->wrbuf); if (priv->wrfilled >= wrexpected) { /* We have enough data to begin transmission */ int length; dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__); 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 */ port->write_urb->transfer_buffer_length = length; /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled = 0; priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); set_bit(0, &port->write_urbs_free); return 0; } dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); if (priv->wrsent >= priv->wrfilled) { dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; } } spin_unlock_irqrestore(&priv->lock, flags); return count; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds32668.06%16.25%
greg kroah-hartmangreg kroah-hartman6513.57%743.75%
matthias bruestlematthias bruestle449.19%16.25%
johan hovoldjohan hovold275.64%318.75%
harvey harrisonharvey harrison91.88%16.25%
alan coxalan cox51.04%16.25%
siegfried hildebrandsiegfried hildebrand20.42%16.25%
ganesh varadarajanganesh varadarajan10.21%16.25%
Total479100.00%16100.00%


static int cyberjack_write_room(struct tty_struct *tty) { /* FIXME: .... */ return CYBERJACK_LOCAL_BUF_SIZE; }

Contributors

PersonTokensPropCommitsCommitProp
matthias bruestlematthias bruestle1280.00%133.33%
alan coxalan cox320.00%266.67%
Total15100.00%3100.00%


static void cyberjack_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; unsigned char *data = urb->transfer_buffer; int status = urb->status; int result; /* the urb might have been killed. */ if (status) return; usb_serial_debug_data(dev, __func__, urb->actual_length, data); /* React only to interrupts signaling a bulk_in transfer */ if (urb->actual_length == 4 && data[0] == 0x01) { 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 > SHRT_MAX - size) { dev_dbg(dev, "To many bulk_in urbs to do.\n"); spin_unlock(&priv->lock); goto resubmit; } /* "+=" is probably more fault tolerant than "=" */ priv->rdtodo += size; dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); spin_unlock(&priv->lock); if (!old_rdtodo) { result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) dev_err(dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } } resubmit: result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__); }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds15255.88%17.14%
matthias bruestlematthias bruestle5319.49%17.14%
greg kroah-hartmangreg kroah-hartman5219.12%750.00%
oliver neukumoliver neukum51.84%17.14%
harvey harrisonharvey harrison51.84%17.14%
dan carpenterdan carpenter31.10%17.14%
rahul bedarkarrahul bedarkar10.37%17.14%
steven colesteven cole10.37%17.14%
Total272100.00%14100.00%


static void cyberjack_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; unsigned char *data = urb->transfer_buffer; short todo; int result; int status = urb->status; usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (status) { dev_dbg(dev, "%s - nonzero read bulk status received: %d\n", __func__, status); return; } if (urb->actual_length) { tty_insert_flip_string(&port->port, data, urb->actual_length); tty_flip_buffer_push(&port->port); } 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); dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); /* Continue to read if we have still urbs to do. */ if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) dev_err(dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds12957.85%16.67%
greg kroah-hartmangreg kroah-hartman4721.08%746.67%
matthias bruestlematthias bruestle2511.21%16.67%
jiri slabyjiri slaby83.59%213.33%
harvey harrisonharvey harrison52.24%16.67%
alan coxalan cox41.79%16.67%
oliver neukumoliver neukum31.35%16.67%
harald welteharald welte20.90%16.67%
Total223100.00%15100.00%


static void cyberjack_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; int status = urb->status; set_bit(0, &port->write_urbs_free); if (status) { dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", __func__, status); return; } spin_lock(&priv->lock); /* only do something if we have more data to send */ if (priv->wrfilled) { int length, blksize, result; dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__); 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 */ port->write_urb->transfer_buffer_length = length; /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { dev_err(dev, "%s - failed submitting write urb, error %d\n", __func__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled = 0; priv->wrsent = 0; goto exit; } dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; if (priv->wrsent >= priv->wrfilled || priv->wrsent >= blksize) { dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; } } exit: spin_unlock(&priv->lock); usb_serial_port_softint(port); }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds24872.94%16.25%
greg kroah-hartmangreg kroah-hartman5917.35%850.00%
matthias bruestlematthias bruestle144.12%16.25%
johan hovoldjohan hovold92.65%212.50%
harvey harrisonharvey harrison61.76%16.25%
oliver neukumoliver neukum20.59%16.25%
ganesh varadarajanganesh varadarajan10.29%16.25%
pete zaitcevpete zaitcev10.29%16.25%
Total340100.00%16100.00%

module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds120262.09%59.26%
greg kroah-hartmangreg kroah-hartman27714.31%2138.89%
matthias bruestlematthias bruestle21911.31%23.70%
johan hovoldjohan hovold784.03%59.26%
alan coxalan cox301.55%47.41%
alan sternalan stern261.34%23.70%
harvey harrisonharvey harrison261.34%11.85%
harald welteharald welte251.29%23.70%
rusty russellrusty russell221.14%11.85%
oliver neukumoliver neukum100.52%11.85%
jiri slabyjiri slaby80.41%23.70%
dan carpenterdan carpenter30.15%11.85%
siegfried hildebrandsiegfried hildebrand30.15%11.85%
ganesh varadarajanganesh varadarajan20.10%11.85%
rahul bedarkarrahul bedarkar10.05%11.85%
steven colesteven cole10.05%11.85%
marton nemethmarton nemeth10.05%11.85%
mathieu othacehemathieu othacehe10.05%11.85%
pete zaitcevpete zaitcev10.05%11.85%
Total1936100.00%54100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}