mirror of https://github.com/encounter/SDL.git
Port libusb hid.c to SDL, add to MinGW configure
This commit is contained in:
parent
aebaa316c7
commit
aa09e61223
|
@ -24121,10 +24121,6 @@ CheckHIDAPI()
|
||||||
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
||||||
# so we'll just use libusb when it's available.
|
# so we'll just use libusb when it's available.
|
||||||
case "$host" in
|
case "$host" in
|
||||||
# TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
|
|
||||||
*-*-cygwin* | *-*-mingw32* )
|
|
||||||
skiplibusb=yes
|
|
||||||
;;
|
|
||||||
# libusb does not support iOS
|
# libusb does not support iOS
|
||||||
arm*-apple-darwin* | *-ios-* )
|
arm*-apple-darwin* | *-ios-* )
|
||||||
skiplibusb=yes
|
skiplibusb=yes
|
||||||
|
|
|
@ -3205,10 +3205,6 @@ CheckHIDAPI()
|
||||||
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
||||||
# so we'll just use libusb when it's available.
|
# so we'll just use libusb when it's available.
|
||||||
case "$host" in
|
case "$host" in
|
||||||
# TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
|
|
||||||
*-*-cygwin* | *-*-mingw32* )
|
|
||||||
skiplibusb=yes
|
|
||||||
;;
|
|
||||||
# libusb does not support iOS
|
# libusb does not support iOS
|
||||||
arm*-apple-darwin* | *-ios-* )
|
arm*-apple-darwin* | *-ios-* )
|
||||||
skiplibusb=yes
|
skiplibusb=yes
|
||||||
|
|
|
@ -22,37 +22,18 @@
|
||||||
code repository located at:
|
code repository located at:
|
||||||
https://github.com/libusb/hidapi .
|
https://github.com/libusb/hidapi .
|
||||||
********************************************************/
|
********************************************************/
|
||||||
|
|
||||||
|
/* This file is heavily modified from the original libusb.c, for portability.
|
||||||
|
* Last upstream update was from July 25, 2019, Git commit 93dca807.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../../SDL_internal.h"
|
#include "../../SDL_internal.h"
|
||||||
|
#include "SDL_thread.h"
|
||||||
|
#include "SDL_mutex.h"
|
||||||
|
|
||||||
#ifdef SDL_JOYSTICK_HIDAPI
|
#ifdef SDL_JOYSTICK_HIDAPI
|
||||||
|
|
||||||
#ifndef _GNU_SOURCE
|
|
||||||
#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* C */
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/* Unix */
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/utsname.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
/* GNU / LibUSB */
|
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
#ifndef __ANDROID__
|
|
||||||
#include <iconv.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "hidapi.h"
|
#include "hidapi.h"
|
||||||
|
|
||||||
|
@ -61,67 +42,63 @@ namespace NAMESPACE
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
|
|
||||||
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
|
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
|
||||||
This implementation came from Brent Priddy and was posted on
|
This implementation came from Brent Priddy and was posted on
|
||||||
StackOverflow. It is used with his permission. */
|
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)
|
typedef struct _SDL_ThreadBarrier
|
||||||
{
|
{
|
||||||
if(count == 0) {
|
SDL_mutex *mutex;
|
||||||
errno = EINVAL;
|
SDL_cond *cond;
|
||||||
return -1;
|
Uint32 count;
|
||||||
|
Uint32 trip_count;
|
||||||
|
} SDL_ThreadBarrier;
|
||||||
|
|
||||||
|
static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count)
|
||||||
|
{
|
||||||
|
if (barrier == NULL) {
|
||||||
|
return SDL_SetError("barrier must be non-NULL");
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return SDL_SetError("count must be > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
|
barrier->mutex = SDL_CreateMutex();
|
||||||
return -1;
|
if (barrier->mutex == NULL) {
|
||||||
|
return -1; /* Error set by CreateMutex */
|
||||||
}
|
}
|
||||||
if(pthread_cond_init(&barrier->cond, 0) < 0) {
|
barrier->cond = SDL_CreateCond();
|
||||||
pthread_mutex_destroy(&barrier->mutex);
|
if (barrier->cond == NULL) {
|
||||||
return -1;
|
return -1; /* Error set by CreateCond */
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier->trip_count = count;
|
barrier->trip_count = count;
|
||||||
barrier->count = 0;
|
barrier->count = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pthread_barrier_destroy(pthread_barrier_t *barrier)
|
static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
|
||||||
{
|
{
|
||||||
pthread_cond_destroy(&barrier->cond);
|
SDL_DestroyCond(barrier->cond);
|
||||||
pthread_mutex_destroy(&barrier->mutex);
|
SDL_DestroyMutex(barrier->mutex);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pthread_barrier_wait(pthread_barrier_t *barrier)
|
static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&barrier->mutex);
|
SDL_LockMutex(barrier->mutex);
|
||||||
++(barrier->count);
|
barrier->count += 1;
|
||||||
if(barrier->count >= barrier->trip_count)
|
if (barrier->count >= barrier->trip_count) {
|
||||||
{
|
|
||||||
barrier->count = 0;
|
barrier->count = 0;
|
||||||
pthread_cond_broadcast(&barrier->cond);
|
SDL_CondBroadcast(barrier->cond);
|
||||||
pthread_mutex_unlock(&barrier->mutex);
|
SDL_UnlockMutex(barrier->mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
SDL_CondWait(barrier->cond, barrier->mutex);
|
||||||
{
|
SDL_UnlockMutex(barrier->mutex);
|
||||||
pthread_cond_wait(&barrier->cond, &(barrier->mutex));
|
|
||||||
pthread_mutex_unlock(&barrier->mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__cplusplus) && !defined(NAMESPACE)
|
#if defined(__cplusplus) && !defined(NAMESPACE)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -173,10 +150,10 @@ struct hid_device_ {
|
||||||
int blocking; /* boolean */
|
int blocking; /* boolean */
|
||||||
|
|
||||||
/* Read thread objects */
|
/* Read thread objects */
|
||||||
pthread_t thread;
|
SDL_Thread *thread;
|
||||||
pthread_mutex_t mutex; /* Protects input_reports */
|
SDL_mutex *mutex; /* Protects input_reports */
|
||||||
pthread_cond_t condition;
|
SDL_cond *condition;
|
||||||
pthread_barrier_t barrier; /* Ensures correct startup sequence */
|
SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
|
||||||
int shutdown_thread;
|
int shutdown_thread;
|
||||||
int cancelled;
|
int cancelled;
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
|
@ -192,12 +169,12 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length);
|
||||||
|
|
||||||
static hid_device *new_hid_device(void)
|
static hid_device *new_hid_device(void)
|
||||||
{
|
{
|
||||||
hid_device *dev = (hid_device *)calloc(1, sizeof(hid_device));
|
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
|
||||||
dev->blocking = 1;
|
dev->blocking = 1;
|
||||||
|
|
||||||
pthread_mutex_init(&dev->mutex, NULL);
|
dev->mutex = SDL_CreateMutex();
|
||||||
pthread_cond_init(&dev->condition, NULL);
|
dev->condition = SDL_CreateCond();
|
||||||
pthread_barrier_init(&dev->barrier, NULL, 2);
|
SDL_CreateThreadBarrier(&dev->barrier, 2);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
@ -205,17 +182,17 @@ static hid_device *new_hid_device(void)
|
||||||
static void free_hid_device(hid_device *dev)
|
static void free_hid_device(hid_device *dev)
|
||||||
{
|
{
|
||||||
/* Clean up the thread objects */
|
/* Clean up the thread objects */
|
||||||
pthread_barrier_destroy(&dev->barrier);
|
SDL_DestroyThreadBarrier(&dev->barrier);
|
||||||
pthread_cond_destroy(&dev->condition);
|
SDL_DestroyCond(dev->condition);
|
||||||
pthread_mutex_destroy(&dev->mutex);
|
SDL_DestroyMutex(dev->mutex);
|
||||||
|
|
||||||
/* Free the device itself */
|
/* Free the device itself */
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/*TODO: Implement this funciton on hidapi/libusb.. */
|
/*TODO: Implement this function on hidapi/libusb.. */
|
||||||
static void register_error(hid_device *device, const char *op)
|
static void register_error(hid_device *dev, const char *op)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -400,20 +377,13 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
|
||||||
int len;
|
int len;
|
||||||
wchar_t *str = NULL;
|
wchar_t *str = NULL;
|
||||||
|
|
||||||
#ifndef __ANDROID__ /* we don't use iconv on Android */
|
|
||||||
wchar_t wbuf[256];
|
wchar_t wbuf[256];
|
||||||
/* iconv variables */
|
SDL_iconv_t ic;
|
||||||
iconv_t ic;
|
|
||||||
size_t inbytes;
|
size_t inbytes;
|
||||||
size_t outbytes;
|
size_t outbytes;
|
||||||
size_t res;
|
size_t res;
|
||||||
#ifdef __FreeBSD__
|
|
||||||
const char *inptr;
|
const char *inptr;
|
||||||
#else
|
|
||||||
char *inptr;
|
|
||||||
#endif
|
|
||||||
char *outptr;
|
char *outptr;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Determine which language to use. */
|
/* Determine which language to use. */
|
||||||
uint16_t lang;
|
uint16_t lang;
|
||||||
|
@ -430,32 +400,13 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return NULL;
|
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
|
/* buf does not need to be explicitly NULL-terminated because
|
||||||
it is only passed into iconv() which does not need it. */
|
it is only passed into iconv() which does not need it. */
|
||||||
|
|
||||||
/* Initialize iconv. */
|
/* Initialize iconv. */
|
||||||
ic = iconv_open("WCHAR_T", "UTF-16LE");
|
ic = SDL_iconv_open("WCHAR_T", "UTF-16LE");
|
||||||
if (ic == (iconv_t)-1) {
|
if (ic == (SDL_iconv_t)-1) {
|
||||||
LOG("iconv_open() failed\n");
|
LOG("SDL_iconv_open() failed\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,9 +416,9 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
|
||||||
inbytes = len-2;
|
inbytes = len-2;
|
||||||
outptr = (char*) wbuf;
|
outptr = (char*) wbuf;
|
||||||
outbytes = sizeof(wbuf);
|
outbytes = sizeof(wbuf);
|
||||||
res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
|
res = SDL_iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
|
||||||
if (res == (size_t)-1) {
|
if (res == (size_t)-1) {
|
||||||
LOG("iconv() failed\n");
|
LOG("SDL_iconv() failed\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,9 +431,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
|
||||||
str = wcsdup(wbuf);
|
str = wcsdup(wbuf);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
iconv_close(ic);
|
SDL_iconv_close(ic);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -503,16 +452,20 @@ static char *make_path(libusb_device *dev, int interface_number)
|
||||||
int HID_API_EXPORT hid_init(void)
|
int HID_API_EXPORT hid_init(void)
|
||||||
{
|
{
|
||||||
if (!usb_context) {
|
if (!usb_context) {
|
||||||
|
#ifndef _WIN32 /* TODO: Win32 setlocale */
|
||||||
const char *locale;
|
const char *locale;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
/* Init Libusb */
|
/* Init Libusb */
|
||||||
if (libusb_init(&usb_context))
|
if (libusb_init(&usb_context))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#ifndef _WIN32 /* TODO: Win32 setlocale */
|
||||||
/* Set the locale if it's not set. */
|
/* Set the locale if it's not set. */
|
||||||
locale = setlocale(LC_CTYPE, NULL);
|
locale = setlocale(LC_CTYPE, NULL);
|
||||||
if (!locale)
|
if (!locale)
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
|
#endif /* _WIN32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -663,7 +616,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||||
struct hid_device_info *tmp;
|
struct hid_device_info *tmp;
|
||||||
|
|
||||||
/* VID/PID match. Create the record. */
|
/* VID/PID match. Create the record. */
|
||||||
tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
|
tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
||||||
if (cur_dev) {
|
if (cur_dev) {
|
||||||
cur_dev->next = tmp;
|
cur_dev->next = tmp;
|
||||||
}
|
}
|
||||||
|
@ -836,19 +789,19 @@ static void read_callback(struct libusb_transfer *transfer)
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
|
|
||||||
struct input_report *rpt = (struct input_report *)malloc(sizeof(*rpt));
|
struct input_report *rpt = (struct input_report*) malloc(sizeof(*rpt));
|
||||||
rpt->data = (uint8_t *)malloc(transfer->actual_length);
|
rpt->data = (uint8_t*) malloc(transfer->actual_length);
|
||||||
memcpy(rpt->data, transfer->buffer, transfer->actual_length);
|
memcpy(rpt->data, transfer->buffer, transfer->actual_length);
|
||||||
rpt->len = transfer->actual_length;
|
rpt->len = transfer->actual_length;
|
||||||
rpt->next = NULL;
|
rpt->next = NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&dev->mutex);
|
SDL_LockMutex(dev->mutex);
|
||||||
|
|
||||||
/* Attach the new report object to the end of the list. */
|
/* Attach the new report object to the end of the list. */
|
||||||
if (dev->input_reports == NULL) {
|
if (dev->input_reports == NULL) {
|
||||||
/* The list is empty. Put it at the root. */
|
/* The list is empty. Put it at the root. */
|
||||||
dev->input_reports = rpt;
|
dev->input_reports = rpt;
|
||||||
pthread_cond_signal(&dev->condition);
|
SDL_CondSignal(dev->condition);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Find the end of the list and attach. */
|
/* Find the end of the list and attach. */
|
||||||
|
@ -867,7 +820,7 @@ static void read_callback(struct libusb_transfer *transfer)
|
||||||
return_data(dev, NULL, 0);
|
return_data(dev, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&dev->mutex);
|
SDL_UnlockMutex(dev->mutex);
|
||||||
}
|
}
|
||||||
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||||
dev->shutdown_thread = 1;
|
dev->shutdown_thread = 1;
|
||||||
|
@ -896,14 +849,14 @@ static void read_callback(struct libusb_transfer *transfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *read_thread(void *param)
|
static int read_thread(void *param)
|
||||||
{
|
{
|
||||||
hid_device *dev = (hid_device *)param;
|
hid_device *dev = (hid_device *)param;
|
||||||
unsigned char *buf;
|
uint8_t *buf;
|
||||||
const size_t length = dev->input_ep_max_packet_size;
|
const size_t length = dev->input_ep_max_packet_size;
|
||||||
|
|
||||||
/* Set up the transfer object. */
|
/* Set up the transfer object. */
|
||||||
buf = (unsigned char *)malloc(length);
|
buf = (uint8_t*) malloc(length);
|
||||||
dev->transfer = libusb_alloc_transfer(0);
|
dev->transfer = libusb_alloc_transfer(0);
|
||||||
libusb_fill_interrupt_transfer(dev->transfer,
|
libusb_fill_interrupt_transfer(dev->transfer,
|
||||||
dev->device_handle,
|
dev->device_handle,
|
||||||
|
@ -919,7 +872,7 @@ static void *read_thread(void *param)
|
||||||
libusb_submit_transfer(dev->transfer);
|
libusb_submit_transfer(dev->transfer);
|
||||||
|
|
||||||
/* Notify the main thread that the read thread is up and running. */
|
/* Notify the main thread that the read thread is up and running. */
|
||||||
pthread_barrier_wait(&dev->barrier);
|
SDL_WaitThreadBarrier(&dev->barrier);
|
||||||
|
|
||||||
/* Handle all the events. */
|
/* Handle all the events. */
|
||||||
while (!dev->shutdown_thread) {
|
while (!dev->shutdown_thread) {
|
||||||
|
@ -951,9 +904,9 @@ static void *read_thread(void *param)
|
||||||
make sure that a thread which is about to go to sleep waiting on
|
make sure that a thread which is about to go to sleep waiting on
|
||||||
the condition actually will go to sleep before the condition is
|
the condition actually will go to sleep before the condition is
|
||||||
signaled. */
|
signaled. */
|
||||||
pthread_mutex_lock(&dev->mutex);
|
SDL_LockMutex(dev->mutex);
|
||||||
pthread_cond_broadcast(&dev->condition);
|
SDL_CondBroadcast(dev->condition);
|
||||||
pthread_mutex_unlock(&dev->mutex);
|
SDL_UnlockMutex(dev->mutex);
|
||||||
|
|
||||||
/* The dev->transfer->buffer and dev->transfer objects are cleaned up
|
/* The dev->transfer->buffer and dev->transfer objects are cleaned up
|
||||||
in hid_close(). They are not cleaned up here because this thread
|
in hid_close(). They are not cleaned up here because this thread
|
||||||
|
@ -963,7 +916,7 @@ static void *read_thread(void *param)
|
||||||
since hid_close() calls libusb_cancel_transfer(), on these objects,
|
since hid_close() calls libusb_cancel_transfer(), on these objects,
|
||||||
they can not be cleaned up here. */
|
they can not be cleaned up here. */
|
||||||
|
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1072,10 +1025,10 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_create(&dev->thread, NULL, read_thread, dev);
|
dev->thread = SDL_CreateThread(read_thread, NULL, dev);
|
||||||
|
|
||||||
/* Wait here for the read thread to be initialized. */
|
/* Wait here for the read thread to be initialized. */
|
||||||
pthread_barrier_wait(&dev->barrier);
|
SDL_WaitThreadBarrier(&dev->barrier);
|
||||||
|
|
||||||
}
|
}
|
||||||
free(dev_path);
|
free(dev_path);
|
||||||
|
@ -1166,11 +1119,13 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 /* TODO: pthread_cleanup SDL? */
|
||||||
static void cleanup_mutex(void *param)
|
static void cleanup_mutex(void *param)
|
||||||
{
|
{
|
||||||
hid_device *dev = (hid_device *)param;
|
hid_device *dev = (hid_device *)param;
|
||||||
pthread_mutex_unlock(&dev->mutex);
|
SDL_UnlockMutex(dev->mutex);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
|
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
|
||||||
|
@ -1184,8 +1139,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
|
||||||
return transferred;
|
return transferred;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_lock(&dev->mutex);
|
SDL_LockMutex(dev->mutex);
|
||||||
pthread_cleanup_push(&cleanup_mutex, dev);
|
/* TODO: pthread_cleanup SDL? */
|
||||||
|
|
||||||
/* There's an input report queued up. Return it. */
|
/* There's an input report queued up. Return it. */
|
||||||
if (dev->input_reports) {
|
if (dev->input_reports) {
|
||||||
|
@ -1204,7 +1159,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
|
||||||
if (milliseconds == -1) {
|
if (milliseconds == -1) {
|
||||||
/* Blocking */
|
/* Blocking */
|
||||||
while (!dev->input_reports && !dev->shutdown_thread) {
|
while (!dev->input_reports && !dev->shutdown_thread) {
|
||||||
pthread_cond_wait(&dev->condition, &dev->mutex);
|
SDL_CondWait(dev->condition, dev->mutex);
|
||||||
}
|
}
|
||||||
if (dev->input_reports) {
|
if (dev->input_reports) {
|
||||||
bytes_read = return_data(dev, data, length);
|
bytes_read = return_data(dev, data, length);
|
||||||
|
@ -1213,17 +1168,9 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
|
||||||
else if (milliseconds > 0) {
|
else if (milliseconds > 0) {
|
||||||
/* Non-blocking, but called with timeout. */
|
/* Non-blocking, but called with timeout. */
|
||||||
int res;
|
int res;
|
||||||
struct timespec ts;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
|
||||||
ts.tv_sec += milliseconds / 1000;
|
|
||||||
ts.tv_nsec += (milliseconds % 1000) * 1000000;
|
|
||||||
if (ts.tv_nsec >= 1000000000L) {
|
|
||||||
ts.tv_sec++;
|
|
||||||
ts.tv_nsec -= 1000000000L;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!dev->input_reports && !dev->shutdown_thread) {
|
while (!dev->input_reports && !dev->shutdown_thread) {
|
||||||
res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
|
res = SDL_CondWaitTimeout(dev->condition, dev->mutex, milliseconds);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
if (dev->input_reports) {
|
if (dev->input_reports) {
|
||||||
bytes_read = return_data(dev, data, length);
|
bytes_read = return_data(dev, data, length);
|
||||||
|
@ -1234,7 +1181,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
|
||||||
or the read thread was shutdown. Run the
|
or the read thread was shutdown. Run the
|
||||||
loop again (ie: don't break). */
|
loop again (ie: don't break). */
|
||||||
}
|
}
|
||||||
else if (res == ETIMEDOUT) {
|
else if (res == SDL_MUTEX_TIMEDOUT) {
|
||||||
/* Timed out. */
|
/* Timed out. */
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -1252,8 +1199,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
pthread_mutex_unlock(&dev->mutex);
|
SDL_UnlockMutex(dev->mutex);
|
||||||
pthread_cleanup_pop(0);
|
/* TODO: pthread_cleanup SDL? */
|
||||||
|
|
||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
@ -1334,6 +1281,8 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data,
|
||||||
|
|
||||||
void HID_API_EXPORT hid_close(hid_device *dev)
|
void HID_API_EXPORT hid_close(hid_device *dev)
|
||||||
{
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1342,7 +1291,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
|
||||||
libusb_cancel_transfer(dev->transfer);
|
libusb_cancel_transfer(dev->transfer);
|
||||||
|
|
||||||
/* Wait for read_thread() to end. */
|
/* Wait for read_thread() to end. */
|
||||||
pthread_join(dev->thread, NULL);
|
SDL_WaitThread(dev->thread, &status);
|
||||||
|
|
||||||
/* Clean up the Transfer objects allocated in read_thread(). */
|
/* Clean up the Transfer objects allocated in read_thread(). */
|
||||||
free(dev->transfer->buffer);
|
free(dev->transfer->buffer);
|
||||||
|
@ -1355,11 +1304,11 @@ void HID_API_EXPORT hid_close(hid_device *dev)
|
||||||
libusb_close(dev->device_handle);
|
libusb_close(dev->device_handle);
|
||||||
|
|
||||||
/* Clear out the queue of received reports. */
|
/* Clear out the queue of received reports. */
|
||||||
pthread_mutex_lock(&dev->mutex);
|
SDL_LockMutex(dev->mutex);
|
||||||
while (dev->input_reports) {
|
while (dev->input_reports) {
|
||||||
return_data(dev, NULL, 0);
|
return_data(dev, NULL, 0);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&dev->mutex);
|
SDL_UnlockMutex(dev->mutex);
|
||||||
|
|
||||||
free_hid_device(dev);
|
free_hid_device(dev);
|
||||||
}
|
}
|
||||||
|
@ -1408,6 +1357,7 @@ struct lang_map_entry {
|
||||||
uint16_t usb_code;
|
uint16_t usb_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef _WIN32 /* TODO: Win32 setlocale */
|
||||||
#define LANG(name,code,usb_code) { name, code, usb_code }
|
#define LANG(name,code,usb_code) { name, code, usb_code }
|
||||||
static struct lang_map_entry lang_map[] = {
|
static struct lang_map_entry lang_map[] = {
|
||||||
LANG("Afrikaans", "af", 0x0436),
|
LANG("Afrikaans", "af", 0x0436),
|
||||||
|
@ -1452,7 +1402,7 @@ static struct lang_map_entry lang_map[] = {
|
||||||
LANG("English - Ireland", "en_ie", 0x1809),
|
LANG("English - Ireland", "en_ie", 0x1809),
|
||||||
LANG("English - Jamaica", "en_jm", 0x2009),
|
LANG("English - Jamaica", "en_jm", 0x2009),
|
||||||
LANG("English - New Zealand", "en_nz", 0x1409),
|
LANG("English - New Zealand", "en_nz", 0x1409),
|
||||||
LANG("English - Phillippines", "en_ph", 0x3409),
|
LANG("English - Philippines", "en_ph", 0x3409),
|
||||||
LANG("English - Southern Africa", "en_za", 0x1C09),
|
LANG("English - Southern Africa", "en_za", 0x1C09),
|
||||||
LANG("English - Trinidad", "en_tt", 0x2C09),
|
LANG("English - Trinidad", "en_tt", 0x2C09),
|
||||||
LANG("English - Great Britain", "en_gb", 0x0809),
|
LANG("English - Great Britain", "en_gb", 0x0809),
|
||||||
|
@ -1545,9 +1495,11 @@ static struct lang_map_entry lang_map[] = {
|
||||||
LANG("Zulu", "zu", 0x0435),
|
LANG("Zulu", "zu", 0x0435),
|
||||||
LANG(NULL, NULL, 0x0),
|
LANG(NULL, NULL, 0x0),
|
||||||
};
|
};
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
uint16_t get_usb_code_for_current_locale(void)
|
uint16_t get_usb_code_for_current_locale(void)
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32 /* TODO: Win32 setlocale? */
|
||||||
char *locale;
|
char *locale;
|
||||||
char search_string[64];
|
char search_string[64];
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
@ -1605,6 +1557,7 @@ uint16_t get_usb_code_for_current_locale(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
/* Found nothing. */
|
/* Found nothing. */
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue