]> sigrok.org Git - libserialport.git/blob - serialport.c
Refactor port configuration code.
[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 #else // !_WIN32
650
651         if (tcgetattr(port->fd, &data->term) < 0)
652                 return SP_ERR_FAIL;
653
654         if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
655                 return SP_ERR_FAIL;
656         for (i = 0; i < NUM_STD_BAUDRATES; i++) {
657                 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
658                         config->baudrate = std_baudrates[i].value;
659                         break;
660                 }
661         }
662
663         if (i == NUM_STD_BAUDRATES)
664                 config->baudrate = -1;
665
666         switch (data->term.c_cflag & CSIZE) {
667         case CS8:
668                 config->bits = 8;
669                 break;
670         case CS7:
671                 config->bits = 7;
672                 break;
673         case CS6:
674                 config->bits = 6;
675                 break;
676         case CS5:
677                 config->bits = 5;
678                 break;
679         default:
680                 config->bits = -1;
681         }
682
683         if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
684                 config->parity = SP_PARITY_NONE;
685         else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
686                 config->parity = -1;
687         else
688                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
689
690         config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
691
692         if (data->term.c_cflag & CRTSCTS) {
693                 config->rts = SP_RTS_FLOW_CONTROL;
694                 config->cts = SP_CTS_FLOW_CONTROL;
695         } else {
696                 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
697                 config->cts = SP_CTS_IGNORE;
698         }
699
700         config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
701         config->dsr = SP_DSR_IGNORE;
702 #endif
703
704         return SP_OK;
705 }
706
707 static int set_config(struct sp_port *port, struct sp_port_data *data, struct sp_port_config *config)
708 {
709         unsigned int i;
710
711 #ifdef _WIN32
712         if (config->baudrate >= 0)
713         {
714                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
715                         if (config->baudrate == std_baudrates[i].value) {
716                                 data->dcb.BaudRate = std_baudrates[i].index;
717                                 break;
718                         }
719                 }
720
721                 if (i == NUM_STD_BAUDRATES)
722                         data->dcb.BaudRate = config->baudrate;
723         }
724
725         if (config->bits >= 0)
726                 data->dcb.ByteSize = config->bits;
727
728         if (config->parity >= 0) {
729                 switch (config->parity) {
730                 /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
731                 case SP_PARITY_NONE:
732                         data->dcb.Parity = NOPARITY;
733                         break;
734                 case SP_PARITY_EVEN:
735                         data->dcb.Parity = EVENPARITY;
736                         break;
737                 case SP_PARITY_ODD:
738                         data->dcb.Parity = ODDPARITY;
739                         break;
740                 default:
741                         return SP_ERR_ARG;
742                 }
743         }
744
745         if (config->stopbits >= 0) {
746                 switch (config->stopbits) {
747                 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
748                 case 1:
749                         data->dcb.StopBits = ONESTOPBIT;
750                         break;
751                 case 2:
752                         data->dcb.StopBits = TWOSTOPBITS;
753                         break;
754                 default:
755                         return SP_ERR_ARG;
756                 }
757         }
758
759         if (config->rts >= 0) {
760                 switch (config->rts) {
761                 case SP_RTS_OFF:
762                         data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
763                         break;
764                 case SP_RTS_ON:
765                         data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
766                         break;
767                 case SP_RTS_FLOW_CONTROL:
768                         data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
769                         break;
770                 default:
771                         return SP_ERR_ARG;
772                 }
773         }
774
775         if (config->cts >= 0) {
776                 switch (config->cts) {
777                 case SP_CTS_IGNORE:
778                         data->dcb.fOutxCtsFlow = FALSE;
779                         break;
780                 case SP_CTS_FLOW_CONTROL:
781                         data->dcb.fOutxCtsFlow = TRUE;
782                         break;
783                 default:
784                         return SP_ERR_ARG;
785                 }
786         }
787
788         if (config->dtr >= 0) {
789                 switch (config->dtr) {
790                 case SP_DTR_OFF:
791                         data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
792                         break;
793                 case SP_DTR_ON:
794                         data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
795                         break;
796                 case SP_DTR_FLOW_CONTROL:
797                         data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
798                         break;
799                 default:
800                         return SP_ERR_ARG;
801                 }
802         }
803
804         if (config->dsr >= 0) {
805                 switch (config->dsr) {
806                 case SP_DSR_IGNORE:
807                         data->dcb.fOutxDsrFlow = FALSE;
808                         break;
809                 case SP_DSR_FLOW_CONTROL:
810                         data->dcb.fOutxDsrFlow = TRUE;
811                         break;
812                 default:
813                         return SP_ERR_ARG;
814                 }
815         }
816
817         if (config->xon_xoff >= 0) {
818                 switch (config->xon_xoff) {
819                 case SP_XONXOFF_DISABLED:
820                         data->dcb.fInX = FALSE;
821                         data->dcb.fOutX = FALSE;
822                         break;
823                 case SP_XONXOFF_IN:
824                         data->dcb.fInX = TRUE;
825                         data->dcb.fOutX = FALSE;
826                         break;
827                 case SP_XONXOFF_OUT:
828                         data->dcb.fInX = FALSE;
829                         data->dcb.fOutX = TRUE;
830                         break;
831                 case SP_XONXOFF_INOUT:
832                         data->dcb.fInX = TRUE;
833                         data->dcb.fOutX = TRUE;
834                         break;
835                 default:
836                         return SP_ERR_ARG;
837                 }
838         }
839
840         if (!SetCommState(port->hdl, &data->dcb))
841                 return SP_ERR_FAIL;
842
843 #else // !_WIN32
844
845         if (config->baudrate >= 0)
846         {
847                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
848                         if (config->baudrate == std_baudrates[i].value) {
849                                 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
850                                         return SP_ERR_FAIL;
851
852                                 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
853                                         return SP_ERR_FAIL;
854                                 break;
855                         }
856                 }
857
858                 if (i == NUM_STD_BAUDRATES)
859                         return SP_ERR_ARG;
860         }
861
862         if (config->bits >= 0) {
863                 data->term.c_cflag &= ~CSIZE;
864                 switch (config->bits) {
865                 case 8:
866                         data->term.c_cflag |= CS8;
867                         break;
868                 case 7:
869                         data->term.c_cflag |= CS7;
870                         break;
871                 case 6:
872                         data->term.c_cflag |= CS6;
873                         break;
874                 default:
875                         return SP_ERR_ARG;
876                 }
877         }
878
879         if (config->parity >= 0) {
880                 data->term.c_iflag &= ~IGNPAR;
881                 data->term.c_cflag &= ~(PARENB | PARODD);
882                 switch (config->parity) {
883                 case SP_PARITY_NONE:
884                         data->term.c_iflag |= IGNPAR;
885                         break;
886                 case SP_PARITY_EVEN:
887                         data->term.c_cflag |= PARENB;
888                         break;
889                 case SP_PARITY_ODD:
890                         data->term.c_cflag |= PARENB | PARODD;
891                         break;
892                 default:
893                         return SP_ERR_ARG;
894                 }
895         }
896
897         if (config->stopbits >= 0) {
898                 data->term.c_cflag &= ~CSTOPB;
899                 switch (config->stopbits) {
900                 case 1:
901                         data->term.c_cflag &= ~CSTOPB;
902                         break;
903                 case 2:
904                         data->term.c_cflag |= CSTOPB;
905                         break;
906                 default:
907                         return SP_ERR_ARG;
908                 }
909         }
910
911         if (config->rts >= 0 || config->cts >= 0)
912         {
913                 /* Asymmetric use of RTS/CTS not supported yet. */
914
915                 if (data->term.c_iflag & CRTSCTS) {
916                         /* Flow control can only be disabled for both RTS & CTS together. */
917                         if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
918                                 if (config->cts != SP_CTS_IGNORE)
919                                         return SP_ERR_ARG;
920                         }
921                         if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
922                                 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
923                                         return SP_ERR_ARG;
924                         }
925                 } else {
926                         /* Flow control can only be enabled for both RTS & CTS together. */
927                         if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
928                                 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
929                                 return SP_ERR_ARG;
930                 }
931
932                 if (config->rts >= 0) {
933                         if (config->rts == SP_RTS_FLOW_CONTROL) {
934                                 data->term.c_iflag |= CRTSCTS;
935                         } else {
936                                 int controlbits = TIOCM_RTS;
937                                 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
938                                                 &controlbits) < 0)
939                                         return SP_ERR_FAIL;
940                         }
941                 }
942         }
943
944         if (config->dtr >= 0 || config->dsr >= 0)
945         {
946                 /* DTR/DSR flow control not supported yet. */
947                 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
948                         return SP_ERR_ARG;
949
950                 if (config->dtr >= 0) {
951                         int controlbits = TIOCM_DTR;
952                         if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
953                                         &controlbits) < 0)
954                                 return SP_ERR_FAIL;
955                 }
956         }
957
958         if (config->xon_xoff >= 0) {
959                 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
960                 switch (config->xon_xoff) {
961                 case SP_XONXOFF_DISABLED:
962                         break;
963                 case SP_XONXOFF_IN:
964                         data->term.c_iflag |= IXOFF;
965                         break;
966                 case SP_XONXOFF_OUT:
967                         data->term.c_iflag |= IXON | IXANY;
968                         break;
969                 case SP_XONXOFF_INOUT:
970                         data->term.c_iflag |= IXON | IXOFF | IXANY;
971                         break;
972                 default:
973                         return SP_ERR_ARG;
974                 }
975         }
976
977         if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
978                 return SP_ERR_FAIL;
979 #endif
980
981         return SP_OK;
982 }
983
984 #define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
985
986 int sp_set_config(struct sp_port *port, struct sp_port_config *config)
987 {
988         struct sp_port_data data;
989         struct sp_port_config prev_config;
990
991         TRY(get_config(port, &data, &prev_config));
992         TRY(set_config(port, &data, config));
993
994         return SP_OK;
995 }
996
997 #define CREATE_SETTER(x) int sp_set_##x(struct sp_port *port, int x) { \
998         struct sp_port_data data; \
999         struct sp_port_config config; \
1000         TRY(get_config(port, &data, &config)); \
1001         config.x = x; \
1002         TRY(set_config(port, &data, &config)); \
1003         return SP_OK; \
1004 }
1005
1006 CREATE_SETTER(baudrate)
1007 CREATE_SETTER(bits)
1008 CREATE_SETTER(parity)
1009 CREATE_SETTER(stopbits)
1010 CREATE_SETTER(rts)
1011 CREATE_SETTER(cts)
1012 CREATE_SETTER(dtr)
1013 CREATE_SETTER(dsr)
1014 CREATE_SETTER(xon_xoff)
1015
1016 int sp_set_flowcontrol(struct sp_port *port, int flowcontrol)
1017 {
1018         struct sp_port_data data;
1019         struct sp_port_config config;
1020
1021         TRY(get_config(port, &data, &config));
1022
1023         if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
1024                 config.xon_xoff = SP_XONXOFF_INOUT;
1025         else
1026                 config.xon_xoff = SP_XONXOFF_DISABLED;
1027
1028         if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
1029                 config.rts = SP_RTS_FLOW_CONTROL;
1030                 config.cts = SP_CTS_FLOW_CONTROL;
1031         } else {
1032                 if (config.rts == SP_RTS_FLOW_CONTROL)
1033                         config.rts = SP_RTS_ON;
1034                 config.cts = SP_CTS_IGNORE;
1035         }
1036
1037         if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
1038                 config.dtr = SP_DTR_FLOW_CONTROL;
1039                 config.dsr = SP_DSR_FLOW_CONTROL;
1040         } else {
1041                 if (config.dtr == SP_DTR_FLOW_CONTROL)
1042                         config.dtr = SP_DTR_ON;
1043                 config.dsr = SP_DSR_IGNORE;
1044         }
1045
1046         TRY(set_config(port, &data, &config));
1047
1048         return SP_OK;
1049 }
1050
1051 int sp_last_error_code(void)
1052 {
1053 #ifdef _WIN32
1054         return GetLastError();
1055 #else
1056         return errno;
1057 #endif
1058 }
1059
1060 char *sp_last_error_message(void)
1061 {
1062 #ifdef _WIN32
1063         LPVOID message;
1064         DWORD error = GetLastError();
1065
1066         FormatMessage(
1067                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1068                 FORMAT_MESSAGE_FROM_SYSTEM |
1069                 FORMAT_MESSAGE_IGNORE_INSERTS,
1070                 NULL,
1071                 error,
1072                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1073                 (LPTSTR) &message,
1074                 0, NULL );
1075
1076         return message;
1077 #else
1078         return strerror(errno);
1079 #endif
1080 }
1081
1082 void sp_free_error_message(char *message)
1083 {
1084 #ifdef _WIN32
1085         LocalFree(message);
1086 #else
1087         (void)message;
1088 #endif
1089 }