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