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