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