aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_io.c21
-rw-r--r--drivers/serial/serial_core.c35
-rw-r--r--drivers/usb/serial/usb-serial.c13
-rw-r--r--include/linux/tty_driver.h9
-rw-r--r--include/linux/usb/serial.h2
5 files changed, 61 insertions, 19 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e185db36f8ad..c05c5af5aa04 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -96,6 +96,7 @@
96#include <linux/bitops.h> 96#include <linux/bitops.h>
97#include <linux/delay.h> 97#include <linux/delay.h>
98#include <linux/seq_file.h> 98#include <linux/seq_file.h>
99#include <linux/serial.h>
99 100
100#include <linux/uaccess.h> 101#include <linux/uaccess.h>
101#include <asm/system.h> 102#include <asm/system.h>
@@ -2511,6 +2512,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
2511 return tty->ops->tiocmset(tty, file, set, clear); 2512 return tty->ops->tiocmset(tty, file, set, clear);
2512} 2513}
2513 2514
2515static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
2516{
2517 int retval = -EINVAL;
2518 struct serial_icounter_struct icount;
2519 memset(&icount, 0, sizeof(icount));
2520 if (tty->ops->get_icount)
2521 retval = tty->ops->get_icount(tty, &icount);
2522 if (retval != 0)
2523 return retval;
2524 if (copy_to_user(arg, &icount, sizeof(icount)))
2525 return -EFAULT;
2526 return 0;
2527}
2528
2514struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) 2529struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
2515{ 2530{
2516 if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 2531 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2631,6 +2646,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2631 case TIOCMBIC: 2646 case TIOCMBIC:
2632 case TIOCMBIS: 2647 case TIOCMBIS:
2633 return tty_tiocmset(tty, file, cmd, p); 2648 return tty_tiocmset(tty, file, cmd, p);
2649 case TIOCGICOUNT:
2650 retval = tty_tiocgicount(tty, p);
2651 /* For the moment allow fall through to the old method */
2652 if (retval != -EINVAL)
2653 return retval;
2654 break;
2634 case TCFLSH: 2655 case TCFLSH:
2635 switch (arg) { 2656 switch (arg) {
2636 case TCIFLUSH: 2657 case TCIFLUSH:
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index bc6cddd10294..c4ea14670d44 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)
1074 * NB: both 1->0 and 0->1 transitions are counted except for 1074 * NB: both 1->0 and 0->1 transitions are counted except for
1075 * RI where only 0->1 is counted. 1075 * RI where only 0->1 is counted.
1076 */ 1076 */
1077static int uart_get_count(struct uart_state *state, 1077static int uart_get_icount(struct tty_struct *tty,
1078 struct serial_icounter_struct __user *icnt) 1078 struct serial_icounter_struct *icount)
1079{ 1079{
1080 struct serial_icounter_struct icount; 1080 struct uart_state *state = tty->driver_data;
1081 struct uart_icount cnow; 1081 struct uart_icount cnow;
1082 struct uart_port *uport = state->uart_port; 1082 struct uart_port *uport = state->uart_port;
1083 1083
@@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state,
1085 memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 1085 memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
1086 spin_unlock_irq(&uport->lock); 1086 spin_unlock_irq(&uport->lock);
1087 1087
1088 icount.cts = cnow.cts; 1088 icount->cts = cnow.cts;
1089 icount.dsr = cnow.dsr; 1089 icount->dsr = cnow.dsr;
1090 icount.rng = cnow.rng; 1090 icount->rng = cnow.rng;
1091 icount.dcd = cnow.dcd; 1091 icount->dcd = cnow.dcd;
1092 icount.rx = cnow.rx; 1092 icount->rx = cnow.rx;
1093 icount.tx = cnow.tx; 1093 icount->tx = cnow.tx;
1094 icount.frame = cnow.frame; 1094 icount->frame = cnow.frame;
1095 icount.overrun = cnow.overrun; 1095 icount->overrun = cnow.overrun;
1096 icount.parity = cnow.parity; 1096 icount->parity = cnow.parity;
1097 icount.brk = cnow.brk; 1097 icount->brk = cnow.brk;
1098 icount.buf_overrun = cnow.buf_overrun; 1098 icount->buf_overrun = cnow.buf_overrun;
1099 1099
1100 return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; 1100 return 0;
1101} 1101}
1102 1102
1103/* 1103/*
@@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
1150 case TIOCMIWAIT: 1150 case TIOCMIWAIT:
1151 ret = uart_wait_modem_status(state, arg); 1151 ret = uart_wait_modem_status(state, arg);
1152 break; 1152 break;
1153
1154 case TIOCGICOUNT:
1155 ret = uart_get_count(state, uarg);
1156 break;
1157 } 1153 }
1158 1154
1159 if (ret != -ENOIOCTLCMD) 1155 if (ret != -ENOIOCTLCMD)
@@ -2295,6 +2291,7 @@ static const struct tty_operations uart_ops = {
2295#endif 2291#endif
2296 .tiocmget = uart_tiocmget, 2292 .tiocmget = uart_tiocmget,
2297 .tiocmset = uart_tiocmset, 2293 .tiocmset = uart_tiocmset,
2294 .get_icount = uart_get_icount,
2298#ifdef CONFIG_CONSOLE_POLL 2295#ifdef CONFIG_CONSOLE_POLL
2299 .poll_init = uart_poll_init, 2296 .poll_init = uart_poll_init,
2300 .poll_get_char = uart_poll_get_char, 2297 .poll_get_char = uart_poll_get_char,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 7a2177c79bde..e64da74bdcc5 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,
519 return -EINVAL; 519 return -EINVAL;
520} 520}
521 521
522static int serial_get_icount(struct tty_struct *tty,
523 struct serial_icounter_struct *icount)
524{
525 struct usb_serial_port *port = tty->driver_data;
526
527 dbg("%s - port %d", __func__, port->number);
528
529 if (port->serial->type->get_icount)
530 return port->serial->type->get_icount(tty, icount);
531 return -EINVAL;
532}
533
522/* 534/*
523 * We would be calling tty_wakeup here, but unfortunately some line 535 * We would be calling tty_wakeup here, but unfortunately some line
524 * disciplines have an annoying habit of calling tty->write from 536 * disciplines have an annoying habit of calling tty->write from
@@ -1195,6 +1207,7 @@ static const struct tty_operations serial_ops = {
1195 .chars_in_buffer = serial_chars_in_buffer, 1207 .chars_in_buffer = serial_chars_in_buffer,
1196 .tiocmget = serial_tiocmget, 1208 .tiocmget = serial_tiocmget,
1197 .tiocmset = serial_tiocmset, 1209 .tiocmset = serial_tiocmset,
1210 .get_icount = serial_get_icount,
1198 .cleanup = serial_cleanup, 1211 .cleanup = serial_cleanup,
1199 .install = serial_install, 1212 .install = serial_install,
1200 .proc_fops = &serial_proc_fops, 1213 .proc_fops = &serial_proc_fops,
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index b08677982525..db2d227694da 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -224,6 +224,12 @@
224 * unless the tty also has a valid tty->termiox pointer. 224 * unless the tty also has a valid tty->termiox pointer.
225 * 225 *
226 * Optional: Called under the termios lock 226 * Optional: Called under the termios lock
227 *
228 * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount);
229 *
230 * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel
231 * structure to complete. This method is optional and will only be called
232 * if provided (otherwise EINVAL will be returned).
227 */ 233 */
228 234
229#include <linux/fs.h> 235#include <linux/fs.h>
@@ -232,6 +238,7 @@
232 238
233struct tty_struct; 239struct tty_struct;
234struct tty_driver; 240struct tty_driver;
241struct serial_icounter_struct;
235 242
236struct tty_operations { 243struct tty_operations {
237 struct tty_struct * (*lookup)(struct tty_driver *driver, 244 struct tty_struct * (*lookup)(struct tty_driver *driver,
@@ -268,6 +275,8 @@ struct tty_operations {
268 unsigned int set, unsigned int clear); 275 unsigned int set, unsigned int clear);
269 int (*resize)(struct tty_struct *tty, struct winsize *ws); 276 int (*resize)(struct tty_struct *tty, struct winsize *ws);
270 int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); 277 int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
278 int (*get_icount)(struct tty_struct *tty,
279 struct serial_icounter_struct *icount);
271#ifdef CONFIG_CONSOLE_POLL 280#ifdef CONFIG_CONSOLE_POLL
272 int (*poll_init)(struct tty_driver *driver, int line, char *options); 281 int (*poll_init)(struct tty_driver *driver, int line, char *options);
273 int (*poll_get_char)(struct tty_driver *driver, int line); 282 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 55675b1efb28..16d682f4f7c3 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -271,6 +271,8 @@ struct usb_serial_driver {
271 int (*tiocmget)(struct tty_struct *tty, struct file *file); 271 int (*tiocmget)(struct tty_struct *tty, struct file *file);
272 int (*tiocmset)(struct tty_struct *tty, struct file *file, 272 int (*tiocmset)(struct tty_struct *tty, struct file *file,
273 unsigned int set, unsigned int clear); 273 unsigned int set, unsigned int clear);
274 int (*get_icount)(struct tty_struct *tty,
275 struct serial_icounter_struct *icount);
274 /* Called by the tty layer for port level work. There may or may not 276 /* Called by the tty layer for port level work. There may or may not
275 be an attached tty at this point */ 277 be an attached tty at this point */
276 void (*dtr_rts)(struct usb_serial_port *port, int on); 278 void (*dtr_rts)(struct usb_serial_port *port, int on);