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>
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ba8782b..a185263 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -218,7 +218,7 @@
 
 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
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 37457e5..3530ff4 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1248,7 +1248,7 @@
 /*
  * 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 @@
 	  custom.adkcon = AC_UARTBRK;
 	mb();
 	local_irq_restore(flags);
+	return 0;
 }
 
 
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e991dc85..fe6d774 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -3700,14 +3700,15 @@
 /*
  * 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 @@
 			}
 		}
 	} else {
-		int retval;
-
 		if (break_state == -1) {
 			retval = cyz_issue_cmd(card,
 				info->line - card->first_line,
@@ -3758,6 +3757,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&card->card_lock, flags);
+	return retval;
 }				/* cy_break */
 
 static int get_mon_info(struct cyclades_port *info,
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 2eaf09f..7f077c0 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1725,13 +1725,13 @@
 /*
  * 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 @@
 		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,
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 7930fba..63d22b5 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -609,7 +609,7 @@
 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_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 @@
 
 	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;
 }
 
 /*****************************************************************************/
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 2bba250..d3d7864e 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -374,12 +374,13 @@
 	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 = {
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 1fb2557..f04c3c5 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -2183,7 +2183,7 @@
 /*
  * 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 @@
 		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)
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b694d43..d1fceab 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2230,7 +2230,7 @@
  * 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 @@
 			 __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 @@
 	else
 		clear_reg_bits(info, CHA+DAFO, BIT6);
 	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
 }
 
 /* Service an IOCTL request
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index e670eae..584d791 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1236,13 +1236,13 @@
 	}
 }
 
-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 @@
 	else
 		sClrBreak(&info->channel);
 	spin_unlock_irqrestore(&info->slock, flags);
+	return 0;
 }
 
 /*
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index d5cffcd..2162439b 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -1840,7 +1840,7 @@
 	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 @@
 			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)
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 527d220..ef6706f 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2897,9 +2897,9 @@
  *
  * 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 @@
 			 __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 @@
 	else 
 		usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7));
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
+	return 0;
 	
 }	/* end of mgsl_break() */
 
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2c3e43b..cf87bb8 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -165,7 +165,7 @@
 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  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 @@
  * 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 @@
 		value &= ~BIT6;
 	wr_reg16(info, TCR, value);
 	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
 }
 
 #if SYNCLINK_GENERIC_HDLC
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 5768c41..c0490cb 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -527,7 +527,7 @@
 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  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 @@
 /* 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 @@
 			 __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 @@
 		RegValue &= ~BIT3;
 	write_reg(info, CTL, RegValue);
 	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
 }
 
 #if SYNCLINK_GENERIC_HDLC
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index d27a08b..d94cd84 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2849,16 +2849,29 @@
 
 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 @@
 	    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 @@
 		break;
 	}
 
+	/*
+	 *	Now do the stuff.
+	 */
 	switch (cmd) {
 	case TIOCSTI:
 		return tiocsti(tty, p);
@@ -3043,12 +3029,11 @@
 	 */
 	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
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index f17ac04..69c5afe 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -85,7 +85,7 @@
 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 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 @@
 	SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 
 			break_state ? TCR_SEND_BREAK : 0);
 	local_irq_restore(flags);
+	return 0;
 }
 
 
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 8a35029..19e005e 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1302,11 +1302,12 @@
 #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)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0bce1fe..f977c98 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -934,7 +934,7 @@
 	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 @@
 		port->ops->break_ctl(port, break_state);
 
 	mutex_unlock(&state->mutex);
+	return 0;
 }
 
 static int uart_do_autoconfig(struct uart_state *state)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 95ae637..0725b18 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -732,13 +732,16 @@
 	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)
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 51917b0..8c2d531 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -395,7 +395,7 @@
 		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 @@
 		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,
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index d2a0035..e1065ac 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -135,7 +135,7 @@
  *
  *	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,
@@ -146,6 +146,10 @@
  * 	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 @@
 	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 @@
  * 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