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