File indexing completed on 2025-05-11 08:24:35
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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
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
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
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
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
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>