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