linux/drivers/usb/serial/kobil_sct.c
<<
>>
Prefs
   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");
 572