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