]> sigrok.org Git - libserialport.git/blame - serialport.c
Include <stdio.h> on Windows for sprintf, used in sp_open.
[libserialport.git] / serialport.c
CommitLineData
74510d4b
ML
1/*
2 * This file is part of the libserialport project.
3 *
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <string.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <unistd.h>
3b63f34d
ML
27#include <stdlib.h>
28#include <errno.h>
74510d4b
ML
29#ifdef _WIN32
30#include <windows.h>
3b63f34d 31#include <tchar.h>
767c5ba8 32#include <stdio.h>
74510d4b 33#else
74510d4b
ML
34#include <termios.h>
35#include <sys/ioctl.h>
36#endif
3b63f34d 37#ifdef __APPLE__
1ebf4347
ML
38#include <IOKit/IOKitLib.h>
39#include <IOKit/serial/IOSerialKeys.h>
40#include <sys/syslimits.h>
3b63f34d
ML
41#endif
42#ifdef __linux__
43#include "libudev.h"
4b97c9fc 44#include "linux/serial.h"
3b63f34d 45#endif
74510d4b 46
f6a1fb65 47#include "libserialport.h"
74510d4b 48
77f262c4 49int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
d54e9004
ML
50{
51 struct sp_port *port;
5919c913 52 int len;
d54e9004 53
32b5ac05
ML
54 if (!port_ptr)
55 return SP_ERR_ARG;
56
77f262c4
ML
57 *port_ptr = NULL;
58
d4babed2 59 if (!portname)
77f262c4 60 return SP_ERR_ARG;
d4babed2 61
d54e9004 62 if (!(port = malloc(sizeof(struct sp_port))))
77f262c4 63 return SP_ERR_MEM;
d54e9004 64
5919c913
ML
65 len = strlen(portname) + 1;
66
d54e9004
ML
67 if (!(port->name = malloc(len)))
68 {
69 free(port);
77f262c4 70 return SP_ERR_MEM;
d54e9004
ML
71 }
72
73 memcpy(port->name, portname, len);
74
77f262c4
ML
75 *port_ptr = port;
76
77 return SP_OK;
d54e9004
ML
78}
79
32b5ac05
ML
80int sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
81{
82 if (!copy_ptr)
83 return SP_ERR_ARG;
84
85 *copy_ptr = NULL;
86
87 if (!port || !port->name)
88 return SP_ERR_ARG;
89
90 return sp_get_port_by_name(port->name, copy_ptr);
91}
92
e3b2f7a4
ML
93void sp_free_port(struct sp_port *port)
94{
95 if (!port)
96 return;
97
98 if (port->name)
99 free(port->name);
100
101 free(port);
102}
103
5919c913 104static struct sp_port **sp_list_append(struct sp_port **list, const char *portname)
3b63f34d
ML
105{
106 void *tmp;
107 unsigned int count;
108 for (count = 0; list[count]; count++);
d54e9004 109 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
3b63f34d
ML
110 goto fail;
111 list = tmp;
77f262c4 112 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
3b63f34d 113 goto fail;
db2794ce 114 list[count + 1] = NULL;
3b63f34d
ML
115 return list;
116fail:
117 sp_free_port_list(list);
118 return NULL;
119}
120
77f262c4 121int sp_list_ports(struct sp_port ***list_ptr)
3b63f34d 122{
d54e9004 123 struct sp_port **list;
77f262c4 124 int ret = SP_OK;
24c1a4bb 125
d54e9004 126 if (!(list = malloc(sizeof(struct sp_port **))))
77f262c4 127 return SP_ERR_MEM;;
24c1a4bb
ML
128
129 list[0] = NULL;
3b63f34d
ML
130
131#ifdef _WIN32
132 HKEY key;
bdfb5b8c
ML
133 TCHAR *value, *data;
134 DWORD max_value_len, max_data_size, max_data_len;
135 DWORD value_len, data_size, data_len;
3b63f34d 136 DWORD type, index = 0;
8b532d9c
ML
137 char *name;
138 int name_len;
3b63f34d
ML
139
140 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
141 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
77f262c4
ML
142 {
143 ret = SP_ERR_FAIL;
144 goto out_done;
145 }
3b63f34d 146 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
bdfb5b8c 147 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS)
77f262c4
ML
148 {
149 ret = SP_ERR_FAIL;
3b63f34d 150 goto out_close;
77f262c4 151 }
3b63f34d 152 max_data_len = max_data_size / sizeof(TCHAR);
bdfb5b8c 153 if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR))))
77f262c4
ML
154 {
155 ret = SP_ERR_MEM;
3b63f34d 156 goto out_close;
77f262c4 157 }
3b63f34d 158 if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR))))
77f262c4
ML
159 {
160 ret = SP_ERR_MEM;
bdfb5b8c 161 goto out_free_value;
77f262c4 162 }
3b63f34d 163 while (
d9573bad 164 value_len = max_value_len + 1,
3b63f34d 165 data_size = max_data_size,
bdfb5b8c 166 RegEnumValue(key, index, value, &value_len,
3b63f34d
ML
167 NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
168 {
169 data_len = data_size / sizeof(TCHAR);
170 data[data_len] = '\0';
8b532d9c
ML
171#ifdef UNICODE
172 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL)
173#else
174 name_len = data_len + 1;
175#endif
176 if (!(name = malloc(name_len)))
77f262c4
ML
177 {
178 ret = SP_ERR_MEM;
8b532d9c 179 goto out;
77f262c4 180 }
8b532d9c
ML
181#ifdef UNICODE
182 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
183#else
184 strcpy(name, data);
185#endif
77f262c4
ML
186 if (type == REG_SZ && !(list = sp_list_append(list, name)))
187 {
188 ret = SP_ERR_MEM;
189 goto out;
190 }
3b63f34d
ML
191 index++;
192 }
193out:
194 free(data);
bdfb5b8c
ML
195out_free_value:
196 free(value);
3b63f34d
ML
197out_close:
198 RegCloseKey(key);
77f262c4 199out_done:
3b63f34d
ML
200#endif
201#ifdef __APPLE__
202 mach_port_t master;
203 CFMutableDictionaryRef classes;
204 io_iterator_t iter;
205 char *path;
206 io_object_t port;
207 CFTypeRef cf_path;
208 Boolean result;
209
210 if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS)
77f262c4
ML
211 {
212 ret = SP_ERR_FAIL;
213 goto out_done;
214 }
3b63f34d
ML
215
216 if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
77f262c4
ML
217 {
218 ret = SP_ERR_FAIL;
219 goto out_done;
220 }
3b63f34d
ML
221
222 CFDictionarySetValue(classes,
223 CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
224
0d34b451 225 if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS)
77f262c4
ML
226 {
227 ret = SP_ERR_FAIL;
228 goto out_done;
229 }
3b63f34d
ML
230
231 if (!(path = malloc(PATH_MAX)))
77f262c4
ML
232 {
233 ret = SP_ERR_MEM;
3b63f34d 234 goto out_release;
77f262c4 235 }
3b63f34d 236
1ebf4347 237 while ((port = IOIteratorNext(iter))) {
3b63f34d
ML
238 cf_path = IORegistryEntryCreateCFProperty(port,
239 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
240 if (cf_path) {
241 result = CFStringGetCString(cf_path,
242 path, PATH_MAX, kCFStringEncodingASCII);
243 CFRelease(cf_path);
77f262c4
ML
244 if (result && !(list = sp_list_append(list, path)))
245 {
246 ret = SP_ERR_MEM;
247 IOObjectRelease(port);
248 goto out;
249 }
3b63f34d
ML
250 }
251 IOObjectRelease(port);
252 }
3b63f34d
ML
253out:
254 free(path);
255out_release:
256 IOObjectRelease(iter);
77f262c4 257out_done:
3b63f34d
ML
258#endif
259#ifdef __linux__
260 struct udev *ud;
261 struct udev_enumerate *ud_enumerate;
262 struct udev_list_entry *ud_list;
263 struct udev_list_entry *ud_entry;
264 const char *path;
08fe0bdb 265 struct udev_device *ud_dev, *ud_parent;
3b63f34d 266 const char *name;
4b97c9fc
ML
267 const char *driver;
268 int fd, ioctl_result;
269 struct serial_struct serial_info;
3b63f34d
ML
270
271 ud = udev_new();
272 ud_enumerate = udev_enumerate_new(ud);
273 udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
274 udev_enumerate_scan_devices(ud_enumerate);
275 ud_list = udev_enumerate_get_list_entry(ud_enumerate);
3b63f34d
ML
276 udev_list_entry_foreach(ud_entry, ud_list)
277 {
278 path = udev_list_entry_get_name(ud_entry);
279 ud_dev = udev_device_new_from_syspath(ud, path);
08fe0bdb
ML
280 /* If there is no parent device, this is a virtual tty. */
281 ud_parent = udev_device_get_parent(ud_dev);
282 if (ud_parent == NULL)
283 {
284 udev_device_unref(ud_dev);
285 continue;
286 }
3b63f34d 287 name = udev_device_get_devnode(ud_dev);
4b97c9fc
ML
288 /* The serial8250 driver has a hardcoded number of ports.
289 * The only way to tell which actually exist on a given system
290 * is to try to open them and make an ioctl call. */
291 driver = udev_device_get_driver(ud_parent);
292 if (driver && !strcmp(driver, "serial8250"))
293 {
294 if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0)
295 goto skip;
296 ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
297 close(fd);
298 if (ioctl_result != 0)
299 goto skip;
300 if (serial_info.type == PORT_UNKNOWN)
301 goto skip;
302 }
5919c913 303 list = sp_list_append(list, name);
4b97c9fc 304skip:
3b63f34d
ML
305 udev_device_unref(ud_dev);
306 if (!list)
77f262c4
ML
307 {
308 ret = SP_ERR_MEM;
3b63f34d 309 goto out;
77f262c4 310 }
3b63f34d
ML
311 }
312out:
313 udev_enumerate_unref(ud_enumerate);
314 udev_unref(ud);
3b63f34d 315#endif
77f262c4
ML
316
317 if (ret == SP_OK)
318 {
319 *list_ptr = list;
320 }
321 else
322 {
323 if (list)
324 sp_free_port_list(list);
325
326 *list_ptr = NULL;
327 }
328
329 return ret;
3b63f34d
ML
330}
331
d54e9004 332void sp_free_port_list(struct sp_port **list)
3b63f34d
ML
333{
334 unsigned int i;
335 for (i = 0; list[i]; i++)
e3b2f7a4 336 sp_free_port(list[i]);
3b63f34d
ML
337 free(list);
338}
339
74510d4b
ML
340static int sp_validate_port(struct sp_port *port)
341{
342 if (port == NULL)
343 return 0;
344#ifdef _WIN32
345 if (port->hdl == INVALID_HANDLE_VALUE)
346 return 0;
347#else
348 if (port->fd < 0)
349 return 0;
350#endif
351 return 1;
352}
353
354#define CHECK_PORT() do { if (!sp_validate_port(port)) return SP_ERR_ARG; } while (0)
355
d54e9004 356int sp_open(struct sp_port *port, int flags)
74510d4b
ML
357{
358 if (!port)
359 return SP_ERR_ARG;
360
74510d4b
ML
361#ifdef _WIN32
362 DWORD desired_access = 0, flags_and_attributes = 0;
99945a1f
ML
363 char *escaped_port_name;
364
365 /* Prefix port name with '\\.\' to work with ports above COM9. */
366 if (!(escaped_port_name = malloc(strlen(port->name + 5))))
367 return SP_ERR_MEM;
368 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
369
74510d4b
ML
370 /* Map 'flags' to the OS-specific settings. */
371 desired_access |= GENERIC_READ;
372 flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
373 if (flags & SP_MODE_RDWR)
374 desired_access |= GENERIC_WRITE;
375 if (flags & SP_MODE_NONBLOCK)
376 flags_and_attributes |= FILE_FLAG_OVERLAPPED;
377
99945a1f 378 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
74510d4b 379 OPEN_EXISTING, flags_and_attributes, 0);
99945a1f
ML
380
381 free(escaped_port_name);
382
74510d4b
ML
383 if (port->hdl == INVALID_HANDLE_VALUE)
384 return SP_ERR_FAIL;
385#else
386 int flags_local = 0;
387 /* Map 'flags' to the OS-specific settings. */
388 if (flags & SP_MODE_RDWR)
389 flags_local |= O_RDWR;
390 if (flags & SP_MODE_RDONLY)
391 flags_local |= O_RDONLY;
392 if (flags & SP_MODE_NONBLOCK)
393 flags_local |= O_NONBLOCK;
394
395 if ((port->fd = open(port->name, flags_local)) < 0)
396 return SP_ERR_FAIL;
397#endif
398
399 return SP_OK;
400}
401
74510d4b
ML
402int sp_close(struct sp_port *port)
403{
404 CHECK_PORT();
405
406#ifdef _WIN32
407 /* Returns non-zero upon success, 0 upon failure. */
408 if (CloseHandle(port->hdl) == 0)
409 return SP_ERR_FAIL;
410#else
411 /* Returns 0 upon success, -1 upon failure. */
412 if (close(port->fd) == -1)
413 return SP_ERR_FAIL;
414#endif
415
416 return SP_OK;
417}
418
74510d4b
ML
419int sp_flush(struct sp_port *port)
420{
421 CHECK_PORT();
422
423#ifdef _WIN32
424 /* Returns non-zero upon success, 0 upon failure. */
425 if (PurgeComm(port->hdl, PURGE_RXCLEAR | PURGE_TXCLEAR) == 0)
426 return SP_ERR_FAIL;
427#else
428 /* Returns 0 upon success, -1 upon failure. */
429 if (tcflush(port->fd, TCIOFLUSH) < 0)
430 return SP_ERR_FAIL;
431#endif
432 return SP_OK;
433}
434
74510d4b
ML
435int sp_write(struct sp_port *port, const void *buf, size_t count)
436{
437 CHECK_PORT();
438
439 if (!buf)
440 return SP_ERR_ARG;
441
442#ifdef _WIN32
443 DWORD written = 0;
444 /* Returns non-zero upon success, 0 upon failure. */
445 if (WriteFile(port->hdl, buf, count, &written, NULL) == 0)
446 return SP_ERR_FAIL;
447 return written;
448#else
449 /* Returns the number of bytes written, or -1 upon failure. */
450 ssize_t written = write(port->fd, buf, count);
451 if (written < 0)
452 return SP_ERR_FAIL;
453 else
454 return written;;
455#endif
456}
457
74510d4b
ML
458int sp_read(struct sp_port *port, void *buf, size_t count)
459{
460 CHECK_PORT();
461
462 if (!buf)
463 return SP_ERR_ARG;
464
465#ifdef _WIN32
466 DWORD bytes_read = 0;
467 /* Returns non-zero upon success, 0 upon failure. */
468 if (ReadFile(port->hdl, buf, count, &bytes_read, NULL) == 0)
469 return SP_ERR_FAIL;
470 return bytes_read;
471#else
472 ssize_t bytes_read;
473 /* Returns the number of bytes read, or -1 upon failure. */
474 if ((bytes_read = read(port->fd, buf, count)) < 0)
475 return SP_ERR_FAIL;
476 return bytes_read;
477#endif
478}
479
74510d4b
ML
480int sp_set_params(struct sp_port *port, int baudrate,
481 int bits, int parity, int stopbits,
482 int flowcontrol, int rts, int dtr)
483{
484 CHECK_PORT();
485
486#ifdef _WIN32
487 DCB dcb;
488
489 if (!GetCommState(port->hdl, &dcb))
490 return SP_ERR_FAIL;
491
492 switch (baudrate) {
493 /*
494 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
495 * have documented CBR_* macros.
496 */
497 case 110:
498 dcb.BaudRate = CBR_110;
499 break;
500 case 300:
501 dcb.BaudRate = CBR_300;
502 break;
503 case 600:
504 dcb.BaudRate = CBR_600;
505 break;
506 case 1200:
507 dcb.BaudRate = CBR_1200;
508 break;
509 case 2400:
510 dcb.BaudRate = CBR_2400;
511 break;
512 case 4800:
513 dcb.BaudRate = CBR_4800;
514 break;
515 case 9600:
516 dcb.BaudRate = CBR_9600;
517 break;
518 case 14400:
519 dcb.BaudRate = CBR_14400; /* Not available on Unix? */
520 break;
521 case 19200:
522 dcb.BaudRate = CBR_19200;
523 break;
524 case 38400:
525 dcb.BaudRate = CBR_38400;
526 break;
527 case 57600:
528 dcb.BaudRate = CBR_57600;
529 break;
530 case 115200:
531 dcb.BaudRate = CBR_115200;
532 break;
533 case 128000:
534 dcb.BaudRate = CBR_128000; /* Not available on Unix? */
535 break;
536 case 256000:
537 dcb.BaudRate = CBR_256000; /* Not available on Unix? */
538 break;
539 default:
540 return SP_ERR_ARG;
541 }
542
e4cc1a53
ML
543 dcb.ByteSize = bits;
544
74510d4b
ML
545 switch (stopbits) {
546 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
547 case 1:
548 dcb.StopBits = ONESTOPBIT;
549 break;
550 case 2:
551 dcb.StopBits = TWOSTOPBITS;
552 break;
553 default:
554 return SP_ERR_ARG;
555 }
556
557 switch (parity) {
558 /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
559 case SP_PARITY_NONE:
560 dcb.Parity = NOPARITY;
561 break;
562 case SP_PARITY_EVEN:
563 dcb.Parity = EVENPARITY;
564 break;
565 case SP_PARITY_ODD:
566 dcb.Parity = ODDPARITY;
567 break;
568 default:
569 return SP_ERR_ARG;
570 }
571
572 if (rts != -1) {
573 if (rts)
574 dcb.fRtsControl = RTS_CONTROL_ENABLE;
575 else
576 dcb.fRtsControl = RTS_CONTROL_DISABLE;
577 }
578
579 if (dtr != -1) {
580 if (dtr)
581 dcb.fDtrControl = DTR_CONTROL_ENABLE;
582 else
583 dcb.fDtrControl = DTR_CONTROL_DISABLE;
584 }
585
586 if (!SetCommState(port->hdl, &dcb))
587 return SP_ERR_FAIL;
588#else
589 struct termios term;
590 speed_t baud;
591 int controlbits;
592
593 if (tcgetattr(port->fd, &term) < 0)
594 return SP_ERR_FAIL;
595
596 switch (baudrate) {
597 case 50:
598 baud = B50;
599 break;
600 case 75:
601 baud = B75;
602 break;
603 case 110:
604 baud = B110;
605 break;
606 case 134:
607 baud = B134;
608 break;
609 case 150:
610 baud = B150;
611 break;
612 case 200:
613 baud = B200;
614 break;
615 case 300:
616 baud = B300;
617 break;
618 case 600:
619 baud = B600;
620 break;
621 case 1200:
622 baud = B1200;
623 break;
624 case 1800:
625 baud = B1800;
626 break;
627 case 2400:
628 baud = B2400;
629 break;
630 case 4800:
631 baud = B4800;
632 break;
633 case 9600:
634 baud = B9600;
635 break;
636 case 19200:
637 baud = B19200;
638 break;
639 case 38400:
640 baud = B38400;
641 break;
642 case 57600:
643 baud = B57600;
644 break;
645 case 115200:
646 baud = B115200;
647 break;
648 case 230400:
649 baud = B230400;
650 break;
651#if !defined(__APPLE__) && !defined(__OpenBSD__)
652 case 460800:
653 baud = B460800;
654 break;
655#endif
656 default:
657 return SP_ERR_ARG;
658 }
659
660 if (cfsetospeed(&term, baud) < 0)
661 return SP_ERR_FAIL;
662
663 if (cfsetispeed(&term, baud) < 0)
664 return SP_ERR_FAIL;
665
666 term.c_cflag &= ~CSIZE;
667 switch (bits) {
668 case 8:
669 term.c_cflag |= CS8;
670 break;
671 case 7:
672 term.c_cflag |= CS7;
673 break;
d1d566f2
ML
674 case 6:
675 term.c_cflag |= CS6;
676 break;
74510d4b
ML
677 default:
678 return SP_ERR_ARG;
679 }
680
681 term.c_cflag &= ~CSTOPB;
682 switch (stopbits) {
683 case 1:
684 term.c_cflag &= ~CSTOPB;
685 break;
686 case 2:
687 term.c_cflag |= CSTOPB;
688 break;
689 default:
690 return SP_ERR_ARG;
691 }
692
8683177b 693 term.c_iflag &= ~(IXON | IXOFF | IXANY);
74510d4b
ML
694 term.c_cflag &= ~CRTSCTS;
695 switch (flowcontrol) {
696 case 0:
697 /* No flow control. */
698 break;
699 case 1:
700 term.c_cflag |= CRTSCTS;
701 break;
702 case 2:
8683177b 703 term.c_iflag |= IXON | IXOFF | IXANY;
74510d4b
ML
704 break;
705 default:
706 return SP_ERR_ARG;
707 }
708
709 term.c_iflag &= ~IGNPAR;
8683177b 710 term.c_cflag &= ~(PARENB | PARODD);
74510d4b
ML
711 switch (parity) {
712 case SP_PARITY_NONE:
713 term.c_iflag |= IGNPAR;
714 break;
715 case SP_PARITY_EVEN:
716 term.c_cflag |= PARENB;
717 break;
718 case SP_PARITY_ODD:
719 term.c_cflag |= PARENB | PARODD;
720 break;
721 default:
722 return SP_ERR_ARG;
723 }
724
725 /* Turn off all serial port cooking. */
726 term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
727 term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
728#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
729 term.c_oflag &= ~OFILL;
730#endif
731
732 /* Disable canonical mode, and don't echo input characters. */
733 term.c_lflag &= ~(ICANON | ECHO);
734
8683177b
ML
735 /* Ignore modem status lines; enable receiver */
736 term.c_cflag |= (CLOCAL | CREAD);
737
74510d4b
ML
738 /* Write the configured settings. */
739 if (tcsetattr(port->fd, TCSADRAIN, &term) < 0)
740 return SP_ERR_FAIL;
741
742 if (rts != -1) {
743 controlbits = TIOCM_RTS;
744 if (ioctl(port->fd, rts ? TIOCMBIS : TIOCMBIC,
745 &controlbits) < 0)
746 return SP_ERR_FAIL;
747 }
748
749 if (dtr != -1) {
750 controlbits = TIOCM_DTR;
751 if (ioctl(port->fd, dtr ? TIOCMBIS : TIOCMBIC,
752 &controlbits) < 0)
753 return SP_ERR_FAIL;
754 }
755#endif
756
757 return SP_OK;
758}
759
74510d4b
ML
760int sp_last_error_code(void)
761{
762#ifdef _WIN32
763 return GetLastError();
764#else
765 return errno;
766#endif
767}
768
74510d4b
ML
769char *sp_last_error_message(void)
770{
771#ifdef _WIN32
772 LPVOID message;
773 DWORD error = GetLastError();
774
775 FormatMessage(
776 FORMAT_MESSAGE_ALLOCATE_BUFFER |
777 FORMAT_MESSAGE_FROM_SYSTEM |
778 FORMAT_MESSAGE_IGNORE_INSERTS,
779 NULL,
780 error,
781 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
782 (LPTSTR) &message,
783 0, NULL );
784
785 return message;
786#else
787 return strerror(errno);
788#endif
789}
790
74510d4b
ML
791void sp_free_error_message(char *message)
792{
793#ifdef _WIN32
794 LocalFree(message);
64eec30d
ML
795#else
796 (void)message;
74510d4b
ML
797#endif
798}