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