From 70f778c02b1cb2f9855d0311e105f72b02c3555d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 27 Nov 2014 19:14:10 -0600 Subject: [PATCH] EFM32 Serial: Add support for termios TCGET and TCSET. For the moment, only set/get speed is implemetned. From Pierre-noel Bouteville --- arch/arm/src/efm32/Kconfig | 3 + arch/arm/src/efm32/efm32_serial.c | 128 +++++++++++++++++++++++++++--- 2 files changed, 118 insertions(+), 13 deletions(-) diff --git a/arch/arm/src/efm32/Kconfig b/arch/arm/src/efm32/Kconfig index 448cb9f20d..3d59d11deb 100644 --- a/arch/arm/src/efm32/Kconfig +++ b/arch/arm/src/efm32/Kconfig @@ -132,17 +132,20 @@ config EFM32_USART0 bool "USART0" default n select ARCH_HAVE_USART0 + select ARCH_HAVE_SERIAL_TERMIOS config EFM32_USART1 bool "USART1" default n select ARCH_HAVE_USART1 + select ARCH_HAVE_SERIAL_TERMIOS config EFM32_USART2 bool "USART2" default n depends on EFM32_HAVE_USART2 select ARCH_HAVE_USART2 + select ARCH_HAVE_SERIAL_TERMIOS config EFM32_UART0 bool "UART0" diff --git a/arch/arm/src/efm32/efm32_serial.c b/arch/arm/src/efm32/efm32_serial.c index 06e16af932..86229d3b4a 100644 --- a/arch/arm/src/efm32/efm32_serial.c +++ b/arch/arm/src/efm32/efm32_serial.c @@ -52,6 +52,11 @@ #include #include +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include #include #include "up_arch.h" @@ -226,8 +231,12 @@ struct efm32_config_s struct efm32_usart_s { +#ifdef CONFIG_SERIAL_TERMIOS + struct efm32_config_s *config; +#else const struct efm32_config_s *config; - uint16_t ien; /* Interrupts enabled */ +#endif + uint16_t ien; /* Interrupts enabled */ }; /**************************************************************************** @@ -576,7 +585,7 @@ static void efm32_restoreuartint(struct efm32_usart_s *priv, uint32_t ien) * Name: efm32_disableuartint ****************************************************************************/ -#ifdef HAVE_UART_CONSOLE +#if defined(HAVE_UART_CONSOLE) || defined(CONFIG_SERIAL_TERMIOS) static void efm32_disableuartint(struct efm32_usart_s *priv, uint32_t *ien) { irqstate_t flags; @@ -603,13 +612,13 @@ static void efm32_disableuartint(struct efm32_usart_s *priv, uint32_t *ien) static int efm32_setup(struct uart_dev_s *dev) { - struct efm32_usart_s *priv = (struct efm32_usart_s*)dev->priv; - uint32_t regval; + struct efm32_usart_s *priv = (struct efm32_usart_s*)dev->priv; + uint32_t regval; #ifndef CONFIG_SUPPRESS_UART_CONFIG - const struct efm32_config_s *config = priv->config; + const struct efm32_config_s *config = priv->config; - /* Configure the UART as an RS-232 UART */ + /* Configure the UART as an RS-232 UART */ efm32_uartconfigure(config->uartbase, config->baud, config->parity, config->bits, config->stop2); @@ -905,33 +914,126 @@ static int efm32_uart1_txinterrupt(int irq, void *context) static int efm32_ioctl(struct file *filep, int cmd, unsigned long arg) { -#if 0 /* Reserved for future growth */ struct inode *inode; struct uart_dev_s *dev; +#ifdef CONFIG_SERIAL_TERMIOS struct efm32_usart_s *priv; +#endif + int ret = OK; - DEBUGASSERT(filep, filep->f_inode); + DEBUGASSERT(filep); + DEBUGASSERT(filep->f_inode); + inode = filep->f_inode; dev = inode->i_private; - DEBUGASSERT(dev, dev->priv) + DEBUGASSERT(dev); + DEBUGASSERT(dev->priv); + +#ifdef CONFIG_SERIAL_TERMIOS priv = (struct efm32_usart_s*)dev->priv; +#endif switch (cmd) { - case xxx: /* Add commands here */ +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios*)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + cfsetispeed(termiosp, priv->config->baud); + + /* Note that since we only support 8/9 bit modes and + * there is no way to report 9-bit mode, we always claim 8. + */ + + termiosp->c_cflag = CS8; + + /* TODO: PARENB, PARODD, CSTOPB, CCTS_IFLOW, CCTS_OFLOW */ + } break; + case TCSETS: + { + struct termios *termiosp = (struct termios*)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Perform some sanity checks before accepting any changes */ + + if (((termiosp->c_cflag & CSIZE) != CS8) +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + /* TODO : PARENB, PARODD, CSTOPB, CCTS_OFLOW, CCTS_IFLOW */ + +#if 0 + if (termiosp->c_cflag & PARENB) + { + priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + priv->parity = 0; + } + + priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif +#endif + + /* Note that only cfgetispeed is used because we have knowledge + * that only one speed is supported. + */ + + { + uint32_t ien; + struct efm32_config_s* config = priv->config; + + config->baud = cfgetispeed(termiosp); + + /* Just speed is yet implemented */ + efm32_disableuartint(priv,&ien); + + efm32_uartconfigure(config->uartbase, config->baud, config->parity, + config->bits, config->stop2); + + efm32_restoreuartint(priv, ien); + } + } + break; +#endif + default: ret = -ENOTTY; break; } return ret; -#else - return -ENOTTY; -#endif } /****************************************************************************