Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:35

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2017 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <sys/stat.h>
0033 #include <fcntl.h>
0034 #include <string.h>
0035 #include <termios.h>
0036 #include <unistd.h>
0037 
0038 #include <rtems/termiostypes.h>
0039 
0040 #include "tmacros.h"
0041 
0042 const char rtems_test_name[] = "TERMIOS 9";
0043 
0044 #define INTERRUPT 0
0045 
0046 #define POLLED 1
0047 
0048 #define DEVICE_COUNT 2
0049 
0050 #define OUTPUT_BUFFER_SIZE 64
0051 
0052 #define INPUT_BUFFER_SIZE 64
0053 
0054 static const char * const paths[DEVICE_COUNT] = {
0055   "/interrupt",
0056   "/polled"
0057 };
0058 
0059 typedef struct {
0060   rtems_termios_device_context base;
0061   rtems_termios_tty *tty;
0062   size_t output_pending;
0063   size_t output_count;
0064   char output_buf[OUTPUT_BUFFER_SIZE];
0065   size_t input_head;
0066   size_t input_tail;
0067   unsigned char input_buf[INPUT_BUFFER_SIZE];
0068   int callback_counter;
0069 } device_context;
0070 
0071 typedef struct {
0072   device_context devices[DEVICE_COUNT];
0073   int fds[DEVICE_COUNT];
0074   struct termios term[DEVICE_COUNT];
0075   int context_switch_counter;
0076   rtems_id flush_task_id;
0077 } test_context;
0078 
0079 static test_context test_instance = {
0080   .devices = {
0081     {
0082       .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Interrupt")
0083     }, {
0084       .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled")
0085     }
0086   }
0087 };
0088 
0089 static bool first_open(
0090   rtems_termios_tty *tty,
0091   rtems_termios_device_context *base,
0092   struct termios *term,
0093   rtems_libio_open_close_args_t *args
0094 )
0095 {
0096   device_context *dev = (device_context *) base;
0097 
0098   dev->tty = tty;
0099 
0100   return true;
0101 }
0102 
0103 static void write_polled(
0104   rtems_termios_device_context *base,
0105   const char *buf,
0106   size_t len
0107 )
0108 {
0109   device_context *dev = (device_context *) base;
0110 
0111   rtems_test_assert(dev->output_count + len <= OUTPUT_BUFFER_SIZE);
0112   memcpy(&dev->output_buf[dev->output_count], buf, len);
0113   dev->output_count += len;
0114 }
0115 
0116 static void write_interrupt(
0117   rtems_termios_device_context *base,
0118   const char *buf,
0119   size_t len
0120 )
0121 {
0122   device_context *dev = (device_context *) base;
0123 
0124   write_polled(base, buf, len);
0125   dev->output_pending = len;
0126 }
0127 
0128 static int read_polled(rtems_termios_device_context *base)
0129 {
0130   device_context *dev = (device_context *) base;
0131   int c;
0132 
0133   if (dev->input_head != dev->input_tail) {
0134     c = dev->input_buf[dev->input_head];
0135     dev->input_head = (dev->input_head + 1) % INPUT_BUFFER_SIZE;
0136   } else {
0137     c = -1;
0138   }
0139 
0140   return c;
0141 }
0142 
0143 static const rtems_termios_device_handler handlers[DEVICE_COUNT] = {
0144   {
0145     .first_open = first_open,
0146     .write = write_interrupt,
0147     .mode = TERMIOS_IRQ_DRIVEN
0148   }, {
0149     .first_open = first_open,
0150     .write = write_polled,
0151     .poll_read = read_polled,
0152     .mode = TERMIOS_POLLED
0153   }
0154 };
0155 
0156 static void set_term(test_context *ctx, size_t i)
0157 {
0158   int rv;
0159 
0160   rv = tcsetattr(ctx->fds[i], TCSANOW, &ctx->term[i]);
0161   rtems_test_assert(rv == 0);
0162 }
0163 
0164 static void init_term(test_context *ctx, size_t i)
0165 {
0166   int rv;
0167 
0168   rv = tcgetattr(ctx->fds[i], &ctx->term[i]);
0169   rtems_test_assert(rv == 0);
0170 
0171   ctx->term[i].c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
0172     | INLCR | IGNCR | ICRNL | IXON);
0173   ctx->term[i].c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT
0174     | ECHOCTL | ECHOKE | ICANON | ISIG | IEXTEN);
0175   ctx->term[i].c_cflag &= ~(CSIZE | PARENB);
0176   ctx->term[i].c_cflag |= CS8;
0177   ctx->term[i].c_oflag &= ~(OPOST | ONLRET | ONLCR | OCRNL | ONLRET
0178     | TABDLY | OLCUC);
0179 
0180   ctx->term[i].c_cc[VMIN] = 0;
0181   ctx->term[i].c_cc[VTIME] = 0;
0182 
0183   set_term(ctx, i);
0184 }
0185 
0186 static void setup(test_context *ctx)
0187 {
0188   rtems_status_code sc;
0189   size_t i;
0190 
0191   rtems_termios_initialize();
0192 
0193   for (i = 0; i < DEVICE_COUNT; ++i) {
0194     sc = rtems_termios_device_install(
0195       paths[i],
0196       &handlers[i],
0197       NULL,
0198       &ctx->devices[i].base
0199     );
0200     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0201 
0202     ctx->fds[i] = open(paths[i], O_RDWR);
0203     rtems_test_assert(ctx->fds[i] >= 0);
0204 
0205     init_term(ctx, i);
0206   }
0207 }
0208 
0209 static void input(test_context *ctx, size_t i, char c)
0210 {
0211   device_context *dev = &ctx->devices[i];
0212 
0213   switch (i) {
0214     case INTERRUPT:
0215       rtems_termios_enqueue_raw_characters(dev->tty, &c, sizeof(c));
0216       break;
0217     case POLLED:
0218       dev->input_buf[dev->input_tail] = (unsigned char) c;
0219       dev->input_tail = (dev->input_tail + 1) % INPUT_BUFFER_SIZE;
0220       rtems_test_assert(dev->input_head != dev->input_tail);
0221       break;
0222     default:
0223       rtems_test_assert(0);
0224   }
0225 }
0226 
0227 static void enable_non_blocking(test_context *ctx, size_t i, bool enable)
0228 {
0229   int flags;
0230   int rv;
0231 
0232   flags = fcntl(ctx->fds[i], F_GETFL, 0);
0233   rtems_test_assert(flags >= 0);
0234 
0235   if (enable) {
0236     flags |= O_NONBLOCK;
0237   } else {
0238     flags &= ~O_NONBLOCK;
0239   }
0240 
0241   rv = fcntl(ctx->fds[i], F_SETFL, flags);
0242   rtems_test_assert(rv == 0);
0243 }
0244 
0245 static void clear_set_iflag(
0246   test_context *ctx,
0247   size_t i,
0248   tcflag_t clear,
0249   tcflag_t set
0250 )
0251 {
0252   ctx->term[i].c_iflag &= ~clear;
0253   ctx->term[i].c_iflag |= set;
0254   set_term(ctx, i);
0255 }
0256 
0257 static void clear_set_lflag(
0258   test_context *ctx,
0259   size_t i,
0260   tcflag_t clear,
0261   tcflag_t set
0262 )
0263 {
0264   ctx->term[i].c_lflag &= ~clear;
0265   ctx->term[i].c_lflag |= set;
0266   set_term(ctx, i);
0267 }
0268 
0269 static void clear_set_oflag(
0270   test_context *ctx,
0271   size_t i,
0272   tcflag_t clear,
0273   tcflag_t set
0274 )
0275 {
0276   ctx->term[i].c_oflag &= ~clear;
0277   ctx->term[i].c_oflag |= set;
0278   set_term(ctx, i);
0279 }
0280 
0281 static void set_vmin_vtime(
0282   test_context *ctx,
0283   size_t i,
0284   cc_t vmin,
0285   cc_t vtime
0286 )
0287 {
0288   ctx->term[i].c_cc[VMIN] = vmin;
0289   ctx->term[i].c_cc[VTIME] = vtime;
0290   set_term(ctx, i);
0291 }
0292 
0293 static void set_veol_veol2(
0294   test_context *ctx,
0295   size_t i,
0296   cc_t veol,
0297   cc_t veol2
0298 )
0299 {
0300   ctx->term[i].c_cc[VEOL] = veol;
0301   ctx->term[i].c_cc[VEOL2] = veol2;
0302   set_term(ctx, i);
0303 }
0304 
0305 static void test_igncr(test_context *ctx)
0306 {
0307   size_t i;
0308 
0309   for (i = 0; i < DEVICE_COUNT; ++i) {
0310     ssize_t n;
0311     char c;
0312 
0313     c = 'x';
0314 
0315     clear_set_iflag(ctx, i, 0, IGNCR);
0316 
0317     n = read(ctx->fds[i], &c, sizeof(c));
0318     rtems_test_assert(n == 0);
0319     rtems_test_assert(c == 'x');
0320 
0321     input(ctx, i, '\r');
0322 
0323     n = read(ctx->fds[i], &c, sizeof(c));
0324     rtems_test_assert(n == 0);
0325     rtems_test_assert(c == 'x');
0326 
0327     clear_set_iflag(ctx, i, IGNCR, 0);
0328     input(ctx, i, '\r');
0329 
0330     n = read(ctx->fds[i], &c, sizeof(c));
0331     rtems_test_assert(n == 1);
0332     rtems_test_assert(c == '\r');
0333   }
0334 }
0335 
0336 static void test_istrip(test_context *ctx)
0337 {
0338   size_t i;
0339 
0340   for (i = 0; i < DEVICE_COUNT; ++i) {
0341     ssize_t n;
0342     char c;
0343 
0344     c = 'x';
0345 
0346     clear_set_iflag(ctx, i, 0, ISTRIP);
0347 
0348     n = read(ctx->fds[i], &c, sizeof(c));
0349     rtems_test_assert(n == 0);
0350     rtems_test_assert(c == 'x');
0351 
0352     input(ctx, i, '\376');
0353 
0354     n = read(ctx->fds[i], &c, sizeof(c));
0355     rtems_test_assert(n == 1);
0356     rtems_test_assert(c == '~');
0357 
0358     clear_set_iflag(ctx, i, ISTRIP, 0);
0359     input(ctx, i, '\376');
0360 
0361     n = read(ctx->fds[i], &c, sizeof(c));
0362     rtems_test_assert(n == 1);
0363     rtems_test_assert(c == '\376');
0364   }
0365 }
0366 
0367 static void test_iuclc(test_context *ctx)
0368 {
0369   size_t i;
0370 
0371   for (i = 0; i < DEVICE_COUNT; ++i) {
0372     ssize_t n;
0373     char c;
0374 
0375     c = 'x';
0376 
0377     clear_set_iflag(ctx, i, 0, IUCLC);
0378 
0379     n = read(ctx->fds[i], &c, sizeof(c));
0380     rtems_test_assert(n == 0);
0381     rtems_test_assert(c == 'x');
0382 
0383     input(ctx, i, 'A');
0384 
0385     n = read(ctx->fds[i], &c, sizeof(c));
0386     rtems_test_assert(n == 1);
0387     rtems_test_assert(c == 'a');
0388 
0389     clear_set_iflag(ctx, i, IUCLC, 0);
0390     input(ctx, i, 'A');
0391 
0392     n = read(ctx->fds[i], &c, sizeof(c));
0393     rtems_test_assert(n == 1);
0394     rtems_test_assert(c == 'A');
0395   }
0396 }
0397 
0398 static void test_icrnl(test_context *ctx)
0399 {
0400   size_t i;
0401 
0402   for (i = 0; i < DEVICE_COUNT; ++i) {
0403     ssize_t n;
0404     char c;
0405 
0406     c = 'x';
0407 
0408     clear_set_iflag(ctx, i, 0, ICRNL);
0409 
0410     n = read(ctx->fds[i], &c, sizeof(c));
0411     rtems_test_assert(n == 0);
0412     rtems_test_assert(c == 'x');
0413 
0414     input(ctx, i, '\r');
0415 
0416     n = read(ctx->fds[i], &c, sizeof(c));
0417     rtems_test_assert(n == 1);
0418     rtems_test_assert(c == '\n');
0419 
0420     clear_set_iflag(ctx, i, ICRNL, 0);
0421     input(ctx, i, '\r');
0422 
0423     n = read(ctx->fds[i], &c, sizeof(c));
0424     rtems_test_assert(n == 1);
0425     rtems_test_assert(c == '\r');
0426   }
0427 }
0428 
0429 static void test_inlcr(test_context *ctx)
0430 {
0431   size_t i;
0432 
0433   for (i = 0; i < DEVICE_COUNT; ++i) {
0434     ssize_t n;
0435     char c;
0436 
0437     c = 'x';
0438 
0439     clear_set_iflag(ctx, i, 0, INLCR);
0440 
0441     n = read(ctx->fds[i], &c, sizeof(c));
0442     rtems_test_assert(n == 0);
0443     rtems_test_assert(c == 'x');
0444 
0445     input(ctx, i, '\n');
0446 
0447     n = read(ctx->fds[i], &c, sizeof(c));
0448     rtems_test_assert(n == 1);
0449     rtems_test_assert(c == '\r');
0450 
0451     clear_set_iflag(ctx, i, INLCR, 0);
0452     input(ctx, i, '\n');
0453 
0454     n = read(ctx->fds[i], &c, sizeof(c));
0455     rtems_test_assert(n == 1);
0456     rtems_test_assert(c == '\n');
0457   }
0458 }
0459 
0460 static void callback(struct termios *tty, void *arg)
0461 {
0462   device_context *ctx = arg;
0463 
0464   ++ctx->callback_counter;
0465 }
0466 
0467 static void test_rx_callback(test_context *ctx)
0468 {
0469   size_t i = INTERRUPT;
0470   device_context *dev = &ctx->devices[i];
0471   ssize_t n;
0472   char buf[3];
0473 
0474   buf[0] = 'x';
0475 
0476   dev->callback_counter = 0;
0477   dev->tty->tty_rcv.sw_pfn = callback;
0478   dev->tty->tty_rcv.sw_arg = dev;
0479   clear_set_lflag(ctx, i, ICANON, 0);
0480 
0481   set_vmin_vtime(ctx, i, 0, 0);
0482 
0483   n = read(ctx->fds[i], buf, 1);
0484   rtems_test_assert(n == 0);
0485   rtems_test_assert(buf[0] == 'x');
0486 
0487   input(ctx, i, 'a');
0488   rtems_test_assert(dev->callback_counter == 1);
0489 
0490   input(ctx, i, 'b');
0491   rtems_test_assert(dev->callback_counter == 1);
0492 
0493   n = read(ctx->fds[i], buf, 2);
0494   rtems_test_assert(n == 2);
0495   rtems_test_assert(buf[0] == 'a');
0496   rtems_test_assert(buf[1] == 'b');
0497 
0498   set_vmin_vtime(ctx, i, 2, 0);
0499 
0500   input(ctx, i, 'd');
0501   rtems_test_assert(dev->callback_counter == 1);
0502 
0503   input(ctx, i, 'e');
0504   rtems_test_assert(dev->callback_counter == 2);
0505 
0506   input(ctx, i, 'f');
0507   rtems_test_assert(dev->callback_counter == 2);
0508 
0509   n = read(ctx->fds[i], buf, 3);
0510   rtems_test_assert(n == 3);
0511   rtems_test_assert(buf[0] == 'd');
0512   rtems_test_assert(buf[1] == 'e');
0513   rtems_test_assert(buf[2] == 'f');
0514 
0515   dev->tty->tty_rcv.sw_pfn = NULL;
0516   dev->tty->tty_rcv.sw_arg = NULL;
0517 }
0518 
0519 static void test_rx_callback_icanon(test_context *ctx)
0520 {
0521   size_t i = INTERRUPT;
0522   device_context *dev = &ctx->devices[i];
0523   ssize_t n;
0524   char buf[255];
0525   size_t j;
0526 
0527   buf[0] = 'x';
0528 
0529   dev->callback_counter = 0;
0530   dev->tty->tty_rcv.sw_pfn = callback;
0531   dev->tty->tty_rcv.sw_arg = dev;
0532 
0533   set_vmin_vtime(ctx, i, 0, 0);
0534 
0535   n = read(ctx->fds[i], buf, 1);
0536   rtems_test_assert(n == 0);
0537   rtems_test_assert(buf[0] == 'x');
0538 
0539   clear_set_lflag(ctx, i, 0, ICANON);
0540   set_veol_veol2(ctx, i, '1', '2');
0541 
0542   input(ctx, i, '\n');
0543   rtems_test_assert(dev->callback_counter == 1);
0544 
0545   input(ctx, i, 'a');
0546   rtems_test_assert(dev->callback_counter == 1);
0547 
0548   input(ctx, i, '\n');
0549   rtems_test_assert(dev->callback_counter == 1);
0550 
0551   n = read(ctx->fds[i], buf, 2);
0552   rtems_test_assert(n == 1);
0553   rtems_test_assert(buf[0] == '\n');
0554   n = read(ctx->fds[i], buf, 3);
0555   rtems_test_assert(n == 2);
0556   rtems_test_assert(buf[0] == 'a');
0557   rtems_test_assert(buf[1] == '\n');
0558 
0559   input(ctx, i, '\4');
0560   rtems_test_assert(dev->callback_counter == 2);
0561 
0562   input(ctx, i, 'b');
0563   rtems_test_assert(dev->callback_counter == 2);
0564 
0565   input(ctx, i, '\n');
0566   rtems_test_assert(dev->callback_counter == 2);
0567 
0568   n = read(ctx->fds[i], buf, 1);
0569   rtems_test_assert(n == 0);
0570 
0571   n = read(ctx->fds[i], buf, 3);
0572   rtems_test_assert(n == 2);
0573   rtems_test_assert(buf[0] == 'b');
0574   rtems_test_assert(buf[1] == '\n');
0575 
0576   /* EOL */
0577   input(ctx, i, '1');
0578   rtems_test_assert(dev->callback_counter == 3);
0579 
0580   input(ctx, i, 'c');
0581   rtems_test_assert(dev->callback_counter == 3);
0582 
0583   input(ctx, i, '\n');
0584   rtems_test_assert(dev->callback_counter == 3);
0585 
0586   n = read(ctx->fds[i], buf, 2);
0587   rtems_test_assert(n == 1);
0588   rtems_test_assert(buf[0] == '1');
0589   n = read(ctx->fds[i], buf, 3);
0590   rtems_test_assert(n == 2);
0591   rtems_test_assert(buf[0] == 'c');
0592   rtems_test_assert(buf[1] == '\n');
0593 
0594   /* EOL2 */
0595   input(ctx, i, '2');
0596   rtems_test_assert(dev->callback_counter == 4);
0597 
0598   input(ctx, i, 'd');
0599   rtems_test_assert(dev->callback_counter == 4);
0600 
0601   input(ctx, i, '\n');
0602   rtems_test_assert(dev->callback_counter == 4);
0603 
0604   n = read(ctx->fds[i], buf, 2);
0605   rtems_test_assert(n == 1);
0606   rtems_test_assert(buf[0] == '2');
0607   n = read(ctx->fds[i], buf, 3);
0608   rtems_test_assert(n == 2);
0609   rtems_test_assert(buf[0] == 'd');
0610   rtems_test_assert(buf[1] == '\n');
0611 
0612   for (j = 0; j < 255; ++j) {
0613     input(ctx, i, 'e');
0614     rtems_test_assert(dev->callback_counter == 4);
0615   }
0616 
0617   /* Raw input buffer overflow */
0618   input(ctx, i, 'e');
0619   rtems_test_assert(dev->callback_counter == 5);
0620 
0621   n = read(ctx->fds[i], buf, 255);
0622   rtems_test_assert(n == 255);
0623 
0624   dev->tty->tty_rcv.sw_pfn = NULL;
0625   dev->tty->tty_rcv.sw_arg = NULL;
0626   set_veol_veol2(ctx, i, '\0', '\0');
0627   clear_set_lflag(ctx, i, ICANON, 0);
0628 }
0629 
0630 static void test_read_icanon(test_context *ctx, size_t i)
0631 {
0632   ssize_t n;
0633   char buf[3];
0634 
0635   clear_set_lflag(ctx, i, 0, ICANON);
0636 
0637   input(ctx, i, 'a');
0638   input(ctx, i, '\n');
0639   input(ctx, i, 'b');
0640   input(ctx, i, '\n');
0641   input(ctx, i, 'c');
0642   input(ctx, i, '\n');
0643 
0644   n = read(ctx->fds[i], buf, 3);
0645   rtems_test_assert(n == 2);
0646   rtems_test_assert(buf[0] == 'a');
0647   rtems_test_assert(buf[1] == '\n');
0648 
0649   n = read(ctx->fds[i], buf, 3);
0650   rtems_test_assert(n == 2);
0651   rtems_test_assert(buf[0] == 'b');
0652   rtems_test_assert(buf[1] == '\n');
0653 
0654   n = read(ctx->fds[i], buf, 3);
0655   rtems_test_assert(n == 2);
0656   rtems_test_assert(buf[0] == 'c');
0657   rtems_test_assert(buf[1] == '\n');
0658 
0659   clear_set_lflag(ctx, i, ICANON, 0);
0660 }
0661 
0662 static void flush_output(test_context *ctx, size_t i)
0663 {
0664   if (i == INTERRUPT) {
0665     device_context *dev = &ctx->devices[i];
0666     int left;
0667 
0668     do {
0669       left = rtems_termios_dequeue_characters(dev->tty, dev->output_pending);
0670     } while (left > 0);
0671   }
0672 }
0673 
0674 static void clear_output(test_context *ctx, size_t i)
0675 {
0676   device_context *dev = &ctx->devices[i];
0677 
0678   flush_output(ctx, i);
0679   dev->output_count = 0;
0680   memset(&dev->output_buf, 0, OUTPUT_BUFFER_SIZE);
0681 }
0682 
0683 static void test_onlret(test_context *ctx)
0684 {
0685   tcflag_t oflags = OPOST | ONLRET;
0686   size_t i;
0687 
0688   for (i = 0; i < DEVICE_COUNT; ++i) {
0689     device_context *dev = &ctx->devices[i];
0690     char c;
0691     ssize_t n;
0692 
0693     dev->tty->column = 0;
0694     clear_output(ctx, i);
0695 
0696     clear_set_oflag(ctx, i, 0, oflags);
0697 
0698     c = 'a';
0699     n = write(ctx->fds[i], &c, sizeof(c));
0700     rtems_test_assert(n == 1);
0701     rtems_test_assert(dev->tty->column == 1);
0702     flush_output(ctx, i);
0703     rtems_test_assert(dev->output_count == 1);
0704     rtems_test_assert(dev->output_buf[0] == 'a');
0705 
0706     c = '\n';
0707     n = write(ctx->fds[i], &c, sizeof(c));
0708     rtems_test_assert(n == 1);
0709     rtems_test_assert(dev->tty->column == 0);
0710     flush_output(ctx, i);
0711     rtems_test_assert(dev->output_count == 2);
0712     rtems_test_assert(dev->output_buf[1] == '\n');
0713 
0714     clear_set_oflag(ctx, i, oflags, 0);
0715   }
0716 }
0717 
0718 static void test_onlcr(test_context *ctx)
0719 {
0720   tcflag_t oflags = OPOST | ONLCR;
0721   size_t i;
0722 
0723   for (i = 0; i < DEVICE_COUNT; ++i) {
0724     device_context *dev = &ctx->devices[i];
0725     char c;
0726     ssize_t n;
0727 
0728     dev->tty->column = 0;
0729     clear_output(ctx, i);
0730 
0731     clear_set_oflag(ctx, i, 0, oflags);
0732 
0733     c = 'a';
0734     n = write(ctx->fds[i], &c, sizeof(c));
0735     rtems_test_assert(n == 1);
0736     rtems_test_assert(dev->tty->column == 1);
0737     flush_output(ctx, i);
0738     rtems_test_assert(dev->output_count == 1);
0739     rtems_test_assert(dev->output_buf[0] == 'a');
0740 
0741     c = '\n';
0742     n = write(ctx->fds[i], &c, sizeof(c));
0743     rtems_test_assert(n == 1);
0744     rtems_test_assert(dev->tty->column == 0);
0745     flush_output(ctx, i);
0746     rtems_test_assert(dev->output_count == 3);
0747     rtems_test_assert(dev->output_buf[1] == '\r');
0748     rtems_test_assert(dev->output_buf[2] == '\n');
0749 
0750     clear_set_oflag(ctx, i, oflags, 0);
0751   }
0752 }
0753 
0754 static void test_onocr(test_context *ctx)
0755 {
0756   tcflag_t oflags = OPOST | ONOCR;
0757   size_t i;
0758 
0759   for (i = 0; i < DEVICE_COUNT; ++i) {
0760     device_context *dev = &ctx->devices[i];
0761     char c;
0762     ssize_t n;
0763 
0764     dev->tty->column = 0;
0765     clear_output(ctx, i);
0766 
0767     clear_set_oflag(ctx, i, 0, oflags);
0768 
0769     c = '\r';
0770     n = write(ctx->fds[i], &c, sizeof(c));
0771     rtems_test_assert(n == 1);
0772     rtems_test_assert(dev->tty->column == 0);
0773     flush_output(ctx, i);
0774     rtems_test_assert(dev->output_count == 0);
0775 
0776     c = 'a';
0777     n = write(ctx->fds[i], &c, sizeof(c));
0778     rtems_test_assert(n == 1);
0779     rtems_test_assert(dev->tty->column == 1);
0780     flush_output(ctx, i);
0781     rtems_test_assert(dev->output_count == 1);
0782     rtems_test_assert(dev->output_buf[0] == 'a');
0783 
0784     c = '\r';
0785     n = write(ctx->fds[i], &c, sizeof(c));
0786     rtems_test_assert(n == 1);
0787     rtems_test_assert(dev->tty->column == 0);
0788     flush_output(ctx, i);
0789     rtems_test_assert(dev->output_count == 2);
0790     rtems_test_assert(dev->output_buf[1] == '\r');
0791 
0792     clear_set_oflag(ctx, i, oflags, 0);
0793   }
0794 }
0795 
0796 static void test_ocrnl(test_context *ctx)
0797 {
0798   tcflag_t oflags = OPOST | OCRNL;
0799   size_t i;
0800 
0801   for (i = 0; i < DEVICE_COUNT; ++i) {
0802     device_context *dev = &ctx->devices[i];
0803     char c;
0804     ssize_t n;
0805 
0806     dev->tty->column = 0;
0807     clear_output(ctx, i);
0808 
0809     clear_set_oflag(ctx, i, 0, oflags);
0810 
0811     c = '\r';
0812     n = write(ctx->fds[i], &c, sizeof(c));
0813     rtems_test_assert(n == 1);
0814     rtems_test_assert(dev->tty->column == 0);
0815     flush_output(ctx, i);
0816     rtems_test_assert(dev->output_count == 1);
0817     rtems_test_assert(dev->output_buf[0] == '\n');
0818 
0819     clear_set_oflag(ctx, i, oflags, 0);
0820   }
0821 }
0822 
0823 static void test_ocrnl_onlret(test_context *ctx)
0824 {
0825   tcflag_t oflags = OPOST | OCRNL | ONLRET;
0826   size_t i;
0827 
0828   for (i = 0; i < DEVICE_COUNT; ++i) {
0829     device_context *dev = &ctx->devices[i];
0830     char c;
0831     ssize_t n;
0832 
0833     dev->tty->column = 0;
0834     clear_output(ctx, i);
0835 
0836     clear_set_oflag(ctx, i, 0, oflags);
0837 
0838     c = 'a';
0839     n = write(ctx->fds[i], &c, sizeof(c));
0840     rtems_test_assert(n == 1);
0841     rtems_test_assert(dev->tty->column == 1);
0842     flush_output(ctx, i);
0843     rtems_test_assert(dev->output_count == 1);
0844     rtems_test_assert(dev->output_buf[0] == 'a');
0845 
0846     c = '\r';
0847     n = write(ctx->fds[i], &c, sizeof(c));
0848     rtems_test_assert(n == 1);
0849     rtems_test_assert(dev->tty->column == 0);
0850     flush_output(ctx, i);
0851     rtems_test_assert(dev->output_count == 2);
0852     rtems_test_assert(dev->output_buf[1] == '\n');
0853 
0854     clear_set_oflag(ctx, i, oflags, 0);
0855   }
0856 }
0857 
0858 static void test_opost(test_context *ctx)
0859 {
0860   tcflag_t oflags = OPOST;
0861   size_t i;
0862 
0863   for (i = 0; i < DEVICE_COUNT; ++i) {
0864     device_context *dev = &ctx->devices[i];
0865     char c;
0866     ssize_t n;
0867 
0868     dev->tty->column = 0;
0869     clear_output(ctx, i);
0870 
0871     clear_set_oflag(ctx, i, 0, oflags);
0872 
0873     c = 'a';
0874     n = write(ctx->fds[i], &c, sizeof(c));
0875     rtems_test_assert(n == 1);
0876     rtems_test_assert(dev->tty->column == 1);
0877     flush_output(ctx, i);
0878     rtems_test_assert(dev->output_count == 1);
0879     rtems_test_assert(dev->output_buf[0] == 'a');
0880 
0881     c = '\33';
0882     n = write(ctx->fds[i], &c, sizeof(c));
0883     rtems_test_assert(n == 1);
0884     rtems_test_assert(dev->tty->column == 1);
0885     flush_output(ctx, i);
0886     rtems_test_assert(dev->output_count == 2);
0887     rtems_test_assert(dev->output_buf[1] == '\33');
0888 
0889     c = '\t';
0890     n = write(ctx->fds[i], &c, sizeof(c));
0891     rtems_test_assert(n == 1);
0892     rtems_test_assert(dev->tty->column == 8);
0893     flush_output(ctx, i);
0894     rtems_test_assert(dev->output_count == 3);
0895     rtems_test_assert(dev->output_buf[2] == '\t');
0896 
0897     c = '\b';
0898     n = write(ctx->fds[i], &c, sizeof(c));
0899     rtems_test_assert(n == 1);
0900     rtems_test_assert(dev->tty->column == 7);
0901     flush_output(ctx, i);
0902     rtems_test_assert(dev->output_count == 4);
0903     rtems_test_assert(dev->output_buf[3] == '\b');
0904 
0905     c = '\r';
0906     n = write(ctx->fds[i], &c, sizeof(c));
0907     rtems_test_assert(n == 1);
0908     rtems_test_assert(dev->tty->column == 0);
0909     flush_output(ctx, i);
0910     rtems_test_assert(dev->output_count == 5);
0911     rtems_test_assert(dev->output_buf[4] == '\r');
0912 
0913     clear_set_oflag(ctx, i, oflags, 0);
0914   }
0915 }
0916 
0917 static void test_xtabs(test_context *ctx)
0918 {
0919   tcflag_t oflags = OPOST | OXTABS;
0920   size_t i;
0921 
0922   for (i = 0; i < DEVICE_COUNT; ++i) {
0923     device_context *dev = &ctx->devices[i];
0924     char c;
0925     ssize_t n;
0926 
0927     dev->tty->column = 0;
0928     clear_output(ctx, i);
0929 
0930     clear_set_oflag(ctx, i, 0, oflags);
0931 
0932     c = 'a';
0933     n = write(ctx->fds[i], &c, sizeof(c));
0934     rtems_test_assert(n == 1);
0935     rtems_test_assert(dev->tty->column == 1);
0936     flush_output(ctx, i);
0937     rtems_test_assert(dev->output_count == 1);
0938     rtems_test_assert(dev->output_buf[0] == 'a');
0939 
0940     c = '\t';
0941     n = write(ctx->fds[i], &c, sizeof(c));
0942     rtems_test_assert(n == 1);
0943     rtems_test_assert(dev->tty->column == 8);
0944     flush_output(ctx, i);
0945     rtems_test_assert(dev->output_count == 8);
0946     rtems_test_assert(dev->output_buf[1] == ' ');
0947     rtems_test_assert(dev->output_buf[2] == ' ');
0948     rtems_test_assert(dev->output_buf[3] == ' ');
0949     rtems_test_assert(dev->output_buf[4] == ' ');
0950     rtems_test_assert(dev->output_buf[5] == ' ');
0951     rtems_test_assert(dev->output_buf[6] == ' ');
0952     rtems_test_assert(dev->output_buf[7] == ' ');
0953 
0954     clear_set_oflag(ctx, i, oflags, 0);
0955   }
0956 }
0957 
0958 static void test_olcuc(test_context *ctx)
0959 {
0960   tcflag_t oflags = OPOST | OLCUC;
0961   size_t i;
0962 
0963   for (i = 0; i < DEVICE_COUNT; ++i) {
0964     device_context *dev = &ctx->devices[i];
0965     char c;
0966     ssize_t n;
0967 
0968     dev->tty->column = 0;
0969     clear_output(ctx, i);
0970 
0971     clear_set_oflag(ctx, i, 0, oflags);
0972 
0973     c = 'a';
0974     n = write(ctx->fds[i], &c, sizeof(c));
0975     rtems_test_assert(n == 1);
0976     rtems_test_assert(dev->tty->column == 1);
0977     flush_output(ctx, i);
0978     rtems_test_assert(dev->output_count == 1);
0979     rtems_test_assert(dev->output_buf[0] == 'A');
0980 
0981     c = 'B';
0982     n = write(ctx->fds[i], &c, sizeof(c));
0983     rtems_test_assert(n == 1);
0984     rtems_test_assert(dev->tty->column == 2);
0985     flush_output(ctx, i);
0986     rtems_test_assert(dev->output_count == 2);
0987     rtems_test_assert(dev->output_buf[1] == 'B');
0988 
0989     c = '9';
0990     n = write(ctx->fds[i], &c, sizeof(c));
0991     rtems_test_assert(n == 1);
0992     rtems_test_assert(dev->tty->column == 3);
0993     flush_output(ctx, i);
0994     rtems_test_assert(dev->output_count == 3);
0995     rtems_test_assert(dev->output_buf[2] == '9');
0996 
0997     clear_set_oflag(ctx, i, oflags, 0);
0998   }
0999 }
1000 
1001 static void
1002 set_self_prio(rtems_task_priority prio)
1003 {
1004   rtems_status_code sc;
1005 
1006   sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
1007   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1008 }
1009 
1010 static void flush_task(rtems_task_argument arg)
1011 {
1012   test_context *ctx = (test_context *) arg;
1013 
1014   while (true) {
1015     set_self_prio(1);
1016     flush_output(ctx, INTERRUPT);
1017     set_self_prio(2);
1018   }
1019 }
1020 
1021 static void test_write(test_context *ctx)
1022 {
1023   tcflag_t oflags = OPOST | ONLCR | OXTABS;
1024   rtems_status_code sc;
1025   size_t i = INTERRUPT;
1026   device_context *dev = &ctx->devices[i];
1027   char buf[OUTPUT_BUFFER_SIZE];
1028   ssize_t n;
1029 
1030   ctx->context_switch_counter = 0;
1031 
1032   sc = rtems_task_create(
1033     rtems_build_name('F', 'L', 'S', 'H'),
1034     2,
1035     RTEMS_MINIMUM_STACK_SIZE,
1036     RTEMS_DEFAULT_MODES,
1037     RTEMS_DEFAULT_ATTRIBUTES,
1038     &ctx->flush_task_id
1039   );
1040   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1041 
1042   sc = rtems_task_start(
1043     ctx->flush_task_id,
1044     flush_task,
1045     (rtems_task_argument) ctx
1046   );
1047   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1048 
1049   clear_output(ctx, i);
1050   memset(buf, 'a', OUTPUT_BUFFER_SIZE);
1051 
1052   n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE);
1053   rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 1);
1054 
1055   rtems_test_assert(ctx->context_switch_counter == 0);
1056 
1057   enable_non_blocking(ctx, i, true);
1058   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 1], 1);
1059   rtems_test_assert(n == 0);
1060 
1061   enable_non_blocking(ctx, i, false);
1062   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 1], 1);
1063   rtems_test_assert(n == 1);
1064 
1065   rtems_test_assert(ctx->context_switch_counter == 2);
1066   rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
1067   rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1068 
1069   clear_set_oflag(ctx, i, 0, oflags);
1070 
1071   /* Ensure that ONLCR output expansion is taken into account */
1072 
1073   dev->tty->column = 0;
1074   clear_output(ctx, i);
1075   memset(buf, 'b', OUTPUT_BUFFER_SIZE - 1);
1076   buf[OUTPUT_BUFFER_SIZE - 2] = '\n';
1077 
1078   n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 3);
1079   rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 3);
1080 
1081   rtems_test_assert(ctx->context_switch_counter == 2);
1082 
1083   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 3], 2);
1084   rtems_test_assert(n == 1);
1085 
1086   rtems_test_assert(ctx->context_switch_counter == 2);
1087 
1088   enable_non_blocking(ctx, i, true);
1089   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 2], 1);
1090   rtems_test_assert(n == 0);
1091 
1092   enable_non_blocking(ctx, i, false);
1093   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 2], 1);
1094   rtems_test_assert(n == 1);
1095 
1096   rtems_test_assert(ctx->context_switch_counter == 4);
1097   rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
1098   buf[OUTPUT_BUFFER_SIZE - 2] = '\r';
1099   buf[OUTPUT_BUFFER_SIZE - 1] = '\n';
1100   rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1101 
1102   /* Ensure that OXTABS output expansion is taken into account */
1103 
1104   dev->tty->column = 0;
1105   clear_output(ctx, i);
1106   memset(buf, 'c', OUTPUT_BUFFER_SIZE - 8);
1107   buf[OUTPUT_BUFFER_SIZE - 8] = '\t';
1108 
1109   n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 9);
1110   rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 9);
1111 
1112   rtems_test_assert(ctx->context_switch_counter == 4);
1113 
1114   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 9], 2);
1115   rtems_test_assert(n == 1);
1116 
1117   rtems_test_assert(ctx->context_switch_counter == 4);
1118 
1119   enable_non_blocking(ctx, i, true);
1120   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 8], 1);
1121   rtems_test_assert(n == 0);
1122 
1123   enable_non_blocking(ctx, i, false);
1124   n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 8], 1);
1125   rtems_test_assert(n == 1);
1126 
1127   rtems_test_assert(ctx->context_switch_counter == 6);
1128   rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
1129   memset(&buf[OUTPUT_BUFFER_SIZE - 8], ' ', 8);
1130   rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1131 
1132   clear_set_oflag(ctx, i, oflags, 0);
1133 
1134   sc = rtems_task_delete(ctx->flush_task_id);
1135   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1136 }
1137 
1138 static void test_tx_callback(test_context *ctx)
1139 {
1140   size_t i = INTERRUPT;
1141   device_context *dev = &ctx->devices[i];
1142   char c;
1143   ssize_t n;
1144 
1145   clear_output(ctx, i);
1146   dev->callback_counter = 0;
1147   dev->tty->tty_snd.sw_pfn = callback;
1148   dev->tty->tty_snd.sw_arg = dev;
1149 
1150   c = 'a';
1151   n = write(ctx->fds[i], &c, sizeof(c));
1152   rtems_test_assert(n == 1);
1153   rtems_test_assert(dev->callback_counter == 0);
1154   flush_output(ctx, i);
1155   rtems_test_assert(dev->callback_counter == 1);
1156   rtems_test_assert(dev->output_count == 1);
1157   rtems_test_assert(dev->output_buf[0] == 'a');
1158 
1159   dev->tty->tty_snd.sw_pfn = NULL;
1160   dev->tty->tty_snd.sw_arg = NULL;
1161 }
1162 
1163 static void Init(rtems_task_argument arg)
1164 {
1165   test_context *ctx = &test_instance;
1166 
1167   TEST_BEGIN();
1168 
1169   setup(ctx);
1170   test_igncr(ctx);
1171   test_istrip(ctx);
1172   test_iuclc(ctx);
1173   test_icrnl(ctx);
1174   test_inlcr(ctx);
1175   test_rx_callback(ctx);
1176   test_rx_callback_icanon(ctx);
1177   test_read_icanon(ctx, INTERRUPT);
1178   test_read_icanon(ctx, POLLED);
1179   test_onlret(ctx);
1180   test_onlcr(ctx);
1181   test_onocr(ctx);
1182   test_ocrnl(ctx);
1183   test_ocrnl_onlret(ctx);
1184   test_opost(ctx);
1185   test_xtabs(ctx);
1186   test_olcuc(ctx);
1187   test_write(ctx);
1188   test_tx_callback(ctx);
1189 
1190   TEST_END();
1191   rtems_test_exit(0);
1192 }
1193 
1194 static void switch_extension(Thread_Control *executing, Thread_Control *heir)
1195 {
1196   test_context *ctx = &test_instance;
1197 
1198   ++ctx->context_switch_counter;
1199 }
1200 
1201 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
1202 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
1203 
1204 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
1205 
1206 #define CONFIGURE_MAXIMUM_TASKS 2
1207 
1208 #define CONFIGURE_MAXIMUM_SEMAPHORES 7
1209 
1210 #define CONFIGURE_INITIAL_EXTENSIONS \
1211   { .thread_switch = switch_extension }, \
1212   RTEMS_TEST_INITIAL_EXTENSION
1213 
1214 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
1215 
1216 #define CONFIGURE_INIT
1217 
1218 #include <rtems/confdefs.h>