#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
-#include <stdio.h>
#else
#include <limits.h>
#include <termios.h>
#include <sys/syslimits.h>
#endif
#ifdef __linux__
-#ifdef HAVE_LIBUDEV
-#include "libudev.h"
-#endif
+#include <dirent.h>
#ifndef __ANDROID__
#include "linux/serial.h"
#endif
/* 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)
} \
} 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); \
#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,
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);
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) {
COMSTAT status;
/* Prefix port name with '\\.\' to work with ports above COM9. */
- if (!(escaped_port_name = malloc(strlen(port->name + 5))))
+ if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
sprintf(escaped_port_name, "\\\\.\\%s", port->name);
}
va_end(args);
}
+
+int sp_get_major_package_version(void)
+{
+ return SP_PACKAGE_VERSION_MAJOR;
+}
+
+int sp_get_minor_package_version(void)
+{
+ return SP_PACKAGE_VERSION_MINOR;
+}
+
+int sp_get_micro_package_version(void)
+{
+ return SP_PACKAGE_VERSION_MICRO;
+}
+
+const char *sp_get_package_version_string(void)
+{
+ return SP_PACKAGE_VERSION_STRING;
+}
+
+int sp_get_current_lib_version(void)
+{
+ return SP_LIB_VERSION_CURRENT;
+}
+
+int sp_get_revision_lib_version(void)
+{
+ return SP_LIB_VERSION_REVISION;
+}
+
+int sp_get_age_lib_version(void)
+{
+ return SP_LIB_VERSION_AGE;
+}
+
+const char *sp_get_lib_version_string(void)
+{
+ return SP_LIB_VERSION_STRING;
+}
+
+/** @} */