opticon driver patch kernel version 2.6.35

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



--- drivers/usb/serial/opticon.c.orig    2011-02-22 07:33:50.917536943 -0800
+++ drivers/usb/serial/opticon.c    2011-02-23 04:32:33.347347089 -0800
@@ -1,9 +1,15 @@
 /*
  * Opticon USB barcode to serial driver
  *
+ * Copyright (C) 2011 Martin Jansen <martin.jansen@xxxxxxxxxxx>
  * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@xxxxxxx>
  * Copyright (C) 2008 - 2009 Novell Inc.
  *
+ * 22 February 2011 Martin Jansen
+ *        Changes for version v0.1
+ *        Add write support
+ *        Add support for RTS and CTS line status
+ *
  *    This program is free software; you can redistribute it and/or
  *    modify it under the terms of the GNU General Public License version
  *    2 as published by the Free Software Foundation.
@@ -21,6 +27,16 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>

+#define CONTROL_RTS            0x02
+#define RESEND_CTS_STATE    0x03
+
+/* max number of write urbs in flight */
+#define URB_UPPER_LIMIT    8
+
+/* Version Information */
+#define DRIVER_VERSION    "v0.1"
+#define DRIVER_DESC    "Opticon USB barcode to serial driver (1D)"
+
 static int debug;

 static const struct usb_device_id id_table[] = {
@@ -37,18 +53,20 @@ struct opticon_private {
     unsigned char *bulk_in_buffer;
     struct urb *bulk_read_urb;
     int buffer_size;
+    char ctrl_write_buf[8];    /* Ctrl buffer for the vendor commands */
     u8 bulk_address;
+
     spinlock_t lock;    /* protects the following flags */
     bool throttled;
     bool actually_throttled;
     bool rts;
+    bool cts;
     int outstanding_urbs;
 };

-/* max number of write urbs in flight */
-#define URB_UPPER_LIMIT    4

-static void opticon_bulk_callback(struct urb *urb)
+
+static void opticon_read_bulk_callback(struct urb *urb)
 {
     struct opticon_private *priv = urb->context;
     unsigned char *data = urb->transfer_buffer;
@@ -57,6 +75,7 @@ static void opticon_bulk_callback(struct
     struct tty_struct *tty;
     int result;
     int data_length;
+    unsigned long flags;

     dbg("%s - port %d", __func__, port->number);

@@ -73,7 +92,7 @@ static void opticon_bulk_callback(struct
         return;
     default:
         dbg("%s - nonzero urb status received: %d",
-            __func__, status);
+            __func__, status);
         goto exit;
     }

@@ -87,27 +106,31 @@ static void opticon_bulk_callback(struct
          * Data from the device comes with a 2 byte header:
          *
          * <0x00><0x00>data...
-         *     This is real data to be sent to the tty layer
+         *    This is real data to be sent to the tty layer
          * <0x00><0x01)level
-         *     This is a RTS level change, the third byte is the RTS
-         *     value (0 for low, 1 for high).
+         *    This is a CTS level change, the third byte is the CTS
+         *    value (0 for low, 1 for high).
          */
         if ((data[0] == 0x00) && (data[1] == 0x00)) {
             /* real data, send it to the tty layer */
             tty = tty_port_tty_get(&port->port);
             if (tty) {
-                tty_insert_flip_string(tty, data,
-                                   data_length);
+                tty_insert_flip_string(tty, data + 2,
+                    data_length);
                 tty_flip_buffer_push(tty);
                 tty_kref_put(tty);
             }
         } else {
             if ((data[0] == 0x00) && (data[1] == 0x01)) {
+                spin_lock_irqsave(&priv->lock, flags);
+                /* CTS status infomation package */
                 if (data[2] == 0x00)
-                    priv->rts = false;
+                    priv->cts = false;
                 else
-                    priv->rts = true;
+                    priv->cts = true;
+                spin_unlock_irqrestore(&priv->lock, flags);
             } else {
+
             dev_dbg(&priv->udev->dev,
                 "Unknown data packet received from the device:"
                 " %2x %2x\n",
@@ -121,25 +144,69 @@ static void opticon_bulk_callback(struct
     }

 exit:
-    spin_lock(&priv->lock);
-
     /* Continue trying to always read if we should */
-    if (!priv->throttled) {
-        usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
+    spin_lock_irqsave(&priv->lock, flags);
+    if (priv->throttled) {
+        priv->actually_throttled = true;
+        spin_unlock_irqrestore(&priv->lock, flags);
+        return;
+    }
+    spin_unlock_irqrestore(&priv->lock, flags);
+
+    usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
                   usb_rcvbulkpipe(priv->udev,
-                          priv->bulk_address),
+                  priv->bulk_address),
                   priv->bulk_in_buffer, priv->buffer_size,
-                  opticon_bulk_callback, priv);
-        result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-        if (result)
-            dev_err(&port->dev,
-                "%s - failed resubmitting read urb, error %d\n",
-                            __func__, result);
-    } else
-        priv->actually_throttled = true;
-    spin_unlock(&priv->lock);
+                  opticon_read_bulk_callback, priv);
+
+    result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
+    if (result)
+        dev_err(&port->dev,
+            "%s - failed resubmitting read urb, error %d\n",
+                        __func__, result);
+
+}
+
+static void opticon_write_control_callback(struct urb *urb)
+{
+    struct opticon_private *priv = urb->context;
+    int status = urb->status;
+    unsigned long flags;
+
+    /* free up the transfer buffer, as usb_free_urb() does not do this */
+    kfree(urb->transfer_buffer);
+
+    if (status)
+        dbg("%s - nonzero write bulk status received: %d",
+            __func__, status);
+
+    spin_lock_irqsave(&priv->lock, flags);
+    --priv->outstanding_urbs;
+    spin_unlock_irqrestore(&priv->lock, flags);
+
+    usb_serial_port_softint(priv->port);
 }

+
+static int send_control_msg(struct usb_serial_port *port, u8 requesttype,
+                u8 val)
+{
+    struct usb_serial *serial = port->serial;
+    int retval;
+    u8 buffer[2];
+
+    buffer[0] = val;
+    /* Send the message to the vendor control endpoint
+     * of the connected device */
+    retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                requesttype,
+                USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+                0, 0, buffer, 1, 0);
+
+    return retval;
+}
+
+
static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
     struct opticon_private *priv = usb_get_serial_data(port->serial);
