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