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