From ed2a7c91feb7bb207db124f5b4a05917950f00c0 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 18 Aug 2016 08:25:02 +0200 Subject: [PATCH] Use the hidapi library on Mac OS X. On Mac OS X, libusb doesn't work for USB HID devices. We can use the hidapi library instead. Although the hidapi library supports Linux and Windows too, we keep using libusb there to avoid the extra dependency. --- configure.ac | 19 +++++++++++++- src/Makefile.am | 4 +-- src/usbhid.c | 69 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index b8c25dc..0bb834f 100644 --- a/configure.ac +++ b/configure.ac @@ -73,6 +73,8 @@ esac AC_MSG_RESULT([$os_win32]) AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"]) +DEPENDENCIES="" + # Checks for USB support. AC_ARG_WITH([libusb], [AS_HELP_STRING([--without-libusb], @@ -82,10 +84,25 @@ AS_IF([test "x$with_libusb" != "xno"], [ PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], [have_libusb=yes], [have_libusb=no]) AS_IF([test "x$have_libusb" = "xyes"], [ AC_DEFINE([HAVE_LIBUSB], [1], [libusb library]) - AC_SUBST([DEPENDENCIES], [libusb-1.0]) + DEPENDENCIES="$DEPENDENCIES libusb-1.0" ]) ]) +# Checks for HIDAPI support. +AC_ARG_WITH([hidapi], + [AS_HELP_STRING([--without-hidapi], + [Build without the hidapi library])], + [], [with_hidapi=auto]) +AS_IF([test "x$with_hidapi" != "xno"], [ + PKG_CHECK_MODULES([HIDAPI], [hidapi], [have_hidapi=yes], [have_hidapi=no]) + AS_IF([test "x$have_hidapi" = "xyes"], [ + AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library]) + DEPENDENCIES="$DEPENDENCIES hidapi" + ]) +]) + +AC_SUBST([DEPENDENCIES]) + # Checks for IrDA support. AC_CHECK_HEADERS([winsock2.h af_irda.h], [irda_win32=yes], [irda_win32=no], [ #if HAVE_WINSOCK2_H diff --git a/src/Makefile.am b/src/Makefile.am index e52d1cd..fba41a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,9 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -AM_CFLAGS = $(LIBUSB_CFLAGS) -DENABLE_DEPRECATED +AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) -DENABLE_DEPRECATED lib_LTLIBRARIES = libdivecomputer.la -libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) -lm +libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) -lm libdivecomputer_la_LDFLAGS = \ -version-info $(DC_VERSION_LIBTOOL) \ -no-undefined \ diff --git a/src/usbhid.c b/src/usbhid.c index 1bdb1fd..f5b602d 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -25,11 +25,13 @@ #include -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) #ifdef _WIN32 #define NOGDI #endif #include +#elif defined(HAVE_HIDAPI) +#include #endif #include "usbhid.h" @@ -40,17 +42,20 @@ struct dc_usbhid_t { /* Library context. */ dc_context_t *context; /* Internal state. */ -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) libusb_context *ctx; libusb_device_handle *handle; int interface; unsigned char endpoint_in; unsigned char endpoint_out; unsigned int timeout; +#elif defined(HAVE_HIDAPI) + hid_device *handle; + int timeout; #endif }; -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) static dc_status_t syserror(int errcode) { @@ -95,7 +100,7 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi // Library context. usbhid->context = context; -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) struct libusb_device **devices = NULL; struct libusb_config_descriptor *config = NULL; @@ -226,13 +231,33 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi libusb_free_config_descriptor (config); libusb_free_device_list (devices, 1); + +#elif defined(HAVE_HIDAPI) + + // Initialize the hidapi library. + rc = hid_init(); + if (rc < 0) { + ERROR (context, "Failed to initialize usb support."); + status = DC_STATUS_IO; + goto error_free; + } + + // Open the USB device. + usbhid->handle = hid_open (vid, pid, NULL); + if (usbhid->handle == NULL) { + ERROR (context, "Failed to open the usb device."); + status = DC_STATUS_IO; + goto error_hid_exit; + } + + usbhid->timeout = -1; #endif *out = usbhid; return DC_STATUS_SUCCESS; -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) error_usb_close: libusb_close (usbhid->handle); error_usb_free_config: @@ -241,6 +266,9 @@ error_usb_free_list: libusb_free_device_list (devices, 1); error_usb_exit: libusb_exit (usbhid->ctx); +#elif defined(HAVE_HIDAPI) +error_hid_exit: + hid_exit (); #endif error_free: free (usbhid); @@ -255,10 +283,13 @@ dc_usbhid_close (dc_usbhid_t *usbhid) if (usbhid == NULL) return DC_STATUS_SUCCESS; -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) libusb_release_interface (usbhid->handle, usbhid->interface); libusb_close (usbhid->handle); libusb_exit (usbhid->ctx); +#elif defined(HAVE_HIDAPI) + hid_close(usbhid->handle); + hid_exit(); #endif free (usbhid); @@ -273,7 +304,7 @@ dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout) INFO (usbhid->context, "Timeout: value=%i", timeout); -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) if (timeout < 0) { usbhid->timeout = 0; } else if (timeout == 0) { @@ -281,6 +312,12 @@ dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout) } else { usbhid->timeout = timeout; } +#elif defined(HAVE_HIDAPI) + if (timeout < 0) { + usbhid->timeout = -1; + } else { + usbhid->timeout = timeout; + } #endif return DC_STATUS_SUCCESS; @@ -297,7 +334,7 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual) goto out; } -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_in, data, size, &nbytes, usbhid->timeout); if (rc != LIBUSB_SUCCESS) { ERROR (usbhid->context, "Usb read interrupt transfer failed (%s).", @@ -305,6 +342,13 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual) status = syserror (rc); goto out; } +#elif defined(HAVE_HIDAPI) + nbytes = hid_read_timeout(usbhid->handle, data, size, usbhid->timeout); + if (nbytes < 0) { + ERROR (usbhid->context, "Usb read interrupt transfer failed."); + status = DC_STATUS_IO; + goto out; + } #endif out: @@ -327,7 +371,7 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act goto out; } -#if defined(HAVE_LIBUSB) +#if defined(HAVE_LIBUSB) && !defined(__APPLE__) int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_out, (void *) data, size, &nbytes, 0); if (rc != LIBUSB_SUCCESS) { ERROR (usbhid->context, "Usb write interrupt transfer failed (%s).", @@ -335,6 +379,13 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act status = syserror (rc); goto out; } +#elif defined(HAVE_HIDAPI) + nbytes = hid_write(usbhid->handle, data, size); + if (nbytes < 0) { + ERROR (usbhid->context, "Usb write interrupt transfer failed."); + status = DC_STATUS_IO; + goto out; + } #endif out: