mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 15:23:22 +00:00
1053 lines
27 KiB
C
1053 lines
27 KiB
C
![]() |
/*++
|
||
|
|
||
|
Copyright (c) Microsoft. All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Template.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file is a ttys test.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "lxtcommon.h"
|
||
|
#include "unittests.h"
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/sysmacros.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <termios.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <poll.h>
|
||
|
|
||
|
#define LXT_NAME "Ttys"
|
||
|
|
||
|
#define LXT_TTYS_LARGE_BUFFER_SIZE (1 * 1024)
|
||
|
#define LXT_TTYS_DEFAULT "/dev/ttyS1"
|
||
|
#define LXT_TTYS_DEFAULT_MINOR (LXT_TTYS_DEV_OFFSET + 1)
|
||
|
#define LXT_TTYS_DEFAULT2 "/dev/ttyS2"
|
||
|
#define LXT_TTYS_DEFAULT2_MINOR (LXT_TTYS_DEV_OFFSET + 2)
|
||
|
#define LXT_TTYS_FORMAT "/dev/ttyS%d"
|
||
|
#define LXT_TTYS_MAX 192
|
||
|
#define LXT_TTYS_DEV_MODE (S_IFCHR | 0660)
|
||
|
#define LXT_TTYS_DEV_MAJOR 4
|
||
|
#define LXT_TTYS_DEV_OFFSET 64
|
||
|
|
||
|
LXT_VARIATION_HANDLER TtysBasicOps;
|
||
|
LXT_VARIATION_HANDLER TtysTermiosBaudParity;
|
||
|
LXT_VARIATION_HANDLER TtysWrite;
|
||
|
LXT_VARIATION_HANDLER TtysWindowSize;
|
||
|
LXT_VARIATION_HANDLER TtysTermiosFlowControl;
|
||
|
LXT_VARIATION_HANDLER TtysWriteRead;
|
||
|
LXT_VARIATION_HANDLER TtysModemIoctls;
|
||
|
|
||
|
//
|
||
|
// Global constants
|
||
|
//
|
||
|
// TtysWriteRead requires two connected serial ports for testing.
|
||
|
//
|
||
|
|
||
|
static const LXT_VARIATION g_LxtVariations[] = {
|
||
|
{"Ttys basic operations", TtysBasicOps},
|
||
|
{"Ttys termios - baud rate and parity", TtysTermiosBaudParity},
|
||
|
{"Ttys write", TtysWrite},
|
||
|
{"Ttys window size", TtysWindowSize},
|
||
|
/* {"Ttys write read", TtysWriteRead}, */
|
||
|
{"Ttys termios - flow control", TtysTermiosFlowControl},
|
||
|
{"Ttys modem ioctls", TtysModemIoctls}};
|
||
|
|
||
|
int TtysTestEntry(int Argc, char* Argv[])
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
LXT_ARGS Args;
|
||
|
int Result;
|
||
|
|
||
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
||
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
||
|
|
||
|
ErrorExit:
|
||
|
LxtUninitialize();
|
||
|
return !LXT_SUCCESS(Result);
|
||
|
}
|
||
|
|
||
|
int TtysBasicOps(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
char Buffer[64];
|
||
|
dev_t Device;
|
||
|
int Fd;
|
||
|
char Path[32];
|
||
|
int Index;
|
||
|
int Result;
|
||
|
|
||
|
for (Index = 0; Index < LXT_TTYS_MAX; ++Index)
|
||
|
{
|
||
|
snprintf(Path, sizeof(Path), LXT_TTYS_FORMAT, Index);
|
||
|
unlink(Path);
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, Index + LXT_TTYS_DEV_OFFSET);
|
||
|
LxtCheckErrno(mknod(Path, LXT_TTYS_DEV_MODE, Device));
|
||
|
Fd = open(Path, O_RDWR | O_NONBLOCK, 0);
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
read(Fd, Buffer, sizeof(Buffer));
|
||
|
write(Fd, Buffer, sizeof(Buffer));
|
||
|
fsync(Fd);
|
||
|
tcflush(Fd, TCIOFLUSH);
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysTermiosBaudParity(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int BaudRate;
|
||
|
int BaudRates[] = {B1200, B9600, B9600};
|
||
|
int Cflag;
|
||
|
dev_t Device;
|
||
|
int Iflag;
|
||
|
int Index;
|
||
|
int Fd;
|
||
|
int Result;
|
||
|
struct termios Termios = {0};
|
||
|
struct termios TermiosNew = {0};
|
||
|
|
||
|
Fd = -1;
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
|
||
|
//
|
||
|
// Check the default termios values.
|
||
|
//
|
||
|
// N.B. Ignore termios fields that may differ.
|
||
|
//
|
||
|
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
if (Fd == -1)
|
||
|
{
|
||
|
if (errno == EIO)
|
||
|
{
|
||
|
LxtLogInfo("Skipping test %d", errno);
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LxtLogError("Unexpected error %d", errno);
|
||
|
}
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
LxtCheckErrno(tcgetattr(Fd, &Termios));
|
||
|
LxtCheckEqual(Termios.c_oflag, 05, "%d");
|
||
|
LxtCheckEqual(Termios.c_lflag, 0105063, "%d");
|
||
|
LxtCheckEqual(Termios.c_line, 0, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[0], 3, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[1], 28, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[2], 127, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[3], 21, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[5], 0, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[6], 1, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[7], 0, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[10], 26, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[11], 0, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[12], 18, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[13], 15, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[14], 23, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[15], 22, "%d");
|
||
|
LxtCheckEqual(Termios.c_cc[16], 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Set and check the baud rate.
|
||
|
//
|
||
|
|
||
|
BaudRate = cfgetispeed(&Termios);
|
||
|
for (Index = 0; Index < LXT_COUNT_OF(BaudRates); ++Index)
|
||
|
{
|
||
|
cfsetspeed(&Termios, BaudRates[Index]);
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset to the original.
|
||
|
//
|
||
|
|
||
|
cfsetspeed(&Termios, BaudRate);
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Set and check the parity enable and type bits
|
||
|
//
|
||
|
// N.B. NT does not support setting input and output parity independently,
|
||
|
// but Linux does.
|
||
|
//
|
||
|
|
||
|
Cflag = Termios.c_cflag;
|
||
|
Iflag = Termios.c_iflag;
|
||
|
|
||
|
//
|
||
|
// No parity, 8 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag &= ~INPCK;
|
||
|
Termios.c_cflag &= ~PARENB;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CMSPAR;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS8;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Even parity, 7 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag &= ~PARODD;
|
||
|
Termios.c_cflag &= ~CMSPAR;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS7;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Odd parity, 7 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag |= PARODD;
|
||
|
Termios.c_cflag &= ~CMSPAR;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS7;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Even parity, 5 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag &= ~PARODD;
|
||
|
Termios.c_cflag &= ~CMSPAR;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS5;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Odd parity, 5 bits, with stop bit
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag |= PARODD;
|
||
|
Termios.c_cflag &= ~CMSPAR;
|
||
|
Termios.c_cflag |= CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS5;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Space parity, 7 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag &= ~PARODD;
|
||
|
Termios.c_cflag |= CMSPAR;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS7;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Mark parity, 7 bits
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= INPCK;
|
||
|
Termios.c_cflag |= PARENB;
|
||
|
Termios.c_cflag |= PARODD;
|
||
|
Termios.c_cflag |= CMSPAR;
|
||
|
Termios.c_cflag &= ~CSTOPB;
|
||
|
Termios.c_cflag &= ~CSIZE;
|
||
|
Termios.c_cflag |= CS7;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Reset to the original
|
||
|
//
|
||
|
|
||
|
Termios.c_cflag = Cflag;
|
||
|
Termios.c_iflag = Iflag;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysWrite(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
char Buffer[64];
|
||
|
int BytesWritten;
|
||
|
dev_t Device;
|
||
|
int Fd;
|
||
|
char Path[32];
|
||
|
struct pollfd PollFd;
|
||
|
int Index;
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Test non-blocking write paths.
|
||
|
//
|
||
|
// N.B. Blocking can hang if there is no reader.
|
||
|
//
|
||
|
|
||
|
Fd = -1;
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
if (Fd == -1)
|
||
|
{
|
||
|
if (errno == EIO)
|
||
|
{
|
||
|
LxtLogInfo("Skipping test %d", errno);
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LxtLogError("Unexpected error %d", errno);
|
||
|
}
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
memset(&PollFd, 0, sizeof(PollFd));
|
||
|
PollFd.fd = Fd;
|
||
|
PollFd.events = POLLIN | POLLOUT | POLLHUP;
|
||
|
LxtCheckErrno(poll(&PollFd, 1, 0));
|
||
|
LxtCheckEqual(PollFd.revents & POLLOUT, POLLOUT, "%d");
|
||
|
|
||
|
errno = 0;
|
||
|
BytesWritten = write(Fd, Buffer, sizeof(Buffer));
|
||
|
if ((BytesWritten != sizeof(Buffer)) && (errno != EAGAIN))
|
||
|
{
|
||
|
LxtLogError("Unexpected BytesWritten %d, %d", BytesWritten, errno);
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysWindowSize(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
dev_t Device;
|
||
|
int Fd;
|
||
|
char Path[32];
|
||
|
int Result;
|
||
|
struct winsize WindowSize;
|
||
|
struct winsize WindowSizeNew;
|
||
|
|
||
|
//
|
||
|
// Test setting and getting the window size of a serial device.
|
||
|
//
|
||
|
|
||
|
Fd = -1;
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
|
||
|
if (Fd == -1)
|
||
|
{
|
||
|
if (errno == EIO)
|
||
|
{
|
||
|
LxtLogInfo("Skipping test %d", errno);
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LxtLogError("Unexpected error %d", errno);
|
||
|
}
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
|
||
|
LxtLogInfo("%d, %d", WindowSize.ws_row, WindowSize.ws_col);
|
||
|
WindowSizeNew = WindowSize;
|
||
|
WindowSizeNew.ws_row += 1;
|
||
|
WindowSizeNew.ws_col += 1;
|
||
|
LxtCheckErrno(ioctl(Fd, TIOCSWINSZ, &WindowSizeNew));
|
||
|
LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
|
||
|
LxtCheckMemoryEqual(&WindowSize, &WindowSizeNew, sizeof(WindowSize));
|
||
|
memset(&WindowSizeNew, 0, sizeof(WindowSizeNew));
|
||
|
LxtCheckErrno(ioctl(Fd, TIOCSWINSZ, &WindowSizeNew));
|
||
|
LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
|
||
|
LxtCheckMemoryEqual(&WindowSize, &WindowSizeNew, sizeof(WindowSize));
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysTermiosFlowControl(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int Cflag;
|
||
|
dev_t Device;
|
||
|
int Iflag;
|
||
|
int Index;
|
||
|
int Fd;
|
||
|
int Result;
|
||
|
struct termios Termios = {0};
|
||
|
struct termios TermiosNew = {0};
|
||
|
char VStart;
|
||
|
char VStop;
|
||
|
|
||
|
Fd = -1;
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
|
||
|
//
|
||
|
// Check the default termios values.
|
||
|
//
|
||
|
// N.B. Ignore the termios settings that may differ..
|
||
|
//
|
||
|
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
if (Fd == -1)
|
||
|
{
|
||
|
if (errno == EIO)
|
||
|
{
|
||
|
LxtLogInfo("Skipping test %d", errno);
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LxtLogError("Unexpected error %d", errno);
|
||
|
}
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set and check the parity enable and type bits
|
||
|
//
|
||
|
// N.B. NT does not support setting input and output parity independently,
|
||
|
// but Linux does.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(tcgetattr(Fd, &Termios));
|
||
|
Cflag = Termios.c_cflag;
|
||
|
Iflag = Termios.c_iflag;
|
||
|
VStart = Termios.c_cc[VSTART];
|
||
|
VStop = Termios.c_cc[VSTOP];
|
||
|
|
||
|
//
|
||
|
// ixon and ixoff set
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag |= IXON;
|
||
|
Termios.c_iflag |= IXOFF;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// ixon and ixoff not set
|
||
|
//
|
||
|
|
||
|
Termios.c_iflag &= ~IXON;
|
||
|
Termios.c_iflag &= ~IXOFF;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// crtscts set
|
||
|
//
|
||
|
|
||
|
Termios.c_cflag |= CRTSCTS;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// crtscts not set
|
||
|
//
|
||
|
|
||
|
Termios.c_cflag &= ~CRTSCTS;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// clocal not set
|
||
|
//
|
||
|
|
||
|
LxtLogInfo("Clearing clocal");
|
||
|
Termios.c_cflag &= ~CLOCAL;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// clocal set
|
||
|
//
|
||
|
|
||
|
Termios.c_cflag |= CLOCAL;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Flip vstart and vstop
|
||
|
//
|
||
|
|
||
|
LxtLogInfo("Updating vstart and vstop");
|
||
|
Termios.c_cc[VSTART] = VStop;
|
||
|
Termios.c_cc[VSTOP] = VStart;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
//
|
||
|
// Reset to the original
|
||
|
//
|
||
|
|
||
|
LxtLogInfo("Resetting...");
|
||
|
Termios.c_cflag = Cflag;
|
||
|
Termios.c_iflag = Iflag;
|
||
|
Termios.c_cc[VSTART] = VStart;
|
||
|
Termios.c_cc[VSTOP] = VStop;
|
||
|
LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
|
||
|
LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysWriteReadTransfer(PLXT_ARGS Args, int FdRead, int FdWrite)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int BytesRead;
|
||
|
int BytesWritten;
|
||
|
int BytesTotal;
|
||
|
pid_t ChildPid;
|
||
|
int Index;
|
||
|
char* RecvBuffer;
|
||
|
int Result;
|
||
|
char* SendBuffer;
|
||
|
|
||
|
ChildPid = -1;
|
||
|
RecvBuffer = NULL;
|
||
|
SendBuffer = NULL;
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer with known data to transfer and a buffer to recieve
|
||
|
// the data.
|
||
|
//
|
||
|
|
||
|
SendBuffer = LxtAlloc(LXT_TTYS_LARGE_BUFFER_SIZE);
|
||
|
if (SendBuffer == NULL)
|
||
|
{
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
for (Index = 0; Index < LXT_TTYS_LARGE_BUFFER_SIZE; ++Index)
|
||
|
{
|
||
|
SendBuffer[Index] = (char)Index;
|
||
|
}
|
||
|
|
||
|
RecvBuffer = LxtAlloc(LXT_TTYS_LARGE_BUFFER_SIZE);
|
||
|
if (RecvBuffer == NULL)
|
||
|
{
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
memset(RecvBuffer, 0, LXT_TTYS_LARGE_BUFFER_SIZE);
|
||
|
|
||
|
//
|
||
|
// Send and recv the data.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(ChildPid = fork());
|
||
|
if (ChildPid == 0)
|
||
|
{
|
||
|
for (BytesTotal = 0; BytesTotal < LXT_TTYS_LARGE_BUFFER_SIZE; BytesTotal += BytesWritten)
|
||
|
{
|
||
|
BytesWritten = write(FdWrite, &SendBuffer[BytesTotal], LXT_TTYS_LARGE_BUFFER_SIZE - BytesTotal);
|
||
|
|
||
|
if (BytesWritten == -1)
|
||
|
{
|
||
|
if ((errno == EAGAIN) || (errno == EINTR))
|
||
|
{
|
||
|
BytesWritten = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
LxtLogError("Write failed with %d", errno);
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_exit(0);
|
||
|
}
|
||
|
|
||
|
for (BytesTotal = 0; BytesTotal < LXT_TTYS_LARGE_BUFFER_SIZE; BytesTotal += BytesRead)
|
||
|
{
|
||
|
BytesRead = read(FdRead, &RecvBuffer[BytesTotal], LXT_TTYS_LARGE_BUFFER_SIZE - BytesTotal);
|
||
|
|
||
|
if (BytesRead == -1)
|
||
|
{
|
||
|
if ((errno == EAGAIN) || (errno == EINTR))
|
||
|
{
|
||
|
BytesRead = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
LxtLogError("Read failed with %d", errno);
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtWaitPidPoll(ChildPid, 0);
|
||
|
for (Index = 0; Index < LXT_TTYS_LARGE_BUFFER_SIZE; ++Index)
|
||
|
{
|
||
|
if (RecvBuffer[Index] != (char)Index)
|
||
|
{
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
LxtLogError("Mismatch at index %d: %d != %d", Index, (int)(RecvBuffer[Index]), (int)((char)Index));
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (ChildPid == 0)
|
||
|
{
|
||
|
_exit(Result);
|
||
|
}
|
||
|
|
||
|
if (RecvBuffer != NULL)
|
||
|
{
|
||
|
LxtFree(RecvBuffer);
|
||
|
}
|
||
|
|
||
|
if (SendBuffer != NULL)
|
||
|
{
|
||
|
LxtFree(SendBuffer);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysWriteReadTermios(PLXT_ARGS Args, int FdRead, int FdWrite)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct termios FdReadTermios;
|
||
|
int Fds[2];
|
||
|
struct termios FdWriteTermios;
|
||
|
int Index;
|
||
|
struct termios Termios;
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Set the termios structure for transferring raw data.
|
||
|
//
|
||
|
|
||
|
Fds[0] = FdRead;
|
||
|
Fds[1] = FdWrite;
|
||
|
for (Index = 0; Index < LXT_COUNT_OF(Fds); ++Index)
|
||
|
{
|
||
|
LxtCheckErrno(tcgetattr(Fds[Index], &Termios));
|
||
|
Termios.c_iflag = 0;
|
||
|
Termios.c_oflag = 0;
|
||
|
Termios.c_cflag = B115200 | CREAD | CS8;
|
||
|
Termios.c_lflag = 0;
|
||
|
LxtCheckErrno(tcsetattr(Fds[Index], TCSANOW, &Termios));
|
||
|
}
|
||
|
|
||
|
memset(&FdReadTermios, 0, sizeof(FdReadTermios));
|
||
|
LxtCheckErrno(tcgetattr(FdRead, &FdReadTermios));
|
||
|
memset(&FdWriteTermios, 0, sizeof(FdWriteTermios));
|
||
|
LxtCheckErrno(tcgetattr(FdWrite, &FdWriteTermios));
|
||
|
LxtCheckMemoryEqual(&FdReadTermios, &FdWriteTermios, sizeof(FdWriteTermios));
|
||
|
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysWriteRead(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int BytesWritten;
|
||
|
dev_t Device;
|
||
|
int FdRead;
|
||
|
int FdWrite;
|
||
|
char Path[32];
|
||
|
int Result;
|
||
|
|
||
|
FdRead = -1;
|
||
|
FdWrite = -1;
|
||
|
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
LxtCheckErrno(FdRead = open(LXT_TTYS_DEFAULT, O_RDWR, 0));
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT2_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT2, LXT_TTYS_DEV_MODE, Device);
|
||
|
LxtCheckErrno(FdWrite = open(LXT_TTYS_DEFAULT2, O_RDWR, 0));
|
||
|
LxtCheckResult(TtysWriteReadTermios(Args, FdRead, FdWrite));
|
||
|
|
||
|
//
|
||
|
// Transfer data with blocking IO
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(TtysWriteReadTransfer(Args, FdRead, FdWrite));
|
||
|
|
||
|
//
|
||
|
// Transfer again with non-blocking IO.
|
||
|
//
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (FdRead != -1)
|
||
|
{
|
||
|
LxtClose(FdRead);
|
||
|
}
|
||
|
|
||
|
if (FdWrite != -1)
|
||
|
{
|
||
|
LxtClose(FdWrite);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int TtysModemIoctls(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
dev_t Device;
|
||
|
int Fd;
|
||
|
int ModemSettings;
|
||
|
int ModemSettingsOrig;
|
||
|
int Result;
|
||
|
struct termios Termios;
|
||
|
struct termios TermiosOrig;
|
||
|
|
||
|
Fd = -1;
|
||
|
ModemSettingsOrig = -1;
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
|
||
|
//
|
||
|
// Check the default modem settings
|
||
|
//
|
||
|
|
||
|
Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
|
||
|
mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
|
||
|
Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
|
||
|
if (Fd == -1)
|
||
|
{
|
||
|
if (errno == EIO)
|
||
|
{
|
||
|
LxtLogInfo("Skipping test %d", errno);
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LxtLogError("Unexpected error %d", errno);
|
||
|
}
|
||
|
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettingsOrig));
|
||
|
LxtLogInfo("ModemSettingsOrig: %d", ModemSettingsOrig);
|
||
|
ModemSettings = ModemSettingsOrig;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckEqual(ModemSettings, ModemSettingsOrig, "%d");
|
||
|
|
||
|
//
|
||
|
// Check that invalid settings are ignored
|
||
|
//
|
||
|
|
||
|
ModemSettings = -1;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
|
||
|
ModemSettings = -1;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMBIC, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckEqual(ModemSettings, 0, "%d");
|
||
|
ModemSettings = -1;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
|
||
|
|
||
|
//
|
||
|
// Recheck the settings after closing and reopening.
|
||
|
//
|
||
|
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
|
||
|
|
||
|
//
|
||
|
// Check DTR
|
||
|
//
|
||
|
// N.B. Some serial drivers start up with DTR on native Linux.
|
||
|
//
|
||
|
|
||
|
ModemSettings = ModemSettingsOrig & ~TIOCM_DTR;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckEqual(ModemSettings, ModemSettingsOrig & ~TIOCM_DTR, "%d");
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
|
||
|
|
||
|
ModemSettings = TIOCM_DTR;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckEqual(ModemSettings, ModemSettingsOrig | TIOCM_DTR, "%d");
|
||
|
LxtClose(Fd);
|
||
|
Fd = -1;
|
||
|
LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
|
||
|
LxtCheckEqual(ModemSettings, ModemSettingsOrig | TIOCM_DTR, "%d");
|
||
|
|
||
|
//
|
||
|
// Check that changing RTS doesn't impact termios
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(tcgetattr(Fd, &TermiosOrig));
|
||
|
ModemSettings = TIOCM_RTS;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &Termios));
|
||
|
LxtCheckMemoryEqual(&TermiosOrig, &Termios, sizeof(Termios));
|
||
|
ModemSettings = TIOCM_RTS;
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMBIC, &ModemSettings));
|
||
|
LxtCheckErrno(tcgetattr(Fd, &Termios));
|
||
|
LxtCheckMemoryEqual(&TermiosOrig, &Termios, sizeof(Termios));
|
||
|
|
||
|
Result = LXT_RESULT_SUCCESS;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Fd != -1)
|
||
|
{
|
||
|
if (ModemSettingsOrig != -1)
|
||
|
{
|
||
|
LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettingsOrig));
|
||
|
}
|
||
|
|
||
|
LxtClose(Fd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|