tty: rework break handling
Alan Cox [Tue, 22 Jul 2008 10:18:03 +0000 (11:18 +0100)]
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>

20 files changed:
drivers/char/Kconfig
drivers/char/amiserial.c
drivers/char/cyclades.c
drivers/char/esp.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/rocket.c
drivers/char/sx.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tty_io.c
drivers/char/vme_scc.c
drivers/isdn/capi/capi.c
drivers/serial/serial_core.c
drivers/usb/class/cdc-acm.c
drivers/usb/serial/usb-serial.c
include/linux/tty_driver.h

index ba8782b..a185263 100644 (file)
@@ -218,7 +218,7 @@ config MOXA_SMARTIO
 
 config ISI
        tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
-       depends on SERIAL_NONSTANDARD && PCI
+       depends on SERIAL_NONSTANDARD && PCI && BROKEN
        select FW_LOADER
        help
          This is a driver for the Multi-Tech cards which provide several
index 37457e5..3530ff4 100644 (file)
@@ -1248,7 +1248,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
 /*
  * rs_break() --- routine which turns the break handling on or off
  */
-static void rs_break(struct tty_struct *tty, int break_state)
+static int rs_break(struct tty_struct *tty, int break_state)
 {
        struct async_struct * info = (struct async_struct *)tty->driver_data;
        unsigned long flags;
@@ -1263,6 +1263,7 @@ static void rs_break(struct tty_struct *tty, int break_state)
          custom.adkcon = AC_UARTBRK;
        mb();
        local_irq_restore(flags);
+       return 0;
 }
 
 
index e991dc8..fe6d774 100644 (file)
@@ -3700,14 +3700,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
 /*
  * cy_break() --- routine which turns the break handling on or off
  */
-static void cy_break(struct tty_struct *tty, int break_state)
+static int cy_break(struct tty_struct *tty, int break_state)
 {
        struct cyclades_port *info = tty->driver_data;
        struct cyclades_card *card;
        unsigned long flags;
+       int retval = 0;
 
        if (serial_paranoia_check(info, tty->name, "cy_break"))
-               return;
+               return -EINVAL;
 
        card = info->card;
 
@@ -3736,8 +3737,6 @@ static void cy_break(struct tty_struct *tty, int break_state)
                        }
                }
        } else {
-               int retval;
-
                if (break_state == -1) {
                        retval = cyz_issue_cmd(card,
                                info->line - card->first_line,
@@ -3758,6 +3757,7 @@ static void cy_break(struct tty_struct *tty, int break_state)
                }
        }
        spin_unlock_irqrestore(&card->card_lock, flags);
+       return retval;
 }                              /* cy_break */
 
 static int get_mon_info(struct cyclades_port *info,
index 2eaf09f..7f077c0 100644 (file)
@@ -1725,13 +1725,13 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
 /*
  * rs_break() --- routine which turns the break handling on or off
  */
-static void esp_break(struct tty_struct *tty, int break_state)
+static int esp_break(struct tty_struct *tty, int break_state)
 {
        struct esp_struct *info = tty->driver_data;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "esp_break"))
-               return;
+               return -EINVAL;
 
        if (break_state == -1) {
                spin_lock_irqsave(&info->lock, flags);
@@ -1747,6 +1747,7 @@ static void esp_break(struct tty_struct *tty, int break_state)
                serial_out(info, UART_ESI_CMD2, 0x00);
                spin_unlock_irqrestore(&info->lock, flags);
        }
+       return 0;
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file *file,
index 7930fba..63d22b5 100644 (file)
@@ -609,7 +609,7 @@ static void stli_unthrottle(struct tty_struct *tty);
 static void    stli_stop(struct tty_struct *tty);
 static void    stli_start(struct tty_struct *tty);
 static void    stli_flushbuffer(struct tty_struct *tty);
-static void    stli_breakctl(struct tty_struct *tty, int state);
+static int     stli_breakctl(struct tty_struct *tty, int state);
 static void    stli_waituntilsent(struct tty_struct *tty, int timeout);
 static void    stli_sendxchar(struct tty_struct *tty, char ch);
 static void    stli_hangup(struct tty_struct *tty);
@@ -1909,7 +1909,7 @@ static void stli_flushbuffer(struct tty_struct *tty)
 
 /*****************************************************************************/
 
-static void stli_breakctl(struct tty_struct *tty, int state)
+static int stli_breakctl(struct tty_struct *tty, int state)
 {
        struct stlibrd  *brdp;
        struct stliport *portp;
@@ -1917,15 +1917,16 @@ static void stli_breakctl(struct tty_struct *tty, int state)
 
        portp = tty->driver_data;
        if (portp == NULL)
-               return;
+               return -EINVAL;
        if (portp->brdnr >= stli_nrbrds)
-               return;
+               return -EINVAL;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
-               return;
+               return -EINVAL;
 
        arg = (state == -1) ? BREAKON : BREAKOFF;
        stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
+       return 0;
 }
 
 /*****************************************************************************/
index 2bba250..d3d7864 100644 (file)
@@ -374,12 +374,13 @@ copy:
        return ret;
 }
 
-static void moxa_break_ctl(struct tty_struct *tty, int state)
+static int moxa_break_ctl(struct tty_struct *tty, int state)
 {
        struct moxa_port *port = tty->driver_data;
 
        moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
                        Magic_code);
+       return 0;
 }
 
 static const struct tty_operations moxa_ops = {
index 1fb2557..f04c3c5 100644 (file)
@@ -2183,7 +2183,7 @@ static void mxser_hangup(struct tty_struct *tty)
 /*
  * mxser_rs_break() --- routine which turns the break handling on or off
  */
-static void mxser_rs_break(struct tty_struct *tty, int break_state)
+static int mxser_rs_break(struct tty_struct *tty, int break_state)
 {
        struct mxser_port *info = tty->driver_data;
        unsigned long flags;
@@ -2196,6 +2196,7 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state)
                outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
                        info->ioaddr + UART_LCR);
        spin_unlock_irqrestore(&info->slock, flags);
+       return 0;
 }
 
 static void mxser_receive_chars(struct mxser_port *port, int *status)
index b694d43..d1fceab 100644 (file)
@@ -2230,7 +2230,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
  * Arguments:          tty             pointer to tty instance data
  *                     break_state     -1=set break condition, 0=clear
  */
-static void mgslpc_break(struct tty_struct *tty, int break_state)
+static int mgslpc_break(struct tty_struct *tty, int break_state)
 {
        MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
        unsigned long flags;
@@ -2240,7 +2240,7 @@ static void mgslpc_break(struct tty_struct *tty, int break_state)
                         __FILE__,__LINE__, info->device_name, break_state);
 
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&info->lock,flags);
        if (break_state == -1)
@@ -2248,6 +2248,7 @@ static void mgslpc_break(struct tty_struct *tty, int break_state)
        else
                clear_reg_bits(info, CHA+DAFO, BIT6);
        spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
 }
 
 /* Service an IOCTL request
index e670eae..584d791 100644 (file)
@@ -1236,13 +1236,13 @@ static void rp_set_termios(struct tty_struct *tty,
        }
 }
 
-static void rp_break(struct tty_struct *tty, int break_state)
+static int rp_break(struct tty_struct *tty, int break_state)
 {
        struct r_port *info = (struct r_port *) tty->driver_data;
        unsigned long flags;
 
        if (rocket_paranoia_check(info, "rp_break"))
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&info->slock, flags);
        if (break_state == -1)
@@ -1250,6 +1250,7 @@ static void rp_break(struct tty_struct *tty, int break_state)
        else
                sClrBreak(&info->channel);
        spin_unlock_irqrestore(&info->slock, flags);
+       return 0;
 }
 
 /*
index d5cffcd..2162439 100644 (file)
@@ -1840,7 +1840,7 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
        return rc;
 }
 
-static void sx_break(struct tty_struct *tty, int flag)
+static int sx_break(struct tty_struct *tty, int flag)
 {
        struct sx_port *port = tty->driver_data;
        int rv;
@@ -1857,6 +1857,7 @@ static void sx_break(struct tty_struct *tty, int flag)
                        read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
        unlock_kernel();
        func_exit();
+       return 0;
 }
 
 static int sx_tiocmget(struct tty_struct *tty, struct file *file)
index 527d220..ef6706f 100644 (file)
@@ -2897,9 +2897,9 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
  *
  * Arguments:          tty             pointer to tty instance data
  *                     break_state     -1=set break condition, 0=clear
- * Return Value:       None
+ * Return Value:       error code
  */
-static void mgsl_break(struct tty_struct *tty, int break_state)
+static int mgsl_break(struct tty_struct *tty, int break_state)
 {
        struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
        unsigned long flags;
@@ -2909,7 +2909,7 @@ static void mgsl_break(struct tty_struct *tty, int break_state)
                         __FILE__,__LINE__, info->device_name, break_state);
                         
        if (mgsl_paranoia_check(info, tty->name, "mgsl_break"))
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&info->irq_spinlock,flags);
        if (break_state == -1)
@@ -2917,6 +2917,7 @@ static void mgsl_break(struct tty_struct *tty, int break_state)
        else 
                usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7));
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
+       return 0;
        
 }      /* end of mgsl_break() */
 
index 2c3e43b..cf87bb8 100644 (file)
@@ -165,7 +165,7 @@ static int  read_proc(char *page, char **start, off_t off, int count,int *eof, v
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
 
 /*
  * generic HDLC support and callbacks
@@ -513,7 +513,7 @@ static int  wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr);
 static int  tiocmget(struct tty_struct *tty, struct file *file);
 static int  tiocmset(struct tty_struct *tty, struct file *file,
                     unsigned int set, unsigned int clear);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
 static int  get_interface(struct slgt_info *info, int __user *if_mode);
 static int  set_interface(struct slgt_info *info, int if_mode);
 static int  set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
@@ -1452,14 +1452,14 @@ static void unthrottle(struct tty_struct * tty)
  * set or clear transmit break condition
  * break_state -1=set break condition, 0=clear
  */
-static void set_break(struct tty_struct *tty, int break_state)
+static int set_break(struct tty_struct *tty, int break_state)
 {
        struct slgt_info *info = tty->driver_data;
        unsigned short value;
        unsigned long flags;
 
        if (sanity_check(info, tty->name, "set_break"))
-               return;
+               return -EINVAL;
        DBGINFO(("%s set_break(%d)\n", info->device_name, break_state));
 
        spin_lock_irqsave(&info->lock,flags);
@@ -1470,6 +1470,7 @@ static void set_break(struct tty_struct *tty, int break_state)
                value &= ~BIT6;
        wr_reg16(info, TCR, value);
        spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
 }
 
 #if SYNCLINK_GENERIC_HDLC
index 5768c41..c0490cb 100644 (file)
@@ -527,7 +527,7 @@ static int  read_proc(char *page, char **start, off_t off, int count,int *eof, v
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
 
 #if SYNCLINK_GENERIC_HDLC
 #define dev_to_port(D) (dev_to_hdlc(D)->priv)
@@ -552,7 +552,7 @@ static int  wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr);
 static int  tiocmget(struct tty_struct *tty, struct file *file);
 static int  tiocmset(struct tty_struct *tty, struct file *file,
                     unsigned int set, unsigned int clear);
-static void set_break(struct tty_struct *tty, int break_state);
+static int  set_break(struct tty_struct *tty, int break_state);
 
 static void add_device(SLMP_INFO *info);
 static void device_init(int adapter_num, struct pci_dev *pdev);
@@ -1587,7 +1587,7 @@ static void unthrottle(struct tty_struct * tty)
 /* set or clear transmit break condition
  * break_state -1=set break condition, 0=clear
  */
-static void set_break(struct tty_struct *tty, int break_state)
+static int set_break(struct tty_struct *tty, int break_state)
 {
        unsigned char RegValue;
        SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
@@ -1598,7 +1598,7 @@ static void set_break(struct tty_struct *tty, int break_state)
                         __FILE__,__LINE__, info->device_name, break_state);
 
        if (sanity_check(info, tty->name, "set_break"))
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&info->lock,flags);
        RegValue = read_reg(info, CTL);
@@ -1608,6 +1608,7 @@ static void set_break(struct tty_struct *tty, int break_state)
                RegValue &= ~BIT3;
        write_reg(info, CTL, RegValue);
        spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
 }
 
 #if SYNCLINK_GENERIC_HDLC
