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