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