master
c 1,052 lines 27.4 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 Template.c
8
9 Abstract:
10
11 This file is a ttys test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/sysmacros.h>
21 #include <fcntl.h>
22 #include <termios.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <poll.h>
26
27 #define LXT_NAME "Ttys"
28
29 #define LXT_TTYS_LARGE_BUFFER_SIZE (1 * 1024)
30 #define LXT_TTYS_DEFAULT "/dev/ttyS1"
31 #define LXT_TTYS_DEFAULT_MINOR (LXT_TTYS_DEV_OFFSET + 1)
32 #define LXT_TTYS_DEFAULT2 "/dev/ttyS2"
33 #define LXT_TTYS_DEFAULT2_MINOR (LXT_TTYS_DEV_OFFSET + 2)
34 #define LXT_TTYS_FORMAT "/dev/ttyS%d"
35 #define LXT_TTYS_MAX 192
36 #define LXT_TTYS_DEV_MODE (S_IFCHR | 0660)
37 #define LXT_TTYS_DEV_MAJOR 4
38 #define LXT_TTYS_DEV_OFFSET 64
39
40 LXT_VARIATION_HANDLER TtysBasicOps;
41 LXT_VARIATION_HANDLER TtysTermiosBaudParity;
42 LXT_VARIATION_HANDLER TtysWrite;
43 LXT_VARIATION_HANDLER TtysWindowSize;
44 LXT_VARIATION_HANDLER TtysTermiosFlowControl;
45 LXT_VARIATION_HANDLER TtysWriteRead;
46 LXT_VARIATION_HANDLER TtysModemIoctls;
47
48 //
49 // Global constants
50 //
51 // TtysWriteRead requires two connected serial ports for testing.
52 //
53
54 static const LXT_VARIATION g_LxtVariations[] = {
55 {"Ttys basic operations", TtysBasicOps},
56 {"Ttys termios - baud rate and parity", TtysTermiosBaudParity},
57 {"Ttys write", TtysWrite},
58 {"Ttys window size", TtysWindowSize},
59 /* {"Ttys write read", TtysWriteRead}, */
60 {"Ttys termios - flow control", TtysTermiosFlowControl},
61 {"Ttys modem ioctls", TtysModemIoctls}};
62
63 int TtysTestEntry(int Argc, char* Argv[])
64
65 /*++
66 --*/
67
68 {
69
70 LXT_ARGS Args;
71 int Result;
72
73 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
74 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
75
76 ErrorExit:
77 LxtUninitialize();
78 return !LXT_SUCCESS(Result);
79 }
80
81 int TtysBasicOps(PLXT_ARGS Args)
82
83 /*++
84 --*/
85
86 {
87
88 char Buffer[64];
89 dev_t Device;
90 int Fd;
91 char Path[32];
92 int Index;
93 int Result;
94
95 for (Index = 0; Index < LXT_TTYS_MAX; ++Index)
96 {
97 snprintf(Path, sizeof(Path), LXT_TTYS_FORMAT, Index);
98 unlink(Path);
99 Device = makedev(LXT_TTYS_DEV_MAJOR, Index + LXT_TTYS_DEV_OFFSET);
100 LxtCheckErrno(mknod(Path, LXT_TTYS_DEV_MODE, Device));
101 Fd = open(Path, O_RDWR | O_NONBLOCK, 0);
102 if (Fd != -1)
103 {
104 read(Fd, Buffer, sizeof(Buffer));
105 write(Fd, Buffer, sizeof(Buffer));
106 fsync(Fd);
107 tcflush(Fd, TCIOFLUSH);
108 LxtClose(Fd);
109 }
110 }
111
112 Result = LXT_RESULT_SUCCESS;
113
114 ErrorExit:
115 return Result;
116 }
117
118 int TtysTermiosBaudParity(PLXT_ARGS Args)
119
120 /*++
121 --*/
122
123 {
124
125 int BaudRate;
126 int BaudRates[] = {B1200, B9600, B9600};
127 int Cflag;
128 dev_t Device;
129 int Iflag;
130 int Index;
131 int Fd;
132 int Result;
133 struct termios Termios = {0};
134 struct termios TermiosNew = {0};
135
136 Fd = -1;
137 Result = LXT_RESULT_FAILURE;
138
139 //
140 // Check the default termios values.
141 //
142 // N.B. Ignore termios fields that may differ.
143 //
144
145 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
146 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
147 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
148 if (Fd == -1)
149 {
150 if (errno == EIO)
151 {
152 LxtLogInfo("Skipping test %d", errno);
153 Result = LXT_RESULT_SUCCESS;
154 }
155 else
156 {
157 LxtLogError("Unexpected error %d", errno);
158 }
159
160 goto ErrorExit;
161 }
162
163 LxtCheckErrno(tcgetattr(Fd, &Termios));
164 LxtCheckEqual(Termios.c_oflag, 05, "%d");
165 LxtCheckEqual(Termios.c_lflag, 0105063, "%d");
166 LxtCheckEqual(Termios.c_line, 0, "%d");
167 LxtCheckEqual(Termios.c_cc[0], 3, "%d");
168 LxtCheckEqual(Termios.c_cc[1], 28, "%d");
169 LxtCheckEqual(Termios.c_cc[2], 127, "%d");
170 LxtCheckEqual(Termios.c_cc[3], 21, "%d");
171 LxtCheckEqual(Termios.c_cc[5], 0, "%d");
172 LxtCheckEqual(Termios.c_cc[6], 1, "%d");
173 LxtCheckEqual(Termios.c_cc[7], 0, "%d");
174 LxtCheckEqual(Termios.c_cc[10], 26, "%d");
175 LxtCheckEqual(Termios.c_cc[11], 0, "%d");
176 LxtCheckEqual(Termios.c_cc[12], 18, "%d");
177 LxtCheckEqual(Termios.c_cc[13], 15, "%d");
178 LxtCheckEqual(Termios.c_cc[14], 23, "%d");
179 LxtCheckEqual(Termios.c_cc[15], 22, "%d");
180 LxtCheckEqual(Termios.c_cc[16], 0, "%d");
181
182 //
183 // Set and check the baud rate.
184 //
185
186 BaudRate = cfgetispeed(&Termios);
187 for (Index = 0; Index < LXT_COUNT_OF(BaudRates); ++Index)
188 {
189 cfsetspeed(&Termios, BaudRates[Index]);
190 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
191 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
192 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
193 LxtClose(Fd);
194 Fd = -1;
195 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
196 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
197 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
198 }
199
200 //
201 // Reset to the original.
202 //
203
204 cfsetspeed(&Termios, BaudRate);
205 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
206 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
207 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
208 LxtClose(Fd);
209 Fd = -1;
210 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
211 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
212 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
213
214 //
215 // Set and check the parity enable and type bits
216 //
217 // N.B. NT does not support setting input and output parity independently,
218 // but Linux does.
219 //
220
221 Cflag = Termios.c_cflag;
222 Iflag = Termios.c_iflag;
223
224 //
225 // No parity, 8 bits
226 //
227
228 Termios.c_iflag &= ~INPCK;
229 Termios.c_cflag &= ~PARENB;
230 Termios.c_cflag &= ~CSTOPB;
231 Termios.c_cflag &= ~CMSPAR;
232 Termios.c_cflag &= ~CSIZE;
233 Termios.c_cflag |= CS8;
234 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
235 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
236 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
237 LxtClose(Fd);
238 Fd = -1;
239 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
240 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
241 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
242
243 //
244 // Even parity, 7 bits
245 //
246
247 Termios.c_iflag |= INPCK;
248 Termios.c_cflag |= PARENB;
249 Termios.c_cflag &= ~PARODD;
250 Termios.c_cflag &= ~CMSPAR;
251 Termios.c_cflag &= ~CSTOPB;
252 Termios.c_cflag &= ~CSIZE;
253 Termios.c_cflag |= CS7;
254 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
255 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
256 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
257 LxtClose(Fd);
258 Fd = -1;
259 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
260 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
261 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
262
263 //
264 // Odd parity, 7 bits
265 //
266
267 Termios.c_iflag |= INPCK;
268 Termios.c_cflag |= PARENB;
269 Termios.c_cflag |= PARODD;
270 Termios.c_cflag &= ~CMSPAR;
271 Termios.c_cflag &= ~CSTOPB;
272 Termios.c_cflag &= ~CSIZE;
273 Termios.c_cflag |= CS7;
274 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
275 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
276 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
277 LxtClose(Fd);
278 Fd = -1;
279 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
280 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
281 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
282
283 //
284 // Even parity, 5 bits
285 //
286
287 Termios.c_iflag |= INPCK;
288 Termios.c_cflag |= PARENB;
289 Termios.c_cflag &= ~PARODD;
290 Termios.c_cflag &= ~CMSPAR;
291 Termios.c_cflag &= ~CSTOPB;
292 Termios.c_cflag &= ~CSIZE;
293 Termios.c_cflag |= CS5;
294 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
295 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
296 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
297 LxtClose(Fd);
298 Fd = -1;
299 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
300 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
301 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
302
303 //
304 // Odd parity, 5 bits, with stop bit
305 //
306
307 Termios.c_iflag |= INPCK;
308 Termios.c_cflag |= PARENB;
309 Termios.c_cflag |= PARODD;
310 Termios.c_cflag &= ~CMSPAR;
311 Termios.c_cflag |= CSTOPB;
312 Termios.c_cflag &= ~CSIZE;
313 Termios.c_cflag |= CS5;
314 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
315 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
316 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
317 LxtClose(Fd);
318 Fd = -1;
319 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
320 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
321 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
322
323 //
324 // Space parity, 7 bits
325 //
326
327 Termios.c_iflag |= INPCK;
328 Termios.c_cflag |= PARENB;
329 Termios.c_cflag &= ~PARODD;
330 Termios.c_cflag |= CMSPAR;
331 Termios.c_cflag &= ~CSTOPB;
332 Termios.c_cflag &= ~CSIZE;
333 Termios.c_cflag |= CS7;
334 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
335 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
336 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
337 LxtClose(Fd);
338 Fd = -1;
339 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
340 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
341 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
342
343 //
344 // Mark parity, 7 bits
345 //
346
347 Termios.c_iflag |= INPCK;
348 Termios.c_cflag |= PARENB;
349 Termios.c_cflag |= PARODD;
350 Termios.c_cflag |= CMSPAR;
351 Termios.c_cflag &= ~CSTOPB;
352 Termios.c_cflag &= ~CSIZE;
353 Termios.c_cflag |= CS7;
354 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
355 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
356 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
357 LxtClose(Fd);
358 Fd = -1;
359 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
360 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
361 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
362
363 //
364 // Reset to the original
365 //
366
367 Termios.c_cflag = Cflag;
368 Termios.c_iflag = Iflag;
369 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
370 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
371 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
372 LxtClose(Fd);
373 Fd = -1;
374 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
375 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
376 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
377
378 Result = LXT_RESULT_SUCCESS;
379
380 ErrorExit:
381 if (Fd != -1)
382 {
383 LxtClose(Fd);
384 }
385
386 return Result;
387 }
388
389 int TtysWrite(PLXT_ARGS Args)
390
391 /*++
392 --*/
393
394 {
395
396 char Buffer[64];
397 int BytesWritten;
398 dev_t Device;
399 int Fd;
400 char Path[32];
401 struct pollfd PollFd;
402 int Index;
403 int Result;
404
405 //
406 // Test non-blocking write paths.
407 //
408 // N.B. Blocking can hang if there is no reader.
409 //
410
411 Fd = -1;
412 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
413 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
414 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
415 if (Fd == -1)
416 {
417 if (errno == EIO)
418 {
419 LxtLogInfo("Skipping test %d", errno);
420 Result = LXT_RESULT_SUCCESS;
421 }
422 else
423 {
424 LxtLogError("Unexpected error %d", errno);
425 }
426
427 goto ErrorExit;
428 }
429
430 memset(&PollFd, 0, sizeof(PollFd));
431 PollFd.fd = Fd;
432 PollFd.events = POLLIN | POLLOUT | POLLHUP;
433 LxtCheckErrno(poll(&PollFd, 1, 0));
434 LxtCheckEqual(PollFd.revents & POLLOUT, POLLOUT, "%d");
435
436 errno = 0;
437 BytesWritten = write(Fd, Buffer, sizeof(Buffer));
438 if ((BytesWritten != sizeof(Buffer)) && (errno != EAGAIN))
439 {
440 LxtLogError("Unexpected BytesWritten %d, %d", BytesWritten, errno);
441 Result = LXT_RESULT_FAILURE;
442 goto ErrorExit;
443 }
444
445 Result = LXT_RESULT_SUCCESS;
446
447 ErrorExit:
448 if (Fd != -1)
449 {
450 LxtClose(Fd);
451 }
452
453 return Result;
454 }
455
456 int TtysWindowSize(PLXT_ARGS Args)
457
458 /*++
459 --*/
460
461 {
462
463 dev_t Device;
464 int Fd;
465 char Path[32];
466 int Result;
467 struct winsize WindowSize;
468 struct winsize WindowSizeNew;
469
470 //
471 // Test setting and getting the window size of a serial device.
472 //
473
474 Fd = -1;
475 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
476 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
477 Fd = open(LXT_TTYS_DEFAULT, O_RDWR, 0);
478 if (Fd == -1)
479 {
480 if (errno == EIO)
481 {
482 LxtLogInfo("Skipping test %d", errno);
483 Result = LXT_RESULT_SUCCESS;
484 }
485 else
486 {
487 LxtLogError("Unexpected error %d", errno);
488 }
489
490 goto ErrorExit;
491 }
492
493 LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
494 LxtLogInfo("%d, %d", WindowSize.ws_row, WindowSize.ws_col);
495 WindowSizeNew = WindowSize;
496 WindowSizeNew.ws_row += 1;
497 WindowSizeNew.ws_col += 1;
498 LxtCheckErrno(ioctl(Fd, TIOCSWINSZ, &WindowSizeNew));
499 LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
500 LxtCheckMemoryEqual(&WindowSize, &WindowSizeNew, sizeof(WindowSize));
501 memset(&WindowSizeNew, 0, sizeof(WindowSizeNew));
502 LxtCheckErrno(ioctl(Fd, TIOCSWINSZ, &WindowSizeNew));
503 LxtCheckErrno(ioctl(Fd, TIOCGWINSZ, &WindowSize));
504 LxtCheckMemoryEqual(&WindowSize, &WindowSizeNew, sizeof(WindowSize));
505
506 Result = LXT_RESULT_SUCCESS;
507
508 ErrorExit:
509 if (Fd != -1)
510 {
511 LxtClose(Fd);
512 }
513
514 return Result;
515 }
516
517 int TtysTermiosFlowControl(PLXT_ARGS Args)
518
519 /*++
520 --*/
521
522 {
523
524 int Cflag;
525 dev_t Device;
526 int Iflag;
527 int Index;
528 int Fd;
529 int Result;
530 struct termios Termios = {0};
531 struct termios TermiosNew = {0};
532 char VStart;
533 char VStop;
534
535 Fd = -1;
536 Result = LXT_RESULT_FAILURE;
537
538 //
539 // Check the default termios values.
540 //
541 // N.B. Ignore the termios settings that may differ..
542 //
543
544 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
545 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
546 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
547 if (Fd == -1)
548 {
549 if (errno == EIO)
550 {
551 LxtLogInfo("Skipping test %d", errno);
552 Result = LXT_RESULT_SUCCESS;
553 }
554 else
555 {
556 LxtLogError("Unexpected error %d", errno);
557 }
558
559 goto ErrorExit;
560 }
561
562 //
563 // Set and check the parity enable and type bits
564 //
565 // N.B. NT does not support setting input and output parity independently,
566 // but Linux does.
567 //
568
569 LxtCheckErrno(tcgetattr(Fd, &Termios));
570 Cflag = Termios.c_cflag;
571 Iflag = Termios.c_iflag;
572 VStart = Termios.c_cc[VSTART];
573 VStop = Termios.c_cc[VSTOP];
574
575 //
576 // ixon and ixoff set
577 //
578
579 Termios.c_iflag |= IXON;
580 Termios.c_iflag |= IXOFF;
581 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
582 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
583 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
584 LxtClose(Fd);
585 Fd = -1;
586 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
587 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
588 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
589
590 //
591 // ixon and ixoff not set
592 //
593
594 Termios.c_iflag &= ~IXON;
595 Termios.c_iflag &= ~IXOFF;
596 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
597 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
598 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
599 LxtClose(Fd);
600 Fd = -1;
601 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
602 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
603 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
604
605 //
606 // crtscts set
607 //
608
609 Termios.c_cflag |= CRTSCTS;
610 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
611 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
612 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
613 LxtClose(Fd);
614 Fd = -1;
615 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
616 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
617 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
618
619 //
620 // crtscts not set
621 //
622
623 Termios.c_cflag &= ~CRTSCTS;
624 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
625 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
626 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
627 LxtClose(Fd);
628 Fd = -1;
629 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
630 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
631 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
632
633 //
634 // clocal not set
635 //
636
637 LxtLogInfo("Clearing clocal");
638 Termios.c_cflag &= ~CLOCAL;
639 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
640 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
641 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
642 LxtClose(Fd);
643 Fd = -1;
644 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
645 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
646 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
647
648 //
649 // clocal set
650 //
651
652 Termios.c_cflag |= CLOCAL;
653 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
654 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
655 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
656 LxtClose(Fd);
657 Fd = -1;
658 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
659 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
660 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
661
662 //
663 // Flip vstart and vstop
664 //
665
666 LxtLogInfo("Updating vstart and vstop");
667 Termios.c_cc[VSTART] = VStop;
668 Termios.c_cc[VSTOP] = VStart;
669 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
670 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
671 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
672 LxtClose(Fd);
673 Fd = -1;
674 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
675 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
676 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
677
678 //
679 // Reset to the original
680 //
681
682 LxtLogInfo("Resetting...");
683 Termios.c_cflag = Cflag;
684 Termios.c_iflag = Iflag;
685 Termios.c_cc[VSTART] = VStart;
686 Termios.c_cc[VSTOP] = VStop;
687 LxtCheckErrno(tcsetattr(Fd, TCSANOW, &Termios));
688 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
689 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
690 LxtClose(Fd);
691 Fd = -1;
692 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
693 LxtCheckErrno(tcgetattr(Fd, &TermiosNew));
694 LxtCheckMemoryEqual(&Termios, &TermiosNew, sizeof(Termios));
695
696 Result = LXT_RESULT_SUCCESS;
697
698 ErrorExit:
699 if (Fd != -1)
700 {
701 LxtClose(Fd);
702 }
703
704 return Result;
705 }
706
707 int TtysWriteReadTransfer(PLXT_ARGS Args, int FdRead, int FdWrite)
708
709 /*++
710 --*/
711
712 {
713
714 int BytesRead;
715 int BytesWritten;
716 int BytesTotal;
717 pid_t ChildPid;
718 int Index;
719 char* RecvBuffer;
720 int Result;
721 char* SendBuffer;
722
723 ChildPid = -1;
724 RecvBuffer = NULL;
725 SendBuffer = NULL;
726
727 //
728 // Allocate a buffer with known data to transfer and a buffer to receive
729 // the data.
730 //
731
732 SendBuffer = LxtAlloc(LXT_TTYS_LARGE_BUFFER_SIZE);
733 if (SendBuffer == NULL)
734 {
735 Result = LXT_RESULT_FAILURE;
736 goto ErrorExit;
737 }
738
739 for (Index = 0; Index < LXT_TTYS_LARGE_BUFFER_SIZE; ++Index)
740 {
741 SendBuffer[Index] = (char)Index;
742 }
743
744 RecvBuffer = LxtAlloc(LXT_TTYS_LARGE_BUFFER_SIZE);
745 if (RecvBuffer == NULL)
746 {
747 Result = LXT_RESULT_FAILURE;
748 goto ErrorExit;
749 }
750
751 memset(RecvBuffer, 0, LXT_TTYS_LARGE_BUFFER_SIZE);
752
753 //
754 // Send and recv the data.
755 //
756
757 LxtCheckErrno(ChildPid = fork());
758 if (ChildPid == 0)
759 {
760 for (BytesTotal = 0; BytesTotal < LXT_TTYS_LARGE_BUFFER_SIZE; BytesTotal += BytesWritten)
761 {
762 BytesWritten = write(FdWrite, &SendBuffer[BytesTotal], LXT_TTYS_LARGE_BUFFER_SIZE - BytesTotal);
763
764 if (BytesWritten == -1)
765 {
766 if ((errno == EAGAIN) || (errno == EINTR))
767 {
768 BytesWritten = 0;
769 continue;
770 }
771
772 Result = LXT_RESULT_FAILURE;
773 LxtLogError("Write failed with %d", errno);
774 goto ErrorExit;
775 }
776 }
777
778 _exit(0);
779 }
780
781 for (BytesTotal = 0; BytesTotal < LXT_TTYS_LARGE_BUFFER_SIZE; BytesTotal += BytesRead)
782 {
783 BytesRead = read(FdRead, &RecvBuffer[BytesTotal], LXT_TTYS_LARGE_BUFFER_SIZE - BytesTotal);
784
785 if (BytesRead == -1)
786 {
787 if ((errno == EAGAIN) || (errno == EINTR))
788 {
789 BytesRead = 0;
790 continue;
791 }
792
793 Result = LXT_RESULT_FAILURE;
794 LxtLogError("Read failed with %d", errno);
795 goto ErrorExit;
796 }
797 }
798
799 LxtWaitPidPoll(ChildPid, 0);
800 for (Index = 0; Index < LXT_TTYS_LARGE_BUFFER_SIZE; ++Index)
801 {
802 if (RecvBuffer[Index] != (char)Index)
803 {
804 Result = LXT_RESULT_FAILURE;
805 LxtLogError("Mismatch at index %d: %d != %d", Index, (int)(RecvBuffer[Index]), (int)((char)Index));
806
807 goto ErrorExit;
808 }
809 }
810
811 Result = 0;
812
813 ErrorExit:
814 if (ChildPid == 0)
815 {
816 _exit(Result);
817 }
818
819 if (RecvBuffer != NULL)
820 {
821 LxtFree(RecvBuffer);
822 }
823
824 if (SendBuffer != NULL)
825 {
826 LxtFree(SendBuffer);
827 }
828
829 return Result;
830 }
831
832 int TtysWriteReadTermios(PLXT_ARGS Args, int FdRead, int FdWrite)
833
834 /*++
835 --*/
836
837 {
838
839 struct termios FdReadTermios;
840 int Fds[2];
841 struct termios FdWriteTermios;
842 int Index;
843 struct termios Termios;
844 int Result;
845
846 //
847 // Set the termios structure for transferring raw data.
848 //
849
850 Fds[0] = FdRead;
851 Fds[1] = FdWrite;
852 for (Index = 0; Index < LXT_COUNT_OF(Fds); ++Index)
853 {
854 LxtCheckErrno(tcgetattr(Fds[Index], &Termios));
855 Termios.c_iflag = 0;
856 Termios.c_oflag = 0;
857 Termios.c_cflag = B115200 | CREAD | CS8;
858 Termios.c_lflag = 0;
859 LxtCheckErrno(tcsetattr(Fds[Index], TCSANOW, &Termios));
860 }
861
862 memset(&FdReadTermios, 0, sizeof(FdReadTermios));
863 LxtCheckErrno(tcgetattr(FdRead, &FdReadTermios));
864 memset(&FdWriteTermios, 0, sizeof(FdWriteTermios));
865 LxtCheckErrno(tcgetattr(FdWrite, &FdWriteTermios));
866 LxtCheckMemoryEqual(&FdReadTermios, &FdWriteTermios, sizeof(FdWriteTermios));
867
868 Result = 0;
869
870 ErrorExit:
871 return Result;
872 }
873
874 int TtysWriteRead(PLXT_ARGS Args)
875
876 /*++
877 --*/
878
879 {
880
881 int BytesWritten;
882 dev_t Device;
883 int FdRead;
884 int FdWrite;
885 char Path[32];
886 int Result;
887
888 FdRead = -1;
889 FdWrite = -1;
890
891 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
892 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
893 LxtCheckErrno(FdRead = open(LXT_TTYS_DEFAULT, O_RDWR, 0));
894 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT2_MINOR);
895 mknod(LXT_TTYS_DEFAULT2, LXT_TTYS_DEV_MODE, Device);
896 LxtCheckErrno(FdWrite = open(LXT_TTYS_DEFAULT2, O_RDWR, 0));
897 LxtCheckResult(TtysWriteReadTermios(Args, FdRead, FdWrite));
898
899 //
900 // Transfer data with blocking IO
901 //
902
903 LxtCheckResult(TtysWriteReadTransfer(Args, FdRead, FdWrite));
904
905 //
906 // Transfer again with non-blocking IO.
907 //
908
909 Result = LXT_RESULT_SUCCESS;
910
911 ErrorExit:
912 if (FdRead != -1)
913 {
914 LxtClose(FdRead);
915 }
916
917 if (FdWrite != -1)
918 {
919 LxtClose(FdWrite);
920 }
921
922 return Result;
923 }
924
925 int TtysModemIoctls(PLXT_ARGS Args)
926
927 /*++
928 --*/
929
930 {
931
932 dev_t Device;
933 int Fd;
934 int ModemSettings;
935 int ModemSettingsOrig;
936 int Result;
937 struct termios Termios;
938 struct termios TermiosOrig;
939
940 Fd = -1;
941 ModemSettingsOrig = -1;
942 Result = LXT_RESULT_FAILURE;
943
944 //
945 // Check the default modem settings
946 //
947
948 Device = makedev(LXT_TTYS_DEV_MAJOR, LXT_TTYS_DEFAULT_MINOR);
949 mknod(LXT_TTYS_DEFAULT, LXT_TTYS_DEV_MODE, Device);
950 Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0);
951 if (Fd == -1)
952 {
953 if (errno == EIO)
954 {
955 LxtLogInfo("Skipping test %d", errno);
956 Result = LXT_RESULT_SUCCESS;
957 }
958 else
959 {
960 LxtLogError("Unexpected error %d", errno);
961 }
962
963 goto ErrorExit;
964 }
965
966 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettingsOrig));
967 LxtLogInfo("ModemSettingsOrig: %d", ModemSettingsOrig);
968 ModemSettings = ModemSettingsOrig;
969 LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
970 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
971 LxtCheckEqual(ModemSettings, ModemSettingsOrig, "%d");
972
973 //
974 // Check that invalid settings are ignored
975 //
976
977 ModemSettings = -1;
978 LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
979 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
980 LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
981 ModemSettings = -1;
982 LxtCheckResult(ioctl(Fd, TIOCMBIC, &ModemSettings));
983 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
984 LxtCheckEqual(ModemSettings, 0, "%d");
985 ModemSettings = -1;
986 LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
987 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
988 LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
989
990 //
991 // Recheck the settings after closing and reopening.
992 //
993
994 LxtClose(Fd);
995 Fd = -1;
996 LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
997 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
998 LxtCheckNotEqual(ModemSettings, ModemSettingsOrig, "%d");
999
1000 //
1001 // Check DTR
1002 //
1003 // N.B. Some serial drivers start up with DTR on native Linux.
1004 //
1005
1006 ModemSettings = ModemSettingsOrig & ~TIOCM_DTR;
1007 LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettings));
1008 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
1009 LxtCheckEqual(ModemSettings, ModemSettingsOrig & ~TIOCM_DTR, "%d");
1010 LxtClose(Fd);
1011 Fd = -1;
1012 LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
1013
1014 ModemSettings = TIOCM_DTR;
1015 LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
1016 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
1017 LxtCheckEqual(ModemSettings, ModemSettingsOrig | TIOCM_DTR, "%d");
1018 LxtClose(Fd);
1019 Fd = -1;
1020 LxtCheckErrno(Fd = open(LXT_TTYS_DEFAULT, O_RDWR | O_NONBLOCK, 0));
1021 LxtCheckResult(ioctl(Fd, TIOCMGET, &ModemSettings));
1022 LxtCheckEqual(ModemSettings, ModemSettingsOrig | TIOCM_DTR, "%d");
1023
1024 //
1025 // Check that changing RTS doesn't impact termios
1026 //
1027
1028 LxtCheckErrno(tcgetattr(Fd, &TermiosOrig));
1029 ModemSettings = TIOCM_RTS;
1030 LxtCheckResult(ioctl(Fd, TIOCMBIS, &ModemSettings));
1031 LxtCheckErrno(tcgetattr(Fd, &Termios));
1032 LxtCheckMemoryEqual(&TermiosOrig, &Termios, sizeof(Termios));
1033 ModemSettings = TIOCM_RTS;
1034 LxtCheckResult(ioctl(Fd, TIOCMBIC, &ModemSettings));
1035 LxtCheckErrno(tcgetattr(Fd, &Termios));
1036 LxtCheckMemoryEqual(&TermiosOrig, &Termios, sizeof(Termios));
1037
1038 Result = LXT_RESULT_SUCCESS;
1039
1040 ErrorExit:
1041 if (Fd != -1)
1042 {
1043 if (ModemSettingsOrig != -1)
1044 {
1045 LxtCheckResult(ioctl(Fd, TIOCMSET, &ModemSettingsOrig));
1046 }
1047
1048 LxtClose(Fd);
1049 }
1050
1051 return Result;
1052 }