USB: serial: opticon: add serial line ioctls
[pandora-kernel.git] / drivers / usb / serial / opticon.c
index 8c87a49..839583d 100644 (file)
@@ -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 urb *urb)
                                        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 tty_struct *tty)
                                                        __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_device = {
        .shutdown =             opticon_shutdown,
        .throttle =             opticon_throttle,
        .unthrottle =           opticon_unthrottle,
+       .ioctl =                opticon_ioctl,
+       .tiocmget =             opticon_tiocmget,
 };
 
 static int __init opticon_init(void)