Merge git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch

Merge with upstream libdivecomputer: USB HID fixes.

* git://git.libdivecomputer.org/libdivecomputer:
  Make the initialization thread-safe
  Initialize the usb library only once
This commit is contained in:
Linus Torvalds 2017-10-19 15:57:16 -04:00
commit 0099aeeb70
2 changed files with 111 additions and 30 deletions

View File

@ -154,6 +154,7 @@ AC_CHECK_HEADERS([linux/serial.h])
AC_CHECK_HEADERS([IOKit/serial/ioss.h]) AC_CHECK_HEADERS([IOKit/serial/ioss.h])
AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([getopt.h])
AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/param.h])
AC_CHECK_HEADERS([pthread.h])
# Checks for global variable declarations. # Checks for global variable declarations.
AC_CHECK_DECLS([optreset]) AC_CHECK_DECLS([optreset])

View File

@ -24,6 +24,13 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef _WIN32
#define NOGDI
#include <windows.h>
#endif
#if defined(HAVE_HIDAPI) #if defined(HAVE_HIDAPI)
#define USE_HIDAPI #define USE_HIDAPI
@ -47,12 +54,19 @@
#include "context-private.h" #include "context-private.h"
#include "platform.h" #include "platform.h"
#ifdef _WIN32
typedef LONG dc_mutex_t;
#define DC_MUTEX_INIT 0
#else
typedef pthread_mutex_t dc_mutex_t;
#define DC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#endif
struct dc_usbhid_t { struct dc_usbhid_t {
/* Library context. */ /* Library context. */
dc_context_t *context; dc_context_t *context;
/* Internal state. */ /* Internal state. */
#if defined(USE_LIBUSB) #if defined(USE_LIBUSB)
libusb_context *ctx;
libusb_device_handle *handle; libusb_device_handle *handle;
int interface; int interface;
unsigned char endpoint_in; unsigned char endpoint_in;
@ -162,13 +176,94 @@ dc_usbhid_custom_io (dc_context_t *context, unsigned int vid, unsigned int pid)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
#ifdef USBHID
static dc_mutex_t g_usbhid_mutex = DC_MUTEX_INIT;
static size_t g_usbhid_refcount = 0;
#ifdef USE_LIBUSB
static libusb_context *g_usbhid_ctx = NULL;
#endif
static void
dc_mutex_lock (dc_mutex_t *mutex)
{
#ifdef _WIN32
while (InterlockedCompareExchange (mutex, 1, 0) == 1) {
SleepEx (0, TRUE);
}
#else
pthread_mutex_lock (mutex);
#endif
}
static void
dc_mutex_unlock (dc_mutex_t *mutex)
{
#ifdef _WIN32
InterlockedExchange (mutex, 0);
#else
pthread_mutex_unlock (mutex);
#endif
}
static dc_status_t
dc_usbhid_init (dc_context_t *context)
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_mutex_lock (&g_usbhid_mutex);
if (g_usbhid_refcount == 0) {
#if defined(USE_LIBUSB)
int rc = libusb_init (&g_usbhid_ctx);
if (rc != LIBUSB_SUCCESS) {
ERROR (context, "Failed to initialize usb support (%s).",
libusb_error_name (rc));
status = syserror (rc);
goto error;
}
#elif defined(USE_HIDAPI)
int rc = hid_init();
if (rc < 0) {
ERROR (context, "Failed to initialize usb support.");
status = DC_STATUS_IO;
goto error;
}
#endif
}
g_usbhid_refcount++;
error:
dc_mutex_unlock (&g_usbhid_mutex);
return status;
}
static dc_status_t
dc_usbhid_exit (void)
{
dc_mutex_lock (&g_usbhid_mutex);
if (--g_usbhid_refcount == 0) {
#if defined(USE_LIBUSB)
libusb_exit (g_usbhid_ctx);
g_usbhid_ctx = NULL;
#elif defined(USE_HIDAPI)
hid_exit ();
#endif
}
dc_mutex_unlock (&g_usbhid_mutex);
return DC_STATUS_SUCCESS;
}
#endif
dc_status_t dc_status_t
dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsigned int pid) dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsigned int pid)
{ {
#ifdef USBHID #ifdef USBHID
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
dc_usbhid_t *usbhid = NULL; dc_usbhid_t *usbhid = NULL;
int rc = 0;
if (out == NULL) if (out == NULL)
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
@ -185,21 +280,19 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi
// Library context. // Library context.
usbhid->context = context; usbhid->context = context;
#if defined(USE_LIBUSB) // Initialize the usb library.
struct libusb_device **devices = NULL; status = dc_usbhid_init (context);
struct libusb_config_descriptor *config = NULL; if (status != DC_STATUS_SUCCESS) {
// Initialize the libusb library.
rc = libusb_init (&usbhid->ctx);
if (rc != LIBUSB_SUCCESS) {
ERROR (context, "Failed to initialize usb support (%s).",
libusb_error_name (rc));
status = syserror (rc);
goto error_free; goto error_free;
} }
#if defined(USE_LIBUSB)
struct libusb_device **devices = NULL;
struct libusb_config_descriptor *config = NULL;
int rc = 0;
// Enumerate the USB devices. // Enumerate the USB devices.
ssize_t ndevices = libusb_get_device_list (usbhid->ctx, &devices); ssize_t ndevices = libusb_get_device_list (g_usbhid_ctx, &devices);
if (ndevices < 0) { if (ndevices < 0) {
ERROR (context, "Failed to enumerate the usb devices (%s).", ERROR (context, "Failed to enumerate the usb devices (%s).",
libusb_error_name (ndevices)); libusb_error_name (ndevices));
@ -318,21 +411,12 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi
libusb_free_device_list (devices, 1); libusb_free_device_list (devices, 1);
#elif defined(USE_HIDAPI) #elif defined(USE_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. // Open the USB device.
usbhid->handle = hid_open (vid, pid, NULL); usbhid->handle = hid_open (vid, pid, NULL);
if (usbhid->handle == NULL) { if (usbhid->handle == NULL) {
ERROR (context, "Failed to open the usb device."); ERROR (context, "Failed to open the usb device.");
status = DC_STATUS_IO; status = DC_STATUS_IO;
goto error_hid_exit; goto error_usb_exit;
} }
usbhid->timeout = -1; usbhid->timeout = -1;
@ -349,12 +433,9 @@ error_usb_free_config:
libusb_free_config_descriptor (config); libusb_free_config_descriptor (config);
error_usb_free_list: error_usb_free_list:
libusb_free_device_list (devices, 1); libusb_free_device_list (devices, 1);
error_usb_exit:
libusb_exit (usbhid->ctx);
#elif defined(USE_HIDAPI)
error_hid_exit:
hid_exit ();
#endif #endif
error_usb_exit:
dc_usbhid_exit ();
error_free: error_free:
free (usbhid); free (usbhid);
return status; return status;
@ -375,11 +456,10 @@ dc_usbhid_close (dc_usbhid_t *usbhid)
#if defined(USE_LIBUSB) #if defined(USE_LIBUSB)
libusb_release_interface (usbhid->handle, usbhid->interface); libusb_release_interface (usbhid->handle, usbhid->interface);
libusb_close (usbhid->handle); libusb_close (usbhid->handle);
libusb_exit (usbhid->ctx);
#elif defined(USE_HIDAPI) #elif defined(USE_HIDAPI)
hid_close(usbhid->handle); hid_close(usbhid->handle);
hid_exit();
#endif #endif
dc_usbhid_exit();
free (usbhid); free (usbhid);
return status; return status;