summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-24 14:43:41 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-24 14:43:41 +0100
commit44adbac8f7217040be97928cd19998259d9d4418 (patch)
treec1c6ac9aa4d47801dc9133d6d641286631a8f4b4 /drivers/tty
parent08ffb584d9eb17940321317ef6c9c7383ad4f149 (diff)
parentce5a983191ce466cbe35e240ac09e28cca3e50c9 (diff)
Merge branch 'work.tty-ioctl' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull tty ioctl updates from Al Viro: "This is the compat_ioctl work related to tty ioctls. Quite a bit of dead code taken out, all tty-related stuff gone from fs/compat_ioctl.c. A bunch of compat bugs fixed - some still remain, but all more or less generic tty-related ioctls should be covered (remaining issues are in things like driver-private ioctls in a pcmcia serial card driver not getting properly handled in 32bit processes on 64bit host, etc)" * 'work.tty-ioctl' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (53 commits) kill TIOCSERGSTRUCT change semantics of ldisc ->compat_ioctl() kill TIOCSER[SG]WILD synclink_gt(): fix compat_ioctl() pty: fix compat ioctls compat_ioctl - kill keyboard ioctl handling gigaset: add ->compat_ioctl() vt_compat_ioctl(): clean up, use compat_ptr() properly gigaset: don't try to printk userland buffer contents dgnc: don't bother with (empty) stub for TCXONC dgnc: leave TIOC[GS]SOFTCAR to ldisc remove fallback to drivers for TIOCGICOUNT dgnc: break-related ioctls won't reach ->ioctl() kill the rest of tty COMPAT_IOCTL() entries dgnc: TIOCM... won't reach ->ioctl() isdn_tty: TCSBRK{,P} won't reach ->ioctl() kill capinc_tty_ioctl() take compat TIOC[SG]SERIAL treatment into tty_compat_ioctl() synclink: reduce pointless checks in ->ioctl() complete ->[sg]et_serial() switchover ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/amiserial.c90
-rw-r--r--drivers/tty/cyclades.c77
-rw-r--r--drivers/tty/ipwireless/tty.c36
-rw-r--r--drivers/tty/isicom.c72
-rw-r--r--drivers/tty/moxa.c79
-rw-r--r--drivers/tty/mxser.c97
-rw-r--r--drivers/tty/n_gsm.c11
-rw-r--r--drivers/tty/n_r3964.c22
-rw-r--r--drivers/tty/pty.c14
-rw-r--r--drivers/tty/serial/serial_core.c43
-rw-r--r--drivers/tty/synclink.c3
-rw-r--r--drivers/tty/synclink_gt.c19
-rw-r--r--drivers/tty/synclinkmp.c3
-rw-r--r--drivers/tty/tty_io.c229
-rw-r--r--drivers/tty/tty_ioctl.c16
-rw-r--r--drivers/tty/vt/vt_ioctl.c31
16 files changed, 452 insertions, 390 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 34dead614149..8330fd809a05 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -996,63 +996,55 @@ static void rs_unthrottle(struct tty_struct * tty)
* ------------------------------------------------------------
*/
-static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
- struct serial_struct __user * retinfo)
+static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
+ struct serial_state *state = tty->driver_data;
+
tty_lock(tty);
- tmp.line = tty->index;
- tmp.port = state->port;
- tmp.flags = state->tport.flags;
- tmp.xmit_fifo_size = state->xmit_fifo_size;
- tmp.baud_base = state->baud_base;
- tmp.close_delay = state->tport.close_delay;
- tmp.closing_wait = state->tport.closing_wait;
- tmp.custom_divisor = state->custom_divisor;
+ ss->line = tty->index;
+ ss->port = state->port;
+ ss->flags = state->tport.flags;
+ ss->xmit_fifo_size = state->xmit_fifo_size;
+ ss->baud_base = state->baud_base;
+ ss->close_delay = state->tport.close_delay;
+ ss->closing_wait = state->tport.closing_wait;
+ ss->custom_divisor = state->custom_divisor;
tty_unlock(tty);
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
return 0;
}
-static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
- struct serial_struct __user * new_info)
+static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
+ struct serial_state *state = tty->driver_data;
struct tty_port *port = &state->tport;
- struct serial_struct new_serial;
bool change_spd;
int retval = 0;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
-
tty_lock(tty);
- change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
- new_serial.custom_divisor != state->custom_divisor;
- if (new_serial.irq || new_serial.port != state->port ||
- new_serial.xmit_fifo_size != state->xmit_fifo_size) {
+ change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) ||
+ ss->custom_divisor != state->custom_divisor;
+ if (ss->irq || ss->port != state->port ||
+ ss->xmit_fifo_size != state->xmit_fifo_size) {
tty_unlock(tty);
return -EINVAL;
}
if (!serial_isroot()) {
- if ((new_serial.baud_base != state->baud_base) ||
- (new_serial.close_delay != port->close_delay) ||
- (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ if ((ss->baud_base != state->baud_base) ||
+ (ss->close_delay != port->close_delay) ||
+ (ss->xmit_fifo_size != state->xmit_fifo_size) ||
+ ((ss->flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- state->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK));
+ state->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
- if (new_serial.baud_base < 9600) {
+ if (ss->baud_base < 9600) {
tty_unlock(tty);
return -EINVAL;
}
@@ -1062,19 +1054,19 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
* At this point, we start making changes.....
*/
- state->baud_base = new_serial.baud_base;
+ state->baud_base = ss->baud_base;
port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- state->custom_divisor = new_serial.custom_divisor;
- port->close_delay = new_serial.close_delay * HZ/100;
- port->closing_wait = new_serial.closing_wait * HZ/100;
+ (ss->flags & ASYNC_FLAGS));
+ state->custom_divisor = ss->custom_divisor;
+ port->close_delay = ss->close_delay * HZ/100;
+ port->closing_wait = ss->closing_wait * HZ/100;
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit:
if (tty_port_initialized(port)) {
if (change_spd) {
/* warn about deprecation unless clearing */
- if (new_serial.flags & ASYNC_SPD_MASK)
+ if (ss->flags & ASYNC_SPD_MASK)
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
change_speed(tty, state, NULL);
}
@@ -1084,7 +1076,6 @@ check_and_exit:
return retval;
}
-
/*
* get_lsr_info - get line status register info
*
@@ -1224,30 +1215,19 @@ static int rs_ioctl(struct tty_struct *tty,
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ if ((cmd != TIOCSERCONFIG) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty_io_error(tty))
return -EIO;
}
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(tty, info, argp);
- case TIOCSSERIAL:
- return set_serial_info(tty, info, argp);
case TIOCSERCONFIG:
return 0;
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, argp);
- case TIOCSERGSTRUCT:
- if (copy_to_user(argp,
- info, sizeof(struct serial_state)))
- return -EFAULT;
- return 0;
-
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1288,12 +1268,6 @@ static int rs_ioctl(struct tty_struct *tty,
finish_wait(&info->tport.delta_msr_wait, &wait);
return ret;
- case TIOCSERGWILD:
- case TIOCSERSWILD:
- /* "setserial -W" is called in Debian boot */
- printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
- return 0;
-
default:
return -ENOIOCTLCMD;
}
@@ -1607,6 +1581,8 @@ static const struct tty_operations serial_ops = {
.tiocmget = rs_tiocmget,
.tiocmset = rs_tiocmset,
.get_icount = rs_get_icount,
+ .set_serial = set_serial_info,
+ .get_serial = get_serial_info,
.proc_show = rs_proc_show,
};
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index 6d3c58051ce3..4562c8060d09 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -2257,44 +2257,45 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
}
} /* set_line_char */
-static int cy_get_serial_info(struct cyclades_port *info,
- struct serial_struct __user *retinfo)
+static int cy_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
+ struct cyclades_port *info = tty->driver_data;
struct cyclades_card *cinfo = info->card;
- struct serial_struct tmp = {
- .type = info->type,
- .line = info->line,
- .port = (info->card - cy_card) * 0x100 + info->line -
- cinfo->first_line,
- .irq = cinfo->irq,
- .flags = info->port.flags,
- .close_delay = info->port.close_delay,
- .closing_wait = info->port.closing_wait,
- .baud_base = info->baud,
- .custom_divisor = info->custom_divisor,
- };
- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
+ ss->type = info->type;
+ ss->line = info->line;
+ ss->port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line;
+ ss->irq = cinfo->irq;
+ ss->flags = info->port.flags;
+ ss->close_delay = info->port.close_delay;
+ ss->closing_wait = info->port.closing_wait;
+ ss->baud_base = info->baud;
+ ss->custom_divisor = info->custom_divisor;
+ return 0;
}
-static int
-cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
- struct serial_struct __user *new_info)
+static int cy_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct cyclades_port *info = tty->driver_data;
int old_flags;
int ret;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
mutex_lock(&info->port.mutex);
old_flags = info->port.flags;
if (!capable(CAP_SYS_ADMIN)) {
- if (new_serial.close_delay != info->port.close_delay ||
- new_serial.baud_base != info->baud ||
- (new_serial.flags & ASYNC_FLAGS &
+ if (ss->close_delay != info->port.close_delay ||
+ ss->baud_base != info->baud ||
+ (ss->flags & ASYNC_FLAGS &
~ASYNC_USR_MASK) !=
(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
{
@@ -2302,9 +2303,9 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
return -EPERM;
}
info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK);
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK);
+ info->baud = ss->baud_base;
+ info->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
@@ -2313,18 +2314,18 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
* At this point, we start making changes.....
*/
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
+ info->baud = ss->baud_base;
+ info->custom_divisor = ss->custom_divisor;
info->port.flags = (info->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;
+ (ss->flags & ASYNC_FLAGS);
+ info->port.close_delay = ss->close_delay * HZ / 100;
+ info->port.closing_wait = ss->closing_wait * HZ / 100;
check_and_exit:
if (tty_port_initialized(&info->port)) {
- if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) {
+ if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) {
/* warn about deprecation unless clearing */
- if (new_serial.flags & ASYNC_SPD_MASK)
+ if (ss->flags & ASYNC_SPD_MASK)
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
}
cy_set_line_char(info, tty);
@@ -2698,12 +2699,6 @@ cy_ioctl(struct tty_struct *tty,
case CYGETWAIT:
ret_val = info->port.closing_wait / (HZ / 100);
break;
- case TIOCGSERIAL:
- ret_val = cy_get_serial_info(info, argp);
- break;
- case TIOCSSERIAL:
- ret_val = cy_set_serial_info(info, tty, argp);
- break;
case TIOCSERGETLSR: /* Get line status register */
ret_val = get_lsr_info(info, argp);
break;
@@ -4011,6 +4006,8 @@ static const struct tty_operations cy_ops = {
.tiocmget = cy_tiocmget,
.tiocmset = cy_tiocmset,
.get_icount = cy_get_icount,
+ .set_serial = cy_set_serial_info,
+ .get_serial = cy_get_serial_info,
.proc_show = cyclades_proc_show,
};
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 1ef751c27ac6..fad3401e604d 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -248,22 +248,29 @@ static int ipw_write_room(struct tty_struct *linux_tty)
return room;
}
-static int ipwireless_get_serial_info(struct ipw_tty *tty,
- struct serial_struct __user *retinfo)
+static int ipwireless_get_serial_info(struct tty_struct *linux_tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct ipw_tty *tty = linux_tty->driver_data;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_UNKNOWN;
- tmp.line = tty->index;
- tmp.baud_base = 115200;
+ if (!tty)
+ return -ENODEV;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ if (!tty->port.count)
+ return -EINVAL;
+ ss->type = PORT_UNKNOWN;
+ ss->line = tty->index;
+ ss->baud_base = 115200;
return 0;
}
+static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
+ struct serial_struct *ss)
+{
+ return 0; /* Keeps the PCMCIA scripts happy. */
+}
+
static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
@@ -386,15 +393,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ipwireless_get_serial_info(tty, (void __user *) arg);
-
- case TIOCSSERIAL:
- return 0; /* Keeps the PCMCIA scripts happy. */
- }
-
if (tty->tty_type == TTYTYPE_MODEM) {
switch (cmd) {
case PPPIOCGCHAN:
@@ -561,6 +559,8 @@ static const struct tty_operations tty_ops = {
.chars_in_buffer = ipw_chars_in_buffer,
.tiocmget = ipw_tiocmget,
.tiocmset = ipw_tiocmset,
+ .set_serial = ipwireless_set_serial_info,
+ .get_serial = ipwireless_get_serial_info,
};
int ipwireless_tty_init(void)
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 8d96e86966f1..e04a43e89f6b 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1091,34 +1091,33 @@ static int isicom_tiocmset(struct tty_struct *tty,
}
static int isicom_set_serial_info(struct tty_struct *tty,
- struct serial_struct __user *info)
+ struct serial_struct *ss)
{
struct isi_port *port = tty->driver_data;
- struct serial_struct newinfo;
int reconfig_port;
- if (copy_from_user(&newinfo, info, sizeof(newinfo)))
- return -EFAULT;
+ if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
+ return -ENODEV;
mutex_lock(&port->port.mutex);
reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
- (newinfo.flags & ASYNC_SPD_MASK));
+ (ss->flags & ASYNC_SPD_MASK));
if (!capable(CAP_SYS_ADMIN)) {
- if ((newinfo.close_delay != port->port.close_delay) ||
- (newinfo.closing_wait != port->port.closing_wait) ||
- ((newinfo.flags & ~ASYNC_USR_MASK) !=
+ if ((ss->close_delay != port->port.close_delay) ||
+ (ss->closing_wait != port->port.closing_wait) ||
+ ((ss->flags & ~ASYNC_USR_MASK) !=
(port->port.flags & ~ASYNC_USR_MASK))) {
mutex_unlock(&port->port.mutex);
return -EPERM;
}
port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
- (newinfo.flags & ASYNC_USR_MASK));
+ (ss->flags & ASYNC_USR_MASK));
} else {
- port->port.close_delay = newinfo.close_delay;
- port->port.closing_wait = newinfo.closing_wait;
+ port->port.close_delay = ss->close_delay;
+ port->port.closing_wait = ss->closing_wait;
port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
- (newinfo.flags & ASYNC_FLAGS));
+ (ss->flags & ASYNC_FLAGS));
}
if (reconfig_port) {
unsigned long flags;
@@ -1130,46 +1129,24 @@ static int isicom_set_serial_info(struct tty_struct *tty,
return 0;
}
-static int isicom_get_serial_info(struct isi_port *port,
- struct serial_struct __user *info)
-{
- struct serial_struct out_info;
-
- mutex_lock(&port->port.mutex);
- memset(&out_info, 0, sizeof(out_info));
-/* out_info.type = ? */
- out_info.line = port - isi_ports;
- out_info.port = port->card->base;
- out_info.irq = port->card->irq;
- out_info.flags = port->port.flags;
-/* out_info.baud_base = ? */
- out_info.close_delay = port->port.close_delay;
- out_info.closing_wait = port->port.closing_wait;
- mutex_unlock(&port->port.mutex);
- if (copy_to_user(info, &out_info, sizeof(out_info)))
- return -EFAULT;
- return 0;
-}
-
-static int isicom_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int isicom_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct isi_port *port = tty->driver_data;
- void __user *argp = (void __user *)arg;
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
- switch (cmd) {
- case TIOCGSERIAL:
- return isicom_get_serial_info(port, argp);
-
- case TIOCSSERIAL:
- return isicom_set_serial_info(tty, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
+ mutex_lock(&port->port.mutex);
+/* ss->type = ? */
+ ss->line = port - isi_ports;
+ ss->port = port->card->base;
+ ss->irq = port->card->irq;
+ ss->flags = port->port.flags;
+/* ss->baud_base = ? */
+ ss->close_delay = port->port.close_delay;
+ ss->closing_wait = port->port.closing_wait;
+ mutex_unlock(&port->port.mutex);
return 0;
}
@@ -1273,7 +1250,6 @@ static const struct tty_operations isicom_ops = {
.flush_chars = isicom_flush_chars,
.write_room = isicom_write_room,
.chars_in_buffer = isicom_chars_in_buffer,
- .ioctl = isicom_ioctl,
.set_termios = isicom_set_termios,
.throttle = isicom_throttle,
.unthrottle = isicom_unthrottle,
@@ -1284,6 +1260,8 @@ static const struct tty_operations isicom_ops = {
.tiocmget = isicom_tiocmget,
.tiocmset = isicom_tiocmset,
.break_ctl = isicom_send_break,
+ .get_serial = isicom_get_serial_info,
+ .set_serial = isicom_set_serial_info,
};
static const struct tty_port_operations isicom_port_ops = {
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 250a19f042d7..3a1a5e0ee93f 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -221,8 +221,8 @@ static int MoxaPortRxQueue(struct moxa_port *);
static int MoxaPortTxFree(struct moxa_port *);
static void MoxaPortTxDisable(struct moxa_port *);
static void MoxaPortTxEnable(struct moxa_port *);
-static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
-static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
+static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *);
+static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *);
static void MoxaSetFifo(struct moxa_port *port, int enable);
/*
@@ -375,16 +375,6 @@ copy:
}
break;
}
- case TIOCGSERIAL:
- mutex_lock(&ch->port.mutex);
- ret = moxa_get_serial_info(ch, argp);
- mutex_unlock(&ch->port.mutex);
- break;
- case TIOCSSERIAL:
- mutex_lock(&ch->port.mutex);
- ret = moxa_set_serial_info(ch, argp);
- mutex_unlock(&ch->port.mutex);
- break;
default:
ret = -ENOIOCTLCMD;
}
@@ -415,6 +405,8 @@ static const struct tty_operations moxa_ops = {
.break_ctl = moxa_break_ctl,
.tiocmget = moxa_tiocmget,
.tiocmset = moxa_tiocmset,
+ .set_serial = moxa_set_serial_info,
+ .get_serial = moxa_get_serial_info,
};
static const struct tty_port_operations moxa_port_ops = {
@@ -2034,46 +2026,55 @@ static void MoxaPortTxEnable(struct moxa_port *port)
moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
}
-static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+static int moxa_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp = {
- .type = info->type,
- .line = info->port.tty->index,
- .flags = info->port.flags,
- .baud_base = 921600,
- .close_delay = info->port.close_delay
- };
- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+ struct moxa_port *info = tty->driver_data;
+
+ if (tty->index == MAX_PORTS)
+ return -EINVAL;
+ if (!info)
+ return -ENODEV;
+ mutex_lock(&info->port.mutex);
+ ss->type = info->type,
+ ss->line = info->port.tty->index,
+ ss->flags = info->port.flags,
+ ss->baud_base = 921600,
+ ss->close_delay = info->port.close_delay;
+ mutex_unlock(&info->port.mutex);
+ return 0;
}
-static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+static int moxa_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct moxa_port *info = tty->driver_data;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ if (tty->index == MAX_PORTS)
+ return -EINVAL;
+ if (!info)
+ return -ENODEV;
- if (new_serial.irq != 0 || new_serial.port != 0 ||
- new_serial.custom_divisor != 0 ||
- new_serial.baud_base != 921600)
+ if (ss->irq != 0 || ss->port != 0 ||
+ ss->custom_divisor != 0 ||
+ ss->baud_base != 921600)
return -EPERM;
+ mutex_lock(&info->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
- if (((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->port.flags & ~ASYNC_USR_MASK)))
+ if (((ss->flags & ~ASYNC_USR_MASK) !=
+ (info->port.flags & ~ASYNC_USR_MASK))) {
+ mutex_unlock(&info->port.mutex);
return -EPERM;
- } else
- info->port.close_delay = new_serial.close_delay * HZ / 100;
-
- new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
- new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
+ }
+ }
+ info->port.close_delay = ss->close_delay * HZ / 100;
- MoxaSetFifo(info, new_serial.type == PORT_16550A);
+ MoxaSetFifo(info, ss->type == PORT_16550A);
- info->type = new_serial.type;
+ info->type = ss->type;
+ mutex_unlock(&info->port.mutex);
return 0;
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 8bc15cb67a58..9d00ff5ef961 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1207,76 +1207,90 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
static int mxser_get_serial_info(struct tty_struct *tty,
- struct serial_struct __user *retinfo)
+ struct serial_struct *ss)
{
struct mxser_port *info = tty->driver_data;
- struct serial_struct tmp = {
- .type = info->type,
- .line = tty->index,
- .port = info->ioaddr,
- .irq = info->board->irq,
- .flags = info->port.flags,
- .baud_base = info->baud_base,
- .close_delay = info->port.close_delay,
- .closing_wait = info->port.closing_wait,
- .custom_divisor = info->custom_divisor,
- };
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ struct tty_port *port = &info->port;
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOTTY;
+
+ mutex_lock(&port->mutex);
+ ss->type = info->type,
+ ss->line = tty->index,
+ ss->port = info->ioaddr,
+ ss->irq = info->board->irq,
+ ss->flags = info->port.flags,
+ ss->baud_base = info->baud_base,
+ ss->close_delay = info->port.close_delay,
+ ss->closing_wait = info->port.closing_wait,
+ ss->custom_divisor = info->custom_divisor,
+ mutex_unlock(&port->mutex);
return 0;
}
static int mxser_set_serial_info(struct tty_struct *tty,
- struct serial_struct __user *new_info)
+ struct serial_struct *ss)
{
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;
unsigned int flags;
int retval = 0;
- if (!new_info || !info->ioaddr)
+ if (tty->index == MXSER_PORTS)
+ return -ENOTTY;
+ if (tty_io_error(tty))
+ return -EIO;
+
+ mutex_lock(&port->mutex);
+ if (!info->ioaddr) {
+ mutex_unlock(&port->mutex);
return -ENODEV;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ }
- if (new_serial.irq != info->board->irq ||
- new_serial.port != info->ioaddr)
+ if (ss->irq != info->board->irq ||
+ ss->port != info->ioaddr) {
+ mutex_unlock(&port->mutex);
return -EINVAL;
+ }
flags = port->flags & ASYNC_SPD_MASK;
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.close_delay != info->port.close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK)))
+ if ((ss->baud_base != info->baud_base) ||
+ (ss->close_delay != info->port.close_delay) ||
+ ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) {
+ mutex_unlock(&port->mutex);
return -EPERM;
+ }
info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
+ (ss->flags & ASYNC_USR_MASK));
} else {
/*
* OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/
port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- port->close_delay = new_serial.close_delay * HZ / 100;
- port->closing_wait = new_serial.closing_wait * HZ / 100;
+ (ss->flags & ASYNC_FLAGS));
+ port->close_delay = ss->close_delay * HZ / 100;
+ port->closing_wait = ss->closing_wait * HZ / 100;
port->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 !=
+ (ss->baud_base != info->baud_base ||
+ ss->custom_divisor !=
info->custom_divisor)) {
- if (new_serial.custom_divisor == 0)
+ if (ss->custom_divisor == 0) {
+ mutex_unlock(&port->mutex);
return -EINVAL;
- baud = new_serial.baud_base / new_serial.custom_divisor;
+ }
+ baud = ss->baud_base / ss->custom_divisor;
tty_encode_baud_rate(tty, baud, baud);
}
}
- info->type = new_serial.type;
+ info->type = ss->type;
process_txrx_fifo(info);
@@ -1291,6 +1305,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
if (retval == 0)
tty_port_set_initialized(port, 1);
}
+ mutex_unlock(&port->mutex);
return retval;
}
@@ -1660,11 +1675,9 @@ static int mxser_ioctl(struct tty_struct *tty,
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;
- int retval;
if (tty->index == MXSER_PORTS)
return mxser_ioctl_special(cmd, argp);
@@ -1708,20 +1721,10 @@ static int mxser_ioctl(struct tty_struct *tty,
return 0;
}
- if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty))
+ if (cmd != TIOCMIWAIT && tty_io_error(tty))
return -EIO;
switch (cmd) {
- case TIOCGSERIAL:
- mutex_lock(&port->mutex);
- retval = mxser_get_serial_info(tty, argp);
- mutex_unlock(&port->mutex);
- return retval;
- case TIOCSSERIAL:
- mutex_lock(&port->mutex);
- retval = mxser_set_serial_info(tty, argp);
- mutex_unlock(&port->mutex);
- return retval;
case TIOCSERGETLSR: /* Get line status register */
return mxser_get_lsr_info(info, argp);
/*
@@ -2325,6 +2328,8 @@ static const struct tty_operations mxser_ops = {
.wait_until_sent = mxser_wait_until_sent,
.tiocmget = mxser_tiocmget,
.tiocmset = mxser_tiocmset,
+ .set_serial = mxser_set_serial_info,
+ .get_serial = mxser_get_serial_info,
.get_icount = mxser_get_icount,
};
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 86b7e20ffd7f..6f7da9a9d76f 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2614,14 +2614,6 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
}
}
-#ifdef CONFIG_COMPAT
-static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return gsmld_ioctl(tty, file, cmd, arg);
-}
-#endif
-
/*
* Network interface
*
@@ -2833,9 +2825,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
.flush_buffer = gsmld_flush_buffer,
.read = gsmld_read,
.write = gsmld_write,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = gsmld_compat_ioctl,
-#endif
.ioctl = gsmld_ioctl,
.poll = gsmld_poll,
.receive_buf = gsmld_receive_buf,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index dbf1ab36758e..749a608c40b0 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -134,6 +134,10 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr);
static int r3964_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg);
+#endif
static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
static __poll_t r3964_poll(struct tty_struct *tty, struct file *file,
struct poll_table_struct *wait);
@@ -149,6 +153,9 @@ static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
.read = r3964_read,
.write = r3964_write,
.ioctl = r3964_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = r3964_compat_ioctl,
+#endif
.set_termios = r3964_set_termios,
.poll = r3964_poll,
.receive_buf = r3964_receive_buf,
@@ -1210,6 +1217,21 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
}
}
+#ifdef CONFIG_COMPAT
+static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case R3964_ENABLE_SIGNALS:
+ case R3964_SETPRIORITY:
+ case R3964_USE_BCC:
+ return r3964_ioctl(tty, file, cmd, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#endif
+
static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
{
TRACE_L("set_termios");
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 678406e0948b..00099a8439d2 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -28,6 +28,7 @@
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/ioctl.h>
+#include <linux/compat.h>
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
@@ -488,6 +489,7 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+#ifdef CONFIG_COMPAT
static long pty_bsd_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -495,8 +497,11 @@ static long pty_bsd_compat_ioctl(struct tty_struct *tty,
* PTY ioctls don't require any special translation between 32-bit and
* 64-bit userspace, they are already compatible.
*/
- return pty_bsd_ioctl(tty, cmd, arg);
+ return pty_bsd_ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
}
+#else
+#define pty_bsd_compat_ioctl NULL
+#endif
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
/*
@@ -676,6 +681,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+#ifdef CONFIG_COMPAT
static long pty_unix98_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -683,8 +689,12 @@ static long pty_unix98_compat_ioctl(struct tty_struct *tty,
* PTY ioctls don't require any special translation between 32-bit and
* 64-bit userspace, they are already compatible.
*/
- return pty_unix98_ioctl(tty, cmd, arg);
+ return pty_unix98_ioctl(tty, cmd,
+ cmd == TIOCSIG ? arg : (unsigned long)compat_ptr(arg));
}
+#else
+#define pty_unix98_compat_ioctl NULL
+#endif
/**
* ptm_unix98_lookup - find a pty master
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 80bb56facfb6..54726c3f74c6 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -778,17 +778,13 @@ out:
return ret;
}
-static int uart_get_info_user(struct tty_port *port,
- struct serial_struct __user *retinfo)
+static int uart_get_info_user(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- if (uart_get_info(port, &tmp) < 0)
- return -EIO;
+ struct uart_state *state = tty->driver_data;
+ struct tty_port *port = &state->port;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
+ return uart_get_info(port, ss) < 0 ? -EIO : 0;
}
static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
@@ -990,16 +986,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
return retval;
}
-static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
- struct serial_struct __user *newinfo)
+static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
int retval;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
+ down_write(&tty->termios_rwsem);
/*
* This semaphore protects port->count. It is also
* very useful to prevent opens. Also, take the
@@ -1008,8 +1001,9 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
* under us.
*/
mutex_lock(&port->mutex);
- retval = uart_set_info(tty, port, state, &new_serial);
+ retval = uart_set_info(tty, port, state, ss);
mutex_unlock(&port->mutex);
+ up_write(&tty->termios_rwsem);
return retval;
}
@@ -1325,26 +1319,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
* These ioctls don't rely on the hardware to be present.
*/
switch (cmd) {
- case TIOCGSERIAL:
- ret = uart_get_info_user(port, uarg);
- break;
-
- case TIOCSSERIAL:
- down_write(&tty->termios_rwsem);
- ret = uart_set_info_user(tty, state, uarg);
- up_write(&tty->termios_rwsem);
- break;
-
case TIOCSERCONFIG:
down_write(&tty->termios_rwsem);
ret = uart_do_autoconfig(tty, state);
up_write(&tty->termios_rwsem);
break;
-
- case TIOCSERGWILD: /* obsolete */
- case TIOCSERSWILD: /* obsolete */
- ret = 0;
- break;
}
if (ret != -ENOIOCTLCMD)
@@ -2413,6 +2392,8 @@ static const struct tty_operations uart_ops = {
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
+ .set_serial = uart_set_info_user,
+ .get_serial = uart_get_info_user,
.get_icount = uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index fbdf4d01c6a9..d55c858d6058 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -2959,8 +2959,7 @@ static int mgsl_ioctl(struct tty_struct *tty,
if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index a94086597ebd..e8a9047de451 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -1029,8 +1029,7 @@ static int ioctl(struct tty_struct *tty,
return -ENODEV;
DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
@@ -1186,14 +1185,13 @@ static long slgt_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct slgt_info *info = tty->driver_data;
- int rc = -ENOIOCTLCMD;
+ int rc;
if (sanity_check(info, tty->name, "compat_ioctl"))
return -ENODEV;
DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
switch (cmd) {
-
case MGSL_IOCSPARAMS32:
rc = set_params32(info, compat_ptr(arg));
break;
@@ -1213,18 +1211,11 @@ static long slgt_compat_ioctl(struct tty_struct *tty,
case MGSL_IOCWAITGPIO:
case MGSL_IOCGXSYNC:
case MGSL_IOCGXCTRL:
- case MGSL_IOCSTXIDLE:
- case MGSL_IOCTXENABLE:
- case MGSL_IOCRXENABLE:
- case MGSL_IOCTXABORT:
- case TIOCMIWAIT:
- case MGSL_IOCSIF:
- case MGSL_IOCSXSYNC:
- case MGSL_IOCSXCTRL:
- rc = ioctl(tty, cmd, arg);
+ rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
break;
+ default:
+ rc = ioctl(tty, cmd, arg);
}
-
DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
return rc;
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 1e4d5b9c981a..fcb91bf7a15b 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -1259,8 +1259,7 @@ static int ioctl(struct tty_struct *tty,
if (sanity_check(info, tty->name, "ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 816d8ba971a2..da3c1c2f73c4 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -97,6 +97,7 @@
#include <linux/seq_file.h>
#include <linux/serial.h>
#include <linux/ratelimit.h>
+#include <linux/compat.h>
#include <linux/uaccess.h>
@@ -2293,34 +2294,6 @@ static int tioccons(struct file *file)
}
/**
- * fionbio - non blocking ioctl
- * @file: file to set blocking value
- * @p: user parameter
- *
- * Historical tty interfaces had a blocking control ioctl before
- * the generic functionality existed. This piece of history is preserved
- * in the expected tty API of posix OS's.
- *
- * Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
- int nonblock;
-
- if (get_user(nonblock, p))
- return -EFAULT;
-
- spin_lock(&file->f_lock);
- if (nonblock)
- file->f_flags |= O_NONBLOCK;
- else
- file->f_flags &= ~O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-}
-
-/**
* tiocsetd - set line discipline
* @tty: tty device
* @p: pointer to user data
@@ -2488,22 +2461,40 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
return 0;
}
-static void tty_warn_deprecated_flags(struct serial_struct __user *ss)
+static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss)
{
static DEFINE_RATELIMIT_STATE(depr_flags,
DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
char comm[TASK_COMM_LEN];
+ struct serial_struct v;
int flags;
- if (get_user(flags, &ss->flags))
- return;
+ if (copy_from_user(&v, ss, sizeof(struct serial_struct)))
+ return -EFAULT;
- flags &= ASYNC_DEPRECATED;
+ flags = v.flags & ASYNC_DEPRECATED;
if (flags && __ratelimit(&depr_flags))
pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
__func__, get_task_comm(comm, current), flags);
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ return tty->ops->set_serial(tty, &v);
+}
+
+static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss)
+{
+ struct serial_struct v;
+ int err;
+
+ memset(&v, 0, sizeof(struct serial_struct));
+ if (!tty->ops->get_serial)
+ return -ENOTTY;
+ err = tty->ops->get_serial(tty, &v);
+ if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct)))
+ err = -EFAULT;
+ return err;
}
/*
@@ -2566,8 +2557,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return tiocswinsz(real_tty, p);
case TIOCCONS:
return real_tty != tty ? -EINVAL : tioccons(file);
- case FIONBIO:
- return fionbio(file, p);
case TIOCEXCL:
set_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
@@ -2622,11 +2611,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCMBIS:
return tty_tiocmset(tty, cmd, p);
case TIOCGICOUNT:
- retval = tty_tiocgicount(tty, p);
- /* For the moment allow fall through to the old method */
- if (retval != -EINVAL)
- return retval;
- break;
+ return tty_tiocgicount(tty, p);
case TCFLSH:
switch (arg) {
case TCIFLUSH:
@@ -2637,8 +2622,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
break;
case TIOCSSERIAL:
- tty_warn_deprecated_flags(p);
- break;
+ return tty_tiocsserial(tty, p);
+ case TIOCGSERIAL:
+ return tty_tiocgserial(tty, p);
case TIOCGPTPEER:
/* Special because the struct file is needed */
return ptm_open_peer(file, tty, (int)arg);
@@ -2666,6 +2652,81 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#ifdef CONFIG_COMPAT
+
+struct serial_struct32 {
+ compat_int_t type;
+ compat_int_t line;
+ compat_uint_t port;
+ compat_int_t irq;
+ compat_int_t flags;
+ compat_int_t xmit_fifo_size;
+ compat_int_t custom_divisor;
+ compat_int_t baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char[1];
+ compat_int_t hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ compat_uint_t iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ /* compat_ulong_t iomap_base FIXME */
+ compat_int_t reserved[1];
+};
+
+static int compat_tty_tiocsserial(struct tty_struct *tty,
+ struct serial_struct32 __user *ss)
+{
+ static DEFINE_RATELIMIT_STATE(depr_flags,
+ DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ char comm[TASK_COMM_LEN];
+ struct serial_struct32 v32;
+ struct serial_struct v;
+ int flags;
+
+ if (copy_from_user(&v32, ss, sizeof(struct serial_struct32)))
+ return -EFAULT;
+
+ memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base));
+ v.iomem_base = compat_ptr(v32.iomem_base);
+ v.iomem_reg_shift = v32.iomem_reg_shift;
+ v.port_high = v32.port_high;
+ v.iomap_base = 0;
+
+ flags = v.flags & ASYNC_DEPRECATED;
+
+ if (flags && __ratelimit(&depr_flags))
+ pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
+ __func__, get_task_comm(comm, current), flags);
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ return tty->ops->set_serial(tty, &v);
+}
+
+static int compat_tty_tiocgserial(struct tty_struct *tty,
+ struct serial_struct32 __user *ss)
+{
+ struct serial_struct32 v32;
+ struct serial_struct v;
+ int err;
+ memset(&v, 0, sizeof(struct serial_struct));
+
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ err = tty->ops->get_serial(tty, &v);
+ if (!err) {
+ memcpy(&v32, &v, offsetof(struct serial_struct32, iomem_base));
+ v32.iomem_base = (unsigned long)v.iomem_base >> 32 ?
+ 0xfffffff : ptr_to_compat(v.iomem_base);
+ v32.iomem_reg_shift = v.iomem_reg_shift;
+ v32.port_high = v.port_high;
+ if (copy_to_user(ss, &v32, sizeof(struct serial_struct32)))
+ err = -EFAULT;
+ }
+ return err;
+}
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -2673,9 +2734,90 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
struct tty_ldisc *ld;
int retval = -ENOIOCTLCMD;
+ switch (cmd) {
+ case TIOCSTI:
+ case TIOCGWINSZ:
+ case TIOCSWINSZ:
+ case TIOCGEXCL:
+ case TIOCGETD:
+ case TIOCSETD:
+ case TIOCGDEV:
+ case TIOCMGET:
+ case TIOCMSET:
+ case TIOCMBIC:
+ case TIOCMBIS:
+ case TIOCGICOUNT:
+ case TIOCGPGRP:
+ case TIOCSPGRP:
+ case TIOCGSID:
+ case TIOCSERGETLSR:
+ case TIOCGRS485:
+ case TIOCSRS485:
+#ifdef TIOCGETP
+ case TIOCGETP:
+ case TIOCSETP:
+ case TIOCSETN:
+#endif
+#ifdef TIOCGETC
+ case TIOCGETC:
+ case TIOCSETC:
+#endif
+#ifdef TIOCGLTC
+ case TIOCGLTC:
+ case TIOCSLTC:
+#endif
+ case TCSETSF:
+ case TCSETSW:
+ case TCSETS:
+ case TCGETS:
+#ifdef TCGETS2
+ case TCGETS2:
+ case TCSETSF2:
+ case TCSETSW2:
+ case TCSETS2:
+#endif
+ case TCGETA:
+ case TCSETAF:
+ case TCSETAW:
+ case TCSETA:
+ case TIOCGLCKTRMIOS:
+ case TIOCSLCKTRMIOS:
+#ifdef TCGETX
+ case TCGETX:
+ case TCSETX:
+ case TCSETXW:
+ case TCSETXF:
+#endif
+ case TIOCGSOFTCAR:
+ case TIOCSSOFTCAR:
+ return tty_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+ case TIOCCONS:
+ case TIOCEXCL:
+ case TIOCNXCL:
+ case TIOCVHANGUP:
+ case TIOCSBRK:
+ case TIOCCBRK:
+ case TCSBRK:
+ case TCSBRKP:
+ case TCFLSH:
+ case TIOCGPTPEER:
+ case TIOCNOTTY:
+ case TIOCSCTTY:
+ case TCXONC:
+ case TIOCMIWAIT:
+ case TIOCSERCONFIG:
+ return tty_ioctl(file, cmd, arg);
+ }
+
if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl"))
return -EINVAL;
+ switch (cmd) {
+ case TIOCSSERIAL:
+ return compat_tty_tiocsserial(tty, compat_ptr(arg));
+ case TIOCGSERIAL:
+ return compat_tty_tiocgserial(tty, compat_ptr(arg));
+ }
if (tty->ops->compat_ioctl) {
retval = tty->ops->compat_ioctl(tty, cmd, arg);
if (retval != -ENOIOCTLCMD)
@@ -2687,8 +2829,9 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
return hung_up_tty_compat_ioctl(file, cmd, arg);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
- else
- retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
+ if (retval == -ENOIOCTLCMD && ld->ops->ioctl)
+ retval = ld->ops->ioctl(tty, file,
+ (unsigned long)compat_ptr(cmd), arg);
tty_ldisc_deref(ld);
return retval;
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index d99fec44036c..9245fffdbceb 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -941,19 +941,3 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
}
}
EXPORT_SYMBOL(n_tty_ioctl_helper);
-
-#ifdef CONFIG_COMPAT
-long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case TIOCGLCKTRMIOS:
- case TIOCSLCKTRMIOS:
- return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
- default:
- return -ENOIOCTLCMD;
- }
-}
-EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
-#endif
-
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 73cdc0d633dd..8b0ed139592f 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1175,17 +1175,13 @@ long vt_compat_ioctl(struct tty_struct *tty,
{
struct vc_data *vc = tty->driver_data;
struct console_font_op op; /* used in multiple places here */
- unsigned int console;
- void __user *up = (void __user *)arg;
+ unsigned int console = vc->vc_num;
+ void __user *up = compat_ptr(arg);
int perm;
- int ret = 0;
- console = vc->vc_num;
- if (!vc_cons_allocated(console)) { /* impossible? */
- ret = -ENOIOCTLCMD;
- goto out;
- }
+ if (!vc_cons_allocated(console)) /* impossible? */
+ return -ENOIOCTLCMD;
/*
* To have permissions to do most of the vt ioctls, we either have
@@ -1201,17 +1197,14 @@ long vt_compat_ioctl(struct tty_struct *tty,
*/
case PIO_FONTX:
case GIO_FONTX:
- ret = compat_fontx_ioctl(cmd, up, perm, &op);
- break;
+ return compat_fontx_ioctl(cmd, up, perm, &op);
case KDFONTOP:
- ret = compat_kdfontop_ioctl(up, perm, &op, vc);
- break;
+ return compat_kdfontop_ioctl(up, perm, &op, vc);
case PIO_UNIMAP:
case GIO_UNIMAP:
- ret = compat_unimap_ioctl(cmd, up, perm, vc);
- break;
+ return compat_unimap_ioctl(cmd, up, perm, vc);
/*
* all these treat 'arg' as an integer
@@ -1236,21 +1229,15 @@ long vt_compat_ioctl(struct tty_struct *tty,
case VT_DISALLOCATE:
case VT_RESIZE:
case VT_RESIZEX:
- goto fallback;
+ return vt_ioctl(tty, cmd, arg);
/*
* the rest has a compatible data structure behind arg,
* but we have to convert it to a proper 64 bit pointer.
*/
default:
- arg = (unsigned long)compat_ptr(arg);
- goto fallback;
+ return vt_ioctl(tty, cmd, (unsigned long)up);
}
-out:
- return ret;
-
-fallback:
- return vt_ioctl(tty, cmd, arg);
}