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