diff options
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 14 |
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; |