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