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