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