aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/serial/ftdi_sio.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index dd5bfbc77051..82612997f92c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -33,12 +33,12 @@
33#include <linux/errno.h> 33#include <linux/errno.h>
34#include <linux/init.h> 34#include <linux/init.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/smp_lock.h>
37#include <linux/tty.h> 36#include <linux/tty.h>
38#include <linux/tty_driver.h> 37#include <linux/tty_driver.h>
39#include <linux/tty_flip.h> 38#include <linux/tty_flip.h>
40#include <linux/module.h> 39#include <linux/module.h>
41#include <linux/spinlock.h> 40#include <linux/spinlock.h>
41#include <linux/mutex.h>
42#include <linux/uaccess.h> 42#include <linux/uaccess.h>
43#include <linux/usb.h> 43#include <linux/usb.h>
44#include <linux/serial.h> 44#include <linux/serial.h>
@@ -92,6 +92,7 @@ struct ftdi_private {
92 unsigned long tx_outstanding_bytes; 92 unsigned long tx_outstanding_bytes;
93 unsigned long tx_outstanding_urbs; 93 unsigned long tx_outstanding_urbs;
94 unsigned short max_packet_size; 94 unsigned short max_packet_size;
95 struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() */
95}; 96};
96 97
97/* struct ftdi_sio_quirk is used by devices requiring special attention. */ 98/* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -1218,7 +1219,7 @@ static int set_serial_info(struct tty_struct *tty,
1218 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) 1219 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
1219 return -EFAULT; 1220 return -EFAULT;
1220 1221
1221 lock_kernel(); 1222 mutex_lock(&priv->cfg_lock);
1222 old_priv = *priv; 1223 old_priv = *priv;
1223 1224
1224 /* Do error checking and permission checking */ 1225 /* Do error checking and permission checking */
@@ -1226,7 +1227,7 @@ static int set_serial_info(struct tty_struct *tty,
1226 if (!capable(CAP_SYS_ADMIN)) { 1227 if (!capable(CAP_SYS_ADMIN)) {
1227 if (((new_serial.flags & ~ASYNC_USR_MASK) != 1228 if (((new_serial.flags & ~ASYNC_USR_MASK) !=
1228 (priv->flags & ~ASYNC_USR_MASK))) { 1229 (priv->flags & ~ASYNC_USR_MASK))) {
1229 unlock_kernel(); 1230 mutex_unlock(&priv->cfg_lock);
1230 return -EPERM; 1231 return -EPERM;
1231 } 1232 }
1232 priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | 1233 priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
@@ -1237,7 +1238,7 @@ static int set_serial_info(struct tty_struct *tty,
1237 1238
1238 if ((new_serial.baud_base != priv->baud_base) && 1239 if ((new_serial.baud_base != priv->baud_base) &&
1239 (new_serial.baud_base < 9600)) { 1240 (new_serial.baud_base < 9600)) {
1240 unlock_kernel(); 1241 mutex_unlock(&priv->cfg_lock);
1241 return -EINVAL; 1242 return -EINVAL;
1242 } 1243 }
1243 1244
@@ -1267,11 +1268,11 @@ check_and_exit:
1267 (priv->flags & ASYNC_SPD_MASK)) || 1268 (priv->flags & ASYNC_SPD_MASK)) ||
1268 (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && 1269 (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
1269 (old_priv.custom_divisor != priv->custom_divisor))) { 1270 (old_priv.custom_divisor != priv->custom_divisor))) {
1270 unlock_kernel(); 1271 mutex_unlock(&priv->cfg_lock);
1271 change_speed(tty, port); 1272 change_speed(tty, port);
1272 } 1273 }
1273 else 1274 else
1274 unlock_kernel(); 1275 mutex_unlock(&priv->cfg_lock);
1275 return 0; 1276 return 0;
1276 1277
1277} /* set_serial_info */ 1278} /* set_serial_info */
@@ -1538,6 +1539,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
1538 1539
1539 kref_init(&priv->kref); 1540 kref_init(&priv->kref);
1540 spin_lock_init(&priv->tx_lock); 1541 spin_lock_init(&priv->tx_lock);
1542 mutex_init(&priv->cfg_lock);
1541 init_waitqueue_head(&priv->delta_msr_wait); 1543 init_waitqueue_head(&priv->delta_msr_wait);
1542 1544
1543 priv->flags = ASYNC_LOW_LATENCY; 1545 priv->flags = ASYNC_LOW_LATENCY;