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