Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alan Cox and committed by
Greg Kroah-Hartman
d281da7f 68707539

+61 -19
+21
drivers/char/tty_io.c
··· 96 96 #include <linux/bitops.h> 97 97 #include <linux/delay.h> 98 98 #include <linux/seq_file.h> 99 + #include <linux/serial.h> 99 100 100 101 #include <linux/uaccess.h> 101 102 #include <asm/system.h> ··· 2512 2511 return tty->ops->tiocmset(tty, file, set, clear); 2513 2512 } 2514 2513 2514 + static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) 2515 + { 2516 + int retval = -EINVAL; 2517 + struct serial_icounter_struct icount; 2518 + memset(&icount, 0, sizeof(icount)); 2519 + if (tty->ops->get_icount) 2520 + retval = tty->ops->get_icount(tty, &icount); 2521 + if (retval != 0) 2522 + return retval; 2523 + if (copy_to_user(arg, &icount, sizeof(icount))) 2524 + return -EFAULT; 2525 + return 0; 2526 + } 2527 + 2515 2528 struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) 2516 2529 { 2517 2530 if (tty->driver->type == TTY_DRIVER_TYPE_PTY && ··· 2646 2631 case TIOCMBIC: 2647 2632 case TIOCMBIS: 2648 2633 return tty_tiocmset(tty, file, cmd, p); 2634 + case TIOCGICOUNT: 2635 + retval = tty_tiocgicount(tty, p); 2636 + /* For the moment allow fall through to the old method */ 2637 + if (retval != -EINVAL) 2638 + return retval; 2639 + break; 2649 2640 case TCFLSH: 2650 2641 switch (arg) { 2651 2642 case TCIFLUSH:
+16 -19
drivers/serial/serial_core.c
··· 1074 1074 * NB: both 1->0 and 0->1 transitions are counted except for 1075 1075 * RI where only 0->1 is counted. 1076 1076 */ 1077 - static int uart_get_count(struct uart_state *state, 1078 - struct serial_icounter_struct __user *icnt) 1077 + static int uart_get_icount(struct tty_struct *tty, 1078 + struct serial_icounter_struct *icount) 1079 1079 { 1080 - struct serial_icounter_struct icount; 1080 + struct uart_state *state = tty->driver_data; 1081 1081 struct uart_icount cnow; 1082 1082 struct uart_port *uport = state->uart_port; 1083 1083 ··· 1085 1085 memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); 1086 1086 spin_unlock_irq(&uport->lock); 1087 1087 1088 - icount.cts = cnow.cts; 1089 - icount.dsr = cnow.dsr; 1090 - icount.rng = cnow.rng; 1091 - icount.dcd = cnow.dcd; 1092 - icount.rx = cnow.rx; 1093 - icount.tx = cnow.tx; 1094 - icount.frame = cnow.frame; 1095 - icount.overrun = cnow.overrun; 1096 - icount.parity = cnow.parity; 1097 - icount.brk = cnow.brk; 1098 - icount.buf_overrun = cnow.buf_overrun; 1088 + icount->cts = cnow.cts; 1089 + icount->dsr = cnow.dsr; 1090 + icount->rng = cnow.rng; 1091 + icount->dcd = cnow.dcd; 1092 + icount->rx = cnow.rx; 1093 + icount->tx = cnow.tx; 1094 + icount->frame = cnow.frame; 1095 + icount->overrun = cnow.overrun; 1096 + icount->parity = cnow.parity; 1097 + icount->brk = cnow.brk; 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 /* ··· 1149 1149 switch (cmd) { 1150 1150 case TIOCMIWAIT: 1151 1151 ret = uart_wait_modem_status(state, arg); 1152 - break; 1153 - 1154 - case TIOCGICOUNT: 1155 - ret = uart_get_count(state, uarg); 1156 1152 break; 1157 1153 } 1158 1154 ··· 2291 2295 #endif 2292 2296 .tiocmget = uart_tiocmget, 2293 2297 .tiocmset = uart_tiocmset, 2298 + .get_icount = uart_get_icount, 2294 2299 #ifdef CONFIG_CONSOLE_POLL 2295 2300 .poll_init = uart_poll_init, 2296 2301 .poll_get_char = uart_poll_get_char,
+13
drivers/usb/serial/usb-serial.c
··· 519 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 535 * We would be calling tty_wakeup here, but unfortunately some line 524 536 * disciplines have an annoying habit of calling tty->write from ··· 1207 1195 .chars_in_buffer = serial_chars_in_buffer, 1208 1196 .tiocmget = serial_tiocmget, 1209 1197 .tiocmset = serial_tiocmset, 1198 + .get_icount = serial_get_icount, 1210 1199 .cleanup = serial_cleanup, 1211 1200 .install = serial_install, 1212 1201 .proc_fops = &serial_proc_fops,
+9
include/linux/tty_driver.h
··· 224 224 * unless the tty also has a valid tty->termiox pointer. 225 225 * 226 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 235 #include <linux/fs.h> ··· 238 232 239 233 struct tty_struct; 240 234 struct tty_driver; 235 + struct serial_icounter_struct; 241 236 242 237 struct tty_operations { 243 238 struct tty_struct * (*lookup)(struct tty_driver *driver, ··· 275 268 unsigned int set, unsigned int clear); 276 269 int (*resize)(struct tty_struct *tty, struct winsize *ws); 277 270 int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); 271 + int (*get_icount)(struct tty_struct *tty, 272 + struct serial_icounter_struct *icount); 278 273 #ifdef CONFIG_CONSOLE_POLL 279 274 int (*poll_init)(struct tty_driver *driver, int line, char *options); 280 275 int (*poll_get_char)(struct tty_driver *driver, int line);
+2
include/linux/usb/serial.h
··· 271 271 int (*tiocmget)(struct tty_struct *tty, struct file *file); 272 272 int (*tiocmset)(struct tty_struct *tty, struct file *file, 273 273 unsigned int set, unsigned int clear); 274 + int (*get_icount)(struct tty_struct *tty, 275 + struct serial_icounter_struct *icount); 274 276 /* Called by the tty layer for port level work. There may or may not 275 277 be an attached tty at this point */ 276 278 void (*dtr_rts)(struct usb_serial_port *port, int on);