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