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