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