index d27a08b..d94cd84 100644 (file)
@@ -2849,16 +2849,29 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
 
 static int send_break(struct tty_struct *tty, unsigned int duration)
 {
-       if (tty_write_lock(tty, 0) < 0)
-               return -EINTR;
-       tty->ops->break_ctl(tty, -1);
-       if (!signal_pending(current))
-               msleep_interruptible(duration);
-       tty->ops->break_ctl(tty, 0);
-       tty_write_unlock(tty);
-       if (signal_pending(current))
-               return -EINTR;
-       return 0;
+       int retval;
+
+       if (tty->ops->break_ctl == NULL)
+               return 0;
+
+       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
+               retval = tty->ops->break_ctl(tty, duration);
+       else {
+               /* Do the work ourselves */
+               if (tty_write_lock(tty, 0) < 0)
+                       return -EINTR;
+               retval = tty->ops->break_ctl(tty, -1);
+               if (retval)
+                       goto out;
+               if (!signal_pending(current))
+                       msleep_interruptible(duration);
+               retval = tty->ops->break_ctl(tty, 0);
+out:
+               tty_write_unlock(tty);
+               if (signal_pending(current))
+                       retval = -EINTR;
+       }
+       return retval;
 }
 
 /**
@@ -2949,36 +2962,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
            tty->driver->subtype == PTY_TYPE_MASTER)
                real_tty = tty->link;
 
-       /*
-        * Break handling by driver
-        */
-
-       retval = -EINVAL;
-
-       if (!tty->ops->break_ctl) {
-               switch (cmd) {
-               case TIOCSBRK:
-               case TIOCCBRK:
-                       if (tty->ops->ioctl)
-                               retval = tty->ops->ioctl(tty, file, cmd, arg);
-                       if (retval != -EINVAL && retval != -ENOIOCTLCMD)
-                               printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
-                       return retval;
-
-               /* These two ioctl's always return success; even if */
-               /* the driver doesn't support them. */
-               case TCSBRK:
-               case TCSBRKP:
-                       if (!tty->ops->ioctl)
-                               return 0;
-                       retval = tty->ops->ioctl(tty, file, cmd, arg);
-                       if (retval != -EINVAL && retval != -ENOIOCTLCMD)
-                               printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
-                       if (retval == -ENOIOCTLCMD)
-                               retval = 0;
-                       return retval;
-               }
-       }
 
        /*
         * Factor out some common prep work
@@ -3000,6 +2983,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
        }
 
+       /*
+        *      Now do the stuff.
+        */
        switch (cmd) {
        case TIOCSTI:
                return tiocsti(tty, p);
@@ -3043,12 +3029,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
         */
        case TIOCSBRK:  /* Turn break on, unconditionally */
                if (tty->ops->break_ctl)
-                       tty->ops->break_ctl(tty, -1);
+                       return tty->ops->break_ctl(tty, -1);
                return 0;
-
        case TIOCCBRK:  /* Turn break off, unconditionally */
                if (tty->ops->break_ctl)
-                       tty->ops->break_ctl(tty, 0);
+                       return tty->ops->break_ctl(tty, 0);
                return 0;
        case TCSBRK:   /* SVID version: non-zero arg --> no break */
                /* non-zero arg means wait for all output data
index f17ac04..69c5afe 100644 (file)
@@ -85,7 +85,7 @@ static irqreturn_t scc_rx_int(int irq, void *data);
 static irqreturn_t scc_stat_int(int irq, void *data);
 static irqreturn_t scc_spcond_int(int irq, void *data);
 static void scc_setsignals(struct scc_port *port, int dtr, int rts);
-static void scc_break_ctl(struct tty_struct *tty, int break_state);
+static int scc_break_ctl(struct tty_struct *tty, int break_state);
 
 static struct tty_driver *scc_driver;
 
@@ -942,7 +942,7 @@ static int scc_ioctl(struct tty_struct *tty, struct file *file,
 }
 
 
-static void scc_break_ctl(struct tty_struct *tty, int break_state)
+static int scc_break_ctl(struct tty_struct *tty, int break_state)
 {
        struct scc_port *port = (struct scc_port *)tty->driver_data;
        unsigned long   flags;
@@ -952,6 +952,7 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state)
        SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 
                        break_state ? TCR_SEND_BREAK : 0);
        local_irq_restore(flags);
+       return 0;
 }
 
 
index 8a35029..19e005e 100644 (file)
@@ -1302,11 +1302,12 @@ static void capinc_tty_hangup(struct tty_struct *tty)
 #endif
 }
 
-static void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
 {
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
 #endif
+       return 0;
 }
 
 static void capinc_tty_flush_buffer(struct tty_struct *tty)
index 0bce1fe..f977c98 100644 (file)
@@ -934,7 +934,7 @@ uart_tiocmset(struct tty_struct *tty, struct file *file,
        return ret;
 }
 
-static void uart_break_ctl(struct tty_struct *tty, int break_state)
+static int uart_break_ctl(struct tty_struct *tty, int break_state)
 {
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->port;
@@ -945,6 +945,7 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
                port->ops->break_ctl(port, break_state);
 
        mutex_unlock(&state->mutex);
+       return 0;
 }
 
 static int uart_do_autoconfig(struct uart_state *state)
index 95ae637..0725b18 100644 (file)
@@ -732,13 +732,16 @@ static void acm_tty_unthrottle(struct tty_struct *tty)
        tasklet_schedule(&acm->urb_task);
 }
 
-static void acm_tty_break_ctl(struct tty_struct *tty, int state)
+static int acm_tty_break_ctl(struct tty_struct *tty, int state)
 {
        struct acm *acm = tty->driver_data;
+       int retval;
        if (!ACM_READY(acm))
-               return;
-       if (acm_send_break(acm, state ? 0xffff : 0))
+               return -EINVAL;
+       retval = acm_send_break(acm, state ? 0xffff : 0);
+       if (retval < 0)
                dbg("send break failed");
+       return retval;
 }
 
 static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
index 51917b0..8c2d531 100644 (file)
@@ -395,7 +395,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
                tty_termios_copy_hw(tty->termios, old);
 }
 
-static void serial_break(struct tty_struct *tty, int break_state)
+static int serial_break(struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
 
@@ -409,6 +409,7 @@ static void serial_break(struct tty_struct *tty, int break_state)
                port->serial->type->break_ctl(tty, break_state);
                unlock_kernel();
        }
+       return 0;
 }
 
 static int serial_read_proc(char *page, char **start, off_t off, int count,
index d2a0035..e1065ac 100644 (file)
  *
  *     Optional:
  *
- * void (*break_ctl)(struct tty_stuct *tty, int state);
+ * int (*break_ctl)(struct tty_stuct *tty, int state);
  *
  *     This optional routine requests the tty driver to turn on or
  *     off BREAK status on the RS-232 port.  If state is -1,
  *     handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK,
  *     TIOCCBRK.
  *
+ *     If the driver sets TTY_DRIVER_HARDWARE_BREAK then the interface
+ *     will also be called with actual times and the hardware is expected
+ *     to do the delay work itself. 0 and -1 are still used for on/off.
+ *
  *     Optional: Required for TCSBRK/BRKP/etc handling.
  *
  * void (*wait_until_sent)(struct tty_struct *tty, int timeout);
@@ -192,7 +196,7 @@ struct tty_operations {
        void (*stop)(struct tty_struct *tty);
        void (*start)(struct tty_struct *tty);
        void (*hangup)(struct tty_struct *tty);
-       void (*break_ctl)(struct tty_struct *tty, int state);
+       int (*break_ctl)(struct tty_struct *tty, int state);
        void (*flush_buffer)(struct tty_struct *tty);
        void (*set_ldisc)(struct tty_struct *tty);
        void (*wait_until_sent)(struct tty_struct *tty, int timeout);
@@ -285,12 +289,18 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
  * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead
  *     use dynamic memory keyed through the devpts filesystem.  This
  *     is only applicable to the pty driver.
+ *
+ * TTY_DRIVER_HARDWARE_BREAK -- hardware handles break signals. Pass
+ *     the requested timeout to the caller instead of using a simple
+ *     on/off interface.
+ *
  */
 #define TTY_DRIVER_INSTALLED           0x0001
 #define TTY_DRIVER_RESET_TERMIOS       0x0002
 #define TTY_DRIVER_REAL_RAW            0x0004
 #define TTY_DRIVER_DYNAMIC_DEV         0x0008
 #define TTY_DRIVER_DEVPTS_MEM          0x0010
+#define TTY_DRIVER_HARDWARE_BREAK      0x0020
 
 /* tty driver types */
 #define TTY_DRIVER_TYPE_SYSTEM         0x0001