From 6fbf635a468fb86516effb0a3015b2e4736eb850 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Mon, 29 Dec 2014 14:54:15 +0000 Subject: Added Solaris backend stubs --- configure.ac | 23 ++- libusb/Makefile.am | 6 + libusb/core.c | 2 + libusb/io.c | 7 + libusb/libusbi.h | 11 +- libusb/os/solaris_usb.c | 464 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 503 insertions(+), 10 deletions(-) create mode 100644 libusb/os/solaris_usb.c diff --git a/configure.ac b/configure.ac index 399f397..72c03be 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,11 @@ case $host in esac case $host in +*-solaris*|*-kopensolaris*) + AC_MSG_RESULT([Solaris-based]) + backend="solaris" + threads="posix" + ;; *-linux* | *-uclinux*) AC_MSG_RESULT([Linux]) backend="linux" @@ -100,6 +105,17 @@ case $host in esac case $backend in +solaris) + AC_DEFINE(OS_SOLARIS, 1, [Solaris backend]) + AC_SUBST(OS_SOLARIS) + AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of the second poll() argument]) + AC_CHECK_LIB([devinfo], [di_prop_lookup_ints], [], + [AC_MSG_ERROR([missing libdevinfo, which is required to get USB device properties])] + ) + AC_CHECK_HEADER([libdevinfo.h], [], + [AC_MSG_ERROR([missing libdevinfo.h])] + ) + ;; linux) AC_DEFINE(OS_LINUX, 1, [Linux backend]) AC_SUBST(OS_LINUX) @@ -138,7 +154,6 @@ yes) LIBS="${LIBS} -pthread" esac - AC_CHECK_HEADERS([poll.h]) AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) ;; darwin) @@ -146,7 +161,6 @@ darwin) AC_SUBST(OS_DARWIN) LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation" LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind" - AC_CHECK_HEADERS([poll.h]) AC_CHECK_TYPE([nfds_t], [AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])], [AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])], @@ -157,7 +171,6 @@ openbsd) AC_SUBST(OS_OPENBSD) THREAD_CFLAGS="-pthread" LIBS="-pthread" - AC_CHECK_HEADERS([poll.h]) AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) ;; netbsd) @@ -165,7 +178,6 @@ netbsd) AC_SUBST(OS_NETBSD) THREAD_CFLAGS="-pthread" LIBS="-pthread" - AC_CHECK_HEADERS([poll.h]) AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) ;; windows) @@ -180,13 +192,14 @@ haiku) AC_DEFINE(OS_HAIKU, 1, [Haiku backend]) AC_SUBST(OS_HAIKU) LIBS="${LIBS} -lbe" - AC_CHECK_HEADERS([poll.h]) AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) ;; esac +AC_CHECK_HEADERS([poll.h]) AC_SUBST(LIBS) +AM_CONDITIONAL(OS_SOLARIS, test "x$backend" = xsolaris) AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux) AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin) AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd) diff --git a/libusb/Makefile.am b/libusb/Makefile.am index 2cd7021..1cb64b8 100644 --- a/libusb/Makefile.am +++ b/libusb/Makefile.am @@ -4,6 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects lib_LTLIBRARIES = libusb-1.0.la +SOLARIS_SRC = os/solaris_usb.c POSIX_POLL_SRC = os/poll_posix.c LINUX_USBFS_SRC = os/linux_usbfs.c DARWIN_USB_SRC = os/darwin_usb.c @@ -17,12 +18,17 @@ DIST_SUBDIRS = EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \ $(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \ $(POSIX_POLL_SRC) \ + $(SOLARIS_SRC) \ os/threads_posix.c os/threads_windows.c \ os/linux_udev.c os/linux_netlink.c dist-hook: -cp -r os/haiku $(distdir)/os/haiku +if OS_SOLARIS +OS_SRC = $(SOLARIS_SRC) $(POSIX_POLL_SRC) +endif + if OS_LINUX if USE_UDEV diff --git a/libusb/core.c b/libusb/core.c index 9894209..330a95f 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -46,6 +46,8 @@ #if defined(OS_LINUX) const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; +#elif defined(OS_SOLARIS) +const struct usbi_os_backend * const usbi_backend = &solaris_backend; #elif defined(OS_DARWIN) const struct usbi_os_backend * const usbi_backend = &darwin_backend; #elif defined(OS_OPENBSD) diff --git a/libusb/io.c b/libusb/io.c index a5fda69..1520fb7 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -40,6 +40,13 @@ #include "libusbi.h" #include "hotplug.h" +#if !defined(TIMESPEC_TO_TIMEVAL) +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (long)(ts)->tv_sec; \ + (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ +} +#endif + /** * \page io Synchronous and asynchronous device I/O * diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 2d2f71a..1eee278 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -479,11 +479,11 @@ int usbi_signal_event(struct libusb_context *ctx); int usbi_clear_event(struct libusb_context *ctx); /* Internal abstraction for poll (needs struct usbi_transfer on Windows) */ -#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_HAIKU) -#include -#include "os/poll_posix.h" -#elif defined(OS_WINDOWS) || defined(OS_WINCE) -#include "os/poll_windows.h" +#if defined(OS_WINDOWS) +# include +#else +# include +# include #endif #if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GNUC__) @@ -1047,6 +1047,7 @@ struct usbi_os_backend { extern const struct usbi_os_backend * const usbi_backend; extern const struct usbi_os_backend linux_usbfs_backend; +extern const struct usbi_os_backend solaris_backend; extern const struct usbi_os_backend darwin_backend; extern const struct usbi_os_backend openbsd_backend; extern const struct usbi_os_backend netbsd_backend; diff --git a/libusb/os/solaris_usb.c b/libusb/os/solaris_usb.c new file mode 100644 index 0000000..5360452 --- /dev/null +++ b/libusb/os/solaris_usb.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2013 Igor Pashev (http://osdyson.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "libusb.h" +#include "libusbi.h" + +static const char dev_usb[] = "/dev/usb"; +static const char devices[] = "/devices"; +static const size_t devices_len = sizeof (devices) - 1; + + +/* + * Backend functions + */ +static int solaris_get_device_list (struct libusb_context *, + struct discovered_devs **); +static int solaris_open (struct libusb_device_handle *); +static void solaris_close (struct libusb_device_handle *); + +static int solaris_get_device_descriptor (struct libusb_device *, + unsigned char *, int *); +static int solaris_get_active_config_descriptor (struct libusb_device *, + unsigned char *, size_t, + int *); +static int solaris_get_config_descriptor (struct libusb_device *, uint8_t, + unsigned char *, size_t, int *); + +static int solaris_get_configuration (struct libusb_device_handle *, int *); +static int solaris_set_configuration (struct libusb_device_handle *, int); + +static int solaris_claim_interface (struct libusb_device_handle *, int); +static int solaris_release_interface (struct libusb_device_handle *, int); + +static int solaris_set_interface_altsetting (struct libusb_device_handle *, + int, int); +static int solaris_clear_halt (struct libusb_device_handle *, unsigned char); +static int solaris_reset_device (struct libusb_device_handle *); +static void solaris_destroy_device (struct libusb_device *); + +static int solaris_submit_transfer (struct usbi_transfer *); +static int solaris_cancel_transfer (struct usbi_transfer *); +static void solaris_clear_transfer_priv (struct usbi_transfer *); +static int solaris_handle_events (struct libusb_context *ctx, struct pollfd *, + nfds_t, int); +static int solaris_clock_gettime (int, struct timespec *); + + +const struct usbi_os_backend solaris_backend = { + .name = "Synchronous Solaris backend", + .init = NULL, + .exit = NULL, + .get_device_list = solaris_get_device_list, + .open = solaris_open, + .close = solaris_close, + + .get_device_descriptor = solaris_get_device_descriptor, + .get_active_config_descriptor = solaris_get_active_config_descriptor, + .get_config_descriptor = solaris_get_config_descriptor, + + .get_configuration = solaris_get_configuration, + .set_configuration = solaris_set_configuration, + + .claim_interface = solaris_claim_interface, + .release_interface = solaris_release_interface, + + .set_interface_altsetting = solaris_set_interface_altsetting, + .clear_halt = solaris_clear_halt, + .reset_device = solaris_reset_device, + + .kernel_driver_active = NULL, + .detach_kernel_driver = NULL, + .attach_kernel_driver = NULL, + + .destroy_device = solaris_destroy_device, + + .submit_transfer = solaris_submit_transfer, + .cancel_transfer = solaris_cancel_transfer, + .clear_transfer_priv = solaris_clear_transfer_priv, + + .handle_events = solaris_handle_events, + + .clock_gettime = solaris_clock_gettime, + + .device_priv_size = 0, + .device_handle_priv_size = 0, + .transfer_priv_size = 0, + .add_iso_packet_size = 0, +}; + + +static int +di_prop_get_int (di_node_t dn, const char *propname, int *out) +{ + int retval; + int *intp; + + usbi_dbg ("looking for \"%s\" property", propname); + + retval = di_prop_lookup_ints (DDI_DEV_T_ANY, dn, propname, &intp); + if (1 == retval) + { + if (NULL != out) + *out = *intp; + usbi_dbg ("found %s = %d", propname, *intp); + } + else if (0 == retval) + usbi_dbg ("property \"%s\" is empty", propname); + else if (retval < 0) + usbi_dbg ("failed to get property \"%s\": %s", propname, + strerror (errno)); + else + usbi_dbg ("got %d values of \"%s\"", retval, propname); + + return retval; +} + +static void +solaris_add_device (struct libusb_context *ctx, + struct discovered_devs **discdevs, + const char *device_node_path) +{ + int busnum = 0; + int devaddr = 0; + int numconf = 1; + unsigned long session_id; + enum libusb_speed speed; + + usbi_info (ctx, "device node \"%s\"", device_node_path); + + di_node_t devnode = di_init (device_node_path, DINFOPROP); + if (DI_NODE_NIL == devnode) + { + usbi_err (ctx, "di_init() failed: %s, skipping", strerror (errno)); + return; + } + + /* From now work with libdevinfo */ + + if (1 != di_prop_get_int (devnode, "assigned-address", &busnum)) + goto cleanup; + + if (1 != di_prop_get_int (devnode, "usb-num-configs", &numconf)) + goto cleanup; + + /* XXX: Super speed is not supported. */ + /* XXX: if no *-speed property exists, it is full-speed device. */ + if (0 <= di_prop_get_int (devnode, "low-speed", NULL)) + speed = LIBUSB_SPEED_LOW; + else if (0 <= di_prop_get_int (devnode, "full-speed", NULL)) + speed = LIBUSB_SPEED_FULL; + else if (0 <= di_prop_get_int (devnode, "high-speed", NULL)) + speed = LIBUSB_SPEED_HIGH; + else if (0 <= di_prop_get_int (devnode, "super-speed", NULL)) + speed = LIBUSB_SPEED_SUPER; + else + speed = LIBUSB_SPEED_FULL; + + + /* get device address - a number after @ in device_node_path: + * in "pci@0,0/pci106b,3f@6/device@2" device address is 2 + */ + char *at = strrchr (device_node_path, '@'); + if (NULL == at) + { /* can't happen! */ + usbi_err (ctx, + "failed to parse device node to device address, skipping"); + goto cleanup; + } + at++; + devaddr = atoi (at); + + session_id = busnum << 8 | devaddr; + usbi_dbg ("busnum %d devaddr %d session_id %u", busnum, devaddr, + session_id); + +cleanup: + di_fini (devnode); + return; +} + + +int +solaris_get_device_list (struct libusb_context *ctx, + struct discovered_devs **discdevs) +{ + char vidpid_path[sizeof ("/dev/usb/vvvv.pppp")]; + char devstat_path[sizeof ("/dev/usb/vvvv.pppp/iiii/devstat")]; /* 9999 instances should be enough. */ + + /* for realpath(): */ + char + device_path[sizeof + ("/devices/pci@NNNN,MMMM/pciXXXX,YYYY@IIII/device@IIII:AAAA.BBBB.devstat")]; + + regex_t regex; + int retval; + char *device_node_path; + + if (0 != regcomp (®ex, "[0-9a-f]+\\.[0-9a-f]+", REG_EXTENDED)) + { + usbi_err (ctx, "regcomp() failed"); + return (LIBUSB_ERROR_NO_MEM); + } + + /* open /dev/usb for browsing. */ + DIR *dev_usb_dir = opendir (dev_usb); + if (NULL == dev_usb_dir) + { + usbi_err (ctx, "opendir(\"%s\") failed: %s", dev_usb, strerror (errno)); + regfree (®ex); + return (LIBUSB_ERROR_ACCESS); + } + + struct dirent *vidpid; + usbi_dbg ("start browsing %s", dev_usb); + while ((vidpid = readdir (dev_usb_dir)) != NULL) + { + if (0 != regexec (®ex, vidpid->d_name, 0, NULL, 0)) + { + if ('.' != vidpid->d_name[0]) + usbi_dbg ("skipping %s", vidpid->d_name); + continue; + } + + usbi_dbg ("found %s", vidpid->d_name); + + retval = + snprintf (vidpid_path, sizeof (vidpid_path), "%s/%s", dev_usb, + vidpid->d_name); + if (retval >= sizeof (vidpid_path)) + { + usbi_err (ctx, "vidpid_path: snprintf() failed, skipping"); + continue; + } + + /* open /dev/usb/. for browsing. */ + DIR *vidpid_dir = opendir (vidpid_path); + if (NULL == vidpid_dir) + { + usbi_err (ctx, "opendir(\"%s\") failed: %s, skipping", vidpid_path, + strerror (errno)); + continue; + } + + struct dirent *inst; + usbi_dbg ("start browsing %s", vidpid_path); + while ((inst = readdir (vidpid_dir)) != NULL) + { + if ('.' == inst->d_name[0]) + continue; + + usbi_dbg ("found instance %s", inst->d_name); + + usbi_info (ctx, "found ugen device %s/%s", vidpid_path, + inst->d_name); + + /* We need *any* file in the instance subdir + * only to get the real device path under /devices. + * E. g. given /dev/usb/a12.1/0/devstat -> /devices/pci@0,0/pci106b,3f@6/device@2:a12.1.devstat + * we should get /devices/pci@0,0/pci106b,3f@6/device@2 + * devstat always exists, so use it. + */ + retval = + snprintf (devstat_path, sizeof (devstat_path), "%s/%s/devstat", + vidpid_path, inst->d_name); + if (retval >= sizeof (devstat_path)) + { + usbi_err (ctx, "devstat_path: snprintf() failed, skipping"); + continue; + } + + device_node_path = realpath (devstat_path, device_path); + if (NULL == device_node_path) + { + usbi_err (ctx, "realpath() for \"%s\" failed: %s", devstat_path, + strerror (errno)); + continue; + } + + usbi_dbg ("device path \"%s\"", device_path); + + /* is real path under /devices directory? */ + if (strncmp (device_path, devices, devices_len) != 0) + { + /* No */ + usbi_warn (ctx, "\"%s\" is not under /devices, skipping", + device_path); + continue; + } + + /* for di_init() we need to: + * + * a) strip /devices from the beginning of device_path + * b) strip everything after the colon in device_path + * + * E. g. /devices/pci@0,0/pci106b,3f@6/device@2:a12.1.devstat + * should become /pci@0,0/pci106b,3f@6/device@2 + */ + + /* a) */ + device_node_path += devices_len; + + /* b) */ + char *colon = strrchr (device_node_path, ':'); + if (colon) + *colon = '\0'; + else + usbi_warn (ctx, "no colon in device node path"); + + solaris_add_device (ctx, discdevs, device_node_path); + } + usbi_dbg ("stop browsing %s", vidpid_path); + } + usbi_dbg ("stop browsing %s", dev_usb); + + (void) closedir (dev_usb_dir); + + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_open (struct libusb_device_handle *handle) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +void +solaris_close (struct libusb_device_handle *handle) +{ +} + +int +solaris_get_device_descriptor (struct libusb_device *dev, unsigned char *buf, + int *host_endian) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_get_active_config_descriptor (struct libusb_device *dev, + unsigned char *buf, size_t len, + int *host_endian) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_get_config_descriptor (struct libusb_device *dev, uint8_t idx, + unsigned char *buf, size_t len, + int *host_endian) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_get_configuration (struct libusb_device_handle *handle, int *config) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_set_configuration (struct libusb_device_handle *handle, int config) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_claim_interface (struct libusb_device_handle *handle, int iface) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_release_interface (struct libusb_device_handle *handle, int iface) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_set_interface_altsetting (struct libusb_device_handle *handle, + int iface, int altsetting) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_clear_halt (struct libusb_device_handle *handle, + unsigned char endpoint) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_reset_device (struct libusb_device_handle *handle) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +void +solaris_destroy_device (struct libusb_device *dev) +{ +} + +int +solaris_submit_transfer (struct usbi_transfer *itransfer) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_cancel_transfer (struct usbi_transfer *itransfer) +{ + usbi_dbg (""); + + return (LIBUSB_ERROR_NOT_SUPPORTED); +} + +void +solaris_clear_transfer_priv (struct usbi_transfer *itransfer) +{ +} + +int +solaris_handle_events (struct libusb_context *ctx, struct pollfd *fds, + nfds_t nfds, int num_ready) +{ + return (LIBUSB_ERROR_NO_DEVICE); +} + +int +solaris_clock_gettime (int clkid, struct timespec *tp) +{ + usbi_dbg ("clock %d", clkid); + + if (clkid == USBI_CLOCK_REALTIME) + return clock_gettime (CLOCK_REALTIME, tp); + + if (clkid == USBI_CLOCK_MONOTONIC) + return clock_gettime (CLOCK_MONOTONIC, tp); + + return (LIBUSB_ERROR_INVALID_PARAM); +} -- cgit v1.2.3