| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver | |||
| 3 | * | |||
| 4 | * Copyright (C) 2001 REINER SCT | |||
| 5 | * Author: Matthias Bruestle | |||
| 6 | * | |||
| 7 | * Contact: support@reiner-sct.com (see MAINTAINERS) | |||
| 8 | * | |||
| 9 | * This program is largely derived from work by the linux-usb group | |||
| 10 | * and associated source files. Please see the usb/serial files for | |||
| 11 | * individual credits and copyrights. | |||
| 12 | * | |||
| 13 | * This program is free software; you can redistribute it and/or modify | |||
| 14 | * it under the terms of the GNU General Public License as published by | |||
| 15 | * the Free Software Foundation; either version 2 of the License, or | |||
| 16 | * (at your option) any later version. | |||
| 17 | * | |||
| 18 | * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and | |||
| 19 | * patience. | |||
| 20 | * | |||
| 21 | * In case of problems, please write to the contact e-mail address | |||
| 22 | * mentioned above. | |||
| 23 | * | |||
| 24 | * Please note that later models of the cyberjack reader family are | |||
| 25 | * supported by a libusb-based userspace device driver. | |||
| 26 | * | |||
| 27 | * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux | |||
| 28 | */ | |||
| 29 | ||||
| 30 | ||||
| 31 | #include <linux/config.h> | |||
| 32 | #include <linux/kernel.h> | |||
| 33 | #include <linux/errno.h> | |||
| 34 | #include <linux/init.h> | |||
| 35 | #include <linux/slab.h> | |||
| 36 | #include <linux/tty.h> | |||
| 37 | #include <linux/tty_driver.h> | |||
| 38 | #include <linux/tty_flip.h> | |||
| 39 | #include <linux/module.h> | |||
| 40 | #include <linux/spinlock.h> | |||
| 41 | #include <asm/uaccess.h> | |||
| 42 | #include <linux/usb.h> | |||
| 43 | #include "usb-serial.h" | |||
| 44 | ||||
| 45 | #define CYBERJACK_LOCAL_BUF_SIZE 32 | |||
| 46 | ||||
| 47 | static int debug; | |||
| 48 | ||||
| 49 | /* | |||
| 50 | * Version Information | |||
| 51 | */ | |||
| 52 | #define DRIVER_VERSION "v1.01" | |||
| 53 | #define DRIVER_AUTHOR "Matthias Bruestle" | |||
| 54 | #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" | |||
| 55 | ||||
| 56 | ||||
| 57 | #define CYBERJACK_VENDOR_ID 0x0C4B | |||
| 58 | #define CYBERJACK_PRODUCT_ID 0x0100 | |||
| 59 | ||||
| 60 | /* Function prototypes */ | |||
| 61 | static int cyberjack_startup (struct usb_serial *serial); | |||
| 62 | static void cyberjack_shutdown (struct usb_serial *serial); | |||
| 63 | static int cyberjack_open (struct usb_serial_port *port, struct file *filp); | |||
| 64 | static void cyberjack_close (struct usb_serial_port *port, struct file *filp); | |||
| 65 | static int cyberjack_write (struct usb_serial_port *port, const unsigned char *buf, int count); | |||
| 66 | static int cyberjack_write_room( struct usb_serial_port *port ); | |||
| 67 | static void cyberjack_read_int_callback (struct urb *urb, struct pt_regs *regs); | |||
| 68 | static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs); | |||
| 69 | static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs); | |||
| 70 | ||||
| 71 | static struct usb_device_id id_table [] = { | |||
| 72 | { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) }, | |||
| 73 | { } /* Terminating entry */ | |||
| 74 | }; | |||
| 75 | ||||
| 76 | MODULE_DEVICE_TABLE (usb, id_table); | |||
| 77 | ||||
| 78 | static struct usb_driver cyberjack_driver = { | |||
| 79 | .name = "cyberjack", | |||
| 80 | .probe = usb_serial_probe, | |||
| 81 | .disconnect = usb_serial_disconnect, | |||
| 82 | .id_table = id_table, | |||
| 83 | .no_dynamic_id = 1, | |||
| 84 | }; | |||
| 85 | ||||
| 86 | static struct usb_serial_driver cyberjack_device = { | |||
| 87 | .driver = { | |||
| 88 | .owner = THIS_MODULE, | |||
| 89 | .name = "cyberjack", | |||
| 90 | }, | |||
| 91 | .description = "Reiner SCT Cyberjack USB card reader", | |||
| 92 | .id_table = id_table, | |||
| 93 | .num_interrupt_in = 1, | |||
| 94 | .num_bulk_in = 1, | |||
| 95 | .num_bulk_out = 1, | |||
| 96 | .num_ports = 1, | |||
| 97 | .attach = cyberjack_startup, | |||
| 98 | .shutdown = cyberjack_shutdown, | |||
| 99 | .open = cyberjack_open, | |||
| 100 | .close = cyberjack_close, | |||
| 101 | .write = cyberjack_write, | |||
| 102 | .write_room = cyberjack_write_room, | |||
| 103 | .read_int_callback = cyberjack_read_int_callback, | |||
| 104 | .read_bulk_callback = cyberjack_read_bulk_callback, | |||
| 105 | .write_bulk_callback = cyberjack_write_bulk_callback, | |||
| 106 | }; | |||
| 107 | ||||
| 108 | struct cyberjack_private { | |||
| 109 | spinlock_t lock; /* Lock for SMP */ | |||
| 110 | short rdtodo; /* Bytes still to read */ | |||
| 111 | unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ | |||
| 112 | short wrfilled; /* Overall data size we already got */ | |||
| 113 | short wrsent; /* Data already sent */ | |||
| 114 | }; | |||
| 115 | ||||
| 116 | /* do some startup allocations not currently performed by usb_serial_probe() */ | |||
| 0 | 0 | - | 117 | static int cyberjack_startup (struct usb_serial *serial) |
| 118 | { | |||
| 119 | struct cyberjack_private *priv; | |||
| 120 | int i; | |||
| 121 | ||||
| 122 | dbg("%s", __FUNCTION__); | |||
| 0 | 0 | - | 122 | if (debug) |
| 0 | 0 | - | 122 | do-while (0) |
| 123 | ||||
| 124 | /* allocate the private data structure */ | |||
| 125 | priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); | |||
| 0 | 0 | - | 126 | if (!priv) |
| 0 | - | 127 | return -ENOMEM; | |
| 128 | ||||
| 129 | /* set initial values */ | |||
| 130 | spin_lock_init(&priv->lock); | |||
| 0 | 0 | - | 130 | do-while (0) |
| 131 | priv->rdtodo = 0; | |||
| 132 | priv->wrfilled = 0; | |||
| 133 | priv->wrsent = 0; | |||
| 134 | usb_set_serial_port_data(serial->port[0], priv); | |||
| 135 | ||||
| 136 | init_waitqueue_head(&serial->port[0]->write_wait); | |||
| 137 | ||||
| 0 | 0 | - | 138 | for (i = 0; i < serial->num_ports; ++i) { |
| 139 | int result; | |||
| 140 | serial->port[i]->interrupt_in_urb->dev = serial->dev; | |||
| 141 | result = usb_submit_urb(serial->port[i]->interrupt_in_urb, | |||
| 142 | GFP_KERNEL); | |||
| 0 | 0 | - | 143 | if (result) |
| 144 | err(" usb_submit_urb(read int) failed"); | |||
| 145 | dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); | |||
| 0 | 0 | - | 145 | if (debug) |
| 0 | 0 | - | 145 | do-while (0) |
| 146 | } | |||
| 147 | ||||
| 0 | - | 148 | return( 0 ); | |
| 149 | } | |||
| 150 | ||||
| 0 | 0 | - | 151 | static void cyberjack_shutdown (struct usb_serial *serial) |
| 152 | { | |||
| 153 | int i; | |||
| 154 | ||||
| 155 | dbg("%s", __FUNCTION__); | |||
| 0 | 0 | - | 155 | if (debug) |
| 0 | 0 | - | 155 | do-while (0) |
| 156 | ||||
| 0 | 0 | - | 157 | for (i=0; i < serial->num_ports; ++i) { |
| 158 | usb_kill_urb(serial->port[i]->interrupt_in_urb); | |||
| 159 | /* My special items, the standard routines free my urbs */ | |||
| 160 | kfree(usb_get_serial_port_data(serial->port[i])); | |||
| 161 | usb_set_serial_port_data(serial->port[i], NULL); | |||
| 162 | } | |||
| 163 | } | |||
| 164 | ||||
| 0 | 0 | - | 165 | static int cyberjack_open (struct usb_serial_port *port, struct file *filp) |
| 166 | { | |||
| 167 | struct cyberjack_private *priv; | |||
| 168 | unsigned long flags; | |||
| 169 | int result = 0; | |||
| 170 | ||||
| 171 | dbg("%s - port %d", __FUNCTION__, port->number); | |||
| 0 | 0 | - | 171 | if (debug) |
| 0 | 0 | - | 171 | do-while (0) |
| 172 | ||||
| 173 | dbg("%s - usb_clear_halt", __FUNCTION__ ); | |||
| 0 | 0 | - | 173 | if (debug) |
| 0 | 0 | - | 173 | do-while (0) |
| 174 | usb_clear_halt(port->serial->dev, port->write_urb->pipe); | |||
| 175 | ||||
| 176 | /* force low_latency on so that our tty_push actually forces | |||
| 177 | * the data through, otherwise it is scheduled, and with high | |||
| 178 | * data rates (like with OHCI) data can get lost. | |||
| 179 | */ | |||
| 180 | port->tty->low_latency = 1; | |||
| 181 | ||||
| 182 | priv = usb_get_serial_port_data(port); | |||
| 183 | spin_lock_irqsave(&priv->lock, flags); | |||
| 183 | do | |||
| 183 | do | |||
| 0 | 0 | - | 183 | do-while (0) |
| 0 | 0 | - | 183 | do-while (0) |
| 183 | do | |||
| 183 | do | |||
| 0 | 0 | - | 183 | do-while (0) |
| 0 | 0 | - | 183 | do-while (0) |
| 0 | 0 | - | 183 | do-while (0) |
| 184 | priv->rdtodo = 0; | |||
| 185 | priv->wrfilled = 0; | |||
| 186 | priv->wrsent = 0; | |||
| 187 | spin_unlock_irqrestore(&priv->lock, flags); | |||
| 187 | do | |||
| 187 | do | |||
| 0 | 0 | - | 187 | do-while (0) |
| 0 | 0 | - | 187 | do-while (0) |
| 0 | 0 | - | 187 | do-while (0) |
| 188 | ||||
| 0 | - | 189 | return result; | |
| 190 | } | |||
| 191 | ||||
| 0 | 0 | - | 192 | static void cyberjack_close (struct usb_serial_port *port, struct file *filp) |
| 193 | { | |||
| 194 | dbg("%s - port %d", __FUNCTION__, port->number); | |||
| 0 | 0 | - | 194 | if (debug) |
| 0 | 0 | - | 194 | do-while (0) |
| 195 | ||||
| 0 | 0 | - | 196 | if (port->serial->dev) { |
| 197 | /* shutdown any bulk reads that might be going on */ | |||
| 198 | usb_kill_urb(port->write_urb); | |||
| 199 | usb_kill_urb(port->read_urb); | |||
| 200 | } | |||
| 201 | } | |||
| 202 | ||||
| 0 | 0 | - | 203 | static int cyberjack_write (struct usb_serial_port *port, const unsigned char *buf, int count) |
| 204 | { | |||
| 205 | struct usb_serial *serial = port->serial; | |||
| 206 | struct cyberjack_private *priv = usb_get_serial_port_data(port); | |||
| 207 | unsigned long flags; | |||
| 208 | int result; | |||
| 209 | int wrexpected; | |||
| 210 | ||||
| 211 | dbg("%s - port %d", __FUNCTION__, port->number); | |||
| 0 | 0 | - | 211 | if (debug) |
| 0 | 0 | - | 211 | do-while (0) |
| 212 | ||||
| 0 | 0 | - | 213 | if (count == 0) { |
| 214 | dbg("%s - write request of 0 bytes", __FUNCTION__); | |||
| 0 | 0 | - | 214 | if (debug) |
| 0 | 0 | - | 214 | do-while (0) |
| 0 | - | 215 | return (0); | |
| 216 | } | |||
| 217 | ||||
| 218 | spin_lock(&port->lock); | |||
| 218 | do | |||
| 0 | 0 | - | 218 | do-while (0) |
| 0 | 0 | - | 218 | do-while (0) |
| 0 | 0 | - | 219 | if (port->write_urb_busy) { |
| 220 | spin_unlock(&port->lock); | |||
| 220 | do | |||
| 0 | 0 | - | 220 | do-while (0) |
| 0 | 0 | - | 220 | do-while (0) |
| 221 | dbg("%s - already writing", __FUNCTION__); | |||
| 0 | 0 | - | 221 | if (debug) |
| 0 | 0 | - | 221 | do-while (0) |
| 0 | - | 222 | return 0; | |
| 223 | } | |||
| 224 | port->write_urb_busy = 1; | |||
| 225 | spin_unlock(&port->lock); | |||
| 225 | do | |||
| 0 | 0 | - | 225 | do-while (0) |
| 0 | 0 | - | 225 | do-while (0) |
| 226 | ||||
| 227 | spin_lock_irqsave(&priv->lock, flags); | |||
| 227 | do | |||
| 227 | do | |||
| 0 | 0 | - | 227 | do-while (0) |
| 0 | 0 | - | 227 | do-while (0) |
| 227 | do | |||
| 227 | do | |||
| 0 | 0 | - | 227 | do-while (0) |
| 0 | 0 | - | 227 | do-while (0) |
| 0 | 0 | - | 227 | do-while (0) |
| 228 | ||||
| 0 | 0 | - | 229 | if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) { |
| 230 | /* To much data for buffer. Reset buffer. */ | |||
| 231 | priv->wrfilled=0; | |||
| 232 | spin_unlock_irqrestore(&priv->lock, flags); | |||
| 232 | do | |||
| 232 | do | |||
| 0 | 0 | - | 232 | do-while (0) |
| 0 | 0 | - | 232 | do-while (0) |
| 0 | 0 | - | 232 | do-while (0) |
| 233 | port->write_urb_busy = 0; | |||
| 0 | - | 234 | return (0); | |
| 235 | } | |||
| 236 | ||||
| 237 | /* Copy data */ | |||
| 238 | memcpy (priv->wrbuf+priv->wrfilled, buf, count); | |||
| 239 | ||||
| 240 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, | |||
| 241 | priv->wrbuf+priv->wrfilled); | |||
| 242 | priv->wrfilled += count; | |||
| 243 | ||||
| 0 | 0 | - | 244 | if( priv->wrfilled >= 3 ) { |
| 245 | wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; | |||
| 246 | dbg("%s - expected data: %d", __FUNCTION__, wrexpected); | |||
| 0 | 0 | - | 246 | if (debug) |
| 0 | 0 | - | 246 | do-while (0) |
| 247 | } else { | |||
| 248 | wrexpected = sizeof(priv->wrbuf); | |||
| 249 | } | |||
| 250 | ||||
| 0 | 0 | - | 251 | if( priv->wrfilled >= wrexpected ) { |
| 252 | /* We have enough data to begin transmission */ | |||
| 253 | int length; | |||
| 254 | ||||
| 255 | dbg("%s - transmitting data (frame 1)", __FUNCTION__); | |||
| 0 | 0 | - | 255 | if (debug) |
| 0 | 0 | - | 255 | do-while (0) |
| 256 | length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected; | |||
| 0 | 0 | - | 256 | ternary-?: ( wrexpected > port -> bulk_out_s.. |
| 257 | ||||
| 258 | memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length ); | |||
| 259 | priv->wrsent=length; | |||
| 260 | ||||
| 261 | /* set up our urb */ | |||
| 262 | usb_fill_bulk_urb(port->write_urb, serial->dev, | |||
| 263 | usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), | |||
| 264 | port->write_urb->transfer_buffer, length, | |||
| 265 | ((serial->type->write_bulk_callback) ? | |||
| 0 | 0 | - | 265 | ternary-?: ( serial -> type -> write_bulk_ca.. |
| 266 | serial->type->write_bulk_callback : | |||
| 267 | cyberjack_write_bulk_callback), | |||
| 268 | port); | |||
| 269 | ||||
| 270 | /* send the data out the bulk port */ | |||
| 271 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); | |||
| 0 | 0 | - | 272 | if (result) { |
| 273 | err("%s - failed submitting write urb, error %d", __FUNCTION__, result); | |||
| 274 | /* Throw away data. No better idea what to do with it. */ | |||
| 275 | priv->wrfilled=0; | |||
| 276 | priv->wrsent=0; | |||
| 277 | spin_unlock_irqrestore(&priv->lock, flags); | |||
| 277 | do | |||
| 277 | do | |||
| 0 | 0 | - | 277 | do-while (0) |
| 0 | 0 | - | 277 | do-while (0) |
| 0 | 0 | - | 277 | do-while (0) |
| 278 | port->write_urb_busy = 0; | |||
| 0 | - | 279 | return 0; | |
| 280 | } | |||
| 281 | ||||
| 282 | dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent); | |||
| 0 | 0 | - | 282 | if (debug) |
| 0 | 0 | - | 282 | do-while (0) |
| 283 | dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled); | |||
| 0 | 0 | - | 283 | if (debug) |
| 0 | 0 | - | 283 | do-while (0) |
| 284 | ||||
| 0 | 0 | - | 285 | if( priv->wrsent>=priv->wrfilled ) { |
| 286 | dbg("%s - buffer cleaned", __FUNCTION__); | |||
| 0 | 0 | - | 286 | if (debug) |
| 0 | 0 | - | 286 | do-while (0) |
| 287 | memset( priv->wrbuf, 0, sizeof(priv->wrbuf) ); | |||
| 288 | priv->wrfilled=0; | |||
| 289 | priv->wrsent=0; | |||
| 290 | } | |||
| 291 | } | |||
| 292 | ||||
| 293 | spin_unlock_irqrestore(&priv->lock, flags); | |||
| 293 | do | |||
| 293 | do | |||
| 0 | 0 | - | 293 | do-while (0) |
| 0 | 0 | - | 293 | do-while (0) |
| 0 | 0 | - | 293 | do-while (0) |
| 294 | ||||
| 0 | - | 295 | return (count); | |
| 296 | } | |||
| 297 | ||||
| 0 | 0 | - | 298 | static int cyberjack_write_room( struct usb_serial_port *port ) |
| 299 | { | |||
| 0 | - | 300 | return CYBERJACK_LOCAL_BUF_SIZE; | |
| 301 | } | |||
| 302 | ||||
| 0 | 0 | - | 303 | static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs ) |
| 304 | { | |||
| 305 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | |||
| 306 | struct cyberjack_private *priv = usb_get_serial_port_data(port); | |||
| 307 | unsigned char *data = urb->transfer_buffer; | |||
| 308 | int result; | |||
| 309 | ||||
| 310 | dbg("%s - port %d", __FUNCTION__, port->number); | |||
| 0 | 0 | - | 310 | if (debug) |
| 0 | 0 | - | 310 | do-while (0) |
| 311 | ||||
| 312 | /* the urb might have been killed. */ | |||
| 0 | 0 | - | 313 | if (urb->status) |
| 0 | - | 314 | return; | |
| 315 | ||||
| 316 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); | |||
| 317 | ||||
| 318 | /* React only to interrupts signaling a bulk_in transfer */ | |||
| 0 | 0 | - | 319 | if( (urb->actual_length==4) && (data[0]==0x01) ) { |
| 0 | - | 319 | (T) && (T) | |
| 0 | - | 319 | (T) && (F) | |
| 0 | - | 319 | (F) && (_) | |
| 320 | short old_rdtodo; | |||
| 321 | int result; | |||
| 322 | ||||
| 323 | /* This is a announcement of coming bulk_ins. */ | |||
| 324 | unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; | |||
| 325 | ||||
| 326 | spin_lock(&priv->lock); | |||
| 326 | do | |||
| 0 | 0 | - | 326 | do-while (0) |
| 0 | 0 | - | 326 | do-while (0) |
| 327 | ||||
| 328 | old_rdtodo = priv->rdtodo; | |||
| 329 | ||||
| 0 | 0 | - | 330 | if( (old_rdtodo+size)<(old_rdtodo) ) { |
| 331 | dbg( "To many bulk_in urbs to do." ); | |||
| 0 | 0 | - | 331 | if (debug) |
| 0 | 0 | - | 331 | do-while (0) |
| 332 | spin_unlock(&priv->lock); | |||
| 332 | do | |||
| 0 | 0 | - | 332 | do-while (0) |
| 0 | 0 | - | 332 | do-while (0) |
| 0 | - | 333 | goto resubmit; | |
| 334 | } | |||
| 335 | ||||
| 336 | /* "+=" is probably more fault tollerant than "=" */ | |||
| 337 | priv->rdtodo += size; | |||
| 338 | ||||
| 339 | dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo); | |||
| 0 | 0 | - | 339 | if (debug) |
| 0 | 0 | - | 339 | do-while (0) |
| 340 | ||||
| 341 | spin_unlock(&priv->lock); | |||
| 341 | do | |||
| 0 | 0 | - | 341 | do-while (0) |
| 0 | 0 | - | 341 | do-while (0) |
| 342 | ||||
| 0 | 0 | - | 343 | if( !old_rdtodo ) { |
| 344 | port->read_urb->dev = port->serial->dev; | |||
| 345 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | |||
| 0 | 0 | - | 346 | if( result ) |
| 347 | err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); | |||
| 348 | dbg("%s - usb_submit_urb(read urb)", __FUNCTION__); | |||
| 0 | 0 | - | 348 | if (debug) |
| 0 | 0 | - | 348 | do-while (0) |
| 349 | } | |||
| 350 | } | |||
| 351 | ||||
| 352 | resubmit: | |||
| 353 | port->interrupt_in_urb->dev = port->serial->dev; | |||
| 354 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); | |||
| 0 | 0 | - | 355 | if (result) |
| 356 | err(" usb_submit_urb(read int) failed"); | |||
| 357 | dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); | |||
| 0 | 0 | - | 357 | if (debug) |
| 0 | 0 | - | 357 | do-while (0) |
| 358 | } | |||
| 359 | ||||
| 0 | 0 | - | 360 | static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) |
| 361 | { | |||
| 362 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | |||
| 363 | struct cyberjack_private *priv = usb_get_serial_port_data(port); | |||
| 364 | struct tty_struct *tty; | |||
| 365 | unsigned char *data = urb->transfer_buffer; | |||
| 366 | short todo; | |||
| 367 | int result; | |||
| 368 | ||||
| 369 | dbg("%s - port %d", __FUNCTION__, port->number); | |||
| 0 | 0 | - | 369 | if (debug) |
| 0 | 0 | - | 369 | do-while (0) |
| 370 | ||||
| 371 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); | |||
| 0 | 0 | - | 372 | if (urb->status) { |
| 373 | dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); | |||
| 0 | 0 | - | 373 | if (debug) |
| 0 | 0 | - | 373 | do-while (0) |
| 0 | - | 374 | return; | |
| 375 | } | |||
| 376 | ||||
| 377 | tty = port->tty; | |||
| 0 | 0 | - | 378 | if (!tty) { |
| 379 | dbg("%s - ignoring since device not open\n", __FUNCTION__); | |||
| 0 | 0 | - | 379 | if (debug) |
| 0 | 0 | - | 379 | do-while (0) |
| 0 | - | 380 | return; | |
| 381 | } | |||
| 0 | 0 | - | 382 | if (urb->actual_length) { |
| 383 | tty_buffer_request_room(tty, urb->actual_length); | |||
| 384 | tty_insert_flip_string(tty, data, urb->actual_length); | |||
| 385 | tty_flip_buffer_push(tty); | |||
| 386 | } | |||
| 387 | ||||
| 388 | spin_lock(&priv->lock); | |||
| 388 | do | |||
| 0 | 0 | - | 388 | do-while (0) |
| 0 | 0 | - | 388 | do-while (0) |
| 389 | ||||
| 390 | /* Reduce urbs to do by one. */ | |||
| 391 | priv->rdtodo-=urb->actual_length; | |||
| 392 | /* Just to be sure */ | |||
| 0 | 0 | - | 393 | if ( priv->rdtodo<0 ) priv->rdtodo = 0; |
| 394 | todo = priv->rdtodo; | |||
| 395 | ||||
| 396 | spin_unlock(&priv->lock); | |||
| 396 | do | |||
| 0 | 0 | - | 396 | do-while (0) |
| 0 | 0 | - | 396 | do-while (0) |
| 397 | ||||
| 398 | dbg("%s - rdtodo: %d", __FUNCTION__, todo); | |||
| 0 | 0 | - | 398 | |