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