diff options
-rw-r--r-- | drivers/char/tty_io.c | 21 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 35 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 13 | ||||
-rw-r--r-- | include/linux/tty_driver.h | 9 | ||||
-rw-r--r-- | include/linux/usb/serial.h | 2 |
5 files changed, 61 insertions, 19 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e185db36f8a..c05c5af5aa0 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -96,6 +96,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/seq_file.h> +#include <linux/serial.h> #include <linux/uaccess.h> #include <asm/system.h> @@ -2511,6 +2512,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int return tty->ops->tiocmset(tty, file, set, clear); } +static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) +{ + int retval = -EINVAL; + struct serial_icounter_struct icount; + memset(&icount, 0, sizeof(icount)); + if (tty->ops->get_icount) + retval = tty->ops->get_icount(tty, &icount); + if (retval != 0) + return retval; + if (copy_to_user(arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; +} + struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) { if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -2631,6 +2646,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, 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; case TCFLSH: switch (arg) { case TCIFLUSH: diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index bc6cddd1029..c4ea14670d4 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1074,10 +1074,10 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ -static int uart_get_count(struct uart_state *state, - struct serial_icounter_struct __user *icnt) +static int uart_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) { - struct serial_icounter_struct icount; + struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport = state->uart_port; @@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state, memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); spin_unlock_irq(&uport->lock); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; - return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; + return 0; } /* @@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, case TIOCMIWAIT: ret = uart_wait_modem_status(state, arg); break; - - case TIOCGICOUNT: - ret = uart_get_count(state, uarg); - break; } if (ret != -ENOIOCTLCMD) @@ -2295,6 +2291,7 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, .poll_get_char = uart_poll_get_char, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 7a2177c79bd..e64da74bdcc 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -519,6 +519,18 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file, return -EINVAL; } +static int serial_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + + dbg("%s - port %d", __func__, port->number); + + if (port->serial->type->get_icount) + return port->serial->type->get_icount(tty, icount); + return -EINVAL; +} + /* * We would be calling tty_wakeup here, but unfortunately some line * disciplines have an annoying habit of calling tty->write from @@ -1195,6 +1207,7 @@ static const struct tty_operations serial_ops = { .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, + .get_icount = serial_get_icount, .cleanup = serial_cleanup, .install = serial_install, .proc_fops = &serial_proc_fops, diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index b0867798252..db2d227694d 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -224,6 +224,12 @@ * unless the tty also has a valid tty->termiox pointer. * * Optional: Called under the termios lock + * + * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount); + * + * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel + * structure to complete. This method is optional and will only be called + * if provided (otherwise EINVAL will be returned). */ #include <linux/fs.h> @@ -232,6 +238,7 @@ struct tty_struct; struct tty_driver; +struct serial_icounter_struct; struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, @@ -268,6 +275,8 @@ struct tty_operations { unsigned int set, unsigned int clear); int (*resize)(struct tty_struct *tty, struct winsize *ws); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); + int (*get_icount)(struct tty_struct *tty, + struct serial_icounter_struct *icount); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_get_char)(struct tty_driver *driver, int line); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 55675b1efb2..16d682f4f7c 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -271,6 +271,8 @@ struct usb_serial_driver { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); + int (*get_icount)(struct tty_struct *tty, + struct serial_icounter_struct *icount); /* Called by the tty layer for port level work. There may or may not be an attached tty at this point */ void (*dtr_rts)(struct usb_serial_port *port, int on); |