From da432cdc35ddc3e2e1374f7fc46210b4a92e6f54 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 15 Dec 2019 19:13:26 +0100 Subject: libosmocore libusb integration Osmocom applications typically use libosmocore select.[ch] event loop code as their main event dispatch mechanism. When they want to deal with libusb in a non-blocking/asynchronous way, they need to integrate libusb into that select(). The new libosmousb is doing exactly that: Providing a shared utility library for Osmocom programs that wish to use libusb. This is useful for example in simtrace2 host utilitie as well as osmo-e1d. Change-Id: I656a1a38cbb5b1f3a9145d2869d3b4d0adefcae3 Closes: OS#4299 --- src/usb/Makefile.am | 21 ++++++++ src/usb/osmo_libusb.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 src/usb/Makefile.am create mode 100644 src/usb/osmo_libusb.c (limited to 'src') diff --git a/src/usb/Makefile.am b/src/usb/Makefile.am new file mode 100644 index 00000000..bca39bfe --- /dev/null +++ b/src/usb/Makefile.am @@ -0,0 +1,21 @@ +# This is _NOT_ the library release version, it's an API version. +# Please read chapter "Library interface versions" of the libtool documentation +# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html +LIBVERSION=0:0:0 + +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include +AM_CFLAGS = -fPIC -Wall $(LIBUSB_CFLAGS) $(TALLOC_CFLAGS) +AM_LDFLAGS = $(COVERAGE_LDFLAGS) + +if ENABLE_LIBUSB + +lib_LTLIBRARIES = libosmousb.la + +libosmousb_la_SOURCES = osmo_libusb.c +libosmosim_la_LDFLAGS = -version-info $(LIBVERSION) +libosmosim_la_LIBADD = \ + $(top_builddir)/src/libosmocore.la \ + $(TALLOC_LIBS) \ + $(LIBUSB_LIBS) + +endif diff --git a/src/usb/osmo_libusb.c b/src/usb/osmo_libusb.c new file mode 100644 index 00000000..fda95739 --- /dev/null +++ b/src/usb/osmo_libusb.c @@ -0,0 +1,137 @@ +/* libosmocore integration with libusb-1.0 + * + * (C) 2019 by Harald Welte + * All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/*********************************************************************** + * logging integration + ***********************************************************************/ + +#define DLUSB DLINP + +#ifdef LIBUSB_LOG_CB_CONTEXT /* introduced in 1.0.23 */ +static const int usb2logl[] = { + [LIBUSB_LOG_LEVEL_NONE] = LOGL_FATAL, + [LIBUSB_LOG_LEVEL_ERROR] = LOGL_ERROR, + [LIBUSB_LOG_LEVEL_WARNING] = LOGL_NOTICE, + [LIBUSB_LOG_LEVEL_INFO] = LOGL_INFO, + [LIBUSB_LOG_LEVEL_DEBUG] = LOGL_DEBUG, +}; + +/* called by libusb if it wants to log something */ +static void libosmo_usb_log_cb(libusb_context *luctx, enum libusb_log_level level_usb, const char *str) +{ + int level = LOGL_NOTICE; + + if (level_usb < ARRAY_SIZE(usb2logl)) + level = usb2logl[level_usb]; + + LOGP(DLUSB, level, "%s", str); +} +#endif /* LIBUSB_LOG_CB_CONTEXT */ + +/*********************************************************************** + * select loop integration + ***********************************************************************/ + +static int osmo_usb_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + libusb_context *luctx = ofd->data; + + /* we assume that we're running Linux v2.6.27 with timerfd support here + * and hence don't have to perform manual timeout handling. See + * "Notes on time-based events" at + * http://libusb.sourceforge.net/api-1.0/group__libusb__poll.html */ + struct timeval zero_tv = { 0, 0 }; + libusb_handle_events_timeout(luctx, &zero_tv); + + return 0; +} + +/* called by libusb if it wants to add a file-descriptor */ +static void osmo_usb_added_cb(int fd, short events, void *user_data) +{ + struct osmo_fd *ofd = talloc_zero(OTC_GLOBAL, struct osmo_fd); + libusb_context *luctx = user_data; + unsigned int when = 0; + + if (events & POLLIN) + when |= OSMO_FD_READ; + if (events & POLLOUT) + when |= OSMO_FD_WRITE; + + osmo_fd_setup(ofd, fd, when, osmo_usb_fd_cb, luctx, 0); + osmo_fd_register(ofd); +} + +/* called by libusb if it wants to remove a file-descriptor */ +static void osmo_usb_removed_cb(int fd, void *user_data) +{ + struct osmo_fd *ofd = osmo_fd_get_by_fd(fd); + if (!fd) + return; + osmo_fd_unregister(ofd); + talloc_free(ofd); +} + + +/*********************************************************************** + * initialization + ***********************************************************************/ + +int osmo_libusb_init(libusb_context **pluctx) +{ + libusb_context *luctx = NULL; + int rc; + + rc = libusb_init(pluctx); + if (rc != 0) + return rc; + + if (pluctx) + luctx = *pluctx; + +#ifdef LIBUSB_LOG_CB_CONTEXT /* introduced in 1.0.23 */ + libusb_set_log_cb(luctx, &libosmo_usb_log_cb, LIBUSB_LOG_CB_CONTEXT); +#endif + + libusb_set_pollfd_notifiers(luctx, osmo_usb_added_cb, osmo_usb_removed_cb, luctx); + + return 0; +} + +void osmo_libusb_exit(libusb_context *luctx) +{ + /* we just assume libusb is cleaning up all the osmo_Fd's we've allocated */ + libusb_exit(luctx); +} -- cgit v1.2.3