Skip to content

Commit

Permalink
libusb: Add Android support
Browse files Browse the repository at this point in the history
This code originally came from Pekka Nikander <[email protected]>
  • Loading branch information
prusnak authored and signal11 committed Jul 23, 2014
1 parent ac6120b commit 417b2bf
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
19 changes: 19 additions & 0 deletions android/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
LOCAL_PATH:= $(call my-dir)

HIDAPI_ROOT_REL:= ../..
HIDAPI_ROOT_ABS:= $(LOCAL_PATH)/../..

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
$(HIDAPI_ROOT_REL)/libusb/hid.c

LOCAL_C_INCLUDES += \
$(HIDAPI_ROOT_ABS)/hidapi \
$(HIDAPI_ROOT_ABS)/android

LOCAL_SHARED_LIBRARIES := libusb1.0

LOCAL_MODULE := libhidapi

include $(BUILD_SHARED_LIBRARY)
92 changes: 89 additions & 3 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,74 @@
#include <wchar.h>

/* GNU / LibUSB */
#include "libusb.h"
#include "iconv.h"
#include <libusb.h>
#ifndef __ANDROID__
#include <iconv.h>
#endif

#include "hidapi.h"

#ifdef __ANDROID__

/* Barrier implementation because Android/Bionic don't have pthread_barrier.
This implementation came from Brent Priddy and was posted on
StackOverflow. It is used with his permission. */
typedef int pthread_barrierattr_t;
typedef struct pthread_barrier {
pthread_mutex_t mutex;
pthread_cond_t cond;
int count;
int trip_count;
} pthread_barrier_t;

static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
{
if(count == 0) {
errno = EINVAL;
return -1;
}

if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
return -1;
}
if(pthread_cond_init(&barrier->cond, 0) < 0) {
pthread_mutex_destroy(&barrier->mutex);
return -1;
}
barrier->trip_count = count;
barrier->count = 0;

return 0;
}

static int pthread_barrier_destroy(pthread_barrier_t *barrier)
{
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
return 0;
}

static int pthread_barrier_wait(pthread_barrier_t *barrier)
{
pthread_mutex_lock(&barrier->mutex);
++(barrier->count);
if(barrier->count >= barrier->trip_count)
{
barrier->count = 0;
pthread_cond_broadcast(&barrier->cond);
pthread_mutex_unlock(&barrier->mutex);
return 1;
}
else
{
pthread_cond_wait(&barrier->cond, &(barrier->mutex));
pthread_mutex_unlock(&barrier->mutex);
return 0;
}
}

#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -326,8 +389,9 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
char buf[512];
int len;
wchar_t *str = NULL;
wchar_t wbuf[256];

#ifndef __ANDROID__ /* we don't use iconv on Android */
wchar_t wbuf[256];
/* iconv variables */
iconv_t ic;
size_t inbytes;
Expand All @@ -339,6 +403,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
char *inptr;
#endif
char *outptr;
#endif

/* Determine which language to use. */
uint16_t lang;
Expand All @@ -355,6 +420,25 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
if (len < 0)
return NULL;

#ifdef __ANDROID__

/* Bionic does not have iconv support nor wcsdup() function, so it
has to be done manually. The following code will only work for
code points that can be represented as a single UTF-16 character,
and will incorrectly convert any code points which require more
than one UTF-16 character.
Skip over the first character (2-bytes). */
len -= 2;
str = malloc((len / 2 + 1) * sizeof(wchar_t));
int i;
for (i = 0; i < len / 2; i++) {
str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
}
str[len / 2] = 0x00000000;

#else

/* buf does not need to be explicitly NULL-terminated because
it is only passed into iconv() which does not need it. */

Expand Down Expand Up @@ -388,6 +472,8 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
err:
iconv_close(ic);

#endif

return str;
}

Expand Down

0 comments on commit 417b2bf

Please sign in to comment.