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