aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-09-16 13:21:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:20:04 -0400
commitd281da7ff6f70efca0553c288bb883e8605b3862 (patch)
treeee6a46b33070159af51c07643cf99186f1ef3e03
parent68707539df1e9d12435e5d54ffedc7ded50fcd01 (diff)
tty: Make tiocgicount a handler
Dan Rosenberg noted that various drivers return the struct with uncleared fields. Instead of spending forever trying to stomp all the drivers that get it wrong (and every new driver) do the job in one place. This first patch adds the needed operations and hooks them up, including the needed USB midlayer and serial core plumbing. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-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);