summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-02-23 10:35:16 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-02-28 08:51:31 +0100
commit9f69ac2a9dead44b62842081c8357b4dcd23dcaa (patch)
tree176daa49e3a86c37baff9f3f0643d22741eaf1b8
parenttermios: Protect raw input buffer with device lock (diff)
downloadrtems-9f69ac2a9dead44b62842081c8357b4dcd23dcaa.tar.bz2
termios: Ignore carriage return early if desired
In case carriage return characters should be ignored in the input (IGNCR), then drop them early before they reach the raw input buffer. This makes it easier to calculate the content size of the raw input buffer.
-rw-r--r--cpukit/libcsupport/src/termios.c25
-rw-r--r--testsuites/libtests/Makefile.am1
-rw-r--r--testsuites/libtests/configure.ac1
-rw-r--r--testsuites/libtests/termios09/Makefile.am19
-rw-r--r--testsuites/libtests/termios09/init.c269
-rw-r--r--testsuites/libtests/termios09/termios09.doc11
-rw-r--r--testsuites/libtests/termios09/termios09.scn2
7 files changed, 322 insertions, 6 deletions
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index f88494f15d..c1d6cd5297 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -1295,12 +1295,11 @@ iproc (unsigned char c, struct rtems_termios_tty *tty)
c = tolower (c);
if (c == '\r') {
- if (tty->termios.c_iflag & IGNCR)
- return 0;
if (tty->termios.c_iflag & ICRNL)
c = '\n';
- } else if ((c == '\n') && (tty->termios.c_iflag & INLCR)) {
- c = '\r';
+ } else if (c == '\n') {
+ if (tty->termios.c_iflag & INLCR)
+ c = '\r';
}
if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
@@ -1366,6 +1365,16 @@ siproc (unsigned char c, struct rtems_termios_tty *tty)
return i;
}
+static int
+siprocPoll (unsigned char c, rtems_termios_tty *tty)
+{
+ if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) {
+ return 0;
+ }
+
+ return siproc (c, tty);
+}
+
/*
* Fill the input buffer by polling the device
*/
@@ -1380,7 +1389,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
if (n < 0) {
rtems_task_wake_after (1);
} else {
- if (siproc (n, tty))
+ if (siprocPoll (n, tty))
break;
}
}
@@ -1408,7 +1417,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
}
rtems_task_wake_after (1);
} else {
- siproc (n, tty);
+ siprocPoll (n, tty);
if (tty->ccount >= tty->termios.c_cc[VMIN])
break;
if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
@@ -1637,6 +1646,10 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
unsigned int oldTail;
unsigned int newTail;
+ if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) {
+ continue;
+ }
+
rtems_termios_device_lock_acquire (ctx, &lock_context);
head = tty->rawInBuf.Head;
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index 9ff4394f9e..286875d143 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -1,6 +1,7 @@
ACLOCAL_AMFLAGS = -I ../aclocal
_SUBDIRS = POSIX
+_SUBDIRS += termios09
_SUBDIRS += libfdt01
_SUBDIRS += defaultconfig01
_SUBDIRS += pwdgrp02
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index 8e74b3e979..4e82caff18 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -172,6 +172,7 @@ termios05/Makefile
termios06/Makefile
termios07/Makefile
termios08/Makefile
+termios09/Makefile
top/Makefile
tztest/Makefile
capture01/Makefile
diff --git a/testsuites/libtests/termios09/Makefile.am b/testsuites/libtests/termios09/Makefile.am
new file mode 100644
index 0000000000..18714de490
--- /dev/null
+++ b/testsuites/libtests/termios09/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = termios09
+termios09_SOURCES = init.c
+
+dist_rtems_tests_DATA = termios09.scn termios09.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(termios09_OBJECTS)
+LINK_LIBS = $(termios09_LDLIBS)
+
+termios09$(EXEEXT): $(termios09_OBJECTS) $(termios09_DEPENDENCIES)
+ @rm -f termios09$(EXEEXT)
+ $(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/libtests/termios09/init.c b/testsuites/libtests/termios09/init.c
new file mode 100644
index 0000000000..6e651bfafa
--- /dev/null
+++ b/testsuites/libtests/termios09/init.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2017 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <rtems/termiostypes.h>
+
+#include "tmacros.h"
+
+const char rtems_test_name[] = "TERMIOS 9";
+
+#define INTERRUPT 0
+
+#define POLLED 1
+
+#define DEVICE_COUNT 2
+
+#define OUTPUT_BUFFER_SIZE 64
+
+static const char * const paths[DEVICE_COUNT] = {
+ "/interrupt",
+ "/polled"
+};
+
+typedef struct {
+ rtems_termios_device_context base;
+ rtems_termios_tty *tty;
+ size_t output_pending;
+ size_t output_count;
+ char output_buf[OUTPUT_BUFFER_SIZE];
+ int input_char;
+} device_context;
+
+typedef struct {
+ device_context devices[DEVICE_COUNT];
+ int fds[DEVICE_COUNT];
+ struct termios term[DEVICE_COUNT];
+} test_context;
+
+static test_context test_instance = {
+ .devices = {
+ {
+ .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Interrupt")
+ }, {
+ .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled"),
+ .input_char = -1
+ }
+ }
+};
+
+static bool first_open(
+ rtems_termios_tty *tty,
+ rtems_termios_device_context *base,
+ struct termios *term,
+ rtems_libio_open_close_args_t *args
+)
+{
+ device_context *dev = (device_context *) base;
+
+ dev->tty = tty;
+
+ return true;
+}
+
+static void write_polled(
+ rtems_termios_device_context *base,
+ const char *buf,
+ size_t len
+)
+{
+ device_context *dev = (device_context *) base;
+
+ rtems_test_assert(dev->output_count + len <= OUTPUT_BUFFER_SIZE);
+ memcpy(&dev->output_buf[dev->output_count], buf, len);
+ dev->output_count += len;
+}
+
+static void write_interrupt(
+ rtems_termios_device_context *base,
+ const char *buf,
+ size_t len
+)
+{
+ device_context *dev = (device_context *) base;
+
+ write_polled(base, buf, len);
+ dev->output_pending = len;
+}
+
+static int read_polled(rtems_termios_device_context *base)
+{
+ device_context *dev = (device_context *) base;
+ int c = dev->input_char;
+
+ dev->input_char = -1;
+
+ return c;
+}
+
+static const rtems_termios_device_handler handlers[DEVICE_COUNT] = {
+ {
+ .first_open = first_open,
+ .write = write_interrupt,
+ .mode = TERMIOS_IRQ_DRIVEN
+ }, {
+ .first_open = first_open,
+ .write = write_polled,
+ .poll_read = read_polled,
+ .mode = TERMIOS_POLLED
+ }
+};
+
+static void set_term(test_context *ctx, size_t i)
+{
+ int rv;
+
+ rv = tcsetattr(ctx->fds[i], TCSANOW, &ctx->term[i]);
+ rtems_test_assert(rv == 0);
+}
+
+static void init_term(test_context *ctx, size_t i)
+{
+ int rv;
+
+ rv = tcgetattr(ctx->fds[i], &ctx->term[i]);
+ rtems_test_assert(rv == 0);
+
+ ctx->term[i].c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON);
+ ctx->term[i].c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ ctx->term[i].c_cflag &= ~(CSIZE | PARENB);
+ ctx->term[i].c_cflag |= CS8;
+ ctx->term[i].c_oflag &= ~(OPOST | ONLRET | ONLCR | OCRNL | ONLRET
+ | TABDLY | OLCUC);
+
+ ctx->term[i].c_cc[VMIN] = 0;
+ ctx->term[i].c_cc[VTIME] = 0;
+
+ set_term(ctx, i);
+}
+
+static void setup(test_context *ctx)
+{
+ rtems_status_code sc;
+ size_t i;
+
+ rtems_termios_initialize();
+
+ for (i = 0; i < DEVICE_COUNT; ++i) {
+ sc = rtems_termios_device_install(
+ paths[i],
+ &handlers[i],
+ NULL,
+ &ctx->devices[i].base
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ ctx->fds[i] = open(paths[i], O_RDWR);
+ rtems_test_assert(ctx->fds[i] >= 0);
+
+ init_term(ctx, i);
+ }
+}
+
+static void input(test_context *ctx, size_t i, char c)
+{
+ switch (i) {
+ case INTERRUPT:
+ rtems_termios_enqueue_raw_characters(ctx->devices[i].tty, &c, sizeof(c));
+ break;
+ case POLLED:
+ ctx->devices[i].input_char = (unsigned char) c;
+ break;
+ default:
+ rtems_test_assert(0);
+ }
+}
+
+static void clear_set_iflag(
+ test_context *ctx,
+ size_t i,
+ tcflag_t clear,
+ tcflag_t set
+)
+{
+ ctx->term[i].c_iflag &= ~clear;
+ ctx->term[i].c_iflag |= set;
+ set_term(ctx, i);
+}
+
+static void test_igncr(test_context *ctx)
+{
+ size_t i;
+
+ for (i = 0; i < DEVICE_COUNT; ++i) {
+ ssize_t n;
+ char c;
+
+ c = 'x';
+
+ clear_set_iflag(ctx, i, 0, IGNCR);
+
+ n = read(ctx->fds[i], &c, sizeof(c));
+ rtems_test_assert(n == 0);
+ rtems_test_assert(c == 'x');
+
+ input(ctx, i, '\r');
+
+ n = read(ctx->fds[i], &c, sizeof(c));
+ rtems_test_assert(n == 0);
+ rtems_test_assert(c == 'x');
+
+ clear_set_iflag(ctx, i, IGNCR, 0);
+ input(ctx, i, '\r');
+
+ n = read(ctx->fds[i], &c, sizeof(c));
+ rtems_test_assert(n == 1);
+ rtems_test_assert(c == '\r');
+ }
+}
+
+static void Init(rtems_task_argument arg)
+{
+ test_context *ctx = &test_instance;
+
+ TEST_BEGIN();
+
+ setup(ctx);
+ test_igncr(ctx);
+
+ TEST_END();
+ rtems_test_exit(0);
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_MAXIMUM_SEMAPHORES 7
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/libtests/termios09/termios09.doc b/testsuites/libtests/termios09/termios09.doc
new file mode 100644
index 0000000000..d2c0be4336
--- /dev/null
+++ b/testsuites/libtests/termios09/termios09.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: termios09
+
+directives:
+
+ - Termios
+
+concepts:
+
+ - Ensure that carriage return characters are ignored if desired (IGNCR).
diff --git a/testsuites/libtests/termios09/termios09.scn b/testsuites/libtests/termios09/termios09.scn
new file mode 100644
index 0000000000..5e0d17d757
--- /dev/null
+++ b/testsuites/libtests/termios09/termios09.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST TERMIOS 9 ***
+*** END OF TEST TERMIOS 9 ***