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