aboutsummaryrefslogtreecommitdiffstats
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-02-06 18:35:11 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2009-02-06 18:35:11 -0800
commit049bbe76bbd4522c770ad0f236cd0672284875d7 (patch)
tree892886b60826653afa52a0574fea8487e56af2b2
parent3ec13e803b8b6b954d3e6361fdf62edf0d382db4 (diff)
downloadpatches-049bbe76bbd4522c770ad0f236cd0672284875d7.tar.gz
opticon patches
-rw-r--r--series3
-rw-r--r--usb/usb-serial-opticon-add-serial-line-ioctls.patch112
-rw-r--r--usb/usb-serial-opticon-add-write-support.patch171
3 files changed, 285 insertions, 1 deletions
diff --git a/series b/series
index b38f72b1e11f49..2fc7b30b4927bc 100644
--- a/series
+++ b/series
@@ -144,6 +144,8 @@ usb/usb-serial-use-generic-method-if-no-alternative-is-provided-in-usb-serial-la
usb/usb-add-missing-kern_-constants-to-printks.patch
usb/usb-ftdi_sio-remove-pointless-syslog-spew.patch
usb/usb-otg-adding-nop-usb-transceiver.patch
+usb/usb-serial-opticon-add-write-support.patch
+usb/usb-serial-opticon-add-serial-line-ioctls.patch
# stuff I want in my tree, but not to go into -next
gregkh.post/usb-gotemp.patch
@@ -329,4 +331,3 @@ staging/staging-add-b3dfg-driver.patch
staging/staging-b3dfg-fixups-and-improvements.patch
staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch
-
diff --git a/usb/usb-serial-opticon-add-serial-line-ioctls.patch b/usb/usb-serial-opticon-add-serial-line-ioctls.patch
new file mode 100644
index 00000000000000..b4a1f71ae22dec
--- /dev/null
+++ b/usb/usb-serial-opticon-add-serial-line-ioctls.patch
@@ -0,0 +1,112 @@
+From foo@baz Fri Feb 6 18:31:46 PST 2009
+Date: Fri, 06 Feb 2009 18:31:46 -0800
+To: Greg KH <greg@kroah.com>
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Subject: USB: serial: opticon: add serial line ioctls
+
+This lets userspace determine what the state of the RTS line is, which
+is what is needed to properly handle data flow for this device (it
+raises RTS when there is data to be sent from it.)
+
+Cc: Kees Stoop <kees.stoop@opticon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/opticon.c | 65 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 64 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/opticon.c
++++ b/drivers/usb/serial/opticon.c
+@@ -14,6 +14,7 @@
+ #include <linux/tty.h>
+ #include <linux/tty_driver.h>
+ #include <linux/tty_flip.h>
++#include <linux/serial.h>
+ #include <linux/module.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+@@ -110,7 +111,6 @@ static void opticon_bulk_callback(struct
+ priv->rts = false;
+ else
+ priv->rts = true;
+- /* FIXME change the RTS level */
+ } else {
+ dev_dbg(&priv->udev->dev,
+ "Unknown data packet received from the device:"
+@@ -341,6 +341,67 @@ static void opticon_unthrottle(struct tt
+ __func__, result);
+ }
+
++static int opticon_tiocmget(struct tty_struct *tty, struct file *file)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct opticon_private *priv = usb_get_serial_data(port->serial);
++ unsigned long flags;
++ int result = 0;
++
++ dbg("%s - port %d", __func__, port->number);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->rts)
++ result = TIOCM_RTS;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ dbg("%s - %x", __func__, result);
++ return result;
++}
++
++static int get_serial_info(struct opticon_private *priv,
++ struct serial_struct __user *serial)
++{
++ struct serial_struct tmp;
++
++ if (!serial)
++ return -EFAULT;
++
++ memset(&tmp, 0x00, sizeof(tmp));
++
++ /* fake emulate a 16550 uart to make userspace code happy */
++ tmp.type = PORT_16550A;
++ tmp.line = priv->serial->minor;
++ tmp.port = 0;
++ tmp.irq = 0;
++ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
++ tmp.xmit_fifo_size = 1024;
++ tmp.baud_base = 9600;
++ tmp.close_delay = 5*HZ;
++ tmp.closing_wait = 30*HZ;
++
++ if (copy_to_user(serial, &tmp, sizeof(*serial)))
++ return -EFAULT;
++ return 0;
++}
++
++static int opticon_ioctl(struct tty_struct *tty, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct opticon_private *priv = usb_get_serial_data(port->serial);
++
++ dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
++
++ switch (cmd) {
++ case TIOCGSERIAL:
++ return get_serial_info(priv,
++ (struct serial_struct __user *)arg);
++ }
++
++ return -ENOIOCTLCMD;
++}
++
+ static int opticon_startup(struct usb_serial *serial)
+ {
+ struct opticon_private *priv;
+@@ -475,6 +536,8 @@ static struct usb_serial_driver opticon_
+ .shutdown = opticon_shutdown,
+ .throttle = opticon_throttle,
+ .unthrottle = opticon_unthrottle,
++ .ioctl = opticon_ioctl,
++ .tiocmget = opticon_tiocmget,
+ };
+
+ static int __init opticon_init(void)
diff --git a/usb/usb-serial-opticon-add-write-support.patch b/usb/usb-serial-opticon-add-write-support.patch
new file mode 100644
index 00000000000000..f82f1654ca0b25
--- /dev/null
+++ b/usb/usb-serial-opticon-add-write-support.patch
@@ -0,0 +1,171 @@
+From foo@baz Fri Feb 6 18:30:56 PST 2009
+Date: Fri, 06 Feb 2009 18:30:56 -0800
+To: Greg KH <greg@kroah.com>
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Subject: USB: serial: opticon: add write support
+
+This patch allows data to be sent to the scanner.
+
+Cc: Kees Stoop <kees.stoop@opticon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/opticon.c | 124 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 122 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/serial/opticon.c
++++ b/drivers/usb/serial/opticon.c
+@@ -1,8 +1,8 @@
+ /*
+ * Opticon USB barcode to serial driver
+ *
+- * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+- * Copyright (C) 2008 Novell Inc.
++ * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de>
++ * Copyright (C) 2008 - 2009 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+@@ -40,8 +40,12 @@ struct opticon_private {
+ bool throttled;
+ bool actually_throttled;
+ bool rts;
++ int outstanding_urbs;
+ };
+
++/* max number of write urbs in flight */
++#define URB_UPPER_LIMIT 4
++
+ static void opticon_bulk_callback(struct urb *urb)
+ {
+ struct opticon_private *priv = urb->context;
+@@ -188,6 +192,120 @@ static void opticon_close(struct tty_str
+ 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)
++{
++ struct opticon_private *priv = usb_get_serial_data(port->serial);
++ struct usb_serial *serial = port->serial;
++ struct urb *urb;
++ unsigned char *buffer;
++ unsigned long flags;
++ int status;
++
++ dbg("%s - port %d", __func__, port->number);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ dbg("%s - write limit hit\n", __func__);
++ return 0;
++ }
++ priv->outstanding_urbs++;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ buffer = kmalloc(count, GFP_ATOMIC);
++ if (!buffer) {
++ dev_err(&port->dev, "out of memory\n");
++ count = -ENOMEM;
++ goto error_no_buffer;
++ }
++
++ urb = usb_alloc_urb(0, GFP_ATOMIC);
++ if (!urb) {
++ dev_err(&port->dev, "no more free urbs\n");
++ count = -ENOMEM;
++ goto error_no_urb;
++ }
++
++ memcpy(buffer, buf, count);
++
++ 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);
++
++ /* 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",
++ __func__, status);
++ count = status;
++ goto error;
++ }
++
++ /* we are done with this urb, so let the host driver
++ * really free it when it is finished with it */
++ usb_free_urb(urb);
++
++ return count;
++error:
++ usb_free_urb(urb);
++error_no_urb:
++ kfree(buffer);
++error_no_buffer:
++ spin_lock_irqsave(&priv->lock, flags);
++ --priv->outstanding_urbs;
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return count;
++}
++
++static int opticon_write_room(struct tty_struct *tty)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct opticon_private *priv = usb_get_serial_data(port->serial);
++ unsigned long flags;
++
++ dbg("%s - port %d", __func__, port->number);
++
++ /*
++ * We really can take almost anything the user throws at us
++ * but let's pick a nice big number to tell the 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\n", __func__);
++ return 0;
++ }
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 2048;
++}
++
+ static void opticon_throttle(struct tty_struct *tty)
+ {
+ struct usb_serial_port *port = tty->driver_data;
+@@ -352,6 +470,8 @@ static struct usb_serial_driver opticon_
+ .attach = opticon_startup,
+ .open = opticon_open,
+ .close = opticon_close,
++ .write = opticon_write,
++ .write_room = opticon_write_room,
+ .shutdown = opticon_shutdown,
+ .throttle = opticon_throttle,
+ .unthrottle = opticon_unthrottle,