linux/drivers/usb/serial/symbolserial.c
<<
>>
Prefs
   1/*
   2 * Symbol USB barcode to serial driver
   3 *
   4 * Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de>
   5 * Copyright (C) 2009 Novell Inc.
   6 *
   7 *      This program is free software; you can redistribute it and/or
   8 *      modify it under the terms of the GNU General Public License version
   9 *      2 as published by the Free Software Foundation.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/tty.h>
  15#include <linux/slab.h>
  16#include <linux/tty_driver.h>
  17#include <linux/tty_flip.h>
  18#include <linux/module.h>
  19#include <linux/usb.h>
  20#include <linux/usb/serial.h>
  21#include <linux/uaccess.h>
  22
  23static const struct usb_device_id id_table[] = {
  24        { USB_DEVICE(0x05e0, 0x0600) },
  25        { },
  26};
  27MODULE_DEVICE_TABLE(usb, id_table);
  28
  29/* This structure holds all of the individual device information */
  30struct symbol_private {
  31        struct usb_device *udev;
  32        struct usb_serial *serial;
  33        struct usb_serial_port *port;
  34        unsigned char *int_buffer;
  35        struct urb *int_urb;
  36        int buffer_size;
  37        u8 bInterval;
  38        u8 int_address;
  39        spinlock_t lock;        /* protects the following flags */
  40        bool throttled;
  41        bool actually_throttled;
  42        bool rts;
  43};
  44
  45static void symbol_int_callback(struct urb *urb)
  46{
  47        struct symbol_private *priv = urb->context;
  48        unsigned char *data = urb->transfer_buffer;
  49        struct usb_serial_port *port = priv->port;
  50        int status = urb->status;
  51        int result;
  52        int data_length;
  53
  54        switch (status) {
  55        case 0:
  56                /* success */
  57                break;
  58        case -ECONNRESET:
  59        case -ENOENT:
  60        case -ESHUTDOWN:
  61                /* this urb is terminated, clean up */
  62                dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
  63                        __func__, status);
  64                return;
  65        default:
  66                dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
  67                        __func__, status);
  68                goto exit;
  69        }
  70
  71        usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
  72
  73        if (urb->actual_length > 1) {
  74                data_length = urb->actual_length - 1;
  75
  76                /*
  77                 * Data from the device comes with a 1 byte header:
  78                 *
  79                 * <size of data>data...
  80                 *      This is real data to be sent to the tty layer
  81                 * we pretty much just ignore the size and send everything
  82                 * else to the tty layer.
  83                 */
  84                tty_insert_flip_string(&port->port, &data[1], data_length);
  85                tty_flip_buffer_push(&port->port);
  86        } else {
  87                dev_dbg(&priv->udev->dev,
  88                        "Improper amount of data received from the device, "
  89                        "%d bytes", urb->actual_length);
  90        }
  91
  92exit:
  93        spin_lock(&priv->lock);
  94
  95        /* Continue trying to always read if we should */
  96        if (!priv->throttled) {
  97                usb_fill_int_urb(priv->int_urb, priv->udev,
  98                                 usb_rcvintpipe(priv->udev,
  99                                                priv->int_address),
 100                                 priv->int_buffer, priv->buffer_size,
 101                                 symbol_int_callback, priv, priv->bInterval);
 102                result = usb_submit_urb(priv->int_urb, GFP_ATOMIC);
 103                if (result)
 104                        dev_err(&port->dev,
 105                            "%s - failed resubmitting read urb, error %d\n",
 106                                                        __func__, result);
 107        } else
 108                priv->actually_throttled = true;
 109        spin_unlock(&priv->lock);
 110}
 111
 112static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
 113{
 114        struct symbol_private *priv = usb_get_serial_data(port->serial);
 115        unsigned long flags;
 116        int result = 0;
 117
 118        spin_lock_irqsave(&priv->lock, flags);
 119        priv->throttled = false;
 120        priv->actually_throttled = false;
 121        priv->port = port;
 122        spin_unlock_irqrestore(&priv->lock, flags);
 123
 124        /* Start reading from the device */
 125        usb_fill_int_urb(priv->int_urb, priv->udev,
 126                         usb_rcvintpipe(priv->udev, priv->int_address),
 127                         priv->int_buffer, priv->buffer_size,
 128                         symbol_int_callback, priv, priv->bInterval);
 129        result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
 130        if (result)
 131                dev_err(&port->dev,
 132                        "%s - failed resubmitting read urb, error %d\n",
 133                        __func__, result);
 134        return result;
 135}
 136
 137static void symbol_close(struct usb_serial_port *port)
 138{
 139        struct symbol_private *priv = usb_get_serial_data(port->serial);
 140
 141        /* shutdown our urbs */
 142        usb_kill_urb(priv->int_urb);
 143}
 144
 145static void symbol_throttle(struct tty_struct *tty)
 146{
 147        struct usb_serial_port *port = tty->driver_data;
 148        struct symbol_private *priv = usb_get_serial_data(port->serial);
 149
 150        spin_lock_irq(&priv->lock);
 151        priv->throttled = true;
 152        spin_unlock_irq(&priv->lock);
 153}
 154
 155static void symbol_unthrottle(struct tty_struct *tty)
 156{
 157        struct usb_serial_port *port = tty->driver_data;
 158        struct symbol_private *priv = usb_get_serial_data(port->serial);
 159        int result;
 160        bool was_throttled;
 161
 162        spin_lock_irq(&priv->lock);
 163        priv->throttled = false;
 164        was_throttled = priv->actually_throttled;
 165        priv->actually_throttled = false;
 166        spin_unlock_irq(&priv->lock);
 167
 168        if (was_throttled) {
 169                result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
 170                if (result)
 171                        dev_err(&port->dev,
 172                                "%s - failed submitting read urb, error %d\n",
 173                                                        __func__, result);
 174        }
 175}
 176
 177static int symbol_startup(struct usb_serial *serial)
 178{
 179        struct symbol_private *priv;
 180        struct usb_host_interface *intf;
 181        int i;
 182        int retval = -ENOMEM;
 183        bool int_in_found = false;
 184
 185        /* create our private serial structure */
 186        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 187        if (priv == NULL) {
 188                dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
 189                return -ENOMEM;
 190        }
 191        spin_lock_init(&priv->lock);
 192        priv->serial = serial;
 193        priv->port = serial->port[0];
 194        priv->udev = serial->dev;
 195
 196        /* find our interrupt endpoint */
 197        intf = serial->interface->altsetting;
 198        for (i = 0; i < intf->desc.bNumEndpoints; ++i) {
 199                struct usb_endpoint_descriptor *endpoint;
 200
 201                endpoint = &intf->endpoint[i].desc;
 202                if (!usb_endpoint_is_int_in(endpoint))
 203                        continue;
 204
 205                priv->int_urb = usb_alloc_urb(0, GFP_KERNEL);
 206                if (!priv->int_urb) {
 207                        dev_err(&priv->udev->dev, "out of memory\n");
 208                        goto error;
 209                }
 210
 211                priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
 212                priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
 213                if (!priv->int_buffer) {
 214                        dev_err(&priv->udev->dev, "out of memory\n");
 215                        goto error;
 216                }
 217
 218                priv->int_address = endpoint->bEndpointAddress;
 219                priv->bInterval = endpoint->bInterval;
 220
 221                /* set up our int urb */
 222                usb_fill_int_urb(priv->int_urb, priv->udev,
 223                                 usb_rcvintpipe(priv->udev,
 224                                                endpoint->bEndpointAddress),
 225                                 priv->int_buffer, priv->buffer_size,
 226                                 symbol_int_callback, priv, priv->bInterval);
 227
 228                int_in_found = true;
 229                break;
 230                }
 231
 232        if (!int_in_found) {
 233                dev_err(&priv->udev->dev,
 234                        "Error - the proper endpoints were not found!\n");
 235                goto error;
 236        }
 237
 238        usb_set_serial_data(serial, priv);
 239        return 0;
 240
 241error:
 242        usb_free_urb(priv->int_urb);
 243        kfree(priv->int_buffer);
 244        kfree(priv);
 245        return retval;
 246}
 247
 248static void symbol_disconnect(struct usb_serial *serial)
 249{
 250        struct symbol_private *priv = usb_get_serial_data(serial);
 251
 252        usb_kill_urb(priv->int_urb);
 253        usb_free_urb(priv->int_urb);
 254}
 255
 256static void symbol_release(struct usb_serial *serial)
 257{
 258        struct symbol_private *priv = usb_get_serial_data(serial);
 259
 260        kfree(priv->int_buffer);
 261        kfree(priv);
 262}
 263
 264static struct usb_serial_driver symbol_device = {
 265        .driver = {
 266                .owner =        THIS_MODULE,
 267                .name =         "symbol",
 268        },
 269        .id_table =             id_table,
 270        .num_ports =            1,
 271        .attach =               symbol_startup,
 272        .open =                 symbol_open,
 273        .close =                symbol_close,
 274        .disconnect =           symbol_disconnect,
 275        .release =              symbol_release,
 276        .throttle =             symbol_throttle,
 277        .unthrottle =           symbol_unthrottle,
 278};
 279
 280static struct usb_serial_driver * const serial_drivers[] = {
 281        &symbol_device, NULL
 282};
 283
 284module_usb_serial_driver(serial_drivers, id_table);
 285
 286MODULE_LICENSE("GPL");
 287
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.