arch/tiva: Serial TIOCxBRK BSD-compatible BREAK support

In the lower half UART driver for Tiva architecture (TM4C12x), adding
the TIOCxBRK ioctl calls, which allow an application to transmit a BSD
compatible line BREAK. TIOCSBRK starts the BREAK and TIOCCBRK ends it.

This architecture supports BSD-style BREAK in hardware. We write to
the BRK bit (bit 0) of the UART Line Control register (UARTLCRH) to
start the BREAK, which begins after the UART finishes shifting out the
current character in progress, if any, including its stop bit(s), and
continues indefinitely until we write to the BRK bit again to stop the
BREAK.

* arch/arm/src/tiva/Kconfig
  (config TIVA_UART_BREAKS): New. Appears as CONFIG_TIVA_UART_BREAKS
   in code.

* arch/arm/src/tiva/common/tiva_serial.c
  (struct up_dev_s): Add new field 'brk' to indicate line break in
   progress when built with CONFIG_TIVA_UART_BREAKS.
  (up_ioctl): Add cases for TIOCSBRK to turn BSD-compatible break on
   unconditionally and TIOCCBRK to turn break off unconditionally.
  (up_txint): Block enabling TX interrupt if line break in progress.
   This is similar to the STM32F7 implementation.
This commit is contained in:
Nathan Hartman 2023-02-08 08:48:39 -05:00 committed by Xiang Xiao
parent abba05a934
commit 8b2c8c73e8
2 changed files with 75 additions and 2 deletions

View File

@ -1081,6 +1081,19 @@ config TIVA_HCIUART_SW_TXFLOW
endmenu # HCI UART Driver Configuration endmenu # HCI UART Driver Configuration
config TIVA_UART_BREAKS
bool "Add TIOxSBRK to support sending Breaks"
depends on TIVA_UART0 || TIVA_UART1 || TIVA_UART2 || TIVA_UART3 || TIVA_UART4 || TIVA_UART5 || TIVA_UART6 || TIVA_UART7
default n
---help---
Add TIOCxBRK routines to send a BSD compatible line break.
TIOCSBRK will start the break and TIOCCBRK will end the break.
This implementation uses the BRK bit (bit 0) of the UART Line
Control register (UARTLCRH) to send the break. The break begins
after the UART finishes shifting out the current character in
progress, if any, including its stop bit(s), and continues
indefinitely until stopped by software.
config TIVA_SSI0 config TIVA_SSI0
bool "SSI0" bool "SSI0"
default n default n

View File

@ -301,6 +301,9 @@ struct up_dev_s
#ifdef CONFIG_SERIAL_OFLOWCONTROL #ifdef CONFIG_SERIAL_OFLOWCONTROL
bool oflow; /* output flow control (CTS) enabled */ bool oflow; /* output flow control (CTS) enabled */
#endif #endif
#ifdef CONFIG_TIVA_UART_BREAKS
bool brk; /* true: Line break in progress */
#endif
}; };
/**************************************************************************** /****************************************************************************
@ -1099,11 +1102,12 @@ static int up_interrupt(int irq, void *context, void *arg)
static int up_ioctl(struct file *filep, int cmd, unsigned long arg) static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
{ {
#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) #if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) \
|| defined(CONFIG_TIVA_UART_BREAKS)
struct inode *inode = filep->f_inode; struct inode *inode = filep->f_inode;
struct uart_dev_s *dev = inode->i_private; struct uart_dev_s *dev = inode->i_private;
#endif #endif
#if defined(CONFIG_SERIAL_TERMIOS) #if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_TIVA_UART_BREAKS)
struct up_dev_s *priv = (struct up_dev_s *)dev->priv; struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
#endif #endif
int ret = OK; int ret = OK;
@ -1242,6 +1246,52 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
break; break;
#endif /* CONFIG_SERIAL_TERMIOS */ #endif /* CONFIG_SERIAL_TERMIOS */
#ifdef CONFIG_TIVA_UART_BREAKS
case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
{
irqstate_t flags;
uint32_t tx_break;
flags = enter_critical_section();
/* Disable any further tx activity */
priv->brk = true;
up_txint(dev, false);
/* Send a break signal */
tx_break = up_serialin(priv, TIVA_UART_LCRH_OFFSET);
tx_break |= UART_LCRH_BRK;
up_serialout(priv, TIVA_UART_LCRH_OFFSET, tx_break);
leave_critical_section(flags);
}
break;
case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
{
irqstate_t flags;
uint32_t tx_break;
flags = enter_critical_section();
/* Stop sending the break signal */
tx_break = up_serialin(priv, TIVA_UART_LCRH_OFFSET);
tx_break &= ~UART_LCRH_BRK;
up_serialout(priv, TIVA_UART_LCRH_OFFSET, tx_break);
/* Enable further tx activity */
priv->brk = false;
up_txint(dev, true);
leave_critical_section(flags);
}
break;
#endif /* CONFIG_TIVA_UART_BREAKS */
default: default:
ret = -ENOTTY; ret = -ENOTTY;
break; break;
@ -1351,6 +1401,16 @@ static void up_txint(struct uart_dev_s *dev, bool enable)
/* Set to receive an interrupt when the TX fifo is half emptied */ /* Set to receive an interrupt when the TX fifo is half emptied */
#ifndef CONFIG_SUPPRESS_SERIAL_INTS #ifndef CONFIG_SUPPRESS_SERIAL_INTS
# ifdef CONFIG_TIVA_UART_BREAKS
/* Do not enable TX interrupt if line break in progress */
if (priv->brk)
{
leave_critical_section(flags);
return;
}
# endif
priv->im |= UART_IM_TXIM; priv->im |= UART_IM_TXIM;
up_serialout(priv, TIVA_UART_IM_OFFSET, priv->im); up_serialout(priv, TIVA_UART_IM_OFFSET, priv->im);