<div dir="ltr">Hi Cyril:<div>Thank you porting the serialcheck.c into LTP</div><div>I am sorry to find the serialcheck have not LOOPBACK mode support</div><div>the LOOPBACK mode is a better test than HW flow , because most machine's uart have not connect the Rx & TX</div><div>in LOOPBACK mode. we test the uart port directly, So we can test one uart port Rx and Tx functions at the same time .</div><div>here is the diff  serialcheck with loopback patch</div><div>So I'd prefer use loopback mode test the uart in case.</div><div><h3 class="gmail-iw" style="overflow:hidden;white-space:nowrap;font-size:0.75rem;font-weight:inherit;margin:inherit;text-overflow:ellipsis;font-family:Roboto,RobotoDraft,Helvetica,Arial,sans-serif;letter-spacing:0.3px;color:rgb(95,99,104);line-height:20px">$ diff serialcheck.c serialcheck-with-loopback.c<br>14a15,16<br>> #define TIOCM_LOOP    0x8000<br>><br>42a45<br>>     unsigned char loopback;<br>53a57<br>>     {"loopback",    'k', NULL,   0, "loopback mode", 0},<br>69a74<br>>         go->loopback = 0;<br>115a121,123<br>>     case 'k':<br>>         go->loopback = 1;<br>>         break;<br>316c324<br><         ret = poll(&pfd, 1, 10 * 1000);<br>---<br>>         ret = poll(&pfd, 1, 100 * 1000);<br>421a430<br>>     unsigned int mcr;<br>489a499,511<br>>     if (opts.loopback) {<br>>         ret = ioctl(fd, TIOCMGET, &mcr);<br>>         if (ret < 0)<br>>             die("mcr get failed: %m\n");<br>><br>>         mcr |= TIOCM_LOOP;<br>><br>>         ret = ioctl(fd, TIOCMSET, &mcr);<br>>         if (ret < 0)<br>>             die ("mcr set failed: %m\n");<br>><br>>     }<br>><br>514a537,542<br>>     if(opts.loopback){<br>>         mcr &= ~(TIOCM_LOOP);<br>>         ret = ioctl(fd,TIOCMSET,&mcr);<br>>     }<br>>     if(ret)<br>>         printf("disabling loopback failed:%m\n");<br></h3></div><div>  </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Cyril Hrubis <<a href="mailto:chrubis@suse.cz">chrubis@suse.cz</a>> 于2020年3月27日周五 下午9:47写道:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Signed-off-by: Cyril Hrubis <<a href="mailto:chrubis@suse.cz" target="_blank">chrubis@suse.cz</a>><br>
---<br>
 runtest/kernel_misc                           |   5 +<br>
 .../kernel/device-drivers/uart/.gitignore     |   1 +<br>
 testcases/kernel/device-drivers/uart/Makefile |   4 +<br>
 testcases/kernel/device-drivers/uart/uart01.c | 522 ++++++++++++++++++<br>
 4 files changed, 532 insertions(+)<br>
 create mode 100644 testcases/kernel/device-drivers/uart/.gitignore<br>
 create mode 100644 testcases/kernel/device-drivers/uart/Makefile<br>
 create mode 100644 testcases/kernel/device-drivers/uart/uart01.c<br>
<br>
diff --git a/runtest/kernel_misc b/runtest/kernel_misc<br>
index 7937c7bbf..a7f1d9b56 100644<br>
--- a/runtest/kernel_misc<br>
+++ b/runtest/kernel_misc<br>
@@ -13,3 +13,8 @@ zram01 zram01.sh<br>
 zram02 zram02.sh<br>
 zram03 zram03<br>
 umip_basic_test umip_basic_test<br>
