1 /* Unit test suite for comm functions
2 *
3 * Copyright 2003 Kevin Groeneveld
4 * Copyright 2005 Uwe Bonnes
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdio.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "wine/test.h"
26 #include "winternl.h"
27 #include "winbase.h"
28 #include "winnls.h"
29
30 #define TIMEOUT 1000 /* one second for Timeouts*/
31 #define SLOWBAUD 150
32 #define FASTBAUD 115200
33 #define TIMEDELTA 150 /* 150 ms uncertainty allowed */
34
35 /* Define the appropriate LOOPBACK(s) TRUE if you have a Loopback cable with
36 * the mentioned shorts connected to your Serial port
37 */
38 #define LOOPBACK_TXD_RXD FALSE /* Sub-D 9: Short 2-3 */
39 #define LOOPBACK_CTS_RTS FALSE /* Sub-D 9: Short 7-8 */
40 #define LOOPBACK_DTR_DSR FALSE /* Sub-D 9: Short 4-6 */
41 #define LOOPBACK_DTR_RING FALSE /* Sub-D 9: Short 4-9 */
42 #define LOOPBACK_DTR_DCD FALSE /* Sub-D 9: Short 4-1 */
43 /* Many Linux serial drivers have the TIOCM_LOOP flag in the TIOCM_SET ioctl
44 * available. For the 8250 this is equivalent to TXD->RXD, OUT2->DCD,
45 * OUT1->RI, RTS->CTS and DTR->DSR
46 */
47 /* use variables and not #define to compile the code */
48 static BOOL loopback_txd_rxd = LOOPBACK_TXD_RXD;
49 static BOOL loopback_rts_cts = LOOPBACK_CTS_RTS;
50 static BOOL loopback_dtr_dsr = LOOPBACK_DTR_DSR;
51 static BOOL loopback_dtr_ring = LOOPBACK_DTR_RING;
52 static BOOL loopback_dtr_dcd = LOOPBACK_DTR_DCD;
53
54 static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent,
55 PIO_APC_ROUTINE apc, void* apc_user,
56 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
57 PLARGE_INTEGER offset, PULONG key);
58 static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
59 PIO_APC_ROUTINE apc, void* apc_user,
60 PIO_STATUS_BLOCK io_status,
61 const void* buffer, ULONG length,
62 PLARGE_INTEGER offset, PULONG key);
63
64 typedef struct
65 {
66 char string[100];
67 BOOL result;
68 BOOL old_style;
69 DCB dcb1, dcb2;
70 COMMTIMEOUTS timeouts1, timeouts2;
71 } TEST;
72
73 static const TEST test[] =
74 {
75 {
76 "baud=9600 parity=e data=5 stop=1 xon=on odsr=off octs=off dtr=on rts=on idsr=on",
77 TRUE, FALSE,
78 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
79 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
80 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
81 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
82 },
83 {
84 "baud=0 parity=M data=6 stop=1.5 xon=off odsr=on octs=ON dtr=off rts=off idsr=OFF",
85 TRUE, FALSE,
86 { 0x00000000, 0x00000000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
87 { 0xffffffff, 0x00000000, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
88 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
89 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
90 },
91 {
92 "BAUD=4000000000 parity=n data=7 stop=2 to=off",
93 TRUE, FALSE,
94 { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
95 { 0xffffffff, 0xee6b2800, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
96 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
97 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
98 },
99 {
100 "Baud=115200 Parity=O Data=8 To=On",
101 TRUE, FALSE,
102 { 0x00000000, 0x0001c200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
103 { 0xffffffff, 0x0001c200, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
104 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
105 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
106 },
107 {
108 "PaRiTy=s Data=7 DTR=on",
109 TRUE, FALSE,
110 { 0x00000000, 0x00000000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
111 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
112 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
113 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
114 },
115 {
116 "data=4",
117 FALSE, FALSE,
118 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
119 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
120 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
121 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
122 },
123 {
124 "data=9",
125 FALSE, FALSE,
126 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
127 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
128 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
129 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
130 },
131 {
132 "parity=no",
133 FALSE, FALSE,
134 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
135 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
136 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
137 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
138 },
139 {
140 "stop=0",
141 FALSE, FALSE,
142 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
143 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
144 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
145 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
146 },
147 {
148 "stop=1.501",
149 FALSE, FALSE,
150 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
151 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
152 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
153 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
154 },
155 {
156 "stop=3",
157 FALSE, FALSE,
158 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
159 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
160 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
161 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
162 },
163 {
164 "to=foobar",
165 FALSE, FALSE,
166 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
167 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
168 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
169 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
170 },
171 {
172 " baud=9600",
173 FALSE, FALSE,
174 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
175 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
176 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
177 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
178 },
179 {
180 "baud= 9600",
181 FALSE, FALSE,
182 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
183 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
184 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
185 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
186 },
187 {
188 "baud=9600,data=8",
189 FALSE, FALSE,
190 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
191 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
192 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
193 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
194 },
195 {
196 "11,n,8,1",
197 TRUE, TRUE,
198 { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
199 { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
200 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
201 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
202 },
203 {
204 "30 ,E, 5,1.5",
205 TRUE, TRUE,
206 { 0x00000000, 0x0000012c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
207 { 0xffffffff, 0x0000012c, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
208 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
209 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
210 },
211 {
212 "60, m, 6, 2 ",
213 TRUE, TRUE,
214 { 0x00000000, 0x00000258, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
215 { 0xffffffff, 0x00000258, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
216 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
217 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
218 },
219 {
220 "12 , o , 7 , 1",
221 TRUE, TRUE,
222 { 0x00000000, 0x000004b0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
223 { 0xffffffff, 0x000004b0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
224 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
225 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
226 },
227 {
228 "24,s,8,1.5",
229 TRUE, TRUE,
230 { 0x00000000, 0x00000960, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
231 { 0xffffffff, 0x00000960, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x04, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
232 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
233 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
234 },
235 {
236 "48,n,8,1,p",
237 TRUE, TRUE,
238 { 0x00000000, 0x000012c0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
239 { 0xffffffff, 0x000012c0, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
240 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
241 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
242 },
243 {
244 "96,N,8,1 , x ",
245 TRUE, TRUE,
246 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
247 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
248 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
249 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
250 },
251 {
252 "19, e, 7, 1, x",
253 TRUE, TRUE,
254 { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
255 { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
256 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
257 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
258 },
259 {
260 "0,M,7,1,P",
261 TRUE, TRUE,
262 { 0x00000000, 0x00000000, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
263 { 0xffffffff, 0x00000000, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
264 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
265 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
266 },
267 {
268 "4000000000,O,7,1.5,X",
269 TRUE, TRUE,
270 { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
271 { 0xffffffff, 0xee6b2800, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
272 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
273 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
274 },
275 {
276 "96,N,8,1 to=on",
277 FALSE, TRUE,
278 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
279 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
280 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
281 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
282 },
283 {
284 "96,NO,8,1",
285 FALSE, TRUE,
286 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
287 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
288 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
289 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
290 },
291 {
292 "96,N,4,1",
293 FALSE, TRUE,
294 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
295 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
296 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
297 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
298 },
299 {
300 "96,N,9,1",
301 FALSE, TRUE,
302 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
303 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
304 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
305 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
306 },
307 {
308 "96,N,8,0",
309 FALSE, TRUE,
310 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
311 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
312 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
313 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
314 },
315 {
316 "96,N,8,3",
317 FALSE, TRUE,
318 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
319 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
320 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
321 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
322 },
323 {
324 "96,N,8,1,K",
325 FALSE, TRUE,
326 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
327 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
328 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
329 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
330 },
331 {
332 "COM0:baud=115200",
333 FALSE, FALSE,
334 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
335 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
336 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
337 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
338 },
339 {
340 "COMx:baud=38400 data=8",
341 TRUE, FALSE,
342 { 0x00000000, 0x00009600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
343 { 0xffffffff, 0x00009600, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
344 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
345 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
346 },
347 {
348 "COMx :to=on stop=1.5",
349 TRUE, FALSE,
350 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
351 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
352 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
353 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
354 },
355 {
356 "COMx: baud=12345 data=7",
357 TRUE, FALSE,
358 { 0x00000000, 0x00003039, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
359 { 0xffffffff, 0x00003039, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
360 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
361 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
362 },
363 {
364 "COMx : xon=on odsr=off",
365 TRUE, FALSE,
366 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
367 { 0xffffffff, 0xffffffff, 1, 1, 1, 0, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
368 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
369 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
370 },
371 {
372 "COM0:9600,N,8,1",
373 FALSE, TRUE,
374 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
375 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
376 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
377 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
378 },
379 {
380 "COMx:9600,N,8,1",
381 TRUE, TRUE,
382 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
383 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
384 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
385 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
386 },
387 {
388 "COMx: 11,E,7,2",
389 TRUE, TRUE,
390 { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
391 { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
392 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
393 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
394 },
395 {
396 "COMx :19,M,5,1",
397 TRUE, TRUE,
398 { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
399 { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
400 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
401 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
402 },
403 {
404 "COMx : 57600,S,6,2,x",
405 TRUE, TRUE,
406 { 0x00000000, 0x0000e100, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
407 { 0xffffffff, 0x0000e100, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x04, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
408 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
409 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
410 },
411 };
412
413 #define TEST_COUNT (sizeof(test) / sizeof(TEST))
414
415 /* This function can be useful if you are modifying the test cases and want to
416 output the contents of a DCB structure. */
417 /*static print_dcb(DCB *pdcb)
418 {
419 printf("0x%08x, 0x%08x, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, 0x%05x, 0x%04x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%04x\n",
420 pdcb->DCBlength,
421 pdcb->BaudRate,
422 pdcb->fBinary,
423 pdcb->fParity,
424 pdcb->fOutxCtsFlow,
425 pdcb->fOutxDsrFlow,
426 pdcb->fDtrControl,
427 pdcb->fDsrSensitivity,
428 pdcb->fTXContinueOnXoff,
429 pdcb->fOutX,
430 pdcb->fInX,
431 pdcb->fErrorChar,
432 pdcb->fNull,
433 pdcb->fRtsControl,
434 pdcb->fAbortOnError,
435 pdcb->fDummy2,
436 pdcb->wReserved,
437 pdcb->XonLim,
438 pdcb->XoffLim,
439 pdcb->ByteSize,
440 pdcb->Parity,
441 pdcb->StopBits,
442 pdcb->XonChar & 0xff,
443 pdcb->XoffChar & 0xff,
444 pdcb->ErrorChar & 0xff,
445 pdcb->EofChar & 0xff,
446 pdcb->EvtChar & 0xff,
447 pdcb->wReserved1 & 0xffff );
448 } */
449
check_result(const char * function,const TEST * ptest,int initial_value,BOOL result)450 static void check_result(const char *function, const TEST *ptest, int initial_value, BOOL result)
451 {
452 DWORD LastError = GetLastError();
453 DWORD CorrectError = (ptest->result ? 0xdeadbeef : ERROR_INVALID_PARAMETER);
454
455 ok(LastError == CorrectError, "%s(\"%s\"), 0x%02x: GetLastError() returned %d, should be %d\n", function, ptest->string, initial_value, LastError, CorrectError);
456 ok(result == ptest->result, "%s(\"%s\"), 0x%02x: return value should be %s\n", function, ptest->string, initial_value, ptest->result ? "TRUE" : "FALSE");
457 }
458
459 #define check_dcb_member(a,b) ok(pdcb1->a == pdcb2->a, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a)
460 #define check_dcb_member2(a,c,b) if(pdcb2->a == c) { check_dcb_member(a,b); } else { ok(pdcb1->a == pdcb2->a || pdcb1->a == c, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b" or "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a, c); }
461
check_dcb(const char * function,const TEST * ptest,int initial_value,const DCB * pdcb1,const DCB * pdcb2)462 static void check_dcb(const char *function, const TEST *ptest, int initial_value, const DCB *pdcb1, const DCB *pdcb2)
463 {
464 /* DCBlength is a special case since Win 9x sets it but NT does not.
465 We will accept either as correct. */
466 check_dcb_member2(DCBlength, (DWORD)sizeof(DCB), "%u");
467
468 /* For old style control strings Win 9x does not set the next five members, NT does. */
469 if(ptest->old_style && ptest->result)
470 {
471 check_dcb_member2(fOutxCtsFlow, ((unsigned int)initial_value & 1), "%u");
472 check_dcb_member2(fDtrControl, ((unsigned int)initial_value & 3), "%u");
473 check_dcb_member2(fOutX, ((unsigned int)initial_value & 1), "%u");
474 check_dcb_member2(fInX, ((unsigned)initial_value & 1), "%u");
475 check_dcb_member2(fRtsControl, ((unsigned)initial_value & 3), "%u");
476 }
477 else
478 {
479 check_dcb_member(fOutxCtsFlow, "%u");
480 check_dcb_member(fDtrControl, "%u");
481 check_dcb_member(fOutX, "%u");
482 check_dcb_member(fInX, "%u");
483 check_dcb_member(fRtsControl, "%u");
484 }
485
486 if(ptest->result)
487 {
488 /* For the idsr=xxx parameter, NT sets fDsrSensitivity, 9x sets
489 fOutxDsrFlow. */
490 if(!ptest->old_style)
491 {
492 check_dcb_member2(fOutxDsrFlow, pdcb2->fDsrSensitivity, "%u");
493 check_dcb_member2(fDsrSensitivity, pdcb2->fOutxDsrFlow, "%u");
494 }
495 else
496 {
497 /* For old style control strings Win 9x does not set the
498 fOutxDsrFlow member, NT does. */
499 check_dcb_member2(fOutxDsrFlow, ((unsigned int)initial_value & 1), "%u");
500 check_dcb_member(fDsrSensitivity, "%u");
501 }
502 }
503 else
504 {
505 check_dcb_member(fOutxDsrFlow, "%u");
506 check_dcb_member(fDsrSensitivity, "%u");
507 }
508
509 /* Check the result of the DCB members. */
510 check_dcb_member(BaudRate, "%u");
511 check_dcb_member(fBinary, "%u");
512 check_dcb_member(fParity, "%u");
513 check_dcb_member(fTXContinueOnXoff, "%u");
514 check_dcb_member(fErrorChar, "%u");
515 check_dcb_member(fNull, "%u");
516 check_dcb_member(fAbortOnError, "%u");
517 check_dcb_member(fDummy2, "%u");
518 check_dcb_member(wReserved, "%u");
519 check_dcb_member(XonLim, "%u");
520 check_dcb_member(XoffLim, "%u");
521 check_dcb_member(ByteSize, "%u");
522 check_dcb_member(Parity, "%u");
523 check_dcb_member(StopBits, "%u");
524 check_dcb_member(XonChar, "%d");
525 check_dcb_member(XoffChar, "%d");
526 check_dcb_member(ErrorChar, "%d");
527 check_dcb_member(EofChar, "%d");
528 check_dcb_member(EvtChar, "%d");
529 check_dcb_member(wReserved1, "%u");
530 }
531
532 #define check_timeouts_member(a) ok(ptimeouts1->a == ptimeouts2->a, "%s(\"%s\"), 0x%02x: "#a" is %u, should be %u\n", function, ptest->string, initial_value, ptimeouts1->a, ptimeouts2->a);
533
check_timeouts(const char * function,const TEST * ptest,int initial_value,const COMMTIMEOUTS * ptimeouts1,const COMMTIMEOUTS * ptimeouts2)534 static void check_timeouts(const char *function, const TEST *ptest, int initial_value, const COMMTIMEOUTS *ptimeouts1, const COMMTIMEOUTS *ptimeouts2)
535 {
536 check_timeouts_member(ReadIntervalTimeout);
537 check_timeouts_member(ReadTotalTimeoutMultiplier);
538 check_timeouts_member(ReadTotalTimeoutConstant);
539 check_timeouts_member(WriteTotalTimeoutMultiplier);
540 check_timeouts_member(WriteTotalTimeoutConstant);
541 }
542
test_BuildCommDCBA(const char * string,const TEST * ptest,int initial_value,const DCB * pexpected_dcb)543 static void test_BuildCommDCBA(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb)
544 {
545 BOOL result;
546 DCB dcb;
547
548 /* set initial conditions */
549 memset(&dcb, initial_value, sizeof(DCB));
550 SetLastError(0xdeadbeef);
551
552 result = BuildCommDCBA(string, &dcb);
553
554 /* check results */
555 check_result("BuildCommDCBA", ptest, initial_value, result);
556 check_dcb("BuildCommDCBA", ptest, initial_value, &dcb, pexpected_dcb);
557 }
558
test_BuildCommDCBAndTimeoutsA(const char * string,const TEST * ptest,int initial_value,const DCB * pexpected_dcb,const COMMTIMEOUTS * pexpected_timeouts)559 static void test_BuildCommDCBAndTimeoutsA(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb, const COMMTIMEOUTS *pexpected_timeouts)
560 {
561 BOOL result;
562 DCB dcb;
563 COMMTIMEOUTS timeouts;
564
565 /* set initial conditions */
566 memset(&dcb, initial_value, sizeof(DCB));
567 memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
568 SetLastError(0xdeadbeef);
569
570 result = BuildCommDCBAndTimeoutsA(string, &dcb, &timeouts);
571
572 /* check results */
573 check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result);
574 check_dcb("BuildCommDCBAndTimeoutsA", ptest, initial_value, &dcb, pexpected_dcb);
575 check_timeouts("BuildCommDCBAndTimeoutsA", ptest, initial_value, &timeouts, pexpected_timeouts);
576 }
577
test_BuildCommDCBW(const char * string,const TEST * ptest,int initial_value,const DCB * pexpected_dcb)578 static void test_BuildCommDCBW(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb)
579 {
580 BOOL result;
581 DCB dcb;
582 WCHAR wide_string[sizeof(ptest->string)];
583 static int reportedDCBW = 0;
584
585 MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
586
587 /* set initial conditions */
588 memset(&dcb, initial_value, sizeof(DCB));
589 SetLastError(0xdeadbeef);
590
591 result = BuildCommDCBW(wide_string, &dcb);
592
593 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
594 {
595 if(!reportedDCBW++)
596 win_skip("BuildCommDCBW is not implemented\n");
597 return;
598 }
599
600 /* check results */
601 check_result("BuildCommDCBW", ptest, initial_value, result);
602 check_dcb("BuildCommDCBW", ptest, initial_value, &dcb, pexpected_dcb);
603 }
604
test_BuildCommDCBAndTimeoutsW(const char * string,const TEST * ptest,int initial_value,const DCB * pexpected_dcb,const COMMTIMEOUTS * pexpected_timeouts)605 static void test_BuildCommDCBAndTimeoutsW(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb, const COMMTIMEOUTS *pexpected_timeouts)
606 {
607 BOOL result;
608 DCB dcb;
609 COMMTIMEOUTS timeouts;
610 WCHAR wide_string[sizeof(ptest->string)];
611 static int reportedDCBAndTW = 0;
612
613 MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
614
615 /* set initial conditions */
616 memset(&dcb, initial_value, sizeof(DCB));
617 memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
618 SetLastError(0xdeadbeef);
619
620 result = BuildCommDCBAndTimeoutsW(wide_string, &dcb, &timeouts);
621
622 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
623 {
624 if(!reportedDCBAndTW++)
625 win_skip("BuildCommDCBAndTimeoutsW is not implemented\n");
626 return;
627 }
628
629 /* check results */
630 check_result("BuildCommDCBAndTimeoutsW", ptest, initial_value, result);
631 check_dcb("BuildCommDCBAndTimeoutsW", ptest, initial_value, &dcb, pexpected_dcb);
632 check_timeouts("BuildCommDCBAndTimeoutsW", ptest, initial_value, &timeouts, pexpected_timeouts);
633 }
634
test_BuildCommDCB(void)635 static void test_BuildCommDCB(void)
636 {
637 char port_name[] = "COMx";
638 char port = 0;
639 unsigned int i;
640 char *ptr;
641
642 /* Some of these tests require a valid COM port. This loop will try to find
643 a valid port. */
644 for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
645 {
646 COMMCONFIG commconfig;
647 DWORD size = sizeof(COMMCONFIG);
648
649 if(GetDefaultCommConfigA(port_name, &commconfig, &size))
650 {
651 port = port_name[3];
652 break;
653 }
654 }
655
656 if(!port)
657 trace("Could not find a valid COM port. Some tests will be skipped.\n");
658
659 for(i = 0; i < TEST_COUNT; i++)
660 {
661 char string[sizeof(test[i].string)];
662
663 strcpy(string, test[i].string);
664
665 /* Check if this test case needs a valid COM port. */
666 ptr = strstr(string, "COMx");
667
668 /* If required, substitute valid port number into device control string. */
669 if(ptr)
670 {
671 if(port)
672 ptr[3] = port;
673 else
674 continue;
675 }
676
677 test_BuildCommDCBA(string, &test[i], 0x00, &test[i].dcb1);
678 test_BuildCommDCBA(string, &test[i], 0xff, &test[i].dcb2);
679 test_BuildCommDCBAndTimeoutsA(string, &test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
680 test_BuildCommDCBAndTimeoutsA(string, &test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
681
682 test_BuildCommDCBW(string, &test[i], 0x00, &test[i].dcb1);
683 test_BuildCommDCBW(string, &test[i], 0xff, &test[i].dcb2);
684 test_BuildCommDCBAndTimeoutsW(string, &test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
685 test_BuildCommDCBAndTimeoutsW(string, &test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
686 }
687 }
688
test_OpenComm(BOOL doOverlap)689 static HANDLE test_OpenComm(BOOL doOverlap)
690 {
691 HANDLE hcom = INVALID_HANDLE_VALUE;
692 char port_name[] = "COMx";
693 static BOOL shown = FALSE;
694 DWORD errors;
695 COMSTAT comstat;
696
697 /* Try to find a port */
698 for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
699 {
700 hcom = CreateFileA( port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
701 (doOverlap)?FILE_FLAG_OVERLAPPED:0, NULL );
702 if (hcom != INVALID_HANDLE_VALUE)
703 break;
704 }
705 if(!shown)
706 {
707 if (hcom == INVALID_HANDLE_VALUE)
708 trace("Could not find a valid COM port.\n");
709 else
710 trace("Found Com port %s. Connected devices may disturb results\n", port_name);
711 /*shown = TRUE; */
712 }
713 if (hcom != INVALID_HANDLE_VALUE)
714 {
715 BOOL ret;
716
717 ret = ClearCommError(hcom, &errors, &comstat);
718 if (!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_HANDLE))
719 {
720 if (GetLastError() == ERROR_NOT_READY)
721 trace("%s doesn't respond, skipping the test\n", port_name);
722 else
723 trace("%s is not a real serial port, skipping the test\n", port_name);
724 CloseHandle(hcom);
725 return INVALID_HANDLE_VALUE;
726 }
727
728 ok(ret, "Unexpected error %u on open\n", GetLastError());
729 ok(comstat.cbInQue == 0, "Unexpected %d chars in InQueue\n",comstat.cbInQue);
730 ok(comstat.cbOutQue == 0, "Still pending %d charcters in OutQueue\n", comstat.cbOutQue);
731 ok(errors == 0, "Unexpected errors 0x%08x\n", errors);
732 }
733 return hcom;
734 }
735
test_GetModemStatus(HANDLE hcom)736 static void test_GetModemStatus(HANDLE hcom)
737 {
738 DWORD ModemStat = 0;
739
740 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
741 trace("GetCommModemStatus returned 0x%08x->%s%s%s%s\n", ModemStat,
742 (ModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
743 (ModemStat &MS_RING_ON)?"MS_RING_ON ":"",
744 (ModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
745 (ModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
746 }
747
748 /* When we don't write anything, Read should time out even on a loopbacked port */
test_ReadTimeOut(void)749 static void test_ReadTimeOut(void)
750 {
751 HANDLE hcom;
752 DCB dcb;
753 COMMTIMEOUTS timeouts;
754 char rbuf[32];
755 DWORD before, after, read, timediff, LastError;
756 BOOL res;
757
758 hcom = test_OpenComm(FALSE);
759 if (hcom == INVALID_HANDLE_VALUE) return;
760
761 test_GetModemStatus(hcom);
762
763 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
764 dcb.BaudRate = FASTBAUD;
765 dcb.ByteSize = 8;
766 dcb.Parity = NOPARITY;
767 dcb.fRtsControl=RTS_CONTROL_ENABLE;
768 dcb.fDtrControl=DTR_CONTROL_ENABLE;
769 dcb.StopBits = ONESTOPBIT;
770 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
771
772 ZeroMemory( &timeouts, sizeof(timeouts));
773 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
774 ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
775
776 before = GetTickCount();
777 SetLastError(0xdeadbeef);
778 res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
779 LastError = GetLastError();
780 after = GetTickCount();
781 ok( res == TRUE, "A timed-out read should return TRUE\n");
782 ok( LastError == 0xdeadbeef, "err=%d\n", LastError);
783 timediff = after - before;
784 ok( timediff > TIMEOUT>>2 && timediff < TIMEOUT *2,
785 "Unexpected TimeOut %d, expected %d\n", timediff, TIMEOUT);
786
787 CloseHandle(hcom);
788 }
789
test_waittxempty(void)790 static void test_waittxempty(void)
791 {
792 HANDLE hcom;
793 DCB dcb;
794 COMMTIMEOUTS timeouts;
795 char tbuf[]="test_waittxempty";
796 DWORD before, after, bytes, timediff, evtmask, errors, i;
797 BOOL res;
798 DWORD baud = SLOWBAUD;
799 OVERLAPPED ovl_write, ovl_wait, ovl_wait2;
800 COMSTAT stat;
801
802 hcom = test_OpenComm(TRUE);
803 if (hcom == INVALID_HANDLE_VALUE) return;
804
805 /* set a low baud rate to have ample time*/
806 res = GetCommState(hcom, &dcb);
807 ok(res, "GetCommState error %d\n", GetLastError());
808 dcb.BaudRate = baud;
809 dcb.ByteSize = 8;
810 dcb.Parity = NOPARITY;
811 dcb.fRtsControl=RTS_CONTROL_ENABLE;
812 dcb.fDtrControl=DTR_CONTROL_ENABLE;
813 dcb.StopBits = ONESTOPBIT;
814 res = SetCommState(hcom, &dcb);
815 ok(res, "SetCommState error %d\n", GetLastError());
816
817 ZeroMemory( &timeouts, sizeof(timeouts));
818 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
819 res = SetCommTimeouts(hcom, &timeouts);
820 ok(res,"SetCommTimeouts error %d\n", GetLastError());
821
822 res = SetupComm(hcom, 1024, 1024);
823 ok(res, "SetUpComm error %d\n", GetLastError());
824
825 /* calling SetCommMask after WriteFile leads to WaitCommEvent failures
826 * due to timeout (no events) under testbot VMs and VirtualBox
827 */
828 res = SetCommMask(hcom, EV_TXEMPTY);
829 ok(res, "SetCommMask error %d\n", GetLastError());
830
831 SetLastError(0xdeadbeef);
832 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, NULL);
833 ok(!res, "WriteFile on an overlapped handle without ovl structure should fail\n");
834 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
835
836 S(U(ovl_write)).Offset = 0;
837 S(U(ovl_write)).OffsetHigh = 0;
838 ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
839 before = GetTickCount();
840 SetLastError(0xdeadbeef);
841 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write);
842 after = GetTickCount();
843 ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)),
844 "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError());
845 if (!res) ok(!bytes, "expected 0, got %u\n", bytes);
846 ok(after - before < 30, "WriteFile took %d ms to write %d Bytes at %d Baud\n",
847 after - before, bytes, baud);
848 /* don't wait for WriteFile completion */
849
850 S(U(ovl_wait)).Offset = 0;
851 S(U(ovl_wait)).OffsetHigh = 0;
852 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
853 evtmask = 0;
854 before = GetTickCount();
855 SetLastError(0xdeadbeef);
856 res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
857 ok(!res && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %d\n", GetLastError());
858 after = GetTickCount();
859 ok(after - before < 30, "WaitCommEvent should have returned immediately, took %d ms\n", after - before);
860 res = WaitForSingleObject(ovl_wait.hEvent, 1500);
861 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
862 if (res == WAIT_OBJECT_0)
863 {
864 res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
865 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
866 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
867 res = TRUE;
868 }
869 else
870 {
871 /* unblock pending wait */
872 trace("recovering after WAIT_TIMEOUT...\n");
873 res = SetCommMask(hcom, EV_TXEMPTY);
874 ok(res, "SetCommMask error %d\n", GetLastError());
875
876 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
877 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
878
879 res = FALSE;
880 }
881 after = GetTickCount();
882 ok(res, "WaitCommEvent error %d\n", GetLastError());
883 ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
884 CloseHandle(ovl_wait.hEvent);
885
886 timediff = after - before;
887 trace("WaitCommEvent for EV_TXEMPTY took %d ms (timeout 1500)\n", timediff);
888 ok(timediff < 1200, "WaitCommEvent used %d ms for waiting\n", timediff);
889
890 res = WaitForSingleObject(ovl_write.hEvent, 0);
891 ok(res == WAIT_OBJECT_0, "WriteFile failed with a timeout\n");
892 res = GetOverlappedResult(hcom, &ovl_write, &bytes, FALSE);
893 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
894 ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes);
895 CloseHandle(ovl_write.hEvent);
896
897 CloseHandle(hcom);
898
899 for (i = 0; i < 2; i++)
900 {
901 hcom = test_OpenComm(TRUE);
902 if (hcom == INVALID_HANDLE_VALUE) return;
903
904 res = SetCommMask(hcom, EV_TXEMPTY);
905 ok(res, "SetCommMask error %d\n", GetLastError());
906
907 if (i == 0)
908 {
909 S(U(ovl_write)).Offset = 0;
910 S(U(ovl_write)).OffsetHigh = 0;
911 ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
912 before = GetTickCount();
913 SetLastError(0xdeadbeef);
914 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write);
915 ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)),
916 "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError());
917 if (!res) ok(!bytes, "expected 0, got %u\n", bytes);
918
919 ClearCommError(hcom, &errors, &stat);
920 ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue);
921 ok(stat.cbOutQue != 0 || broken(stat.cbOutQue == 0) /* VM */, "OutQueue should not be empty\n");
922 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
923
924 res = GetOverlappedResult(hcom, &ovl_write, &bytes, TRUE);
925 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
926 ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes);
927 CloseHandle(ovl_write.hEvent);
928
929 res = FlushFileBuffers(hcom);
930 ok(res, "FlushFileBuffers error %d\n", GetLastError());
931 }
932
933 ClearCommError(hcom, &errors, &stat);
934 ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue);
935 ok(stat.cbOutQue == 0, "OutQueue should be empty, got %d bytes\n", stat.cbOutQue);
936 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
937
938 S(U(ovl_wait)).Offset = 0;
939 S(U(ovl_wait)).OffsetHigh = 0;
940 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
941 evtmask = 0;
942 SetLastError(0xdeadbeef);
943 res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
944 ok(res /* busy system */ || GetLastError() == ERROR_IO_PENDING,
945 "%d: WaitCommEvent error %d\n", i, GetLastError());
946
947 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
948 if (i == 0)
949 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
950 else
951 ok(res == WAIT_TIMEOUT, "WaitCommEvent should fail with a timeout\n");
952 if (res == WAIT_OBJECT_0)
953 {
954 res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
955 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
956 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
957 ok(res, "WaitCommEvent error %d\n", GetLastError());
958 ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
959 }
960 else
961 {
962 ok(!evtmask, "WaitCommEvent: expected 0, got %#x\n", evtmask);
963
964 S(U(ovl_wait2)).Offset = 0;
965 S(U(ovl_wait2)).OffsetHigh = 0;
966 ovl_wait2.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
967 SetLastError(0xdeadbeef);
968 res = WaitCommEvent(hcom, &evtmask, &ovl_wait2);
969 ok(!res, "WaitCommEvent should fail if there is a pending wait\n");
970 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
971 CloseHandle(ovl_wait2.hEvent);
972
973 /* unblock pending wait */
974 trace("recovering after WAIT_TIMEOUT...\n");
975 res = SetCommMask(hcom, EV_TXEMPTY);
976 ok(res, "SetCommMask error %d\n", GetLastError());
977
978 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
979 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
980 CloseHandle(ovl_wait.hEvent);
981 }
982
983 CloseHandle(hcom);
984 }
985 }
986
987 /* A new open handle should not return error or have bytes in the Queues */
test_ClearCommError(void)988 static void test_ClearCommError(void)
989 {
990 HANDLE hcom;
991 DWORD errors;
992 COMSTAT lpStat;
993
994 hcom = test_OpenComm(FALSE);
995 if (hcom == INVALID_HANDLE_VALUE) return;
996
997 ok(ClearCommError(hcom, &errors, &lpStat), "ClearCommError failed\n");
998 ok(lpStat.cbInQue == 0, "Unexpected %d chars in InQueue\n", lpStat.cbInQue);
999 ok(lpStat.cbOutQue == 0, "Unexpected %d chars in OutQueue\n", lpStat.cbOutQue);
1000 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
1001
1002 CloseHandle(hcom);
1003 }
1004
test_non_pending_errors(void)1005 static void test_non_pending_errors(void)
1006 {
1007 HANDLE hcom;
1008 DCB dcb;
1009 DWORD err;
1010
1011 hcom = test_OpenComm(FALSE);
1012 if (hcom == INVALID_HANDLE_VALUE) return;
1013
1014 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1015 dcb.ByteSize = 255; /* likely bogus */
1016 ok(!SetCommState(hcom, &dcb), "SetCommState should have failed\n");
1017 ok(ClearCommError(hcom, &err, NULL), "ClearCommError should succeed\n");
1018 ok(!(err & CE_MODE), "ClearCommError shouldn't set CE_MODE byte in this case (%x)\n", err);
1019
1020 CloseHandle(hcom);
1021 }
1022
test_LoopbackRead(void)1023 static void test_LoopbackRead(void)
1024 {
1025 HANDLE hcom;
1026 DCB dcb;
1027 COMMTIMEOUTS timeouts;
1028 char rbuf[32];
1029 DWORD before, after, diff, read, read1, written, evtmask=0, i;
1030 BOOL res;
1031 char tbuf[]="test_LoopbackRead";
1032
1033 if (!loopback_txd_rxd) return;
1034
1035 hcom = test_OpenComm(FALSE);
1036 if (hcom == INVALID_HANDLE_VALUE) return;
1037
1038 trace("Starting test_LoopbackRead\n");
1039 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1040 dcb.BaudRate = FASTBAUD;
1041 dcb.ByteSize = 8;
1042 dcb.Parity = NOPARITY;
1043 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1044 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1045 dcb.StopBits = ONESTOPBIT;
1046 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1047
1048 ZeroMemory( &timeouts, sizeof(timeouts));
1049 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
1050 ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
1051
1052 ok(SetCommMask(hcom, EV_TXEMPTY), "SetCommMask failed\n");
1053
1054 before = GetTickCount();
1055 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1056 after = GetTickCount();
1057 ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written);
1058 diff = after -before;
1059
1060 /* make sure all bytes are written, so Readfile will succeed in one call*/
1061 ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
1062 before = GetTickCount();
1063 ok(evtmask == EV_TXEMPTY,
1064 "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n",
1065 evtmask, EV_TXEMPTY);
1066 trace("Write %d ms WaitCommEvent EV_TXEMPTY %d ms\n", diff, before- after);
1067
1068 read=0;
1069 ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n");
1070 ok(read == sizeof(tbuf),"ReadFile read %d bytes, expected \"%s\"\n", read,rbuf);
1071
1072 /* Now do the same with a slower Baud rate.
1073 As we request more characters than written, we will hit the timeout
1074 */
1075
1076 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1077 dcb.BaudRate = 9600;
1078 dcb.ByteSize = 8;
1079 dcb.Parity = NOPARITY;
1080 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1081 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1082 dcb.StopBits = ONESTOPBIT;
1083 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1084
1085 ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
1086 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1087 ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written);
1088
1089 trace("WaitCommEventEV_RXCHAR\n");
1090 ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
1091 ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n",
1092 evtmask, EV_RXCHAR);
1093
1094 before = GetTickCount();
1095 res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
1096 after = GetTickCount();
1097 ok(res, "Readfile failed\n");
1098 ok(read == sizeof(tbuf),"ReadFile read %d bytes\n", read);
1099 diff = after - before;
1100 trace("Readfile for %d chars took %d ms\n", read, diff);
1101 ok( (diff > TIMEOUT - TIMEDELTA) && (diff < TIMEOUT + TIMEDELTA),
1102 "Timedout Wait took %d ms, expected around %d\n", diff, TIMEOUT);
1103
1104 /* now do a plain read with slow speed
1105 * This will result in several low level reads and a timeout to happen
1106 */
1107 dcb.BaudRate = SLOWBAUD;
1108 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1109 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1110 before = GetTickCount();
1111 read = 0;
1112 read1 =0;
1113 i=0;
1114 do
1115 {
1116 res = ReadFile(hcom, rbuf+read, sizeof(rbuf)-read, &read1, NULL);
1117 ok(res, "Readfile failed\n");
1118 read += read1;
1119 i++;
1120 }
1121 while ((read < sizeof(tbuf)) && (i <10));
1122 after = GetTickCount();
1123 ok( read == sizeof(tbuf),"ReadFile read %d bytes\n", read);
1124 trace("Plain Read for %d char at %d baud took %d ms\n", read, SLOWBAUD, after-before);
1125
1126 CloseHandle(hcom);
1127 }
1128
test_LoopbackCtsRts(void)1129 static void test_LoopbackCtsRts(void)
1130 {
1131 HANDLE hcom;
1132 DWORD ModemStat = 0, defaultStat = 0;
1133 DCB dcb;
1134
1135 if (!loopback_rts_cts) return;
1136
1137 hcom = test_OpenComm(FALSE);
1138 if (hcom == INVALID_HANDLE_VALUE) return;
1139
1140 memset (&dcb, 0, sizeof (dcb));
1141 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1142 if (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE)
1143 {
1144 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate RTS\n");
1145 CloseHandle(hcom);
1146 return;
1147 }
1148 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1149 /* XP returns some values in the low nibble, so mask them out*/
1150 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1151 if(defaultStat & MS_CTS_ON)
1152 {
1153 ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
1154 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1155 ok ((ModemStat & MS_CTS_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n",
1156 ModemStat, (defaultStat & ~MS_CTS_ON));
1157 ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to clear RTS\n");
1158 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1159 ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n",
1160 ModemStat, defaultStat);
1161 }
1162 else
1163 {
1164 ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to set RTS\n");
1165 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1166 ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON,
1167 "CTS didn't react: 0x%04x, expected 0x%04x\n",
1168 ModemStat, (defaultStat | MS_CTS_ON));
1169 ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
1170 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1171 ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n",
1172 ModemStat, defaultStat);
1173 }
1174
1175 CloseHandle(hcom);
1176 }
1177
test_LoopbackDtrDcd(void)1178 static void test_LoopbackDtrDcd(void)
1179 {
1180 HANDLE hcom;
1181 DWORD ModemStat = 0, defaultStat = 0;
1182 DCB dcb;
1183
1184 if (!loopback_dtr_dcd) return;
1185
1186 hcom = test_OpenComm(FALSE);
1187 if (hcom == INVALID_HANDLE_VALUE) return;
1188
1189 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1190 if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
1191 {
1192 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1193 CloseHandle(hcom);
1194 return;
1195 }
1196 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1197 /* XP returns some values in the low nibble, so mask them out*/
1198 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1199 if(defaultStat & MS_RLSD_ON)
1200 {
1201 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1202 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1203 ok ((ModemStat & MS_RLSD_ON) == 0, "RLSD didn't react: 0x%04x, expected 0x%04x\n",
1204 ModemStat, (defaultStat & ~MS_RLSD_ON));
1205 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1206 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1207 ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n",
1208 ModemStat, defaultStat);
1209 }
1210 else
1211 {
1212 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1213 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1214 ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON,
1215 "RLSD didn't react: 0x%04x, expected 0x%04x\n",
1216 ModemStat, (defaultStat | MS_RLSD_ON));
1217 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1218 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1219 ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n",
1220 ModemStat, defaultStat);
1221 }
1222
1223 CloseHandle(hcom);
1224 }
1225
test_LoopbackDtrDsr(void)1226 static void test_LoopbackDtrDsr(void)
1227 {
1228 HANDLE hcom;
1229 DWORD ModemStat = 0, defaultStat = 0;
1230 DCB dcb;
1231
1232 if (!loopback_dtr_dsr) return;
1233
1234 hcom = test_OpenComm(FALSE);
1235 if (hcom == INVALID_HANDLE_VALUE) return;
1236
1237 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1238 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1239 {
1240 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1241 CloseHandle(hcom);
1242 return;
1243 }
1244 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1245 /* XP returns some values in the low nibble, so mask them out*/
1246 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1247 if(defaultStat & MS_DSR_ON)
1248 {
1249 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1250 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1251 ok ((ModemStat & MS_DSR_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n",
1252 ModemStat, (defaultStat & ~MS_DSR_ON));
1253 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to clear DTR\n");
1254 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1255 ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n",
1256 ModemStat, defaultStat);
1257 }
1258 else
1259 {
1260 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1261 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1262 ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON,
1263 "CTS didn't react: 0x%04x,expected 0x%04x\n",
1264 ModemStat, (defaultStat | MS_DSR_ON));
1265 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1266 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1267 ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n",
1268 ModemStat, defaultStat);
1269 }
1270
1271 CloseHandle(hcom);
1272 }
1273
test_LoopbackDtrRing(void)1274 static void test_LoopbackDtrRing(void)
1275 {
1276 HANDLE hcom;
1277 DWORD ModemStat = 0, defaultStat = 0;
1278 DCB dcb;
1279
1280 if (!loopback_dtr_ring) return;
1281
1282 hcom = test_OpenComm(FALSE);
1283 if (hcom == INVALID_HANDLE_VALUE) return;
1284
1285 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1286 if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
1287 {
1288 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1289 CloseHandle(hcom);
1290 return;
1291 }
1292 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1293 /* XP returns some values in the low nibble, so mask them out*/
1294 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1295 if(defaultStat & MS_RING_ON)
1296 {
1297 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1298 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1299 ok ((ModemStat & MS_RING_ON) == 0, "RING didn't react: 0x%04x, expected 0x%04x\n",
1300 ModemStat, (defaultStat & ~MS_RING_ON));
1301 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1302 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1303 ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n",
1304 ModemStat, defaultStat);
1305 }
1306 else
1307 {
1308 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1309 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1310 ok ((ModemStat & MS_RING_ON) == MS_RING_ON,
1311 "RING didn't react: 0x%04x,expected 0x%04x\n",
1312 ModemStat, (defaultStat | MS_RING_ON));
1313 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1314 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1315 ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n",
1316 ModemStat, defaultStat);
1317 }
1318
1319 CloseHandle(hcom);
1320 }
1321
1322 /*
1323 * Set up a WaitCommEvent for anything in the receive buffer,
1324 * then write to TX to put a character
1325 * into the RX buffer
1326 * Need Loopback TX->RX
1327 */
1328
test_WaitRx(void)1329 static void test_WaitRx(void)
1330 {
1331 OVERLAPPED overlapped, overlapped_w;
1332 HANDLE hcom, hComPortEvent, hComWriteEvent;
1333 DWORD before, after, after1, diff, success_wait = FALSE, success_write;
1334 DWORD err_wait, err_write, written, evtmask=0;
1335
1336 if (!loopback_txd_rxd) return;
1337
1338 hcom = test_OpenComm(TRUE);
1339 if (hcom == INVALID_HANDLE_VALUE) return;
1340
1341 ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
1342 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1343 ok(hComPortEvent != 0, "CreateEvent failed\n");
1344 ZeroMemory( &overlapped, sizeof(overlapped));
1345 overlapped.hEvent = hComPortEvent;
1346
1347 hComWriteEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1348 ok(hComWriteEvent != NULL, "CreateEvent res %d\n", GetLastError());
1349 ZeroMemory( &overlapped_w, sizeof(overlapped_w));
1350 overlapped_w.hEvent = hComWriteEvent;
1351
1352 before = GetTickCount();
1353 success_wait = WaitCommEvent(hcom, &evtmask, &overlapped);
1354 err_wait = GetLastError();
1355 after = GetTickCount();
1356 trace("Success 0x%08x err %d evtmask 0x%08x\n", success_wait, err_wait, evtmask);
1357 ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1358 trace("overlapped WaitCommEvent returned.\n");
1359
1360 success_write= WriteFile(hcom, "X", 1, &written, &overlapped_w);
1361 err_write = GetLastError();
1362 ok(success_write || err_write == ERROR_IO_PENDING,
1363 "overlapped WriteFile failed, err %d\n",
1364 err_write);
1365
1366 if (!success_write && (err_write == ERROR_IO_PENDING)) {
1367 success_write = WaitForSingleObjectEx(hComWriteEvent, TIMEOUT, TRUE);
1368 err_write = GetLastError();
1369 ok(success_write == WAIT_OBJECT_0, "WaitForSingleObjectEx, res %d, err %d\n",
1370 success_write, err_write);
1371 }
1372 Sleep(TIMEOUT >>1);
1373 success_write = GetOverlappedResult(hcom, &overlapped_w, &written, FALSE);
1374 err_write = GetLastError();
1375
1376 trace("Write after Wait res 0x%08x err %d\n",success_write, err_write);
1377 ok(success_write && written ==1, "Write after Wait res 0x%08x err %d\n",
1378 success_write, err_write);
1379
1380 if (!success_wait && (err_wait == ERROR_IO_PENDING)) {
1381 success_wait = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1382 err_wait = GetLastError();
1383 ok(success_wait == WAIT_OBJECT_0, "wait hComPortEvent, res 0x%08x, err %d\n",
1384 success_wait, err_wait);
1385 }
1386 success_wait = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1387 err_wait = GetLastError();
1388 after1 = GetTickCount();
1389 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1390 success_wait, err_wait, evtmask, after-before, after1-before);
1391
1392 ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08x, expected 0x%08x\n",
1393 evtmask, EV_RXCHAR);
1394 diff = after1 - before;
1395 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1396 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1397
1398 CloseHandle(hcom);
1399 }
1400
1401 /* Change the controlling line after the given timeout to the given state
1402 By the loopback, this should trigger the WaitCommEvent
1403 */
toggle_ctlLine(LPVOID arg)1404 static DWORD CALLBACK toggle_ctlLine(LPVOID arg)
1405 {
1406 DWORD_PTR *args = arg;
1407 DWORD timeout = args[0];
1408 DWORD ctl = args[1];
1409 HANDLE hcom = (HANDLE) args[2];
1410 HANDLE hComPortEvent = (HANDLE) args[3];
1411 DWORD success, err;
1412
1413 trace("toggle_ctlLine timeout %d ctl 0x%08x handle %p\n", timeout, ctl, hcom );
1414 Sleep(timeout);
1415 ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08x failed\n", ctl);
1416 trace("toggle_ctline done\n");
1417 success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1418 err = GetLastError();
1419 trace("toggle_ctline WaitForSingleObjectEx res 0x%08x err %d\n",
1420 success, err);
1421 return 0;
1422 }
1423
1424 /*
1425 * Wait for a change in CTS
1426 * Needs Loopback from DTR to CTS
1427 */
test_WaitCts(void)1428 static void test_WaitCts(void)
1429 {
1430 DCB dcb;
1431 OVERLAPPED overlapped;
1432 HANDLE hcom, hComPortEvent, alarmThread;
1433 DWORD_PTR args[4];
1434 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1435
1436 if (!loopback_rts_cts) return;
1437
1438 hcom = test_OpenComm(TRUE);
1439 if (hcom == INVALID_HANDLE_VALUE) return;
1440
1441 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1442 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1443 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1444 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1445 if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
1446 {
1447 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1448 CloseHandle(hcom);
1449 return;
1450 }
1451 args[0]= TIMEOUT >>1;
1452 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1453 if(defaultStat & MS_CTS_ON)
1454 args[1] = CLRRTS;
1455 else
1456 args[1] = SETRTS;
1457 args[2]=(DWORD_PTR)hcom;
1458
1459 trace("test_WaitCts timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1460
1461 ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
1462 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1463 ok(hComPortEvent != 0, "CreateEvent failed\n");
1464 args[3] = (DWORD_PTR)hComPortEvent;
1465 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1466 /* Wait a minimum to let the thread start up */
1467 Sleep(10);
1468 trace("Thread created\n");
1469 ok(alarmThread !=0 , "CreateThread Failed\n");
1470
1471 ZeroMemory( &overlapped, sizeof(overlapped));
1472 overlapped.hEvent = hComPortEvent;
1473 before = GetTickCount();
1474 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1475 err = GetLastError();
1476 after = GetTickCount();
1477
1478 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1479 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1480 trace("overlapped WaitCommEvent returned.\n");
1481 if (!success && (err == ERROR_IO_PENDING))
1482 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1483 "WaitCts hComPortEvent failed\n");
1484 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1485 err = GetLastError();
1486 after1 = GetTickCount();
1487 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1488 success, err, evtmask, after-before, after1-before);
1489
1490 ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08x, expected 0x%08x\n",
1491 evtmask, EV_CTS);
1492 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1493 if(defaultStat & MS_CTS_ON)
1494 ok((evtmask & MS_CTS_ON) == 0,"CTS didn't change state!\n");
1495 else
1496 ok((evtmask & MS_CTS_ON), "CTS didn't change state!\n");
1497
1498 diff = after1 - before;
1499 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1500 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1501
1502 /*restore RTS Settings*/
1503 if(defaultStat & MS_CTS_ON)
1504 args[1] = SETRTS;
1505 else
1506 args[1] = CLRRTS;
1507
1508 CloseHandle(hcom);
1509 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1510 CloseHandle( alarmThread );
1511 }
1512
1513 /* Change the Comm Mask while a Wait is going on
1514 WaitCommevent should return with a EVTMASK set to zero
1515 */
reset_CommMask(LPVOID arg)1516 static DWORD CALLBACK reset_CommMask(LPVOID arg)
1517 {
1518 DWORD_PTR *args = arg;
1519 DWORD timeout = args[0];
1520 HANDLE hcom = (HANDLE) args[1];
1521
1522 trace(" Changing CommMask on the fly for handle %p after timeout %d\n",
1523 hcom, timeout);
1524 Sleep(timeout);
1525 ok(SetCommMask(hcom, 0),"SetCommMask %p failed\n", hcom);
1526 trace("SetCommMask changed\n");
1527 return 0;
1528 }
1529
1530 /* Set up a Wait for a change on CTS. We don't toggle any line, but we
1531 reset the CommMask and expect the wait to return with a mask of 0
1532 No special port connections needed
1533 */
test_AbortWaitCts(void)1534 static void test_AbortWaitCts(void)
1535 {
1536 DCB dcb;
1537 OVERLAPPED overlapped;
1538 HANDLE hcom, hComPortEvent, alarmThread;
1539 DWORD_PTR args[2];
1540 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
1541
1542 hcom = test_OpenComm(TRUE);
1543 if (hcom == INVALID_HANDLE_VALUE) return;
1544
1545 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1546 if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
1547 {
1548 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1549 CloseHandle(hcom);
1550 return;
1551 }
1552 args[0]= TIMEOUT >>1;
1553 args[1]= (DWORD_PTR)hcom;
1554
1555 trace("test_AbortWaitCts timeout %ld handle %p\n",args[0], hcom);
1556
1557 ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
1558 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1559 ok(hComPortEvent != 0, "CreateEvent failed\n");
1560 alarmThread = CreateThread(NULL, 0, reset_CommMask, args, 0, &alarmThreadId);
1561 /* Wait a minimum to let the thread start up */
1562 Sleep(10);
1563 trace("Thread created\n");
1564 ok(alarmThread !=0 , "CreateThread Failed\n");
1565
1566 ZeroMemory( &overlapped, sizeof(overlapped));
1567 overlapped.hEvent = hComPortEvent;
1568 before = GetTickCount();
1569 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1570 err = GetLastError();
1571 after = GetTickCount();
1572
1573 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1574 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1575 trace("overlapped WaitCommEvent returned.\n");
1576 if (!success && (err == ERROR_IO_PENDING))
1577 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1578 "AbortWaitCts hComPortEvent failed\n");
1579 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1580 err = GetLastError();
1581 after1 = GetTickCount();
1582 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1583 success, err, evtmask, after-before, after1-before);
1584
1585 ok(evtmask == 0, "Incorrect EventMask 0x%08x returned on Wait aborted bu SetCommMask, expected 0x%08x\n",
1586 evtmask, 0);
1587 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1588 diff = after1 - before;
1589 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1590 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1591
1592 CloseHandle(hcom);
1593 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1594 CloseHandle( alarmThread );
1595 }
1596
1597 /*
1598 * Wait for a change in DSR
1599 * Needs Loopback from DTR to DSR
1600 */
test_WaitDsr(void)1601 static void test_WaitDsr(void)
1602 {
1603 DCB dcb;
1604 OVERLAPPED overlapped;
1605 HANDLE hcom, hComPortEvent, alarmThread;
1606 DWORD_PTR args[3];
1607 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1608
1609 if (!loopback_dtr_dsr) return;
1610
1611 hcom = test_OpenComm(TRUE);
1612 if (hcom == INVALID_HANDLE_VALUE) return;
1613
1614 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1615 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1616 {
1617 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1618 CloseHandle(hcom);
1619 return;
1620 }
1621 args[0]= TIMEOUT >>1;
1622 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1623 if(defaultStat & MS_DSR_ON)
1624 args[1] = CLRDTR;
1625 else
1626 args[1] = SETDTR;
1627 args[2]= (DWORD_PTR)hcom;
1628
1629 trace("test_WaitDsr timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1630
1631 ok(SetCommMask(hcom, EV_DSR), "SetCommMask failed\n");
1632 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1633 ok(hComPortEvent != 0, "CreateEvent failed\n");
1634 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1635 ok(alarmThread !=0 , "CreateThread Failed\n");
1636
1637 ZeroMemory( &overlapped, sizeof(overlapped));
1638 overlapped.hEvent = hComPortEvent;
1639 before = GetTickCount();
1640 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1641 err = GetLastError();
1642 after = GetTickCount();
1643
1644 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1645 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1646 trace("overlapped WaitCommEvent returned.\n");
1647 if (!success && (err == ERROR_IO_PENDING))
1648 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1649 "wait hComPortEvent failed\n");
1650 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1651 err = GetLastError();
1652 after1 = GetTickCount();
1653 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1654 success, err, evtmask, after-before, after1-before);
1655
1656 ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08x, expected 0x%08x\n",
1657 evtmask, EV_DSR);
1658 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1659 if(defaultStat & MS_DSR_ON)
1660 ok((evtmask & MS_DSR_ON) == 0,"DTR didn't change state!\n");
1661 else
1662 ok((evtmask & MS_DSR_ON), "DTR didn't change state!\n");
1663
1664 diff = after1 - before;
1665 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1666 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1667
1668 /*restore RTS Settings*/
1669 if(defaultStat & MS_DSR_ON)
1670 args[1] = SETDTR;
1671 else
1672 args[1] = CLRDTR;
1673
1674 CloseHandle(hcom);
1675 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1676 CloseHandle( alarmThread );
1677 }
1678
1679 /*
1680 * Wait for a Ring
1681 * Needs Loopback from DTR to RING
1682 */
test_WaitRing(void)1683 static void test_WaitRing(void)
1684 {
1685 DCB dcb;
1686 OVERLAPPED overlapped;
1687 HANDLE hcom, hComPortEvent, alarmThread;
1688 DWORD_PTR args[3];
1689 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat;
1690 BOOL ret;
1691
1692 if (!loopback_dtr_ring) return;
1693
1694 hcom = test_OpenComm(TRUE);
1695 if (hcom == INVALID_HANDLE_VALUE) return;
1696
1697 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1698 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1699 {
1700 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1701 CloseHandle(hcom);
1702 return;
1703 }
1704 args[0]= TIMEOUT >>1;
1705 ok((ret = GetCommModemStatus(hcom, &defaultStat)), "GetCommModemStatus failed\n");
1706 if (!ret) {
1707 skip("modem status failed -> skip.\n");
1708 CloseHandle(hcom);
1709 return;
1710 }
1711 if(defaultStat & MS_RING_ON)
1712 args[1] = CLRDTR;
1713 else
1714 args[1] = SETDTR;
1715 args[2]=(DWORD_PTR) hcom;
1716
1717 trace("test_WaitRing timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1718
1719 ok(SetCommMask(hcom, EV_RING), "SetCommMask failed\n");
1720 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1721 ok(hComPortEvent != 0, "CreateEvent failed\n");
1722 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1723 ok(alarmThread !=0 , "CreateThread Failed\n");
1724
1725 ZeroMemory( &overlapped, sizeof(overlapped));
1726 overlapped.hEvent = hComPortEvent;
1727 before = GetTickCount();
1728 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1729 err = GetLastError();
1730 after = GetTickCount();
1731
1732 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1733 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1734 trace("overlapped WaitCommEvent returned.\n");
1735 if (!success && (err == ERROR_IO_PENDING))
1736 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1737 "wait hComPortEvent failed\n");
1738 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1739 err = GetLastError();
1740 after1 = GetTickCount();
1741 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1742 success, err, evtmask, after-before, after1-before);
1743
1744 ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08x, expected 0x%08x\n",
1745 evtmask, EV_RING);
1746 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1747 if(defaultStat & MS_RING_ON)
1748 ok((evtmask & MS_RING_ON) == 0,"DTR didn't change state!\n");
1749 else
1750 ok((evtmask & MS_RING_ON), "DTR didn't change state!\n");
1751
1752 diff = after1 - before;
1753 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1754 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1755
1756 /*restore RTS Settings*/
1757 if(defaultStat & MS_RING_ON)
1758 args[1] = SETDTR;
1759 else
1760 args[1] = CLRDTR;
1761
1762 CloseHandle(hcom);
1763 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1764 CloseHandle( alarmThread );
1765 }
1766 /*
1767 * Wait for a change in DCD
1768 * Needs Loopback from DTR to DCD
1769 */
test_WaitDcd(void)1770 static void test_WaitDcd(void)
1771 {
1772 DCB dcb;
1773 OVERLAPPED overlapped;
1774 HANDLE hcom, hComPortEvent, alarmThread;
1775 DWORD_PTR args[3];
1776 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1777
1778 if (!loopback_dtr_dcd) return;
1779
1780 hcom = test_OpenComm(TRUE);
1781 if (hcom == INVALID_HANDLE_VALUE) return;
1782
1783 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1784 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1785 {
1786 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1787 CloseHandle(hcom);
1788 return;
1789 }
1790 args[0]= TIMEOUT >>1;
1791 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1792 if(defaultStat & MS_RLSD_ON)
1793 args[1] = CLRDTR;
1794 else
1795 args[1] = SETDTR;
1796 args[2]= (DWORD_PTR)hcom;
1797
1798 trace("test_WaitDcd timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1799
1800 ok(SetCommMask(hcom, EV_RLSD), "SetCommMask failed\n");
1801 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1802 ok(hComPortEvent != 0, "CreateEvent failed\n");
1803 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1804 ok(alarmThread !=0 , "CreateThread Failed\n");
1805
1806 ZeroMemory( &overlapped, sizeof(overlapped));
1807 overlapped.hEvent = hComPortEvent;
1808 before = GetTickCount();
1809 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1810 err = GetLastError();
1811 after = GetTickCount();
1812
1813 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1814 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1815 trace("overlapped WaitCommEvent returned.\n");
1816 if (!success && (err == ERROR_IO_PENDING))
1817 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1818 "wait hComPortEvent failed\n");
1819 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1820 err = GetLastError();
1821 after1 = GetTickCount();
1822 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1823 success, err, evtmask, after-before, after1-before);
1824
1825 ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08x, expected 0x%08x\n",
1826 evtmask, EV_RLSD);
1827 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1828 if(defaultStat & MS_RLSD_ON)
1829 ok((evtmask & MS_RLSD_ON) == 0,"DTR didn't change state!\n");
1830 else
1831 ok((evtmask & MS_RLSD_ON), "DTR didn't change state!\n");
1832
1833 diff = after1 - before;
1834 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1835 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1836
1837 /*restore RTS Settings*/
1838 if(defaultStat & MS_RLSD_ON)
1839 args[1] = SETDTR;
1840 else
1841 args[1] = CLRDTR;
1842
1843 CloseHandle(hcom);
1844 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1845 CloseHandle( alarmThread );
1846 }
1847
1848 /*
1849 Set Break after timeout
1850 */
set_CommBreak(LPVOID arg)1851 static DWORD CALLBACK set_CommBreak(LPVOID arg)
1852 {
1853 DWORD_PTR *args = arg;
1854 DWORD timeout = args[0];
1855 HANDLE hcom = (HANDLE) args[1];
1856
1857 trace("SetCommBreak for handle %p after timeout %d\n",
1858 hcom, timeout);
1859 Sleep(timeout);
1860 ok(SetCommBreak(hcom),"SetCommBreak %p failed\n", hcom);
1861 trace("SetCommBreak done\n");
1862 return 0;
1863 }
1864
1865 /*
1866 Wait for the Break condition (TX resp. RX active)
1867 Needs Loopback TX-RX
1868 */
test_WaitBreak(void)1869 static void test_WaitBreak(void)
1870 {
1871 OVERLAPPED overlapped;
1872 HANDLE hcom, hComPortEvent, alarmThread;
1873 DWORD_PTR args[2];
1874 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
1875
1876 if (!loopback_txd_rxd) return;
1877
1878 hcom = test_OpenComm(TRUE);
1879 if (hcom == INVALID_HANDLE_VALUE) return;
1880
1881 ok(SetCommMask(hcom, EV_BREAK), "SetCommMask failed\n");
1882 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1883 ok(hComPortEvent != 0, "CreateEvent failed\n");
1884
1885 trace("test_WaitBreak\n");
1886 args[0]= TIMEOUT >>1;
1887 args[1]= (DWORD_PTR)hcom;
1888 alarmThread = CreateThread(NULL, 0, set_CommBreak, args, 0, &alarmThreadId);
1889 /* Wait a minimum to let the thread start up */
1890 Sleep(10);
1891 trace("Thread created\n");
1892 ok(alarmThread !=0 , "CreateThread Failed\n");
1893
1894 ZeroMemory( &overlapped, sizeof(overlapped));
1895 overlapped.hEvent = hComPortEvent;
1896 before = GetTickCount();
1897 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1898 err = GetLastError();
1899 after = GetTickCount();
1900
1901 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1902 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1903 trace("overlapped WaitCommEvent returned.\n");
1904
1905 if (!success && (err == ERROR_IO_PENDING))
1906 {
1907 success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1908 ok(!success, "wait hComPortEvent res %d\n", GetLastError());
1909 }
1910 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1911 err = GetLastError();
1912 after1 = GetTickCount();
1913 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1914 success, err, evtmask, after-before, after1-before);
1915
1916 ok(evtmask & EV_BREAK, "Failed to detect EV_BREAK: 0x%08x, expected 0x%08x\n",
1917 evtmask, EV_BREAK);
1918 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1919
1920 diff = after1 - before;
1921 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1922 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1923
1924 ok(ClearCommBreak(hcom), "ClearCommBreak failed\n");
1925
1926 CloseHandle(hcom);
1927 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1928 CloseHandle( alarmThread );
1929 }
1930
test_stdio(void)1931 static void test_stdio(void)
1932 {
1933 DCB dcb;
1934
1935 /* cygwin tries this to determine the stdin handle type */
1936 ok( !GetCommState( GetStdHandle(STD_INPUT_HANDLE), &dcb ), "GetCommState succeeded on stdin\n" );
1937 ok( GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_FUNCTION,
1938 "got error %u\n", GetLastError() );
1939 }
1940
test_WaitCommEvent(void)1941 static void test_WaitCommEvent(void)
1942 {
1943 HANDLE hcom;
1944 DWORD evtmask, ret, bytes, before, after, last_event_time;
1945 OVERLAPPED ovl_wait;
1946
1947 hcom = test_OpenComm(TRUE);
1948 if (hcom == INVALID_HANDLE_VALUE) return;
1949
1950 test_GetModemStatus(hcom);
1951
1952 ret = SetCommMask(hcom, 0x1fff);
1953 ok(ret, "SetCommMask error %d\n", GetLastError());
1954
1955 S(U(ovl_wait)).Offset = 0;
1956 S(U(ovl_wait)).OffsetHigh = 0;
1957 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
1958
1959 trace("waiting 10 secs for com port events (turn on/off the device)...\n");
1960 last_event_time = 0;
1961 before = GetTickCount();
1962 do
1963 {
1964 evtmask = 0;
1965 SetLastError(0xdeadbeef);
1966 ret = WaitCommEvent(hcom, &evtmask, &ovl_wait);
1967 ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError());
1968 if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */
1969 for (;;)
1970 {
1971 ret = WaitForSingleObject(ovl_wait.hEvent, 500);
1972 after = GetTickCount();
1973 if (ret == WAIT_OBJECT_0)
1974 {
1975 last_event_time = after;
1976 ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
1977 ok(ret, "GetOverlappedResult reported error %d\n", GetLastError());
1978 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
1979 trace("WaitCommEvent: got events %#x\n", evtmask);
1980 test_GetModemStatus(hcom);
1981 break;
1982 }
1983 else
1984 {
1985 if (last_event_time || after - before >= 10000) goto done;
1986 }
1987 }
1988 } while (after - before < 10000);
1989
1990 done:
1991 CloseHandle(ovl_wait.hEvent);
1992 CloseHandle(hcom);
1993 }
1994
test_FlushFileBuffers(void)1995 static void test_FlushFileBuffers(void)
1996 {
1997 HANDLE hcom;
1998 DWORD ret, bytes, errors;
1999 COMSTAT stat;
2000
2001 hcom = test_OpenComm(FALSE);
2002 if (hcom == INVALID_HANDLE_VALUE) return;
2003
2004 ret = WriteFile(hcom, "\0\0\0\0\0\0\0", 7, &bytes, NULL);
2005 ok(ret, "WriteFile error %d\n", GetLastError());
2006 ok(bytes == 7, "expected 7, got %u\n", bytes);
2007
2008 ret = FlushFileBuffers(hcom);
2009 ok(ret, "FlushFileBuffers error %d\n", GetLastError());
2010
2011 ret = ClearCommError(hcom, &errors, &stat);
2012 ok(ret, "ClearCommError error %d\n", GetLastError());
2013 ok(stat.cbInQue == 0, "expected 0, got %d bytes in InQueue\n", stat.cbInQue);
2014 ok(stat.cbOutQue == 0, "expected 0, got %d bytes in OutQueue\n", stat.cbOutQue);
2015 ok(errors == 0, "expected errors 0, got %#x\n", errors);
2016
2017 CloseHandle(hcom);
2018 }
2019
test_read_write(void)2020 static void test_read_write(void)
2021 {
2022 static const char atz[]="ATZ\r\n";
2023 char buf[256];
2024 HANDLE hcom;
2025 DCB dcb;
2026 COMMTIMEOUTS timeouts;
2027 DWORD ret, bytes, status, evtmask, before, after, last_event_time;
2028 OVERLAPPED ovl_wait;
2029 IO_STATUS_BLOCK iob;
2030 LARGE_INTEGER offset;
2031 LONG i;
2032
2033 if (!pNtReadFile || !pNtWriteFile)
2034 {
2035 win_skip("not running on NT, skipping test\n");
2036 return;
2037 }
2038
2039 hcom = test_OpenComm(TRUE);
2040 if (hcom == INVALID_HANDLE_VALUE) return;
2041
2042 ret = GetCommState(hcom, &dcb);
2043 ok(ret, "GetCommState error %d\n", GetLastError());
2044 dcb.BaudRate = 9600;
2045 dcb.ByteSize = 8;
2046 dcb.Parity = NOPARITY;
2047 dcb.fRtsControl = RTS_CONTROL_ENABLE;
2048 dcb.fDtrControl = DTR_CONTROL_ENABLE;
2049 dcb.StopBits = ONESTOPBIT;
2050 ret = SetCommState(hcom, &dcb);
2051 ok(ret, "SetCommState error %d\n", GetLastError());
2052
2053 memset(&timeouts, 0, sizeof(timeouts));
2054 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
2055 ret = SetCommTimeouts(hcom, &timeouts);
2056 ok(ret,"SetCommTimeouts error %d\n", GetLastError());
2057
2058 ret = SetupComm(hcom, 1024, 1024);
2059 ok(ret, "SetUpComm error %d\n", GetLastError());
2060
2061 bytes = 0xdeadbeef;
2062 SetLastError(0xdeadbeef);
2063 ret = WriteFile(hcom, atz, 0, &bytes, NULL);
2064 ok(!ret, "WriteFile should fail\n");
2065 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2066 ok(bytes == 0, "bytes %u\n", bytes);
2067
2068 U(iob).Status = -1;
2069 iob.Information = -1;
2070 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, NULL, NULL);
2071 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
2072 ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
2073 ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
2074
2075 for (i = -20; i < 20; i++)
2076 {
2077 U(iob).Status = -1;
2078 iob.Information = -1;
2079 offset.QuadPart = (LONGLONG)i;
2080 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, &offset, NULL);
2081 if (i >= 0 || i == -1)
2082 {
2083 ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
2084 ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status);
2085 ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
2086 }
2087 else
2088 {
2089 ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
2090 ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status);
2091 ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
2092 }
2093 }
2094
2095 U(iob).Status = -1;
2096 iob.Information = -1;
2097 offset.QuadPart = 0;
2098 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, sizeof(atz), &offset, NULL);
2099 ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status);
2100 /* Under Windows checking IO_STATUS_BLOCK right after the call leads
2101 * to races, iob.Status is either -1 or STATUS_SUCCESS, which means
2102 * that it's set only when the operation completes.
2103 */
2104 ret = WaitForSingleObject(hcom, TIMEOUT);
2105 if (ret == WAIT_TIMEOUT)
2106 {
2107 skip("Probably modem is not connected.\n");
2108 CloseHandle(hcom);
2109 return;
2110 }
2111 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret);
2112 ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status);
2113 ok(iob.Information == sizeof(atz), "expected sizeof(atz), got %lu\n", iob.Information);
2114
2115 ret = SetCommMask(hcom, EV_RXCHAR);
2116 ok(ret, "SetCommMask error %d\n", GetLastError());
2117
2118 S(U(ovl_wait)).Offset = 0;
2119 S(U(ovl_wait)).OffsetHigh = 0;
2120 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2121
2122 trace("waiting 3 secs for modem response...\n");
2123 last_event_time = 0;
2124 before = GetTickCount();
2125 do
2126 {
2127 evtmask = 0;
2128 SetLastError(0xdeadbeef);
2129 ret = WaitCommEvent(hcom, &evtmask, &ovl_wait);
2130 ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError());
2131 if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */
2132 for (;;)
2133 {
2134 ret = WaitForSingleObject(ovl_wait.hEvent, 100);
2135 after = GetTickCount();
2136 if (ret == WAIT_OBJECT_0)
2137 {
2138 trace("got modem response.\n");
2139
2140 last_event_time = after;
2141 ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
2142 ok(ret, "GetOverlappedResult reported error %d\n", GetLastError());
2143 ok(bytes == sizeof(evtmask), "expected sizeof(evtmask), got %u\n", bytes);
2144 ok(evtmask & EV_RXCHAR, "EV_RXCHAR should be set\n");
2145
2146 bytes = 0xdeadbeef;
2147 SetLastError(0xdeadbeef);
2148 ret = ReadFile(hcom, buf, 0, &bytes, NULL);
2149 ok(!ret, "ReadFile should fail\n");
2150 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2151 ok(bytes == 0, "bytes %u\n", bytes);
2152
2153 U(iob).Status = -1;
2154 iob.Information = -1;
2155 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, NULL, NULL);
2156 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
2157 ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
2158 ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
2159
2160 for (i = -20; i < 20; i++)
2161 {
2162 U(iob).Status = -1;
2163 iob.Information = -1;
2164 offset.QuadPart = (LONGLONG)i;
2165 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, &offset, NULL);
2166 if (i >= 0)
2167 {
2168 ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
2169 ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status);
2170 ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
2171 }
2172 else
2173 {
2174 ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
2175 ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status);
2176 ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
2177 }
2178 }
2179
2180 U(iob).Status = -1;
2181 iob.Information = -1;
2182 offset.QuadPart = 0;
2183 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 1, &offset, NULL);
2184 ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", status);
2185 ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status);
2186 ok(iob.Information == 1, "expected 1, got %lu\n", iob.Information);
2187 goto done;
2188 }
2189 else
2190 {
2191 if (last_event_time || after - before >= 3000) goto done;
2192 }
2193 }
2194 } while (after - before < 3000);
2195
2196 done:
2197 CloseHandle(ovl_wait.hEvent);
2198 CloseHandle(hcom);
2199 }
2200
START_TEST(comm)2201 START_TEST(comm)
2202 {
2203 HMODULE ntdll = GetModuleHandleA("ntdll.dll");
2204 if (ntdll)
2205 {
2206 pNtReadFile = (void *)GetProcAddress(ntdll, "NtReadFile");
2207 pNtWriteFile = (void *)GetProcAddress(ntdll, "NtWriteFile");
2208 }
2209
2210 test_ClearCommError(); /* keep it the very first test */
2211 test_FlushFileBuffers();
2212 test_BuildCommDCB();
2213 test_ReadTimeOut();
2214 test_waittxempty();
2215 test_non_pending_errors();
2216 test_LoopbackRead();
2217 test_LoopbackCtsRts();
2218 test_LoopbackDtrDsr();
2219 test_LoopbackDtrRing();
2220 test_LoopbackDtrDcd();
2221 test_WaitRx();
2222 test_WaitCts();
2223 test_AbortWaitCts();
2224 test_WaitDsr();
2225 test_WaitRing();
2226 test_WaitDcd();
2227 test_WaitBreak();
2228 test_stdio();
2229 test_read_write();
2230
2231 if (!winetest_interactive)
2232 {
2233 skip("interactive tests (set WINETEST_INTERACTIVE=1)\n");
2234 return;
2235 }
2236
2237 test_WaitCommEvent();
2238 }
2239