]> sigrok.org Git - libserialport.git/blob - serialport.c
2ec2c2f19225f9a526f6438f7b6144a5a6270351
[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  * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
8  * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as
12  * published by the Free Software Foundation, either version 3 of the
13  * License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "libserialport.h"
25 #include "libserialport_internal.h"
26
27 const struct std_baudrate std_baudrates[] = {
28 #ifdef _WIN32
29         /*
30          * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
31          * have documented CBR_* macros.
32          */
33         BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
34         BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
35         BAUD(115200), BAUD(128000), BAUD(256000),
36 #else
37         BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
38         BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
39         BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
40         BAUD(230400),
41 #if !defined(__APPLE__) && !defined(__OpenBSD__)
42         BAUD(460800),
43 #endif
44 #endif
45 };
46
47 void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
48
49 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
50         struct sp_port_config *config);
51
52 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
53         const struct sp_port_config *config);
54
55 SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
56 {
57         struct sp_port *port;
58 #ifndef NO_PORT_METADATA
59         enum sp_return ret;
60 #endif
61         int len;
62
63         TRACE("%s, %p", portname, port_ptr);
64
65         if (!port_ptr)
66                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
67
68         *port_ptr = NULL;
69
70         if (!portname)
71                 RETURN_ERROR(SP_ERR_ARG, "Null port name");
72
73         DEBUG_FMT("Building structure for port %s", portname);
74
75         if (!(port = malloc(sizeof(struct sp_port))))
76                 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
77
78         len = strlen(portname) + 1;
79
80         if (!(port->name = malloc(len))) {
81                 free(port);
82                 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
83         }
84
85         memcpy(port->name, portname, len);
86
87 #ifdef _WIN32
88         port->usb_path = NULL;
89         port->hdl = INVALID_HANDLE_VALUE;
90 #else
91         port->fd = -1;
92 #endif
93
94         port->description = NULL;
95         port->transport = SP_TRANSPORT_NATIVE;
96         port->usb_bus = -1;
97         port->usb_address = -1;
98         port->usb_vid = -1;
99         port->usb_pid = -1;
100         port->usb_manufacturer = NULL;
101         port->usb_product = NULL;
102         port->usb_serial = NULL;
103         port->bluetooth_address = NULL;
104
105 #ifndef NO_PORT_METADATA
106         if ((ret = get_port_details(port)) != SP_OK) {
107                 sp_free_port(port);
108                 return ret;
109         }
110 #endif
111
112         *port_ptr = port;
113
114         RETURN_OK();
115 }
116
117 SP_API char *sp_get_port_name(const struct sp_port *port)
118 {
119         TRACE("%p", port);
120
121         if (!port)
122                 return NULL;
123
124         RETURN_STRING(port->name);
125 }
126
127 SP_API char *sp_get_port_description(struct sp_port *port)
128 {
129         TRACE("%p", port);
130
131         if (!port || !port->description)
132                 return NULL;
133
134         RETURN_STRING(port->description);
135 }
136
137 SP_API enum sp_transport sp_get_port_transport(struct sp_port *port)
138 {
139         TRACE("%p", port);
140
141         if (!port)
142                 RETURN_ERROR(SP_ERR_ARG, "Null port");
143
144         RETURN_INT(port->transport);
145 }
146
147 SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
148                                                   int *usb_bus,int *usb_address)
149 {
150         TRACE("%p", port);
151
152         if (!port)
153                 RETURN_ERROR(SP_ERR_ARG, "Null port");
154         if (port->transport != SP_TRANSPORT_USB)
155                 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
156         if (port->usb_bus < 0 || port->usb_address < 0)
157                 RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available");
158
159         if (usb_bus)      *usb_bus     = port->usb_bus;
160         if (usb_address)  *usb_address = port->usb_address;
161
162         RETURN_OK();
163 }
164
165 SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port,
166                                               int *usb_vid, int *usb_pid)
167 {
168         TRACE("%p", port);
169
170         if (!port)
171                 RETURN_ERROR(SP_ERR_ARG, "Null port");
172         if (port->transport != SP_TRANSPORT_USB)
173                 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
174         if (port->usb_vid < 0 || port->usb_pid < 0)
175                 RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available");
176
177         if (usb_vid)  *usb_vid = port->usb_vid;
178         if (usb_pid)  *usb_pid = port->usb_pid;
179
180         RETURN_OK();
181 }
182
183 SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port)
184 {
185         TRACE("%p", port);
186
187         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer)
188                 return NULL;
189
190         RETURN_STRING(port->usb_manufacturer);
191 }
192
193 SP_API char *sp_get_port_usb_product(const struct sp_port *port)
194 {
195         TRACE("%p", port);
196
197         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product)
198                 return NULL;
199
200         RETURN_STRING(port->usb_product);
201 }
202
203 SP_API char *sp_get_port_usb_serial(const struct sp_port *port)
204 {
205         TRACE("%p", port);
206
207         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial)
208                 return NULL;
209
210         RETURN_STRING(port->usb_serial);
211 }
212
213 SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port)
214 {
215         TRACE("%p", port);
216
217         if (!port || port->transport != SP_TRANSPORT_BLUETOOTH
218             || !port->bluetooth_address)
219                 return NULL;
220
221         RETURN_STRING(port->bluetooth_address);
222 }
223
224 SP_API enum sp_return sp_get_port_handle(const struct sp_port *port,
225                                          void *result_ptr)
226 {
227         TRACE("%p, %p", port, result_ptr);
228
229         if (!port)
230                 RETURN_ERROR(SP_ERR_ARG, "Null port");
231
232 #ifdef _WIN32
233         HANDLE *handle_ptr = result_ptr;
234         *handle_ptr = port->hdl;
235 #else
236         int *fd_ptr = result_ptr;
237         *fd_ptr = port->fd;
238 #endif
239
240         RETURN_OK();
241 }
242
243 SP_API enum sp_return sp_copy_port(const struct sp_port *port,
244                                    struct sp_port **copy_ptr)
245 {
246         TRACE("%p, %p", port, copy_ptr);
247
248         if (!copy_ptr)
249                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
250
251         *copy_ptr = NULL;
252
253         if (!port)
254                 RETURN_ERROR(SP_ERR_ARG, "Null port");
255
256         if (!port->name)
257                 RETURN_ERROR(SP_ERR_ARG, "Null port name");
258
259         DEBUG("Copying port structure");
260
261         RETURN_INT(sp_get_port_by_name(port->name, copy_ptr));
262 }
263
264 SP_API void sp_free_port(struct sp_port *port)
265 {
266         TRACE("%p", port);
267
268         if (!port) {
269                 DEBUG("Null port");
270                 RETURN();
271         }
272
273         DEBUG("Freeing port structure");
274
275         if (port->name)
276                 free(port->name);
277         if (port->description)
278                 free(port->description);
279         if (port->usb_manufacturer)
280                 free(port->usb_manufacturer);
281         if (port->usb_product)
282                 free(port->usb_product);
283         if (port->usb_serial)
284                 free(port->usb_serial);
285         if (port->bluetooth_address)
286                 free(port->bluetooth_address);
287 #ifdef _WIN32
288         if (port->usb_path)
289                 free(port->usb_path);
290 #endif
291
292         free(port);
293
294         RETURN();
295 }
296
297 SP_PRIV struct sp_port **list_append(struct sp_port **list,
298                                      const char *portname)
299 {
300         void *tmp;
301         unsigned int count;
302
303         for (count = 0; list[count]; count++);
304         if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
305                 goto fail;
306         list = tmp;
307         if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
308                 goto fail;
309         list[count + 1] = NULL;
310         return list;
311
312 fail:
313         sp_free_port_list(list);
314         return NULL;
315 }
316
317 SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr)
318 {
319         struct sp_port **list;
320         int ret;
321
322         TRACE("%p", list_ptr);
323
324         if (!list_ptr)
325                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
326
327         DEBUG("Enumerating ports");
328
329         if (!(list = malloc(sizeof(struct sp_port **))))
330                 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
331
332         list[0] = NULL;
333
334 #ifdef NO_ENUMERATION
335         ret = SP_ERR_SUPP;
336 #else
337         ret = list_ports(&list);
338 #endif
339
340         switch (ret) {
341         case SP_OK:
342                 *list_ptr = list;
343                 RETURN_OK();
344         case SP_ERR_SUPP:
345                 DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
346         default:
347                 if (list)
348                         sp_free_port_list(list);
349                 *list_ptr = NULL;
350                 return ret;
351         }
352 }
353
354 SP_API void sp_free_port_list(struct sp_port **list)
355 {
356         unsigned int i;
357
358         TRACE("%p", list);
359
360         if (!list) {
361                 DEBUG("Null list");
362                 RETURN();
363         }
364
365         DEBUG("Freeing port list");
366
367         for (i = 0; list[i]; i++)
368                 sp_free_port(list[i]);
369         free(list);
370
371         RETURN();
372 }
373
374 #define CHECK_PORT() do { \
375         if (port == NULL) \
376                 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
377         if (port->name == NULL) \
378                 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
379 } while (0)
380 #ifdef _WIN32
381 #define CHECK_PORT_HANDLE() do { \
382         if (port->hdl == INVALID_HANDLE_VALUE) \
383                 RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \
384 } while (0)
385 #else
386 #define CHECK_PORT_HANDLE() do { \
387         if (port->fd < 0) \
388                 RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \
389 } while (0)
390 #endif
391 #define CHECK_OPEN_PORT() do { \
392         CHECK_PORT(); \
393         CHECK_PORT_HANDLE(); \
394 } while (0)
395
396 SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
397 {
398         struct port_data data;
399         struct sp_port_config config;
400         enum sp_return ret;
401
402         TRACE("%p, 0x%x", port, flags);
403
404         CHECK_PORT();
405
406         if (flags > SP_MODE_READ_WRITE)
407                 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
408
409         DEBUG_FMT("Opening port %s", port->name);
410
411 #ifdef _WIN32
412         DWORD desired_access = 0, flags_and_attributes = 0, errors;
413         char *escaped_port_name;
414         COMSTAT status;
415
416         /* Prefix port name with '\\.\' to work with ports above COM9. */
417         if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
418                 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
419         sprintf(escaped_port_name, "\\\\.\\%s", port->name);
420
421         /* Map 'flags' to the OS-specific settings. */
422         flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
423         if (flags & SP_MODE_READ)
424                 desired_access |= GENERIC_READ;
425         if (flags & SP_MODE_WRITE)
426                 desired_access |= GENERIC_WRITE;
427
428         port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
429                          OPEN_EXISTING, flags_and_attributes, 0);
430
431         free(escaped_port_name);
432
433         if (port->hdl == INVALID_HANDLE_VALUE)
434                 RETURN_FAIL("port CreateFile() failed");
435
436         /* All timeouts initially disabled. */
437         port->timeouts.ReadIntervalTimeout = 0;
438         port->timeouts.ReadTotalTimeoutMultiplier = 0;
439         port->timeouts.ReadTotalTimeoutConstant = 0;
440         port->timeouts.WriteTotalTimeoutMultiplier = 0;
441         port->timeouts.WriteTotalTimeoutConstant = 0;
442
443         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) {
444                 sp_close(port);
445                 RETURN_FAIL("SetCommTimeouts() failed");
446         }
447
448         /* Prepare OVERLAPPED structures. */
449 #define INIT_OVERLAPPED(ovl) do { \
450         memset(&port->ovl, 0, sizeof(port->ovl)); \
451         port->ovl.hEvent = INVALID_HANDLE_VALUE; \
452         if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \
453                         == INVALID_HANDLE_VALUE) { \
454                 sp_close(port); \
455                 RETURN_FAIL(#ovl "CreateEvent() failed"); \
456         } \
457 } while (0)
458
459         INIT_OVERLAPPED(read_ovl);
460         INIT_OVERLAPPED(write_ovl);
461         INIT_OVERLAPPED(wait_ovl);
462
463         /* Set event mask for RX and error events. */
464         if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) {
465                 sp_close(port);
466                 RETURN_FAIL("SetCommMask() failed");
467         }
468
469         /* Start background operation for RX and error events. */
470         if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
471                 if (GetLastError() != ERROR_IO_PENDING) {
472                         sp_close(port);
473                         RETURN_FAIL("WaitCommEvent() failed");
474                 }
475         }
476
477         port->writing = FALSE;
478
479 #else
480         int flags_local = O_NONBLOCK | O_NOCTTY;
481
482         /* Map 'flags' to the OS-specific settings. */
483         if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE)
484                 flags_local |= O_RDWR;
485         else if (flags & SP_MODE_READ)
486                 flags_local |= O_RDONLY;
487         else if (flags & SP_MODE_WRITE)
488                 flags_local |= O_WRONLY;
489
490         if ((port->fd = open(port->name, flags_local)) < 0)
491                 RETURN_FAIL("open() failed");
492 #endif
493
494         ret = get_config(port, &data, &config);
495
496         if (ret < 0) {
497                 sp_close(port);
498                 RETURN_CODEVAL(ret);
499         }
500
501         /* Set sane port settings. */
502 #ifdef _WIN32
503         data.dcb.fBinary = TRUE;
504         data.dcb.fDsrSensitivity = FALSE;
505         data.dcb.fErrorChar = FALSE;
506         data.dcb.fNull = FALSE;
507         data.dcb.fAbortOnError = TRUE;
508 #else
509         /* Turn off all fancy termios tricks, give us a raw channel. */
510         data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL);
511 #ifdef IUCLC
512         data.term.c_iflag &= ~IUCLC;
513 #endif
514         data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
515 #ifdef OLCUC
516         data.term.c_oflag &= ~OLCUC;
517 #endif
518 #ifdef NLDLY
519         data.term.c_oflag &= ~NLDLY;
520 #endif
521 #ifdef CRDLY
522         data.term.c_oflag &= ~CRDLY;
523 #endif
524 #ifdef TABDLY
525         data.term.c_oflag &= ~TABDLY;
526 #endif
527 #ifdef BSDLY
528         data.term.c_oflag &= ~BSDLY;
529 #endif
530 #ifdef VTDLY
531         data.term.c_oflag &= ~VTDLY;
532 #endif
533 #ifdef FFDLY
534         data.term.c_oflag &= ~FFDLY;
535 #endif
536 #ifdef OFILL
537         data.term.c_oflag &= ~OFILL;
538 #endif
539         data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
540         data.term.c_cc[VMIN] = 0;
541         data.term.c_cc[VTIME] = 0;
542
543         /* Ignore modem status lines; enable receiver; leave control lines alone on close. */
544         data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
545 #endif
546
547 #ifdef _WIN32
548         if (ClearCommError(port->hdl, &errors, &status) == 0)
549                 RETURN_FAIL("ClearCommError() failed");
550 #endif
551
552         ret = set_config(port, &data, &config);
553
554         if (ret < 0) {
555                 sp_close(port);
556                 RETURN_CODEVAL(ret);
557         }
558
559         RETURN_OK();
560 }
561
562 SP_API enum sp_return sp_close(struct sp_port *port)
563 {
564         TRACE("%p", port);
565
566         CHECK_OPEN_PORT();
567
568         DEBUG_FMT("Closing port %s", port->name);
569
570 #ifdef _WIN32
571         /* Returns non-zero upon success, 0 upon failure. */
572         if (CloseHandle(port->hdl) == 0)
573                 RETURN_FAIL("port CloseHandle() failed");
574         port->hdl = INVALID_HANDLE_VALUE;
575
576         /* Close event handles for overlapped structures. */
577 #define CLOSE_OVERLAPPED(ovl) do { \
578         if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \
579                 CloseHandle(port->ovl.hEvent) == 0) \
580                 RETURN_FAIL(# ovl "event CloseHandle() failed"); \
581 } while (0)
582         CLOSE_OVERLAPPED(read_ovl);
583         CLOSE_OVERLAPPED(write_ovl);
584         CLOSE_OVERLAPPED(wait_ovl);
585
586 #else
587         /* Returns 0 upon success, -1 upon failure. */
588         if (close(port->fd) == -1)
589                 RETURN_FAIL("close() failed");
590         port->fd = -1;
591 #endif
592
593         RETURN_OK();
594 }
595
596 SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
597 {
598         TRACE("%p, 0x%x", port, buffers);
599
600         CHECK_OPEN_PORT();
601
602         if (buffers > SP_BUF_BOTH)
603                 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
604
605         const char *buffer_names[] = {"no", "input", "output", "both"};
606
607         DEBUG_FMT("Flushing %s buffers on port %s",
608                 buffer_names[buffers], port->name);
609
610 #ifdef _WIN32
611         DWORD flags = 0;
612         if (buffers & SP_BUF_INPUT)
613                 flags |= PURGE_RXCLEAR;
614         if (buffers & SP_BUF_OUTPUT)
615                 flags |= PURGE_TXCLEAR;
616
617         /* Returns non-zero upon success, 0 upon failure. */
618         if (PurgeComm(port->hdl, flags) == 0)
619                 RETURN_FAIL("PurgeComm() failed");
620 #else
621         int flags = 0;
622         if (buffers == SP_BUF_BOTH)
623                 flags = TCIOFLUSH;
624         else if (buffers == SP_BUF_INPUT)
625                 flags = TCIFLUSH;
626         else if (buffers == SP_BUF_OUTPUT)
627                 flags = TCOFLUSH;
628
629         /* Returns 0 upon success, -1 upon failure. */
630         if (tcflush(port->fd, flags) < 0)
631                 RETURN_FAIL("tcflush() failed");
632 #endif
633         RETURN_OK();
634 }
635
636 SP_API enum sp_return sp_drain(struct sp_port *port)
637 {
638         TRACE("%p", port);
639
640         CHECK_OPEN_PORT();
641
642         DEBUG_FMT("Draining port %s", port->name);
643
644 #ifdef _WIN32
645         /* Returns non-zero upon success, 0 upon failure. */
646         if (FlushFileBuffers(port->hdl) == 0)
647                 RETURN_FAIL("FlushFileBuffers() failed");
648         RETURN_OK();
649 #else
650         int result;
651         while (1) {
652 #ifdef __ANDROID__
653                 int arg = 1;
654                 result = ioctl(port->fd, TCSBRK, &arg);
655 #else
656                 result = tcdrain(port->fd);
657 #endif
658                 if (result < 0) {
659                         if (errno == EINTR) {
660                                 DEBUG("tcdrain() was interrupted");
661                                 continue;
662                         } else {
663                                 RETURN_FAIL("tcdrain() failed");
664                         }
665                 } else {
666                         RETURN_OK();
667                 }
668         }
669 #endif
670 }
671
672 SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
673                                         size_t count, unsigned int timeout)
674 {
675         TRACE("%p, %p, %d, %d", port, buf, count, timeout);
676
677         CHECK_OPEN_PORT();
678
679         if (!buf)
680                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
681
682         if (timeout)
683                 DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms",
684                         count, port->name, timeout);
685         else
686                 DEBUG_FMT("Writing %d bytes to port %s, no timeout",
687                         count, port->name);
688
689         if (count == 0)
690                 RETURN_INT(0);
691
692 #ifdef _WIN32
693         DWORD bytes_written = 0;
694         BOOL result;
695
696         /* Wait for previous non-blocking write to complete, if any. */
697         if (port->writing) {
698                 DEBUG("Waiting for previous write to complete");
699                 result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
700                 port->writing = 0;
701                 if (!result)
702                         RETURN_FAIL("Previous write failed to complete");
703                 DEBUG("Previous write completed");
704         }
705
706         /* Set timeout. */
707         port->timeouts.WriteTotalTimeoutConstant = timeout;
708         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
709                 RETURN_FAIL("SetCommTimeouts() failed");
710
711         /* Start write. */
712         if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0) {
713                 if (GetLastError() == ERROR_IO_PENDING) {
714                         DEBUG("Waiting for write to complete");
715                         GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
716                         DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count);
717                         RETURN_INT(bytes_written);
718                 } else {
719                         RETURN_FAIL("WriteFile() failed");
720                 }
721         } else {
722                 DEBUG("Write completed immediately");
723                 RETURN_INT(count);
724         }
725 #else
726         size_t bytes_written = 0;
727         unsigned char *ptr = (unsigned char *) buf;
728         struct timeval start, delta, now, end = {0, 0};
729         fd_set fds;
730         int result;
731
732         if (timeout) {
733                 /* Get time at start of operation. */
734                 gettimeofday(&start, NULL);
735                 /* Define duration of timeout. */
736                 delta.tv_sec = timeout / 1000;
737                 delta.tv_usec = (timeout % 1000) * 1000;
738                 /* Calculate time at which we should give up. */
739                 timeradd(&start, &delta, &end);
740         }
741
742         /* Loop until we have written the requested number of bytes. */
743         while (bytes_written < count)
744         {
745                 /* Wait until space is available. */
746                 FD_ZERO(&fds);
747                 FD_SET(port->fd, &fds);
748                 if (timeout) {
749                         gettimeofday(&now, NULL);
750                         if (timercmp(&now, &end, >)) {
751                                 DEBUG("write timed out");
752                                 RETURN_INT(bytes_written);
753                         }
754                         timersub(&end, &now, &delta);
755                 }
756                 result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL);
757                 if (result < 0) {
758                         if (errno == EINTR) {
759                                 DEBUG("select() call was interrupted, repeating");
760                                 continue;
761                         } else {
762                                 RETURN_FAIL("select() failed");
763                         }
764                 } else if (result == 0) {
765                         DEBUG("write timed out");
766                         RETURN_INT(bytes_written);
767                 }
768
769                 /* Do write. */
770                 result = write(port->fd, ptr, count - bytes_written);
771
772                 if (result < 0) {
773                         if (errno == EAGAIN)
774                                 /* This shouldn't happen because we did a select() first, but handle anyway. */
775                                 continue;
776                         else
777                                 /* This is an actual failure. */
778                                 RETURN_FAIL("write() failed");
779                 }
780
781                 bytes_written += result;
782                 ptr += result;
783         }
784
785         RETURN_INT(bytes_written);
786 #endif
787 }
788
789 SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
790                                            const void *buf, size_t count)
791 {
792         TRACE("%p, %p, %d", port, buf, count);
793
794         CHECK_OPEN_PORT();
795
796         if (!buf)
797                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
798
799         DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name);
800
801         if (count == 0)
802                 RETURN_INT(0);
803
804 #ifdef _WIN32
805         DWORD written = 0;
806         BYTE *ptr = (BYTE *) buf;
807
808         /* Check whether previous write is complete. */
809         if (port->writing) {
810                 if (HasOverlappedIoCompleted(&port->write_ovl)) {
811                         DEBUG("Previous write completed");
812                         port->writing = 0;
813                 } else {
814                         DEBUG("Previous write not complete");
815                         /* Can't take a new write until the previous one finishes. */
816                         RETURN_INT(0);
817                 }
818         }
819
820         /* Set timeout. */
821         port->timeouts.WriteTotalTimeoutConstant = 0;
822         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
823                 RETURN_FAIL("SetCommTimeouts() failed");
824
825         /* Keep writing data until the OS has to actually start an async IO for it.
826          * At that point we know the buffer is full. */
827         while (written < count)
828         {
829                 /* Copy first byte of user buffer. */
830                 port->pending_byte = *ptr++;
831
832                 /* Start asynchronous write. */
833                 if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
834                         if (GetLastError() == ERROR_IO_PENDING) {
835                                 if (HasOverlappedIoCompleted(&port->write_ovl)) {
836                                         DEBUG("Asynchronous write completed immediately");
837                                         port->writing = 0;
838                                         written++;
839                                         continue;
840                                 } else {
841                                         DEBUG("Asynchronous write running");
842                                         port->writing = 1;
843                                         RETURN_INT(++written);
844                                 }
845                         } else {
846                                 /* Actual failure of some kind. */
847                                 RETURN_FAIL("WriteFile() failed");
848                         }
849                 } else {
850                         DEBUG("Single byte written immediately");
851                         written++;
852                 }
853         }
854
855         DEBUG("All bytes written immediately");
856
857         RETURN_INT(written);
858 #else
859         /* Returns the number of bytes written, or -1 upon failure. */
860         ssize_t written = write(port->fd, buf, count);
861
862         if (written < 0)
863                 RETURN_FAIL("write() failed");
864         else
865                 RETURN_INT(written);
866 #endif
867 }
868
869 SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
870                                        size_t count, unsigned int timeout)
871 {
872         TRACE("%p, %p, %d, %d", port, buf, count, timeout);
873
874         CHECK_OPEN_PORT();
875
876         if (!buf)
877                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
878
879         if (timeout)
880                 DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms",
881                         count, port->name, timeout);
882         else
883                 DEBUG_FMT("Reading %d bytes from port %s, no timeout",
884                         count, port->name);
885
886         if (count == 0)
887                 RETURN_INT(0);
888
889 #ifdef _WIN32
890         DWORD bytes_read = 0;
891
892         /* Set timeout. */
893         port->timeouts.ReadIntervalTimeout = 0;
894         port->timeouts.ReadTotalTimeoutConstant = timeout;
895         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
896                 RETURN_FAIL("SetCommTimeouts() failed");
897
898         /* Start read. */
899         if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) {
900                 if (GetLastError() == ERROR_IO_PENDING) {
901                         DEBUG("Waiting for read to complete");
902                         GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE);
903                         DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count);
904                 } else {
905                         RETURN_FAIL("ReadFile() failed");
906                 }
907         } else {
908                 DEBUG("Read completed immediately");
909                 bytes_read = count;
910         }
911
912         /* Start background operation for subsequent events. */
913         if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
914                 if (GetLastError() != ERROR_IO_PENDING)
915                         RETURN_FAIL("WaitCommEvent() failed");
916         }
917
918         RETURN_INT(bytes_read);
919
920 #else
921         size_t bytes_read = 0;
922         unsigned char *ptr = (unsigned char *) buf;
923         struct timeval start, delta, now, end = {0, 0};
924         fd_set fds;
925         int result;
926
927         if (timeout) {
928                 /* Get time at start of operation. */
929                 gettimeofday(&start, NULL);
930                 /* Define duration of timeout. */
931                 delta.tv_sec = timeout / 1000;
932                 delta.tv_usec = (timeout % 1000) * 1000;
933                 /* Calculate time at which we should give up. */
934                 timeradd(&start, &delta, &end);
935         }
936
937         /* Loop until we have the requested number of bytes. */
938         while (bytes_read < count)
939         {
940                 /* Wait until data is available. */
941                 FD_ZERO(&fds);
942                 FD_SET(port->fd, &fds);
943                 if (timeout) {
944                         gettimeofday(&now, NULL);
945                         if (timercmp(&now, &end, >))
946                                 /* Timeout has expired. */
947                                 RETURN_INT(bytes_read);
948                         timersub(&end, &now, &delta);
949                 }
950                 result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL);
951                 if (result < 0) {
952                         if (errno == EINTR) {
953                                 DEBUG("select() call was interrupted, repeating");
954                                 continue;
955                         } else {
956                                 RETURN_FAIL("select() failed");
957                         }
958                 } else if (result == 0) {
959                         DEBUG("read timed out");
960                         RETURN_INT(bytes_read);
961                 }
962
963                 /* Do read. */
964                 result = read(port->fd, ptr, count - bytes_read);
965
966                 if (result < 0) {
967                         if (errno == EAGAIN)
968                                 /* This shouldn't happen because we did a select() first, but handle anyway. */
969                                 continue;
970                         else
971                                 /* This is an actual failure. */
972                                 RETURN_FAIL("read() failed");
973                 }
974
975                 bytes_read += result;
976                 ptr += result;
977         }
978
979         RETURN_INT(bytes_read);
980 #endif
981 }
982
983 SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
984                                           size_t count)
985 {
986         TRACE("%p, %p, %d", port, buf, count);
987
988         CHECK_OPEN_PORT();
989
990         if (!buf)
991                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
992
993         DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name);
994
995 #ifdef _WIN32
996         DWORD bytes_read;
997
998         /* Set timeout. */
999         port->timeouts.ReadIntervalTimeout = MAXDWORD;
1000         port->timeouts.ReadTotalTimeoutConstant = 0;
1001         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1002                 RETURN_FAIL("SetCommTimeouts() failed");
1003
1004         /* Do read. */
1005         if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
1006                 RETURN_FAIL("ReadFile() failed");
1007
1008         /* Get number of bytes read. */
1009         if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
1010                 RETURN_FAIL("GetOverlappedResult() failed");
1011
1012         if (bytes_read > 0) {
1013                 /* Start background operation for subsequent events. */
1014                 if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
1015                         if (GetLastError() != ERROR_IO_PENDING)
1016                                 RETURN_FAIL("WaitCommEvent() failed");
1017                 }
1018         }
1019
1020         RETURN_INT(bytes_read);
1021 #else
1022         ssize_t bytes_read;
1023
1024         /* Returns the number of bytes read, or -1 upon failure. */
1025         if ((bytes_read = read(port->fd, buf, count)) < 0) {
1026                 if (errno == EAGAIN)
1027                         /* No bytes available. */
1028                         bytes_read = 0;
1029                 else
1030                         /* This is an actual failure. */
1031                         RETURN_FAIL("read() failed");
1032         }
1033         RETURN_INT(bytes_read);
1034 #endif
1035 }
1036
1037 SP_API enum sp_return sp_input_waiting(struct sp_port *port)
1038 {
1039         TRACE("%p", port);
1040
1041         CHECK_OPEN_PORT();
1042
1043         DEBUG_FMT("Checking input bytes waiting on port %s", port->name);
1044
1045 #ifdef _WIN32
1046         DWORD errors;
1047         COMSTAT comstat;
1048
1049         if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1050                 RETURN_FAIL("ClearCommError() failed");
1051         RETURN_INT(comstat.cbInQue);
1052 #else
1053         int bytes_waiting;
1054         if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
1055                 RETURN_FAIL("TIOCINQ ioctl failed");
1056         RETURN_INT(bytes_waiting);
1057 #endif
1058 }
1059
1060 SP_API enum sp_return sp_output_waiting(struct sp_port *port)
1061 {
1062         TRACE("%p", port);
1063
1064         CHECK_OPEN_PORT();
1065
1066         DEBUG_FMT("Checking output bytes waiting on port %s", port->name);
1067
1068 #ifdef _WIN32
1069         DWORD errors;
1070         COMSTAT comstat;
1071
1072         if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1073                 RETURN_FAIL("ClearCommError() failed");
1074         RETURN_INT(comstat.cbOutQue);
1075 #else
1076         int bytes_waiting;
1077         if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
1078                 RETURN_FAIL("TIOCOUTQ ioctl failed");
1079         RETURN_INT(bytes_waiting);
1080 #endif
1081 }
1082
1083 SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
1084 {
1085         struct sp_event_set *result;
1086
1087         TRACE("%p", result_ptr);
1088
1089         if (!result_ptr)
1090                 RETURN_ERROR(SP_ERR_ARG, "Null result");
1091
1092         *result_ptr = NULL;
1093
1094         if (!(result = malloc(sizeof(struct sp_event_set))))
1095                 RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed");
1096
1097         memset(result, 0, sizeof(struct sp_event_set));
1098
1099         *result_ptr = result;
1100
1101         RETURN_OK();
1102 }
1103
1104 static enum sp_return add_handle(struct sp_event_set *event_set,
1105                 event_handle handle, enum sp_event mask)
1106 {
1107         void *new_handles;
1108         enum sp_event *new_masks;
1109
1110         TRACE("%p, %d, %d", event_set, handle, mask);
1111
1112         if (!(new_handles = realloc(event_set->handles,
1113                         sizeof(event_handle) * (event_set->count + 1))))
1114                 RETURN_ERROR(SP_ERR_MEM, "handle array realloc() failed");
1115
1116         if (!(new_masks = realloc(event_set->masks,
1117                         sizeof(enum sp_event) * (event_set->count + 1))))
1118                 RETURN_ERROR(SP_ERR_MEM, "mask array realloc() failed");
1119
1120         event_set->handles = new_handles;
1121         event_set->masks = new_masks;
1122
1123         ((event_handle *) event_set->handles)[event_set->count] = handle;
1124         event_set->masks[event_set->count] = mask;
1125
1126         event_set->count++;
1127
1128         RETURN_OK();
1129 }
1130
1131 SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set,
1132         const struct sp_port *port, enum sp_event mask)
1133 {
1134         TRACE("%p, %p, %d", event_set, port, mask);
1135
1136         if (!event_set)
1137                 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1138
1139         if (!port)
1140                 RETURN_ERROR(SP_ERR_ARG, "Null port");
1141
1142         if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR))
1143                 RETURN_ERROR(SP_ERR_ARG, "Invalid event mask");
1144
1145         if (!mask)
1146                 RETURN_OK();
1147
1148 #ifdef _WIN32
1149         enum sp_event handle_mask;
1150         if ((handle_mask = mask & SP_EVENT_TX_READY))
1151                 TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask));
1152         if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR)))
1153                 TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask));
1154 #else
1155         TRY(add_handle(event_set, port->fd, mask));
1156 #endif
1157
1158         RETURN_OK();
1159 }
1160
1161 SP_API void sp_free_event_set(struct sp_event_set *event_set)
1162 {
1163         TRACE("%p", event_set);
1164
1165         if (!event_set) {
1166                 DEBUG("Null event set");
1167                 RETURN();
1168         }
1169
1170         DEBUG("Freeing event set");
1171
1172         if (event_set->handles)
1173                 free(event_set->handles);
1174         if (event_set->masks)
1175                 free(event_set->masks);
1176
1177         free(event_set);
1178
1179         RETURN();
1180 }
1181
1182 SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
1183                               unsigned int timeout)
1184 {
1185         TRACE("%p, %d", event_set, timeout);
1186
1187         if (!event_set)
1188                 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1189
1190 #ifdef _WIN32
1191         if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE,
1192                         timeout ? timeout : INFINITE) == WAIT_FAILED)
1193                 RETURN_FAIL("WaitForMultipleObjects() failed");
1194
1195         RETURN_OK();
1196 #else
1197         struct timeval start, delta, now, end = {0, 0};
1198         int result, timeout_remaining;
1199         struct pollfd *pollfds;
1200         unsigned int i;
1201
1202         if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count)))
1203                 RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
1204
1205         for (i = 0; i < event_set->count; i++) {
1206                 pollfds[i].fd = ((int *) event_set->handles)[i];
1207                 pollfds[i].events = 0;
1208                 pollfds[i].revents = 0;
1209                 if (event_set->masks[i] & SP_EVENT_RX_READY)
1210                         pollfds[i].events |= POLLIN;
1211                 if (event_set->masks[i] & SP_EVENT_TX_READY)
1212                         pollfds[i].events |= POLLOUT;
1213                 if (event_set->masks[i] & SP_EVENT_ERROR)
1214                         pollfds[i].events |= POLLERR;
1215         }
1216
1217         if (timeout) {
1218                 /* Get time at start of operation. */
1219                 gettimeofday(&start, NULL);
1220                 /* Define duration of timeout. */
1221                 delta.tv_sec = timeout / 1000;
1222                 delta.tv_usec = (timeout % 1000) * 1000;
1223                 /* Calculate time at which we should give up. */
1224                 timeradd(&start, &delta, &end);
1225         }
1226
1227         /* Loop until an event occurs. */
1228         while (1)
1229         {
1230                 if (timeout) {
1231                         gettimeofday(&now, NULL);
1232                         if (timercmp(&now, &end, >)) {
1233                                 DEBUG("wait timed out");
1234                                 break;
1235                         }
1236                         timersub(&end, &now, &delta);
1237                         timeout_remaining = delta.tv_sec * 1000 + delta.tv_usec / 1000;
1238                 }
1239
1240                 result = poll(pollfds, event_set->count, timeout ? timeout_remaining : -1);
1241
1242                 if (result < 0) {
1243                         if (errno == EINTR) {
1244                                 DEBUG("poll() call was interrupted, repeating");
1245                                 continue;
1246                         } else {
1247                                 free(pollfds);
1248                                 RETURN_FAIL("poll() failed");
1249                         }
1250                 } else if (result == 0) {
1251                         DEBUG("poll() timed out");
1252                         break;
1253                 } else {
1254                         DEBUG("poll() completed");
1255                         break;
1256                 }
1257         }
1258
1259         free(pollfds);
1260         RETURN_OK();
1261 #endif
1262 }
1263
1264 #ifdef USE_TERMIOS_SPEED
1265 static enum sp_return get_baudrate(int fd, int *baudrate)
1266 {
1267         void *data;
1268
1269         TRACE("%d, %p", fd, baudrate);
1270
1271         DEBUG("Getting baud rate");
1272
1273         if (!(data = malloc(get_termios_size())))
1274                 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
1275
1276         if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1277                 free(data);
1278                 RETURN_FAIL("getting termios failed");
1279         }
1280
1281         *baudrate = get_termios_speed(data);
1282
1283         free(data);
1284
1285         RETURN_OK();
1286 }
1287
1288 static enum sp_return set_baudrate(int fd, int baudrate)
1289 {
1290         void *data;
1291
1292         TRACE("%d, %d", fd, baudrate);
1293
1294         DEBUG("Getting baud rate");
1295
1296         if (!(data = malloc(get_termios_size())))
1297                 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
1298
1299         if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1300                 free(data);
1301                 RETURN_FAIL("getting termios failed");
1302         }
1303
1304         DEBUG("Setting baud rate");
1305
1306         set_termios_speed(data, baudrate);
1307
1308         if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
1309                 free(data);
1310                 RETURN_FAIL("setting termios failed");
1311         }
1312
1313         free(data);
1314
1315         RETURN_OK();
1316 }
1317 #endif /* USE_TERMIOS_SPEED */
1318
1319 #ifdef USE_TERMIOX
1320 static enum sp_return get_flow(int fd, struct port_data *data)
1321 {
1322         void *termx;
1323
1324         TRACE("%d, %p", fd, data);
1325
1326         DEBUG("Getting advanced flow control");
1327
1328         if (!(termx = malloc(get_termiox_size())))
1329                 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
1330
1331         if (ioctl(fd, TCGETX, termx) < 0) {
1332                 free(termx);
1333                 RETURN_FAIL("getting termiox failed");
1334         }
1335
1336         get_termiox_flow(termx, &data->rts_flow, &data->cts_flow,
1337                         &data->dtr_flow, &data->dsr_flow);
1338
1339         free(termx);
1340
1341         RETURN_OK();
1342 }
1343
1344 static enum sp_return set_flow(int fd, struct port_data *data)
1345 {
1346         void *termx;
1347
1348         TRACE("%d, %p", fd, data);
1349
1350         DEBUG("Getting advanced flow control");
1351
1352         if (!(termx = malloc(get_termiox_size())))
1353                 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
1354
1355         if (ioctl(fd, TCGETX, termx) < 0) {
1356                 free(termx);
1357                 RETURN_FAIL("getting termiox failed");
1358         }
1359
1360         DEBUG("Setting advanced flow control");
1361
1362         set_termiox_flow(termx, data->rts_flow, data->cts_flow,
1363                         data->dtr_flow, data->dsr_flow);
1364
1365         if (ioctl(fd, TCSETX, termx) < 0) {
1366                 free(termx);
1367                 RETURN_FAIL("setting termiox failed");
1368         }
1369
1370         free(termx);
1371
1372         RETURN_OK();
1373 }
1374 #endif /* USE_TERMIOX */
1375
1376 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
1377         struct sp_port_config *config)
1378 {
1379         unsigned int i;
1380
1381         TRACE("%p, %p, %p", port, data, config);
1382
1383         DEBUG_FMT("Getting configuration for port %s", port->name);
1384
1385 #ifdef _WIN32
1386         if (!GetCommState(port->hdl, &data->dcb))
1387                 RETURN_FAIL("GetCommState() failed");
1388
1389         for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1390                 if (data->dcb.BaudRate == std_baudrates[i].index) {
1391                         config->baudrate = std_baudrates[i].value;
1392                         break;
1393                 }
1394         }
1395
1396         if (i == NUM_STD_BAUDRATES)
1397                 /* BaudRate field can be either an index or a custom baud rate. */
1398                 config->baudrate = data->dcb.BaudRate;
1399
1400         config->bits = data->dcb.ByteSize;
1401
1402         if (data->dcb.fParity)
1403                 switch (data->dcb.Parity) {
1404                 case NOPARITY:
1405                         config->parity = SP_PARITY_NONE;
1406                         break;
1407                 case ODDPARITY:
1408                         config->parity = SP_PARITY_ODD;
1409                         break;
1410                 case EVENPARITY:
1411                         config->parity = SP_PARITY_EVEN;
1412                         break;
1413                 case MARKPARITY:
1414                         config->parity = SP_PARITY_MARK;
1415                         break;
1416                 case SPACEPARITY:
1417                         config->parity = SP_PARITY_SPACE;
1418                         break;
1419                 default:
1420                         config->parity = -1;
1421                 }
1422         else
1423                 config->parity = SP_PARITY_NONE;
1424
1425         switch (data->dcb.StopBits) {
1426         case ONESTOPBIT:
1427                 config->stopbits = 1;
1428                 break;
1429         case TWOSTOPBITS:
1430                 config->stopbits = 2;
1431                 break;
1432         default:
1433                 config->stopbits = -1;
1434         }
1435
1436         switch (data->dcb.fRtsControl) {
1437         case RTS_CONTROL_DISABLE:
1438                 config->rts = SP_RTS_OFF;
1439                 break;
1440         case RTS_CONTROL_ENABLE:
1441                 config->rts = SP_RTS_ON;
1442                 break;
1443         case RTS_CONTROL_HANDSHAKE:
1444                 config->rts = SP_RTS_FLOW_CONTROL;
1445                 break;
1446         default:
1447                 config->rts = -1;
1448         }
1449
1450         config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
1451
1452         switch (data->dcb.fDtrControl) {
1453         case DTR_CONTROL_DISABLE:
1454                 config->dtr = SP_DTR_OFF;
1455                 break;
1456         case DTR_CONTROL_ENABLE:
1457                 config->dtr = SP_DTR_ON;
1458                 break;
1459         case DTR_CONTROL_HANDSHAKE:
1460                 config->dtr = SP_DTR_FLOW_CONTROL;
1461                 break;
1462         default:
1463                 config->dtr = -1;
1464         }
1465
1466         config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
1467
1468         if (data->dcb.fInX) {
1469                 if (data->dcb.fOutX)
1470                         config->xon_xoff = SP_XONXOFF_INOUT;
1471                 else
1472                         config->xon_xoff = SP_XONXOFF_IN;
1473         } else {
1474                 if (data->dcb.fOutX)
1475                         config->xon_xoff = SP_XONXOFF_OUT;
1476                 else
1477                         config->xon_xoff = SP_XONXOFF_DISABLED;
1478         }
1479
1480 #else // !_WIN32
1481
1482         if (tcgetattr(port->fd, &data->term) < 0)
1483                 RETURN_FAIL("tcgetattr() failed");
1484
1485         if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
1486                 RETURN_FAIL("TIOCMGET ioctl failed");
1487
1488 #ifdef USE_TERMIOX
1489         int ret = get_flow(port->fd, data);
1490
1491         if (ret == SP_ERR_FAIL && errno == EINVAL)
1492                 data->termiox_supported = 0;
1493         else if (ret < 0)
1494                 RETURN_CODEVAL(ret);
1495         else
1496                 data->termiox_supported = 1;
1497 #else
1498         data->termiox_supported = 0;
1499 #endif
1500
1501         for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1502                 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
1503                         config->baudrate = std_baudrates[i].value;
1504                         break;
1505                 }
1506         }
1507
1508         if (i == NUM_STD_BAUDRATES) {
1509 #ifdef __APPLE__
1510                 config->baudrate = (int)data->term.c_ispeed;
1511 #elif defined(USE_TERMIOS_SPEED)
1512                 TRY(get_baudrate(port->fd, &config->baudrate));
1513 #else
1514                 config->baudrate = -1;
1515 #endif
1516         }
1517
1518         switch (data->term.c_cflag & CSIZE) {
1519         case CS8:
1520                 config->bits = 8;
1521                 break;
1522         case CS7:
1523                 config->bits = 7;
1524                 break;
1525         case CS6:
1526                 config->bits = 6;
1527                 break;
1528         case CS5:
1529                 config->bits = 5;
1530                 break;
1531         default:
1532                 config->bits = -1;
1533         }
1534
1535         if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
1536                 config->parity = SP_PARITY_NONE;
1537         else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
1538                 config->parity = -1;
1539 #ifdef CMSPAR
1540         else if (data->term.c_cflag & CMSPAR)
1541                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE;
1542 #endif
1543         else
1544                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
1545
1546         config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
1547
1548         if (data->term.c_cflag & CRTSCTS) {
1549                 config->rts = SP_RTS_FLOW_CONTROL;
1550                 config->cts = SP_CTS_FLOW_CONTROL;
1551         } else {
1552                 if (data->termiox_supported && data->rts_flow)
1553                         config->rts = SP_RTS_FLOW_CONTROL;
1554                 else
1555                         config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
1556
1557                 config->cts = (data->termiox_supported && data->cts_flow) ?
1558                         SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
1559         }
1560
1561         if (data->termiox_supported && data->dtr_flow)
1562                 config->dtr = SP_DTR_FLOW_CONTROL;
1563         else
1564                 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
1565
1566         config->dsr = (data->termiox_supported && data->dsr_flow) ?
1567                 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
1568
1569         if (data->term.c_iflag & IXOFF) {
1570                 if (data->term.c_iflag & IXON)
1571                         config->xon_xoff = SP_XONXOFF_INOUT;
1572                 else
1573                         config->xon_xoff = SP_XONXOFF_IN;
1574         } else {
1575                 if (data->term.c_iflag & IXON)
1576                         config->xon_xoff = SP_XONXOFF_OUT;
1577                 else
1578                         config->xon_xoff = SP_XONXOFF_DISABLED;
1579         }
1580 #endif
1581
1582         RETURN_OK();
1583 }
1584
1585 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
1586         const struct sp_port_config *config)
1587 {
1588         unsigned int i;
1589 #ifdef __APPLE__
1590         BAUD_TYPE baud_nonstd;
1591
1592         baud_nonstd = B0;
1593 #endif
1594 #ifdef USE_TERMIOS_SPEED
1595         int baud_nonstd = 0;
1596 #endif
1597
1598         TRACE("%p, %p, %p", port, data, config);
1599
1600         DEBUG_FMT("Setting configuration for port %s", port->name);
1601
1602 #ifdef _WIN32
1603         if (config->baudrate >= 0) {
1604                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1605                         if (config->baudrate == std_baudrates[i].value) {
1606                                 data->dcb.BaudRate = std_baudrates[i].index;
1607                                 break;
1608                         }
1609                 }
1610
1611                 if (i == NUM_STD_BAUDRATES)
1612                         data->dcb.BaudRate = config->baudrate;
1613         }
1614
1615         if (config->bits >= 0)
1616                 data->dcb.ByteSize = config->bits;
1617
1618         if (config->parity >= 0) {
1619                 switch (config->parity) {
1620                 case SP_PARITY_NONE:
1621                         data->dcb.Parity = NOPARITY;
1622                         break;
1623                 case SP_PARITY_ODD:
1624                         data->dcb.Parity = ODDPARITY;
1625                         break;
1626                 case SP_PARITY_EVEN:
1627                         data->dcb.Parity = EVENPARITY;
1628                         break;
1629                 case SP_PARITY_MARK:
1630                         data->dcb.Parity = MARKPARITY;
1631                         break;
1632                 case SP_PARITY_SPACE:
1633                         data->dcb.Parity = SPACEPARITY;
1634                         break;
1635                 default:
1636                         RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
1637                 }
1638         }
1639
1640         if (config->stopbits >= 0) {
1641                 switch (config->stopbits) {
1642                 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
1643                 case 1:
1644                         data->dcb.StopBits = ONESTOPBIT;
1645                         break;
1646                 case 2:
1647                         data->dcb.StopBits = TWOSTOPBITS;
1648                         break;
1649                 default:
1650                         RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
1651                 }
1652         }
1653
1654         if (config->rts >= 0) {
1655                 switch (config->rts) {
1656                 case SP_RTS_OFF:
1657                         data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
1658                         break;
1659                 case SP_RTS_ON:
1660                         data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
1661                         break;
1662                 case SP_RTS_FLOW_CONTROL:
1663                         data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
1664                         break;
1665                 default:
1666                         RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
1667                 }
1668         }
1669
1670         if (config->cts >= 0) {
1671                 switch (config->cts) {
1672                 case SP_CTS_IGNORE:
1673                         data->dcb.fOutxCtsFlow = FALSE;
1674                         break;
1675                 case SP_CTS_FLOW_CONTROL:
1676                         data->dcb.fOutxCtsFlow = TRUE;
1677                         break;
1678                 default:
1679                         RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
1680                 }
1681         }
1682
1683         if (config->dtr >= 0) {
1684                 switch (config->dtr) {
1685                 case SP_DTR_OFF:
1686                         data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
1687                         break;
1688                 case SP_DTR_ON:
1689                         data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
1690                         break;
1691                 case SP_DTR_FLOW_CONTROL:
1692                         data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
1693                         break;
1694                 default:
1695                         RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
1696                 }
1697         }
1698
1699         if (config->dsr >= 0) {
1700                 switch (config->dsr) {
1701                 case SP_DSR_IGNORE:
1702                         data->dcb.fOutxDsrFlow = FALSE;
1703                         break;
1704                 case SP_DSR_FLOW_CONTROL:
1705                         data->dcb.fOutxDsrFlow = TRUE;
1706                         break;
1707                 default:
1708                         RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
1709                 }
1710         }
1711
1712         if (config->xon_xoff >= 0) {
1713                 switch (config->xon_xoff) {
1714                 case SP_XONXOFF_DISABLED:
1715                         data->dcb.fInX = FALSE;
1716                         data->dcb.fOutX = FALSE;
1717                         break;
1718                 case SP_XONXOFF_IN:
1719                         data->dcb.fInX = TRUE;
1720                         data->dcb.fOutX = FALSE;
1721                         break;
1722                 case SP_XONXOFF_OUT:
1723                         data->dcb.fInX = FALSE;
1724                         data->dcb.fOutX = TRUE;
1725                         break;
1726                 case SP_XONXOFF_INOUT:
1727                         data->dcb.fInX = TRUE;
1728                         data->dcb.fOutX = TRUE;
1729                         break;
1730                 default:
1731                         RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
1732                 }
1733         }
1734
1735         if (!SetCommState(port->hdl, &data->dcb))
1736                 RETURN_FAIL("SetCommState() failed");
1737
1738 #else /* !_WIN32 */
1739
1740         int controlbits;
1741
1742         if (config->baudrate >= 0) {
1743                 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1744                         if (config->baudrate == std_baudrates[i].value) {
1745                                 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
1746                                         RETURN_FAIL("cfsetospeed() failed");
1747
1748                                 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
1749                                         RETURN_FAIL("cfsetispeed() failed");
1750                                 break;
1751                         }
1752                 }
1753
1754                 /* Non-standard baud rate */
1755                 if (i == NUM_STD_BAUDRATES) {
1756 #ifdef __APPLE__
1757                         /* Set "dummy" baud rate. */
1758                         if (cfsetspeed(&data->term, B9600) < 0)
1759                                 RETURN_FAIL("cfsetspeed() failed");
1760                         baud_nonstd = config->baudrate;
1761 #elif defined(USE_TERMIOS_SPEED)
1762                         baud_nonstd = 1;
1763 #else
1764                         RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
1765 #endif
1766                 }
1767         }
1768
1769         if (config->bits >= 0) {
1770                 data->term.c_cflag &= ~CSIZE;
1771                 switch (config->bits) {
1772                 case 8:
1773                         data->term.c_cflag |= CS8;
1774                         break;
1775                 case 7:
1776                         data->term.c_cflag |= CS7;
1777                         break;
1778                 case 6:
1779                         data->term.c_cflag |= CS6;
1780                         break;
1781                 case 5:
1782                         data->term.c_cflag |= CS5;
1783                         break;
1784                 default:
1785                         RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
1786                 }
1787         }
1788
1789         if (config->parity >= 0) {
1790                 data->term.c_iflag &= ~IGNPAR;
1791                 data->term.c_cflag &= ~(PARENB | PARODD);
1792 #ifdef CMSPAR
1793                 data->term.c_cflag &= ~CMSPAR;
1794 #endif
1795                 switch (config->parity) {
1796                 case SP_PARITY_NONE:
1797                         data->term.c_iflag |= IGNPAR;
1798                         break;
1799                 case SP_PARITY_EVEN:
1800                         data->term.c_cflag |= PARENB;
1801                         break;
1802                 case SP_PARITY_ODD:
1803                         data->term.c_cflag |= PARENB | PARODD;
1804                         break;
1805 #ifdef CMSPAR
1806                 case SP_PARITY_MARK:
1807                         data->term.c_cflag |= PARENB | PARODD;
1808                         data->term.c_cflag |= CMSPAR;
1809                         break;
1810                 case SP_PARITY_SPACE:
1811                         data->term.c_cflag |= PARENB;
1812                         data->term.c_cflag |= CMSPAR;
1813                         break;
1814 #else
1815                 case SP_PARITY_MARK:
1816                 case SP_PARITY_SPACE:
1817                         RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported");
1818 #endif
1819                 default:
1820                         RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
1821                 }
1822         }
1823
1824         if (config->stopbits >= 0) {
1825                 data->term.c_cflag &= ~CSTOPB;
1826                 switch (config->stopbits) {
1827                 case 1:
1828                         data->term.c_cflag &= ~CSTOPB;
1829                         break;
1830                 case 2:
1831                         data->term.c_cflag |= CSTOPB;
1832                         break;
1833                 default:
1834                         RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
1835                 }
1836         }
1837
1838         if (config->rts >= 0 || config->cts >= 0) {
1839                 if (data->termiox_supported) {
1840                         data->rts_flow = data->cts_flow = 0;
1841                         switch (config->rts) {
1842                         case SP_RTS_OFF:
1843                         case SP_RTS_ON:
1844                                 controlbits = TIOCM_RTS;
1845                                 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
1846                                         RETURN_FAIL("Setting RTS signal level failed");
1847                                 break;
1848                         case SP_RTS_FLOW_CONTROL:
1849                                 data->rts_flow = 1;
1850                                 break;
1851                         default:
1852                                 break;
1853                         }
1854                         if (config->cts == SP_CTS_FLOW_CONTROL)
1855                                 data->cts_flow = 1;
1856
1857                         if (data->rts_flow && data->cts_flow)
1858                                 data->term.c_iflag |= CRTSCTS;
1859                         else
1860                                 data->term.c_iflag &= ~CRTSCTS;
1861                 } else {
1862                         /* Asymmetric use of RTS/CTS not supported. */
1863                         if (data->term.c_iflag & CRTSCTS) {
1864                                 /* Flow control can only be disabled for both RTS & CTS together. */
1865                                 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
1866                                         if (config->cts != SP_CTS_IGNORE)
1867                                                 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
1868                                 }
1869                                 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
1870                                         if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
1871                                                 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
1872                                 }
1873                         } else {
1874                                 /* Flow control can only be enabled for both RTS & CTS together. */
1875                                 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
1876                                         ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
1877                                         RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together");
1878                         }
1879
1880                         if (config->rts >= 0) {
1881                                 if (config->rts == SP_RTS_FLOW_CONTROL) {
1882                                         data->term.c_iflag |= CRTSCTS;
1883                                 } else {
1884                                         controlbits = TIOCM_RTS;
1885                                         if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
1886                                                         &controlbits) < 0)
1887                                                 RETURN_FAIL("Setting RTS signal level failed");
1888                                 }
1889                         }
1890                 }
1891         }
1892
1893         if (config->dtr >= 0 || config->dsr >= 0) {
1894                 if (data->termiox_supported) {
1895                         data->dtr_flow = data->dsr_flow = 0;
1896                         switch (config->dtr) {
1897                         case SP_DTR_OFF:
1898                         case SP_DTR_ON:
1899                                 controlbits = TIOCM_DTR;
1900                                 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
1901                                         RETURN_FAIL("Setting DTR signal level failed");
1902                                 break;
1903                         case SP_DTR_FLOW_CONTROL:
1904                                 data->dtr_flow = 1;
1905                                 break;
1906                         default:
1907                                 break;
1908                         }
1909                         if (config->dsr == SP_DSR_FLOW_CONTROL)
1910                                 data->dsr_flow = 1;
1911                 } else {
1912                         /* DTR/DSR flow control not supported. */
1913                         if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
1914                                 RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported");
1915
1916                         if (config->dtr >= 0) {
1917                                 controlbits = TIOCM_DTR;
1918                                 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
1919                                                 &controlbits) < 0)
1920                                         RETURN_FAIL("Setting DTR signal level failed");
1921                         }
1922                 }
1923         }
1924
1925         if (config->xon_xoff >= 0) {
1926                 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
1927                 switch (config->xon_xoff) {
1928                 case SP_XONXOFF_DISABLED:
1929                         break;
1930                 case SP_XONXOFF_IN:
1931                         data->term.c_iflag |= IXOFF;
1932                         break;
1933                 case SP_XONXOFF_OUT:
1934                         data->term.c_iflag |= IXON | IXANY;
1935                         break;
1936                 case SP_XONXOFF_INOUT:
1937                         data->term.c_iflag |= IXON | IXOFF | IXANY;
1938                         break;
1939                 default:
1940                         RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
1941                 }
1942         }
1943
1944         if (tcsetattr(port->fd, TCSANOW, &data->term) < 0)
1945                 RETURN_FAIL("tcsetattr() failed");
1946
1947 #ifdef __APPLE__
1948         if (baud_nonstd != B0) {
1949                 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
1950                         RETURN_FAIL("IOSSIOSPEED ioctl failed");
1951                 /* Set baud rates in data->term to correct, but incompatible
1952                  * with tcsetattr() value, same as delivered by tcgetattr(). */
1953                 if (cfsetspeed(&data->term, baud_nonstd) < 0)
1954                         RETURN_FAIL("cfsetspeed() failed");
1955         }
1956 #elif defined(__linux__)
1957 #ifdef USE_TERMIOS_SPEED
1958         if (baud_nonstd)
1959                 TRY(set_baudrate(port->fd, config->baudrate));
1960 #endif
1961 #ifdef USE_TERMIOX
1962         if (data->termiox_supported)
1963                 TRY(set_flow(port->fd, data));
1964 #endif
1965 #endif
1966
1967 #endif /* !_WIN32 */
1968
1969         RETURN_OK();
1970 }
1971
1972 SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr)
1973 {
1974         struct sp_port_config *config;
1975
1976         TRACE("%p", config_ptr);
1977
1978         if (!config_ptr)
1979                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1980
1981         *config_ptr = NULL;
1982
1983         if (!(config = malloc(sizeof(struct sp_port_config))))
1984                 RETURN_ERROR(SP_ERR_MEM, "config malloc failed");
1985
1986         config->baudrate = -1;
1987         config->bits = -1;
1988         config->parity = -1;
1989         config->stopbits = -1;
1990         config->rts = -1;
1991         config->cts = -1;
1992         config->dtr = -1;
1993         config->dsr = -1;
1994
1995         *config_ptr = config;
1996
1997         RETURN_OK();
1998 }
1999
2000 SP_API void sp_free_config(struct sp_port_config *config)
2001 {
2002         TRACE("%p", config);
2003
2004         if (!config)
2005                 DEBUG("Null config");
2006         else
2007                 free(config);
2008
2009         RETURN();
2010 }
2011
2012 SP_API enum sp_return sp_get_config(struct sp_port *port,
2013                                     struct sp_port_config *config)
2014 {
2015         struct port_data data;
2016
2017         TRACE("%p, %p", port, config);
2018
2019         CHECK_OPEN_PORT();
2020
2021         if (!config)
2022                 RETURN_ERROR(SP_ERR_ARG, "Null config");
2023
2024         TRY(get_config(port, &data, config));
2025
2026         RETURN_OK();
2027 }
2028
2029 SP_API enum sp_return sp_set_config(struct sp_port *port,
2030                                     const struct sp_port_config *config)
2031 {
2032         struct port_data data;
2033         struct sp_port_config prev_config;
2034
2035         TRACE("%p, %p", port, config);
2036
2037         CHECK_OPEN_PORT();
2038
2039         if (!config)
2040                 RETURN_ERROR(SP_ERR_ARG, "Null config");
2041
2042         TRY(get_config(port, &data, &prev_config));
2043         TRY(set_config(port, &data, config));
2044
2045         RETURN_OK();
2046 }
2047
2048 #define CREATE_ACCESSORS(x, type) \
2049 SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \
2050         struct port_data data; \
2051         struct sp_port_config config; \
2052         TRACE("%p, %d", port, x); \
2053         CHECK_OPEN_PORT(); \
2054         TRY(get_config(port, &data, &config)); \
2055         config.x = x; \
2056         TRY(set_config(port, &data, &config)); \
2057         RETURN_OK(); \
2058 } \
2059 SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \
2060                                         type *x) { \
2061         TRACE("%p, %p", config, x); \
2062         if (!config) \
2063                 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2064         *x = config->x; \
2065         RETURN_OK(); \
2066 } \
2067 SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \
2068                                         type x) { \
2069         TRACE("%p, %d", config, x); \
2070         if (!config) \
2071                 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2072         config->x = x; \
2073         RETURN_OK(); \
2074 }
2075
2076 CREATE_ACCESSORS(baudrate, int)
2077 CREATE_ACCESSORS(bits, int)
2078 CREATE_ACCESSORS(parity, enum sp_parity)
2079 CREATE_ACCESSORS(stopbits, int)
2080 CREATE_ACCESSORS(rts, enum sp_rts)
2081 CREATE_ACCESSORS(cts, enum sp_cts)
2082 CREATE_ACCESSORS(dtr, enum sp_dtr)
2083 CREATE_ACCESSORS(dsr, enum sp_dsr)
2084 CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff)
2085
2086 SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config,
2087                                                 enum sp_flowcontrol flowcontrol)
2088 {
2089         if (!config)
2090                 RETURN_ERROR(SP_ERR_ARG, "Null configuration");
2091
2092         if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
2093                 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
2094
2095         if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
2096                 config->xon_xoff = SP_XONXOFF_INOUT;
2097         else
2098                 config->xon_xoff = SP_XONXOFF_DISABLED;
2099
2100         if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
2101                 config->rts = SP_RTS_FLOW_CONTROL;
2102                 config->cts = SP_CTS_FLOW_CONTROL;
2103         } else {
2104                 if (config->rts == SP_RTS_FLOW_CONTROL)
2105                         config->rts = SP_RTS_ON;
2106                 config->cts = SP_CTS_IGNORE;
2107         }
2108
2109         if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
2110                 config->dtr = SP_DTR_FLOW_CONTROL;
2111                 config->dsr = SP_DSR_FLOW_CONTROL;
2112         } else {
2113                 if (config->dtr == SP_DTR_FLOW_CONTROL)
2114                         config->dtr = SP_DTR_ON;
2115                 config->dsr = SP_DSR_IGNORE;
2116         }
2117
2118         RETURN_OK();
2119 }
2120
2121 SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port,
2122                                          enum sp_flowcontrol flowcontrol)
2123 {
2124         struct port_data data;
2125         struct sp_port_config config;
2126
2127         TRACE("%p, %d", port, flowcontrol);
2128
2129         CHECK_OPEN_PORT();
2130
2131         TRY(get_config(port, &data, &config));
2132
2133         TRY(sp_set_config_flowcontrol(&config, flowcontrol));
2134
2135         TRY(set_config(port, &data, &config));
2136
2137         RETURN_OK();
2138 }
2139
2140 SP_API enum sp_return sp_get_signals(struct sp_port *port,
2141                                      enum sp_signal *signals)
2142 {
2143         TRACE("%p, %p", port, signals);
2144
2145         CHECK_OPEN_PORT();
2146
2147         if (!signals)
2148                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
2149
2150         DEBUG_FMT("Getting control signals for port %s", port->name);
2151
2152         *signals = 0;
2153 #ifdef _WIN32
2154         DWORD bits;
2155         if (GetCommModemStatus(port->hdl, &bits) == 0)
2156                 RETURN_FAIL("GetCommModemStatus() failed");
2157         if (bits & MS_CTS_ON)
2158                 *signals |= SP_SIG_CTS;
2159         if (bits & MS_DSR_ON)
2160                 *signals |= SP_SIG_DSR;
2161         if (bits & MS_RLSD_ON)
2162                 *signals |= SP_SIG_DCD;
2163         if (bits & MS_RING_ON)
2164                 *signals |= SP_SIG_RI;
2165 #else
2166         int bits;
2167         if (ioctl(port->fd, TIOCMGET, &bits) < 0)
2168                 RETURN_FAIL("TIOCMGET ioctl failed");
2169         if (bits & TIOCM_CTS)
2170                 *signals |= SP_SIG_CTS;
2171         if (bits & TIOCM_DSR)
2172                 *signals |= SP_SIG_DSR;
2173         if (bits & TIOCM_CAR)
2174                 *signals |= SP_SIG_DCD;
2175         if (bits & TIOCM_RNG)
2176                 *signals |= SP_SIG_RI;
2177 #endif
2178         RETURN_OK();
2179 }
2180
2181 SP_API enum sp_return sp_start_break(struct sp_port *port)
2182 {
2183         TRACE("%p", port);
2184
2185         CHECK_OPEN_PORT();
2186 #ifdef _WIN32
2187         if (SetCommBreak(port->hdl) == 0)
2188                 RETURN_FAIL("SetCommBreak() failed");
2189 #else
2190         if (ioctl(port->fd, TIOCSBRK, 1) < 0)
2191                 RETURN_FAIL("TIOCSBRK ioctl failed");
2192 #endif
2193
2194         RETURN_OK();
2195 }
2196
2197 SP_API enum sp_return sp_end_break(struct sp_port *port)
2198 {
2199         TRACE("%p", port);
2200
2201         CHECK_OPEN_PORT();
2202 #ifdef _WIN32
2203         if (ClearCommBreak(port->hdl) == 0)
2204                 RETURN_FAIL("ClearCommBreak() failed");
2205 #else
2206         if (ioctl(port->fd, TIOCCBRK, 1) < 0)
2207                 RETURN_FAIL("TIOCCBRK ioctl failed");
2208 #endif
2209
2210         RETURN_OK();
2211 }
2212
2213 SP_API int sp_last_error_code(void)
2214 {
2215         TRACE_VOID();
2216 #ifdef _WIN32
2217         RETURN_INT(GetLastError());
2218 #else
2219         RETURN_INT(errno);
2220 #endif
2221 }
2222
2223 SP_API char *sp_last_error_message(void)
2224 {
2225         TRACE_VOID();
2226
2227 #ifdef _WIN32
2228         LPVOID message;
2229         DWORD error = GetLastError();
2230
2231         FormatMessage(
2232                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
2233                 FORMAT_MESSAGE_FROM_SYSTEM |
2234                 FORMAT_MESSAGE_IGNORE_INSERTS,
2235                 NULL,
2236                 error,
2237                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2238                 (LPTSTR) &message,
2239                 0, NULL );
2240
2241         RETURN_STRING(message);
2242 #else
2243         RETURN_STRING(strerror(errno));
2244 #endif
2245 }
2246
2247 SP_API void sp_free_error_message(char *message)
2248 {
2249         TRACE("%s", message);
2250
2251 #ifdef _WIN32
2252         LocalFree(message);
2253 #else
2254         (void)message;
2255 #endif
2256
2257         RETURN();
2258 }
2259
2260 SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...))
2261 {
2262         TRACE("%p", handler);
2263
2264         sp_debug_handler = handler;
2265
2266         RETURN();
2267 }
2268
2269 SP_API void sp_default_debug_handler(const char *format, ...)
2270 {
2271         va_list args;
2272         va_start(args, format);
2273         if (getenv("LIBSERIALPORT_DEBUG")) {
2274                 fputs("sp: ", stderr);
2275                 vfprintf(stderr, format, args);
2276         }
2277         va_end(args);
2278 }
2279
2280 SP_API int sp_get_major_package_version(void)
2281 {
2282         return SP_PACKAGE_VERSION_MAJOR;
2283 }
2284
2285 SP_API int sp_get_minor_package_version(void)
2286 {
2287         return SP_PACKAGE_VERSION_MINOR;
2288 }
2289
2290 SP_API int sp_get_micro_package_version(void)
2291 {
2292         return SP_PACKAGE_VERSION_MICRO;
2293 }
2294
2295 SP_API const char *sp_get_package_version_string(void)
2296 {
2297         return SP_PACKAGE_VERSION_STRING;
2298 }
2299
2300 SP_API int sp_get_current_lib_version(void)
2301 {
2302         return SP_LIB_VERSION_CURRENT;
2303 }
2304
2305 SP_API int sp_get_revision_lib_version(void)
2306 {
2307         return SP_LIB_VERSION_REVISION;
2308 }
2309
2310 SP_API int sp_get_age_lib_version(void)
2311 {
2312         return SP_LIB_VERSION_AGE;
2313 }
2314
2315 SP_API const char *sp_get_lib_version_string(void)
2316 {
2317         return SP_LIB_VERSION_STRING;
2318 }
2319
2320 /** @} */