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 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 | ||
2515 | static 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 | |||
2514 | struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) | 2529 | struct 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 | */ |
1077 | static int uart_get_count(struct uart_state *state, | 1077 | static 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 | ||
522 | static 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 | ||
233 | struct tty_struct; | 239 | struct tty_struct; |
234 | struct tty_driver; | 240 | struct tty_driver; |
241 | struct serial_icounter_struct; | ||
235 | 242 | ||
236 | struct tty_operations { | 243 | struct 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); |