18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001 REINER SCT 68c2ecf20Sopenharmony_ci * Author: Matthias Bruestle 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Contact: support@reiner-sct.com (see MAINTAINERS) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is largely derived from work by the linux-usb group 118c2ecf20Sopenharmony_ci * and associated source files. Please see the usb/serial files for 128c2ecf20Sopenharmony_ci * individual credits and copyrights. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and 158c2ecf20Sopenharmony_ci * patience. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * In case of problems, please write to the contact e-mail address 188c2ecf20Sopenharmony_ci * mentioned above. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Please note that later models of the cyberjack reader family are 218c2ecf20Sopenharmony_ci * supported by a libusb-based userspace device driver. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/kernel.h> 288c2ecf20Sopenharmony_ci#include <linux/errno.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/tty.h> 318c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 328c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 358c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 368c2ecf20Sopenharmony_ci#include <linux/usb.h> 378c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define CYBERJACK_LOCAL_BUF_SIZE 32 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Matthias Bruestle" 428c2ecf20Sopenharmony_ci#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define CYBERJACK_VENDOR_ID 0x0C4B 468c2ecf20Sopenharmony_ci#define CYBERJACK_PRODUCT_ID 0x0100 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Function prototypes */ 498c2ecf20Sopenharmony_cistatic int cyberjack_port_probe(struct usb_serial_port *port); 508c2ecf20Sopenharmony_cistatic int cyberjack_port_remove(struct usb_serial_port *port); 518c2ecf20Sopenharmony_cistatic int cyberjack_open(struct tty_struct *tty, 528c2ecf20Sopenharmony_ci struct usb_serial_port *port); 538c2ecf20Sopenharmony_cistatic void cyberjack_close(struct usb_serial_port *port); 548c2ecf20Sopenharmony_cistatic int cyberjack_write(struct tty_struct *tty, 558c2ecf20Sopenharmony_ci struct usb_serial_port *port, const unsigned char *buf, int count); 568c2ecf20Sopenharmony_cistatic int cyberjack_write_room(struct tty_struct *tty); 578c2ecf20Sopenharmony_cistatic void cyberjack_read_int_callback(struct urb *urb); 588c2ecf20Sopenharmony_cistatic void cyberjack_read_bulk_callback(struct urb *urb); 598c2ecf20Sopenharmony_cistatic void cyberjack_write_bulk_callback(struct urb *urb); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 628c2ecf20Sopenharmony_ci { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) }, 638c2ecf20Sopenharmony_ci { } /* Terminating entry */ 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct usb_serial_driver cyberjack_device = { 698c2ecf20Sopenharmony_ci .driver = { 708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 718c2ecf20Sopenharmony_ci .name = "cyberjack", 728c2ecf20Sopenharmony_ci }, 738c2ecf20Sopenharmony_ci .description = "Reiner SCT Cyberjack USB card reader", 748c2ecf20Sopenharmony_ci .id_table = id_table, 758c2ecf20Sopenharmony_ci .num_ports = 1, 768c2ecf20Sopenharmony_ci .num_bulk_out = 1, 778c2ecf20Sopenharmony_ci .port_probe = cyberjack_port_probe, 788c2ecf20Sopenharmony_ci .port_remove = cyberjack_port_remove, 798c2ecf20Sopenharmony_ci .open = cyberjack_open, 808c2ecf20Sopenharmony_ci .close = cyberjack_close, 818c2ecf20Sopenharmony_ci .write = cyberjack_write, 828c2ecf20Sopenharmony_ci .write_room = cyberjack_write_room, 838c2ecf20Sopenharmony_ci .read_int_callback = cyberjack_read_int_callback, 848c2ecf20Sopenharmony_ci .read_bulk_callback = cyberjack_read_bulk_callback, 858c2ecf20Sopenharmony_ci .write_bulk_callback = cyberjack_write_bulk_callback, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 898c2ecf20Sopenharmony_ci &cyberjack_device, NULL 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct cyberjack_private { 938c2ecf20Sopenharmony_ci spinlock_t lock; /* Lock for SMP */ 948c2ecf20Sopenharmony_ci short rdtodo; /* Bytes still to read */ 958c2ecf20Sopenharmony_ci unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ 968c2ecf20Sopenharmony_ci short wrfilled; /* Overall data size we already got */ 978c2ecf20Sopenharmony_ci short wrsent; /* Data already sent */ 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int cyberjack_port_probe(struct usb_serial_port *port) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct cyberjack_private *priv; 1038c2ecf20Sopenharmony_ci int result; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); 1068c2ecf20Sopenharmony_ci if (!priv) 1078c2ecf20Sopenharmony_ci return -ENOMEM; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 1108c2ecf20Sopenharmony_ci priv->rdtodo = 0; 1118c2ecf20Sopenharmony_ci priv->wrfilled = 0; 1128c2ecf20Sopenharmony_ci priv->wrsent = 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 1178c2ecf20Sopenharmony_ci if (result) 1188c2ecf20Sopenharmony_ci dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int cyberjack_port_remove(struct usb_serial_port *port) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct cyberjack_private *priv; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 1308c2ecf20Sopenharmony_ci kfree(priv); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int cyberjack_open(struct tty_struct *tty, 1368c2ecf20Sopenharmony_ci struct usb_serial_port *port) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct cyberjack_private *priv; 1398c2ecf20Sopenharmony_ci unsigned long flags; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__); 1428c2ecf20Sopenharmony_ci usb_clear_halt(port->serial->dev, port->write_urb->pipe); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 1458c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1468c2ecf20Sopenharmony_ci priv->rdtodo = 0; 1478c2ecf20Sopenharmony_ci priv->wrfilled = 0; 1488c2ecf20Sopenharmony_ci priv->wrsent = 0; 1498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void cyberjack_close(struct usb_serial_port *port) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci usb_kill_urb(port->write_urb); 1578c2ecf20Sopenharmony_ci usb_kill_urb(port->read_urb); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int cyberjack_write(struct tty_struct *tty, 1618c2ecf20Sopenharmony_ci struct usb_serial_port *port, const unsigned char *buf, int count) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct device *dev = &port->dev; 1648c2ecf20Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 1658c2ecf20Sopenharmony_ci unsigned long flags; 1668c2ecf20Sopenharmony_ci int result; 1678c2ecf20Sopenharmony_ci int wrexpected; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (count == 0) { 1708c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - write request of 0 bytes\n", __func__); 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!test_and_clear_bit(0, &port->write_urbs_free)) { 1758c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - already writing\n", __func__); 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (count+priv->wrfilled > sizeof(priv->wrbuf)) { 1828c2ecf20Sopenharmony_ci /* To much data for buffer. Reset buffer. */ 1838c2ecf20Sopenharmony_ci priv->wrfilled = 0; 1848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1858c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Copy data */ 1908c2ecf20Sopenharmony_ci memcpy(priv->wrbuf + priv->wrfilled, buf, count); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled); 1938c2ecf20Sopenharmony_ci priv->wrfilled += count; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (priv->wrfilled >= 3) { 1968c2ecf20Sopenharmony_ci wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; 1978c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected); 1988c2ecf20Sopenharmony_ci } else 1998c2ecf20Sopenharmony_ci wrexpected = sizeof(priv->wrbuf); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (priv->wrfilled >= wrexpected) { 2028c2ecf20Sopenharmony_ci /* We have enough data to begin transmission */ 2038c2ecf20Sopenharmony_ci int length; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__); 2068c2ecf20Sopenharmony_ci length = (wrexpected > port->bulk_out_size) ? 2078c2ecf20Sopenharmony_ci port->bulk_out_size : wrexpected; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci memcpy(port->write_urb->transfer_buffer, priv->wrbuf, length); 2108c2ecf20Sopenharmony_ci priv->wrsent = length; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* set up our urb */ 2138c2ecf20Sopenharmony_ci port->write_urb->transfer_buffer_length = length; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* send the data out the bulk port */ 2168c2ecf20Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 2178c2ecf20Sopenharmony_ci if (result) { 2188c2ecf20Sopenharmony_ci dev_err(&port->dev, 2198c2ecf20Sopenharmony_ci "%s - failed submitting write urb, error %d\n", 2208c2ecf20Sopenharmony_ci __func__, result); 2218c2ecf20Sopenharmony_ci /* Throw away data. No better idea what to do with it. */ 2228c2ecf20Sopenharmony_ci priv->wrfilled = 0; 2238c2ecf20Sopenharmony_ci priv->wrsent = 0; 2248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2258c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); 2308c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (priv->wrsent >= priv->wrfilled) { 2338c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - buffer cleaned\n", __func__); 2348c2ecf20Sopenharmony_ci memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); 2358c2ecf20Sopenharmony_ci priv->wrfilled = 0; 2368c2ecf20Sopenharmony_ci priv->wrsent = 0; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return count; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int cyberjack_write_room(struct tty_struct *tty) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci /* FIXME: .... */ 2488c2ecf20Sopenharmony_ci return CYBERJACK_LOCAL_BUF_SIZE; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void cyberjack_read_int_callback(struct urb *urb) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 2548c2ecf20Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 2558c2ecf20Sopenharmony_ci struct device *dev = &port->dev; 2568c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 2578c2ecf20Sopenharmony_ci int status = urb->status; 2588c2ecf20Sopenharmony_ci unsigned long flags; 2598c2ecf20Sopenharmony_ci int result; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* the urb might have been killed. */ 2628c2ecf20Sopenharmony_ci if (status) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci usb_serial_debug_data(dev, __func__, urb->actual_length, data); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* React only to interrupts signaling a bulk_in transfer */ 2688c2ecf20Sopenharmony_ci if (urb->actual_length == 4 && data[0] == 0x01) { 2698c2ecf20Sopenharmony_ci short old_rdtodo; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* This is a announcement of coming bulk_ins. */ 2728c2ecf20Sopenharmony_ci unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci old_rdtodo = priv->rdtodo; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (old_rdtodo > SHRT_MAX - size) { 2798c2ecf20Sopenharmony_ci dev_dbg(dev, "Too many bulk_in urbs to do.\n"); 2808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2818c2ecf20Sopenharmony_ci goto resubmit; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* "+=" is probably more fault tolerant than "=" */ 2858c2ecf20Sopenharmony_ci priv->rdtodo += size; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!old_rdtodo) { 2928c2ecf20Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 2938c2ecf20Sopenharmony_ci if (result) 2948c2ecf20Sopenharmony_ci dev_err(dev, "%s - failed resubmitting read urb, error %d\n", 2958c2ecf20Sopenharmony_ci __func__, result); 2968c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciresubmit: 3018c2ecf20Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 3028c2ecf20Sopenharmony_ci if (result) 3038c2ecf20Sopenharmony_ci dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); 3048c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void cyberjack_read_bulk_callback(struct urb *urb) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 3108c2ecf20Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 3118c2ecf20Sopenharmony_ci struct device *dev = &port->dev; 3128c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 3138c2ecf20Sopenharmony_ci unsigned long flags; 3148c2ecf20Sopenharmony_ci short todo; 3158c2ecf20Sopenharmony_ci int result; 3168c2ecf20Sopenharmony_ci int status = urb->status; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci usb_serial_debug_data(dev, __func__, urb->actual_length, data); 3198c2ecf20Sopenharmony_ci if (status) { 3208c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - nonzero read bulk status received: %d\n", 3218c2ecf20Sopenharmony_ci __func__, status); 3228c2ecf20Sopenharmony_ci return; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (urb->actual_length) { 3268c2ecf20Sopenharmony_ci tty_insert_flip_string(&port->port, data, urb->actual_length); 3278c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Reduce urbs to do by one. */ 3338c2ecf20Sopenharmony_ci priv->rdtodo -= urb->actual_length; 3348c2ecf20Sopenharmony_ci /* Just to be sure */ 3358c2ecf20Sopenharmony_ci if (priv->rdtodo < 0) 3368c2ecf20Sopenharmony_ci priv->rdtodo = 0; 3378c2ecf20Sopenharmony_ci todo = priv->rdtodo; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Continue to read if we have still urbs to do. */ 3448c2ecf20Sopenharmony_ci if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { 3458c2ecf20Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 3468c2ecf20Sopenharmony_ci if (result) 3478c2ecf20Sopenharmony_ci dev_err(dev, "%s - failed resubmitting read urb, error %d\n", 3488c2ecf20Sopenharmony_ci __func__, result); 3498c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic void cyberjack_write_bulk_callback(struct urb *urb) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 3568c2ecf20Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 3578c2ecf20Sopenharmony_ci struct device *dev = &port->dev; 3588c2ecf20Sopenharmony_ci int status = urb->status; 3598c2ecf20Sopenharmony_ci unsigned long flags; 3608c2ecf20Sopenharmony_ci bool resubmitted = false; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (status) { 3638c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", 3648c2ecf20Sopenharmony_ci __func__, status); 3658c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 3668c2ecf20Sopenharmony_ci return; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* only do something if we have more data to send */ 3728c2ecf20Sopenharmony_ci if (priv->wrfilled) { 3738c2ecf20Sopenharmony_ci int length, blksize, result; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? 3788c2ecf20Sopenharmony_ci port->bulk_out_size : (priv->wrfilled - priv->wrsent); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci memcpy(port->write_urb->transfer_buffer, 3818c2ecf20Sopenharmony_ci priv->wrbuf + priv->wrsent, length); 3828c2ecf20Sopenharmony_ci priv->wrsent += length; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* set up our urb */ 3858c2ecf20Sopenharmony_ci port->write_urb->transfer_buffer_length = length; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* send the data out the bulk port */ 3888c2ecf20Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 3898c2ecf20Sopenharmony_ci if (result) { 3908c2ecf20Sopenharmony_ci dev_err(dev, "%s - failed submitting write urb, error %d\n", 3918c2ecf20Sopenharmony_ci __func__, result); 3928c2ecf20Sopenharmony_ci /* Throw away data. No better idea what to do with it. */ 3938c2ecf20Sopenharmony_ci priv->wrfilled = 0; 3948c2ecf20Sopenharmony_ci priv->wrsent = 0; 3958c2ecf20Sopenharmony_ci goto exit; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci resubmitted = true; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); 4018c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (priv->wrsent >= priv->wrfilled || 4068c2ecf20Sopenharmony_ci priv->wrsent >= blksize) { 4078c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - buffer cleaned\n", __func__); 4088c2ecf20Sopenharmony_ci memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); 4098c2ecf20Sopenharmony_ci priv->wrfilled = 0; 4108c2ecf20Sopenharmony_ci priv->wrsent = 0; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciexit: 4158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4168c2ecf20Sopenharmony_ci if (!resubmitted) 4178c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 4188c2ecf20Sopenharmony_ci usb_serial_port_softint(port); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 4248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 426