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