]> sigrok.org Git - libserialport.git/blobdiff - serialport.c
Remove the udev dependency and parse the /sys hierarchy instead.
[libserialport.git] / serialport.c
index 5a88b407e42eb05baddde41d5713459f21d35f4c..056934c7c7eac995faceadd07eeaf45314d4c0b5 100644 (file)
@@ -32,7 +32,6 @@
 #ifdef _WIN32
 #include <windows.h>
 #include <tchar.h>
-#include <stdio.h>
 #else
 #include <limits.h>
 #include <termios.h>
@@ -48,9 +47,7 @@
 #include <sys/syslimits.h>
 #endif
 #ifdef __linux__
-#ifdef HAVE_LIBUDEV
-#include "libudev.h"
-#endif
+#include <dirent.h>
 #ifndef __ANDROID__
 #include "linux/serial.h"
 #endif
@@ -166,10 +163,10 @@ void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
 
 /* Debug output macros. */
 #define DEBUG(fmt, ...) do { if (sp_debug_handler) sp_debug_handler(fmt ".\n", ##__VA_ARGS__); } while (0)
-#define DEBUG_ERROR(err, msg) DEBUG("%s returning " #err ": " msg, __func__)
-#define DEBUG_FAIL(msg) do { \
+#define DEBUG_ERROR(err, fmt, ...) DEBUG("%s returning " #err ": " fmt, __func__, ##__VA_ARGS__)
+#define DEBUG_FAIL(fmt, ...) do {               \
        char *errmsg = sp_last_error_message(); \
-       DEBUG("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \
+       DEBUG("%s returning SP_ERR_FAIL: "fmt": %s", __func__,##__VA_ARGS__,errmsg); \
        sp_free_error_message(errmsg); \
 } while (0);
 #define RETURN() do { DEBUG("%s returning", __func__); return; } while(0)
@@ -184,8 +181,8 @@ void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
        } \
 } while (0)
 #define RETURN_OK() RETURN_CODE(SP_OK);
-#define RETURN_ERROR(err, msg) do { DEBUG_ERROR(err, msg); return err; } while (0)
-#define RETURN_FAIL(msg) do { DEBUG_FAIL(msg); return SP_ERR_FAIL; } while (0)
+#define RETURN_ERROR(err, ...) do { DEBUG_ERROR(err, __VA_ARGS__); return err; } while (0)
+#define RETURN_FAIL(...) do { DEBUG_FAIL(__VA_ARGS__); return SP_ERR_FAIL; } while (0)
 #define RETURN_VALUE(fmt, x) do { \
        typeof(x) _x = x; \
        DEBUG("%s returning " fmt, __func__, _x); \
@@ -198,7 +195,6 @@ void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
 #define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
 
 /* Helper functions. */
-static struct sp_port **list_append(struct sp_port **list, const char *portname);
 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
        struct sp_port_config *config);
 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
@@ -420,49 +416,35 @@ out_close:
 out_done:
 #endif
 #ifdef __APPLE__
-       mach_port_t master;
        CFMutableDictionaryRef classes;
        io_iterator_t iter;
-       char *path;
+       char path[PATH_MAX];
        io_object_t port;
        CFTypeRef cf_path;
        Boolean result;
 
        ret = SP_OK;
 
-       DEBUG("Getting IOKit master port");
-       if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS) {
-               SET_FAIL(ret, "IOMasterPort() failed");
-               goto out_done;
-       }
-
        DEBUG("Creating matching dictionary");
        if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
                SET_FAIL(ret, "IOServiceMatching() failed");
                goto out_done;
        }
 
-       CFDictionarySetValue(classes,
-                       CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
-
        DEBUG("Getting matching services");
-       if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS) {
+       if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
+                                        &iter) != KERN_SUCCESS) {
                SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
                goto out_done;
        }
 