@@ -152,19 +219,28 @@ static int opticon_open(struct tty_struc
     priv->throttled = false;
     priv->actually_throttled = false;
     priv->port = port;
+    priv->rts = false;
     spin_unlock_irqrestore(&priv->lock, flags);

-    /* Start reading from the device */
+    /* Clear RTS line */
+    send_control_msg(port, CONTROL_RTS, 0);
+
+    /* Setup the read URB and start reading from the device */
     usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
               usb_rcvbulkpipe(priv->udev,
                       priv->bulk_address),
               priv->bulk_in_buffer, priv->buffer_size,
-              opticon_bulk_callback, priv);
+              opticon_read_bulk_callback, priv);
+
+    /* clear the halt status of the enpoint */
+    usb_clear_halt(priv->udev, priv->bulk_read_urb->pipe);
+
     result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL);
     if (result)
         dev_err(&port->dev,
             "%s - failed resubmitting read urb, error %d\n",
             __func__, result);
+
     return result;
 }

@@ -178,25 +254,6 @@ static void opticon_close(struct usb_ser
     usb_kill_urb(priv->bulk_read_urb);
 }

-static void opticon_write_bulk_callback(struct urb *urb)
-{
-    struct opticon_private *priv = urb->context;
-    int status = urb->status;
-    unsigned long flags;
-
-    /* free up the transfer buffer, as usb_free_urb() does not do this */
-    kfree(urb->transfer_buffer);
-
-    if (status)
-        dbg("%s - nonzero write bulk status received: %d",
-            __func__, status);
-
-    spin_lock_irqsave(&priv->lock, flags);
-    --priv->outstanding_urbs;
-    spin_unlock_irqrestore(&priv->lock, flags);
-
-    usb_serial_port_softint(priv->port);
-}

static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
              const unsigned char *buf, int count)
