]> sigrok.org Git - libserialport.git/blame - serialport.c
Abstract all time handling operations.
[libserialport.git] / serialport.c
CommitLineData
74510d4b
ML
1/*
2 * This file is part of the libserialport project.
3 *
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
f77bb46d
ML
5 * Copyright (C) 2010-2015 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2013-2015 Martin Ling <martin-libserialport@earth.li>
31b3a8f5 7 * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
a93fb468 8 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
74510d4b
ML
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
1a584c45 24#include <config.h>
f6a1fb65 25#include "libserialport.h"
e33dcf90 26#include "libserialport_internal.h"
da2748bf 27
6c6aebe7 28static const struct std_baudrate std_baudrates[] = {
da2748bf
ML
29#ifdef _WIN32
30 /*
31 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
32 * have documented CBR_* macros.
33 */
34 BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
35 BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
eac329d2 36 BAUD(115200), BAUD(128000), BAUD(256000),
da2748bf 37#else
eac329d2
UH
38 BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
39 BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
40 BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
41 BAUD(230400),
da2748bf 42#if !defined(__APPLE__) && !defined(__OpenBSD__)
eac329d2 43 BAUD(460800),
da2748bf
ML
44#endif
45#endif
46};
47
6c6aebe7
UH
48#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
49
863b35e6
ML
50void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
51
eb6ed20f
ML
52static enum sp_return get_config(struct sp_port *port, struct port_data *data,
53 struct sp_port_config *config);
e33dcf90 54
eb6ed20f
ML
55static enum sp_return set_config(struct sp_port *port, struct port_data *data,
56 const struct sp_port_config *config);
80186526 57
bd0fb609 58#ifndef _WIN32
9a7945af
ML
59
60/* Timing abstraction */
61
62struct time {
63 struct timeval tv;
64};
65
66#define TIME_ZERO {.tv = {0, 0}}
67#define TIME_MS(ms) {.tv = {ms / 1000, (ms % 1000) * 1000}}
68
69static void time_get(struct time *time)
573feabc 70{
f40ea9d4
ML
71#ifdef HAVE_CLOCK_GETTIME
72 struct timespec ts;
7fb9a7b0
ML
73 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
74 clock_gettime(CLOCK_REALTIME, &ts);
9a7945af
ML
75 time->tv.tv_sec = ts.tv_sec;
76 time->tv.tv_usec = ts.tv_nsec / 1000;
192e7749
ML
77#elif defined(__APPLE__)
78 mach_timebase_info_data_t info;
79 mach_timebase_info(&info);
80 uint64_t ticks = mach_absolute_time();
81 uint64_t ns = (ticks * info.numer) / info.denom;
9a7945af
ML
82 time->tv.tv_sec = ns / 1000000000;
83 time->tv.tv_usec = (ns % 1000000000) / 1000;
f40ea9d4 84#else
9a7945af 85 gettimeofday(&time->tv, NULL);
f40ea9d4 86#endif
573feabc 87}
9a7945af
ML
88
89static void time_set_ms(struct time *time, unsigned int ms)
90{
91 time->tv.tv_sec = ms / 1000;
92 time->tv.tv_usec = (ms % 1000) * 1000;
93}
94
95static void time_add(const struct time *a,
96 const struct time *b, struct time *result)
97{
98 timeradd(&a->tv, &b->tv, &result->tv);
99}
100
101static void time_sub(const struct time *a,
102 const struct time *b, struct time *result)
103{
104 timersub(&a->tv, &b->tv, &result->tv);
105}
106
107static bool time_greater(const struct time *a, const struct time *b)
108{
109 return timercmp(&a->tv, &b->tv, >);
110}
111
112static void time_as_timeval(const struct time *time, struct timeval *tv)
113{
114 *tv = time->tv;
115}
116
117static unsigned int time_as_ms(const struct time *time)
118{
119 return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
120}
121
bd0fb609 122#endif
573feabc 123
970f279a 124SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
d54e9004
ML
125{
126 struct sp_port *port;
5a8810e2 127#ifndef NO_PORT_METADATA
a93fb468 128 enum sp_return ret;
5a8810e2 129#endif
5919c913 130 int len;
d54e9004 131
c33efc48
ML
132 TRACE("%s, %p", portname, port_ptr);
133
32b5ac05 134 if (!port_ptr)
c33efc48 135 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
32b5ac05 136
77f262c4
ML
137 *port_ptr = NULL;
138
d4babed2 139 if (!portname)
c33efc48 140 RETURN_ERROR(SP_ERR_ARG, "Null port name");
d4babed2 141
7890cef6 142 DEBUG_FMT("Building structure for port %s", portname);
ea667be7 143
95bad38c
ST
144#if !defined(_WIN32) && defined(HAVE_REALPATH)
145 /*
146 * get_port_details() below tries to be too smart and figure out
147 * some transport properties from the port name which breaks with
148 * symlinks. Therefore we canonicalize the portname first.
149 */
150 char pathbuf[PATH_MAX + 1];
151 char *res = realpath(portname, pathbuf);
152 if (!res)
153 RETURN_ERROR(SP_ERR_ARG, "Could not retrieve realpath behind port name");
154
155 portname = pathbuf;
156#endif
157
d54e9004 158 if (!(port = malloc(sizeof(struct sp_port))))
c33efc48 159 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
d54e9004 160
5919c913
ML
161 len = strlen(portname) + 1;
162
eac329d2 163 if (!(port->name = malloc(len))) {
d54e9004 164 free(port);
c33efc48 165 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
d54e9004
ML
166 }
167
168 memcpy(port->name, portname, len);
169
8f471c66 170#ifdef _WIN32
e31f2c6b 171 port->usb_path = NULL;
8f471c66 172 port->hdl = INVALID_HANDLE_VALUE;
39df7833
ML
173 port->write_buf = NULL;
174 port->write_buf_size = 0;
8f471c66
ML
175#else
176 port->fd = -1;
177#endif
178
e33dcf90
ML
179 port->description = NULL;
180 port->transport = SP_TRANSPORT_NATIVE;
181 port->usb_bus = -1;
182 port->usb_address = -1;
183 port->usb_vid = -1;
184 port->usb_pid = -1;
185 port->usb_manufacturer = NULL;
186 port->usb_product = NULL;
187 port->usb_serial = NULL;
188 port->bluetooth_address = NULL;
189
e4ce975a 190#ifndef NO_PORT_METADATA
e33dcf90 191 if ((ret = get_port_details(port)) != SP_OK) {
a93fb468
AJ
192 sp_free_port(port);
193 return ret;
194 }
e4ce975a 195#endif
a93fb468 196
77f262c4
ML
197 *port_ptr = port;
198
c33efc48 199 RETURN_OK();
d54e9004
ML
200}
201
970f279a 202SP_API char *sp_get_port_name(const struct sp_port *port)
1c5aae9d
ML
203{
204 TRACE("%p", port);
205
206 if (!port)
207 return NULL;
208
9caa2e86 209 RETURN_STRING(port->name);
1c5aae9d
ML
210}
211
f1480939 212SP_API char *sp_get_port_description(const struct sp_port *port)
a93fb468
AJ
213{
214 TRACE("%p", port);
215
216 if (!port || !port->description)
217 return NULL;
218
9caa2e86 219 RETURN_STRING(port->description);
a93fb468
AJ
220}
221
ad036cc8 222SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port)
a93fb468
AJ
223{
224 TRACE("%p", port);
225
226 if (!port)
227 RETURN_ERROR(SP_ERR_ARG, "Null port");
228
9caa2e86 229 RETURN_INT(port->transport);
a93fb468
AJ
230}
231
970f279a
AJ
232SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
233 int *usb_bus,int *usb_address)
a93fb468
AJ
234{
235 TRACE("%p", port);
236
237 if (!port)
238 RETURN_ERROR(SP_ERR_ARG, "Null port");
239 if (port->transport != SP_TRANSPORT_USB)
240 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
65172bef
AJ
241 if (port->usb_bus < 0 || port->usb_address < 0)
242 RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available");
a93fb468 243
dc422c04
UH
244 if (usb_bus)
245 *usb_bus = port->usb_bus;
246 if (usb_address)
247 *usb_address = port->usb_address;
a93fb468
AJ
248
249 RETURN_OK();
250}
251
970f279a
AJ
252SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port,
253 int *usb_vid, int *usb_pid)
a93fb468
AJ
254{
255 TRACE("%p", port);
256
257 if (!port)
258 RETURN_ERROR(SP_ERR_ARG, "Null port");
259 if (port->transport != SP_TRANSPORT_USB)
260 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
65172bef
AJ
261 if (port->usb_vid < 0 || port->usb_pid < 0)
262 RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available");
a93fb468 263
dc422c04
UH
264 if (usb_vid)
265 *usb_vid = port->usb_vid;
266 if (usb_pid)
267 *usb_pid = port->usb_pid;
a93fb468
AJ
268
269 RETURN_OK();
270}
271
970f279a 272SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port)
a93fb468
AJ
273{
274 TRACE("%p", port);
275
276 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer)
277 return NULL;
278
9caa2e86 279 RETURN_STRING(port->usb_manufacturer);
a93fb468
AJ
280}
281
970f279a 282SP_API char *sp_get_port_usb_product(const struct sp_port *port)
a93fb468
AJ
283{
284 TRACE("%p", port);
285
286 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product)
287 return NULL;
288
9caa2e86 289 RETURN_STRING(port->usb_product);
a93fb468
AJ
290}
291
970f279a 292SP_API char *sp_get_port_usb_serial(const struct sp_port *port)
a93fb468
AJ
293{
294 TRACE("%p", port);
295
296 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial)
297 return NULL;
298
9caa2e86 299 RETURN_STRING(port->usb_serial);
a93fb468
AJ
300}
301
970f279a 302SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port)
a93fb468
AJ
303{
304 TRACE("%p", port);
305
306 if (!port || port->transport != SP_TRANSPORT_BLUETOOTH
307 || !port->bluetooth_address)
308 return NULL;
309
9caa2e86 310 RETURN_STRING(port->bluetooth_address);
a93fb468
AJ
311}
312
970f279a
AJ
313SP_API enum sp_return sp_get_port_handle(const struct sp_port *port,
314 void *result_ptr)
3c126654 315{
00d8c56d 316 TRACE("%p, %p", port, result_ptr);
3c126654
ML
317
318 if (!port)
319 RETURN_ERROR(SP_ERR_ARG, "Null port");
5f64c285
UH
320 if (!result_ptr)
321 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
3c126654
ML
322
323#ifdef _WIN32
324 HANDLE *handle_ptr = result_ptr;
325 *handle_ptr = port->hdl;
326#else
327 int *fd_ptr = result_ptr;
328 *fd_ptr = port->fd;
329#endif
330
331 RETURN_OK();
332}
333
970f279a
AJ
334SP_API enum sp_return sp_copy_port(const struct sp_port *port,
335 struct sp_port **copy_ptr)
32b5ac05 336{
c33efc48
ML
337 TRACE("%p, %p", port, copy_ptr);
338
32b5ac05 339 if (!copy_ptr)
c33efc48 340 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
32b5ac05
ML
341
342 *copy_ptr = NULL;
343
c33efc48
ML
344 if (!port)
345 RETURN_ERROR(SP_ERR_ARG, "Null port");
346
347 if (!port->name)
348 RETURN_ERROR(SP_ERR_ARG, "Null port name");
32b5ac05 349
ea667be7
ML
350 DEBUG("Copying port structure");
351
9caa2e86 352 RETURN_INT(sp_get_port_by_name(port->name, copy_ptr));
32b5ac05
ML
353}
354
970f279a 355SP_API void sp_free_port(struct sp_port *port)
e3b2f7a4 356{
c33efc48
ML
357 TRACE("%p", port);
358
00d8c56d 359 if (!port) {
c33efc48
ML
360 DEBUG("Null port");
361 RETURN();
362 }
e3b2f7a4 363
ea667be7
ML
364 DEBUG("Freeing port structure");
365
e3b2f7a4
ML
366 if (port->name)
367 free(port->name);
a93fb468
AJ
368 if (port->description)
369 free(port->description);
370 if (port->usb_manufacturer)
371 free(port->usb_manufacturer);
372 if (port->usb_product)
373 free(port->usb_product);
374 if (port->usb_serial)
375 free(port->usb_serial);
376 if (port->bluetooth_address)
377 free(port->bluetooth_address);
378#ifdef _WIN32
379 if (port->usb_path)
380 free(port->usb_path);
39df7833
ML
381 if (port->write_buf)
382 free(port->write_buf);
a93fb468 383#endif
e3b2f7a4
ML
384
385 free(port);
c33efc48
ML
386
387 RETURN();
e3b2f7a4
ML
388}
389
970f279a
AJ
390SP_PRIV struct sp_port **list_append(struct sp_port **list,
391 const char *portname)
3b63f34d
ML
392{
393 void *tmp;
394 unsigned int count;
f92f1f0c 395
81243567
UH
396 for (count = 0; list[count]; count++)
397 ;
d54e9004 398 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
3b63f34d
ML
399 goto fail;
400 list = tmp;
77f262c4 401 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
3b63f34d 402 goto fail;
db2794ce 403 list[count + 1] = NULL;
3b63f34d 404 return list;
f92f1f0c 405
3b63f34d
ML
406fail:
407 sp_free_port_list(list);
408 return NULL;
409}
410
970f279a 411SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr)
3b63f34d 412{
23e7fa37 413#ifndef NO_ENUMERATION
d54e9004 414 struct sp_port **list;
48a4076f 415 int ret;
23e7fa37 416#endif
24c1a4bb 417
c33efc48
ML
418 TRACE("%p", list_ptr);
419
dec10e31
ML
420 if (!list_ptr)
421 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
422
63926415
UH
423 *list_ptr = NULL;
424
8d12e620
ML
425#ifdef NO_ENUMERATION
426 RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
427#else
ea667be7
ML
428 DEBUG("Enumerating ports");
429
8d12e620 430 if (!(list = malloc(sizeof(struct sp_port *))))
c33efc48 431 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
24c1a4bb
ML
432
433 list[0] = NULL;
3b63f34d 434
48a4076f 435 ret = list_ports(&list);
77f262c4 436
8d12e620 437 if (ret == SP_OK) {
77f262c4 438 *list_ptr = list;
8d12e620
ML
439 } else {
440 sp_free_port_list(list);
77f262c4
ML
441 *list_ptr = NULL;
442 }
8d12e620
ML
443
444 RETURN_CODEVAL(ret);
445#endif
3b63f34d
ML
446}
447
970f279a 448SP_API void sp_free_port_list(struct sp_port **list)
3b63f34d
ML
449{
450 unsigned int i;
f92f1f0c 451
c33efc48
ML
452 TRACE("%p", list);
453
dec10e31
ML
454 if (!list) {
455 DEBUG("Null list");
456 RETURN();
457 }
458
ea667be7
ML
459 DEBUG("Freeing port list");
460
3b63f34d 461 for (i = 0; list[i]; i++)
e3b2f7a4 462 sp_free_port(list[i]);
3b63f34d 463 free(list);
c33efc48
ML
464
465 RETURN();
3b63f34d
ML
466}
467
c33efc48 468#define CHECK_PORT() do { \
dc422c04 469 if (!port) \
c33efc48 470 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
dc422c04 471 if (!port->name) \
dec10e31
ML
472 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
473} while (0)
474#ifdef _WIN32
475#define CHECK_PORT_HANDLE() do { \
c33efc48 476 if (port->hdl == INVALID_HANDLE_VALUE) \
8062087a 477 RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
dec10e31 478} while (0)
74510d4b 479#else
dec10e31 480#define CHECK_PORT_HANDLE() do { \
c33efc48 481 if (port->fd < 0) \
8062087a 482 RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
dec10e31 483} while (0)
74510d4b 484#endif
dec10e31
ML
485#define CHECK_OPEN_PORT() do { \
486 CHECK_PORT(); \
487 CHECK_PORT_HANDLE(); \
488} while (0)
74510d4b 489
47fcf8ec
ML
490#ifdef WIN32
491/** To be called after port receive buffer is emptied. */
492static enum sp_return restart_wait(struct sp_port *port)
493{
494 DWORD wait_result;
495
496 if (port->wait_running) {
497 /* Check status of running wait operation. */
498 if (GetOverlappedResult(port->hdl, &port->wait_ovl,
499 &wait_result, FALSE)) {
500 DEBUG("Previous wait completed");
501 port->wait_running = FALSE;
502 } else if (GetLastError() == ERROR_IO_INCOMPLETE) {
503 DEBUG("Previous wait still running");
504 RETURN_OK();
505 } else {
506 RETURN_FAIL("GetOverlappedResult() failed");
507 }
508 }
509
510 if (!port->wait_running) {
511 /* Start new wait operation. */
512 if (WaitCommEvent(port->hdl, &port->events,
513 &port->wait_ovl)) {
514 DEBUG("New wait returned, events already pending");
515 } else if (GetLastError() == ERROR_IO_PENDING) {
516 DEBUG("New wait running in background");
517 port->wait_running = TRUE;
518 } else {
519 RETURN_FAIL("WaitCommEvent() failed");
520 }
521 }
522
523 RETURN_OK();
524}
525#endif
526
970f279a 527SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
74510d4b 528{
bccc7c9f
ML
529 struct port_data data;
530 struct sp_port_config config;
531 enum sp_return ret;
532
00d8c56d 533 TRACE("%p, 0x%x", port, flags);
c33efc48 534
dec10e31
ML
535 CHECK_PORT();
536
276ef1b9 537 if (flags > SP_MODE_READ_WRITE)
dec10e31 538 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
74510d4b 539
7890cef6 540 DEBUG_FMT("Opening port %s", port->name);
ea667be7 541
74510d4b 542#ifdef _WIN32
537942c9 543 DWORD desired_access = 0, flags_and_attributes = 0, errors;
99945a1f 544 char *escaped_port_name;
537942c9 545 COMSTAT status;
99945a1f
ML
546
547 /* Prefix port name with '\\.\' to work with ports above COM9. */
e48f0ece 548 if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
c33efc48 549 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
99945a1f
ML
550 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
551
74510d4b 552 /* Map 'flags' to the OS-specific settings. */
e3dcf906 553 flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
a036341b
ML
554 if (flags & SP_MODE_READ)
555 desired_access |= GENERIC_READ;
556 if (flags & SP_MODE_WRITE)
74510d4b 557 desired_access |= GENERIC_WRITE;
74510d4b 558
99945a1f 559 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
74510d4b 560 OPEN_EXISTING, flags_and_attributes, 0);
99945a1f
ML
561
562 free(escaped_port_name);
563
74510d4b 564 if (port->hdl == INVALID_HANDLE_VALUE)
dc422c04 565 RETURN_FAIL("Port CreateFile() failed");
e3dcf906
ML
566
567 /* All timeouts initially disabled. */
568 port->timeouts.ReadIntervalTimeout = 0;
569 port->timeouts.ReadTotalTimeoutMultiplier = 0;
570 port->timeouts.ReadTotalTimeoutConstant = 0;
571 port->timeouts.WriteTotalTimeoutMultiplier = 0;
572 port->timeouts.WriteTotalTimeoutConstant = 0;
a3cb91f5 573
e3dcf906 574 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) {
a3cb91f5
ML
575 sp_close(port);
576 RETURN_FAIL("SetCommTimeouts() failed");
577 }
e3dcf906
ML
578
579 /* Prepare OVERLAPPED structures. */
6f1186aa
ML
580#define INIT_OVERLAPPED(ovl) do { \
581 memset(&port->ovl, 0, sizeof(port->ovl)); \
582 port->ovl.hEvent = INVALID_HANDLE_VALUE; \
583 if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \
584 == INVALID_HANDLE_VALUE) { \
585 sp_close(port); \
586 RETURN_FAIL(#ovl "CreateEvent() failed"); \
587 } \
588} while (0)
589
590 INIT_OVERLAPPED(read_ovl);
591 INIT_OVERLAPPED(write_ovl);
592 INIT_OVERLAPPED(wait_ovl);
593
594 /* Set event mask for RX and error events. */
595 if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) {
e3dcf906 596 sp_close(port);
6f1186aa 597 RETURN_FAIL("SetCommMask() failed");
e3dcf906 598 }
6f1186aa 599
e3dcf906 600 port->writing = FALSE;
47fcf8ec 601 port->wait_running = FALSE;
e3dcf906 602
47fcf8ec
ML
603 ret = restart_wait(port);
604
605 if (ret < 0) {
606 sp_close(port);
607 RETURN_CODEVAL(ret);
608 }
74510d4b 609#else
fa106ef1 610 int flags_local = O_NONBLOCK | O_NOCTTY | O_CLOEXEC;
f92f1f0c 611
74510d4b 612 /* Map 'flags' to the OS-specific settings. */
276ef1b9 613 if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE)
74510d4b 614 flags_local |= O_RDWR;
a036341b 615 else if (flags & SP_MODE_READ)
74510d4b 616 flags_local |= O_RDONLY;
a036341b
ML
617 else if (flags & SP_MODE_WRITE)
618 flags_local |= O_WRONLY;
74510d4b
ML
619
620 if ((port->fd = open(port->name, flags_local)) < 0)
c33efc48 621 RETURN_FAIL("open() failed");
bccc7c9f 622#endif
9cb98459 623
e33ab9aa
ML
624 ret = get_config(port, &data, &config);
625
eac329d2 626 if (ret < 0) {
e33ab9aa 627 sp_close(port);
c33efc48 628 RETURN_CODEVAL(ret);
e33ab9aa 629 }
9cb98459 630
bccc7c9f
ML
631 /* Set sane port settings. */
632#ifdef _WIN32
633 data.dcb.fBinary = TRUE;
634 data.dcb.fDsrSensitivity = FALSE;
635 data.dcb.fErrorChar = FALSE;
636 data.dcb.fNull = FALSE;
34442106 637 data.dcb.fAbortOnError = FALSE;
bccc7c9f 638#else
b251be4b 639 /* Turn off all fancy termios tricks, give us a raw channel. */
c3e05092
UH
640 data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL);
641#ifdef IUCLC
642 data.term.c_iflag &= ~IUCLC;
643#endif
644 data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
645#ifdef OLCUC
646 data.term.c_oflag &= ~OLCUC;
647#endif
648#ifdef NLDLY
649 data.term.c_oflag &= ~NLDLY;
650#endif
651#ifdef CRDLY
652 data.term.c_oflag &= ~CRDLY;
653#endif
654#ifdef TABDLY
655 data.term.c_oflag &= ~TABDLY;
656#endif
657#ifdef BSDLY
658 data.term.c_oflag &= ~BSDLY;
659#endif
660#ifdef VTDLY
661 data.term.c_oflag &= ~VTDLY;
662#endif
663#ifdef FFDLY
664 data.term.c_oflag &= ~FFDLY;
665#endif
b251be4b 666#ifdef OFILL
9cb98459
ML
667 data.term.c_oflag &= ~OFILL;
668#endif
c3e05092 669 data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
e3dcf906 670 data.term.c_cc[VMIN] = 0;
b251be4b 671 data.term.c_cc[VTIME] = 0;
9cb98459 672
b251be4b
ML
673 /* Ignore modem status lines; enable receiver; leave control lines alone on close. */
674 data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
bccc7c9f 675#endif
9cb98459 676
537942c9 677#ifdef _WIN32
1a2a1544
UH
678 if (ClearCommError(port->hdl, &errors, &status) == 0)
679 RETURN_FAIL("ClearCommError() failed");
537942c9
ML
680#endif
681
e33ab9aa
ML
682 ret = set_config(port, &data, &config);
683
eac329d2 684 if (ret < 0) {
e33ab9aa 685 sp_close(port);
c33efc48 686 RETURN_CODEVAL(ret);
e33ab9aa 687 }
74510d4b 688
c33efc48 689 RETURN_OK();
74510d4b
ML
690}
691
970f279a 692SP_API enum sp_return sp_close(struct sp_port *port)
74510d4b 693{
c33efc48
ML
694 TRACE("%p", port);
695
dec10e31 696 CHECK_OPEN_PORT();
74510d4b 697
7890cef6 698 DEBUG_FMT("Closing port %s", port->name);
ea667be7 699
74510d4b
ML
700#ifdef _WIN32
701 /* Returns non-zero upon success, 0 upon failure. */
702 if (CloseHandle(port->hdl) == 0)
dc422c04 703 RETURN_FAIL("Port CloseHandle() failed");
8f471c66 704 port->hdl = INVALID_HANDLE_VALUE;
6f1186aa
ML
705
706 /* Close event handles for overlapped structures. */
707#define CLOSE_OVERLAPPED(ovl) do { \
708 if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \
709 CloseHandle(port->ovl.hEvent) == 0) \
710 RETURN_FAIL(# ovl "event CloseHandle() failed"); \
711} while (0)
712 CLOSE_OVERLAPPED(read_ovl);
713 CLOSE_OVERLAPPED(write_ovl);
714 CLOSE_OVERLAPPED(wait_ovl);
715
39df7833
ML
716 if (port->write_buf) {
717 free(port->write_buf);
718 port->write_buf = NULL;
719 }
74510d4b
ML
720#else
721 /* Returns 0 upon success, -1 upon failure. */
722 if (close(port->fd) == -1)
c33efc48 723 RETURN_FAIL("close() failed");
8f471c66 724 port->fd = -1;
74510d4b
ML
725#endif
726
c33efc48 727 RETURN_OK();
74510d4b
ML
728}
729
970f279a 730SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
74510d4b 731{
00d8c56d 732 TRACE("%p, 0x%x", port, buffers);
c33efc48 733
dec10e31
ML
734 CHECK_OPEN_PORT();
735
736 if (buffers > SP_BUF_BOTH)
737 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
74510d4b 738
0ba3e49b 739 const char *buffer_names[] = {"no", "input", "output", "both"};
ea667be7 740
7890cef6
ML
741 DEBUG_FMT("Flushing %s buffers on port %s",
742 buffer_names[buffers], port->name);
ea667be7 743
74510d4b 744#ifdef _WIN32
fd8fd11a
ML
745 DWORD flags = 0;
746 if (buffers & SP_BUF_INPUT)
747 flags |= PURGE_RXCLEAR;
748 if (buffers & SP_BUF_OUTPUT)
749 flags |= PURGE_TXCLEAR;
750
74510d4b 751 /* Returns non-zero upon success, 0 upon failure. */
fd8fd11a 752 if (PurgeComm(port->hdl, flags) == 0)
c33efc48 753 RETURN_FAIL("PurgeComm() failed");
47fcf8ec
ML
754
755 if (buffers & SP_BUF_INPUT)
756 TRY(restart_wait(port));
74510d4b 757#else
fd8fd11a 758 int flags = 0;
ad749855 759 if (buffers == SP_BUF_BOTH)
fd8fd11a 760 flags = TCIOFLUSH;
ad749855 761 else if (buffers == SP_BUF_INPUT)
fd8fd11a 762 flags = TCIFLUSH;
ad749855 763 else if (buffers == SP_BUF_OUTPUT)
fd8fd11a
ML
764 flags = TCOFLUSH;
765
74510d4b 766 /* Returns 0 upon success, -1 upon failure. */
fd8fd11a 767 if (tcflush(port->fd, flags) < 0)
c33efc48 768 RETURN_FAIL("tcflush() failed");
74510d4b 769#endif
c33efc48 770 RETURN_OK();
74510d4b
ML
771}
772
970f279a 773SP_API enum sp_return sp_drain(struct sp_port *port)
69a3739c 774{
c33efc48
ML
775 TRACE("%p", port);
776
dec10e31 777 CHECK_OPEN_PORT();
69a3739c 778
7890cef6 779 DEBUG_FMT("Draining port %s", port->name);
ea667be7 780
69a3739c
ML
781#ifdef _WIN32
782 /* Returns non-zero upon success, 0 upon failure. */
783 if (FlushFileBuffers(port->hdl) == 0)
c33efc48 784 RETURN_FAIL("FlushFileBuffers() failed");
2c827b21 785 RETURN_OK();
69a3739c 786#else
2c827b21
ML
787 int result;
788 while (1) {
abd31fd9
ML
789#if defined(__ANDROID__) && (__ANDROID_API__ < 21)
790 /* Android only has tcdrain from platform 21 onwards.
791 * On previous API versions, use the ioctl directly. */
33fd8804
ML
792 int arg = 1;
793 result = ioctl(port->fd, TCSBRK, &arg);
794#else
2c827b21 795 result = tcdrain(port->fd);
33fd8804 796#endif
2c827b21
ML
797 if (result < 0) {
798 if (errno == EINTR) {
799 DEBUG("tcdrain() was interrupted");
800 continue;
801 } else {
802 RETURN_FAIL("tcdrain() failed");
803 }
804 } else {
805 RETURN_OK();
806 }
807 }
69a3739c 808#endif
69a3739c
ML
809}
810
62ed9f80
ML
811#ifdef _WIN32
812static enum sp_return await_write_completion(struct sp_port *port)
813{
814 TRACE("%p", port);
815 DWORD bytes_written;
816 BOOL result;
817
818 /* Wait for previous non-blocking write to complete, if any. */
819 if (port->writing) {
820 DEBUG("Waiting for previous write to complete");
821 result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
822 port->writing = 0;
823 if (!result)
824 RETURN_FAIL("Previous write failed to complete");
825 DEBUG("Previous write completed");
826 }
827
828 RETURN_OK();
829}
830#endif
831
970f279a 832SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
1b91c6ea 833 size_t count, unsigned int timeout_ms)
e3dcf906 834{
1b91c6ea 835 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
e3dcf906
ML
836
837 CHECK_OPEN_PORT();
838
839 if (!buf)
840 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
841
1b91c6ea 842 if (timeout_ms)
7890cef6 843 DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms",
1b91c6ea 844 count, port->name, timeout_ms);
e3dcf906 845 else
7890cef6
ML
846 DEBUG_FMT("Writing %d bytes to port %s, no timeout",
847 count, port->name);
e3dcf906
ML
848
849 if (count == 0)
9caa2e86 850 RETURN_INT(0);
e3dcf906
ML
851
852#ifdef _WIN32
853 DWORD bytes_written = 0;
e3dcf906 854
62ed9f80 855 TRY(await_write_completion(port));
e3dcf906
ML
856
857 /* Set timeout. */
27a58c05
ML
858 if (port->timeouts.WriteTotalTimeoutConstant != timeout_ms) {
859 port->timeouts.WriteTotalTimeoutConstant = timeout_ms;
860 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
861 RETURN_FAIL("SetCommTimeouts() failed");
862 }
e3dcf906 863
b457865b
ML
864 /* Reduce count if it exceeds the WriteFile limit. */
865 if (count > WRITEFILE_MAX_SIZE)
866 count = WRITEFILE_MAX_SIZE;
867
e3dcf906 868 /* Start write. */
bbe566fe 869 if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl)) {
e3dcf906 870 DEBUG("Write completed immediately");
9caa2e86 871 RETURN_INT(count);
bbe566fe
ML
872 } else if (GetLastError() == ERROR_IO_PENDING) {
873 DEBUG("Waiting for write to complete");
aee7d691
UH
874 if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) {
875 if (GetLastError() == ERROR_SEM_TIMEOUT) {
876 DEBUG("Write timed out");
877 RETURN_INT(0);
878 } else {
879 RETURN_FAIL("GetOverlappedResult() failed");
880 }
881 }
bbe566fe
ML
882 DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count);
883 RETURN_INT(bytes_written);
884 } else {
885 RETURN_FAIL("WriteFile() failed");
e3dcf906
ML
886 }
887#else
888 size_t bytes_written = 0;
889 unsigned char *ptr = (unsigned char *) buf;
9a7945af 890 struct time start, delta, now, end = TIME_ZERO;
76222ee5 891 int started = 0;
e3dcf906
ML
892 fd_set fds;
893 int result;
894
1b91c6ea 895 if (timeout_ms) {
e3dcf906 896 /* Get time at start of operation. */
9a7945af 897 time_get(&start);
e3dcf906 898 /* Define duration of timeout. */
9a7945af 899 time_set_ms(&delta, timeout_ms);
e3dcf906 900 /* Calculate time at which we should give up. */
9a7945af 901 time_add(&start, &delta, &end);
e3dcf906
ML
902 }
903
772c5861
ML
904 FD_ZERO(&fds);
905 FD_SET(port->fd, &fds);
906
e3dcf906 907 /* Loop until we have written the requested number of bytes. */
dc422c04 908 while (bytes_written < count) {
76222ee5
ML
909 /*
910 * Check timeout only if we have run select() at least once,
911 * to avoid any issues if a short timeout is reached before
912 * select() is even run.
913 */
9a7945af 914 struct timeval tv;
76222ee5 915 if (timeout_ms && started) {
9a7945af
ML
916 time_get(&now);
917 if (time_greater(&now, &end))
c3cee38c
ML
918 /* Timeout has expired. */
919 break;
9a7945af
ML
920 time_sub(&end, &now, &delta);
921 time_as_timeval(&delta, &tv);
e3dcf906 922 }
9a7945af 923 result = select(port->fd + 1, NULL, &fds, NULL, timeout_ms ? &tv : NULL);
76222ee5 924 started = 1;
63a17c64
ML
925 if (result < 0) {
926 if (errno == EINTR) {
927 DEBUG("select() call was interrupted, repeating");
928 continue;
929 } else {
930 RETURN_FAIL("select() failed");
931 }
932 } else if (result == 0) {
c3cee38c
ML
933 /* Timeout has expired. */
934 break;
e3dcf906
ML
935 }
936
937 /* Do write. */
938 result = write(port->fd, ptr, count - bytes_written);
939
940 if (result < 0) {
941 if (errno == EAGAIN)
942 /* This shouldn't happen because we did a select() first, but handle anyway. */
943 continue;
944 else
945 /* This is an actual failure. */
946 RETURN_FAIL("write() failed");
947 }
948
949 bytes_written += result;
950 ptr += result;
951 }
952
c3cee38c
ML
953 if (bytes_written < count)
954 DEBUG("Write timed out");
955
9caa2e86 956 RETURN_INT(bytes_written);
e3dcf906
ML
957#endif
958}
959
970f279a
AJ
960SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
961 const void *buf, size_t count)
74510d4b 962{
c33efc48
ML
963 TRACE("%p, %p, %d", port, buf, count);
964
dec10e31 965 CHECK_OPEN_PORT();
74510d4b
ML
966
967 if (!buf)
c33efc48 968 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
74510d4b 969
7890cef6 970 DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name);
ea667be7 971
a3cb91f5 972 if (count == 0)
9caa2e86 973 RETURN_INT(0);
a3cb91f5 974
74510d4b 975#ifdef _WIN32
39df7833 976 DWORD buf_bytes;
f92f1f0c 977
e3dcf906
ML
978 /* Check whether previous write is complete. */
979 if (port->writing) {
980 if (HasOverlappedIoCompleted(&port->write_ovl)) {
981 DEBUG("Previous write completed");
982 port->writing = 0;
983 } else {
984 DEBUG("Previous write not complete");
985 /* Can't take a new write until the previous one finishes. */
9caa2e86 986 RETURN_INT(0);
a3cb91f5 987 }
e3dcf906 988 }
a3cb91f5 989
e3dcf906 990 /* Set timeout. */
27a58c05
ML
991 if (port->timeouts.WriteTotalTimeoutConstant != 0) {
992 port->timeouts.WriteTotalTimeoutConstant = 0;
993 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
994 RETURN_FAIL("SetCommTimeouts() failed");
995 }
e3dcf906 996
b457865b
ML
997 /* Reduce count if it exceeds the WriteFile limit. */
998 if (count > WRITEFILE_MAX_SIZE)
999 count = WRITEFILE_MAX_SIZE;
1000
39df7833
ML
1001 /* Copy data to our write buffer. */
1002 buf_bytes = min(port->write_buf_size, count);
1003 memcpy(port->write_buf, buf, buf_bytes);
1004
1005 /* Start asynchronous write. */
1006 if (WriteFile(port->hdl, port->write_buf, buf_bytes, NULL, &port->write_ovl) == 0) {
1007 if (GetLastError() == ERROR_IO_PENDING) {
1008 if ((port->writing = !HasOverlappedIoCompleted(&port->write_ovl)))
1009 DEBUG("Asynchronous write completed immediately");
1010 else
1011 DEBUG("Asynchronous write running");
e3dcf906 1012 } else {
39df7833
ML
1013 /* Actual failure of some kind. */
1014 RETURN_FAIL("WriteFile() failed");
a3cb91f5
ML
1015 }
1016 }
1017
9af8cff3 1018 DEBUG("All bytes written immediately");
e3dcf906 1019
39df7833 1020 RETURN_INT(buf_bytes);
74510d4b
ML
1021#else
1022 /* Returns the number of bytes written, or -1 upon failure. */
1023 ssize_t written = write(port->fd, buf, count);
f92f1f0c 1024
55ab7e0b
ML
1025 if (written < 0) {
1026 if (errno == EAGAIN)
1027 // Buffer is full, no bytes written.
1028 RETURN_INT(0);
1029 else
1030 RETURN_FAIL("write() failed");
1031 } else {
9caa2e86 1032 RETURN_INT(written);
55ab7e0b 1033 }
74510d4b
ML
1034#endif
1035}
1036
94a314a8
ML
1037#ifdef _WIN32
1038/* Restart wait operation if buffer was emptied. */
1039static enum sp_return restart_wait_if_needed(struct sp_port *port, unsigned int bytes_read)
1040{
8ebfaf89
ML
1041 DWORD errors;
1042 COMSTAT comstat;
94a314a8 1043
21ae5ce1
ML
1044 if (bytes_read == 0)
1045 RETURN_OK();
1046
8ebfaf89
ML
1047 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1048 RETURN_FAIL("ClearCommError() failed");
94a314a8 1049
8ebfaf89 1050 if (comstat.cbInQue == 0)
94a314a8
ML
1051 TRY(restart_wait(port));
1052
1053 RETURN_OK();
1054}
1055#endif
1056
970f279a 1057SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
1b91c6ea 1058 size_t count, unsigned int timeout_ms)
e3dcf906 1059{
1b91c6ea 1060 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
e3dcf906
ML
1061
1062 CHECK_OPEN_PORT();
1063
1064 if (!buf)
1065 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1066
1b91c6ea 1067 if (timeout_ms)
7890cef6 1068 DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms",
1b91c6ea 1069 count, port->name, timeout_ms);
e3dcf906 1070 else
7890cef6
ML
1071 DEBUG_FMT("Reading %d bytes from port %s, no timeout",
1072 count, port->name);
e3dcf906
ML
1073
1074 if (count == 0)
9caa2e86 1075 RETURN_INT(0);
e3dcf906
ML
1076
1077#ifdef _WIN32
1078 DWORD bytes_read = 0;
1079
1080 /* Set timeout. */
27a58c05 1081 if (port->timeouts.ReadIntervalTimeout != 0 ||
0188a545 1082 port->timeouts.ReadTotalTimeoutMultiplier != 0 ||
27a58c05
ML
1083 port->timeouts.ReadTotalTimeoutConstant != timeout_ms) {
1084 port->timeouts.ReadIntervalTimeout = 0;
0188a545 1085 port->timeouts.ReadTotalTimeoutMultiplier = 0;
27a58c05
ML
1086 port->timeouts.ReadTotalTimeoutConstant = timeout_ms;
1087 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1088 RETURN_FAIL("SetCommTimeouts() failed");
1089 }
e3dcf906
ML
1090
1091 /* Start read. */
bbe566fe 1092 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl)) {
e3dcf906 1093 DEBUG("Read completed immediately");
6f1186aa 1094 bytes_read = count;
bbe566fe
ML
1095 } else if (GetLastError() == ERROR_IO_PENDING) {
1096 DEBUG("Waiting for read to complete");
27911925
ML
1097 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
1098 RETURN_FAIL("GetOverlappedResult() failed");
bbe566fe
ML
1099 DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count);
1100 } else {
1101 RETURN_FAIL("ReadFile() failed");
6f1186aa
ML
1102 }
1103
94a314a8 1104 TRY(restart_wait_if_needed(port, bytes_read));
6f1186aa 1105
9caa2e86 1106 RETURN_INT(bytes_read);
6f1186aa 1107
e3dcf906
ML
1108#else
1109 size_t bytes_read = 0;
9a7945af
ML
1110 unsigned char *ptr = (unsigned char *) buf;
1111 struct time start, delta, now, end = TIME_ZERO;
76222ee5 1112 int started = 0;
e3dcf906
ML
1113 fd_set fds;
1114 int result;
1115
1b91c6ea 1116 if (timeout_ms) {
e3dcf906 1117 /* Get time at start of operation. */
9a7945af 1118 time_get(&start);
e3dcf906 1119 /* Define duration of timeout. */
9a7945af 1120 time_set_ms(&delta, timeout_ms);
e3dcf906 1121 /* Calculate time at which we should give up. */
9a7945af 1122 time_add(&start, &delta, &end);
e3dcf906
ML
1123 }
1124
772c5861
ML
1125 FD_ZERO(&fds);
1126 FD_SET(port->fd, &fds);
1127
e3dcf906 1128 /* Loop until we have the requested number of bytes. */
dc422c04 1129 while (bytes_read < count) {
76222ee5
ML
1130 /*
1131 * Check timeout only if we have run select() at least once,
1132 * to avoid any issues if a short timeout is reached before
1133 * select() is even run.
1134 */
9a7945af 1135 struct timeval tv;
76222ee5 1136 if (timeout_ms && started) {
9a7945af
ML
1137 time_get(&now);
1138 if (time_greater(&now, &end))
e3dcf906 1139 /* Timeout has expired. */
c3cee38c 1140 break;
9a7945af
ML
1141 time_sub(&end, &now, &delta);
1142 time_as_timeval(&delta, &tv);
e3dcf906 1143 }
9a7945af 1144 result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &tv : NULL);
76222ee5 1145 started = 1;
63a17c64
ML
1146 if (result < 0) {
1147 if (errno == EINTR) {
1148 DEBUG("select() call was interrupted, repeating");
1149 continue;
1150 } else {
1151 RETURN_FAIL("select() failed");
1152 }
1153 } else if (result == 0) {
c3cee38c
ML
1154 /* Timeout has expired. */
1155 break;
e3dcf906
ML
1156 }
1157
1158 /* Do read. */
1159 result = read(port->fd, ptr, count - bytes_read);
1160
1161 if (result < 0) {
1162 if (errno == EAGAIN)
76222ee5
ML
1163 /*
1164 * This shouldn't happen because we did a
1165 * select() first, but handle anyway.
1166 */
e3dcf906
ML
1167 continue;
1168 else
1169 /* This is an actual failure. */
1170 RETURN_FAIL("read() failed");
1171 }
1172
1173 bytes_read += result;
1174 ptr += result;
1175 }
1176
c3cee38c
ML
1177 if (bytes_read < count)
1178 DEBUG("Read timed out");
1179
9caa2e86 1180 RETURN_INT(bytes_read);
e3dcf906
ML
1181#endif
1182}
1183
e5c2630e
ML
1184SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
1185 size_t count, unsigned int timeout_ms)
1186{
1187 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
1188
1189 CHECK_OPEN_PORT();
1190
1191 if (!buf)
1192 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1193
1194 if (count == 0)
1195 RETURN_ERROR(SP_ERR_ARG, "Zero count");
1196
1197 if (timeout_ms)
1198 DEBUG_FMT("Reading next max %d bytes from port %s, timeout %d ms",
1199 count, port->name, timeout_ms);
1200 else
1201 DEBUG_FMT("Reading next max %d bytes from port %s, no timeout",
1202 count, port->name);
1203
1204#ifdef _WIN32
1205 DWORD bytes_read = 0;
1206
1207 /* If timeout_ms == 0, set maximum timeout. */
1208 DWORD timeout_val = (timeout_ms == 0 ? MAXDWORD - 1 : timeout_ms);
1209
1210 /* Set timeout. */
1211 if (port->timeouts.ReadIntervalTimeout != MAXDWORD ||
1212 port->timeouts.ReadTotalTimeoutMultiplier != MAXDWORD ||
1213 port->timeouts.ReadTotalTimeoutConstant != timeout_val) {
1214 port->timeouts.ReadIntervalTimeout = MAXDWORD;
1215 port->timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
1216 port->timeouts.ReadTotalTimeoutConstant = timeout_val;
1217 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1218 RETURN_FAIL("SetCommTimeouts() failed");
1219 }
1220
1221 /* Loop until we have at least one byte, or timeout is reached. */
1222 while (bytes_read == 0) {
1223 /* Start read. */
888fb45d 1224 if (ReadFile(port->hdl, buf, count, &bytes_read, &port->read_ovl)) {
e5c2630e 1225 DEBUG("Read completed immediately");
e5c2630e
ML
1226 } else if (GetLastError() == ERROR_IO_PENDING) {
1227 DEBUG("Waiting for read to complete");
1228 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
1229 RETURN_FAIL("GetOverlappedResult() failed");
1230 if (bytes_read > 0) {
1231 DEBUG("Read completed");
1232 } else if (timeout_ms > 0) {
1233 DEBUG("Read timed out");
1234 break;
1235 } else {
1236 DEBUG("Restarting read");
1237 }
1238 } else {
1239 RETURN_FAIL("ReadFile() failed");
1240 }
1241 }
1242
1243 TRY(restart_wait_if_needed(port, bytes_read));
1244
1245 RETURN_INT(bytes_read);
1246
1247#else
1248 size_t bytes_read = 0;
9a7945af 1249 struct time start, delta, now, end = TIME_ZERO;
e5c2630e
ML
1250 int started = 0;
1251 fd_set fds;
1252 int result;
1253
1254 if (timeout_ms) {
1255 /* Get time at start of operation. */
9a7945af 1256 time_get(&start);
e5c2630e 1257 /* Define duration of timeout. */
9a7945af 1258 time_set_ms(&delta, timeout_ms);
e5c2630e 1259 /* Calculate time at which we should give up. */
9a7945af 1260 time_add(&start, &delta, &end);
e5c2630e
ML
1261 }
1262
1263 FD_ZERO(&fds);
1264 FD_SET(port->fd, &fds);
1265
1266 /* Loop until we have at least one byte, or timeout is reached. */
1267 while (bytes_read == 0) {
1268 /*
1269 * Check timeout only if we have run select() at least once,
1270 * to avoid any issues if a short timeout is reached before
1271 * select() is even run.
1272 */
9a7945af 1273 struct timeval tv;
e5c2630e 1274 if (timeout_ms && started) {
9a7945af
ML
1275 time_get(&now);
1276 if (time_greater(&now, &end))
e5c2630e
ML
1277 /* Timeout has expired. */
1278 break;
9a7945af
ML
1279 time_sub(&end, &now, &delta);
1280 time_as_timeval(&delta, &tv);
e5c2630e 1281 }
9a7945af 1282 result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &tv : NULL);
e5c2630e
ML
1283 started = 1;
1284 if (result < 0) {
1285 if (errno == EINTR) {
1286 DEBUG("select() call was interrupted, repeating");
1287 continue;
1288 } else {
1289 RETURN_FAIL("select() failed");
1290 }
1291 } else if (result == 0) {
1292 /* Timeout has expired. */
1293 break;
1294 }
1295
1296 /* Do read. */
1297 result = read(port->fd, buf, count);
1298
1299 if (result < 0) {
1300 if (errno == EAGAIN)
1301 /* This shouldn't happen because we did a select() first, but handle anyway. */
1302 continue;
1303 else
1304 /* This is an actual failure. */
1305 RETURN_FAIL("read() failed");
1306 }
1307
1308 bytes_read = result;
1309 }
1310
1311 if (bytes_read == 0)
1312 DEBUG("Read timed out");
1313
1314 RETURN_INT(bytes_read);
1315#endif
1316}
1317
970f279a
AJ
1318SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
1319 size_t count)
74510d4b 1320{
c33efc48
ML
1321 TRACE("%p, %p, %d", port, buf, count);
1322
dec10e31 1323 CHECK_OPEN_PORT();
74510d4b
ML
1324
1325 if (!buf)
c33efc48 1326 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
74510d4b 1327
7890cef6 1328 DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name);
ea667be7 1329
74510d4b 1330#ifdef _WIN32
e3dcf906 1331 DWORD bytes_read;
f92f1f0c 1332
e3dcf906 1333 /* Set timeout. */
27a58c05 1334 if (port->timeouts.ReadIntervalTimeout != MAXDWORD ||
0188a545 1335 port->timeouts.ReadTotalTimeoutMultiplier != 0 ||
27a58c05
ML
1336 port->timeouts.ReadTotalTimeoutConstant != 0) {
1337 port->timeouts.ReadIntervalTimeout = MAXDWORD;
0188a545 1338 port->timeouts.ReadTotalTimeoutMultiplier = 0;
27a58c05
ML
1339 port->timeouts.ReadTotalTimeoutConstant = 0;
1340 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1341 RETURN_FAIL("SetCommTimeouts() failed");
1342 }
e3dcf906
ML
1343
1344 /* Do read. */
1345 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
ae2c5825
ML
1346 if (GetLastError() != ERROR_IO_PENDING)
1347 RETURN_FAIL("ReadFile() failed");
e3dcf906
ML
1348
1349 /* Get number of bytes read. */
ae2c5825 1350 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, FALSE) == 0)
1622ef60 1351 RETURN_FAIL("GetOverlappedResult() failed");
e3dcf906 1352
94a314a8 1353 TRY(restart_wait_if_needed(port, bytes_read));
6f1186aa 1354
9caa2e86 1355 RETURN_INT(bytes_read);
74510d4b
ML
1356#else
1357 ssize_t bytes_read;
f92f1f0c 1358
74510d4b 1359 /* Returns the number of bytes read, or -1 upon failure. */
33d5ff47 1360 if ((bytes_read = read(port->fd, buf, count)) < 0) {
e3dcf906
ML
1361 if (errno == EAGAIN)
1362 /* No bytes available. */
33d5ff47
ML
1363 bytes_read = 0;
1364 else
1365 /* This is an actual failure. */
1366 RETURN_FAIL("read() failed");
1367 }
9caa2e86 1368 RETURN_INT(bytes_read);
74510d4b
ML
1369#endif
1370}
1371
970f279a 1372SP_API enum sp_return sp_input_waiting(struct sp_port *port)
3353c22f
ML
1373{
1374 TRACE("%p", port);
1375
1376 CHECK_OPEN_PORT();
1377
7890cef6 1378 DEBUG_FMT("Checking input bytes waiting on port %s", port->name);
3353c22f
ML
1379
1380#ifdef _WIN32
1381 DWORD errors;
1382 COMSTAT comstat;
1383
1384 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1a2a1544 1385 RETURN_FAIL("ClearCommError() failed");
9caa2e86 1386 RETURN_INT(comstat.cbInQue);
3353c22f
ML
1387#else
1388 int bytes_waiting;
1389 if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
1390 RETURN_FAIL("TIOCINQ ioctl failed");
9caa2e86 1391 RETURN_INT(bytes_waiting);
3353c22f
ML
1392#endif
1393}
1394
970f279a 1395SP_API enum sp_return sp_output_waiting(struct sp_port *port)
3353c22f
ML
1396{
1397 TRACE("%p", port);
1398
1399 CHECK_OPEN_PORT();
1400
7890cef6 1401 DEBUG_FMT("Checking output bytes waiting on port %s", port->name);
3353c22f
ML
1402
1403#ifdef _WIN32
1404 DWORD errors;
1405 COMSTAT comstat;
1406
1407 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1a2a1544 1408 RETURN_FAIL("ClearCommError() failed");
9caa2e86 1409 RETURN_INT(comstat.cbOutQue);
3353c22f
ML
1410#else
1411 int bytes_waiting;
1412 if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
1413 RETURN_FAIL("TIOCOUTQ ioctl failed");
9caa2e86 1414 RETURN_INT(bytes_waiting);
3353c22f
ML
1415#endif
1416}
1417
970f279a 1418SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
6f1186aa
ML
1419{
1420 struct sp_event_set *result;
1421
1422 TRACE("%p", result_ptr);
1423
1424 if (!result_ptr)
1425 RETURN_ERROR(SP_ERR_ARG, "Null result");
1426
1427 *result_ptr = NULL;
1428
1429 if (!(result = malloc(sizeof(struct sp_event_set))))
1430 RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed");
1431
1432 memset(result, 0, sizeof(struct sp_event_set));
1433
1434 *result_ptr = result;
1435
1436 RETURN_OK();
1437}
1438
1439static enum sp_return add_handle(struct sp_event_set *event_set,
1440 event_handle handle, enum sp_event mask)
1441{
1442 void *new_handles;
1443 enum sp_event *new_masks;
1444
1445 TRACE("%p, %d, %d", event_set, handle, mask);
1446
1447 if (!(new_handles = realloc(event_set->handles,
1448 sizeof(event_handle) * (event_set->count + 1))))
dc422c04 1449 RETURN_ERROR(SP_ERR_MEM, "Handle array realloc() failed");
6f1186aa 1450
ac323d80
UH
1451 event_set->handles = new_handles;
1452
6f1186aa 1453 if (!(new_masks = realloc(event_set->masks,
ac323d80 1454 sizeof(enum sp_event) * (event_set->count + 1))))
dc422c04 1455 RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed");
6f1186aa 1456
6f1186aa
ML
1457 event_set->masks = new_masks;
1458
1459 ((event_handle *) event_set->handles)[event_set->count] = handle;
1460 event_set->masks[event_set->count] = mask;
1461
1462 event_set->count++;
1463
1464 RETURN_OK();
1465}
1466
970f279a 1467SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set,
6f1186aa
ML
1468 const struct sp_port *port, enum sp_event mask)
1469{
1470 TRACE("%p, %p, %d", event_set, port, mask);
1471
1472 if (!event_set)
1473 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1474
1475 if (!port)
1476 RETURN_ERROR(SP_ERR_ARG, "Null port");
1477
1478 if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR))
1479 RETURN_ERROR(SP_ERR_ARG, "Invalid event mask");
1480
1481 if (!mask)
1482 RETURN_OK();
1483
1484#ifdef _WIN32
1485 enum sp_event handle_mask;
1486 if ((handle_mask = mask & SP_EVENT_TX_READY))
1487 TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask));
1488 if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR)))
1489 TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask));
1490#else
1491 TRY(add_handle(event_set, port->fd, mask));
1492#endif
1493
1494 RETURN_OK();
1495}
1496
970f279a 1497SP_API void sp_free_event_set(struct sp_event_set *event_set)
6f1186aa
ML
1498{
1499 TRACE("%p", event_set);
1500
1501 if (!event_set) {
1502 DEBUG("Null event set");
1503 RETURN();
1504 }
1505
1506 DEBUG("Freeing event set");
1507
1508 if (event_set->handles)
1509 free(event_set->handles);
1510 if (event_set->masks)
1511 free(event_set->masks);
1512
1513 free(event_set);
1514
1515 RETURN();
1516}
1517
970f279a 1518SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
1b91c6ea 1519 unsigned int timeout_ms)
6f1186aa 1520{
1b91c6ea 1521 TRACE("%p, %d", event_set, timeout_ms);
6f1186aa
ML
1522
1523 if (!event_set)
1524 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1525
1526#ifdef _WIN32
1527 if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE,
1b91c6ea 1528 timeout_ms ? timeout_ms : INFINITE) == WAIT_FAILED)
6f1186aa
ML
1529 RETURN_FAIL("WaitForMultipleObjects() failed");
1530
1531 RETURN_OK();
1532#else
9a7945af
ML
1533 struct time start, delta, now, end = TIME_ZERO;
1534 const struct time max_delta = TIME_MS(INT_MAX);
127d8d0c 1535 int started = 0, timeout_overflow = 0;
1b91c6ea 1536 int result, timeout_remaining_ms;
6f1186aa
ML
1537 struct pollfd *pollfds;
1538 unsigned int i;
1539
1540 if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count)))
1541 RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
1542
1543 for (i = 0; i < event_set->count; i++) {
81243567 1544 pollfds[i].fd = ((int *)event_set->handles)[i];
6f1186aa
ML
1545 pollfds[i].events = 0;
1546 pollfds[i].revents = 0;
1547 if (event_set->masks[i] & SP_EVENT_RX_READY)
1548 pollfds[i].events |= POLLIN;
1549 if (event_set->masks[i] & SP_EVENT_TX_READY)
1550 pollfds[i].events |= POLLOUT;
1551 if (event_set->masks[i] & SP_EVENT_ERROR)
1552 pollfds[i].events |= POLLERR;
1553 }
1554
1b91c6ea 1555 if (timeout_ms) {
6f1186aa 1556 /* Get time at start of operation. */
9a7945af 1557 time_get(&start);
6f1186aa 1558 /* Define duration of timeout. */
9a7945af 1559 time_set_ms(&delta, timeout_ms);
6f1186aa 1560 /* Calculate time at which we should give up. */
9a7945af 1561 time_add(&start, &delta, &end);
6f1186aa
ML
1562 }
1563
1564 /* Loop until an event occurs. */
dc422c04 1565 while (1) {
76222ee5
ML
1566 /*
1567 * Check timeout only if we have run poll() at least once,
1568 * to avoid any issues if a short timeout is reached before
1569 * poll() is even run.
1570 */
6b8eee06
ML
1571 if (!timeout_ms) {
1572 timeout_remaining_ms = -1;
1573 } else if (!started) {
127d8d0c
ML
1574 timeout_overflow = (timeout_ms > INT_MAX);
1575 timeout_remaining_ms = timeout_overflow ? INT_MAX : timeout_ms;
6b8eee06 1576 } else {
9a7945af
ML
1577 time_get(&now);
1578 if (time_greater(&now, &end)) {
dc422c04 1579 DEBUG("Wait timed out");
6f1186aa
ML
1580 break;
1581 }
9a7945af
ML
1582 time_sub(&end, &now, &delta);
1583 if ((timeout_overflow = time_greater(&delta, &max_delta)))
127d8d0c 1584 delta = max_delta;
9a7945af 1585 timeout_remaining_ms = time_as_ms(&delta);
6f1186aa
ML
1586 }
1587
6b8eee06 1588 result = poll(pollfds, event_set->count, timeout_remaining_ms);
76222ee5 1589 started = 1;
6f1186aa
ML
1590
1591 if (result < 0) {
1592 if (errno == EINTR) {
1593 DEBUG("poll() call was interrupted, repeating");
1594 continue;
1595 } else {
1596 free(pollfds);
1597 RETURN_FAIL("poll() failed");
1598 }
1599 } else if (result == 0) {
1600 DEBUG("poll() timed out");
127d8d0c
ML
1601 if (!timeout_overflow)
1602 break;
6f1186aa
ML
1603 } else {
1604 DEBUG("poll() completed");
1605 break;
1606 }
1607 }
1608
1609 free(pollfds);
1610 RETURN_OK();
1611#endif
1612}
1613
5cea279a 1614#ifdef USE_TERMIOS_SPEED
7a6d2196
ML
1615static enum sp_return get_baudrate(int fd, int *baudrate)
1616{
1617 void *data;
1618
c33efc48
ML
1619 TRACE("%d, %p", fd, baudrate);
1620
ea667be7
ML
1621 DEBUG("Getting baud rate");
1622
7a6d2196 1623 if (!(data = malloc(get_termios_size())))
c33efc48 1624 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
7a6d2196 1625
8d43110a
ML
1626 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1627 free(data);
dc422c04 1628 RETURN_FAIL("Getting termios failed");
8d43110a 1629 }
7a6d2196
ML
1630
1631 *baudrate = get_termios_speed(data);
1632
8d43110a
ML
1633 free(data);
1634
c33efc48 1635 RETURN_OK();
7a6d2196
ML
1636}
1637
1638static enum sp_return set_baudrate(int fd, int baudrate)
1639{
1640 void *data;
1641
c33efc48
ML
1642 TRACE("%d, %d", fd, baudrate);
1643
ea667be7
ML
1644 DEBUG("Getting baud rate");
1645
7a6d2196 1646 if (!(data = malloc(get_termios_size())))
c33efc48 1647 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
7a6d2196 1648
8d43110a
ML
1649 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1650 free(data);
dc422c04 1651 RETURN_FAIL("Getting termios failed");
8d43110a 1652 }
7a6d2196 1653
ea667be7
ML
1654 DEBUG("Setting baud rate");
1655
7a6d2196
ML
1656 set_termios_speed(data, baudrate);
1657
8d43110a
ML
1658 if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
1659 free(data);
dc422c04 1660 RETURN_FAIL("Setting termios failed");
8d43110a
ML
1661 }
1662
1663 free(data);
7a6d2196 1664
c33efc48 1665 RETURN_OK();
7a6d2196 1666}
5cea279a 1667#endif /* USE_TERMIOS_SPEED */
40978c2b
ML
1668
1669#ifdef USE_TERMIOX
bd791fe1 1670static enum sp_return get_flow(int fd, struct port_data *data)
40978c2b 1671{
bd791fe1 1672 void *termx;
40978c2b 1673
bd791fe1 1674 TRACE("%d, %p", fd, data);
c33efc48 1675
ea667be7
ML
1676 DEBUG("Getting advanced flow control");
1677
bd791fe1 1678 if (!(termx = malloc(get_termiox_size())))
c33efc48 1679 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
40978c2b 1680
bd791fe1
ML
1681 if (ioctl(fd, TCGETX, termx) < 0) {
1682 free(termx);
dc422c04 1683 RETURN_FAIL("Getting termiox failed");
8d43110a 1684 }
40978c2b 1685
bd791fe1
ML
1686 get_termiox_flow(termx, &data->rts_flow, &data->cts_flow,
1687 &data->dtr_flow, &data->dsr_flow);
40978c2b 1688
bd791fe1 1689 free(termx);
8d43110a 1690
c33efc48 1691 RETURN_OK();
40978c2b
ML
1692}
1693
bd791fe1 1694static enum sp_return set_flow(int fd, struct port_data *data)
40978c2b 1695{
bd791fe1 1696 void *termx;
40978c2b 1697
bd791fe1 1698 TRACE("%d, %p", fd, data);
c33efc48 1699
ea667be7
ML
1700 DEBUG("Getting advanced flow control");
1701
bd791fe1 1702 if (!(termx = malloc(get_termiox_size())))
c33efc48 1703 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
40978c2b 1704
bd791fe1
ML
1705 if (ioctl(fd, TCGETX, termx) < 0) {
1706 free(termx);
dc422c04 1707 RETURN_FAIL("Getting termiox failed");
8d43110a 1708 }
40978c2b 1709
ea667be7
ML
1710 DEBUG("Setting advanced flow control");
1711
bd791fe1
ML
1712 set_termiox_flow(termx, data->rts_flow, data->cts_flow,
1713 data->dtr_flow, data->dsr_flow);
40978c2b 1714
bd791fe1
ML
1715 if (ioctl(fd, TCSETX, termx) < 0) {
1716 free(termx);
dc422c04 1717 RETURN_FAIL("Setting termiox failed");
8d43110a
ML
1718 }
1719
bd791fe1 1720 free(termx);
40978c2b 1721
c33efc48 1722 RETURN_OK();
40978c2b
ML
1723}
1724#endif /* USE_TERMIOX */
7a6d2196 1725
eb6ed20f
ML
1726static enum sp_return get_config(struct sp_port *port, struct port_data *data,
1727 struct sp_port_config *config)
8094e4a0 1728{
da2748bf 1729 unsigned int i;
cbf628c7 1730
c33efc48
ML
1731 TRACE("%p, %p, %p", port, data, config);
1732
7890cef6 1733 DEBUG_FMT("Getting configuration for port %s", port->name);
ea667be7 1734
8094e4a0 1735#ifdef _WIN32
e33ab9aa 1736 if (!GetCommState(port->hdl, &data->dcb))
c33efc48 1737 RETURN_FAIL("GetCommState() failed");
8094e4a0 1738
067417af 1739 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 1740 if (data->dcb.BaudRate == std_baudrates[i].index) {
067417af
ML
1741 config->baudrate = std_baudrates[i].value;
1742 break;
1743 }
1744 }
1745
1746 if (i == NUM_STD_BAUDRATES)
1747 /* BaudRate field can be either an index or a custom baud rate. */
e33ab9aa 1748 config->baudrate = data->dcb.BaudRate;
067417af 1749
e33ab9aa 1750 config->bits = data->dcb.ByteSize;
067417af 1751
e33ab9aa
ML
1752 if (data->dcb.fParity)
1753 switch (data->dcb.Parity) {
067417af
ML
1754 case NOPARITY:
1755 config->parity = SP_PARITY_NONE;
1756 break;
e432ce60
ML
1757 case ODDPARITY:
1758 config->parity = SP_PARITY_ODD;
1759 break;
067417af
ML
1760 case EVENPARITY:
1761 config->parity = SP_PARITY_EVEN;
1762 break;
e432ce60
ML
1763 case MARKPARITY:
1764 config->parity = SP_PARITY_MARK;
1765 break;
1766 case SPACEPARITY:
1767 config->parity = SP_PARITY_SPACE;
067417af
ML
1768 break;
1769 default:
1770 config->parity = -1;
1771 }
1772 else
1773 config->parity = SP_PARITY_NONE;
1774
e33ab9aa 1775 switch (data->dcb.StopBits) {
067417af
ML
1776 case ONESTOPBIT:
1777 config->stopbits = 1;
1778 break;
1779 case TWOSTOPBITS:
1780 config->stopbits = 2;
1781 break;
1782 default:
1783 config->stopbits = -1;
1784 }
1785
e33ab9aa 1786 switch (data->dcb.fRtsControl) {
eac329d2
UH
1787 case RTS_CONTROL_DISABLE:
1788 config->rts = SP_RTS_OFF;
1789 break;
1790 case RTS_CONTROL_ENABLE:
1791 config->rts = SP_RTS_ON;
1792 break;
1793 case RTS_CONTROL_HANDSHAKE:
1794 config->rts = SP_RTS_FLOW_CONTROL;
1795 break;
1796 default:
1797 config->rts = -1;
067417af
ML
1798 }
1799
e33ab9aa 1800 config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
067417af 1801
e33ab9aa 1802 switch (data->dcb.fDtrControl) {
eac329d2
UH
1803 case DTR_CONTROL_DISABLE:
1804 config->dtr = SP_DTR_OFF;
1805 break;
1806 case DTR_CONTROL_ENABLE:
1807 config->dtr = SP_DTR_ON;
1808 break;
1809 case DTR_CONTROL_HANDSHAKE:
1810 config->dtr = SP_DTR_FLOW_CONTROL;
1811 break;
1812 default:
1813 config->dtr = -1;
067417af
ML
1814 }
1815
e33ab9aa
ML
1816 config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
1817
c6754b45
ML
1818 if (data->dcb.fInX) {
1819 if (data->dcb.fOutX)
1820 config->xon_xoff = SP_XONXOFF_INOUT;
1821 else
1822 config->xon_xoff = SP_XONXOFF_IN;
1823 } else {
1824 if (data->dcb.fOutX)
1825 config->xon_xoff = SP_XONXOFF_OUT;
1826 else
1827 config->xon_xoff = SP_XONXOFF_DISABLED;
1828 }
1829
e33ab9aa
ML
1830#else // !_WIN32
1831
1832 if (tcgetattr(port->fd, &data->term) < 0)
c33efc48 1833 RETURN_FAIL("tcgetattr() failed");
e33ab9aa
ML
1834
1835 if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
c33efc48 1836 RETURN_FAIL("TIOCMGET ioctl failed");
40978c2b
ML
1837
1838#ifdef USE_TERMIOX
bd791fe1 1839 int ret = get_flow(port->fd, data);
68ec29db
ML
1840
1841 if (ret == SP_ERR_FAIL && errno == EINVAL)
1842 data->termiox_supported = 0;
1843 else if (ret < 0)
c33efc48 1844 RETURN_CODEVAL(ret);
68ec29db
ML
1845 else
1846 data->termiox_supported = 1;
1847#else
1848 data->termiox_supported = 0;
40978c2b
ML
1849#endif
1850
067417af 1851 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 1852 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
067417af
ML
1853 config->baudrate = std_baudrates[i].value;
1854 break;
1855 }
1856 }
1857
31b3a8f5
MH
1858 if (i == NUM_STD_BAUDRATES) {
1859#ifdef __APPLE__
1860 config->baudrate = (int)data->term.c_ispeed;
5cea279a 1861#elif defined(USE_TERMIOS_SPEED)
7a6d2196 1862 TRY(get_baudrate(port->fd, &config->baudrate));
31b3a8f5 1863#else
067417af 1864 config->baudrate = -1;
31b3a8f5
MH
1865#endif
1866 }
067417af 1867
e33ab9aa 1868 switch (data->term.c_cflag & CSIZE) {
067417af
ML
1869 case CS8:
1870 config->bits = 8;
1871 break;
1872 case CS7:
1873 config->bits = 7;
1874 break;
1875 case CS6:
1876 config->bits = 6;
1877 break;
1878 case CS5:
1879 config->bits = 5;
1880 break;
1881 default:
1882 config->bits = -1;
1883 }
1884
e33ab9aa 1885 if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
067417af 1886 config->parity = SP_PARITY_NONE;
e33ab9aa 1887 else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
067417af 1888 config->parity = -1;
c3e05092 1889#ifdef CMSPAR
e432ce60
ML
1890 else if (data->term.c_cflag & CMSPAR)
1891 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE;
c3e05092 1892#endif
067417af 1893 else
e33ab9aa 1894 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
067417af 1895
e33ab9aa 1896 config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
067417af 1897
e33ab9aa 1898 if (data->term.c_cflag & CRTSCTS) {
067417af
ML
1899 config->rts = SP_RTS_FLOW_CONTROL;
1900 config->cts = SP_CTS_FLOW_CONTROL;
1901 } else {
bd791fe1 1902 if (data->termiox_supported && data->rts_flow)
40978c2b
ML
1903 config->rts = SP_RTS_FLOW_CONTROL;
1904 else
1905 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
1906
bd791fe1 1907 config->cts = (data->termiox_supported && data->cts_flow) ?
68ec29db 1908 SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
067417af
ML
1909 }
1910
bd791fe1 1911 if (data->termiox_supported && data->dtr_flow)
40978c2b
ML
1912 config->dtr = SP_DTR_FLOW_CONTROL;
1913 else
1914 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
1915
bd791fe1 1916 config->dsr = (data->termiox_supported && data->dsr_flow) ?
68ec29db 1917 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
705bdc69 1918
e29b93a5
ML
1919 if (data->term.c_iflag & IXOFF) {
1920 if (data->term.c_iflag & IXON)
1921 config->xon_xoff = SP_XONXOFF_INOUT;
1922 else
1923 config->xon_xoff = SP_XONXOFF_IN;
1924 } else {
1925 if (data->term.c_iflag & IXON)
1926 config->xon_xoff = SP_XONXOFF_OUT;
1927 else
1928 config->xon_xoff = SP_XONXOFF_DISABLED;
1929 }
067417af
ML
1930#endif
1931
c33efc48 1932 RETURN_OK();
067417af
ML
1933}
1934
7a6d2196 1935static enum sp_return set_config(struct sp_port *port, struct port_data *data,
eb6ed20f 1936 const struct sp_port_config *config)
18fc2dd1 1937{
e33ab9aa 1938 unsigned int i;
31b3a8f5
MH
1939#ifdef __APPLE__
1940 BAUD_TYPE baud_nonstd;
1941
1942 baud_nonstd = B0;
1943#endif
5cea279a 1944#ifdef USE_TERMIOS_SPEED
7a6d2196
ML
1945 int baud_nonstd = 0;
1946#endif
18fc2dd1 1947
c33efc48
ML
1948 TRACE("%p, %p, %p", port, data, config);
1949
7890cef6 1950 DEBUG_FMT("Setting configuration for port %s", port->name);
ea667be7 1951
e33ab9aa 1952#ifdef _WIN32
6bd6a8b5
ML
1953
1954 TRY(await_write_completion(port));
1955
eac329d2 1956 if (config->baudrate >= 0) {
e33ab9aa
ML
1957 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1958 if (config->baudrate == std_baudrates[i].value) {
1959 data->dcb.BaudRate = std_baudrates[i].index;
1960 break;
1961 }
1962 }
18fc2dd1 1963
e33ab9aa
ML
1964 if (i == NUM_STD_BAUDRATES)
1965 data->dcb.BaudRate = config->baudrate;
39df7833
ML
1966
1967 /* Allocate write buffer for 50ms of data at baud rate. */
1968 port->write_buf_size = max(config->baudrate / (8 * 20), 1);
1969 port->write_buf = realloc(port->write_buf,
1970 port->write_buf_size);
1971
1972 if (!port->write_buf)
1973 RETURN_ERROR(SP_ERR_MEM, "Allocating write buffer failed");
e33ab9aa 1974 }
18fc2dd1 1975
e33ab9aa
ML
1976 if (config->bits >= 0)
1977 data->dcb.ByteSize = config->bits;
1978
1979 if (config->parity >= 0) {
1980 switch (config->parity) {
e33ab9aa
ML
1981 case SP_PARITY_NONE:
1982 data->dcb.Parity = NOPARITY;
1983 break;
e432ce60
ML
1984 case SP_PARITY_ODD:
1985 data->dcb.Parity = ODDPARITY;
1986 break;
e33ab9aa
ML
1987 case SP_PARITY_EVEN:
1988 data->dcb.Parity = EVENPARITY;
1989 break;
e432ce60
ML
1990 case SP_PARITY_MARK:
1991 data->dcb.Parity = MARKPARITY;
1992 break;
1993 case SP_PARITY_SPACE:
1994 data->dcb.Parity = SPACEPARITY;
e33ab9aa
ML
1995 break;
1996 default:
c33efc48 1997 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
e33ab9aa 1998 }
18fc2dd1
ML
1999 }
2000
e33ab9aa
ML
2001 if (config->stopbits >= 0) {
2002 switch (config->stopbits) {
2003 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
2004 case 1:
2005 data->dcb.StopBits = ONESTOPBIT;
2006 break;
2007 case 2:
2008 data->dcb.StopBits = TWOSTOPBITS;
2009 break;
2010 default:
c33efc48 2011 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
e33ab9aa
ML
2012 }
2013 }
2014
2015 if (config->rts >= 0) {
2016 switch (config->rts) {
2017 case SP_RTS_OFF:
2018 data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
2019 break;
2020 case SP_RTS_ON:
2021 data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
2022 break;
2023 case SP_RTS_FLOW_CONTROL:
2024 data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
2025 break;
2026 default:
c33efc48 2027 RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
e33ab9aa
ML
2028 }
2029 }
2030
2031 if (config->cts >= 0) {
2032 switch (config->cts) {
2033 case SP_CTS_IGNORE:
2034 data->dcb.fOutxCtsFlow = FALSE;
2035 break;
2036 case SP_CTS_FLOW_CONTROL:
2037 data->dcb.fOutxCtsFlow = TRUE;
2038 break;
2039 default:
c33efc48 2040 RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
e33ab9aa
ML
2041 }
2042 }
2043
2044 if (config->dtr >= 0) {
2045 switch (config->dtr) {
2046 case SP_DTR_OFF:
2047 data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
2048 break;
2049 case SP_DTR_ON:
2050 data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
2051 break;
2052 case SP_DTR_FLOW_CONTROL:
2053 data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
2054 break;
2055 default:
c33efc48 2056 RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
e33ab9aa
ML
2057 }
2058 }
2059
2060 if (config->dsr >= 0) {
2061 switch (config->dsr) {
2062 case SP_DSR_IGNORE:
2063 data->dcb.fOutxDsrFlow = FALSE;
2064 break;
2065 case SP_DSR_FLOW_CONTROL:
2066 data->dcb.fOutxDsrFlow = TRUE;
2067 break;
2068 default:
c33efc48 2069 RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
e33ab9aa 2070 }
18fc2dd1
ML
2071 }
2072
e33ab9aa
ML
2073 if (config->xon_xoff >= 0) {
2074 switch (config->xon_xoff) {
2075 case SP_XONXOFF_DISABLED:
2076 data->dcb.fInX = FALSE;
2077 data->dcb.fOutX = FALSE;
2078 break;
2079 case SP_XONXOFF_IN:
2080 data->dcb.fInX = TRUE;
2081 data->dcb.fOutX = FALSE;
2082 break;
2083 case SP_XONXOFF_OUT:
2084 data->dcb.fInX = FALSE;
2085 data->dcb.fOutX = TRUE;
2086 break;
2087 case SP_XONXOFF_INOUT:
2088 data->dcb.fInX = TRUE;
2089 data->dcb.fOutX = TRUE;
2090 break;
2091 default:
c33efc48 2092 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
e33ab9aa
ML
2093 }
2094 }
2095
2096 if (!SetCommState(port->hdl, &data->dcb))
c33efc48 2097 RETURN_FAIL("SetCommState() failed");
e33ab9aa 2098
31b3a8f5 2099#else /* !_WIN32 */
e33ab9aa 2100
7a6d2196
ML
2101 int controlbits;
2102
eac329d2 2103 if (config->baudrate >= 0) {
e33ab9aa
ML
2104 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2105 if (config->baudrate == std_baudrates[i].value) {
2106 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
c33efc48 2107 RETURN_FAIL("cfsetospeed() failed");
e33ab9aa
ML
2108
2109 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
c33efc48 2110 RETURN_FAIL("cfsetispeed() failed");
e33ab9aa
ML
2111 break;
2112 }
2113 }
2114
31b3a8f5
MH
2115 /* Non-standard baud rate */
2116 if (i == NUM_STD_BAUDRATES) {
2117#ifdef __APPLE__
24abdb68 2118 /* Set "dummy" baud rate. */
31b3a8f5 2119 if (cfsetspeed(&data->term, B9600) < 0)
c33efc48 2120 RETURN_FAIL("cfsetspeed() failed");
31b3a8f5 2121 baud_nonstd = config->baudrate;
5cea279a 2122#elif defined(USE_TERMIOS_SPEED)
7a6d2196 2123 baud_nonstd = 1;
31b3a8f5 2124#else
c33efc48 2125 RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
31b3a8f5
MH
2126#endif
2127 }
e33ab9aa
ML
2128 }
2129
2130 if (config->bits >= 0) {
2131 data->term.c_cflag &= ~CSIZE;
2132 switch (config->bits) {
2133 case 8:
2134 data->term.c_cflag |= CS8;
2135 break;
2136 case 7:
2137 data->term.c_cflag |= CS7;
2138 break;
2139 case 6:
2140 data->term.c_cflag |= CS6;
2141 break;
23922313
UH
2142 case 5:
2143 data->term.c_cflag |= CS5;
2144 break;
e33ab9aa 2145 default:
c33efc48 2146 RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
e33ab9aa
ML
2147 }
2148 }
2149
2150 if (config->parity >= 0) {
2151 data->term.c_iflag &= ~IGNPAR;
c3e05092
UH
2152 data->term.c_cflag &= ~(PARENB | PARODD);
2153#ifdef CMSPAR
2154 data->term.c_cflag &= ~CMSPAR;
2155#endif
e33ab9aa
ML
2156 switch (config->parity) {
2157 case SP_PARITY_NONE:
2158 data->term.c_iflag |= IGNPAR;
2159 break;
2160 case SP_PARITY_EVEN:
2161 data->term.c_cflag |= PARENB;
2162 break;
2163 case SP_PARITY_ODD:
2164 data->term.c_cflag |= PARENB | PARODD;
2165 break;
afb518f0 2166#ifdef CMSPAR
e432ce60 2167 case SP_PARITY_MARK:
c3e05092 2168 data->term.c_cflag |= PARENB | PARODD;
c3e05092 2169 data->term.c_cflag |= CMSPAR;
e432ce60
ML
2170 break;
2171 case SP_PARITY_SPACE:
c3e05092 2172 data->term.c_cflag |= PARENB;
c3e05092 2173 data->term.c_cflag |= CMSPAR;
e432ce60 2174 break;
afb518f0
ML
2175#else
2176 case SP_PARITY_MARK:
2177 case SP_PARITY_SPACE:
2178 RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported");
2179#endif
e33ab9aa 2180 default:
c33efc48 2181 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
e33ab9aa
ML
2182 }
2183 }
2184
2185 if (config->stopbits >= 0) {
2186 data->term.c_cflag &= ~CSTOPB;
2187 switch (config->stopbits) {
2188 case 1:
2189 data->term.c_cflag &= ~CSTOPB;
2190 break;
2191 case 2:
2192 data->term.c_cflag |= CSTOPB;
2193 break;
2194 default:
c33efc48 2195 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
e33ab9aa
ML
2196 }
2197 }
2198
eac329d2 2199 if (config->rts >= 0 || config->cts >= 0) {
68ec29db 2200 if (data->termiox_supported) {
bd791fe1 2201 data->rts_flow = data->cts_flow = 0;
68ec29db
ML
2202 switch (config->rts) {
2203 case SP_RTS_OFF:
2204 case SP_RTS_ON:
2205 controlbits = TIOCM_RTS;
2206 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
c33efc48 2207 RETURN_FAIL("Setting RTS signal level failed");
68ec29db
ML
2208 break;
2209 case SP_RTS_FLOW_CONTROL:
bd791fe1 2210 data->rts_flow = 1;
68ec29db
ML
2211 break;
2212 default:
2213 break;
e33ab9aa 2214 }
68ec29db 2215 if (config->cts == SP_CTS_FLOW_CONTROL)
bd791fe1 2216 data->cts_flow = 1;
e33ab9aa 2217
bd791fe1 2218 if (data->rts_flow && data->cts_flow)
e33ab9aa 2219 data->term.c_iflag |= CRTSCTS;
68ec29db
ML
2220 else
2221 data->term.c_iflag &= ~CRTSCTS;
2222 } else {
2223 /* Asymmetric use of RTS/CTS not supported. */
2224 if (data->term.c_iflag & CRTSCTS) {
2225 /* Flow control can only be disabled for both RTS & CTS together. */
2226 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
2227 if (config->cts != SP_CTS_IGNORE)
c33efc48 2228 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
68ec29db
ML
2229 }
2230 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
2231 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
c33efc48 2232 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
68ec29db 2233 }
e33ab9aa 2234 } else {
68ec29db
ML
2235 /* Flow control can only be enabled for both RTS & CTS together. */
2236 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
2237 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
c33efc48 2238 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together");
68ec29db
ML
2239 }
2240
2241 if (config->rts >= 0) {
2242 if (config->rts == SP_RTS_FLOW_CONTROL) {
2243 data->term.c_iflag |= CRTSCTS;
2244 } else {
2245 controlbits = TIOCM_RTS;
2246 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
2247 &controlbits) < 0)
c33efc48 2248 RETURN_FAIL("Setting RTS signal level failed");
68ec29db 2249 }
e33ab9aa
ML
2250 }
2251 }
2252 }
2253
eac329d2 2254 if (config->dtr >= 0 || config->dsr >= 0) {
68ec29db 2255 if (data->termiox_supported) {
bd791fe1 2256 data->dtr_flow = data->dsr_flow = 0;
68ec29db
ML
2257 switch (config->dtr) {
2258 case SP_DTR_OFF:
2259 case SP_DTR_ON:
2260 controlbits = TIOCM_DTR;
2261 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
c33efc48 2262 RETURN_FAIL("Setting DTR signal level failed");
68ec29db
ML
2263 break;
2264 case SP_DTR_FLOW_CONTROL:
bd791fe1 2265 data->dtr_flow = 1;
68ec29db
ML
2266 break;
2267 default:
2268 break;
2269 }
2270 if (config->dsr == SP_DSR_FLOW_CONTROL)
bd791fe1 2271 data->dsr_flow = 1;
68ec29db
ML
2272 } else {
2273 /* DTR/DSR flow control not supported. */
2274 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
c33efc48 2275 RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported");
e33ab9aa 2276
68ec29db
ML
2277 if (config->dtr >= 0) {
2278 controlbits = TIOCM_DTR;
2279 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
2280 &controlbits) < 0)
c33efc48 2281 RETURN_FAIL("Setting DTR signal level failed");
68ec29db 2282 }
e33ab9aa
ML
2283 }
2284 }
2285
2286 if (config->xon_xoff >= 0) {
2287 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
2288 switch (config->xon_xoff) {
2289 case SP_XONXOFF_DISABLED:
2290 break;
2291 case SP_XONXOFF_IN:
2292 data->term.c_iflag |= IXOFF;
2293 break;
2294 case SP_XONXOFF_OUT:
2295 data->term.c_iflag |= IXON | IXANY;
2296 break;
2297 case SP_XONXOFF_INOUT:
2298 data->term.c_iflag |= IXON | IXOFF | IXANY;
2299 break;
2300 default:
c33efc48 2301 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
e33ab9aa
ML
2302 }
2303 }
2304
3f5c06d0 2305 if (tcsetattr(port->fd, TCSANOW, &data->term) < 0)
c33efc48 2306 RETURN_FAIL("tcsetattr() failed");
31b3a8f5
MH
2307
2308#ifdef __APPLE__
2309 if (baud_nonstd != B0) {
2310 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
c33efc48 2311 RETURN_FAIL("IOSSIOSPEED ioctl failed");
dc422c04
UH
2312 /*
2313 * Set baud rates in data->term to correct, but incompatible
2314 * with tcsetattr() value, same as delivered by tcgetattr().
2315 */
31b3a8f5 2316 if (cfsetspeed(&data->term, baud_nonstd) < 0)
c33efc48 2317 RETURN_FAIL("cfsetspeed() failed");
31b3a8f5 2318 }
7a6d2196 2319#elif defined(__linux__)
5cea279a 2320#ifdef USE_TERMIOS_SPEED
7a6d2196
ML
2321 if (baud_nonstd)
2322 TRY(set_baudrate(port->fd, config->baudrate));
5cea279a 2323#endif
40978c2b 2324#ifdef USE_TERMIOX
68ec29db 2325 if (data->termiox_supported)
bd791fe1 2326 TRY(set_flow(port->fd, data));
40978c2b 2327#endif
7a6d2196 2328#endif
31b3a8f5
MH
2329
2330#endif /* !_WIN32 */
e33ab9aa 2331
c33efc48 2332 RETURN_OK();
e33ab9aa
ML
2333}
2334
970f279a 2335SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr)
9b1502ef 2336{
59131d60 2337 struct sp_port_config *config;
9b1502ef 2338
00d8c56d
UH
2339 TRACE("%p", config_ptr);
2340
9b1502ef
ML
2341 if (!config_ptr)
2342 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
2343
59131d60
ML
2344 *config_ptr = NULL;
2345
2346 if (!(config = malloc(sizeof(struct sp_port_config))))
dc422c04 2347 RETURN_ERROR(SP_ERR_MEM, "Config malloc failed");
9b1502ef 2348
59131d60
ML
2349 config->baudrate = -1;
2350 config->bits = -1;
2351 config->parity = -1;
2352 config->stopbits = -1;
2353 config->rts = -1;
2354 config->cts = -1;
2355 config->dtr = -1;
2356 config->dsr = -1;
2357
2358 *config_ptr = config;
2359
9b1502ef
ML
2360 RETURN_OK();
2361}
2362
970f279a 2363SP_API void sp_free_config(struct sp_port_config *config)
9b1502ef
ML
2364{
2365 TRACE("%p", config);
2366
2367 if (!config)
2368 DEBUG("Null config");
2369 else
2370 free(config);
2371
2372 RETURN();
2373}
2374
970f279a
AJ
2375SP_API enum sp_return sp_get_config(struct sp_port *port,
2376 struct sp_port_config *config)
70cd37de
ML
2377{
2378 struct port_data data;
2379
2380 TRACE("%p, %p", port, config);
2381
2382 CHECK_OPEN_PORT();
2383
2384 if (!config)
9b1502ef 2385 RETURN_ERROR(SP_ERR_ARG, "Null config");
70cd37de
ML
2386
2387 TRY(get_config(port, &data, config));
2388
2389 RETURN_OK();
2390}
2391
970f279a
AJ
2392SP_API enum sp_return sp_set_config(struct sp_port *port,
2393 const struct sp_port_config *config)
e33ab9aa 2394{
8f189c4c 2395 struct port_data data;
e33ab9aa
ML
2396 struct sp_port_config prev_config;
2397
c33efc48
ML
2398 TRACE("%p, %p", port, config);
2399
dec10e31 2400 CHECK_OPEN_PORT();
823690ae
ML
2401
2402 if (!config)
c33efc48 2403 RETURN_ERROR(SP_ERR_ARG, "Null config");
823690ae 2404
e33ab9aa
ML
2405 TRY(get_config(port, &data, &prev_config));
2406 TRY(set_config(port, &data, config));
74510d4b 2407
c33efc48 2408 RETURN_OK();
74510d4b
ML
2409}
2410
9b1502ef 2411#define CREATE_ACCESSORS(x, type) \
970f279a 2412SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \
8f189c4c 2413 struct port_data data; \
e33ab9aa 2414 struct sp_port_config config; \
c33efc48 2415 TRACE("%p, %d", port, x); \
dec10e31 2416 CHECK_OPEN_PORT(); \
e33ab9aa
ML
2417 TRY(get_config(port, &data, &config)); \
2418 config.x = x; \
2419 TRY(set_config(port, &data, &config)); \
c33efc48 2420 RETURN_OK(); \
9b1502ef 2421} \
970f279a
AJ
2422SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \
2423 type *x) { \
00d8c56d 2424 TRACE("%p, %p", config, x); \
6aad5bdd
UH
2425 if (!x) \
2426 RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); \
9b1502ef
ML
2427 if (!config) \
2428 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2429 *x = config->x; \
2430 RETURN_OK(); \
2431} \
970f279a
AJ
2432SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \
2433 type x) { \
9b1502ef
ML
2434 TRACE("%p, %d", config, x); \
2435 if (!config) \
2436 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2437 config->x = x; \
2438 RETURN_OK(); \
9069c2fb
ML
2439}
2440
9b1502ef
ML
2441CREATE_ACCESSORS(baudrate, int)
2442CREATE_ACCESSORS(bits, int)
2443CREATE_ACCESSORS(parity, enum sp_parity)
2444CREATE_ACCESSORS(stopbits, int)
2445CREATE_ACCESSORS(rts, enum sp_rts)
2446CREATE_ACCESSORS(cts, enum sp_cts)
2447CREATE_ACCESSORS(dtr, enum sp_dtr)
2448CREATE_ACCESSORS(dsr, enum sp_dsr)
2449CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff)
2450
970f279a
AJ
2451SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config,
2452 enum sp_flowcontrol flowcontrol)
e33ab9aa 2453{
9b1502ef
ML
2454 if (!config)
2455 RETURN_ERROR(SP_ERR_ARG, "Null configuration");
dec10e31
ML
2456
2457 if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
2458 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
823690ae 2459
e33ab9aa 2460 if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
9b1502ef 2461 config->xon_xoff = SP_XONXOFF_INOUT;
e33ab9aa 2462 else
9b1502ef 2463 config->xon_xoff = SP_XONXOFF_DISABLED;
e33ab9aa
ML
2464
2465 if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
9b1502ef
ML
2466 config->rts = SP_RTS_FLOW_CONTROL;
2467 config->cts = SP_CTS_FLOW_CONTROL;
e33ab9aa 2468 } else {
9b1502ef
ML
2469 if (config->rts == SP_RTS_FLOW_CONTROL)
2470 config->rts = SP_RTS_ON;
2471 config->cts = SP_CTS_IGNORE;
e33ab9aa
ML
2472 }
2473
2474 if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
9b1502ef
ML
2475 config->dtr = SP_DTR_FLOW_CONTROL;
2476 config->dsr = SP_DSR_FLOW_CONTROL;
e33ab9aa 2477 } else {
9b1502ef
ML
2478 if (config->dtr == SP_DTR_FLOW_CONTROL)
2479 config->dtr = SP_DTR_ON;
2480 config->dsr = SP_DSR_IGNORE;
e33ab9aa
ML
2481 }
2482
9b1502ef
ML
2483 RETURN_OK();
2484}
2485
970f279a
AJ
2486SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port,
2487 enum sp_flowcontrol flowcontrol)
9b1502ef
ML
2488{
2489 struct port_data data;
2490 struct sp_port_config config;
2491
2492 TRACE("%p, %d", port, flowcontrol);
2493
2494 CHECK_OPEN_PORT();
2495
2496 TRY(get_config(port, &data, &config));
2497
2498 TRY(sp_set_config_flowcontrol(&config, flowcontrol));
2499
e33ab9aa
ML
2500 TRY(set_config(port, &data, &config));
2501
c33efc48 2502 RETURN_OK();
e33ab9aa
ML
2503}
2504
970f279a
AJ
2505SP_API enum sp_return sp_get_signals(struct sp_port *port,
2506 enum sp_signal *signals)
8cf7c697 2507{
c33efc48
ML
2508 TRACE("%p, %p", port, signals);
2509
dec10e31 2510 CHECK_OPEN_PORT();
8cf7c697
ML
2511
2512 if (!signals)
c33efc48 2513 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
8cf7c697 2514
7890cef6 2515 DEBUG_FMT("Getting control signals for port %s", port->name);
ea667be7 2516
8cf7c697
ML
2517 *signals = 0;
2518#ifdef _WIN32
2519 DWORD bits;
2520 if (GetCommModemStatus(port->hdl, &bits) == 0)
c33efc48 2521 RETURN_FAIL("GetCommModemStatus() failed");
8cf7c697
ML
2522 if (bits & MS_CTS_ON)
2523 *signals |= SP_SIG_CTS;
2524 if (bits & MS_DSR_ON)
2525 *signals |= SP_SIG_DSR;
8cf7c697 2526 if (bits & MS_RLSD_ON)
a6cda1e8
ML
2527 *signals |= SP_SIG_DCD;
2528 if (bits & MS_RING_ON)
8cf7c697
ML
2529 *signals |= SP_SIG_RI;
2530#else
2531 int bits;
2532 if (ioctl(port->fd, TIOCMGET, &bits) < 0)
c33efc48 2533 RETURN_FAIL("TIOCMGET ioctl failed");
8cf7c697
ML
2534 if (bits & TIOCM_CTS)
2535 *signals |= SP_SIG_CTS;
2536 if (bits & TIOCM_DSR)
2537 *signals |= SP_SIG_DSR;
2538 if (bits & TIOCM_CAR)
2539 *signals |= SP_SIG_DCD;
2540 if (bits & TIOCM_RNG)
2541 *signals |= SP_SIG_RI;
2542#endif
c33efc48 2543 RETURN_OK();
8cf7c697
ML
2544}
2545
970f279a 2546SP_API enum sp_return sp_start_break(struct sp_port *port)
90cc3ee6 2547{
c33efc48
ML
2548 TRACE("%p", port);
2549
dec10e31 2550 CHECK_OPEN_PORT();
90cc3ee6
ML
2551#ifdef _WIN32
2552 if (SetCommBreak(port->hdl) == 0)
c33efc48 2553 RETURN_FAIL("SetCommBreak() failed");
90cc3ee6
ML
2554#else
2555 if (ioctl(port->fd, TIOCSBRK, 1) < 0)
c33efc48 2556 RETURN_FAIL("TIOCSBRK ioctl failed");
90cc3ee6
ML
2557#endif
2558
c33efc48 2559 RETURN_OK();
90cc3ee6
ML
2560}
2561
970f279a 2562SP_API enum sp_return sp_end_break(struct sp_port *port)
90cc3ee6 2563{
c33efc48
ML
2564 TRACE("%p", port);
2565
dec10e31 2566 CHECK_OPEN_PORT();
90cc3ee6
ML
2567#ifdef _WIN32
2568 if (ClearCommBreak(port->hdl) == 0)
c33efc48 2569 RETURN_FAIL("ClearCommBreak() failed");
90cc3ee6
ML
2570#else
2571 if (ioctl(port->fd, TIOCCBRK, 1) < 0)
c33efc48 2572 RETURN_FAIL("TIOCCBRK ioctl failed");
90cc3ee6
ML
2573#endif
2574
c33efc48 2575 RETURN_OK();
90cc3ee6
ML
2576}
2577
970f279a 2578SP_API int sp_last_error_code(void)
74510d4b 2579{
7890cef6 2580 TRACE_VOID();
74510d4b 2581#ifdef _WIN32
9caa2e86 2582 RETURN_INT(GetLastError());
74510d4b 2583#else
9caa2e86 2584 RETURN_INT(errno);
74510d4b
ML
2585#endif
2586}
2587
970f279a 2588SP_API char *sp_last_error_message(void)
74510d4b 2589{
7890cef6 2590 TRACE_VOID();
c33efc48 2591
74510d4b 2592#ifdef _WIN32
9a0c4bbd 2593 TCHAR *message;
74510d4b
ML
2594 DWORD error = GetLastError();
2595
9a0c4bbd 2596 DWORD length = FormatMessage(
74510d4b
ML
2597 FORMAT_MESSAGE_ALLOCATE_BUFFER |
2598 FORMAT_MESSAGE_FROM_SYSTEM |
2599 FORMAT_MESSAGE_IGNORE_INSERTS,
2600 NULL,
2601 error,
2602 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2603 (LPTSTR) &message,
2604 0, NULL );
2605
9a0c4bbd
ML
2606 if (length >= 2 && message[length - 2] == '\r')
2607 message[length - 2] = '\0';
2608
9caa2e86 2609 RETURN_STRING(message);
74510d4b 2610#else
9caa2e86 2611 RETURN_STRING(strerror(errno));
74510d4b
ML
2612#endif
2613}
2614
970f279a 2615SP_API void sp_free_error_message(char *message)
74510d4b 2616{
c33efc48
ML
2617 TRACE("%s", message);
2618
74510d4b
ML
2619#ifdef _WIN32
2620 LocalFree(message);
64eec30d
ML
2621#else
2622 (void)message;
74510d4b 2623#endif
c33efc48
ML
2624
2625 RETURN();
74510d4b 2626}
863b35e6 2627
970f279a 2628SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...))
863b35e6 2629{
c33efc48
ML
2630 TRACE("%p", handler);
2631
863b35e6 2632 sp_debug_handler = handler;
c33efc48
ML
2633
2634 RETURN();
863b35e6
ML
2635}
2636
970f279a 2637SP_API void sp_default_debug_handler(const char *format, ...)
863b35e6
ML
2638{
2639 va_list args;
2640 va_start(args, format);
2641 if (getenv("LIBSERIALPORT_DEBUG")) {
dd7742fb 2642 fputs("sp: ", stderr);
863b35e6
ML
2643 vfprintf(stderr, format, args);
2644 }
2645 va_end(args);
2646}
524b0e14 2647
970f279a 2648SP_API int sp_get_major_package_version(void)
524b0e14
UH
2649{
2650 return SP_PACKAGE_VERSION_MAJOR;
2651}
2652
970f279a 2653SP_API int sp_get_minor_package_version(void)
524b0e14
UH
2654{
2655 return SP_PACKAGE_VERSION_MINOR;
2656}
2657
970f279a 2658SP_API int sp_get_micro_package_version(void)
524b0e14
UH
2659{
2660 return SP_PACKAGE_VERSION_MICRO;
2661}
2662
970f279a 2663SP_API const char *sp_get_package_version_string(void)
524b0e14
UH
2664{
2665 return SP_PACKAGE_VERSION_STRING;
2666}
2667
970f279a 2668SP_API int sp_get_current_lib_version(void)
524b0e14
UH
2669{
2670 return SP_LIB_VERSION_CURRENT;
2671}
2672
970f279a 2673SP_API int sp_get_revision_lib_version(void)
524b0e14
UH
2674{
2675 return SP_LIB_VERSION_REVISION;
2676}
2677
970f279a 2678SP_API int sp_get_age_lib_version(void)
524b0e14
UH
2679{
2680 return SP_LIB_VERSION_AGE;
2681}
2682
970f279a 2683SP_API const char *sp_get_lib_version_string(void)
524b0e14
UH
2684{
2685 return SP_LIB_VERSION_STRING;
2686}
2687
2688/** @} */