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