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

tty: rework break handling

Some hardware needs to do break handling itself and may have partial
support only. Make break_ctl return an error code. Add a tty driver flag
so you can indicate driver hardware side break support.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alan Cox and committed by
Linus Torvalds
9e98966c abbe629a

+97 -84
+1 -1
drivers/char/Kconfig
··· 218 218 219 219 config ISI 220 220 tristate "Multi-Tech multiport card support (EXPERIMENTAL)" 221 - depends on SERIAL_NONSTANDARD && PCI 221 + depends on SERIAL_NONSTANDARD && PCI && BROKEN 222 222 select FW_LOADER 223 223 help 224 224 This is a driver for the Multi-Tech cards which provide several
+2 -1
drivers/char/amiserial.c
··· 1248 1248 /* 1249 1249 * rs_break() --- routine which turns the break handling on or off 1250 1250 */ 1251 - static void rs_break(struct tty_struct *tty, int break_state) 1251 + static int rs_break(struct tty_struct *tty, int break_state) 1252 1252 { 1253 1253 struct async_struct * info = (struct async_struct *)tty->driver_data; 1254 1254 unsigned long flags; ··· 1263 1263 custom.adkcon = AC_UARTBRK; 1264 1264 mb(); 1265 1265 local_irq_restore(flags); 1266 + return 0; 1266 1267 } 1267 1268 1268 1269
+4 -4
drivers/char/cyclades.c
··· 3700 3700 /* 3701 3701 * cy_break() --- routine which turns the break handling on or off 3702 3702 */ 3703 - static void cy_break(struct tty_struct *tty, int break_state) 3703 + static int cy_break(struct tty_struct *tty, int break_state) 3704 3704 { 3705 3705 struct cyclades_port *info = tty->driver_data; 3706 3706 struct cyclades_card *card; 3707 3707 unsigned long flags; 3708 + int retval = 0; 3708 3709 3709 3710 if (serial_paranoia_check(info, tty->name, "cy_break")) 3710 - return; 3711 + return -EINVAL; 3711 3712 3712 3713 card = info->card; 3713 3714 ··· 3737 3736 } 3738 3737 } 3739 3738 } else { 3740 - int retval; 3741 - 3742 3739 if (break_state == -1) { 3743 3740 retval = cyz_issue_cmd(card, 3744 3741 info->line - card->first_line, ··· 3757 3758 } 3758 3759 } 3759 3760 spin_unlock_irqrestore(&card->card_lock, flags); 3761 + return retval; 3760 3762 } /* cy_break */ 3761 3763 3762 3764 static int get_mon_info(struct cyclades_port *info,
+3 -2
drivers/char/esp.c
··· 1725 1725 /* 1726 1726 * rs_break() --- routine which turns the break handling on or off 1727 1727 */ 1728 - static void esp_break(struct tty_struct *tty, int break_state) 1728 + static int esp_break(struct tty_struct *tty, int break_state) 1729 1729 { 1730 1730 struct esp_struct *info = tty->driver_data; 1731 1731 unsigned long flags; 1732 1732 1733 1733 if (serial_paranoia_check(info, tty->name, "esp_break")) 1734 - return; 1734 + return -EINVAL; 1735 1735 1736 1736 if (break_state == -1) { 1737 1737 spin_lock_irqsave(&info->lock, flags); ··· 1747 1747 serial_out(info, UART_ESI_CMD2, 0x00); 1748 1748 spin_unlock_irqrestore(&info->lock, flags); 1749 1749 } 1750 + return 0; 1750 1751 } 1751 1752 1752 1753 static int rs_ioctl(struct tty_struct *tty, struct file *file,
+6 -5
drivers/char/istallion.c
··· 609 609 static void stli_stop(struct tty_struct *tty); 610 610 static void stli_start(struct tty_struct *tty); 611 611 static void stli_flushbuffer(struct tty_struct *tty); 612 - static void stli_breakctl(struct tty_struct *tty, int state); 612 + static int stli_breakctl(struct tty_struct *tty, int state); 613 613 static void stli_waituntilsent(struct tty_struct *tty, int timeout); 614 614 static void stli_sendxchar(struct tty_struct *tty, char ch); 615 615 static void stli_hangup(struct tty_struct *tty); ··· 1909 1909 1910 1910 /*****************************************************************************/ 1911 1911 1912 - static void stli_breakctl(struct tty_struct *tty, int state) 1912 + static int stli_breakctl(struct tty_struct *tty, int state) 1913 1913 { 1914 1914 struct stlibrd *brdp; 1915 1915 struct stliport *portp; ··· 1917 1917 1918 1918 portp = tty->driver_data; 1919 1919 if (portp == NULL) 1920 - return; 1920 + return -EINVAL; 1921 1921 if (portp->brdnr >= stli_nrbrds) 1922 - return; 1922 + return -EINVAL; 1923 1923 brdp = stli_brds[portp->brdnr]; 1924 1924 if (brdp == NULL) 1925 - return; 1925 + return -EINVAL; 1926 1926 1927 1927 arg = (state == -1) ? BREAKON : BREAKOFF; 1928 1928 stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0); 1929 + return 0; 1929 1930 } 1930 1931 1931 1932 /*****************************************************************************/
+2 -1
drivers/char/moxa.c
··· 374 374 return ret; 375 375 } 376 376 377 - static void moxa_break_ctl(struct tty_struct *tty, int state) 377 + static int moxa_break_ctl(struct tty_struct *tty, int state) 378 378 { 379 379 struct moxa_port *port = tty->driver_data; 380 380 381 381 moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak, 382 382 Magic_code); 383 + return 0; 383 384 } 384 385 385 386 static const struct tty_operations moxa_ops = {
+2 -1
drivers/char/mxser.c
··· 2183 2183 /* 2184 2184 * mxser_rs_break() --- routine which turns the break handling on or off 2185 2185 */ 2186 - static void mxser_rs_break(struct tty_struct *tty, int break_state) 2186 + static int mxser_rs_break(struct tty_struct *tty, int break_state) 2187 2187 { 2188 2188 struct mxser_port *info = tty->driver_data; 2189 2189 unsigned long flags; ··· 2196 2196 outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, 2197 2197 info->ioaddr + UART_LCR); 2198 2198 spin_unlock_irqrestore(&info->slock, flags); 2199 + return 0; 2199 2200 } 2200 2201 2201 2202 static void mxser_receive_chars(struct mxser_port *port, int *status)
+3 -2
drivers/char/rocket.c
··· 1236 1236 } 1237 1237 } 1238 1238 1239 - static void rp_break(struct tty_struct *tty, int break_state) 1239 + static int rp_break(struct tty_struct *tty, int break_state) 1240 1240 { 1241 1241 struct r_port *info = (struct r_port *) tty->driver_data; 1242 1242 unsigned long flags; 1243 1243 1244 1244 if (rocket_paranoia_check(info, "rp_break")) 1245 - return; 1245 + return -EINVAL; 1246 1246 1247 1247 spin_lock_irqsave(&info->slock, flags); 1248 1248 if (break_state == -1) ··· 1250 1250 else 1251 1251 sClrBreak(&info->channel); 1252 1252 spin_unlock_irqrestore(&info->slock, flags); 1253 + return 0; 1253 1254 } 1254 1255 1255 1256 /*
+2 -1
drivers/char/sx.c
··· 1840 1840 return rc; 1841 1841 } 1842 1842 1843 - static void sx_break(struct tty_struct *tty, int flag) 1843 + static int sx_break(struct tty_struct *tty, int flag) 1844 1844 { 1845 1845 struct sx_port *port = tty->driver_data; 1846 1846 int rv; ··· 1857 1857 read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat))); 1858 1858 unlock_kernel(); 1859 1859 func_exit(); 1860 + return 0; 1860 1861 } 1861 1862 1862 1863 static int sx_tiocmget(struct tty_struct *tty, struct file *file)
+4 -3
drivers/char/synclink.c
··· 2897 2897 * 2898 2898 * Arguments: tty pointer to tty instance data 2899 2899 * break_state -1=set break condition, 0=clear 2900 - * Return Value: None 2900 + * Return Value: error code 2901 2901 */ 2902 - static void mgsl_break(struct tty_struct *tty, int break_state) 2902 + static int mgsl_break(struct tty_struct *tty, int break_state) 2903 2903 { 2904 2904 struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; 2905 2905 unsigned long flags; ··· 2909 2909 __FILE__,__LINE__, info->device_name, break_state); 2910 2910 2911 2911 if (mgsl_paranoia_check(info, tty->name, "mgsl_break")) 2912 - return; 2912 + return -EINVAL; 2913 2913 2914 2914 spin_lock_irqsave(&info->irq_spinlock,flags); 2915 2915 if (break_state == -1) ··· 2917 2917 else 2918 2918 usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7)); 2919 2919 spin_unlock_irqrestore(&info->irq_spinlock,flags); 2920 + return 0; 2920 2921 2921 2922 } /* end of mgsl_break() */ 2922 2923
+5 -4
drivers/char/synclinkmp.c
··· 527 527 static int chars_in_buffer(struct tty_struct *tty); 528 528 static void throttle(struct tty_struct * tty); 529 529 static void unthrottle(struct tty_struct * tty); 530 - static void set_break(struct tty_struct *tty, int break_state); 530 + static int set_break(struct tty_struct *tty, int break_state); 531 531 532 532 #if SYNCLINK_GENERIC_HDLC 533 533 #define dev_to_port(D) (dev_to_hdlc(D)->priv) ··· 552 552 static int tiocmget(struct tty_struct *tty, struct file *file); 553 553 static int tiocmset(struct tty_struct *tty, struct file *file, 554 554 unsigned int set, unsigned int clear); 555 - static void set_break(struct tty_struct *tty, int break_state); 555 + static int set_break(struct tty_struct *tty, int break_state); 556 556 557 557 static void add_device(SLMP_INFO *info); 558 558 static void device_init(int adapter_num, struct pci_dev *pdev); ··· 1587 1587 /* set or clear transmit break condition 1588 1588 * break_state -1=set break condition, 0=clear 1589 1589 */ 1590 - static void set_break(struct tty_struct *tty, int break_state) 1590 + static int set_break(struct tty_struct *tty, int break_state) 1591 1591 { 1592 1592 unsigned char RegValue; 1593 1593 SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; ··· 1598 1598 __FILE__,__LINE__, info->device_name, break_state); 1599 1599 1600 1600 if (sanity_check(info, tty->name, "set_break")) 1601 - return; 1601 + return -EINVAL; 1602 1602 1603 1603 spin_lock_irqsave(&info->lock,flags); 1604 1604 RegValue = read_reg(info, CTL); ··· 1608 1608 RegValue &= ~BIT3; 1609 1609 write_reg(info, CTL, RegValue); 1610 1610 spin_unlock_irqrestore(&info->lock,flags); 1611 + return 0; 1611 1612 } 1612 1613 1613 1614 #if SYNCLINK_GENERIC_HDLC
+28 -43
drivers/char/tty_io.c
··· 2849 2849 2850 2850 static int send_break(struct tty_struct *tty, unsigned int duration) 2851 2851 { 2852 - if (tty_write_lock(tty, 0) < 0) 2853 - return -EINTR; 2854 - tty->ops->break_ctl(tty, -1); 2855 - if (!signal_pending(current)) 2856 - msleep_interruptible(duration); 2857 - tty->ops->break_ctl(tty, 0); 2858 - tty_write_unlock(tty); 2859 - if (signal_pending(current)) 2860 - return -EINTR; 2861 - return 0; 2852 + int retval; 2853 + 2854 + if (tty->ops->break_ctl == NULL) 2855 + return 0; 2856 + 2857 + if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK) 2858 + retval = tty->ops->break_ctl(tty, duration); 2859 + else { 2860 + /* Do the work ourselves */ 2861 + if (tty_write_lock(tty, 0) < 0) 2862 + return -EINTR; 2863 + retval = tty->ops->break_ctl(tty, -1); 2864 + if (retval) 2865 + goto out; 2866 + if (!signal_pending(current)) 2867 + msleep_interruptible(duration); 2868 + retval = tty->ops->break_ctl(tty, 0); 2869 + out: 2870 + tty_write_unlock(tty); 2871 + if (signal_pending(current)) 2872 + retval = -EINTR; 2873 + } 2874 + return retval; 2862 2875 } 2863 2876 2864 2877 /** ··· 2962 2949 tty->driver->subtype == PTY_TYPE_MASTER) 2963 2950 real_tty = tty->link; 2964 2951 2965 - /* 2966 - * Break handling by driver 2967 - */ 2968 - 2969 - retval = -EINVAL; 2970 - 2971 - if (!tty->ops->break_ctl) { 2972 - switch (cmd) { 2973 - case TIOCSBRK: 2974 - case TIOCCBRK: 2975 - if (tty->ops->ioctl) 2976 - retval = tty->ops->ioctl(tty, file, cmd, arg); 2977 - if (retval != -EINVAL && retval != -ENOIOCTLCMD) 2978 - printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name); 2979 - return retval; 2980 - 2981 - /* These two ioctl's always return success; even if */ 2982 - /* the driver doesn't support them. */ 2983 - case TCSBRK: 2984 - case TCSBRKP: 2985 - if (!tty->ops->ioctl) 2986 - return 0; 2987 - retval = tty->ops->ioctl(tty, file, cmd, arg); 2988 - if (retval != -EINVAL && retval != -ENOIOCTLCMD) 2989 - printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name); 2990 - if (retval == -ENOIOCTLCMD) 2991 - retval = 0; 2992 - return retval; 2993 - } 2994 - } 2995 2952 2996 2953 /* 2997 2954 * Factor out some common prep work ··· 2983 3000 break; 2984 3001 } 2985 3002 3003 + /* 3004 + * Now do the stuff. 3005 + */ 2986 3006 switch (cmd) { 2987 3007 case TIOCSTI: 2988 3008 return tiocsti(tty, p); ··· 3029 3043 */ 3030 3044 case TIOCSBRK: /* Turn break on, unconditionally */ 3031 3045 if (tty->ops->break_ctl) 3032 - tty->ops->break_ctl(tty, -1); 3046 + return tty->ops->break_ctl(tty, -1); 3033 3047 return 0; 3034 - 3035 3048 case TIOCCBRK: /* Turn break off, unconditionally */ 3036 3049 if (tty->ops->break_ctl) 3037 - tty->ops->break_ctl(tty, 0); 3050 + return tty->ops->break_ctl(tty, 0); 3038 3051 return 0; 3039 3052 case TCSBRK: /* SVID version: non-zero arg --> no break */ 3040 3053 /* non-zero arg means wait for all output data
+3 -2
drivers/char/vme_scc.c
··· 85 85 static irqreturn_t scc_stat_int(int irq, void *data); 86 86 static irqreturn_t scc_spcond_int(int irq, void *data); 87 87 static void scc_setsignals(struct scc_port *port, int dtr, int rts); 88 - static void scc_break_ctl(struct tty_struct *tty, int break_state); 88 + static int scc_break_ctl(struct tty_struct *tty, int break_state); 89 89 90 90 static struct tty_driver *scc_driver; 91 91 ··· 942 942 } 943 943 944 944 945 - static void scc_break_ctl(struct tty_struct *tty, int break_state) 945 + static int scc_break_ctl(struct tty_struct *tty, int break_state) 946 946 { 947 947 struct scc_port *port = (struct scc_port *)tty->driver_data; 948 948 unsigned long flags; ··· 952 952 SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 953 953 break_state ? TCR_SEND_BREAK : 0); 954 954 local_irq_restore(flags); 955 + return 0; 955 956 } 956 957 957 958
+2 -1
drivers/isdn/capi/capi.c
··· 1302 1302 #endif 1303 1303 } 1304 1304 1305 - static void capinc_tty_break_ctl(struct tty_struct *tty, int state) 1305 + static int capinc_tty_break_ctl(struct tty_struct *tty, int state) 1306 1306 { 1307 1307 #ifdef _DEBUG_TTYFUNCS 1308 1308 printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); 1309 1309 #endif 1310 + return 0; 1310 1311 } 1311 1312 1312 1313 static void capinc_tty_flush_buffer(struct tty_struct *tty)
+2 -1
drivers/serial/serial_core.c
··· 934 934 return ret; 935 935 } 936 936 937 - static void uart_break_ctl(struct tty_struct *tty, int break_state) 937 + static int uart_break_ctl(struct tty_struct *tty, int break_state) 938 938 { 939 939 struct uart_state *state = tty->driver_data; 940 940 struct uart_port *port = state->port; ··· 945 945 port->ops->break_ctl(port, break_state); 946 946 947 947 mutex_unlock(&state->mutex); 948 + return 0; 948 949 } 949 950 950 951 static int uart_do_autoconfig(struct uart_state *state)
+6 -3
drivers/usb/class/cdc-acm.c
··· 732 732 tasklet_schedule(&acm->urb_task); 733 733 } 734 734 735 - static void acm_tty_break_ctl(struct tty_struct *tty, int state) 735 + static int acm_tty_break_ctl(struct tty_struct *tty, int state) 736 736 { 737 737 struct acm *acm = tty->driver_data; 738 + int retval; 738 739 if (!ACM_READY(acm)) 739 - return; 740 - if (acm_send_break(acm, state ? 0xffff : 0)) 740 + return -EINVAL; 741 + retval = acm_send_break(acm, state ? 0xffff : 0); 742 + if (retval < 0) 741 743 dbg("send break failed"); 744 + return retval; 742 745 } 743 746 744 747 static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
+2 -1
drivers/usb/serial/usb-serial.c
··· 395 395 tty_termios_copy_hw(tty->termios, old); 396 396 } 397 397 398 - static void serial_break(struct tty_struct *tty, int break_state) 398 + static int serial_break(struct tty_struct *tty, int break_state) 399 399 { 400 400 struct usb_serial_port *port = tty->driver_data; 401 401 ··· 409 409 port->serial->type->break_ctl(tty, break_state); 410 410 unlock_kernel(); 411 411 } 412 + return 0; 412 413 } 413 414 414 415 static int serial_read_proc(char *page, char **start, off_t off, int count,
+12 -2
include/linux/tty_driver.h
··· 135 135 * 136 136 * Optional: 137 137 * 138 - * void (*break_ctl)(struct tty_stuct *tty, int state); 138 + * int (*break_ctl)(struct tty_stuct *tty, int state); 139 139 * 140 140 * This optional routine requests the tty driver to turn on or 141 141 * off BREAK status on the RS-232 port. If state is -1, ··· 145 145 * If this routine is implemented, the high-level tty driver will 146 146 * handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK, 147 147 * TIOCCBRK. 148 + * 149 + * If the driver sets TTY_DRIVER_HARDWARE_BREAK then the interface 150 + * will also be called with actual times and the hardware is expected 151 + * to do the delay work itself. 0 and -1 are still used for on/off. 148 152 * 149 153 * Optional: Required for TCSBRK/BRKP/etc handling. 150 154 * ··· 196 192 void (*stop)(struct tty_struct *tty); 197 193 void (*start)(struct tty_struct *tty); 198 194 void (*hangup)(struct tty_struct *tty); 199 - void (*break_ctl)(struct tty_struct *tty, int state); 195 + int (*break_ctl)(struct tty_struct *tty, int state); 200 196 void (*flush_buffer)(struct tty_struct *tty); 201 197 void (*set_ldisc)(struct tty_struct *tty); 202 198 void (*wait_until_sent)(struct tty_struct *tty, int timeout); ··· 289 285 * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead 290 286 * use dynamic memory keyed through the devpts filesystem. This 291 287 * is only applicable to the pty driver. 288 + * 289 + * TTY_DRIVER_HARDWARE_BREAK -- hardware handles break signals. Pass 290 + * the requested timeout to the caller instead of using a simple 291 + * on/off interface. 292 + * 292 293 */ 293 294 #define TTY_DRIVER_INSTALLED 0x0001 294 295 #define TTY_DRIVER_RESET_TERMIOS 0x0002 295 296 #define TTY_DRIVER_REAL_RAW 0x0004 296 297 #define TTY_DRIVER_DYNAMIC_DEV 0x0008 297 298 #define TTY_DRIVER_DEVPTS_MEM 0x0010 299 + #define TTY_DRIVER_HARDWARE_BREAK 0x0020 298 300 299 301 /* tty driver types */ 300 302 #define TTY_DRIVER_TYPE_SYSTEM 0x0001