162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001 REINER SCT 662306a36Sopenharmony_ci * Author: Matthias Bruestle 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Contact: support@reiner-sct.com (see MAINTAINERS) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is largely derived from work by the linux-usb group 1162306a36Sopenharmony_ci * and associated source files. Please see the usb/serial files for 1262306a36Sopenharmony_ci * individual credits and copyrights. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and 1562306a36Sopenharmony_ci * patience. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * In case of problems, please write to the contact e-mail address 1862306a36Sopenharmony_ci * mentioned above. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Please note that later models of the cyberjack reader family are 2162306a36Sopenharmony_ci * supported by a libusb-based userspace device driver. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/tty.h> 3162306a36Sopenharmony_ci#include <linux/tty_driver.h> 3262306a36Sopenharmony_ci#include <linux/tty_flip.h> 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <linux/spinlock.h> 3562306a36Sopenharmony_ci#include <linux/uaccess.h> 3662306a36Sopenharmony_ci#include <linux/usb.h> 3762306a36Sopenharmony_ci#include <linux/usb/serial.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define CYBERJACK_LOCAL_BUF_SIZE 32 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define DRIVER_AUTHOR "Matthias Bruestle" 4262306a36Sopenharmony_ci#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define CYBERJACK_VENDOR_ID 0x0C4B 4662306a36Sopenharmony_ci#define CYBERJACK_PRODUCT_ID 0x0100 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Function prototypes */ 4962306a36Sopenharmony_cistatic int cyberjack_port_probe(struct usb_serial_port *port); 5062306a36Sopenharmony_cistatic void cyberjack_port_remove(struct usb_serial_port *port); 5162306a36Sopenharmony_cistatic int cyberjack_open(struct tty_struct *tty, 5262306a36Sopenharmony_ci struct usb_serial_port *port); 5362306a36Sopenharmony_cistatic void cyberjack_close(struct usb_serial_port *port); 5462306a36Sopenharmony_cistatic int cyberjack_write(struct tty_struct *tty, 5562306a36Sopenharmony_ci struct usb_serial_port *port, const unsigned char *buf, int count); 5662306a36Sopenharmony_cistatic unsigned int cyberjack_write_room(struct tty_struct *tty); 5762306a36Sopenharmony_cistatic void cyberjack_read_int_callback(struct urb *urb); 5862306a36Sopenharmony_cistatic void cyberjack_read_bulk_callback(struct urb *urb); 5962306a36Sopenharmony_cistatic void cyberjack_write_bulk_callback(struct urb *urb); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 6262306a36Sopenharmony_ci { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) }, 6362306a36Sopenharmony_ci { } /* Terminating entry */ 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic struct usb_serial_driver cyberjack_device = { 6962306a36Sopenharmony_ci .driver = { 7062306a36Sopenharmony_ci .owner = THIS_MODULE, 7162306a36Sopenharmony_ci .name = "cyberjack", 7262306a36Sopenharmony_ci }, 7362306a36Sopenharmony_ci .description = "Reiner SCT Cyberjack USB card reader", 7462306a36Sopenharmony_ci .id_table = id_table, 7562306a36Sopenharmony_ci .num_ports = 1, 7662306a36Sopenharmony_ci .num_bulk_out = 1, 7762306a36Sopenharmony_ci .port_probe = cyberjack_port_probe, 7862306a36Sopenharmony_ci .port_remove = cyberjack_port_remove, 7962306a36Sopenharmony_ci .open = cyberjack_open, 8062306a36Sopenharmony_ci .close = cyberjack_close, 8162306a36Sopenharmony_ci .write = cyberjack_write, 8262306a36Sopenharmony_ci .write_room = cyberjack_write_room, 8362306a36Sopenharmony_ci .read_int_callback = cyberjack_read_int_callback, 8462306a36Sopenharmony_ci .read_bulk_callback = cyberjack_read_bulk_callback, 8562306a36Sopenharmony_ci .write_bulk_callback = cyberjack_write_bulk_callback, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 8962306a36Sopenharmony_ci &cyberjack_device, NULL 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct cyberjack_private { 9362306a36Sopenharmony_ci spinlock_t lock; /* Lock for SMP */ 9462306a36Sopenharmony_ci short rdtodo; /* Bytes still to read */ 9562306a36Sopenharmony_ci unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ 9662306a36Sopenharmony_ci short wrfilled; /* Overall data size we already got */ 9762306a36Sopenharmony_ci short wrsent; /* Data already sent */ 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int cyberjack_port_probe(struct usb_serial_port *port) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct cyberjack_private *priv; 10362306a36Sopenharmony_ci int result; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); 10662306a36Sopenharmony_ci if (!priv) 10762306a36Sopenharmony_ci return -ENOMEM; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci spin_lock_init(&priv->lock); 11062306a36Sopenharmony_ci priv->rdtodo = 0; 11162306a36Sopenharmony_ci priv->wrfilled = 0; 11262306a36Sopenharmony_ci priv->wrsent = 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci usb_set_serial_port_data(port, priv); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 11762306a36Sopenharmony_ci if (result) 11862306a36Sopenharmony_ci dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void cyberjack_port_remove(struct usb_serial_port *port) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct cyberjack_private *priv; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci priv = usb_get_serial_port_data(port); 13062306a36Sopenharmony_ci kfree(priv); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int cyberjack_open(struct tty_struct *tty, 13462306a36Sopenharmony_ci struct usb_serial_port *port) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct cyberjack_private *priv; 13762306a36Sopenharmony_ci unsigned long flags; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__); 14062306a36Sopenharmony_ci usb_clear_halt(port->serial->dev, port->write_urb->pipe); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci priv = usb_get_serial_port_data(port); 14362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 14462306a36Sopenharmony_ci priv->rdtodo = 0; 14562306a36Sopenharmony_ci priv->wrfilled = 0; 14662306a36Sopenharmony_ci priv->wrsent = 0; 14762306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void cyberjack_close(struct usb_serial_port *port) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci usb_kill_urb(port->write_urb); 15562306a36Sopenharmony_ci usb_kill_urb(port->read_urb); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int cyberjack_write(struct tty_struct *tty, 15962306a36Sopenharmony_ci struct usb_serial_port *port, const unsigned char *buf, int count) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct device *dev = &port->dev; 16262306a36Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 16362306a36Sopenharmony_ci unsigned long flags; 16462306a36Sopenharmony_ci int result; 16562306a36Sopenharmony_ci int wrexpected; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (count == 0) { 16862306a36Sopenharmony_ci dev_dbg(dev, "%s - write request of 0 bytes\n", __func__); 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!test_and_clear_bit(0, &port->write_urbs_free)) { 17362306a36Sopenharmony_ci dev_dbg(dev, "%s - already writing\n", __func__); 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (count+priv->wrfilled > sizeof(priv->wrbuf)) { 18062306a36Sopenharmony_ci /* To much data for buffer. Reset buffer. */ 18162306a36Sopenharmony_ci priv->wrfilled = 0; 18262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 18362306a36Sopenharmony_ci set_bit(0, &port->write_urbs_free); 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Copy data */ 18862306a36Sopenharmony_ci memcpy(priv->wrbuf + priv->wrfilled, buf, count); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled); 19162306a36Sopenharmony_ci priv->wrfilled += count; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (priv->wrfilled >= 3) { 19462306a36Sopenharmony_ci wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; 19562306a36Sopenharmony_ci dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected); 19662306a36Sopenharmony_ci } else 19762306a36Sopenharmony_ci wrexpected = sizeof(priv->wrbuf); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (priv->wrfilled >= wrexpected) { 20062306a36Sopenharmony_ci /* We have enough data to begin transmission */ 20162306a36Sopenharmony_ci int length; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__); 20462306a36Sopenharmony_ci length = (wrexpected > port->bulk_out_size) ? 20562306a36Sopenharmony_ci port->bulk_out_size : wrexpected; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci memcpy(port->write_urb->transfer_buffer, priv->wrbuf, length); 20862306a36Sopenharmony_ci priv->wrsent = length; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* set up our urb */ 21162306a36Sopenharmony_ci port->write_urb->transfer_buffer_length = length; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* send the data out the bulk port */ 21462306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 21562306a36Sopenharmony_ci if (result) { 21662306a36Sopenharmony_ci dev_err(&port->dev, 21762306a36Sopenharmony_ci "%s - failed submitting write urb, error %d\n", 21862306a36Sopenharmony_ci __func__, result); 21962306a36Sopenharmony_ci /* Throw away data. No better idea what to do with it. */ 22062306a36Sopenharmony_ci priv->wrfilled = 0; 22162306a36Sopenharmony_ci priv->wrsent = 0; 22262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 22362306a36Sopenharmony_ci set_bit(0, &port->write_urbs_free); 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); 22862306a36Sopenharmony_ci dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (priv->wrsent >= priv->wrfilled) { 23162306a36Sopenharmony_ci dev_dbg(dev, "%s - buffer cleaned\n", __func__); 23262306a36Sopenharmony_ci memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); 23362306a36Sopenharmony_ci priv->wrfilled = 0; 23462306a36Sopenharmony_ci priv->wrsent = 0; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return count; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic unsigned int cyberjack_write_room(struct tty_struct *tty) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci /* FIXME: .... */ 24662306a36Sopenharmony_ci return CYBERJACK_LOCAL_BUF_SIZE; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void cyberjack_read_int_callback(struct urb *urb) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 25262306a36Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 25362306a36Sopenharmony_ci struct device *dev = &port->dev; 25462306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 25562306a36Sopenharmony_ci int status = urb->status; 25662306a36Sopenharmony_ci unsigned long flags; 25762306a36Sopenharmony_ci int result; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* the urb might have been killed. */ 26062306a36Sopenharmony_ci if (status) 26162306a36Sopenharmony_ci return; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci usb_serial_debug_data(dev, __func__, urb->actual_length, data); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* React only to interrupts signaling a bulk_in transfer */ 26662306a36Sopenharmony_ci if (urb->actual_length == 4 && data[0] == 0x01) { 26762306a36Sopenharmony_ci short old_rdtodo; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* This is a announcement of coming bulk_ins. */ 27062306a36Sopenharmony_ci unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci old_rdtodo = priv->rdtodo; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (old_rdtodo > SHRT_MAX - size) { 27762306a36Sopenharmony_ci dev_dbg(dev, "Too many bulk_in urbs to do.\n"); 27862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 27962306a36Sopenharmony_ci goto resubmit; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* "+=" is probably more fault tolerant than "=" */ 28362306a36Sopenharmony_ci priv->rdtodo += size; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!old_rdtodo) { 29062306a36Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 29162306a36Sopenharmony_ci if (result) 29262306a36Sopenharmony_ci dev_err(dev, "%s - failed resubmitting read urb, error %d\n", 29362306a36Sopenharmony_ci __func__, result); 29462306a36Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciresubmit: 29962306a36Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 30062306a36Sopenharmony_ci if (result) 30162306a36Sopenharmony_ci dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); 30262306a36Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic void cyberjack_read_bulk_callback(struct urb *urb) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 30862306a36Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 30962306a36Sopenharmony_ci struct device *dev = &port->dev; 31062306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 31162306a36Sopenharmony_ci unsigned long flags; 31262306a36Sopenharmony_ci short todo; 31362306a36Sopenharmony_ci int result; 31462306a36Sopenharmony_ci int status = urb->status; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci usb_serial_debug_data(dev, __func__, urb->actual_length, data); 31762306a36Sopenharmony_ci if (status) { 31862306a36Sopenharmony_ci dev_dbg(dev, "%s - nonzero read bulk status received: %d\n", 31962306a36Sopenharmony_ci __func__, status); 32062306a36Sopenharmony_ci return; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (urb->actual_length) { 32462306a36Sopenharmony_ci tty_insert_flip_string(&port->port, data, urb->actual_length); 32562306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Reduce urbs to do by one. */ 33162306a36Sopenharmony_ci priv->rdtodo -= urb->actual_length; 33262306a36Sopenharmony_ci /* Just to be sure */ 33362306a36Sopenharmony_ci if (priv->rdtodo < 0) 33462306a36Sopenharmony_ci priv->rdtodo = 0; 33562306a36Sopenharmony_ci todo = priv->rdtodo; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Continue to read if we have still urbs to do. */ 34262306a36Sopenharmony_ci if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { 34362306a36Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 34462306a36Sopenharmony_ci if (result) 34562306a36Sopenharmony_ci dev_err(dev, "%s - failed resubmitting read urb, error %d\n", 34662306a36Sopenharmony_ci __func__, result); 34762306a36Sopenharmony_ci dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void cyberjack_write_bulk_callback(struct urb *urb) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 35462306a36Sopenharmony_ci struct cyberjack_private *priv = usb_get_serial_port_data(port); 35562306a36Sopenharmony_ci struct device *dev = &port->dev; 35662306a36Sopenharmony_ci int status = urb->status; 35762306a36Sopenharmony_ci unsigned long flags; 35862306a36Sopenharmony_ci bool resubmitted = false; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (status) { 36162306a36Sopenharmony_ci dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", 36262306a36Sopenharmony_ci __func__, status); 36362306a36Sopenharmony_ci set_bit(0, &port->write_urbs_free); 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* only do something if we have more data to send */ 37062306a36Sopenharmony_ci if (priv->wrfilled) { 37162306a36Sopenharmony_ci int length, blksize, result; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? 37662306a36Sopenharmony_ci port->bulk_out_size : (priv->wrfilled - priv->wrsent); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci memcpy(port->write_urb->transfer_buffer, 37962306a36Sopenharmony_ci priv->wrbuf + priv->wrsent, length); 38062306a36Sopenharmony_ci priv->wrsent += length; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* set up our urb */ 38362306a36Sopenharmony_ci port->write_urb->transfer_buffer_length = length; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* send the data out the bulk port */ 38662306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 38762306a36Sopenharmony_ci if (result) { 38862306a36Sopenharmony_ci dev_err(dev, "%s - failed submitting write urb, error %d\n", 38962306a36Sopenharmony_ci __func__, result); 39062306a36Sopenharmony_ci /* Throw away data. No better idea what to do with it. */ 39162306a36Sopenharmony_ci priv->wrfilled = 0; 39262306a36Sopenharmony_ci priv->wrsent = 0; 39362306a36Sopenharmony_ci goto exit; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci resubmitted = true; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); 39962306a36Sopenharmony_ci dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (priv->wrsent >= priv->wrfilled || 40462306a36Sopenharmony_ci priv->wrsent >= blksize) { 40562306a36Sopenharmony_ci dev_dbg(dev, "%s - buffer cleaned\n", __func__); 40662306a36Sopenharmony_ci memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); 40762306a36Sopenharmony_ci priv->wrfilled = 0; 40862306a36Sopenharmony_ci priv->wrsent = 0; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ciexit: 41362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 41462306a36Sopenharmony_ci if (!resubmitted) 41562306a36Sopenharmony_ci set_bit(0, &port->write_urbs_free); 41662306a36Sopenharmony_ci usb_serial_port_softint(port); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 42262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 42362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 424