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