cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kobil_sct.c (16219B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  KOBIL USB Smart Card Terminal Driver
      4 *
      5 *  Copyright (C) 2002  KOBIL Systems GmbH
      6 *  Author: Thomas Wahrenbruch
      7 *
      8 *  Contact: linuxusb@kobil.de
      9 *
     10 *  This program is largely derived from work by the linux-usb group
     11 *  and associated source files.  Please see the usb/serial files for
     12 *  individual credits and copyrights.
     13 *
     14 *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
     15 *  patience.
     16 *
     17 * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
     18 * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
     19 */
     20
     21
     22#include <linux/kernel.h>
     23#include <linux/errno.h>
     24#include <linux/slab.h>
     25#include <linux/tty.h>
     26#include <linux/tty_driver.h>
     27#include <linux/tty_flip.h>
     28#include <linux/module.h>
     29#include <linux/spinlock.h>
     30#include <linux/uaccess.h>
     31#include <linux/usb.h>
     32#include <linux/usb/serial.h>
     33#include <linux/ioctl.h>
     34#include "kobil_sct.h"
     35
     36#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
     37#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
     38
     39#define KOBIL_VENDOR_ID			0x0D46
     40#define KOBIL_ADAPTER_B_PRODUCT_ID	0x2011
     41#define KOBIL_ADAPTER_K_PRODUCT_ID	0x2012
     42#define KOBIL_USBTWIN_PRODUCT_ID	0x0078
     43#define KOBIL_KAAN_SIM_PRODUCT_ID       0x0081
     44
     45#define KOBIL_TIMEOUT		500
     46#define KOBIL_BUF_LENGTH	300
     47
     48
     49/* Function prototypes */
     50static int kobil_port_probe(struct usb_serial_port *probe);
     51static void kobil_port_remove(struct usb_serial_port *probe);
     52static int  kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
     53static void kobil_close(struct usb_serial_port *port);
     54static int  kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
     55			 const unsigned char *buf, int count);
     56static unsigned int kobil_write_room(struct tty_struct *tty);
     57static int  kobil_ioctl(struct tty_struct *tty,
     58			unsigned int cmd, unsigned long arg);
     59static int  kobil_tiocmget(struct tty_struct *tty);
     60static int  kobil_tiocmset(struct tty_struct *tty,
     61			   unsigned int set, unsigned int clear);
     62static void kobil_read_int_callback(struct urb *urb);
     63static void kobil_write_int_callback(struct urb *urb);
     64static void kobil_set_termios(struct tty_struct *tty,
     65			struct usb_serial_port *port, struct ktermios *old);
     66static void kobil_init_termios(struct tty_struct *tty);
     67
     68static const struct usb_device_id id_table[] = {
     69	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
     70	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
     71	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
     72	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
     73	{ }			/* Terminating entry */
     74};
     75MODULE_DEVICE_TABLE(usb, id_table);
     76
     77static struct usb_serial_driver kobil_device = {
     78	.driver = {
     79		.owner =	THIS_MODULE,
     80		.name =		"kobil",
     81	},
     82	.description =		"KOBIL USB smart card terminal",
     83	.id_table =		id_table,
     84	.num_ports =		1,
     85	.num_interrupt_out =	1,
     86	.port_probe =		kobil_port_probe,
     87	.port_remove =		kobil_port_remove,
     88	.ioctl =		kobil_ioctl,
     89	.set_termios =		kobil_set_termios,
     90	.init_termios =		kobil_init_termios,
     91	.tiocmget =		kobil_tiocmget,
     92	.tiocmset =		kobil_tiocmset,
     93	.open =			kobil_open,
     94	.close =		kobil_close,
     95	.write =		kobil_write,
     96	.write_room =		kobil_write_room,
     97	.read_int_callback =	kobil_read_int_callback,
     98	.write_int_callback =	kobil_write_int_callback,
     99};
    100
    101static struct usb_serial_driver * const serial_drivers[] = {
    102	&kobil_device, NULL
    103};
    104
    105struct kobil_private {
    106	unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */
    107	int filled;  /* index of the last char in buf */
    108	int cur_pos; /* index of the next char to send in buf */
    109	__u16 device_type;
    110};
    111
    112
    113static int kobil_port_probe(struct usb_serial_port *port)
    114{
    115	struct usb_serial *serial = port->serial;
    116	struct kobil_private *priv;
    117
    118	priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
    119	if (!priv)
    120		return -ENOMEM;
    121
    122	priv->filled = 0;
    123	priv->cur_pos = 0;
    124	priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct);
    125
    126	switch (priv->device_type) {
    127	case KOBIL_ADAPTER_B_PRODUCT_ID:
    128		dev_dbg(&serial->dev->dev, "KOBIL B1 PRO / KAAN PRO detected\n");
    129		break;
    130	case KOBIL_ADAPTER_K_PRODUCT_ID:
    131		dev_dbg(&serial->dev->dev, "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
    132		break;
    133	case KOBIL_USBTWIN_PRODUCT_ID:
    134		dev_dbg(&serial->dev->dev, "KOBIL USBTWIN detected\n");
    135		break;
    136	case KOBIL_KAAN_SIM_PRODUCT_ID:
    137		dev_dbg(&serial->dev->dev, "KOBIL KAAN SIM detected\n");
    138		break;
    139	}
    140	usb_set_serial_port_data(port, priv);
    141
    142	return 0;
    143}
    144
    145
    146static void kobil_port_remove(struct usb_serial_port *port)
    147{
    148	struct kobil_private *priv;
    149
    150	priv = usb_get_serial_port_data(port);
    151	kfree(priv);
    152}
    153
    154static void kobil_init_termios(struct tty_struct *tty)
    155{
    156	/* Default to echo off and other sane device settings */
    157	tty->termios.c_lflag = 0;
    158	tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
    159	tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF;
    160	/* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
    161	tty->termios.c_oflag &= ~ONLCR;
    162}
    163
    164static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
    165{
    166	struct device *dev = &port->dev;
    167	int result = 0;
    168	struct kobil_private *priv;
    169	unsigned char *transfer_buffer;
    170	int transfer_buffer_length = 8;
    171
    172	priv = usb_get_serial_port_data(port);
    173
    174	/* allocate memory for transfer buffer */
    175	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
    176	if (!transfer_buffer)
    177		return -ENOMEM;
    178
    179	/* get hardware version */
    180	result = usb_control_msg(port->serial->dev,
    181			  usb_rcvctrlpipe(port->serial->dev, 0),
    182			  SUSBCRequest_GetMisc,
    183			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
    184			  SUSBCR_MSC_GetHWVersion,
    185			  0,
    186			  transfer_buffer,
    187			  transfer_buffer_length,
    188			  KOBIL_TIMEOUT
    189	);
    190	dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result);
    191	if (result >= 3) {
    192		dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],
    193				transfer_buffer[1], transfer_buffer[2]);
    194	}
    195
    196	/* get firmware version */
    197	result = usb_control_msg(port->serial->dev,
    198			  usb_rcvctrlpipe(port->serial->dev, 0),
    199			  SUSBCRequest_GetMisc,
    200			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
    201			  SUSBCR_MSC_GetFWVersion,
    202			  0,
    203			  transfer_buffer,
    204			  transfer_buffer_length,
    205			  KOBIL_TIMEOUT
    206	);
    207	dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result);
    208	if (result >= 3) {
    209		dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0],
    210				transfer_buffer[1], transfer_buffer[2]);
    211	}
    212
    213	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
    214			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
    215		/* Setting Baudrate, Parity and Stopbits */
    216		result = usb_control_msg(port->serial->dev,
    217			  usb_sndctrlpipe(port->serial->dev, 0),
    218			  SUSBCRequest_SetBaudRateParityAndStopBits,
    219			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    220			  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity |
    221							SUSBCR_SPASB_1StopBit,
    222			  0,
    223			  NULL,
    224			  0,
    225			  KOBIL_TIMEOUT
    226		);
    227		dev_dbg(dev, "%s - Send set_baudrate URB returns: %i\n", __func__, result);
    228
    229		/* reset all queues */
    230		result = usb_control_msg(port->serial->dev,
    231			  usb_sndctrlpipe(port->serial->dev, 0),
    232			  SUSBCRequest_Misc,
    233			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    234			  SUSBCR_MSC_ResetAllQueues,
    235			  0,
    236			  NULL,
    237			  0,
    238			  KOBIL_TIMEOUT
    239		);
    240		dev_dbg(dev, "%s - Send reset_all_queues URB returns: %i\n", __func__, result);
    241	}
    242	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
    243	    priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
    244	    priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
    245		/* start reading (Adapter B 'cause PNP string) */
    246		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
    247		dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result);
    248	}
    249
    250	kfree(transfer_buffer);
    251	return 0;
    252}
    253
    254
    255static void kobil_close(struct usb_serial_port *port)
    256{
    257	/* FIXME: Add rts/dtr methods */
    258	usb_kill_urb(port->interrupt_out_urb);
    259	usb_kill_urb(port->interrupt_in_urb);
    260}
    261
    262
    263static void kobil_read_int_callback(struct urb *urb)
    264{
    265	int result;
    266	struct usb_serial_port *port = urb->context;
    267	unsigned char *data = urb->transfer_buffer;
    268	int status = urb->status;
    269
    270	if (status) {
    271		dev_dbg(&port->dev, "%s - Read int status not zero: %d\n", __func__, status);
    272		return;
    273	}
    274
    275	if (urb->actual_length) {
    276		usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
    277									data);
    278		tty_insert_flip_string(&port->port, data, urb->actual_length);
    279		tty_flip_buffer_push(&port->port);
    280	}
    281
    282	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
    283	dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
    284}
    285
    286
    287static void kobil_write_int_callback(struct urb *urb)
    288{
    289}
    290
    291
    292static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
    293			const unsigned char *buf, int count)
    294{
    295	int length = 0;
    296	int result = 0;
    297	int todo = 0;
    298	struct kobil_private *priv;
    299
    300	if (count == 0) {
    301		dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
    302		return 0;
    303	}
    304
    305	priv = usb_get_serial_port_data(port);
    306
    307	if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
    308		dev_dbg(&port->dev, "%s - Error: write request bigger than buffer size\n", __func__);
    309		return -ENOMEM;
    310	}
    311
    312	/* Copy data to buffer */
    313	memcpy(priv->buf + priv->filled, buf, count);
    314	usb_serial_debug_data(&port->dev, __func__, count, priv->buf + priv->filled);
    315	priv->filled = priv->filled + count;
    316
    317	/* only send complete block. TWIN, KAAN SIM and adapter K
    318	   use the same protocol. */
    319	if (((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) ||
    320	     ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4)))) {
    321		/* stop reading (except TWIN and KAAN SIM) */
    322		if ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID)
    323			|| (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID))
    324			usb_kill_urb(port->interrupt_in_urb);
    325
    326		todo = priv->filled - priv->cur_pos;
    327
    328		while (todo > 0) {
    329			/* max 8 byte in one urb (endpoint size) */
    330			length = min(todo, port->interrupt_out_size);
    331			/* copy data to transfer buffer */
    332			memcpy(port->interrupt_out_buffer,
    333					priv->buf + priv->cur_pos, length);
    334			port->interrupt_out_urb->transfer_buffer_length = length;
    335
    336			priv->cur_pos = priv->cur_pos + length;
    337			result = usb_submit_urb(port->interrupt_out_urb,
    338					GFP_ATOMIC);
    339			dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result);
    340			todo = priv->filled - priv->cur_pos;
    341
    342			if (todo > 0)
    343				msleep(24);
    344		}
    345
    346		priv->filled = 0;
    347		priv->cur_pos = 0;
    348
    349		/* start reading (except TWIN and KAAN SIM) */
    350		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
    351			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
    352			result = usb_submit_urb(port->interrupt_in_urb,
    353					GFP_ATOMIC);
    354			dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
    355		}
    356	}
    357	return count;
    358}
    359
    360
    361static unsigned int kobil_write_room(struct tty_struct *tty)
    362{
    363	/* FIXME */
    364	return 8;
    365}
    366
    367
    368static int kobil_tiocmget(struct tty_struct *tty)
    369{
    370	struct usb_serial_port *port = tty->driver_data;
    371	struct kobil_private *priv;
    372	int result;
    373	unsigned char *transfer_buffer;
    374	int transfer_buffer_length = 8;
    375
    376	priv = usb_get_serial_port_data(port);
    377	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID
    378			|| priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
    379		/* This device doesn't support ioctl calls */
    380		return -EINVAL;
    381	}
    382
    383	/* allocate memory for transfer buffer */
    384	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
    385	if (!transfer_buffer)
    386		return -ENOMEM;
    387
    388	result = usb_control_msg(port->serial->dev,
    389			  usb_rcvctrlpipe(port->serial->dev, 0),
    390			  SUSBCRequest_GetStatusLineState,
    391			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
    392			  0,
    393			  0,
    394			  transfer_buffer,
    395			  transfer_buffer_length,
    396			  KOBIL_TIMEOUT);
    397
    398	dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n",
    399			result);
    400	if (result < 1) {
    401		if (result >= 0)
    402			result = -EIO;
    403		goto out_free;
    404	}
    405
    406	dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]);
    407
    408	result = 0;
    409	if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
    410		result = TIOCM_DSR;
    411out_free:
    412	kfree(transfer_buffer);
    413	return result;
    414}
    415
    416static int kobil_tiocmset(struct tty_struct *tty,
    417			   unsigned int set, unsigned int clear)
    418{
    419	struct usb_serial_port *port = tty->driver_data;
    420	struct device *dev = &port->dev;
    421	struct kobil_private *priv;
    422	int result;
    423	int dtr = 0;
    424	int rts = 0;
    425
    426	/* FIXME: locking ? */
    427	priv = usb_get_serial_port_data(port);
    428	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID
    429		|| priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
    430		/* This device doesn't support ioctl calls */
    431		return -EINVAL;
    432	}
    433
    434	if (set & TIOCM_RTS)
    435		rts = 1;
    436	if (set & TIOCM_DTR)
    437		dtr = 1;
    438	if (clear & TIOCM_RTS)
    439		rts = 0;
    440	if (clear & TIOCM_DTR)
    441		dtr = 0;
    442
    443	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
    444		if (dtr != 0)
    445			dev_dbg(dev, "%s - Setting DTR\n", __func__);
    446		else
    447			dev_dbg(dev, "%s - Clearing DTR\n", __func__);
    448		result = usb_control_msg(port->serial->dev,
    449			  usb_sndctrlpipe(port->serial->dev, 0),
    450			  SUSBCRequest_SetStatusLinesOrQueues,
    451			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    452			  ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
    453			  0,
    454			  NULL,
    455			  0,
    456			  KOBIL_TIMEOUT);
    457	} else {
    458		if (rts != 0)
    459			dev_dbg(dev, "%s - Setting RTS\n", __func__);
    460		else
    461			dev_dbg(dev, "%s - Clearing RTS\n", __func__);
    462		result = usb_control_msg(port->serial->dev,
    463			usb_sndctrlpipe(port->serial->dev, 0),
    464			SUSBCRequest_SetStatusLinesOrQueues,
    465			USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    466			((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
    467			0,
    468			NULL,
    469			0,
    470			KOBIL_TIMEOUT);
    471	}
    472	dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result);
    473	return (result < 0) ? result : 0;
    474}
    475
    476static void kobil_set_termios(struct tty_struct *tty,
    477			struct usb_serial_port *port, struct ktermios *old)
    478{
    479	struct kobil_private *priv;
    480	int result;
    481	unsigned short urb_val = 0;
    482	int c_cflag = tty->termios.c_cflag;
    483	speed_t speed;
    484
    485	priv = usb_get_serial_port_data(port);
    486	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
    487			priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
    488		/* This device doesn't support ioctl calls */
    489		tty_termios_copy_hw(&tty->termios, old);
    490		return;
    491	}
    492
    493	speed = tty_get_baud_rate(tty);
    494	switch (speed) {
    495	case 1200:
    496		urb_val = SUSBCR_SBR_1200;
    497		break;
    498	default:
    499		speed = 9600;
    500		fallthrough;
    501	case 9600:
    502		urb_val = SUSBCR_SBR_9600;
    503		break;
    504	}
    505	urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits :
    506							SUSBCR_SPASB_1StopBit;
    507	if (c_cflag & PARENB) {
    508		if  (c_cflag & PARODD)
    509			urb_val |= SUSBCR_SPASB_OddParity;
    510		else
    511			urb_val |= SUSBCR_SPASB_EvenParity;
    512	} else
    513		urb_val |= SUSBCR_SPASB_NoParity;
    514	tty->termios.c_cflag &= ~CMSPAR;
    515	tty_encode_baud_rate(tty, speed, speed);
    516
    517	result = usb_control_msg(port->serial->dev,
    518		  usb_sndctrlpipe(port->serial->dev, 0),
    519		  SUSBCRequest_SetBaudRateParityAndStopBits,
    520		  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    521		  urb_val,
    522		  0,
    523		  NULL,
    524		  0,
    525		  KOBIL_TIMEOUT
    526		);
    527	if (result) {
    528		dev_err(&port->dev, "failed to update line settings: %d\n",
    529				result);
    530	}
    531}
    532
    533static int kobil_ioctl(struct tty_struct *tty,
    534					unsigned int cmd, unsigned long arg)
    535{
    536	struct usb_serial_port *port = tty->driver_data;
    537	struct kobil_private *priv = usb_get_serial_port_data(port);
    538	int result;
    539
    540	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
    541			priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
    542		/* This device doesn't support ioctl calls */
    543		return -ENOIOCTLCMD;
    544
    545	switch (cmd) {
    546	case TCFLSH:
    547		result = usb_control_msg(port->serial->dev,
    548			  usb_sndctrlpipe(port->serial->dev, 0),
    549			  SUSBCRequest_Misc,
    550			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
    551			  SUSBCR_MSC_ResetAllQueues,
    552			  0,
    553			  NULL,
    554			  0,
    555			  KOBIL_TIMEOUT
    556			);
    557
    558		dev_dbg(&port->dev,
    559			"%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
    560			__func__, result);
    561		return (result < 0) ? -EIO: 0;
    562	default:
    563		return -ENOIOCTLCMD;
    564	}
    565}
    566
    567module_usb_serial_driver(serial_drivers, id_table);
    568
    569MODULE_AUTHOR(DRIVER_AUTHOR);
    570MODULE_DESCRIPTION(DRIVER_DESC);
    571MODULE_LICENSE("GPL");