|
@@ -23,7 +23,6 @@
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/signal.h>
|
|
|
#include <linux/sched.h>
|
|
|
-#include <linux/smp_lock.h>
|
|
|
#include <linux/timer.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/tty.h>
|
|
@@ -1229,6 +1228,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|
|
struct serial_struct __user *new_info)
|
|
|
{
|
|
|
struct mxser_port *info = tty->driver_data;
|
|
|
+ struct tty_port *port = &info->port;
|
|
|
struct serial_struct new_serial;
|
|
|
speed_t baud;
|
|
|
unsigned long sl_flags;
|
|
@@ -1244,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|
|
new_serial.port != info->ioaddr)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- flags = info->port.flags & ASYNC_SPD_MASK;
|
|
|
+ flags = port->flags & ASYNC_SPD_MASK;
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN)) {
|
|
|
if ((new_serial.baud_base != info->baud_base) ||
|
|
@@ -1258,16 +1258,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|
|
* OK, past this point, all the error checking has been done.
|
|
|
* At this point, we start making changes.....
|
|
|
*/
|
|
|
- info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
|
|
|
+ port->flags = ((port->flags & ~ASYNC_FLAGS) |
|
|
|
(new_serial.flags & ASYNC_FLAGS));
|
|
|
- info->port.close_delay = new_serial.close_delay * HZ / 100;
|
|
|
- info->port.closing_wait = new_serial.closing_wait * HZ / 100;
|
|
|
- tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
|
|
|
- ? 1 : 0;
|
|
|
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
|
|
+ port->close_delay = new_serial.close_delay * HZ / 100;
|
|
|
+ port->closing_wait = new_serial.closing_wait * HZ / 100;
|
|
|
+ tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
|
|
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
|
|
(new_serial.baud_base != info->baud_base ||
|
|
|
new_serial.custom_divisor !=
|
|
|
info->custom_divisor)) {
|
|
|
+ if (new_serial.custom_divisor == 0)
|
|
|
+ return -EINVAL;
|
|
|
baud = new_serial.baud_base / new_serial.custom_divisor;
|
|
|
tty_encode_baud_rate(tty, baud, baud);
|
|
|
}
|
|
@@ -1277,18 +1278,16 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|
|
|
|
|
process_txrx_fifo(info);
|
|
|
|
|
|
- if (info->port.flags & ASYNC_INITIALIZED) {
|
|
|
- if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
|
|
|
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
|
|
+ if (flags != (port->flags & ASYNC_SPD_MASK)) {
|
|
|
spin_lock_irqsave(&info->slock, sl_flags);
|
|
|
mxser_change_speed(tty, NULL);
|
|
|
spin_unlock_irqrestore(&info->slock, sl_flags);
|
|
|
}
|
|
|
} else {
|
|
|
- mutex_lock(&info->port.mutex);
|
|
|
- retval = mxser_activate(&info->port, tty);
|
|
|
+ retval = mxser_activate(port, tty);
|
|
|
if (retval == 0)
|
|
|
- set_bit(ASYNCB_INITIALIZED, &info->port.flags);
|
|
|
- mutex_unlock(&info->port.mutex);
|
|
|
+ set_bit(ASYNCB_INITIALIZED, &port->flags);
|
|
|
}
|
|
|
return retval;
|
|
|
}
|
|
@@ -1478,7 +1477,8 @@ static int __init mxser_read_register(int port, unsigned short *regs)
|
|
|
|
|
|
static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|
|
{
|
|
|
- struct mxser_port *port;
|
|
|
+ struct mxser_port *ip;
|
|
|
+ struct tty_port *port;
|
|
|
struct tty_struct *tty;
|
|
|
int result, status;
|
|
|
unsigned int i, j;
|
|
@@ -1494,38 +1494,39 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|
|
|
|
|
case MOXA_CHKPORTENABLE:
|
|
|
result = 0;
|
|
|
- lock_kernel();
|
|
|
for (i = 0; i < MXSER_BOARDS; i++)
|
|
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
|
|
|
if (mxser_boards[i].ports[j].ioaddr)
|
|
|
result |= (1 << i);
|
|
|
- unlock_kernel();
|
|
|
return put_user(result, (unsigned long __user *)argp);
|
|
|
case MOXA_GETDATACOUNT:
|
|
|
- lock_kernel();
|
|
|
+ /* The receive side is locked by port->slock but it isn't
|
|
|
+ clear that an exact snapshot is worth copying here */
|
|
|
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
|
|
|
ret = -EFAULT;
|
|
|
- unlock_kernel();
|
|
|
return ret;
|
|
|
case MOXA_GETMSTATUS: {
|
|
|
struct mxser_mstatus ms, __user *msu = argp;
|
|
|
- lock_kernel();
|
|
|
for (i = 0; i < MXSER_BOARDS; i++)
|
|
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
|
|
|
- port = &mxser_boards[i].ports[j];
|
|
|
+ ip = &mxser_boards[i].ports[j];
|
|
|
+ port = &ip->port;
|
|
|
memset(&ms, 0, sizeof(ms));
|
|
|
|
|
|
- if (!port->ioaddr)
|
|
|
+ mutex_lock(&port->mutex);
|
|
|
+ if (!ip->ioaddr)
|
|
|
goto copy;
|
|
|
|
|
|
- tty = tty_port_tty_get(&port->port);
|
|
|
+ tty = tty_port_tty_get(port);
|
|
|
|
|
|
if (!tty || !tty->termios)
|
|
|
- ms.cflag = port->normal_termios.c_cflag;
|
|
|
+ ms.cflag = ip->normal_termios.c_cflag;
|
|
|
else
|
|
|
ms.cflag = tty->termios->c_cflag;
|
|
|
tty_kref_put(tty);
|
|
|
- status = inb(port->ioaddr + UART_MSR);
|
|
|
+ spin_lock_irq(&ip->slock);
|
|
|
+ status = inb(ip->ioaddr + UART_MSR);
|
|
|
+ spin_unlock_irq(&ip->slock);
|
|
|
if (status & UART_MSR_DCD)
|
|
|
ms.dcd = 1;
|
|
|
if (status & UART_MSR_DSR)
|
|
@@ -1533,13 +1534,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|
|
if (status & UART_MSR_CTS)
|
|
|
ms.cts = 1;
|
|
|
copy:
|
|
|
- if (copy_to_user(msu, &ms, sizeof(ms))) {
|
|
|
- unlock_kernel();
|
|
|
+ mutex_unlock(&port->mutex);
|
|
|
+ if (copy_to_user(msu, &ms, sizeof(ms)))
|
|
|
return -EFAULT;
|
|
|
- }
|
|
|
msu++;
|
|
|
}
|
|
|
- unlock_kernel();
|
|
|
return 0;
|
|
|
}
|
|
|
case MOXA_ASPP_MON_EXT: {
|
|
@@ -1551,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|
|
if (!me)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- lock_kernel();
|
|
|
for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
|
|
|
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
|
|
|
if (p >= ARRAY_SIZE(me->rx_cnt)) {
|
|
|
i = MXSER_BOARDS;
|
|
|
break;
|
|
|
}
|
|
|
- port = &mxser_boards[i].ports[j];
|
|
|
- if (!port->ioaddr)
|
|
|
+ ip = &mxser_boards[i].ports[j];
|
|
|
+ port = &ip->port;
|
|
|
+
|
|
|
+ mutex_lock(&port->mutex);
|
|
|
+ if (!ip->ioaddr) {
|
|
|
+ mutex_unlock(&port->mutex);
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
- status = mxser_get_msr(port->ioaddr, 0, p);
|
|
|
+ spin_lock_irq(&ip->slock);
|
|
|
+ status = mxser_get_msr(ip->ioaddr, 0, p);
|
|
|
|
|
|
if (status & UART_MSR_TERI)
|
|
|
- port->icount.rng++;
|
|
|
+ ip->icount.rng++;
|
|
|
if (status & UART_MSR_DDSR)
|
|
|
- port->icount.dsr++;
|
|
|
+ ip->icount.dsr++;
|
|
|
if (status & UART_MSR_DDCD)
|
|
|
- port->icount.dcd++;
|
|
|
+ ip->icount.dcd++;
|
|
|
if (status & UART_MSR_DCTS)
|
|
|
- port->icount.cts++;
|
|
|
+ ip->icount.cts++;
|
|
|
|
|
|
- port->mon_data.modem_status = status;
|
|
|
- me->rx_cnt[p] = port->mon_data.rxcnt;
|
|
|
- me->tx_cnt[p] = port->mon_data.txcnt;
|
|
|
- me->up_rxcnt[p] = port->mon_data.up_rxcnt;
|
|
|
- me->up_txcnt[p] = port->mon_data.up_txcnt;
|
|
|
+ ip->mon_data.modem_status = status;
|
|
|
+ me->rx_cnt[p] = ip->mon_data.rxcnt;
|
|
|
+ me->tx_cnt[p] = ip->mon_data.txcnt;
|
|
|
+ me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
|
|
|
+ me->up_txcnt[p] = ip->mon_data.up_txcnt;
|
|
|
me->modem_status[p] =
|
|
|
- port->mon_data.modem_status;
|
|
|
- tty = tty_port_tty_get(&port->port);
|
|
|
+ ip->mon_data.modem_status;
|
|
|
+ spin_unlock_irq(&ip->slock);
|
|
|
+
|
|
|
+ tty = tty_port_tty_get(&ip->port);
|
|
|
|
|
|
if (!tty || !tty->termios) {
|
|
|
- cflag = port->normal_termios.c_cflag;
|
|
|
- iflag = port->normal_termios.c_iflag;
|
|
|
- me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
|
|
|
+ cflag = ip->normal_termios.c_cflag;
|
|
|
+ iflag = ip->normal_termios.c_iflag;
|
|
|
+ me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
|
|
|
} else {
|
|
|
cflag = tty->termios->c_cflag;
|
|
|
iflag = tty->termios->c_iflag;
|
|
@@ -1604,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|
|
if (iflag & (IXON | IXOFF))
|
|
|
me->flowctrl[p] |= 0x0C;
|
|
|
|
|
|
- if (port->type == PORT_16550A)
|
|
|
+ if (ip->type == PORT_16550A)
|
|
|
me->fifo[p] = 1;
|
|
|
|
|
|
- opmode = inb(port->opmode_ioaddr) >>
|
|
|
- ((p % 4) * 2);
|
|
|
+ opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
|
|
|
opmode &= OP_MODE_MASK;
|
|
|
me->iftype[p] = opmode;
|
|
|
+ mutex_unlock(&port->mutex);
|
|
|
}
|
|
|
}
|
|
|
- unlock_kernel();
|
|
|
if (copy_to_user(argp, me, sizeof(*me)))
|
|
|
ret = -EFAULT;
|
|
|
kfree(me);
|
|
@@ -1650,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct mxser_port *info = tty->driver_data;
|
|
|
+ struct tty_port *port = &info->port;
|
|
|
struct async_icount cnow;
|
|
|
unsigned long flags;
|
|
|
void __user *argp = (void __user *)arg;
|
|
@@ -1674,20 +1680,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|
|
opmode != RS422_MODE &&
|
|
|
opmode != RS485_4WIRE_MODE)
|
|
|
return -EFAULT;
|
|
|
- lock_kernel();
|
|
|
mask = ModeMask[p];
|
|
|
shiftbit = p * 2;
|
|
|
+ spin_lock_irq(&info->slock);
|
|
|
val = inb(info->opmode_ioaddr);
|
|
|
val &= mask;
|
|
|
val |= (opmode << shiftbit);
|
|
|
outb(val, info->opmode_ioaddr);
|
|
|
- unlock_kernel();
|
|
|
+ spin_unlock_irq(&info->slock);
|
|
|
} else {
|
|
|
- lock_kernel();
|
|
|
shiftbit = p * 2;
|
|
|
+ spin_lock_irq(&info->slock);
|
|
|
opmode = inb(info->opmode_ioaddr) >> shiftbit;
|
|
|
+ spin_unlock_irq(&info->slock);
|
|
|
opmode &= OP_MODE_MASK;
|
|
|
- unlock_kernel();
|
|
|
if (put_user(opmode, (int __user *)argp))
|
|
|
return -EFAULT;
|
|
|
}
|
|
@@ -1700,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|
|
|
|
|
switch (cmd) {
|
|
|
case TIOCGSERIAL:
|
|
|
- lock_kernel();
|
|
|
+ mutex_lock(&port->mutex);
|
|
|
retval = mxser_get_serial_info(tty, argp);
|
|
|
- unlock_kernel();
|
|
|
+ mutex_unlock(&port->mutex);
|
|
|
return retval;
|
|
|
case TIOCSSERIAL:
|
|
|
- lock_kernel();
|
|
|
+ mutex_lock(&port->mutex);
|
|
|
retval = mxser_set_serial_info(tty, argp);
|
|
|
- unlock_kernel();
|
|
|
+ mutex_unlock(&port->mutex);
|
|
|
return retval;
|
|
|
case TIOCSERGETLSR: /* Get line status register */
|
|
|
return mxser_get_lsr_info(info, argp);
|
|
@@ -1753,31 +1759,33 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|
|
case MOXA_HighSpeedOn:
|
|
|
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
|
|
|
case MOXA_SDS_RSTICOUNTER:
|
|
|
- lock_kernel();
|
|
|
+ spin_lock_irq(&info->slock);
|
|
|
info->mon_data.rxcnt = 0;
|
|
|
info->mon_data.txcnt = 0;
|
|
|
- unlock_kernel();
|
|
|
+ spin_unlock_irq(&info->slock);
|
|
|
return 0;
|
|
|
|
|
|
case MOXA_ASPP_OQUEUE:{
|
|
|
int len, lsr;
|
|
|
|
|
|
- lock_kernel();
|
|
|
len = mxser_chars_in_buffer(tty);
|
|
|
+ spin_lock(&info->slock);
|
|
|
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
|
|
|
+ spin_unlock_irq(&info->slock);
|
|
|
len += (lsr ? 0 : 1);
|
|
|
- unlock_kernel();
|
|
|
|
|
|
return put_user(len, (int __user *)argp);
|
|
|
}
|
|
|
case MOXA_ASPP_MON: {
|
|
|
int mcr, status;
|
|
|
|
|
|
- lock_kernel();
|
|
|
+ spin_lock(&info->slock);
|
|
|
status = mxser_get_msr(info->ioaddr, 1, tty->index);
|
|
|
mxser_check_modem_status(tty, info, status);
|
|
|
|
|
|
mcr = inb(info->ioaddr + UART_MCR);
|
|
|
+ spin_unlock(&info->slock);
|
|
|
+
|
|
|
if (mcr & MOXA_MUST_MCR_XON_FLAG)
|
|
|
info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
|
|
|
else
|
|
@@ -1792,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
|
|
|
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
|
|
|
else
|
|
|
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
|
|
|
- unlock_kernel();
|
|
|
+
|
|
|
if (copy_to_user(argp, &info->mon_data,
|
|
|
sizeof(struct mxser_mon)))
|
|
|
return -EFAULT;
|
|
@@ -1951,6 +1959,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
|
|
|
{
|
|
|
struct mxser_port *info = tty->driver_data;
|
|
|
unsigned long orig_jiffies, char_time;
|
|
|
+ unsigned long flags;
|
|
|
int lsr;
|
|
|
|
|
|
if (info->type == PORT_UNKNOWN)
|
|
@@ -1990,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
|
|
|
timeout, char_time);
|
|
|
printk("jiff=%lu...", jiffies);
|
|
|
#endif
|
|
|
- lock_kernel();
|
|
|
+ spin_lock_irqsave(&info->slock, flags);
|
|
|
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
|
|
|
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
|
|
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
|
|
|
#endif
|
|
|
+ spin_unlock_irqrestore(&info->slock, flags);
|
|
|
schedule_timeout_interruptible(char_time);
|
|
|
+ spin_lock_irqsave(&info->slock, flags);
|
|
|
if (signal_pending(current))
|
|
|
break;
|
|
|
if (timeout && time_after(jiffies, orig_jiffies + timeout))
|
|
|
break;
|
|
|
}
|
|
|
+ spin_unlock_irqrestore(&info->slock, flags);
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
- unlock_kernel();
|
|
|
|
|
|
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
|
|
|
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
|