]> sigrok.org Git - libserialport.git/blame - serialport.c
Make port structure opaque.
[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
74510d4b
ML
37#include <termios.h>
38#include <sys/ioctl.h>
39#endif
3b63f34d 40#ifdef __APPLE__
1ebf4347
ML
41#include <IOKit/IOKitLib.h>
42#include <IOKit/serial/IOSerialKeys.h>
31b3a8f5 43#include <IOKit/serial/ioss.h>
1ebf4347 44#include <sys/syslimits.h>
3b63f34d
ML
45#endif
46#ifdef __linux__
47#include "libudev.h"
4b97c9fc 48#include "linux/serial.h"
7a6d2196 49#include "linux_termios.h"
40978c2b 50#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
68ec29db 51#define USE_TERMIOX
40978c2b 52#endif
3b63f34d 53#endif
74510d4b 54
71c8a9b9
UH
55#ifndef _WIN32
56#include "linux_termios.h"
57#endif
58
f6a1fb65 59#include "libserialport.h"
74510d4b 60
1c5aae9d
ML
61struct sp_port {
62 char *name;
63#ifdef _WIN32
64 HANDLE hdl;
65#else
66 int fd;
67#endif
68};
69
8f189c4c 70struct port_data {
8094e4a0
ML
71#ifdef _WIN32
72 DCB dcb;
73#else
74 struct termios term;
824dcb45 75 int controlbits;
68ec29db 76 int termiox_supported;
40978c2b
ML
77 int flow;
78#endif
8094e4a0
ML
79};
80
da2748bf
ML
81/* Standard baud rates. */
82#ifdef _WIN32
83#define BAUD_TYPE DWORD
84#define BAUD(n) {CBR_##n, n}
85#else
86#define BAUD_TYPE speed_t
87#define BAUD(n) {B##n, n}
88#endif
89
90struct std_baudrate {
91 BAUD_TYPE index;
92 int value;
93};
94
95const struct std_baudrate std_baudrates[] = {
96#ifdef _WIN32
97 /*
98 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
99 * have documented CBR_* macros.
100 */
101 BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
102 BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
eac329d2 103 BAUD(115200), BAUD(128000), BAUD(256000),
da2748bf 104#else
eac329d2
UH
105 BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
106 BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
107 BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
108 BAUD(230400),
da2748bf 109#if !defined(__APPLE__) && !defined(__OpenBSD__)
eac329d2 110 BAUD(460800),
da2748bf
ML
111#endif
112#endif
113};
114
863b35e6
ML
115void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
116
da2748bf
ML
117#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
118#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
119
92f756f8
ML
120/* Debug output macros. */
121#define DEBUG(fmt, ...) do { if (sp_debug_handler) sp_debug_handler(fmt ".\n", ##__VA_ARGS__); } while (0)
122#define DEBUG_ERROR(err, msg) DEBUG("%s returning " #err ": " msg, __func__)
123#define DEBUG_FAIL(msg) do { \
124 char *errmsg = sp_last_error_message(); \
125 DEBUG("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \
126 sp_free_error_message(errmsg); \
127} while (0);
128#define RETURN() do { DEBUG("%s returning", __func__); return; } while(0)
129#define RETURN_CODE(x) do { DEBUG("%s returning " #x, __func__); return x; } while (0)
130#define RETURN_CODEVAL(x) do { \
131 switch (x) { \
132 case SP_OK: RETURN_CODE(SP_OK); \
133 case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \
134 case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \
135 case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \
136 case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \
137 } \
138} while (0)
139#define RETURN_OK() RETURN_CODE(SP_OK);
140#define RETURN_ERROR(err, msg) do { DEBUG_ERROR(err, msg); return err; } while (0)
141#define RETURN_FAIL(msg) do { DEBUG_FAIL(msg); return SP_ERR_FAIL; } while (0)
142#define RETURN_VALUE(fmt, x) do { DEBUG("%s returning " fmt, __func__, x); return x; } while (0)
143#define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0)
144#define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = err; } while (0)
145#define TRACE(fmt, ...) DEBUG("%s(" fmt ") called", __func__, ##__VA_ARGS__)
146
64690702
ML
147#define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
148
348e23cc 149/* Helper functions. */
348e23cc 150static struct sp_port **list_append(struct sp_port **list, const char *portname);
eb6ed20f
ML
151static enum sp_return get_config(struct sp_port *port, struct port_data *data,
152 struct sp_port_config *config);
153static enum sp_return set_config(struct sp_port *port, struct port_data *data,
154 const struct sp_port_config *config);
80186526 155
eb6ed20f 156enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
d54e9004
ML
157{
158 struct sp_port *port;
5919c913 159 int len;
d54e9004 160
c33efc48
ML
161 TRACE("%s, %p", portname, port_ptr);
162
32b5ac05 163 if (!port_ptr)
c33efc48 164 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
32b5ac05 165
77f262c4
ML
166 *port_ptr = NULL;
167
d4babed2 168 if (!portname)
c33efc48 169 RETURN_ERROR(SP_ERR_ARG, "Null port name");
d4babed2 170
ea667be7
ML
171 DEBUG("Building structure for port %s", portname);
172
d54e9004 173 if (!(port = malloc(sizeof(struct sp_port))))
c33efc48 174 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
d54e9004 175
5919c913
ML
176 len = strlen(portname) + 1;
177
eac329d2 178 if (!(port->name = malloc(len))) {
d54e9004 179 free(port);
c33efc48 180 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
d54e9004
ML
181 }
182
183 memcpy(port->name, portname, len);
184
8f471c66
ML
185#ifdef _WIN32
186 port->hdl = INVALID_HANDLE_VALUE;
187#else
188 port->fd = -1;
189#endif
190
77f262c4
ML
191 *port_ptr = port;
192
c33efc48 193 RETURN_OK();
d54e9004
ML
194}
195
1c5aae9d
ML
196char *sp_get_port_name(const struct sp_port *port)
197{
198 TRACE("%p", port);
199
200 if (!port)
201 return NULL;
202
203 RETURN_VALUE("%s", port->name);
204}
205
eb6ed20f 206enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
32b5ac05 207{
c33efc48
ML
208 TRACE("%p, %p", port, copy_ptr);
209
32b5ac05 210 if (!copy_ptr)
c33efc48 211 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
32b5ac05
ML
212
213 *copy_ptr = NULL;
214
c33efc48
ML
215 if (!port)
216 RETURN_ERROR(SP_ERR_ARG, "Null port");
217
218 if (!port->name)
219 RETURN_ERROR(SP_ERR_ARG, "Null port name");
32b5ac05 220
ea667be7
ML
221 DEBUG("Copying port structure");
222
c33efc48 223 RETURN_VALUE("%p", sp_get_port_by_name(port->name, copy_ptr));
32b5ac05
ML
224}
225
e3b2f7a4
ML
226void sp_free_port(struct sp_port *port)
227{
c33efc48
ML
228 TRACE("%p", port);
229
e3b2f7a4 230 if (!port)
c33efc48
ML
231 {
232 DEBUG("Null port");
233 RETURN();
234 }
e3b2f7a4 235
ea667be7
ML
236 DEBUG("Freeing port structure");
237
e3b2f7a4
ML
238 if (port->name)
239 free(port->name);
240
241 free(port);
c33efc48
ML
242
243 RETURN();
e3b2f7a4
ML
244}
245
348e23cc 246static struct sp_port **list_append(struct sp_port **list, const char *portname)
3b63f34d
ML
247{
248 void *tmp;
249 unsigned int count;
f92f1f0c 250
3b63f34d 251 for (count = 0; list[count]; count++);
d54e9004 252 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
3b63f34d
ML
253 goto fail;
254 list = tmp;
77f262c4 255 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
3b63f34d 256 goto fail;
db2794ce 257 list[count + 1] = NULL;
3b63f34d 258 return list;
f92f1f0c 259
3b63f34d
ML
260fail:
261 sp_free_port_list(list);
262 return NULL;
263}
264
eb6ed20f 265enum sp_return sp_list_ports(struct sp_port ***list_ptr)
3b63f34d 266{
d54e9004 267 struct sp_port **list;
6b93ede4 268 int ret = SP_ERR_SUPP;
24c1a4bb 269
c33efc48
ML
270 TRACE("%p", list_ptr);
271
dec10e31
ML
272 if (!list_ptr)
273 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
274
ea667be7
ML
275 DEBUG("Enumerating ports");
276
d54e9004 277 if (!(list = malloc(sizeof(struct sp_port **))))
c33efc48 278 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
24c1a4bb
ML
279
280 list[0] = NULL;
3b63f34d
ML
281
282#ifdef _WIN32
283 HKEY key;
bdfb5b8c
ML
284 TCHAR *value, *data;
285 DWORD max_value_len, max_data_size, max_data_len;
286 DWORD value_len, data_size, data_len;
3b63f34d 287 DWORD type, index = 0;
8b532d9c
ML
288 char *name;
289 int name_len;
3b63f34d 290
6b93ede4
ML
291 ret = SP_OK;
292
ea667be7 293 DEBUG("Opening registry key");
3b63f34d 294 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
eac329d2 295 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
c33efc48 296 SET_FAIL(ret, "RegOpenKeyEx() failed");
77f262c4
ML
297 goto out_done;
298 }
ea667be7 299 DEBUG("Querying registry key value and data sizes");
3b63f34d 300 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
eac329d2 301 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
c33efc48 302 SET_FAIL(ret, "RegQueryInfoKey() failed");
3b63f34d 303 goto out_close;
77f262c4 304 }
3b63f34d 305 max_data_len = max_data_size / sizeof(TCHAR);
eac329d2 306 if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
c33efc48 307 SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
3b63f34d 308 goto out_close;
77f262c4 309 }
eac329d2 310 if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
c33efc48 311 SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
bdfb5b8c 312 goto out_free_value;
77f262c4 313 }
ea667be7 314 DEBUG("Iterating over values");
3b63f34d 315 while (
d9573bad 316 value_len = max_value_len + 1,
3b63f34d 317 data_size = max_data_size,
bdfb5b8c 318 RegEnumValue(key, index, value, &value_len,
3b63f34d
ML
319 NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
320 {
321 data_len = data_size / sizeof(TCHAR);
322 data[data_len] = '\0';
8b532d9c
ML
323#ifdef UNICODE
324 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL)
325#else
326 name_len = data_len + 1;
327#endif
eac329d2 328 if (!(name = malloc(name_len))) {
c33efc48 329 SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
8b532d9c 330 goto out;
77f262c4 331 }
8b532d9c
ML
332#ifdef UNICODE
333 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
334#else
335 strcpy(name, data);
336#endif
c33efc48
ML
337 if (type == REG_SZ) {
338 DEBUG("Found port %s", name);
339 if (!(list = list_append(list, name))) {
340 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
341 goto out;
342 }
77f262c4 343 }
3b63f34d
ML
344 index++;
345 }
346out:
347 free(data);
bdfb5b8c
ML
348out_free_value:
349 free(value);
3b63f34d
ML
350out_close:
351 RegCloseKey(key);
77f262c4 352out_done:
3b63f34d
ML
353#endif
354#ifdef __APPLE__
355 mach_port_t master;
356 CFMutableDictionaryRef classes;
357 io_iterator_t iter;
358 char *path;
359 io_object_t port;
360 CFTypeRef cf_path;
361 Boolean result;
362
6b93ede4
ML
363 ret = SP_OK;
364
ea667be7 365 DEBUG("Getting IOKit master port");
eac329d2 366 if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS) {
c33efc48 367 SET_FAIL(ret, "IOMasterPort() failed");
77f262c4
ML
368 goto out_done;
369 }
3b63f34d 370
ea667be7 371 DEBUG("Creating matching dictionary");
eac329d2 372 if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
c33efc48 373 SET_FAIL(ret, "IOServiceMatching() failed");
77f262c4
ML
374 goto out_done;
375 }
3b63f34d
ML
376
377 CFDictionarySetValue(classes,
378 CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
379
ea667be7 380 DEBUG("Getting matching services");
eac329d2 381 if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS) {
c33efc48 382 SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
77f262c4
ML
383 goto out_done;
384 }
3b63f34d 385
eac329d2 386 if (!(path = malloc(PATH_MAX))) {
c33efc48 387 SET_ERROR(ret, SP_ERR_MEM, "device path malloc failed");
3b63f34d 388 goto out_release;
77f262c4 389 }
3b63f34d 390
ea667be7 391 DEBUG("Iterating over results");
1ebf4347 392 while ((port = IOIteratorNext(iter))) {
3b63f34d
ML
393 cf_path = IORegistryEntryCreateCFProperty(port,
394 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
395 if (cf_path) {
396 result = CFStringGetCString(cf_path,
397 path, PATH_MAX, kCFStringEncodingASCII);
398 CFRelease(cf_path);
c33efc48
ML
399 if (result) {
400 DEBUG("Found port %s", path);
401 if (!(list = list_append(list, path))) {
402 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
403 IOObjectRelease(port);
404 goto out;
405 }
77f262c4 406 }
3b63f34d
ML
407 }
408 IOObjectRelease(port);
409 }
3b63f34d
ML
410out:
411 free(path);
412out_release:
413 IOObjectRelease(iter);
77f262c4 414out_done:
3b63f34d
ML
415#endif
416#ifdef __linux__
417 struct udev *ud;
418 struct udev_enumerate *ud_enumerate;
419 struct udev_list_entry *ud_list;
420 struct udev_list_entry *ud_entry;
421 const char *path;
08fe0bdb 422 struct udev_device *ud_dev, *ud_parent;
3b63f34d 423 const char *name;
4b97c9fc
ML
424 const char *driver;
425 int fd, ioctl_result;
426 struct serial_struct serial_info;
3b63f34d 427
6b93ede4
ML
428 ret = SP_OK;
429
ea667be7 430 DEBUG("Enumerating tty devices");
3b63f34d
ML
431 ud = udev_new();
432 ud_enumerate = udev_enumerate_new(ud);
433 udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
434 udev_enumerate_scan_devices(ud_enumerate);
435 ud_list = udev_enumerate_get_list_entry(ud_enumerate);
ea667be7 436 DEBUG("Iterating over results");
eac329d2 437 udev_list_entry_foreach(ud_entry, ud_list) {
3b63f34d 438 path = udev_list_entry_get_name(ud_entry);
ea667be7 439 DEBUG("Found device %s", path);
3b63f34d 440 ud_dev = udev_device_new_from_syspath(ud, path);
08fe0bdb
ML
441 /* If there is no parent device, this is a virtual tty. */
442 ud_parent = udev_device_get_parent(ud_dev);
eac329d2 443 if (ud_parent == NULL) {
ea667be7 444 DEBUG("No parent device, assuming virtual tty");
08fe0bdb
ML
445 udev_device_unref(ud_dev);
446 continue;
447 }
3b63f34d 448 name = udev_device_get_devnode(ud_dev);
4b97c9fc
ML
449 /* The serial8250 driver has a hardcoded number of ports.
450 * The only way to tell which actually exist on a given system
451 * is to try to open them and make an ioctl call. */
452 driver = udev_device_get_driver(ud_parent);
eac329d2 453 if (driver && !strcmp(driver, "serial8250")) {
ea667be7
ML
454 DEBUG("serial8250 device, attempting to open");
455 if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
456 DEBUG("open failed, skipping");
4b97c9fc 457 goto skip;
ea667be7 458 }
4b97c9fc
ML
459 ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
460 close(fd);
ea667be7
ML
461 if (ioctl_result != 0) {
462 DEBUG("ioctl failed, skipping");
4b97c9fc 463 goto skip;
ea667be7
ML
464 }
465 if (serial_info.type == PORT_UNKNOWN) {
466 DEBUG("port type is unknown, skipping");
4b97c9fc 467 goto skip;
ea667be7 468 }
4b97c9fc 469 }
c33efc48 470 DEBUG("Found port %s", name);
348e23cc 471 list = list_append(list, name);
4b97c9fc 472skip:
3b63f34d 473 udev_device_unref(ud_dev);
eac329d2 474 if (!list) {
c33efc48 475 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
3b63f34d 476 goto out;
77f262c4 477 }
3b63f34d
ML
478 }
479out:
480 udev_enumerate_unref(ud_enumerate);
481 udev_unref(ud);
3b63f34d 482#endif
77f262c4 483
6b93ede4
ML
484 switch (ret) {
485 case SP_OK:
77f262c4 486 *list_ptr = list;
c33efc48 487 RETURN_OK();
6b93ede4
ML
488 case SP_ERR_SUPP:
489 DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform.");
490 default:
77f262c4
ML
491 if (list)
492 sp_free_port_list(list);
77f262c4 493 *list_ptr = NULL;
c33efc48 494 return ret;
77f262c4 495 }
3b63f34d
ML
496}
497
d54e9004 498void sp_free_port_list(struct sp_port **list)
3b63f34d
ML
499{
500 unsigned int i;
f92f1f0c 501
c33efc48
ML
502 TRACE("%p", list);
503
dec10e31
ML
504 if (!list) {
505 DEBUG("Null list");
506 RETURN();
507 }
508
ea667be7
ML
509 DEBUG("Freeing port list");
510
3b63f34d 511 for (i = 0; list[i]; i++)
e3b2f7a4 512 sp_free_port(list[i]);
3b63f34d 513 free(list);
c33efc48
ML
514
515 RETURN();
3b63f34d
ML
516}
517
c33efc48
ML
518#define CHECK_PORT() do { \
519 if (port == NULL) \
520 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
dec10e31
ML
521 if (port->name == NULL) \
522 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
523} while (0)
524#ifdef _WIN32
525#define CHECK_PORT_HANDLE() do { \
c33efc48
ML
526 if (port->hdl == INVALID_HANDLE_VALUE) \
527 RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \
dec10e31 528} while (0)
74510d4b 529#else
dec10e31 530#define CHECK_PORT_HANDLE() do { \
c33efc48
ML
531 if (port->fd < 0) \
532 RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \
dec10e31 533} while (0)
74510d4b 534#endif
dec10e31
ML
535#define CHECK_OPEN_PORT() do { \
536 CHECK_PORT(); \
537 CHECK_PORT_HANDLE(); \
538} while (0)
74510d4b 539
eb6ed20f 540enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
74510d4b 541{
c33efc48
ML
542 TRACE("%p, %x", port, flags);
543
dec10e31
ML
544 CHECK_PORT();
545
546 if (flags > (SP_MODE_READ | SP_MODE_WRITE | SP_MODE_NONBLOCK))
547 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
74510d4b 548
ea667be7
ML
549 DEBUG("Opening port %s", port->name);
550
74510d4b
ML
551#ifdef _WIN32
552 DWORD desired_access = 0, flags_and_attributes = 0;
99945a1f
ML
553 char *escaped_port_name;
554
555 /* Prefix port name with '\\.\' to work with ports above COM9. */
556 if (!(escaped_port_name = malloc(strlen(port->name + 5))))
c33efc48 557 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
99945a1f
ML
558 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
559
74510d4b 560 /* Map 'flags' to the OS-specific settings. */
74510d4b 561 flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
a036341b
ML
562 if (flags & SP_MODE_READ)
563 desired_access |= GENERIC_READ;
564 if (flags & SP_MODE_WRITE)
74510d4b
ML
565 desired_access |= GENERIC_WRITE;
566 if (flags & SP_MODE_NONBLOCK)
567 flags_and_attributes |= FILE_FLAG_OVERLAPPED;
568
99945a1f 569 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
74510d4b 570 OPEN_EXISTING, flags_and_attributes, 0);
99945a1f
ML
571
572 free(escaped_port_name);
573
74510d4b 574 if (port->hdl == INVALID_HANDLE_VALUE)
c33efc48 575 RETURN_FAIL("CreateFile() failed");
74510d4b
ML
576#else
577 int flags_local = 0;
8f189c4c 578 struct port_data data;
e33ab9aa
ML
579 struct sp_port_config config;
580 int ret;
f92f1f0c 581
74510d4b 582 /* Map 'flags' to the OS-specific settings. */
a036341b 583 if (flags & (SP_MODE_READ | SP_MODE_WRITE))
74510d4b 584 flags_local |= O_RDWR;
a036341b 585 else if (flags & SP_MODE_READ)
74510d4b 586 flags_local |= O_RDONLY;
a036341b
ML
587 else if (flags & SP_MODE_WRITE)
588 flags_local |= O_WRONLY;
74510d4b
ML
589 if (flags & SP_MODE_NONBLOCK)
590 flags_local |= O_NONBLOCK;
591
592 if ((port->fd = open(port->name, flags_local)) < 0)
c33efc48 593 RETURN_FAIL("open() failed");
9cb98459 594
e33ab9aa
ML
595 ret = get_config(port, &data, &config);
596
eac329d2 597 if (ret < 0) {
e33ab9aa 598 sp_close(port);
c33efc48 599 RETURN_CODEVAL(ret);
e33ab9aa 600 }
9cb98459
ML
601
602 /* Turn off all serial port cooking. */
603 data.term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
604 data.term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
605#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
606 data.term.c_oflag &= ~OFILL;
607#endif
608 /* Disable canonical mode, and don't echo input characters. */
609 data.term.c_lflag &= ~(ICANON | ECHO);
610
611 /* Ignore modem status lines; enable receiver */
612 data.term.c_cflag |= (CLOCAL | CREAD);
613
e33ab9aa
ML
614 ret = set_config(port, &data, &config);
615
eac329d2 616 if (ret < 0) {
e33ab9aa 617 sp_close(port);
c33efc48 618 RETURN_CODEVAL(ret);
e33ab9aa 619 }
74510d4b
ML
620#endif
621
c33efc48 622 RETURN_OK();
74510d4b
ML
623}
624
eb6ed20f 625enum sp_return sp_close(struct sp_port *port)
74510d4b 626{
c33efc48
ML
627 TRACE("%p", port);
628
dec10e31 629 CHECK_OPEN_PORT();
74510d4b 630
ea667be7
ML
631 DEBUG("Closing port %s", port->name);
632
74510d4b
ML
633#ifdef _WIN32
634 /* Returns non-zero upon success, 0 upon failure. */
635 if (CloseHandle(port->hdl) == 0)
c33efc48 636 RETURN_FAIL("CloseHandle() failed");
8f471c66 637 port->hdl = INVALID_HANDLE_VALUE;
74510d4b
ML
638#else
639 /* Returns 0 upon success, -1 upon failure. */
640 if (close(port->fd) == -1)
c33efc48 641 RETURN_FAIL("close() failed");
8f471c66 642 port->fd = -1;
74510d4b
ML
643#endif
644
c33efc48 645 RETURN_OK();
74510d4b
ML
646}
647
fd8fd11a 648enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
74510d4b 649{
c33efc48
ML
650 TRACE("%p, %x", port, buffers);
651
dec10e31
ML
652 CHECK_OPEN_PORT();
653
654 if (buffers > SP_BUF_BOTH)
655 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
74510d4b 656
ea667be7
ML
657 const char *buffer_names[] = {"input", "output", "both"};
658
659 DEBUG("Flushing %s buffers on port %s", buffer_names[buffers], port->name);
660
74510d4b 661#ifdef _WIN32
fd8fd11a
ML
662 DWORD flags = 0;
663 if (buffers & SP_BUF_INPUT)
664 flags |= PURGE_RXCLEAR;
665 if (buffers & SP_BUF_OUTPUT)
666 flags |= PURGE_TXCLEAR;
667
74510d4b 668 /* Returns non-zero upon success, 0 upon failure. */
fd8fd11a 669 if (PurgeComm(port->hdl, flags) == 0)
c33efc48 670 RETURN_FAIL("PurgeComm() failed");
74510d4b 671#else
fd8fd11a
ML
672 int flags = 0;
673 if (buffers & SP_BUF_BOTH)
674 flags = TCIOFLUSH;
675 else if (buffers & SP_BUF_INPUT)
676 flags = TCIFLUSH;
82f424e6 677 else if (buffers & SP_BUF_OUTPUT)
fd8fd11a
ML
678 flags = TCOFLUSH;
679
74510d4b 680 /* Returns 0 upon success, -1 upon failure. */
fd8fd11a 681 if (tcflush(port->fd, flags) < 0)
c33efc48 682 RETURN_FAIL("tcflush() failed");
74510d4b 683#endif
c33efc48 684 RETURN_OK();
74510d4b
ML
685}
686
69a3739c
ML
687enum sp_return sp_drain(struct sp_port *port)
688{
c33efc48
ML
689 TRACE("%p", port);
690
dec10e31 691 CHECK_OPEN_PORT();
69a3739c 692
ea667be7
ML
693 DEBUG("Draining port %s", port->name);
694
69a3739c
ML
695#ifdef _WIN32
696 /* Returns non-zero upon success, 0 upon failure. */
697 if (FlushFileBuffers(port->hdl) == 0)
c33efc48 698 RETURN_FAIL("FlushFileBuffers() failed");
69a3739c
ML
699#else
700 /* Returns 0 upon success, -1 upon failure. */
701 if (tcdrain(port->fd) < 0)
c33efc48 702 RETURN_FAIL("tcdrain() failed");
69a3739c
ML
703#endif
704
c33efc48 705 RETURN_OK();
69a3739c
ML
706}
707
eb6ed20f 708enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count)
74510d4b 709{
c33efc48
ML
710 TRACE("%p, %p, %d", port, buf, count);
711
dec10e31 712 CHECK_OPEN_PORT();
74510d4b
ML
713
714 if (!buf)
c33efc48 715 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
74510d4b 716
ea667be7
ML
717 DEBUG("Writing up to %d bytes to port %s", count, port->name);
718
74510d4b
ML
719#ifdef _WIN32
720 DWORD written = 0;
f92f1f0c 721
74510d4b
ML
722 /* Returns non-zero upon success, 0 upon failure. */
723 if (WriteFile(port->hdl, buf, count, &written, NULL) == 0)
c33efc48
ML
724 RETURN_FAIL("WriteFile() failed");
725 RETURN_VALUE("%d", written);
74510d4b
ML
726#else
727 /* Returns the number of bytes written, or -1 upon failure. */
728 ssize_t written = write(port->fd, buf, count);
f92f1f0c 729
74510d4b 730 if (written < 0)
c33efc48 731 RETURN_FAIL("write() failed");
74510d4b 732 else
c33efc48 733 RETURN_VALUE("%d", written);
74510d4b
ML
734#endif
735}
736
eb6ed20f 737enum sp_return sp_read(struct sp_port *port, void *buf, size_t count)
74510d4b 738{
c33efc48
ML
739 TRACE("%p, %p, %d", port, buf, count);
740
dec10e31 741 CHECK_OPEN_PORT();
74510d4b
ML
742
743 if (!buf)
c33efc48 744 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
74510d4b 745
ea667be7
ML
746 DEBUG("Reading up to %d bytes from port %s", count, port->name);
747
74510d4b
ML
748#ifdef _WIN32
749 DWORD bytes_read = 0;
f92f1f0c 750
74510d4b
ML
751 /* Returns non-zero upon success, 0 upon failure. */
752 if (ReadFile(port->hdl, buf, count, &bytes_read, NULL) == 0)
c33efc48
ML
753 RETURN_FAIL("ReadFile() failed");
754 RETURN_VALUE("%d", bytes_read);
74510d4b
ML
755#else
756 ssize_t bytes_read;
f92f1f0c 757
74510d4b
ML
758 /* Returns the number of bytes read, or -1 upon failure. */
759 if ((bytes_read = read(port->fd, buf, count)) < 0)
c33efc48
ML
760 RETURN_FAIL("read() failed");
761 RETURN_VALUE("%d", bytes_read);
74510d4b
ML
762#endif
763}
764
7a6d2196
ML
765#ifdef __linux__
766static enum sp_return get_baudrate(int fd, int *baudrate)
767{
768 void *data;
769
c33efc48
ML
770 TRACE("%d, %p", fd, baudrate);
771
ea667be7
ML
772 DEBUG("Getting baud rate");
773
7a6d2196 774 if (!(data = malloc(get_termios_size())))
c33efc48 775 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
7a6d2196 776
8d43110a
ML
777 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
778 free(data);
c33efc48 779 RETURN_FAIL("getting termios failed");
8d43110a 780 }
7a6d2196
ML
781
782 *baudrate = get_termios_speed(data);
783
8d43110a
ML
784 free(data);
785
c33efc48 786 RETURN_OK();
7a6d2196
ML
787}
788
789static enum sp_return set_baudrate(int fd, int baudrate)
790{
791 void *data;
792
c33efc48
ML
793 TRACE("%d, %d", fd, baudrate);
794
ea667be7
ML
795 DEBUG("Getting baud rate");
796
7a6d2196 797 if (!(data = malloc(get_termios_size())))
c33efc48 798 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
7a6d2196 799
8d43110a
ML
800 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
801 free(data);
c33efc48 802 RETURN_FAIL("getting termios failed");
8d43110a 803 }
7a6d2196 804
ea667be7
ML
805 DEBUG("Setting baud rate");
806
7a6d2196
ML
807 set_termios_speed(data, baudrate);
808
8d43110a
ML
809 if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
810 free(data);
c33efc48 811 RETURN_FAIL("setting termios failed");
8d43110a
ML
812 }
813
814 free(data);
7a6d2196 815
c33efc48 816 RETURN_OK();
7a6d2196 817}
40978c2b
ML
818
819#ifdef USE_TERMIOX
820static enum sp_return get_flow(int fd, int *flow)
821{
822 void *data;
823
c33efc48
ML
824 TRACE("%d, %p", fd, flow);
825
ea667be7
ML
826 DEBUG("Getting advanced flow control");
827
40978c2b 828 if (!(data = malloc(get_termiox_size())))
c33efc48 829 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
40978c2b 830
8d43110a
ML
831 if (ioctl(fd, TCGETX, data) < 0) {
832 free(data);
c33efc48 833 RETURN_FAIL("getting termiox failed");
8d43110a 834 }
40978c2b
ML
835
836 *flow = get_termiox_flow(data);
837
8d43110a
ML
838 free(data);
839
c33efc48 840 RETURN_OK();
40978c2b
ML
841}
842
843static enum sp_return set_flow(int fd, int flow)
844{
845 void *data;
846
c33efc48
ML
847 TRACE("%d, %d", fd, flow);
848
ea667be7
ML
849 DEBUG("Getting advanced flow control");
850
40978c2b 851 if (!(data = malloc(get_termiox_size())))
c33efc48 852 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
40978c2b 853
8d43110a
ML
854 if (ioctl(fd, TCGETX, data) < 0) {
855 free(data);
c33efc48 856 RETURN_FAIL("getting termiox failed");
8d43110a 857 }
40978c2b 858
ea667be7
ML
859 DEBUG("Setting advanced flow control");
860
40978c2b
ML
861 set_termiox_flow(data, flow);
862
8d43110a
ML
863 if (ioctl(fd, TCSETX, data) < 0) {
864 free(data);
c33efc48 865 RETURN_FAIL("setting termiox failed");
8d43110a
ML
866 }
867
868 free(data);
40978c2b 869
c33efc48 870 RETURN_OK();
40978c2b
ML
871}
872#endif /* USE_TERMIOX */
873#endif /* __linux__ */
7a6d2196 874
eb6ed20f
ML
875static enum sp_return get_config(struct sp_port *port, struct port_data *data,
876 struct sp_port_config *config)
8094e4a0 877{
da2748bf 878 unsigned int i;
cbf628c7 879
c33efc48
ML
880 TRACE("%p, %p, %p", port, data, config);
881
ea667be7
ML
882 DEBUG("Getting configuration for port %s", port->name);
883
8094e4a0 884#ifdef _WIN32
e33ab9aa 885 if (!GetCommState(port->hdl, &data->dcb))
c33efc48 886 RETURN_FAIL("GetCommState() failed");
8094e4a0 887
067417af 888 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 889 if (data->dcb.BaudRate == std_baudrates[i].index) {
067417af
ML
890 config->baudrate = std_baudrates[i].value;
891 break;
892 }
893 }
894
895 if (i == NUM_STD_BAUDRATES)
896 /* BaudRate field can be either an index or a custom baud rate. */
e33ab9aa 897 config->baudrate = data->dcb.BaudRate;
067417af 898
e33ab9aa 899 config->bits = data->dcb.ByteSize;
067417af 900
e33ab9aa
ML
901 if (data->dcb.fParity)
902 switch (data->dcb.Parity) {
067417af
ML
903 case NOPARITY:
904 config->parity = SP_PARITY_NONE;
905 break;
906 case EVENPARITY:
907 config->parity = SP_PARITY_EVEN;
908 break;
909 case ODDPARITY:
910 config->parity = SP_PARITY_ODD;
911 break;
912 default:
913 config->parity = -1;
914 }
915 else
916 config->parity = SP_PARITY_NONE;
917
e33ab9aa 918 switch (data->dcb.StopBits) {
067417af
ML
919 case ONESTOPBIT:
920 config->stopbits = 1;
921 break;
922 case TWOSTOPBITS:
923 config->stopbits = 2;
924 break;
925 default:
926 config->stopbits = -1;
927 }
928
e33ab9aa 929 switch (data->dcb.fRtsControl) {
eac329d2
UH
930 case RTS_CONTROL_DISABLE:
931 config->rts = SP_RTS_OFF;
932 break;
933 case RTS_CONTROL_ENABLE:
934 config->rts = SP_RTS_ON;
935 break;
936 case RTS_CONTROL_HANDSHAKE:
937 config->rts = SP_RTS_FLOW_CONTROL;
938 break;
939 default:
940 config->rts = -1;
067417af
ML
941 }
942
e33ab9aa 943 config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
067417af 944
e33ab9aa 945 switch (data->dcb.fDtrControl) {
eac329d2
UH
946 case DTR_CONTROL_DISABLE:
947 config->dtr = SP_DTR_OFF;
948 break;
949 case DTR_CONTROL_ENABLE:
950 config->dtr = SP_DTR_ON;
951 break;
952 case DTR_CONTROL_HANDSHAKE:
953 config->dtr = SP_DTR_FLOW_CONTROL;
954 break;
955 default:
956 config->dtr = -1;
067417af
ML
957 }
958
e33ab9aa
ML
959 config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
960
c6754b45
ML
961 if (data->dcb.fInX) {
962 if (data->dcb.fOutX)
963 config->xon_xoff = SP_XONXOFF_INOUT;
964 else
965 config->xon_xoff = SP_XONXOFF_IN;
966 } else {
967 if (data->dcb.fOutX)
968 config->xon_xoff = SP_XONXOFF_OUT;
969 else
970 config->xon_xoff = SP_XONXOFF_DISABLED;
971 }
972
e33ab9aa
ML
973#else // !_WIN32
974
975 if (tcgetattr(port->fd, &data->term) < 0)
c33efc48 976 RETURN_FAIL("tcgetattr() failed");
e33ab9aa
ML
977
978 if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
c33efc48 979 RETURN_FAIL("TIOCMGET ioctl failed");
40978c2b
ML
980
981#ifdef USE_TERMIOX
68ec29db
ML
982 int ret = get_flow(port->fd, &data->flow);
983
984 if (ret == SP_ERR_FAIL && errno == EINVAL)
985 data->termiox_supported = 0;
986 else if (ret < 0)
c33efc48 987 RETURN_CODEVAL(ret);
68ec29db
ML
988 else
989 data->termiox_supported = 1;
990#else
991 data->termiox_supported = 0;
40978c2b
ML
992#endif
993
067417af 994 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
e33ab9aa 995 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
067417af
ML
996 config->baudrate = std_baudrates[i].value;
997 break;
998 }
999 }
1000
31b3a8f5
MH
1001 if (i == NUM_STD_BAUDRATES) {
1002#ifdef __APPLE__
1003 config->baudrate = (int)data->term.c_ispeed;
7a6d2196
ML
1004#elif defined(__linux__)
1005 TRY(get_baudrate(port->fd, &config->baudrate));
31b3a8f5 1006#else
067417af 1007 config->baudrate = -1;
31b3a8f5
MH
1008#endif
1009 }
067417af 1010
e33ab9aa 1011 switch (data->term.c_cflag & CSIZE) {
067417af
ML
1012 case CS8:
1013 config->bits = 8;
1014 break;
1015 case CS7:
1016 config->bits = 7;
1017 break;
1018 case CS6:
1019 config->bits = 6;
1020 break;
1021 case CS5:
1022 config->bits = 5;
1023 break;
1024 default:
1025 config->bits = -1;
1026 }
1027
e33ab9aa 1028 if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
067417af 1029 config->parity = SP_PARITY_NONE;
e33ab9aa 1030 else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
067417af
ML
1031 config->parity = -1;
1032 else
e33ab9aa 1033 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
067417af 1034
e33ab9aa 1035 config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
067417af 1036
e33ab9aa 1037 if (data->term.c_cflag & CRTSCTS) {
067417af
ML
1038 config->rts = SP_RTS_FLOW_CONTROL;
1039 config->cts = SP_CTS_FLOW_CONTROL;
1040 } else {
68ec29db 1041 if (data->termiox_supported && data->flow & RTS_FLOW)
40978c2b
ML
1042 config->rts = SP_RTS_FLOW_CONTROL;
1043 else
1044 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
1045
68ec29db
ML
1046 config->cts = (data->termiox_supported && data->flow & CTS_FLOW) ?
1047 SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
067417af
ML
1048 }
1049
68ec29db 1050 if (data->termiox_supported && data->flow & DTR_FLOW)
40978c2b
ML
1051 config->dtr = SP_DTR_FLOW_CONTROL;
1052 else
1053 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
1054
68ec29db
ML
1055 config->dsr = (data->termiox_supported && data->flow & DSR_FLOW) ?
1056 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
705bdc69 1057
e29b93a5
ML
1058 if (data->term.c_iflag & IXOFF) {
1059 if (data->term.c_iflag & IXON)
1060 config->xon_xoff = SP_XONXOFF_INOUT;
1061 else
1062 config->xon_xoff = SP_XONXOFF_IN;
1063 } else {
1064 if (data->term.c_iflag & IXON)
1065 config->xon_xoff = SP_XONXOFF_OUT;
1066 else
1067 config->xon_xoff = SP_XONXOFF_DISABLED;
1068 }
067417af
ML
1069#endif
1070
c33efc48 1071 RETURN_OK();
067417af
ML
1072}
1073
7a6d2196 1074static enum sp_return set_config(struct sp_port *port, struct port_data *data,
eb6ed20f 1075 const struct sp_port_config *config)
18fc2dd1 1076{
e33ab9aa 1077 unsigned int i;
31b3a8f5
MH
1078#ifdef __APPLE__
1079 BAUD_TYPE baud_nonstd;
1080
1081 baud_nonstd = B0;
1082#endif
7a6d2196
ML
1083#ifdef __linux__
1084 int baud_nonstd = 0;
1085#endif
18fc2dd1 1086
c33efc48
ML
1087 TRACE("%p, %p, %p", port, data, config);
1088
ea667be7
ML
1089 DEBUG("Setting configuration for port %s", port->name);
1090
e33ab9aa 1091#ifdef _WIN32
eac329d2 1092 if (config->baudrate >= 0) {
e33ab9aa
ML
1093 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1094 if (config->baudrate == std_baudrates[i].value) {
1095 data->dcb.BaudRate = std_baudrates[i].index;
1096 break;
1097 }
1098 }
18fc2dd1 1099
e33ab9aa
ML
1100 if (i == NUM_STD_BAUDRATES)
1101 data->dcb.BaudRate = config->baudrate;
1102 }
18fc2dd1 1103
e33ab9aa
ML
1104 if (config->bits >= 0)
1105 data->dcb.ByteSize = config->bits;
1106
1107 if (config->parity >= 0) {
1108 switch (config->parity) {
1109 /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
1110 case SP_PARITY_NONE:
1111 data->dcb.Parity = NOPARITY;
1112 break;
1113 case SP_PARITY_EVEN:
1114 data->dcb.Parity = EVENPARITY;
1115 break;
1116 case SP_PARITY_ODD:
1117 data->dcb.Parity = ODDPARITY;
1118 break;
1119 default:
c33efc48 1120 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
e33ab9aa 1121 }
18fc2dd1
ML
1122 }
1123
e33ab9aa
ML
1124 if (config->stopbits >= 0) {
1125 switch (config->stopbits) {
1126 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
1127 case 1:
1128 data->dcb.StopBits = ONESTOPBIT;
1129 break;
1130 case 2:
1131 data->dcb.StopBits = TWOSTOPBITS;
1132 break;
1133 default:
c33efc48 1134 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
e33ab9aa
ML
1135 }
1136 }
1137
1138 if (config->rts >= 0) {
1139 switch (config->rts) {
1140 case SP_RTS_OFF:
1141 data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
1142 break;
1143 case SP_RTS_ON:
1144 data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
1145 break;
1146 case SP_RTS_FLOW_CONTROL:
1147 data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
1148 break;
1149 default:
c33efc48 1150 RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
e33ab9aa
ML
1151 }
1152 }
1153
1154 if (config->cts >= 0) {
1155 switch (config->cts) {
1156 case SP_CTS_IGNORE:
1157 data->dcb.fOutxCtsFlow = FALSE;
1158 break;
1159 case SP_CTS_FLOW_CONTROL:
1160 data->dcb.fOutxCtsFlow = TRUE;
1161 break;
1162 default:
c33efc48 1163 RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
e33ab9aa
ML
1164 }
1165 }
1166
1167 if (config->dtr >= 0) {
1168 switch (config->dtr) {
1169 case SP_DTR_OFF:
1170 data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
1171 break;
1172 case SP_DTR_ON:
1173 data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
1174 break;
1175 case SP_DTR_FLOW_CONTROL:
1176 data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
1177 break;
1178 default:
c33efc48 1179 RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
e33ab9aa
ML
1180 }
1181 }
1182
1183 if (config->dsr >= 0) {
1184 switch (config->dsr) {
1185 case SP_DSR_IGNORE:
1186 data->dcb.fOutxDsrFlow = FALSE;
1187 break;
1188 case SP_DSR_FLOW_CONTROL:
1189 data->dcb.fOutxDsrFlow = TRUE;
1190 break;
1191 default:
c33efc48 1192 RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
e33ab9aa 1193 }
18fc2dd1
ML
1194 }
1195
e33ab9aa
ML
1196 if (config->xon_xoff >= 0) {
1197 switch (config->xon_xoff) {
1198 case SP_XONXOFF_DISABLED:
1199 data->dcb.fInX = FALSE;
1200 data->dcb.fOutX = FALSE;
1201 break;
1202 case SP_XONXOFF_IN:
1203 data->dcb.fInX = TRUE;
1204 data->dcb.fOutX = FALSE;
1205 break;
1206 case SP_XONXOFF_OUT:
1207 data->dcb.fInX = FALSE;
1208 data->dcb.fOutX = TRUE;
1209 break;
1210 case SP_XONXOFF_INOUT:
1211 data->dcb.fInX = TRUE;
1212 data->dcb.fOutX = TRUE;
1213 break;
1214 default:
c33efc48 1215 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
e33ab9aa
ML
1216 }
1217 }
1218
1219 if (!SetCommState(port->hdl, &data->dcb))
c33efc48 1220 RETURN_FAIL("SetCommState() failed");
e33ab9aa 1221
31b3a8f5 1222#else /* !_WIN32 */
e33ab9aa 1223
7a6d2196
ML
1224 int controlbits;
1225
eac329d2 1226 if (config->baudrate >= 0) {
e33ab9aa
ML
1227 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1228 if (config->baudrate == std_baudrates[i].value) {
1229 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
c33efc48 1230 RETURN_FAIL("cfsetospeed() failed");
e33ab9aa
ML
1231
1232 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
c33efc48 1233 RETURN_FAIL("cfsetispeed() failed");
e33ab9aa
ML
1234 break;
1235 }
1236 }
1237
31b3a8f5
MH
1238 /* Non-standard baud rate */
1239 if (i == NUM_STD_BAUDRATES) {
1240#ifdef __APPLE__
24abdb68 1241 /* Set "dummy" baud rate. */
31b3a8f5 1242 if (cfsetspeed(&data->term, B9600) < 0)
c33efc48 1243 RETURN_FAIL("cfsetspeed() failed");
31b3a8f5 1244 baud_nonstd = config->baudrate;
7a6d2196
ML
1245#elif defined(__linux__)
1246 baud_nonstd = 1;
31b3a8f5 1247#else
c33efc48 1248 RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
31b3a8f5
MH
1249#endif
1250 }
e33ab9aa
ML
1251 }
1252
1253 if (config->bits >= 0) {
1254 data->term.c_cflag &= ~CSIZE;
1255 switch (config->bits) {
1256 case 8:
1257 data->term.c_cflag |= CS8;
1258 break;
1259 case 7:
1260 data->term.c_cflag |= CS7;
1261 break;
1262 case 6:
1263 data->term.c_cflag |= CS6;
1264 break;
23922313
UH
1265 case 5:
1266 data->term.c_cflag |= CS5;
1267 break;
e33ab9aa 1268 default:
c33efc48 1269 RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
e33ab9aa
ML
1270 }
1271 }
1272
1273 if (config->parity >= 0) {
1274 data->term.c_iflag &= ~IGNPAR;
1275 data->term.c_cflag &= ~(PARENB | PARODD);
1276 switch (config->parity) {
1277 case SP_PARITY_NONE:
1278 data->term.c_iflag |= IGNPAR;
1279 break;
1280 case SP_PARITY_EVEN:
1281 data->term.c_cflag |= PARENB;
1282 break;
1283 case SP_PARITY_ODD:
1284 data->term.c_cflag |= PARENB | PARODD;
1285 break;
1286 default:
c33efc48 1287 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
e33ab9aa
ML
1288 }
1289 }
1290
1291 if (config->stopbits >= 0) {
1292 data->term.c_cflag &= ~CSTOPB;
1293 switch (config->stopbits) {
1294 case 1:
1295 data->term.c_cflag &= ~CSTOPB;
1296 break;
1297 case 2:
1298 data->term.c_cflag |= CSTOPB;
1299 break;
1300 default:
c33efc48 1301 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
e33ab9aa
ML
1302 }
1303 }
1304
eac329d2 1305 if (config->rts >= 0 || config->cts >= 0) {
68ec29db
ML
1306 if (data->termiox_supported) {
1307 data->flow &= ~(RTS_FLOW | CTS_FLOW);
1308 switch (config->rts) {
1309 case SP_RTS_OFF:
1310 case SP_RTS_ON:
1311 controlbits = TIOCM_RTS;
1312 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
c33efc48 1313 RETURN_FAIL("Setting RTS signal level failed");
68ec29db
ML
1314 break;
1315 case SP_RTS_FLOW_CONTROL:
1316 data->flow |= RTS_FLOW;
1317 break;
1318 default:
1319 break;
e33ab9aa 1320 }
68ec29db
ML
1321 if (config->cts == SP_CTS_FLOW_CONTROL)
1322 data->flow |= CTS_FLOW;
e33ab9aa 1323
68ec29db 1324 if (data->flow & (RTS_FLOW | CTS_FLOW))
e33ab9aa 1325 data->term.c_iflag |= CRTSCTS;
68ec29db
ML
1326 else
1327 data->term.c_iflag &= ~CRTSCTS;
1328 } else {
1329 /* Asymmetric use of RTS/CTS not supported. */
1330 if (data->term.c_iflag & CRTSCTS) {
1331 /* Flow control can only be disabled for both RTS & CTS together. */
1332 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
1333 if (config->cts != SP_CTS_IGNORE)
c33efc48 1334 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
68ec29db
ML
1335 }
1336 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
1337 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
c33efc48 1338 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
68ec29db 1339 }
e33ab9aa 1340 } else {
68ec29db
ML
1341 /* Flow control can only be enabled for both RTS & CTS together. */
1342 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
1343 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
c33efc48 1344 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together");
68ec29db
ML
1345 }
1346
1347 if (config->rts >= 0) {
1348 if (config->rts == SP_RTS_FLOW_CONTROL) {
1349 data->term.c_iflag |= CRTSCTS;
1350 } else {
1351 controlbits = TIOCM_RTS;
1352 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
1353 &controlbits) < 0)
c33efc48 1354 RETURN_FAIL("Setting RTS signal level failed");
68ec29db 1355 }
e33ab9aa
ML
1356 }
1357 }
1358 }
1359
eac329d2 1360 if (config->dtr >= 0 || config->dsr >= 0) {
68ec29db
ML
1361 if (data->termiox_supported) {
1362 data->flow &= ~(DTR_FLOW | DSR_FLOW);
1363 switch (config->dtr) {
1364 case SP_DTR_OFF:
1365 case SP_DTR_ON:
1366 controlbits = TIOCM_DTR;
1367 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
c33efc48 1368 RETURN_FAIL("Setting DTR signal level failed");
68ec29db
ML
1369 break;
1370 case SP_DTR_FLOW_CONTROL:
1371 data->flow |= DTR_FLOW;
1372 break;
1373 default:
1374 break;
1375 }
1376 if (config->dsr == SP_DSR_FLOW_CONTROL)
1377 data->flow |= DSR_FLOW;
1378 } else {
1379 /* DTR/DSR flow control not supported. */
1380 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
c33efc48 1381 RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported");
e33ab9aa 1382
68ec29db
ML
1383 if (config->dtr >= 0) {
1384 controlbits = TIOCM_DTR;
1385 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
1386 &controlbits) < 0)
c33efc48 1387 RETURN_FAIL("Setting DTR signal level failed");
68ec29db 1388 }
e33ab9aa
ML
1389 }
1390 }
1391
1392 if (config->xon_xoff >= 0) {
1393 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
1394 switch (config->xon_xoff) {
1395 case SP_XONXOFF_DISABLED:
1396 break;
1397 case SP_XONXOFF_IN:
1398 data->term.c_iflag |= IXOFF;
1399 break;
1400 case SP_XONXOFF_OUT:
1401 data->term.c_iflag |= IXON | IXANY;
1402 break;
1403 case SP_XONXOFF_INOUT:
1404 data->term.c_iflag |= IXON | IXOFF | IXANY;
1405 break;
1406 default:
c33efc48 1407 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
e33ab9aa
ML
1408 }
1409 }
1410
1411 if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
c33efc48 1412 RETURN_FAIL("tcsetattr() failed");
31b3a8f5
MH
1413
1414#ifdef __APPLE__
1415 if (baud_nonstd != B0) {
1416 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
c33efc48 1417 RETURN_FAIL("IOSSIOSPEED ioctl failed");
31b3a8f5
MH
1418 /* Set baud rates in data->term to correct, but incompatible
1419 * with tcsetattr() value, same as delivered by tcgetattr(). */
1420 if (cfsetspeed(&data->term, baud_nonstd) < 0)
c33efc48 1421 RETURN_FAIL("cfsetspeed() failed");
31b3a8f5 1422 }
7a6d2196
ML
1423#elif defined(__linux__)
1424 if (baud_nonstd)
1425 TRY(set_baudrate(port->fd, config->baudrate));
40978c2b 1426#ifdef USE_TERMIOX
68ec29db
ML
1427 if (data->termiox_supported)
1428 TRY(set_flow(port->fd, data->flow));
40978c2b 1429#endif
7a6d2196 1430#endif
31b3a8f5
MH
1431
1432#endif /* !_WIN32 */
e33ab9aa 1433
c33efc48 1434 RETURN_OK();
e33ab9aa
ML
1435}
1436
70cd37de
ML
1437enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config)
1438{
1439 struct port_data data;
1440
1441 TRACE("%p, %p", port, config);
1442
1443 CHECK_OPEN_PORT();
1444
1445 if (!config)
1446 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1447
1448 TRY(get_config(port, &data, config));
1449
1450 RETURN_OK();
1451}
1452
eb6ed20f 1453enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config)
e33ab9aa 1454{
8f189c4c 1455 struct port_data data;
e33ab9aa
ML
1456 struct sp_port_config prev_config;
1457
c33efc48
ML
1458 TRACE("%p, %p", port, config);
1459
dec10e31 1460 CHECK_OPEN_PORT();
823690ae
ML
1461
1462 if (!config)
c33efc48 1463 RETURN_ERROR(SP_ERR_ARG, "Null config");
823690ae 1464
e33ab9aa
ML
1465 TRY(get_config(port, &data, &prev_config));
1466 TRY(set_config(port, &data, config));
74510d4b 1467
c33efc48 1468 RETURN_OK();
74510d4b
ML
1469}
1470
eb6ed20f 1471#define CREATE_SETTER(x, type) int sp_set_##x(struct sp_port *port, type x) { \
8f189c4c 1472 struct port_data data; \
e33ab9aa 1473 struct sp_port_config config; \
c33efc48 1474 TRACE("%p, %d", port, x); \
dec10e31 1475 CHECK_OPEN_PORT(); \
e33ab9aa
ML
1476 TRY(get_config(port, &data, &config)); \
1477 config.x = x; \
1478 TRY(set_config(port, &data, &config)); \
c33efc48 1479 RETURN_OK(); \
9069c2fb
ML
1480}
1481
eb6ed20f
ML
1482CREATE_SETTER(baudrate, int)
1483CREATE_SETTER(bits, int)
1484CREATE_SETTER(parity, enum sp_parity)
1485CREATE_SETTER(stopbits, int)
1486CREATE_SETTER(rts, enum sp_rts)
1487CREATE_SETTER(cts, enum sp_cts)
1488CREATE_SETTER(dtr, enum sp_dtr)
1489CREATE_SETTER(dsr, enum sp_dsr)
1490CREATE_SETTER(xon_xoff, enum sp_xonxoff)
1491
1492enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol)
e33ab9aa 1493{
8f189c4c 1494 struct port_data data;
e33ab9aa
ML
1495 struct sp_port_config config;
1496
c33efc48
ML
1497 TRACE("%p, %d", port, flowcontrol);
1498
dec10e31
ML
1499 CHECK_OPEN_PORT();
1500
1501 if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
1502 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
823690ae 1503
e33ab9aa
ML
1504 TRY(get_config(port, &data, &config));
1505
1506 if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
1507 config.xon_xoff = SP_XONXOFF_INOUT;
1508 else
1509 config.xon_xoff = SP_XONXOFF_DISABLED;
1510
1511 if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
1512 config.rts = SP_RTS_FLOW_CONTROL;
1513 config.cts = SP_CTS_FLOW_CONTROL;
1514 } else {
1515 if (config.rts == SP_RTS_FLOW_CONTROL)
1516 config.rts = SP_RTS_ON;
1517 config.cts = SP_CTS_IGNORE;
1518 }
1519
1520 if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
1521 config.dtr = SP_DTR_FLOW_CONTROL;
1522 config.dsr = SP_DSR_FLOW_CONTROL;
1523 } else {
1524 if (config.dtr == SP_DTR_FLOW_CONTROL)
1525 config.dtr = SP_DTR_ON;
1526 config.dsr = SP_DSR_IGNORE;
1527 }
1528
1529 TRY(set_config(port, &data, &config));
1530
c33efc48 1531 RETURN_OK();
e33ab9aa
ML
1532}
1533
8cf7c697
ML
1534enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals)
1535{
c33efc48
ML
1536 TRACE("%p, %p", port, signals);
1537
dec10e31 1538 CHECK_OPEN_PORT();
8cf7c697
ML
1539
1540 if (!signals)
c33efc48 1541 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
8cf7c697 1542
ea667be7
ML
1543 DEBUG("Getting control signals for port %s", port->name);
1544
8cf7c697
ML
1545 *signals = 0;
1546#ifdef _WIN32
1547 DWORD bits;
1548 if (GetCommModemStatus(port->hdl, &bits) == 0)
c33efc48 1549 RETURN_FAIL("GetCommModemStatus() failed");
8cf7c697
ML
1550 if (bits & MS_CTS_ON)
1551 *signals |= SP_SIG_CTS;
1552 if (bits & MS_DSR_ON)
1553 *signals |= SP_SIG_DSR;
8cf7c697 1554 if (bits & MS_RLSD_ON)
a6cda1e8
ML
1555 *signals |= SP_SIG_DCD;
1556 if (bits & MS_RING_ON)
8cf7c697
ML
1557 *signals |= SP_SIG_RI;
1558#else
1559 int bits;
1560 if (ioctl(port->fd, TIOCMGET, &bits) < 0)
c33efc48 1561 RETURN_FAIL("TIOCMGET ioctl failed");
8cf7c697
ML
1562 if (bits & TIOCM_CTS)
1563 *signals |= SP_SIG_CTS;
1564 if (bits & TIOCM_DSR)
1565 *signals |= SP_SIG_DSR;
1566 if (bits & TIOCM_CAR)
1567 *signals |= SP_SIG_DCD;
1568 if (bits & TIOCM_RNG)
1569 *signals |= SP_SIG_RI;
1570#endif
c33efc48 1571 RETURN_OK();
8cf7c697
ML
1572}
1573
90cc3ee6
ML
1574enum sp_return sp_start_break(struct sp_port *port)
1575{
c33efc48
ML
1576 TRACE("%p", port);
1577
dec10e31 1578 CHECK_OPEN_PORT();
90cc3ee6
ML
1579#ifdef _WIN32
1580 if (SetCommBreak(port->hdl) == 0)
c33efc48 1581 RETURN_FAIL("SetCommBreak() failed");
90cc3ee6
ML
1582#else
1583 if (ioctl(port->fd, TIOCSBRK, 1) < 0)
c33efc48 1584 RETURN_FAIL("TIOCSBRK ioctl failed");
90cc3ee6
ML
1585#endif
1586
c33efc48 1587 RETURN_OK();
90cc3ee6
ML
1588}
1589
1590enum sp_return sp_end_break(struct sp_port *port)
1591{
c33efc48
ML
1592 TRACE("%p", port);
1593
dec10e31 1594 CHECK_OPEN_PORT();
90cc3ee6
ML
1595#ifdef _WIN32
1596 if (ClearCommBreak(port->hdl) == 0)
c33efc48 1597 RETURN_FAIL("ClearCommBreak() failed");
90cc3ee6
ML
1598#else
1599 if (ioctl(port->fd, TIOCCBRK, 1) < 0)
c33efc48 1600 RETURN_FAIL("TIOCCBRK ioctl failed");
90cc3ee6
ML
1601#endif
1602
c33efc48 1603 RETURN_OK();
90cc3ee6
ML
1604}
1605
74510d4b
ML
1606int sp_last_error_code(void)
1607{
c33efc48 1608 TRACE("");
74510d4b 1609#ifdef _WIN32
c33efc48 1610 RETURN_VALUE("%d", GetLastError());
74510d4b 1611#else
c33efc48 1612 RETURN_VALUE("%d", errno);
74510d4b
ML
1613#endif
1614}
1615
74510d4b
ML
1616char *sp_last_error_message(void)
1617{
c33efc48
ML
1618 TRACE("");
1619
74510d4b
ML
1620#ifdef _WIN32
1621 LPVOID message;
1622 DWORD error = GetLastError();
1623
1624 FormatMessage(
1625 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1626 FORMAT_MESSAGE_FROM_SYSTEM |
1627 FORMAT_MESSAGE_IGNORE_INSERTS,
1628 NULL,
1629 error,
1630 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1631 (LPTSTR) &message,
1632 0, NULL );
1633
c33efc48 1634 RETURN_VALUE("%s", message);
74510d4b 1635#else
c33efc48 1636 RETURN_VALUE("%s", strerror(errno));
74510d4b
ML
1637#endif
1638}
1639
74510d4b
ML
1640void sp_free_error_message(char *message)
1641{
c33efc48
ML
1642 TRACE("%s", message);
1643
74510d4b
ML
1644#ifdef _WIN32
1645 LocalFree(message);
64eec30d
ML
1646#else
1647 (void)message;
74510d4b 1648#endif
c33efc48
ML
1649
1650 RETURN();
74510d4b 1651}
863b35e6
ML
1652
1653void sp_set_debug_handler(void (*handler)(const char *format, ...))
1654{
c33efc48
ML
1655 TRACE("%p", handler);
1656
863b35e6 1657 sp_debug_handler = handler;
c33efc48
ML
1658
1659 RETURN();
863b35e6
ML
1660}
1661
1662void sp_default_debug_handler(const char *format, ...)
1663{
1664 va_list args;
1665 va_start(args, format);
1666 if (getenv("LIBSERIALPORT_DEBUG")) {
1667 fputs("libserialport: ", stderr);
1668 vfprintf(stderr, format, args);
1669 }
1670 va_end(args);
1671}