]> sigrok.org Git - libserialport.git/blob - serialport.c
f95afd0cd0af8d537e6576433654ad0107ac3b87
[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  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as
10  * published by the Free Software Foundation, either version 3 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #ifdef _WIN32
30 #include <windows.h>
31 #include <tchar.h>
32 #include <stdio.h>
33 #else
34 #include <termios.h>
35 #include <sys/ioctl.h>
36 #endif
37 #ifdef __APPLE__
38 #include <IOKit/IOKitLib.h>
39 #include <IOKit/serial/IOSerialKeys.h>
40 #include <sys/syslimits.h>
41 #endif
42 #ifdef __linux__
43 #include "libudev.h"
44 #include "linux/serial.h"
45 #endif
46
47 #include "libserialport.h"
48
49 struct sp_port_data {
50 #ifdef _WIN32
51         DCB dcb;
52 #else
53         struct termios term;
54         int controlbits;
55 #endif
56 };
57
58 /* Standard baud rates. */
59 #ifdef _WIN32
60 #define BAUD_TYPE DWORD
61 #define BAUD(n) {CBR_##n, n}
62 #else
63 #define BAUD_TYPE speed_t
64 #define BAUD(n) {B##n, n}
65 #endif
66
67 struct std_baudrate {
68         BAUD_TYPE index;
69         int value;
70 };
71
72 const struct std_baudrate std_baudrates[] = {
73 #ifdef _WIN32
74         /*
75          * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
76          * have documented CBR_* macros.
77          */
78         BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
79         BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
80         BAUD(115200), BAUD(128000), BAUD(256000)
81 #else
82         BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), BAUD(300),
83         BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), BAUD(9600),
84         BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), BAUD(230400),
85 #if !defined(__APPLE__) && !defined(__OpenBSD__)
86         BAUD(460800)
87 #endif
88 #endif
89 };
90
91 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
92 #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
93
94 /* Helper functions for configuring ports. */
95 static int get_config(struct sp_port *port, struct sp_port_data *data, struct sp_port_config *config);
96 static int set_config(struct sp_port *port, struct sp_port_data *data, struct sp_port_config *config);
97
98 int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
99 {
100         struct sp_port *port;
101         int len;
102
103         if (!port_ptr)
104                 return SP_ERR_ARG;
105
106         *port_ptr = NULL;
107
108         if (!portname)
109                 return SP_ERR_ARG;
110
111         if (!(port = malloc(sizeof(struct sp_port))))
112                 return SP_ERR_MEM;
113
114         len = strlen(portname) + 1;
115
116         if (!(port->name = malloc(len)))
117         {
118                 free(port);
119                 return SP_ERR_MEM;
120         }
121
122         memcpy(port->name, portname, len);
123
124         *port_ptr = port;
125
126         return SP_OK;
127 }
128
129 int sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
130 {
131         if (!copy_ptr)
132                 return SP_ERR_ARG;
133
134         *copy_ptr = NULL;
135
136         if (!port || !port->name)
137                 return SP_ERR_ARG;
138
139         return sp_get_port_by_name(port->name, copy_ptr);
140 }
141
142 void sp_free_port(struct sp_port *port)
143 {
144         if (!port)
145                 return;
146
147         if (port->name)
148                 free(port->name);
149
150         free(port);
151 }
152
153 static struct sp_port **sp_list_append(struct sp_port **list, const char *portname)
154 {
155         void *tmp;
156         unsigned int count;
157
158         for (count = 0; list[count]; count++);
159         if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
160                 goto fail;
161         list = tmp;
162         if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
163                 goto fail;
164         list[count + 1] = NULL;
165         return list;
166
167 fail:
168         sp_free_port_list(list);
169         return NULL;
170 }
171
172 int sp_list_ports(struct sp_port ***list_ptr)
173 {
174         struct sp_port **list;
175         int ret = SP_OK;
176
177         if (!(list = malloc(sizeof(struct sp_port **))))
178                 return SP_ERR_MEM;
179
180         list[0] = NULL;
181
182 #ifdef _WIN32
183         HKEY key;
184         TCHAR *value, *data;
185         DWORD max_value_len, max_data_size, max_data_len;
186         DWORD value_len, data_size, data_len;
187         DWORD type, index = 0;
188         char *name;
189         int name_len;
190
191         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
192                         0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
193         {
194                 ret = SP_ERR_FAIL;
195                 goto out_done;
196         }
197         if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
198                                 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS)
199         {
200                 ret = SP_ERR_FAIL;
201                 goto out_close;
202         }
203         max_data_len = max_data_size / sizeof(TCHAR);
204         if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR))))
205         {
206                 ret = SP_ERR_MEM;
207                 goto out_close;
208         }
209         if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR))))
210         {
211                 ret = SP_ERR_MEM;
212                 goto out_free_value;
213         }
214         while (
215                 value_len = max_value_len + 1,
216                 data_size = max_data_size,
217                 RegEnumValue(key, index, value, &value_len,
218                         NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
219         {
220                 data_len = data_size / sizeof(TCHAR);
221                 data[data_len] = '\0';
222 #ifdef UNICODE
223                 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL)
224 #else
225                 name_len = data_len + 1;
226 #endif
227                 if (!(name = malloc(name_len)))
228                 {
229                         ret = SP_ERR_MEM;
230                         goto out;
231                 }
232 #ifdef UNICODE
233                 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
234 #else
235                 strcpy(name, data);
236 #endif
237                 if (type == REG_SZ && !(list = sp_list_append(list, name)))
238                 {
239                         ret = SP_ERR_MEM;
240                         goto out;
241                 }
242                 index++;
243         }
244 out:
245         free(data);
246 out_free_value:
247         free(value);
248 out_close:
249         RegCloseKey(key);
250 out_done:
251 #endif
252 #ifdef __APPLE__
253         mach_port_t master;
254         CFMutableDictionaryRef classes;
255         io_iterator_t iter;
256         char *path;
257         io_object_t port;
258         CFTypeRef cf_path;
259         Boolean result;
260
261         if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS)
262         {
263                 ret = SP_ERR_FAIL;
264                 goto out_done;
265         }
266
267         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
268         {
269                 ret = SP_ERR_FAIL;
270                 goto out_done;
271         }
272
273         CFDictionarySetValue(classes,
274                         CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
275
276         if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS)
277         {
278                 ret = SP_ERR_FAIL;
279                 goto out_done;
280         }
281
282         if (!(path = malloc(PATH_MAX)))
283         {
284                 ret = SP_ERR_MEM;
285                 goto out_release;
286         }
287
288         while ((port = IOIteratorNext(iter))) {
289                 cf_path = IORegistryEntryCreateCFProperty(port,
290                                 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
291                 if (cf_path) {
292                         result = CFStringGetCString(cf_path,
293                                         path, PATH_MAX, kCFStringEncodingASCII);
294                         CFRelease(cf_path);
295                         if (result && !(list = sp_list_append(list, path)))
296                         {
297                                 ret = SP_ERR_MEM;
298                                 IOObjectRelease(port);
299                                 goto out;
300                         }
301                 }
302                 IOObjectRelease(port);
303         }
304 out:
305         free(path);
306 out_release:
307         IOObjectRelease(iter);
308 out_done:
309 #endif
310 #ifdef __linux__
311         struct udev *ud;
312         struct udev_enumerate *ud_enumerate;
313         struct udev_list_entry *ud_list;
314         struct udev_list_entry *ud_entry;
315         const char *path;
316         struct udev_device *ud_dev, *ud_parent;
317         const char *name;
318         const char *driver;
319         int fd, ioctl_result;
320         struct serial_struct serial_info;
321
322         ud = udev_new();
323         ud_enumerate = udev_enumerate_new(ud);
324         udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
325         udev_enumerate_scan_devices(ud_enumerate);
326         ud_list = udev_enumerate_get_list_entry(ud_enumerate);
327         udev_list_entry_foreach(ud_entry, ud_list)
328         {
329                 path = udev_list_entry_get_name(ud_entry);
330                 ud_dev = udev_device_new_from_syspath(ud, path);
331                 /* If there is no parent device, this is a virtual tty. */
332                 ud_parent = udev_device_get_parent(ud_dev);
333                 if (ud_parent == NULL)
334                 {
335                         udev_device_unref(ud_dev);
336                         continue;
337                 }
338                 name = udev_device_get_devnode(ud_dev);
339                 /* The serial8250 driver has a hardcoded number of ports.
340                  * The only way to tell which actually exist on a given system
341                  * is to try to open them and make an ioctl call. */
342                 driver = udev_device_get_driver(ud_parent);
343                 if (driver && !strcmp(driver, "serial8250"))
344                 {
345                         if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0)
346                                 goto skip;
347                         ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
348                         close(fd);
349                         if (ioctl_result != 0)
350                                 goto skip;
351                         if (serial_info.type == PORT_UNKNOWN)
352                                 goto skip;
353                 }
354                 list = sp_list_append(list, name);
355 skip:
356                 udev_device_unref(ud_dev);
357                 if (!list)
358                 {
359                         ret = SP_ERR_MEM;
360                         goto out;
361                 }
362         }
363 out:
364         udev_enumerate_unref(ud_enumerate);
365         udev_unref(ud);
366 #endif
367
368         if (ret == SP_OK)
369         {
370                 *list_ptr = list;
371         }
372         else
373         {
374                 if (list)
375                         sp_free_port_list(list);
376
377                 *list_ptr = NULL;
378         }
379
380         return ret;
381 }
382
383 void sp_free_port_list(struct sp_port **list)
384 {
385         unsigned int i;
386
387         for (i = 0; list[i]; i++)
388                 sp_free_port(list[i]);
389         free(list);
390 }
391
392 static int sp_validate_port(struct sp_port *port)
393 {
394         if (port == NULL)
395                 return 0;
396 #ifdef _WIN32
397         if (port->hdl == INVALID_HANDLE_VALUE)
398                 return 0;
399 #else
400         if (port->fd < 0)
401                 return 0;
402 #endif
403         return 1;
404 }
405
406 #define CHECK_PORT() do { if (!sp_validate_port(port)) return SP_ERR_ARG; } while (0)
407
408 int sp_open(struct sp_port *port, int flags)
409 {
410         if (!port)
411                 return SP_ERR_ARG;
412
413 #ifdef _WIN32
414         DWORD desired_access = 0, flags_and_attributes = 0;
415         char *escaped_port_name;
416
417         /* Prefix port name with '\\.\' to work with ports above COM9. */
418         if (!(escaped_port_name = malloc(strlen(port->name + 5))))
419                 return SP_ERR_MEM;
420         sprintf(escaped_port_name, "\\\\.\\%s", port->name);
421
422         /* Map 'flags' to the OS-specific settings. */
423         desired_access |= GENERIC_READ;
424         flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
425         if (flags & SP_MODE_RDWR)
426                 desired_access |= GENERIC_WRITE;
427         if (flags & SP_MODE_NONBLOCK)
428                 flags_and_attributes |= FILE_FLAG_OVERLAPPED;
429
430         port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
431                          OPEN_EXISTING, flags_and_attributes, 0);
432
433         free(escaped_port_name);
434
435         if (port->hdl == INVALID_HANDLE_VALUE)
436                 return SP_ERR_FAIL;
437 #else
438         int flags_local = 0;
439         struct sp_port_data data;
440         struct sp_port_config config;
441         int ret;
442
443         /* Map 'flags' to the OS-specific settings. */
444         if (flags & SP_MODE_RDWR)
445                 flags_local |= O_RDWR;
446         if (flags & SP_MODE_RDONLY)
447                 flags_local |= O_RDONLY;
448         if (flags & SP_MODE_NONBLOCK)
449                 flags_local |= O_NONBLOCK;
450
451         if ((port->fd = open(port->name, flags_local)) < 0)
452                 return SP_ERR_FAIL;
453
454         ret = get_config(port, &data, &config);
455
456         if (ret < 0)
457         {
458                 sp_close(port);
459                 return ret;
460         }
461
462         /* Turn off all serial port cooking. */
463         data.term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
464         data.term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
465 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
466         data.term.c_oflag &= ~OFILL;
467 #endif
468         /* Disable canonical mode, and don't echo input characters. */
469         data.term.c_lflag &= ~(ICANON | ECHO);
470
471         /* Ignore modem status lines; enable receiver */
472         data.term.c_cflag |= (CLOCAL | CREAD);
473
474         ret = set_config(port, &data, &config);
475
476         if (ret < 0)
477         {
478                 sp_close(port);
479                 return ret;
480         }
481 #endif
482
483         return SP_OK;
484 }
485
486 int sp_close(struct sp_port *port)
487 {
488         CHECK_PORT();
489
490 #ifdef _WIN32
491         /* Returns non-zero upon success, 0 upon failure. */
492         if (CloseHandle(port->hdl) == 0)
493                 return SP_ERR_FAIL;
494 #else
495         /* Returns 0 upon success, -1 upon failure. */
496         if (close(port->fd) == -1)
497                 return SP_ERR_FAIL;
498 #endif
499
500         return SP_OK;
501 }
502
503 int sp_flush(struct sp_port *port)
504 {
505         CHECK_PORT();
506
507 #ifdef _WIN32
508         /* Returns non-zero upon success, 0 upon failure. */
509         if (PurgeComm(port->hdl, PURGE_RXCLEAR | PURGE_TXCLEAR) == 0)
510                 return SP_ERR_FAIL;
511 #else
512         /* Returns 0 upon success, -1 upon failure. */
513         if (tcflush(port->fd, TCIOFLUSH) < 0)
514                 return SP_ERR_FAIL;
515 #endif
516         return SP_OK;
517 }
518
519 int sp_write(struct sp_port *port, const void *buf, size_t count)
520 {
521         CHECK_PORT();
522
523         if (!buf)
524                 return SP_ERR_ARG;
525
526 #ifdef _WIN32
527         DWORD written = 0;
528
529         /* Returns non-zero upon success, 0 upon failure. */
530         if (WriteFile(port->hdl, buf, count, &written, NULL) == 0)
531                 return SP_ERR_FAIL;
532         return written;
533 #else
534         /* Returns the number of bytes written, or -1 upon failure. */
535         ssize_t written = write(port->fd, buf, count);
536
537         if (written < 0)
538                 return SP_ERR_FAIL;
539         else
540                 return written;
541 #endif
542 }
543
544 int sp_read(struct sp_port *port, void *buf, size_t count)
545 {
546         CHECK_PORT();
547
548         if (!buf)
549                 return SP_ERR_ARG;
550
551 #ifdef _WIN32
552         DWORD bytes_read = 0;
553
554         /* Returns non-zero upon success, 0 upon failure. */
555         if (ReadFile(port->hdl, buf, count, &bytes_read, NULL) == 0)
556                 return SP_ERR_FAIL;
557         return bytes_read;
558 #else
559         ssize_t bytes_read;
560
561         /* Returns the number of bytes read, or -1 upon failure. */
562         if ((bytes_read = read(port->fd, buf, count)) < 0)
563                 return SP_ERR_FAIL;
564         return bytes_read;
565 #endif
566 }
567
568 static int get_config(struct sp_port *port, struct sp_port_data *data, struct sp_port_config *config)
569 {
570         unsigned int i;
571
572 #ifdef _WIN32
573         if (!GetCommState(port->hdl, &data->dcb))
574                 return SP_ERR_FAIL;
575
576         for (i = 0; i < NUM_STD_BAUDRATES; i++) {
577                 if (data->dcb.BaudRate == std_baudrates[i].index) {
578                         config->baudrate = std_baudrates[i].value;
579                         break;
580                 }
581         }
582
583         if (i == NUM_STD_BAUDRATES)
584                 /* BaudRate field can be either an index or a custom baud rate. */
585                 config->baudrate = data->dcb.BaudRate;
586
587         config->bits = data->dcb.ByteSize;
588
589         if (data->dcb.fParity)
590                 switch (data->dcb.Parity) {
591                 case NOPARITY:
592                         config->parity = SP_PARITY_NONE;
593                         break;
594                 case EVENPARITY:
595                         config->parity = SP_PARITY_EVEN;
596                         break;
597                 case ODDPARITY:
598                         config->parity = SP_PARITY_ODD;
599                         break;
600                 default:
601                         config->parity = -1;
602                 }
603         else
604                 config->parity = SP_PARITY_NONE;
605
606         switch (data->dcb.StopBits) {
607         case ONESTOPBIT:
608                 config->stopbits = 1;
609                 break;
610         case TWOSTOPBITS:
611                 config->stopbits = 2;
612                 break;
613         default:
614                 config->stopbits = -1;
615         }
616
617         switch (data->dcb.fRtsControl) {
618                 case RTS_CONTROL_DISABLE:
619                         config->rts = SP_RTS_OFF;
620                         break;
621                 case RTS_CONTROL_ENABLE:
622                         config->rts = SP_RTS_ON;
623                         break;
624                 case RTS_CONTROL_HANDSHAKE:
625                         config->rts = SP_RTS_FLOW_CONTROL;
626                         break;
627                 default:
628                         config->rts = -1;
629         }
630
631         config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
632
633         switch (data->dcb.fDtrControl) {
634                 case DTR_CONTROL_DISABLE:
635                         config->dtr = SP_DTR_OFF;
636                         break;
637                 case DTR_CONTROL_ENABLE:
638                         config->dtr = SP_DTR_ON;
639                         break;
640                 case DTR_CONTROL_HANDSHAKE:
641                         config->dtr = SP_DTR_FLOW_CONTROL;
642                         break;
643                 default:
644                         config->dtr = -1;
645         }
646
647         config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
648
649         if (data->dcb.fInX) {
650                 if (data->dcb.fOutX)
651                         config->xon_xoff = SP_XONXOFF_INOUT;
652                 else
653                         config->xon_xoff = SP_XONXOFF_IN;
654         } else {
655                 if (data->dcb.fOutX)
656                         config->xon_xoff = SP_XONXOFF_OUT;
657                 else
658                         config->xon_xoff = SP_XONXOFF_DISABLED;
659         }
660
661 #else // !_WIN32
662
663         if (tcgetattr(port->fd, &data->term) < 0)
664                 return SP_ERR_FAIL;
665
666         if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
667                 return SP_ERR_FAIL;
668         for (i = 0; i < NUM_STD_BAUDRATES; i++) {
669                 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
670                         config->baudrate = std_baudrates[i].value;
671                         break;
672                 }
673         }
674
675         if (i == NUM_STD_BAUDRATES)
676                 config->baudrate = -1;
677
678         switch (data->term.c_cflag & CSIZE) {
679         case CS8:
680                 config->bits = 8;
681                 break;
682         case CS7:
683                 config->bits = 7;
684                 break;
685         case CS6:
686                 config->bits = 6;
687                 break;
688         case CS5:
689                 config->bits = 5;
690                 break;
691         default:
692                 config->bits = -1;
693         }
694
695         if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
696                 config->parity = SP_PARITY_NONE;
697         else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
698                 config->parity = -1;
699         else
700                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
701
702         config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
703
704         if (data->term.c_cflag & CRTSCTS) {
705                 config->rts = SP_RTS_FLOW_CONTROL;
706                 config->cts = SP_CTS_FLOW_CONTROL;
707         } else {
708                 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
709                 config->cts = SP_CTS_IGNORE;
710         }
711
712         config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
713         config->dsr = SP_DSR_IGNORE;
714 #endif
715
716         return SP_OK;
717 }
718
719 static int set_config(struct sp_port *port, struct sp_port_data *data, struct sp_port_config *config)
720 {
721         unsigned int i;
722
723 #ifdef _WIN32
724         if (config->baudrate >= 0)
725         {
726                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
727                         if (config->baudrate == std_baudrates[i].value) {
728                                 data->dcb.BaudRate = std_baudrates[i].index;
729                                 break;
730                         }
731                 }
732
733                 if (i == NUM_STD_BAUDRATES)
734                         data->dcb.BaudRate = config->baudrate;
735         }
736
737         if (config->bits >= 0)
738                 data->dcb.ByteSize = config->bits;
739
740         if (config->parity >= 0) {
741                 switch (config->parity) {
742                 /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
743                 case SP_PARITY_NONE:
744                         data->dcb.Parity = NOPARITY;
745                         break;
746                 case SP_PARITY_EVEN:
747                         data->dcb.Parity = EVENPARITY;
748                         break;
749                 case SP_PARITY_ODD:
750                         data->dcb.Parity = ODDPARITY;
751                         break;
752                 default:
753                         return SP_ERR_ARG;
754                 }
755         }
756
757         if (config->stopbits >= 0) {
758                 switch (config->stopbits) {
759                 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
760                 case 1:
761                         data->dcb.StopBits = ONESTOPBIT;
762                         break;
763                 case 2:
764                         data->dcb.StopBits = TWOSTOPBITS;
765                         break;
766                 default:
767                         return SP_ERR_ARG;
768                 }
769         }
770
771         if (config->rts >= 0) {
772                 switch (config->rts) {
773                 case SP_RTS_OFF:
774                         data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
775                         break;
776                 case SP_RTS_ON:
777                         data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
778                         break;
779                 case SP_RTS_FLOW_CONTROL:
780                         data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
781                         break;
782                 default:
783                         return SP_ERR_ARG;
784                 }
785         }
786
787         if (config->cts >= 0) {
788                 switch (config->cts) {
789                 case SP_CTS_IGNORE:
790                         data->dcb.fOutxCtsFlow = FALSE;
791                         break;
792                 case SP_CTS_FLOW_CONTROL:
793                         data->dcb.fOutxCtsFlow = TRUE;
794                         break;
795                 default:
796                         return SP_ERR_ARG;
797                 }
798         }
799
800         if (config->dtr >= 0) {
801                 switch (config->dtr) {
802                 case SP_DTR_OFF:
803                         data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
804                         break;
805                 case SP_DTR_ON:
806                         data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
807                         break;
808                 case SP_DTR_FLOW_CONTROL:
809                         data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
810                         break;
811                 default:
812                         return SP_ERR_ARG;
813                 }
814         }
815
816         if (config->dsr >= 0) {
817                 switch (config->dsr) {
818                 case SP_DSR_IGNORE:
819                         data->dcb.fOutxDsrFlow = FALSE;
820                         break;
821                 case SP_DSR_FLOW_CONTROL:
822                         data->dcb.fOutxDsrFlow = TRUE;
823                         break;
824                 default:
825                         return SP_ERR_ARG;
826                 }
827         }
828
829         if (config->xon_xoff >= 0) {
830                 switch (config->xon_xoff) {
831                 case SP_XONXOFF_DISABLED:
832                         data->dcb.fInX = FALSE;
833                         data->dcb.fOutX = FALSE;
834                         break;
835                 case SP_XONXOFF_IN:
836                         data->dcb.fInX = TRUE;
837                         data->dcb.fOutX = FALSE;
838                         break;
839                 case SP_XONXOFF_OUT:
840                         data->dcb.fInX = FALSE;
841                         data->dcb.fOutX = TRUE;
842                         break;
843                 case SP_XONXOFF_INOUT:
844                         data->dcb.fInX = TRUE;
845                         data->dcb.fOutX = TRUE;
846                         break;
847                 default:
848                         return SP_ERR_ARG;
849                 }
850         }
851
852         if (!SetCommState(port->hdl, &data->dcb))
853                 return SP_ERR_FAIL;
854
855 #else // !_WIN32
856
857         if (config->baudrate >= 0)
858         {
859                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
860                         if (config->baudrate == std_baudrates[i].value) {
861                                 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
862                                         return SP_ERR_FAIL;
863
864                                 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
865                                         return SP_ERR_FAIL;
866                                 break;
867                         }
868                 }
869
870                 if (i == NUM_STD_BAUDRATES)
871                         return SP_ERR_ARG;
872         }
873
874         if (config->bits >= 0) {
875                 data->term.c_cflag &= ~CSIZE;
876                 switch (config->bits) {
877                 case 8:
878                         data->term.c_cflag |= CS8;
879                         break;
880                 case 7:
881                         data->term.c_cflag |= CS7;
882                         break;
883                 case 6:
884                         data->term.c_cflag |= CS6;
885                         break;
886                 default:
887                         return SP_ERR_ARG;
888                 }
889         }
890
891         if (config->parity >= 0) {
892                 data->term.c_iflag &= ~IGNPAR;
893                 data->term.c_cflag &= ~(PARENB | PARODD);
894                 switch (config->parity) {
895                 case SP_PARITY_NONE:
896                         data->term.c_iflag |= IGNPAR;
897                         break;
898                 case SP_PARITY_EVEN:
899                         data->term.c_cflag |= PARENB;
900                         break;
901                 case SP_PARITY_ODD:
902                         data->term.c_cflag |= PARENB | PARODD;
903                         break;
904                 default:
905                         return SP_ERR_ARG;
906                 }
907         }
908
909         if (config->stopbits >= 0) {
910                 data->term.c_cflag &= ~CSTOPB;
911                 switch (config->stopbits) {
912                 case 1:
913                         data->term.c_cflag &= ~CSTOPB;
914                         break;
915                 case 2:
916                         data->term.c_cflag |= CSTOPB;
917                         break;
918                 default:
919                         return SP_ERR_ARG;
920                 }
921         }
922
923         if (config->rts >= 0 || config->cts >= 0)
924         {
925                 /* Asymmetric use of RTS/CTS not supported yet. */
926
927                 if (data->term.c_iflag & CRTSCTS) {
928                         /* Flow control can only be disabled for both RTS & CTS together. */
929                         if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
930                                 if (config->cts != SP_CTS_IGNORE)
931                                         return SP_ERR_ARG;
932                         }
933                         if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
934                                 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
935                                         return SP_ERR_ARG;
936                         }
937                 } else {
938                         /* Flow control can only be enabled for both RTS & CTS together. */
939                         if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
940                                 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
941                                 return SP_ERR_ARG;
942                 }
943
944                 if (config->rts >= 0) {
945                         if (config->rts == SP_RTS_FLOW_CONTROL) {
946                                 data->term.c_iflag |= CRTSCTS;
947                         } else {
948                                 int controlbits = TIOCM_RTS;
949                                 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
950                                                 &controlbits) < 0)
951                                         return SP_ERR_FAIL;
952                         }
953                 }
954         }
955
956         if (config->dtr >= 0 || config->dsr >= 0)
957         {
958                 /* DTR/DSR flow control not supported yet. */
959                 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
960                         return SP_ERR_ARG;
961
962                 if (config->dtr >= 0) {
963                         int controlbits = TIOCM_DTR;
964                         if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
965                                         &controlbits) < 0)
966                                 return SP_ERR_FAIL;
967                 }
968         }
969
970         if (config->xon_xoff >= 0) {
971                 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
972                 switch (config->xon_xoff) {
973                 case SP_XONXOFF_DISABLED:
974                         break;
975                 case SP_XONXOFF_IN:
976                         data->term.c_iflag |= IXOFF;
977                         break;
978                 case SP_XONXOFF_OUT:
979                         data->term.c_iflag |= IXON | IXANY;
980                         break;
981                 case SP_XONXOFF_INOUT:
982                         data->term.c_iflag |= IXON | IXOFF | IXANY;
983                         break;
984                 default:
985                         return SP_ERR_ARG;
986                 }
987         }
988
989         if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
990                 return SP_ERR_FAIL;
991 #endif
992
993         return SP_OK;
994 }
995
996 #define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
997
998 int sp_set_config(struct sp_port *port, struct sp_port_config *config)
999 {
1000         struct sp_port_data data;
1001         struct sp_port_config prev_config;
1002
1003         TRY(get_config(port, &data, &prev_config));
1004         TRY(set_config(port, &data, config));
1005
1006         return SP_OK;
1007 }
1008
1009 #define CREATE_SETTER(x) int sp_set_##x(struct sp_port *port, int x) { \
1010         struct sp_port_data data; \
1011         struct sp_port_config config; \
1012         TRY(get_config(port, &data, &config)); \
1013         config.x = x; \
1014         TRY(set_config(port, &data, &config)); \
1015         return SP_OK; \
1016 }
1017
1018 CREATE_SETTER(baudrate)
1019 CREATE_SETTER(bits)
1020 CREATE_SETTER(parity)
1021 CREATE_SETTER(stopbits)
1022 CREATE_SETTER(rts)
1023 CREATE_SETTER(cts)
1024 CREATE_SETTER(dtr)
1025 CREATE_SETTER(dsr)
1026 CREATE_SETTER(xon_xoff)
1027
1028 int sp_set_flowcontrol(struct sp_port *port, int flowcontrol)
1029 {
1030         struct sp_port_data data;
1031         struct sp_port_config config;
1032
1033         TRY(get_config(port, &data, &config));
1034
1035         if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
1036                 config.xon_xoff = SP_XONXOFF_INOUT;
1037         else
1038                 config.xon_xoff = SP_XONXOFF_DISABLED;
1039
1040         if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
1041                 config.rts = SP_RTS_FLOW_CONTROL;
1042                 config.cts = SP_CTS_FLOW_CONTROL;
1043         } else {
1044                 if (config.rts == SP_RTS_FLOW_CONTROL)
1045                         config.rts = SP_RTS_ON;
1046                 config.cts = SP_CTS_IGNORE;
1047         }
1048
1049         if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
1050                 config.dtr = SP_DTR_FLOW_CONTROL;
1051                 config.dsr = SP_DSR_FLOW_CONTROL;
1052         } else {
1053                 if (config.dtr == SP_DTR_FLOW_CONTROL)
1054                         config.dtr = SP_DTR_ON;
1055                 config.dsr = SP_DSR_IGNORE;
1056         }
1057
1058         TRY(set_config(port, &data, &config));
1059
1060         return SP_OK;
1061 }
1062
1063 int sp_last_error_code(void)
1064 {
1065 #ifdef _WIN32
1066         return GetLastError();
1067 #else
1068         return errno;
1069 #endif
1070 }
1071
1072 char *sp_last_error_message(void)
1073 {
1074 #ifdef _WIN32
1075         LPVOID message;
1076         DWORD error = GetLastError();
1077
1078         FormatMessage(
1079                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1080                 FORMAT_MESSAGE_FROM_SYSTEM |
1081                 FORMAT_MESSAGE_IGNORE_INSERTS,
1082                 NULL,
1083                 error,
1084                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1085                 (LPTSTR) &message,
1086                 0, NULL );
1087
1088         return message;
1089 #else
1090         return strerror(errno);
1091 #endif
1092 }
1093
1094 void sp_free_error_message(char *message)
1095 {
1096 #ifdef _WIN32
1097         LocalFree(message);
1098 #else
1099         (void)message;
1100 #endif
1101 }