+uart01_9600 uart01 -b 9600<br>
+uart01_19200 uart01 -b 19200<br>
+uart01_38400 uart01 -b 38400<br>
+uart01_57600 uart01 -b 57600<br>
+uart01_115200 uart01 -b 115200<br>
diff --git a/testcases/kernel/device-drivers/uart/.gitignore b/testcases/kernel/device-drivers/uart/.gitignore<br>
new file mode 100644<br>
index 000000000..9333e8db9<br>
--- /dev/null<br>
+++ b/testcases/kernel/device-drivers/uart/.gitignore<br>
@@ -0,0 +1 @@<br>
+uart01<br>
diff --git a/testcases/kernel/device-drivers/uart/Makefile b/testcases/kernel/device-drivers/uart/Makefile<br>
new file mode 100644<br>
index 000000000..1c90e5cd6<br>
--- /dev/null<br>
+++ b/testcases/kernel/device-drivers/uart/Makefile<br>
@@ -0,0 +1,4 @@<br>
+<br>
+top_srcdir     ?= ../../../..<br>
+include $(top_srcdir)/include/mk/<a href="http://testcases.mk" rel="noreferrer" target="_blank">testcases.mk</a><br>
+include $(top_srcdir)/include/mk/<a href="http://generic_leaf_target.mk" rel="noreferrer" target="_blank">generic_leaf_target.mk</a><br>
diff --git a/testcases/kernel/device-drivers/uart/uart01.c b/testcases/kernel/device-drivers/uart/uart01.c<br>
new file mode 100644<br>
index 000000000..4647c55e3<br>
--- /dev/null<br>
+++ b/testcases/kernel/device-drivers/uart/uart01.c<br>
@@ -0,0 +1,522 @@<br>
+// SPDX-License-Identifier: GPL-2.0-only<br>
+<br>
+/*<br>
+   Copyright (c) 2014 Sebastian Andrzej Siewior <<a href="mailto:bigeasy@linutronix.de" target="_blank">bigeasy@linutronix.de</a>><br>
+   Copyright (c) 2020 Cyril Hrubis <<a href="mailto:chrubis@suse.cz" target="_blank">chrubis@suse.cz</a>><br>
+<br>
+ */<br>
+<br>
+#include <stdio.h><br>
+#include <ctype.h><br>
+#include <string.h><br>
+#include <stdlib.h><br>
+#include <sys/stat.h><br>
+#include <fcntl.h><br>
+#include <termios.h><br>
+#include <stdarg.h><br>
+#include <unistd.h><br>
+#include <sys/mman.h><br>
+#include <stdint.h><br>
+#include <poll.h><br>
+#include <sys/ioctl.h><br>
+#include <linux/serial.h><br>
+<br>
+#include "tst_test.h"<br>
+<br>
+static const char hex_asc[] = "0123456789abcdef";<br>
+#define hex_asc_lo(x)  hex_asc[((x) & 0x0f)]<br>
+#define hex_asc_hi(x)  hex_asc[((x) & 0xf0) >> 4]<br>
+<br>
+struct g_opt {<br>
+       char *uart_dev;<br>
+       char *file_trans;<br>
+       int baud_rate;<br>
+       unsigned int loops;<br>
+       unsigned char hwflow;<br>
+       unsigned char do_termios;<br>
+#define MODE_TX_ONLY    (1 << 0)<br>
+#define MODE_RX_ONLY    (1 << 1)<br>
+#define MODE_DUPLEX     (MODE_TX_ONLY | MODE_RX_ONLY)<br>
+       unsigned int mode;<br>
+       unsigned char *cmp_buff;<br>
+};<br>
+<br>
+static int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)<br>
+{<br>
+       int i;<br>
+<br>
+       i = vsnprintf(buf, size, fmt, args);<br>
+<br>
+       if (i < (int)size)<br>
+               return i;<br>
+       if (size != 0)<br>
+               return size - 1;<br>
+       return 0;<br>
+}<br>
+<br>
+static int scnprintf(char *buf, size_t size, const char *fmt, ...)<br>
+{<br>
+       va_list args;<br>
+       int i;<br>
+<br>
+       va_start(args, fmt);<br>
+       i = vscnprintf(buf, size, fmt, args);<br>
+       va_end(args);<br>
+<br>
+       return i;<br>
+}<br>
+<br>
+<br>
+static void hex_dump_to_buffer(const void *buf, int len, int rowsize,<br>
+               int groupsize, char *linebuf, int linebuflen, int ascii)<br>
+{<br>
+       const uint8_t *ptr = buf;<br>
+       uint8_t ch;<br>
+       int j, lx = 0;<br>
+       int ascii_column;<br>
+<br>
+       if (rowsize != 16 && rowsize != 32)<br>
+               rowsize = 16;<br>
+<br>
+       if (!len)<br>
+               goto nil;<br>
+       if (len > rowsize)      /* limit to one line at a time */<br>
+               len = rowsize;<br>
+       if ((len % groupsize) != 0)     /* no mixed size output */<br>
+               groupsize = 1;<br>
+<br>
+       switch (groupsize) {<br>
+       case 8: {<br>
+               const uint64_t *ptr8 = buf;<br>
+               int ngroups = len / groupsize;<br>
+<br>
+               for (j = 0; j < ngroups; j++)<br>
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,<br>
+                                       "%s%16.16llx", j ? " " : "",<br>
+                                       (unsigned long long)*(ptr8 + j));<br>
+               ascii_column = 17 * ngroups + 2;<br>
+               break;<br>
+               }<br>
+<br>
+       case 4: {<br>
+               const uint32_t *ptr4 = buf;<br>
+               int ngroups = len / groupsize;<br>
+<br>
+               for (j = 0; j < ngroups; j++)<br>
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,<br>
+                                       "%s%8.8x", j ? " " : "", *(ptr4 + j));<br>
+               ascii_column = 9 * ngroups + 2;<br>
+               break;<br>
+               }<br>
+<br>
+       case 2: {<br>
+               const uint16_t *ptr2 = buf;<br>
+               int ngroups = len / groupsize;<br>
+<br>
+               for (j = 0; j < ngroups; j++)<br>
+                       lx += scnprintf(linebuf + lx, linebuflen - lx,<br>
+                                       "%s%4.4x", j ? " " : "", *(ptr2 + j));<br>
+               ascii_column = 5 * ngroups + 2;<br>
+               break;<br>
+               }<br>
+<br>
+       default:<br>
+               for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {<br>
+                       ch = ptr[j];<br>
+                       linebuf[lx++] = hex_asc_hi(ch);<br>
+                       linebuf[lx++] = hex_asc_lo(ch);<br>
+                       linebuf[lx++] = ' ';<br>
+                       if (j == 7)<br>
+                               linebuf[lx++] = ' ';<br>
+               }<br>
+               if (j)<br>
+                       lx--;<br>
+<br>
+               ascii_column = 3 * rowsize + 2 + 2;<br>
+               break;<br>
+       }<br>
+       if (!ascii)<br>
+               goto nil;<br>
+<br>
+       while (lx < (linebuflen - 1) && lx < (ascii_column - 1))<br>
+               linebuf[lx++] = ' ';<br>
+       for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) {<br>
+               ch = ptr[j];<br>
+               linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';<br>
+       }<br>
+nil:<br>
+       linebuf[lx++] = '\0';<br>
+}<br>
+<br>
+static void print_hex_dump(const void *buf, int len, int offset)<br>
+{<br>
+       const uint8_t *ptr = buf;<br>
+       int i, linelen, remaining = len;<br>
+       char linebuf[32 * 3 + 2 + 32 + 2 + 1];<br>
+       int rowsize = 16;<br>
+       int groupsize = 1;<br>
+<br>
+       if (rowsize != 16 && rowsize != 32)<br>
+               rowsize = 16;<br>
+<br>
+       for (i = 0; i < len; i += rowsize) {<br>
+               linelen = MIN(remaining, rowsize);<br>
+               remaining -= rowsize;<br>
+<br>
+               hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,<br>
+                               linebuf, sizeof(linebuf), 1);<br>
+<br>
+               printf("%.8x: %s\n", i + offset, linebuf);<br>
+       }<br>
+}<br>
+<br>
+static int stress_test_uart_once(struct g_opt *opts, int fd, unsigned char *data,<br>
+               off_t data_len)<br>
+{<br>
+       unsigned char *cmp_data = opts->cmp_buff;<br>
+       ssize_t size;<br>
+       int wait_rx;<br>
+       int wait_tx;<br>
+       ssize_t progress_rx = 0;<br>
+       ssize_t progress_tx = 0;<br>
+       unsigned int reads = 0;<br>
+       unsigned int writes = 0;<br>
+<br>
+       do {<br>
+               struct pollfd pfd = {<br>
+                       .fd = fd,<br>
+               };<br>
+               int ret;<br>
+<br>
+               if (opts->mode & MODE_RX_ONLY && progress_rx < data_len) {<br>
+                       pfd.events |= POLLIN;<br>
+                       wait_rx = 1;<br>
+               } else {<br>
+                       wait_rx = 0;<br>
+               }<br>
+<br>
+               if (opts->mode & MODE_TX_ONLY && progress_tx < data_len) {<br>
+                       pfd.events |= POLLOUT;<br>
+                       wait_tx = 1;<br>
+               } else {<br>
+                       wait_tx = 0;<br>
+               }<br>
+<br>
+               ret = poll(&pfd, 1, 10 * 1000);<br>
+               if (ret == 0) {<br>
+                       tst_res(TFAIL, "timeout, RX/TX: %zd/%zd\n", progress_rx, progress_tx);<br>
+                       break;<br>
+               }<br>
+               if (ret < 0) {<br>
+                       tst_res(TFAIL | TERRNO, "poll() failed");<br>
+                       return 1;<br>
+               }<br>
+<br>
+               if (pfd.revents & POLLIN) {<br>
+                       size = read(fd, cmp_data + progress_rx, data_len - progress_rx);<br>
+                       if (size < 0) {<br>
+                               tst_res(TFAIL | TERRNO, "read() failed");<br>
+                               return 1;<br>
+                       }<br>
+                       reads++;<br>
+                       progress_rx += size;<br>
+                       if (progress_rx >= data_len)<br>
+                               wait_rx = 0;<br>
+               }<br>
+<br>
+               if (pfd.revents & POLLOUT) {<br>
+<br>
+                       size = write(fd, data + progress_tx, data_len - progress_tx);<br>
+                       if (size < 0) {<br>
+                               tst_res(TFAIL | TERRNO, "write() failed");<br>
+                               return 1;<br>
+                       }<br>
+                       writes++;<br>
+                       progress_tx += size;<br>
+                       if (progress_tx >= data_len)<br>
+                               wait_tx = 0;<br>
+               }<br>
+       } while (wait_rx || wait_tx);<br>
+<br>
+       tst_res(TINFO, "Needed %u reads %u writes ", reads, writes);<br>
+<br>
+       if (opts->mode & MODE_RX_ONLY) {<br>
+               unsigned int i;<br>
+               int found = 0;<br>
+               unsigned int min_pos;<br>
+               unsigned int max_pos;<br>
+<br>
+               if (!memcmp(data, cmp_data, data_len)) {<br>
+                       tst_res(TPASS, "RX passed");<br>
+                       return 0;<br>
+               }<br>
+<br>
+               for (i = 0; i < data_len && !found; i++) {<br>
+                       if (data[i] != cmp_data[i]) {<br>
+                               found = 1;<br>
+                               break;<br>
+                       }<br>
+               }<br>
+<br>
+               if (!found) {<br>
+                       tst_res(TFAIL, "memcmp() didn't match but manual cmp did");<br>
+                       return 1;<br>
+               }<br>
+<br>
+               max_pos = (i & ~0xfULL) + 16 * 3;<br>
+               if (max_pos > data_len)<br>
+                       max_pos = data_len;<br>
+<br>
+               min_pos = i & ~0xfULL;<br>
+               if (min_pos > 16 * 3)<br>
+                       min_pos -= 16 * 3;<br>
+               else<br>
+                       min_pos = 0;<br>
+<br>
+               tst_res(TFAIL, "Oh oh, inconsistency at pos %d (0x%x)", i, i);<br>
+<br>
+               printf("\nOriginal sample:\n");<br>
+               print_hex_dump(data + min_pos, max_pos - min_pos, min_pos);<br>
+<br>
+               printf("\nReceived sample:\n");<br>
+               print_hex_dump(cmp_data + min_pos, max_pos - min_pos, min_pos);<br>
+               return 1;<br>
+       }<br>
+<br>
+       if (opts->mode & MODE_TX_ONLY)<br>
+               tst_res(TPASS, "TX passed");<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int stress_test_uart(struct g_opt *opts, int fd, unsigned char *data, off_t data_len)<br>
+{<br>
+       unsigned int loops = 0;<br>
+       int status;<br>
+<br>
+       opts->cmp_buff = SAFE_MALLOC(data_len);<br>
+       memset(opts->cmp_buff, 0, data_len);<br>
+<br>
+       do {<br>
+               status = stress_test_uart_once(opts, fd, data, data_len);<br>
+               memset(opts->cmp_buff, 0, data_len);<br>
+       } while (++loops < opts->loops && !status);<br>
+<br>
+       free(opts->cmp_buff);<br>
+<br>
+       return status;<br>
+}<br>
+<br>
+static int setup_uart(struct g_opt *opts, int open_mode, struct termios *old_term)<br>
+{<br>
+       struct termios new_term;<br>
+       int fd;<br>
+       int ret;<br>
+<br>
+       tst_res(TINFO, "Setting up %s speed %u hwflow=%u",<br>
+               opts->uart_dev, opts->baud_rate, opts->hwflow);<br>
+<br>
+       fd = SAFE_OPEN(opts->uart_dev, open_mode | O_NONBLOCK);<br>
+<br>
+       ret = tcgetattr(fd, old_term);<br>
+       if (ret < 0)<br>
+               tst_brk(TBROK, "tcgetattr() failed: %m\n");<br>
+<br>
+       new_term = *old_term;<br>
+<br>
+       /* or c_cflag |= BOTHER and c_ospeed for any speed */<br>
+       ret = cfsetspeed(&new_term, opts->baud_rate);<br>
+       if (ret < 0)<br>
+               tst_brk(TBROK, "cfsetspeed(, %u) failed %m\n", opts->baud_rate);<br>
+       cfmakeraw(&new_term);<br>
+       new_term.c_cflag |= CREAD;<br>
+       if (opts->hwflow)<br>
+               new_term.c_cflag |= CRTSCTS;<br>
+       else<br>
+               new_term.c_cflag &= ~CRTSCTS;<br>
+       new_term.c_cc[VMIN] = 64;<br>
+       new_term.c_cc[VTIME] = 8;<br>
+<br>
+       ret = tcsetattr(fd, TCSANOW, &new_term);<br>
+       if (ret < 0)<br>
+               tst_brk(TBROK, "tcsetattr failed: %m\n");<br>
+<br>
+       if (opts->do_termios) {<br>
+               ret = tcflush(fd, TCIFLUSH);<br>
+               if (ret < 0)<br>
+                       tst_brk(TBROK, "tcflush failed: %m\n");<br>
+       }<br>
+<br>
+       ret = fcntl(fd, F_SETFL, 0);<br>
+       if (ret)<br>
+               printf("Failed to remove nonblock mode\n");<br>
+<br>
+       return fd;<br>
+}<br>
+<br>
+static void restore_uart(int fd, struct termios *old_term)<br>
+{<br>
+       int ret = tcsetattr(fd, TCSAFLUSH, old_term);<br>
+       if (ret)<br>
+               printf("tcsetattr() of old ones failed: %m\n");<br>
+}<br>
+<br>
+static void print_counters(const char *prefix,<br>
+                           struct serial_icounter_struct *old,<br>
+                           struct serial_icounter_struct *new)<br>
+{<br>
+#define CNT(x) (new->x - old->x)<br>
+       printf("%scts: %d dsr: %d rng: %d dcd: %d rx: %d tx: %d "<br>
+               "frame %d ovr %d par: %d brk: %d buf_ovrr: %d\n", prefix,<br>
+               CNT(cts), CNT(dsr), CNT(rng), CNT(dcd), CNT(rx),<br>
+               CNT(tx), CNT(frame), CNT(overrun), CNT(parity),<br>
+               CNT(brk), CNT(buf_overrun));<br>
+#undef CNT<br>
+}<br>
+<br>
+static struct g_opt opts = {<br>
+       .baud_rate = 115200,<br>
+       .loops = 1,<br>
+       .do_termios = 1,<br>
+};<br>
+<br>
+static char *uart_rx;<br>
+static char *uart_tx;<br>
+<br>
+unsigned char *data;<br>
+static long data_len;<br>
+<br>
+void run(void)<br>
+{<br>
+       struct serial_icounter_struct old_counters;<br>
+       struct serial_icounter_struct new_counters;<br>
+       int ret, fd_rx, fd_tx;<br>
+       struct termios old_term_rx, old_term_tx;<br>
+<br>
+       struct g_opt opts_in = opts;<br>
+       struct g_opt opts_out = opts;<br>
+<br>
+       opts_in.uart_dev = uart_rx;<br>
+       opts_out.uart_dev = uart_tx;<br>
+<br>
+       opts_in.mode = MODE_RX_ONLY;<br>
+       opts_out.mode = MODE_TX_ONLY;<br>
+<br>
+       fd_rx = setup_uart(&opts_in, O_RDONLY, &old_term_rx);<br>
+<br>
+       if (!strcmp(uart_rx, uart_tx))<br>
+               fd_tx = SAFE_OPEN(uart_tx, O_WRONLY);<br>
+       else<br>
+               fd_tx = setup_uart(&opts_out, O_WRONLY, &old_term_tx);<br>
+<br>
+       if (!SAFE_FORK()) {<br>
+               ioctl(fd_rx, TIOCGICOUNT, &old_counters);<br>
+               stress_test_uart(&opts_in, fd_rx, data, data_len);<br>
+               ret = ioctl(fd_rx, TIOCGICOUNT, &new_counters);<br>
+               if (ret > 0)<br>
+                       print_counters("RX:", &old_counters, &new_counters);<br>
+               exit(0);<br>
+       }<br>
+<br>
+       if (!SAFE_FORK()) {<br>
+               ioctl(fd_tx, TIOCGICOUNT, &old_counters);<br>
+               stress_test_uart(&opts_out, fd_tx, data, data_len);<br>
+               ret = ioctl(fd_tx, TIOCGICOUNT, &new_counters);<br>
+               if (ret > 0)<br>
+                       print_counters("TX:", &old_counters, &new_counters);<br>
+               exit(0);<br>
+       }<br>
+<br>
+       SAFE_WAIT(NULL);<br>
+       SAFE_WAIT(NULL);<br>
+<br>
+       restore_uart(fd_rx, &old_term_rx);<br>
+<br>
+       if (strcmp(uart_rx, uart_tx))<br>
+               restore_uart(fd_tx, &old_term_tx);<br>
+<br>
+       close(fd_rx);<br>
+       close(fd_tx);<br>
+}<br>
+<br>
+static void map_file(const char *fname)<br>
+{<br>
+       struct stat st;<br>
+       int fd;<br>
+<br>
+       fd = SAFE_OPEN(fname, O_RDONLY);<br>
+<br>
+       SAFE_FSTAT(fd, &st);<br>
+<br>
+       data_len = st.st_size;<br>
+<br>
+       data = SAFE_MMAP(NULL, data_len, PROT_READ,<br>
+                        MAP_SHARED | MAP_LOCKED | MAP_POPULATE, fd, 0);<br>
+<br>
+       tst_res(TINFO, "Mapped file '%s' size %li bytes", fname, data_len);<br>
+<br>
+       SAFE_CLOSE(fd);<br>
+}<br>
+<br>
+static void map_buffer(long buf_size)<br>
+{<br>
+       size_t i;<br>
+<br>
+       data_len = buf_size;<br>
+<br>
+       data = SAFE_MMAP(NULL, data_len, PROT_READ | PROT_WRITE,<br>
+                        MAP_ANONYMOUS | MAP_SHARED | MAP_LOCKED, -1, 0);<br>
+<br>
+       long *p = (void*)data;<br>
+<br>
+       srandom(time(NULL));<br>
+<br>
+       for (i = 0; i < data_len / sizeof(long); i++)<br>
+               p[i] = random();<br>
+<br>
+       tst_res(TINFO, "Mapped anynymous memory size %li bytes", data_len);<br>
+}<br>
+<br>
+static char *baud_rate;<br>
+static char *hwflow;<br>
+static char *fname;<br>
+static char *buf_size;<br>
+<br>
+static void setup(void)<br>
+{<br>
+       long size = 1024;<br>
+<br>
+       if (baud_rate)<br>
+               tst_parse_int(baud_rate, &(opts.baud_rate), 0, INT_MAX);<br>
+<br>
+       if (hwflow)<br>
+               opts.hwflow = 1;<br>
+<br>
+       if (fname && buf_size)<br>
+               tst_brk(TBROK, "Only one of -f and -s could be set!");<br>
+<br>
+       if (buf_size)<br>
+               tst_parse_long(buf_size, &size, 0, LONG_MAX);<br>
+<br>
+       uart_rx = getenv("UART_RX");<br>
+       uart_tx = getenv("UART_TX");<br>
+<br>
+       if (fname)<br>
+               map_file(fname);<br>
+       else<br>
+               map_buffer(size);<br>
+}<br>
+<br>
+static struct tst_test test = {<br>
+       .setup = setup,<br>
+       .test_all = run,<br>
+       .options = (struct tst_option[]) {<br>
+               {"b:", &baud_rate, "-b       Baud rate (9600, ...)"},<br>
+               {"w",  &hwflow   , "-w       Enable hwflow (RTS/CTS)"},<br>
+               {"f:",  &fname,    "-f       Binary file for transfers"},<br>
+               {"s:",  &buf_size, "-s       Binary buffer size"},<br>
+               {}<br>
+       },<br>
+       .needs_devices = (const char *const[]) {"UART_RX", "UART_TX", NULL},<br>
+       .forks_child = 1,<br>
+};<br>
-- <br>
2.24.1<br>
<br>
</blockquote></div>