@@ -207,6 +264,7 @@ static int opticon_write(struct tty_stru
     unsigned char *buffer;
     unsigned long flags;
     int status;
+    struct usb_ctrlrequest *ctrl_req = NULL;

     dbg("%s - port %d", __func__, port->number);

@@ -223,6 +281,7 @@ static int opticon_write(struct tty_stru
     if (!buffer) {
         dev_err(&port->dev, "out of memory\n");
         count = -ENOMEM;
+
         goto error_no_buffer;
     }

@@ -230,6 +289,7 @@ static int opticon_write(struct tty_stru
     if (!urb) {
         dev_err(&port->dev, "no more free urbs\n");
         count = -ENOMEM;
+
         goto error_no_urb;
     }

@@ -237,16 +297,26 @@ static int opticon_write(struct tty_stru

     usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);

-    usb_fill_bulk_urb(urb, serial->dev,
-              usb_sndbulkpipe(serial->dev,
-                      port->bulk_out_endpointAddress),
-              buffer, count, opticon_write_bulk_callback, priv);
+    /* Setup the vendor control command */
+    ctrl_req = (void *)(priv->ctrl_write_buf); /* ctrl_buf is 8 bytes */
+    ctrl_req->bRequestType =
+        USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE; /* 0x41 */
+    ctrl_req->bRequest = 0x01;
+    ctrl_req->wValue = 0;
+    ctrl_req->wIndex = 0;
+    ctrl_req->wLength = cpu_to_le16(count);
+
+    usb_fill_control_urb(urb, serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                (unsigned char *)ctrl_req,
+                buffer, count,
+                opticon_write_control_callback,
+                priv);

     /* send it down the pipe */
     status = usb_submit_urb(urb, GFP_ATOMIC);
     if (status) {
         dev_err(&port->dev,
-           "%s - usb_submit_urb(write bulk) failed with status = %d\n",
+        "%s - usb_submit_urb(write endpoint) failed status = %d\n",
                             __func__, status);
         count = status;
         goto error;
@@ -282,6 +352,7 @@ static int opticon_write_room(struct tty
      * layer that we have lots of free space, unless we don't.
      */
     spin_lock_irqsave(&priv->lock, flags);
+
     if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
         spin_unlock_irqrestore(&priv->lock, flags);
         dbg("%s - write limit hit", __func__);
@@ -338,16 +409,49 @@ static int opticon_tiocmget(struct tty_s
     int result = 0;

     dbg("%s - port %d", __func__, port->number);
+    if (!usb_get_intfdata(port->serial->interface))
+        return -ENODEV;

     spin_lock_irqsave(&priv->lock, flags);
     if (priv->rts)
-        result = TIOCM_RTS;
+        result |= TIOCM_RTS;
+    if (priv->cts)
+        result |= TIOCM_CTS;
     spin_unlock_irqrestore(&priv->lock, flags);

     dbg("%s - %x", __func__, result);
     return result;
 }

+static int opticon_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+    struct usb_serial_port *port = tty->driver_data;
+    struct opticon_private *priv = usb_get_serial_data(port->serial);
+    unsigned long flags;
+    bool rts;
+    bool changed = false;
+
+    if (!usb_get_intfdata(port->serial->interface))
+        return -ENODEV;
+    /* We only support RTS so we only handle that */
+    spin_lock_irqsave(&priv->lock, flags);
+
+    rts = priv->rts;
+    if (set & TIOCM_RTS)
+        priv->rts = true;
+    if (clear & TIOCM_RTS)
+        priv->rts = false;
+    changed = rts ^ priv->rts;
+    spin_unlock_irqrestore(&priv->lock, flags);
+
+    if (!changed)
+        return 0;
+
+    /* Send the new RTS state to the connected device */
+    return send_control_msg(port, CONTROL_RTS, !rts);
+}
+
 static int get_serial_info(struct opticon_private *priv,
                struct serial_struct __user *serial)
 {
@@ -409,6 +513,7 @@ static int opticon_startup(struct usb_se
     priv->serial = serial;
     priv->port = serial->port[0];
     priv->udev = serial->dev;
+    priv->outstanding_urbs = 0;    /* Init the outstanding urbs */

     /* find our bulk endpoint */
     intf = serial->interface->altsetting;
@@ -434,13 +539,6 @@ static int opticon_startup(struct usb_se

         priv->bulk_address = endpoint->bEndpointAddress;

-        /* set up our bulk urb */
-        usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
-                  usb_rcvbulkpipe(priv->udev,
-                          endpoint->bEndpointAddress),
-                  priv->bulk_in_buffer, priv->buffer_size,
-                  opticon_bulk_callback, priv);
-
         bulk_in_found = true;
         break;
         }
@@ -452,12 +550,14 @@ static int opticon_startup(struct usb_se
     }

     usb_set_serial_data(serial, priv);
+
     return 0;

 error:
     usb_free_urb(priv->bulk_read_urb);
     kfree(priv->bulk_in_buffer);
     kfree(priv);
+
     return retval;
 }

@@ -487,6 +587,7 @@ static int opticon_suspend(struct usb_in
     struct opticon_private *priv = usb_get_serial_data(serial);

     usb_kill_urb(priv->bulk_read_urb);
+
     return 0;
 }

@@ -536,6 +637,8 @@ static struct usb_serial_driver opticon_
     .unthrottle =        opticon_unthrottle,
     .ioctl =        opticon_ioctl,
     .tiocmget =        opticon_tiocmget,
+    .tiocmset =        opticon_tiocmset,
+
 };

 static int __init opticon_init(void)
@@ -559,6 +662,8 @@ static void __exit opticon_exit(void)

 module_init(opticon_init);
 module_exit(opticon_exit);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");

 module_param(debug, bool, S_IRUGO | S_IWUSR);

Signed-off-by: Martin Jansen <martin.jansen@xxxxxxxxxxx>

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux