1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2001 REINER SCT
6*4882a593Smuzhiyun * Author: Matthias Bruestle
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Contact: support@reiner-sct.com (see MAINTAINERS)
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * This program is largely derived from work by the linux-usb group
11*4882a593Smuzhiyun * and associated source files. Please see the usb/serial files for
12*4882a593Smuzhiyun * individual credits and copyrights.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
15*4882a593Smuzhiyun * patience.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * In case of problems, please write to the contact e-mail address
18*4882a593Smuzhiyun * mentioned above.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Please note that later models of the cyberjack reader family are
21*4882a593Smuzhiyun * supported by a libusb-based userspace device driver.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <linux/kernel.h>
28*4882a593Smuzhiyun #include <linux/errno.h>
29*4882a593Smuzhiyun #include <linux/slab.h>
30*4882a593Smuzhiyun #include <linux/tty.h>
31*4882a593Smuzhiyun #include <linux/tty_driver.h>
32*4882a593Smuzhiyun #include <linux/tty_flip.h>
33*4882a593Smuzhiyun #include <linux/module.h>
34*4882a593Smuzhiyun #include <linux/spinlock.h>
35*4882a593Smuzhiyun #include <linux/uaccess.h>
36*4882a593Smuzhiyun #include <linux/usb.h>
37*4882a593Smuzhiyun #include <linux/usb/serial.h>
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define CYBERJACK_LOCAL_BUF_SIZE 32
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define DRIVER_AUTHOR "Matthias Bruestle"
42*4882a593Smuzhiyun #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define CYBERJACK_VENDOR_ID 0x0C4B
46*4882a593Smuzhiyun #define CYBERJACK_PRODUCT_ID 0x0100
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* Function prototypes */
49*4882a593Smuzhiyun static int cyberjack_port_probe(struct usb_serial_port *port);
50*4882a593Smuzhiyun static int cyberjack_port_remove(struct usb_serial_port *port);
51*4882a593Smuzhiyun static int cyberjack_open(struct tty_struct *tty,
52*4882a593Smuzhiyun struct usb_serial_port *port);
53*4882a593Smuzhiyun static void cyberjack_close(struct usb_serial_port *port);
54*4882a593Smuzhiyun static int cyberjack_write(struct tty_struct *tty,
55*4882a593Smuzhiyun struct usb_serial_port *port, const unsigned char *buf, int count);
56*4882a593Smuzhiyun static int cyberjack_write_room(struct tty_struct *tty);
57*4882a593Smuzhiyun static void cyberjack_read_int_callback(struct urb *urb);
58*4882a593Smuzhiyun static void cyberjack_read_bulk_callback(struct urb *urb);
59*4882a593Smuzhiyun static void cyberjack_write_bulk_callback(struct urb *urb);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static const struct usb_device_id id_table[] = {
62*4882a593Smuzhiyun { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
63*4882a593Smuzhiyun { } /* Terminating entry */
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, id_table);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static struct usb_serial_driver cyberjack_device = {
69*4882a593Smuzhiyun .driver = {
70*4882a593Smuzhiyun .owner = THIS_MODULE,
71*4882a593Smuzhiyun .name = "cyberjack",
72*4882a593Smuzhiyun },
73*4882a593Smuzhiyun .description = "Reiner SCT Cyberjack USB card reader",
74*4882a593Smuzhiyun .id_table = id_table,
75*4882a593Smuzhiyun .num_ports = 1,
76*4882a593Smuzhiyun .num_bulk_out = 1,
77*4882a593Smuzhiyun .port_probe = cyberjack_port_probe,
78*4882a593Smuzhiyun .port_remove = cyberjack_port_remove,
79*4882a593Smuzhiyun .open = cyberjack_open,
80*4882a593Smuzhiyun .close = cyberjack_close,
81*4882a593Smuzhiyun .write = cyberjack_write,
82*4882a593Smuzhiyun .write_room = cyberjack_write_room,
83*4882a593Smuzhiyun .read_int_callback = cyberjack_read_int_callback,
84*4882a593Smuzhiyun .read_bulk_callback = cyberjack_read_bulk_callback,
85*4882a593Smuzhiyun .write_bulk_callback = cyberjack_write_bulk_callback,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static struct usb_serial_driver * const serial_drivers[] = {
89*4882a593Smuzhiyun &cyberjack_device, NULL
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun struct cyberjack_private {
93*4882a593Smuzhiyun spinlock_t lock; /* Lock for SMP */
94*4882a593Smuzhiyun short rdtodo; /* Bytes still to read */
95*4882a593Smuzhiyun unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */
96*4882a593Smuzhiyun short wrfilled; /* Overall data size we already got */
97*4882a593Smuzhiyun short wrsent; /* Data already sent */
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
cyberjack_port_probe(struct usb_serial_port * port)100*4882a593Smuzhiyun static int cyberjack_port_probe(struct usb_serial_port *port)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct cyberjack_private *priv;
103*4882a593Smuzhiyun int result;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
106*4882a593Smuzhiyun if (!priv)
107*4882a593Smuzhiyun return -ENOMEM;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun spin_lock_init(&priv->lock);
110*4882a593Smuzhiyun priv->rdtodo = 0;
111*4882a593Smuzhiyun priv->wrfilled = 0;
112*4882a593Smuzhiyun priv->wrsent = 0;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun usb_set_serial_port_data(port, priv);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
117*4882a593Smuzhiyun if (result)
118*4882a593Smuzhiyun dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
cyberjack_port_remove(struct usb_serial_port * port)123*4882a593Smuzhiyun static int cyberjack_port_remove(struct usb_serial_port *port)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct cyberjack_private *priv;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun usb_kill_urb(port->interrupt_in_urb);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun priv = usb_get_serial_port_data(port);
130*4882a593Smuzhiyun kfree(priv);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
cyberjack_open(struct tty_struct * tty,struct usb_serial_port * port)135*4882a593Smuzhiyun static int cyberjack_open(struct tty_struct *tty,
136*4882a593Smuzhiyun struct usb_serial_port *port)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct cyberjack_private *priv;
139*4882a593Smuzhiyun unsigned long flags;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__);
142*4882a593Smuzhiyun usb_clear_halt(port->serial->dev, port->write_urb->pipe);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun priv = usb_get_serial_port_data(port);
145*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
146*4882a593Smuzhiyun priv->rdtodo = 0;
147*4882a593Smuzhiyun priv->wrfilled = 0;
148*4882a593Smuzhiyun priv->wrsent = 0;
149*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return 0;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
cyberjack_close(struct usb_serial_port * port)154*4882a593Smuzhiyun static void cyberjack_close(struct usb_serial_port *port)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun usb_kill_urb(port->write_urb);
157*4882a593Smuzhiyun usb_kill_urb(port->read_urb);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
cyberjack_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * buf,int count)160*4882a593Smuzhiyun static int cyberjack_write(struct tty_struct *tty,
161*4882a593Smuzhiyun struct usb_serial_port *port, const unsigned char *buf, int count)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct device *dev = &port->dev;
164*4882a593Smuzhiyun struct cyberjack_private *priv = usb_get_serial_port_data(port);
165*4882a593Smuzhiyun unsigned long flags;
166*4882a593Smuzhiyun int result;
167*4882a593Smuzhiyun int wrexpected;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun if (count == 0) {
170*4882a593Smuzhiyun dev_dbg(dev, "%s - write request of 0 bytes\n", __func__);
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (!test_and_clear_bit(0, &port->write_urbs_free)) {
175*4882a593Smuzhiyun dev_dbg(dev, "%s - already writing\n", __func__);
176*4882a593Smuzhiyun return 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (count+priv->wrfilled > sizeof(priv->wrbuf)) {
182*4882a593Smuzhiyun /* To much data for buffer. Reset buffer. */
183*4882a593Smuzhiyun priv->wrfilled = 0;
184*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
185*4882a593Smuzhiyun set_bit(0, &port->write_urbs_free);
186*4882a593Smuzhiyun return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* Copy data */
190*4882a593Smuzhiyun memcpy(priv->wrbuf + priv->wrfilled, buf, count);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled);
193*4882a593Smuzhiyun priv->wrfilled += count;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (priv->wrfilled >= 3) {
196*4882a593Smuzhiyun wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
197*4882a593Smuzhiyun dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected);
198*4882a593Smuzhiyun } else
199*4882a593Smuzhiyun wrexpected = sizeof(priv->wrbuf);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun if (priv->wrfilled >= wrexpected) {
202*4882a593Smuzhiyun /* We have enough data to begin transmission */
203*4882a593Smuzhiyun int length;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__);
206*4882a593Smuzhiyun length = (wrexpected > port->bulk_out_size) ?
207*4882a593Smuzhiyun port->bulk_out_size : wrexpected;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun memcpy(port->write_urb->transfer_buffer, priv->wrbuf, length);
210*4882a593Smuzhiyun priv->wrsent = length;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /* set up our urb */
213*4882a593Smuzhiyun port->write_urb->transfer_buffer_length = length;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* send the data out the bulk port */
216*4882a593Smuzhiyun result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
217*4882a593Smuzhiyun if (result) {
218*4882a593Smuzhiyun dev_err(&port->dev,
219*4882a593Smuzhiyun "%s - failed submitting write urb, error %d\n",
220*4882a593Smuzhiyun __func__, result);
221*4882a593Smuzhiyun /* Throw away data. No better idea what to do with it. */
222*4882a593Smuzhiyun priv->wrfilled = 0;
223*4882a593Smuzhiyun priv->wrsent = 0;
224*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
225*4882a593Smuzhiyun set_bit(0, &port->write_urbs_free);
226*4882a593Smuzhiyun return 0;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
230*4882a593Smuzhiyun dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun if (priv->wrsent >= priv->wrfilled) {
233*4882a593Smuzhiyun dev_dbg(dev, "%s - buffer cleaned\n", __func__);
234*4882a593Smuzhiyun memset(priv->wrbuf, 0, sizeof(priv->wrbuf));
235*4882a593Smuzhiyun priv->wrfilled = 0;
236*4882a593Smuzhiyun priv->wrsent = 0;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun return count;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
cyberjack_write_room(struct tty_struct * tty)245*4882a593Smuzhiyun static int cyberjack_write_room(struct tty_struct *tty)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun /* FIXME: .... */
248*4882a593Smuzhiyun return CYBERJACK_LOCAL_BUF_SIZE;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
cyberjack_read_int_callback(struct urb * urb)251*4882a593Smuzhiyun static void cyberjack_read_int_callback(struct urb *urb)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct usb_serial_port *port = urb->context;
254*4882a593Smuzhiyun struct cyberjack_private *priv = usb_get_serial_port_data(port);
255*4882a593Smuzhiyun struct device *dev = &port->dev;
256*4882a593Smuzhiyun unsigned char *data = urb->transfer_buffer;
257*4882a593Smuzhiyun int status = urb->status;
258*4882a593Smuzhiyun unsigned long flags;
259*4882a593Smuzhiyun int result;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun /* the urb might have been killed. */
262*4882a593Smuzhiyun if (status)
263*4882a593Smuzhiyun return;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun usb_serial_debug_data(dev, __func__, urb->actual_length, data);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* React only to interrupts signaling a bulk_in transfer */
268*4882a593Smuzhiyun if (urb->actual_length == 4 && data[0] == 0x01) {
269*4882a593Smuzhiyun short old_rdtodo;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* This is a announcement of coming bulk_ins. */
272*4882a593Smuzhiyun unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun old_rdtodo = priv->rdtodo;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (old_rdtodo > SHRT_MAX - size) {
279*4882a593Smuzhiyun dev_dbg(dev, "Too many bulk_in urbs to do.\n");
280*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
281*4882a593Smuzhiyun goto resubmit;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* "+=" is probably more fault tolerant than "=" */
285*4882a593Smuzhiyun priv->rdtodo += size;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (!old_rdtodo) {
292*4882a593Smuzhiyun result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
293*4882a593Smuzhiyun if (result)
294*4882a593Smuzhiyun dev_err(dev, "%s - failed resubmitting read urb, error %d\n",
295*4882a593Smuzhiyun __func__, result);
296*4882a593Smuzhiyun dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun resubmit:
301*4882a593Smuzhiyun result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
302*4882a593Smuzhiyun if (result)
303*4882a593Smuzhiyun dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
304*4882a593Smuzhiyun dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
cyberjack_read_bulk_callback(struct urb * urb)307*4882a593Smuzhiyun static void cyberjack_read_bulk_callback(struct urb *urb)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct usb_serial_port *port = urb->context;
310*4882a593Smuzhiyun struct cyberjack_private *priv = usb_get_serial_port_data(port);
311*4882a593Smuzhiyun struct device *dev = &port->dev;
312*4882a593Smuzhiyun unsigned char *data = urb->transfer_buffer;
313*4882a593Smuzhiyun unsigned long flags;
314*4882a593Smuzhiyun short todo;
315*4882a593Smuzhiyun int result;
316*4882a593Smuzhiyun int status = urb->status;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun usb_serial_debug_data(dev, __func__, urb->actual_length, data);
319*4882a593Smuzhiyun if (status) {
320*4882a593Smuzhiyun dev_dbg(dev, "%s - nonzero read bulk status received: %d\n",
321*4882a593Smuzhiyun __func__, status);
322*4882a593Smuzhiyun return;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (urb->actual_length) {
326*4882a593Smuzhiyun tty_insert_flip_string(&port->port, data, urb->actual_length);
327*4882a593Smuzhiyun tty_flip_buffer_push(&port->port);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* Reduce urbs to do by one. */
333*4882a593Smuzhiyun priv->rdtodo -= urb->actual_length;
334*4882a593Smuzhiyun /* Just to be sure */
335*4882a593Smuzhiyun if (priv->rdtodo < 0)
336*4882a593Smuzhiyun priv->rdtodo = 0;
337*4882a593Smuzhiyun todo = priv->rdtodo;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* Continue to read if we have still urbs to do. */
344*4882a593Smuzhiyun if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) {
345*4882a593Smuzhiyun result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
346*4882a593Smuzhiyun if (result)
347*4882a593Smuzhiyun dev_err(dev, "%s - failed resubmitting read urb, error %d\n",
348*4882a593Smuzhiyun __func__, result);
349*4882a593Smuzhiyun dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
cyberjack_write_bulk_callback(struct urb * urb)353*4882a593Smuzhiyun static void cyberjack_write_bulk_callback(struct urb *urb)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct usb_serial_port *port = urb->context;
356*4882a593Smuzhiyun struct cyberjack_private *priv = usb_get_serial_port_data(port);
357*4882a593Smuzhiyun struct device *dev = &port->dev;
358*4882a593Smuzhiyun int status = urb->status;
359*4882a593Smuzhiyun unsigned long flags;
360*4882a593Smuzhiyun bool resubmitted = false;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (status) {
363*4882a593Smuzhiyun dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
364*4882a593Smuzhiyun __func__, status);
365*4882a593Smuzhiyun set_bit(0, &port->write_urbs_free);
366*4882a593Smuzhiyun return;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun /* only do something if we have more data to send */
372*4882a593Smuzhiyun if (priv->wrfilled) {
373*4882a593Smuzhiyun int length, blksize, result;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
378*4882a593Smuzhiyun port->bulk_out_size : (priv->wrfilled - priv->wrsent);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun memcpy(port->write_urb->transfer_buffer,
381*4882a593Smuzhiyun priv->wrbuf + priv->wrsent, length);
382*4882a593Smuzhiyun priv->wrsent += length;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* set up our urb */
385*4882a593Smuzhiyun port->write_urb->transfer_buffer_length = length;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun /* send the data out the bulk port */
388*4882a593Smuzhiyun result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
389*4882a593Smuzhiyun if (result) {
390*4882a593Smuzhiyun dev_err(dev, "%s - failed submitting write urb, error %d\n",
391*4882a593Smuzhiyun __func__, result);
392*4882a593Smuzhiyun /* Throw away data. No better idea what to do with it. */
393*4882a593Smuzhiyun priv->wrfilled = 0;
394*4882a593Smuzhiyun priv->wrsent = 0;
395*4882a593Smuzhiyun goto exit;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun resubmitted = true;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
401*4882a593Smuzhiyun dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (priv->wrsent >= priv->wrfilled ||
406*4882a593Smuzhiyun priv->wrsent >= blksize) {
407*4882a593Smuzhiyun dev_dbg(dev, "%s - buffer cleaned\n", __func__);
408*4882a593Smuzhiyun memset(priv->wrbuf, 0, sizeof(priv->wrbuf));
409*4882a593Smuzhiyun priv->wrfilled = 0;
410*4882a593Smuzhiyun priv->wrsent = 0;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun exit:
415*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
416*4882a593Smuzhiyun if (!resubmitted)
417*4882a593Smuzhiyun set_bit(0, &port->write_urbs_free);
418*4882a593Smuzhiyun usb_serial_port_softint(port);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun module_usb_serial_driver(serial_drivers, id_table);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
424*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
425*4882a593Smuzhiyun MODULE_LICENSE("GPL");
426