]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/usb/serial/usb_wwan.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / usb / serial / usb_wwan.c
index fbc94679780168b9ef0a455dc0c1bcf0211d741e..9c014e2ecd68ef6fcdf0c6c9f5e0d15a8e046c41 100644 (file)
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/serial.h>
 #include "usb-wwan.h"
 
 static int debug;
@@ -123,6 +125,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
 }
 EXPORT_SYMBOL(usb_wwan_tiocmset);
 
+static int get_serial_info(struct usb_serial_port *port,
+                          struct serial_struct __user *retinfo)
+{
+       struct serial_struct tmp;
+
+       if (!retinfo)
+               return -EFAULT;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.line            = port->serial->minor;
+       tmp.port            = port->number;
+       tmp.baud_base       = tty_get_baud_rate(port->port.tty);
+       tmp.close_delay     = port->port.close_delay / 10;
+       tmp.closing_wait    = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                                ASYNC_CLOSING_WAIT_NONE :
+                                port->port.closing_wait / 10;
+
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+                          struct serial_struct __user *newinfo)
+{
+       struct serial_struct new_serial;
+       unsigned int closing_wait, close_delay;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+               return -EFAULT;
+
+       close_delay = new_serial.close_delay * 10;
+       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+       mutex_lock(&port->port.mutex);
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((close_delay != port->port.close_delay) ||
+                   (closing_wait != port->port.closing_wait))
+                       retval = -EPERM;
+               else
+                       retval = -EOPNOTSUPP;
+       } else {
+               port->port.close_delay  = close_delay;
+               port->port.closing_wait = closing_wait;
+       }
+
+       mutex_unlock(&port->port.mutex);
+       return retval;
+}
+
+int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
+                  unsigned int cmd, unsigned long arg)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       dbg("%s cmd 0x%04x", __func__, cmd);
+
+       switch (cmd) {
+       case TIOCGSERIAL:
+               return get_serial_info(port,
+                                      (struct serial_struct __user *) arg);
+       case TIOCSSERIAL:
+               return set_serial_info(port,
+                                      (struct serial_struct __user *) arg);
+       default:
+               break;
+       }
+
+       dbg("%s arg not supported", __func__);
+
+       return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(usb_wwan_ioctl);
+
 /* Write */
 int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
                   const unsigned char *buf, int count)
@@ -216,12 +295,15 @@ static void usb_wwan_indat_callback(struct urb *urb)
                    __func__, status, endpoint);
        } else {
                tty = tty_port_tty_get(&port->port);
-               if (urb->actual_length) {
-                       tty_insert_flip_string(tty, data, urb->actual_length);
-                       tty_flip_buffer_push(tty);
-               } else
-                       dbg("%s: empty read urb received", __func__);
-               tty_kref_put(tty);
+               if (tty) {
+                       if (urb->actual_length) {
+                               tty_insert_flip_string(tty, data,
+                                               urb->actual_length);
+                               tty_flip_buffer_push(tty);
+                       } else
+                               dbg("%s: empty read urb received", __func__);
+                       tty_kref_put(tty);
+               }
 
                /* Resubmit urb so we continue receiving */
                if (status != -ESHUTDOWN) {