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