-       if (!(path = malloc(PATH_MAX))) {
-               SET_ERROR(ret, SP_ERR_MEM, "device path malloc failed");
-               goto out_release;
-       }
-
        DEBUG("Iterating over results");
        while ((port = IOIteratorNext(iter))) {
                cf_path = IORegistryEntryCreateCFProperty(port,
                                CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
                if (cf_path) {
-                       result = CFStringGetCString(cf_path,
-                                       path, PATH_MAX, kCFStringEncodingASCII);
+                       result = CFStringGetCString(cf_path, path, sizeof(path),
+                                                   kCFStringEncodingASCII);
                        CFRelease(cf_path);
                        if (result) {
                                DEBUG("Found port %s", path);
@@ -476,77 +458,60 @@ out_done:
                IOObjectRelease(port);
        }
 out:
-       free(path);
-out_release:
        IOObjectRelease(iter);
 out_done:
 #endif
-#if defined(__linux__) && defined(HAVE_LIBUDEV)
-       struct udev *ud;
-       struct udev_enumerate *ud_enumerate;
-       struct udev_list_entry *ud_list;
-       struct udev_list_entry *ud_entry;
-       const char *path;
-       struct udev_device *ud_dev, *ud_parent;
-       const char *name;
-       const char *driver;
-       int fd, ioctl_result;
+#ifdef __linux__
+       char name[PATH_MAX], target[PATH_MAX];
+       struct dirent entry, *result;
        struct serial_struct serial_info;
+       int len, fd, ioctl_result;
+       DIR *dir;
 
        ret = SP_OK;
 
        DEBUG("Enumerating tty devices");
-       ud = udev_new();
-       ud_enumerate = udev_enumerate_new(ud);
-       udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
-       udev_enumerate_scan_devices(ud_enumerate);
-       ud_list = udev_enumerate_get_list_entry(ud_enumerate);
+       if (!(dir = opendir("/sys/class/tty")))
+               RETURN_FAIL("could not open /sys/class/tty");
+
        DEBUG("Iterating over results");
-       udev_list_entry_foreach(ud_entry, ud_list) {
-               path = udev_list_entry_get_name(ud_entry);
-               DEBUG("Found device %s", path);
-               ud_dev = udev_device_new_from_syspath(ud, path);
-               /* If there is no parent device, this is a virtual tty. */
-               ud_parent = udev_device_get_parent(ud_dev);
-               if (ud_parent == NULL) {
-                       DEBUG("No parent device, assuming virtual tty");
-                       udev_device_unref(ud_dev);
+       while (!readdir_r(dir, &entry, &result) && result) {
+               len = readlinkat(dirfd(dir), entry.d_name, target, sizeof(target));
+               if (len <= 0 || len >= (int) sizeof(target)-1)
                        continue;
-               }
-               name = udev_device_get_devnode(ud_dev);
-               /* The serial8250 driver has a hardcoded number of ports.
-                * The only way to tell which actually exist on a given system
-                * is to try to open them and make an ioctl call. */
-               driver = udev_device_get_driver(ud_parent);
-               if (driver && !strcmp(driver, "serial8250")) {
+               target[len] = 0;
+               if (strstr(target, "virtual"))
+                       continue;
+               snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
+               DEBUG("Found device %s", name);
+               if (strstr(target, "serial8250")) {
+                       /* The serial8250 driver has a hardcoded number of ports.
+                        * The only way to tell which actually exist on a given system
+                        * is to try to open them and make an ioctl call. */
                        DEBUG("serial8250 device, attempting to open");
                        if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
                                DEBUG("open failed, skipping");
-                               goto skip;
+                               continue;
                        }
                        ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
                        close(fd);
                        if (ioctl_result != 0) {
                                DEBUG("ioctl failed, skipping");
-                               goto skip;
+                               continue;
                        }
                        if (serial_info.type == PORT_UNKNOWN) {
                                DEBUG("port type is unknown, skipping");
-                               goto skip;
+                               continue;
                        }
                }
                DEBUG("Found port %s", name);
                list = list_append(list, name);
-skip:
-               udev_device_unref(ud_dev);
                if (!list) {
                        SET_ERROR(ret, SP_ERR_MEM, "list append failed");
-                       goto out;
+                       break;
                }
        }
-out:
-       udev_enumerate_unref(ud_enumerate);
-       udev_unref(ud);
+       closedir(dir);
 #endif
 
        switch (ret) {