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