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); |
