]> sigrok.org Git - libserialport.git/blame - serialport.c
Fix memory leaks.
[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>
74510d4b
ML
30#ifdef _WIN32
31#include <windows.h>
3b63f34d 32#include <tchar.h>
767c5ba8 33#include <stdio.h>
74510d4b 34#else
74510d4b
ML
35#include <termios.h>
36#include <sys/ioctl.h>
37#endif
3b63f34d 38#ifdef __APPLE__
1ebf4347
ML
39#include <IOKit/IOKitLib.h>
40#include <IOKit/serial/IOSerialKeys.h>
31b3a8f5 41#include <IOKit/serial/ioss.h>
1ebf4347 42#include <sys/syslimits.h>
3b63f34d
ML
43#endif
44#ifdef __linux__
45#include "libudev.h"
4b97c9fc 46#include "linux/serial.h"
7a6d2196 47#include "linux_termios.h"
40978c2b 48#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
1d5d2a16
UH
49// FIXME: Temporarily disabled, breaks all lib functionality on some systems.
50// #define USE_TERMIOX
40978c2b 51#endif
3b63f34d 52#endif
74510d4b 53
f6a1fb65 54#include "libserialport.h"
74510d4b 55
8f189c4c 56struct port_data {
8094e4a0
ML
57#ifdef _WIN32
58 DCB dcb;
59#else
60 struct termios term;
824dcb45 61 int controlbits;
40978c2b
ML
62#ifdef USE_TERMIOX
63 int flow;
64#endif
8094e4a0
ML
65#endif
66};
67
da2748bf
ML
68/* Standard baud rates. */
69#ifdef _WIN32
70#define BAUD_TYPE DWORD
71#define BAUD(n) {CBR_##n, n}
72#else
73#define BAUD_TYPE speed_t
74#define BAUD(n) {B##n, n}
75#endif
76
77struct std_baudrate {
78 BAUD_TYPE index;
79 int value;
80};
81
82const struct std_baudrate std_baudrates[] = {
83#ifdef _WIN32
84 /*
85 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
86 * have documented CBR_* macros.
87 */
88 BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
89 BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
eac329d2 90 BAUD(115200), BAUD(128000), BAUD(256000),
da2748bf 91#else
eac329d2
UH
92 BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
93 BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
94 BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
95 BAUD(230400),
da2748bf 96#if !defined(__APPLE__) && !defined(__OpenBSD__)
eac329d2 97 BAUD(460800),
da2748bf
ML
98#endif
99#endif
100};
101
102#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
103#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
104
7a6d2196
ML
105#define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
106
348e23cc 107/* Helper functions. */
eb6ed20f 108static enum sp_return validate_port(struct sp_port *port);
348e23cc 109static struct sp_port **list_append(struct sp_port **list, const char *portname);
eb6ed20f
ML
110static enum sp_return get_config(struct sp_port *port, struct port_data *data,
111 struct sp_port_config *config);
112static enum sp_return set_config(struct sp_port *port, struct port_data *data,
113 const struct sp_port_config *config);
80186526 114
eb6ed20f 115enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
d54e9004
ML
116{
117 struct sp_port *port;
5919c913 118 int len;
d54e9004 119
32b5ac05
ML
120 if (!port_ptr)
121 return SP_ERR_ARG;
122
77f262c4
ML
123 *port_ptr = NULL;
124
d4babed2 125 if (!portname)
77f262c4 126 return SP_ERR_ARG;
d4babed2 127
d54e9004 128 if (!(port = malloc(sizeof(struct sp_port))))
77f262c4 129 return SP_ERR_MEM;
d54e9004 130
5919c913
ML
131 len = strlen(portname) + 1;
132
eac329d2 133 if (!(port->name = malloc(len))) {
d54e9004 134 free(port);
77f262c4 135 return SP_ERR_MEM;
d54e9004
ML
136 }
137
138 memcpy(port->name, portname, len);
139
8f471c66
ML
140#ifdef _WIN32
141 port->hdl = INVALID_HANDLE_VALUE;
142#else
143 port->fd = -1;
144#endif
145
77f262c4
ML
146 *port_ptr = port;
147
148 return SP_OK;
d54e9004
ML
149}
150
eb6ed20f 151enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
32b5ac05
ML
152{
153 if (!copy_ptr)
154 return SP_ERR_ARG;
155
156 *copy_ptr = NULL;
157
158 if (!port || !port->name)
159 return SP_ERR_ARG;
160
161 return sp_get_port_by_name(port->name, copy_ptr);
162}
163
e3b2f7a4
ML
164void sp_free_port(struct sp_port *port)
165{
166 if (!port)
167 return;
168
169 if (port->name)
170 free(port->name);
171
172 free(port);
173}
174
348e23cc 175static struct sp_port **list_append(struct sp_port **list, const char *portname)
3b63f34d
ML
176{
177 void *tmp;
178 unsigned int count;
f92f1f0c 179
3b63f34d 180 for (count = 0; list[count]; count++);
d54e9004 181 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
3b63f34d
ML
182 goto fail;
183 list = tmp;
77f262c4 184 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
3b63f34d 185 goto fail;
db2794ce 186 list[count + 1] = NULL;
3b63f34d 187 return list;
f92f1f0c 188
3b63f34d
ML
189fail:
190 sp_free_port_list(list);
191 return NULL;
192}
193
eb6ed20f 194enum sp_return sp_list_ports(struct sp_port ***list_ptr)
3b63f34d 195{
d54e9004 196 struct sp_port **list;
77f262c4 197 int ret = SP_OK;
24c1a4bb 198
d54e9004 199 if (!(list = malloc(sizeof(struct sp_port **))))
f92f1f0c 200 return SP_ERR_MEM;
24c1a4bb
ML
201
202 list[0] = NULL;
3b63f34d
ML
203
204#ifdef _WIN32
205 HKEY key;
bdfb5b8c
ML
206 TCHAR *value, *data;
207 DWORD max_value_len, max_data_size, max_data_len;
208 DWORD value_len, data_size, data_len;
3b63f34d 209 DWORD type, index = 0;
8b532d9c
ML
210 char *name;
211 int name_len;
3b63f34d
ML
212
213 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
eac329d2 214 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
77f262c4
ML
215 ret = SP_ERR_FAIL;
216 goto out_done;
217 }
3b63f34d 218 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
eac329d2 219 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
77f262c4 220 ret = SP_ERR_FAIL;
3b63f34d 221 goto out_close;
77f262c4 222 }
3b63f34d 223 max_data_len = max_data_size / sizeof(TCHAR);
eac329d2 224 if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
77f262c4 225 ret = SP_ERR_MEM;
3b63f34d 226 goto out_close;
77f262c4 227 }
eac329d2 228 if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
77f262c4 229 ret = SP_ERR_MEM;
bdfb5b8c 230 goto out_free_value;
77f262c4 231 }
3b63f34d 232 while (
d9573bad 233 value_len = max_value_len + 1,
3b63f34d 234 data_size = max_data_size,
bdfb5b8c 235 RegEnumValue(key, index, value, &value_len,
3b63f34d
ML
236 NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
237 {
238 data_len = data_size / sizeof(TCHAR);
239 data[data_len] = '\0';
8b532d9c
ML
240#ifdef UNICODE
241 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL)
242#else
243 name_len = data_len + 1;
244#endif
eac329d2 245 if (!(name = malloc(name_len))) {
77f262c4 246 ret = SP_ERR_MEM;
8b532d9c 247 goto out;
77f262c4 248 }
8b532d9c
ML
249#ifdef UNICODE
250 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
251#else
252 strcpy(name, data);
253#endif
eac329d2 254 if (type == REG_SZ && !(list = list_append(list, name))) {
77f262c4
ML
255 ret = SP_ERR_MEM;
256 goto out;
257 }
3b63f34d
ML
258 index++;
259 }
260out:
261 free(data);
bdfb5b8c
ML
262out_free_value:
263 free(value);
3b63f34d
ML
264out_close:
265 RegCloseKey(key);
77f262c4 266out_done:
3b63f34d
ML
267#endif
268#ifdef __APPLE__
269 mach_port_t master;
270 CFMutableDictionaryRef classes;
271 io_iterator_t iter;
272 char *path;
273 io_object_t port;
274 CFTypeRef cf_path;
275 Boolean result;
276
eac329d2 277 if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS) {
77f262c4
ML
278 ret = SP_ERR_FAIL;
279 goto out_done;
280 }
3b63f34d 281
eac329d2 282 if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
77f262c4
ML
283 ret = SP_ERR_FAIL;
284 goto out_done;
285 }
3b63f34d
ML
286
287 CFDictionarySetValue(classes,
288 CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
289
eac329d2 290 if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS) {
77f262c4
ML
291 ret = SP_ERR_FAIL;
292 goto out_done;
293 }
3b63f34d 294
eac329d2 295 if (!(path = malloc(PATH_MAX))) {
77f262c4 296 ret = SP_ERR_MEM;
3b63f34d 297 goto out_release;
77f262c4 298 }
3b63f34d 299
1ebf4347 300 while ((port = IOIteratorNext(iter))) {
3b63f34d
ML
301 cf_path = IORegistryEntryCreateCFProperty(port,
302 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
303 if (cf_path) {
304 result = CFStringGetCString(cf_path,
305 path, PATH_MAX, kCFStringEncodingASCII);
306 CFRelease(cf_path);
eac329d2 307 if (result && !(list = list_append(list, path))) {
77f262c4
ML
308 ret = SP_ERR_MEM;
309 IOObjectRelease(port);
310 goto out;
311 }
3b63f34d
ML
312 }
313 IOObjectRelease(port);
314 }
3b63f34d
ML
315out:
316 free(path);
317out_release:
318 IOObjectRelease(iter);
77f262c4 319out_done:
3b63f34d
ML
320#endif
321#ifdef __linux__
322 struct udev *ud;
323 struct udev_enumerate *ud_enumerate;
324 struct udev_list_entry *ud_list;
325 struct udev_list_entry *ud_entry;
326 const char *path;
08fe0bdb 327 struct udev_device *ud_dev, *ud_parent;
3b63f34d 328 const char *name;
4b97c9fc
ML
329 const char *driver;
330 int fd, ioctl_result;
331 struct serial_struct serial_info;
3b63f34d
ML
332
333 ud = udev_new();
334 ud_enumerate = udev_enumerate_new(ud);
335 udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
336 udev_enumerate_scan_devices(ud_enumerate);
337 ud_list = udev_enumerate_get_list_entry(ud_enumerate);
eac329d2 338 udev_list_entry_foreach(ud_entry, ud_list) {
3b63f34d
ML
339 path = udev_list_entry_get_name(ud_entry);
340 ud_dev = udev_device_new_from_syspath(ud, path);
08fe0bdb
ML
341 /* If there is no parent device, this is a virtual tty. */
342 ud_parent = udev_device_get_parent(ud_dev);
eac329d2 343 if (ud_parent == NULL) {
08fe0bdb
ML
344 udev_device_unref(ud_dev);
345 continue;
346 }
3b63f34d 347 name = udev_device_get_devnode(ud_dev);
4b97c9fc
ML
348 /* The serial8250 driver has a hardcoded number of ports.
349 * The only way to tell which actually exist on a given system
350 * is to try to open them and make an ioctl call. */
351 driver = udev_device_get_driver(ud_parent);
eac329d2 352 if (driver && !strcmp(driver, "serial8250")) {
4b97c9fc
ML
353 if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0)
354 goto skip;
355 ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
356 close(fd);
357 if (ioctl_result != 0)
358 goto skip;
359 if (serial_info.type == PORT_UNKNOWN)
360 goto skip;
361 }
348e23cc 362 list = list_append(list, name);
4b97c9fc 363skip:
3b63f34d 364 udev_device_unref(ud_dev);
eac329d2 365 if (!list) {
77f262c4 366 ret = SP_ERR_MEM;
3b63f34d 367 goto out;
77f262c4 368 }
3b63f34d
ML
369 }
370out:
371 udev_enumerate_unref(ud_enumerate);
372 udev_unref(ud);
3b63f34d 373#endif
77f262c4 374
eac329d2 375 if (ret == SP_OK) {
77f262c4 376 *list_ptr = list;
eac329d2 377 } else {
77f262c4
ML
378 if (list)
379 sp_free_port_list(list);
77f262c4
ML
380 *list_ptr = NULL;
381 }
382
383 return ret;
3b63f34d
ML
384}
385
d54e9004 386void sp_free_port_list(struct sp_port **list)
3b63f34d
ML
387{
388 unsigned int i;
f92f1f0c 389
3b63f34d 390 for (i = 0; list[i]; i++)
e3b2f7a4 391 sp_free_port(list[i]);
3b63f34d
ML
392 free(list);
393}
394
eb6ed20f 395static enum sp_return validate_port(struct sp_port *port)
74510d4b
ML
396{
397 if (port == NULL)
398 return 0;
399#ifdef _WIN32
400 if (port->hdl == INVALID_HANDLE_VALUE)
401 return 0;
402#else
403 if (port->fd < 0)
404 return 0;
405#endif
406 return 1;
407}
408
348e23cc 409#define CHECK_PORT() do { if (!validate_port(port)) return SP_ERR_ARG; } while (0)
74510d4b 410
eb6ed20f 411enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
74510d4b
ML
412{
413 if (!port)
414 return SP_ERR_ARG;
415
74510d4b
ML
416#ifdef _WIN32
417 DWORD desired_access = 0, flags_and_attributes = 0;
99945a1f
ML
418 char *escaped_port_name;
419
420 /* Prefix port name with '\\.\' to work with ports above COM9. */
421 if (!(escaped_port_name = malloc(strlen(port->name + 5))))
422 return SP_ERR_MEM;
423 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
424
74510d4b 425 /* Map 'flags' to the OS-specific settings. */
74510d4b 426 flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
a036341b
ML
427 if (flags & SP_MODE_READ)
428 desired_access |= GENERIC_READ;
429 if (flags & SP_MODE_WRITE)
74510d4b
ML
430 desired_access |= GENERIC_WRITE;
431 if (flags & SP_MODE_NONBLOCK)
432 flags_and_attributes |= FILE_FLAG_OVERLAPPED;
433
99945a1f 434 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
74510d4b 435 OPEN_EXISTING, flags_and_attributes, 0);
99945a1f
ML
436
437 free(escaped_port_name);
438
74510d4b
ML
439 if (port->hdl == INVALID_HANDLE_VALUE)
440 return SP_ERR_FAIL;
441#else
442 int flags_local = 0;
8f189c4c 443 struct port_data data;
e33ab9aa
ML
444 struct sp_port_config config;
445 int ret;
f92f1f0c 446
74510d4b 447 /* Map 'flags' to the OS-specific settings. */
a036341b 448 if (flags & (SP_MODE_READ | SP_MODE_WRITE))
74510d4b 449 flags_local |= O_RDWR;
a036341b 450 else if (flags & SP_MODE_READ)
74510d4b 451 flags_local |= O_RDONLY;
a036341b
ML
452 else if (flags & SP_MODE_WRITE)
453 flags_local |= O_WRONLY;
74510d4b
ML
454 if (flags & SP_MODE_NONBLOCK)
455 flags_local |= O_NONBLOCK;
456
457 if ((port->fd = open(port->name, flags_local)) < 0)
458 return SP_ERR_FAIL;
9cb98459 459
e33ab9aa
ML
460 ret = get_config(port, &data, &config);
461
eac329d2 462 if (ret < 0) {
e33ab9aa
ML
463 sp_close(port);
464 return ret;
465 }
9cb98459
ML
466
467 /* Turn off all serial port cooking. */
468 data.term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
469 data.term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
470#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
471 data.term.c_oflag &= ~OFILL;
472#endif
473 /* Disable canonical mode, and don't echo input characters. */
474 data.term.c_lflag &= ~(ICANON | ECHO);
475
476 /* Ignore modem status lines; enable receiver */
477 data.term.c_cflag |= (CLOCAL | CREAD);
478
e33ab9aa
ML
479 ret = set_config(port, &data, &config);
480
eac329d2 481 if (ret < 0) {
e33ab9aa
ML
482 sp_close(port);
483 return ret;
484 }
74510d4b
ML
485#endif
486
487 return SP_OK;
488}
489
eb6ed20f 490enum sp_return sp_close(struct sp_port *port)
74510d4b
ML
491{
492 CHECK_PORT();
493
494#ifdef _WIN32
495 /* Returns non-zero upon success, 0 upon failure. */
496 if (CloseHandle(port->hdl) == 0)
497 return SP_ERR_FAIL;
8f471c66 498 port->hdl = INVALID_HANDLE_VALUE;
74510d4b
ML
499#else
500 /* Returns 0 upon success, -1 upon failure. */
501 if (close(port->fd) == -1)
502 return SP_ERR_FAIL;
8f471c66 503 port->fd = -1;
74510d4b
ML
504#endif
505
506 return SP_OK;
507}
508
fd8fd11a 509enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
74510d4b
ML
510{
511 CHECK_PORT();
512
513#ifdef _WIN32
fd8fd11a
ML
514 DWORD flags = 0;
515 if (buffers & SP_BUF_INPUT)
516 flags |= PURGE_RXCLEAR;
517 if (buffers & SP_BUF_OUTPUT)
518 flags |= PURGE_TXCLEAR;
519
74510d4b 520 /* Returns non-zero upon success, 0 upon failure. */
fd8fd11a 521 if (PurgeComm(port->hdl, flags) == 0)
74510d4b
ML
522 return SP_ERR_FAIL;
523#else
fd8fd11a
ML
524 int flags = 0;
525 if (buffers & SP_BUF_BOTH)
526 flags = TCIOFLUSH;
527 else if (buffers & SP_BUF_INPUT)
528 flags = TCIFLUSH;
82f424e6 529 else if (buffers & SP_BUF_OUTPUT)
fd8fd11a
ML
530 flags = TCOFLUSH;
531
74510d4b 532 /* Returns 0 upon success, -1 upon failure. */
fd8fd11a 533 if (tcflush(port->fd, flags) < 0)
74510d4b
ML
534 return SP_ERR_FAIL;
535#endif
536 return SP_OK;
537}
538
69a3739c
ML
539enum sp_return sp_drain(struct sp_port *port)
540{
541 CHECK_PORT();
542
543#ifdef _WIN32
544 /* Returns non-zero upon success, 0 upon failure. */
545 if (FlushFileBuffers(port->hdl) == 0)
546 return SP_ERR_FAIL;
547#else
548 /* Returns 0 upon success, -1 upon failure. */
549 if (tcdrain(port->fd) < 0)
550 return SP_ERR_FAIL;
551#endif
552
553 return SP_OK;
554}
555
eb6ed20f 556enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count)
74510d4b
ML
557{
558 CHECK_PORT();
559
560 if (!buf)
561 return SP_ERR_ARG;
562
563#ifdef _WIN32
564 DWORD written = 0;
f92f1f0c 565
74510d4b
ML
566 /* Returns non-zero upon success, 0 upon failure. */
567 if (WriteFile(port->hdl, buf, count, &written, NULL) == 0)
568 return SP_ERR_FAIL;
569 return written;
570#else
571 /* Returns the number of bytes written, or -1 upon failure. */
572 ssize_t written = write(port->fd, buf, count);
f92f1f0c 573
74510d4b
ML
574 if (written < 0)
575 return SP_ERR_FAIL;
576 else
f92f1f0c 577 return written;
74510d4b
ML
578#endif
579}
580
eb6ed20f 581enum sp_return sp_read(struct sp_port *port, void *buf, size_t count)
74510d4b
ML
582{
583 CHECK_PORT();
584
585 if (!buf)
586 return SP_ERR_ARG;
587
588#ifdef _WIN32
589 DWORD bytes_read = 0;
f92f1f0c 590
74510d4b
ML
591 /* Returns non-zero upon success, 0 upon failure. */
592 if (ReadFile(port->hdl, buf, count, &bytes_read, NULL) == 0)
593 return SP_ERR_FAIL;
594 return bytes_read;
595#else
596 ssize_t bytes_read;
f92f1f0c 597
74510d4b
ML
598 /* Returns the number of bytes read, or -1 upon failure. */
599 if ((bytes_read = read(port->fd, buf, count)) < 0)
600 return SP_ERR_FAIL;
601 return bytes_read;
602#endif
603}
604
7a6d2196
ML
605#ifdef __linux__
606static enum sp_return get_baudrate(int fd, int *baudrate)
607{
608 void *data;
609
610 if (!(data = malloc(get_termios_size())))
611 return SP_ERR_MEM;
612
8d43110a
ML
613 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
614 free(data);
7a6d2196 615 return SP_ERR_FAIL;
8d43110a 616 }
7a6d2196
ML
617
618 *baudrate = get_termios_speed(data);
619
8d43110a
ML
620 free(data);
621
7a6d2196
ML
622 return SP_OK;
623}
624
625static enum sp_return set_baudrate(int fd, int baudrate)
626{
627 void *data;
628
629 if (!(data = malloc(get_termios_size())))
630 return SP_ERR_MEM;
631
8d43110a
ML
632 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
633 free(data);
7a6d2196 634 return SP_ERR_FAIL;
8d43110a 635 }
7a6d2196
ML
636
637 set_termios_speed(data, baudrate);
638
8d43110a
ML
639 if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
640 free(data);
7a6d2196 641 return SP_ERR_FAIL;
8d43110a
ML
642 }
643
644 free(data);
7a6d2196
ML
645
646 return SP_OK;
647}
40978c2b
ML
648
649#ifdef USE_TERMIOX
650static enum sp_return get_flow(int fd, int *flow)
651{
652 void *data;
653
654 if (!(data = malloc(get_termiox_size())))
655 return SP_ERR_MEM;
656
8d43110a
ML
657 if (ioctl(fd, TCGETX, data) < 0) {
658 free(data);
40978c2b 659 return SP_ERR_FAIL;
8d43110a 660 }
40978c2b
ML
661
662 *flow = get_termiox_flow(data);
663
8d43110a
ML
664 free(data);
665
40978c2b
ML
666 return SP_OK;
667}
668
669static enum sp_return set_flow(int fd, int flow)
670{
671 void *data;
672
673 if (!(data = malloc(get_termiox_size())))
674 return SP_ERR_MEM;
675
8d43110a
ML
676 if (ioctl(fd, TCGETX, data) < 0) {
677 free(data);
40978c2b 678 return SP_ERR_FAIL;
8d43110a 679 }
40978c2b
ML
680
681 set_termiox_flow(data, flow);
682
8d43110a
ML
683 if (ioctl(fd, TCSETX, data) < 0) {
684 free(data);
40978c2b 685 return SP_ERR_FAIL;
8d43110a
ML
686 }
687
688 free(data);
40978c2b
ML
689
690 return SP_OK;
691}
692#endif /* USE_TERMIOX */
693#endif /* __linux__ */
7a6d2196 694
eb6ed20f
ML
695static enum sp_return get_config(struct sp_port *port, struct port_data *data,
696 struct sp_port_config *config)
8094e4a0 697{
da2748bf 698 unsigned int i;
cbf628c7 699
8094e4a0 700#ifdef _WIN32
e33ab9aa 701 if (!GetCommState(port->hdl, &data->dcb))
d514a26f 702 return SP_ERR_FAIL;
8094e4a0 703
067417af 704 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 705 if (data->dcb.BaudRate == std_baudrates[i].index) {
067417af
ML
706 config->baudrate = std_baudrates[i].value;
707 break;
708 }
709 }
710
711 if (i == NUM_STD_BAUDRATES)
712 /* BaudRate field can be either an index or a custom baud rate. */
e33ab9aa 713 config->baudrate = data->dcb.BaudRate;
067417af 714
e33ab9aa 715 config->bits = data->dcb.ByteSize;
067417af 716
e33ab9aa
ML
717 if (data->dcb.fParity)
718 switch (data->dcb.Parity) {
067417af
ML
719 case NOPARITY:
720 config->parity = SP_PARITY_NONE;
721 break;
722 case EVENPARITY:
723 config->parity = SP_PARITY_EVEN;
724 break;
725 case ODDPARITY:
726 config->parity = SP_PARITY_ODD;
727 break;
728 default:
729 config->parity = -1;
730 }
731 else
732 config->parity = SP_PARITY_NONE;
733
e33ab9aa 734 switch (data->dcb.StopBits) {
067417af
ML
735 case ONESTOPBIT:
736 config->stopbits = 1;
737 break;
738 case TWOSTOPBITS:
739 config->stopbits = 2;
740 break;
741 default:
742 config->stopbits = -1;
743 }
744
e33ab9aa 745 switch (data->dcb.fRtsControl) {
eac329d2
UH
746 case RTS_CONTROL_DISABLE:
747 config->rts = SP_RTS_OFF;
748 break;
749 case RTS_CONTROL_ENABLE:
750 config->rts = SP_RTS_ON;
751 break;
752 case RTS_CONTROL_HANDSHAKE:
753 config->rts = SP_RTS_FLOW_CONTROL;
754 break;
755 default:
756 config->rts = -1;
067417af
ML
757 }
758
e33ab9aa 759 config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
067417af 760
e33ab9aa 761 switch (data->dcb.fDtrControl) {
eac329d2
UH
762 case DTR_CONTROL_DISABLE:
763 config->dtr = SP_DTR_OFF;
764 break;
765 case DTR_CONTROL_ENABLE:
766 config->dtr = SP_DTR_ON;
767 break;
768 case DTR_CONTROL_HANDSHAKE:
769 config->dtr = SP_DTR_FLOW_CONTROL;
770 break;
771 default:
772 config->dtr = -1;
067417af
ML
773 }
774
e33ab9aa
ML
775 config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
776
c6754b45
ML
777 if (data->dcb.fInX) {
778 if (data->dcb.fOutX)
779 config->xon_xoff = SP_XONXOFF_INOUT;
780 else
781 config->xon_xoff = SP_XONXOFF_IN;
782 } else {
783 if (data->dcb.fOutX)
784 config->xon_xoff = SP_XONXOFF_OUT;
785 else
786 config->xon_xoff = SP_XONXOFF_DISABLED;
787 }
788
e33ab9aa
ML
789#else // !_WIN32
790
791 if (tcgetattr(port->fd, &data->term) < 0)
792 return SP_ERR_FAIL;
793
794 if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
795 return SP_ERR_FAIL;
40978c2b
ML
796
797#ifdef USE_TERMIOX
798 TRY(get_flow(port->fd, &data->flow));
799#endif
800
067417af 801 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 802 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
067417af
ML
803 config->baudrate = std_baudrates[i].value;
804 break;
805 }
806 }
807
31b3a8f5
MH
808 if (i == NUM_STD_BAUDRATES) {
809#ifdef __APPLE__
810 config->baudrate = (int)data->term.c_ispeed;
7a6d2196
ML
811#elif defined(__linux__)
812 TRY(get_baudrate(port->fd, &config->baudrate));
31b3a8f5 813#else
067417af 814 config->baudrate = -1;
31b3a8f5
MH
815#endif
816 }
067417af 817
e33ab9aa 818 switch (data->term.c_cflag & CSIZE) {
067417af
ML
819 case CS8:
820 config->bits = 8;
821 break;
822 case CS7:
823 config->bits = 7;
824 break;
825 case CS6:
826 config->bits = 6;
827 break;
828 case CS5:
829 config->bits = 5;
830 break;
831 default:
832 config->bits = -1;
833 }
834
e33ab9aa 835 if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
067417af 836 config->parity = SP_PARITY_NONE;
e33ab9aa 837 else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
067417af
ML
838 config->parity = -1;
839 else
e33ab9aa 840 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
067417af 841
e33ab9aa 842 config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
067417af 843
e33ab9aa 844 if (data->term.c_cflag & CRTSCTS) {
067417af
ML
845 config->rts = SP_RTS_FLOW_CONTROL;
846 config->cts = SP_CTS_FLOW_CONTROL;
847 } else {
40978c2b
ML
848#ifdef USE_TERMIOX
849 if (data->flow & RTS_FLOW)
850 config->rts = SP_RTS_FLOW_CONTROL;
851 else
852 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
853
854 config->cts = (data->flow & CTS_FLOW) ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
855#else
e33ab9aa 856 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
067417af 857 config->cts = SP_CTS_IGNORE;
40978c2b 858#endif
067417af
ML
859 }
860
40978c2b
ML
861#ifdef USE_TERMIOX
862 if (data->flow & DTR_FLOW)
863 config->dtr = SP_DTR_FLOW_CONTROL;
864 else
865 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
866
867 config->dsr = (data->flow & DSR_FLOW) ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
868#else
e33ab9aa 869 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
067417af 870 config->dsr = SP_DSR_IGNORE;
40978c2b 871#endif
705bdc69 872
e29b93a5
ML
873 if (data->term.c_iflag & IXOFF) {
874 if (data->term.c_iflag & IXON)
875 config->xon_xoff = SP_XONXOFF_INOUT;
876 else
877 config->xon_xoff = SP_XONXOFF_IN;
878 } else {
879 if (data->term.c_iflag & IXON)
880 config->xon_xoff = SP_XONXOFF_OUT;
881 else
882 config->xon_xoff = SP_XONXOFF_DISABLED;
883 }
067417af
ML
884#endif
885
886 return SP_OK;
887}
888
7a6d2196 889static enum sp_return set_config(struct sp_port *port, struct port_data *data,
eb6ed20f 890 const struct sp_port_config *config)
18fc2dd1 891{
e33ab9aa 892 unsigned int i;
31b3a8f5
MH
893#ifdef __APPLE__
894 BAUD_TYPE baud_nonstd;
895
896 baud_nonstd = B0;
897#endif
7a6d2196
ML
898#ifdef __linux__
899 int baud_nonstd = 0;
900#endif
18fc2dd1 901
e33ab9aa 902#ifdef _WIN32
eac329d2 903 if (config->baudrate >= 0) {
e33ab9aa
ML
904 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
905 if (config->baudrate == std_baudrates[i].value) {
906 data->dcb.BaudRate = std_baudrates[i].index;
907 break;
908 }
909 }
18fc2dd1 910
e33ab9aa
ML
911 if (i == NUM_STD_BAUDRATES)
912 data->dcb.BaudRate = config->baudrate;
913 }
18fc2dd1 914
e33ab9aa
ML
915 if (config->bits >= 0)
916 data->dcb.ByteSize = config->bits;
917
918 if (config->parity >= 0) {
919 switch (config->parity) {
920 /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
921 case SP_PARITY_NONE:
922 data->dcb.Parity = NOPARITY;
923 break;
924 case SP_PARITY_EVEN:
925 data->dcb.Parity = EVENPARITY;
926 break;
927 case SP_PARITY_ODD:
928 data->dcb.Parity = ODDPARITY;
929 break;
930 default:
931 return SP_ERR_ARG;
932 }
18fc2dd1
ML
933 }
934
e33ab9aa
ML
935 if (config->stopbits >= 0) {
936 switch (config->stopbits) {
937 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
938 case 1:
939 data->dcb.StopBits = ONESTOPBIT;
940 break;
941 case 2:
942 data->dcb.StopBits = TWOSTOPBITS;
943 break;
944 default:
945 return SP_ERR_ARG;
946 }
947 }
948
949 if (config->rts >= 0) {
950 switch (config->rts) {
951 case SP_RTS_OFF:
952 data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
953 break;
954 case SP_RTS_ON:
955 data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
956 break;
957 case SP_RTS_FLOW_CONTROL:
958 data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
959 break;
960 default:
961 return SP_ERR_ARG;
962 }
963 }
964
965 if (config->cts >= 0) {
966 switch (config->cts) {
967 case SP_CTS_IGNORE:
968 data->dcb.fOutxCtsFlow = FALSE;
969 break;
970 case SP_CTS_FLOW_CONTROL:
971 data->dcb.fOutxCtsFlow = TRUE;
972 break;
973 default:
974 return SP_ERR_ARG;
975 }
976 }
977
978 if (config->dtr >= 0) {
979 switch (config->dtr) {
980 case SP_DTR_OFF:
981 data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
982 break;
983 case SP_DTR_ON:
984 data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
985 break;
986 case SP_DTR_FLOW_CONTROL:
987 data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
988 break;
989 default:
990 return SP_ERR_ARG;
991 }
992 }
993
994 if (config->dsr >= 0) {
995 switch (config->dsr) {
996 case SP_DSR_IGNORE:
997 data->dcb.fOutxDsrFlow = FALSE;
998 break;
999 case SP_DSR_FLOW_CONTROL:
1000 data->dcb.fOutxDsrFlow = TRUE;
1001 break;
1002 default:
1003 return SP_ERR_ARG;
1004 }
18fc2dd1
ML
1005 }
1006
e33ab9aa
ML
1007 if (config->xon_xoff >= 0) {
1008 switch (config->xon_xoff) {
1009 case SP_XONXOFF_DISABLED:
1010 data->dcb.fInX = FALSE;
1011 data->dcb.fOutX = FALSE;
1012 break;
1013 case SP_XONXOFF_IN:
1014 data->dcb.fInX = TRUE;
1015 data->dcb.fOutX = FALSE;
1016 break;
1017 case SP_XONXOFF_OUT:
1018 data->dcb.fInX = FALSE;
1019 data->dcb.fOutX = TRUE;
1020 break;
1021 case SP_XONXOFF_INOUT:
1022 data->dcb.fInX = TRUE;
1023 data->dcb.fOutX = TRUE;
1024 break;
1025 default:
1026 return SP_ERR_ARG;
1027 }
1028 }
1029
1030 if (!SetCommState(port->hdl, &data->dcb))
1031 return SP_ERR_FAIL;
1032
31b3a8f5 1033#else /* !_WIN32 */
e33ab9aa 1034
7a6d2196
ML
1035 int controlbits;
1036
eac329d2 1037 if (config->baudrate >= 0) {
e33ab9aa
ML
1038 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1039 if (config->baudrate == std_baudrates[i].value) {
1040 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
1041 return SP_ERR_FAIL;
1042
1043 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
1044 return SP_ERR_FAIL;
1045 break;
1046 }
1047 }
1048
31b3a8f5
MH
1049 /* Non-standard baud rate */
1050 if (i == NUM_STD_BAUDRATES) {
1051#ifdef __APPLE__
24abdb68 1052 /* Set "dummy" baud rate. */
31b3a8f5
MH
1053 if (cfsetspeed(&data->term, B9600) < 0)
1054 return SP_ERR_FAIL;
1055 baud_nonstd = config->baudrate;
7a6d2196
ML
1056#elif defined(__linux__)
1057 baud_nonstd = 1;
31b3a8f5 1058#else
e33ab9aa 1059 return SP_ERR_ARG;
31b3a8f5
MH
1060#endif
1061 }
e33ab9aa
ML
1062 }
1063
1064 if (config->bits >= 0) {
1065 data->term.c_cflag &= ~CSIZE;
1066 switch (config->bits) {
1067 case 8:
1068 data->term.c_cflag |= CS8;
1069 break;
1070 case 7:
1071 data->term.c_cflag |= CS7;
1072 break;
1073 case 6:
1074 data->term.c_cflag |= CS6;
1075 break;
23922313
UH
1076 case 5:
1077 data->term.c_cflag |= CS5;
1078 break;
e33ab9aa
ML
1079 default:
1080 return SP_ERR_ARG;
1081 }
1082 }
1083
1084 if (config->parity >= 0) {
1085 data->term.c_iflag &= ~IGNPAR;
1086 data->term.c_cflag &= ~(PARENB | PARODD);
1087 switch (config->parity) {
1088 case SP_PARITY_NONE:
1089 data->term.c_iflag |= IGNPAR;
1090 break;
1091 case SP_PARITY_EVEN:
1092 data->term.c_cflag |= PARENB;
1093 break;
1094 case SP_PARITY_ODD:
1095 data->term.c_cflag |= PARENB | PARODD;
1096 break;
1097 default:
1098 return SP_ERR_ARG;
1099 }
1100 }
1101
1102 if (config->stopbits >= 0) {
1103 data->term.c_cflag &= ~CSTOPB;
1104 switch (config->stopbits) {
1105 case 1:
1106 data->term.c_cflag &= ~CSTOPB;
1107 break;
1108 case 2:
1109 data->term.c_cflag |= CSTOPB;
1110 break;
1111 default:
1112 return SP_ERR_ARG;
1113 }
1114 }
1115
eac329d2 1116 if (config->rts >= 0 || config->cts >= 0) {
40978c2b
ML
1117#ifdef USE_TERMIOX
1118 data->flow &= ~(RTS_FLOW | CTS_FLOW);
1119 switch (config->rts) {
24abdb68
UH
1120 case SP_RTS_OFF:
1121 case SP_RTS_ON:
1122 controlbits = TIOCM_RTS;
1123 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
1124 return SP_ERR_FAIL;
1125 break;
1126 case SP_RTS_FLOW_CONTROL:
1127 data->flow |= RTS_FLOW;
1128 break;
1129 default:
1130 break;
40978c2b
ML
1131 }
1132 if (config->cts == SP_CTS_FLOW_CONTROL)
1133 data->flow |= CTS_FLOW;
e33ab9aa 1134
40978c2b
ML
1135 if (data->flow & (RTS_FLOW | CTS_FLOW))
1136 data->term.c_iflag |= CRTSCTS;
1137 else
1138 data->term.c_iflag &= ~CRTSCTS;
1139#else
1140 /* Asymmetric use of RTS/CTS not supported. */
e33ab9aa
ML
1141 if (data->term.c_iflag & CRTSCTS) {
1142 /* Flow control can only be disabled for both RTS & CTS together. */
1143 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
1144 if (config->cts != SP_CTS_IGNORE)
1145 return SP_ERR_ARG;
1146 }
1147 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
1148 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
1149 return SP_ERR_ARG;
1150 }
1151 } else {
1152 /* Flow control can only be enabled for both RTS & CTS together. */
1153 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
1154 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
1155 return SP_ERR_ARG;
1156 }
1157
1158 if (config->rts >= 0) {
1159 if (config->rts == SP_RTS_FLOW_CONTROL) {
1160 data->term.c_iflag |= CRTSCTS;
1161 } else {
7a6d2196 1162 controlbits = TIOCM_RTS;
e33ab9aa
ML
1163 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
1164 &controlbits) < 0)
1165 return SP_ERR_FAIL;
1166 }
1167 }
40978c2b 1168#endif
e33ab9aa
ML
1169 }
1170
eac329d2 1171 if (config->dtr >= 0 || config->dsr >= 0) {
40978c2b
ML
1172#ifdef USE_TERMIOX
1173 data->flow &= ~(DTR_FLOW | DSR_FLOW);
1174 switch (config->dtr) {
24abdb68
UH
1175 case SP_DTR_OFF:
1176 case SP_DTR_ON:
1177 controlbits = TIOCM_DTR;
1178 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
1179 return SP_ERR_FAIL;
1180 break;
1181 case SP_DTR_FLOW_CONTROL:
1182 data->flow |= DTR_FLOW;
1183 break;
1184 default:
1185 break;
40978c2b
ML
1186 }
1187 if (config->dsr == SP_DSR_FLOW_CONTROL)
1188 data->flow |= DSR_FLOW;
1189#else
1190 /* DTR/DSR flow control not supported. */
e33ab9aa
ML
1191 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
1192 return SP_ERR_ARG;
1193
1194 if (config->dtr >= 0) {
7a6d2196 1195 controlbits = TIOCM_DTR;
e33ab9aa
ML
1196 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
1197 &controlbits) < 0)
1198 return SP_ERR_FAIL;
1199 }
40978c2b 1200#endif
e33ab9aa
ML
1201 }
1202
1203 if (config->xon_xoff >= 0) {
1204 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
1205 switch (config->xon_xoff) {
1206 case SP_XONXOFF_DISABLED:
1207 break;
1208 case SP_XONXOFF_IN:
1209 data->term.c_iflag |= IXOFF;
1210 break;
1211 case SP_XONXOFF_OUT:
1212 data->term.c_iflag |= IXON | IXANY;
1213 break;
1214 case SP_XONXOFF_INOUT:
1215 data->term.c_iflag |= IXON | IXOFF | IXANY;
1216 break;
1217 default:
1218 return SP_ERR_ARG;
1219 }
1220 }
1221
1222 if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
1223 return SP_ERR_FAIL;
31b3a8f5
MH
1224
1225#ifdef __APPLE__
1226 if (baud_nonstd != B0) {
1227 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
1228 return SP_ERR_FAIL;
1229 /* Set baud rates in data->term to correct, but incompatible
1230 * with tcsetattr() value, same as delivered by tcgetattr(). */
1231 if (cfsetspeed(&data->term, baud_nonstd) < 0)
1232 return SP_ERR_FAIL;
1233 }
7a6d2196
ML
1234#elif defined(__linux__)
1235 if (baud_nonstd)
1236 TRY(set_baudrate(port->fd, config->baudrate));
40978c2b
ML
1237#ifdef USE_TERMIOX
1238 TRY(set_flow(port->fd, data->flow));
1239#endif
7a6d2196 1240#endif
31b3a8f5
MH
1241
1242#endif /* !_WIN32 */
e33ab9aa
ML
1243
1244 return SP_OK;
1245}
1246
eb6ed20f 1247enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config)
e33ab9aa 1248{
8f189c4c 1249 struct port_data data;
e33ab9aa
ML
1250 struct sp_port_config prev_config;
1251
823690ae
ML
1252 CHECK_PORT();
1253
1254 if (!config)
1255 return SP_ERR_ARG;
1256
e33ab9aa
ML
1257 TRY(get_config(port, &data, &prev_config));
1258 TRY(set_config(port, &data, config));
74510d4b
ML
1259
1260 return SP_OK;
1261}
1262
eb6ed20f 1263#define CREATE_SETTER(x, type) int sp_set_##x(struct sp_port *port, type x) { \
8f189c4c 1264 struct port_data data; \
e33ab9aa 1265 struct sp_port_config config; \
823690ae 1266 CHECK_PORT(); \
e33ab9aa
ML
1267 TRY(get_config(port, &data, &config)); \
1268 config.x = x; \
1269 TRY(set_config(port, &data, &config)); \
9069c2fb
ML
1270 return SP_OK; \
1271}
1272
eb6ed20f
ML
1273CREATE_SETTER(baudrate, int)
1274CREATE_SETTER(bits, int)
1275CREATE_SETTER(parity, enum sp_parity)
1276CREATE_SETTER(stopbits, int)
1277CREATE_SETTER(rts, enum sp_rts)
1278CREATE_SETTER(cts, enum sp_cts)
1279CREATE_SETTER(dtr, enum sp_dtr)
1280CREATE_SETTER(dsr, enum sp_dsr)
1281CREATE_SETTER(xon_xoff, enum sp_xonxoff)
1282
1283enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol)
e33ab9aa 1284{
8f189c4c 1285 struct port_data data;
e33ab9aa
ML
1286 struct sp_port_config config;
1287
823690ae
ML
1288 CHECK_PORT();
1289
e33ab9aa
ML
1290 TRY(get_config(port, &data, &config));
1291
1292 if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
1293 config.xon_xoff = SP_XONXOFF_INOUT;
1294 else
1295 config.xon_xoff = SP_XONXOFF_DISABLED;
1296
1297 if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
1298 config.rts = SP_RTS_FLOW_CONTROL;
1299 config.cts = SP_CTS_FLOW_CONTROL;
1300 } else {
1301 if (config.rts == SP_RTS_FLOW_CONTROL)
1302 config.rts = SP_RTS_ON;
1303 config.cts = SP_CTS_IGNORE;
1304 }
1305
1306 if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
1307 config.dtr = SP_DTR_FLOW_CONTROL;
1308 config.dsr = SP_DSR_FLOW_CONTROL;
1309 } else {
1310 if (config.dtr == SP_DTR_FLOW_CONTROL)
1311 config.dtr = SP_DTR_ON;
1312 config.dsr = SP_DSR_IGNORE;
1313 }
1314
1315 TRY(set_config(port, &data, &config));
1316
1317 return SP_OK;
1318}
1319
8cf7c697
ML
1320enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals)
1321{
1322 CHECK_PORT();
1323
1324 if (!signals)
1325 return SP_ERR_ARG;
1326
1327 *signals = 0;
1328#ifdef _WIN32
1329 DWORD bits;
1330 if (GetCommModemStatus(port->hdl, &bits) == 0)
1331 return SP_ERR_FAIL;
1332 if (bits & MS_CTS_ON)
1333 *signals |= SP_SIG_CTS;
1334 if (bits & MS_DSR_ON)
1335 *signals |= SP_SIG_DSR;
1336 if (bits & MS_RING_ON)
1337 *signals |= SP_SIG_DCD;
1338 if (bits & MS_RLSD_ON)
1339 *signals |= SP_SIG_RI;
1340#else
1341 int bits;
1342 if (ioctl(port->fd, TIOCMGET, &bits) < 0)
1343 return SP_ERR_FAIL;
1344 if (bits & TIOCM_CTS)
1345 *signals |= SP_SIG_CTS;
1346 if (bits & TIOCM_DSR)
1347 *signals |= SP_SIG_DSR;
1348 if (bits & TIOCM_CAR)
1349 *signals |= SP_SIG_DCD;
1350 if (bits & TIOCM_RNG)
1351 *signals |= SP_SIG_RI;
1352#endif
1353 return SP_OK;
1354}
1355
90cc3ee6
ML
1356enum sp_return sp_start_break(struct sp_port *port)
1357{
1358 CHECK_PORT();
1359#ifdef _WIN32
1360 if (SetCommBreak(port->hdl) == 0)
1361 return SP_ERR_FAIL;
1362#else
1363 if (ioctl(port->fd, TIOCSBRK, 1) < 0)
1364 return SP_ERR_FAIL;
1365#endif
1366
1367 return SP_OK;
1368}
1369
1370enum sp_return sp_end_break(struct sp_port *port)
1371{
1372 CHECK_PORT();
1373#ifdef _WIN32
1374 if (ClearCommBreak(port->hdl) == 0)
1375 return SP_ERR_FAIL;
1376#else
1377 if (ioctl(port->fd, TIOCCBRK, 1) < 0)
1378 return SP_ERR_FAIL;
1379#endif
1380
1381 return SP_OK;
1382}
1383
74510d4b
ML
1384int sp_last_error_code(void)
1385{
1386#ifdef _WIN32
1387 return GetLastError();
1388#else
1389 return errno;
1390#endif
1391}
1392
74510d4b
ML
1393char *sp_last_error_message(void)
1394{
1395#ifdef _WIN32
1396 LPVOID message;
1397 DWORD error = GetLastError();
1398
1399 FormatMessage(
1400 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1401 FORMAT_MESSAGE_FROM_SYSTEM |
1402 FORMAT_MESSAGE_IGNORE_INSERTS,
1403 NULL,
1404 error,
1405 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1406 (LPTSTR) &message,
1407 0, NULL );
1408
1409 return message;
1410#else
1411 return strerror(errno);
1412#endif
1413}
1414
74510d4b
ML
1415void sp_free_error_message(char *message)
1416{
1417#ifdef _WIN32
1418 LocalFree(message);
64eec30d
ML
1419#else
1420 (void)message;
74510d4b
ML
1421#endif
1422}