ChangeSet 1.1002.3.14, 2003/02/25 11:12:34-08:00, [EMAIL PROTECTED]
[PATCH] USB: fix potential races in mct_u232 now that there's no locks in the
usb-serial core.
drivers/usb/serial/mct_u232.c | 106 ++++++++++++++++++++++++++++++------------
1 files changed, 76 insertions(+), 30 deletions(-)
diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c Fri Feb 28 14:50:33 2003
+++ b/drivers/usb/serial/mct_u232.c Fri Feb 28 14:50:33 2003
@@ -171,6 +171,7 @@
struct mct_u232_private {
+ spinlock_t lock;
unsigned long control_state; /* Modem Line Setting (TIOCM) */
unsigned char last_lcr; /* Line Control Register */
unsigned char last_lsr; /* Line Status Register */
@@ -306,8 +307,9 @@
/* allocate the private data structure */
priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
if (!priv)
- return (-1); /* error */
+ return -ENOMEM;
/* set initial values for control structures */
+ spin_lock_init(&priv->lock);
priv->control_state = 0;
priv->last_lsr = 0;
priv->last_msr = 0;
@@ -339,6 +341,10 @@
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
int retval = 0;
+ unsigned long control_state;
+ unsigned long flags;
+ unsigned char last_lcr;
+ unsigned char last_msr;
dbg("%s port %d", __FUNCTION__, port->number);
@@ -355,20 +361,27 @@
* sure if this is really necessary. But it should not harm
* either.
*/
+ spin_lock_irqsave(&priv->lock, flags);
if (port->tty->termios->c_cflag & CBAUD)
priv->control_state = TIOCM_DTR | TIOCM_RTS;
else
priv->control_state = 0;
- mct_u232_set_modem_ctrl(serial, priv->control_state);
priv->last_lcr = (MCT_U232_DATA_BITS_8 |
MCT_U232_PARITY_NONE |
MCT_U232_STOP_BITS_1);
- mct_u232_set_line_ctrl(serial, priv->last_lcr);
+ control_state = priv->control_state;
+ last_lcr = priv->last_lcr;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mct_u232_set_modem_ctrl(serial, control_state);
+ mct_u232_set_line_ctrl(serial, last_lcr);
/* Read modem status and update control state */
- mct_u232_get_modem_stat(serial, &priv->last_msr);
+ mct_u232_get_modem_stat(serial, &last_msr);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->last_msr = last_msr;
mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+ spin_unlock_irqrestore(&priv->lock, flags);
{
/* Puh, that's dirty */
@@ -523,6 +536,7 @@
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status;
+ unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -567,6 +581,7 @@
* The interrupt-in pipe signals exceptional conditions (modem line
* signal changes and errors). data[0] holds MSR, data[1] holds LSR.
*/
+ spin_lock_irqsave(&priv->lock, flags);
priv->last_msr = data[MCT_U232_MSR_INDEX];
/* Record Control Line states */
@@ -597,6 +612,7 @@
}
}
#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
@@ -614,7 +630,16 @@
unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
-
+ unsigned long flags;
+ unsigned long control_state;
+ unsigned char last_lcr;
+
+ /* get a local copy of the current port settings */
+ spin_lock_irqsave(&priv->lock, flags);
+ control_state = priv->control_state;
+ last_lcr = priv->last_lcr;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/*
* Update baud rate
*/
@@ -622,12 +647,12 @@
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag & CBAUD) == B0 ) {
dbg("%s: baud was B0", __FUNCTION__);
- priv->control_state |= TIOCM_DTR;
+ control_state |= TIOCM_DTR;
/* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS)) {
- priv->control_state |= TIOCM_RTS;
+ control_state |= TIOCM_RTS;
}
- mct_u232_set_modem_ctrl(serial, priv->control_state);
+ mct_u232_set_modem_ctrl(serial, control_state);
}
switch(cflag & CBAUD) {
@@ -659,8 +684,8 @@
if ((cflag & CBAUD) == B0 ) {
dbg("%s: baud is B0", __FUNCTION__);
/* Drop RTS and DTR */
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- mct_u232_set_modem_ctrl(serial, priv->control_state);
+ control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ mct_u232_set_modem_ctrl(serial, control_state);
}
}
@@ -672,36 +697,36 @@
|| (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
- priv->last_lcr = 0;
+ last_lcr = 0;
/* set the parity */
if (cflag & PARENB)
- priv->last_lcr |= (cflag & PARODD) ?
+ last_lcr |= (cflag & PARODD) ?
MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
else
- priv->last_lcr |= MCT_U232_PARITY_NONE;
+ last_lcr |= MCT_U232_PARITY_NONE;
/* set the number of data bits */
switch (cflag & CSIZE) {
case CS5:
- priv->last_lcr |= MCT_U232_DATA_BITS_5; break;
+ last_lcr |= MCT_U232_DATA_BITS_5; break;
case CS6:
- priv->last_lcr |= MCT_U232_DATA_BITS_6; break;
+ last_lcr |= MCT_U232_DATA_BITS_6; break;
case CS7:
- priv->last_lcr |= MCT_U232_DATA_BITS_7; break;
+ last_lcr |= MCT_U232_DATA_BITS_7; break;
case CS8:
- priv->last_lcr |= MCT_U232_DATA_BITS_8; break;
+ last_lcr |= MCT_U232_DATA_BITS_8; break;
default:
err("CSIZE was not CS5-CS8, using default of 8");
- priv->last_lcr |= MCT_U232_DATA_BITS_8;
+ last_lcr |= MCT_U232_DATA_BITS_8;
break;
}
/* set the number of stop bits */
- priv->last_lcr |= (cflag & CSTOPB) ?
+ last_lcr |= (cflag & CSTOPB) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
- mct_u232_set_line_ctrl(serial, priv->last_lcr);
+ mct_u232_set_line_ctrl(serial, last_lcr);
}
/*
@@ -714,11 +739,17 @@
/* Drop DTR/RTS if no flow control otherwise assert */
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
- priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+ control_state |= TIOCM_DTR | TIOCM_RTS;
else
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- mct_u232_set_modem_ctrl(serial, priv->control_state);
+ control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ mct_u232_set_modem_ctrl(serial, control_state);
}
+
+ /* save off the modified port settings */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->control_state = control_state;
+ priv->last_lcr = last_lcr;
+ spin_unlock_irqrestore(&priv->lock, flags);
} /* mct_u232_set_termios */
@@ -726,10 +757,15 @@
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned char lcr = priv->last_lcr;
+ unsigned char lcr;
+ unsigned long flags;
dbg("%sstate=%d", __FUNCTION__, break_state);
+ spin_lock_irqsave(&priv->lock, flags);
+ lcr = priv->last_lcr;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
if (break_state)
lcr |= MCT_U232_SET_BREAK;
@@ -743,13 +779,19 @@
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
int mask;
+ unsigned long control_state;
+ unsigned long flags;
dbg("%scmd=0x%x", __FUNCTION__, cmd);
+ spin_lock_irqsave(&priv->lock, flags);
+ control_state = priv->control_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* Based on code from acm.c and others */
switch (cmd) {
case TIOCMGET:
- return put_user(priv->control_state, (unsigned long *) arg);
+ return put_user(control_state, (unsigned long *) arg);
break;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */
@@ -762,20 +804,24 @@
/* RTS needs set */
if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
(cmd == TIOCMBIS) )
- priv->control_state |= TIOCM_RTS;
+ control_state |= TIOCM_RTS;
else
- priv->control_state &= ~TIOCM_RTS;
+ control_state &= ~TIOCM_RTS;
}
if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
/* DTR needs set */
if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
(cmd == TIOCMBIS) )
- priv->control_state |= TIOCM_DTR;
+ control_state |= TIOCM_DTR;
else
- priv->control_state &= ~TIOCM_DTR;
+ control_state &= ~TIOCM_DTR;
}
- mct_u232_set_modem_ctrl(serial, priv->control_state);
+ mct_u232_set_modem_ctrl(serial, control_state);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->control_state = control_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
break;
case TIOCMIWAIT:
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel