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