From 03f8528315fa46c95991a34f3325d7b33ae5538c Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Sat, 02 May 2020 21:48:36 +0000
Subject: [PATCH] Update source to SDL2 2.0.12

---
 source/src/hidapi/libusb/hid.c |  400 ++++++++++++++++++++++++++++----------------------------
 1 files changed, 202 insertions(+), 198 deletions(-)

diff --git a/source/src/hidapi/libusb/hid.c b/source/src/hidapi/libusb/hid.c
index 17378ff..90ca815 100644
--- a/source/src/hidapi/libusb/hid.c
+++ b/source/src/hidapi/libusb/hid.c
@@ -20,39 +20,21 @@
  files located at the root of the source distribution.
  These files may also be found in the public source
  code repository located at:
-        http://github.com/signal11/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_thread.h"
+#include "SDL_mutex.h"
 
 #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>
-#ifndef __ANDROID__
-#include <iconv.h>
-#endif
+#include <locale.h> /* setlocale */
 
 #include "hidapi.h"
 
@@ -61,66 +43,62 @@
 {
 #endif
 
-#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)
+typedef struct _SDL_ThreadBarrier
 {
-	if(count == 0) {
-		errno = EINVAL;
-		return -1;
+	SDL_mutex *mutex;
+	SDL_cond *cond;
+	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) {
-		return -1;
+	barrier->mutex = SDL_CreateMutex();
+	if (barrier->mutex == NULL) {
+		return -1; /* Error set by CreateMutex */
 	}
-	if(pthread_cond_init(&barrier->cond, 0) < 0) {
-		pthread_mutex_destroy(&barrier->mutex);
-		return -1;
+	barrier->cond = SDL_CreateCond();
+	if (barrier->cond == NULL) {
+		return -1; /* Error set by CreateCond */
 	}
+
 	barrier->trip_count = count;
 	barrier->count = 0;
 
 	return 0;
 }
 
-static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
 {
-	pthread_cond_destroy(&barrier->cond);
-	pthread_mutex_destroy(&barrier->mutex);
-	return 0;
+	SDL_DestroyCond(barrier->cond);
+	SDL_DestroyMutex(barrier->mutex);
 }
 
-static int pthread_barrier_wait(pthread_barrier_t *barrier)
+static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
 {
-	pthread_mutex_lock(&barrier->mutex);
-	++(barrier->count);
-	if(barrier->count >= barrier->trip_count)
-	{
+	SDL_LockMutex(barrier->mutex);
+	barrier->count += 1;
+	if (barrier->count >= barrier->trip_count) {
 		barrier->count = 0;
-		pthread_cond_broadcast(&barrier->cond);
-		pthread_mutex_unlock(&barrier->mutex);
+		SDL_CondBroadcast(barrier->cond);
+		SDL_UnlockMutex(barrier->mutex);
 		return 1;
 	}
-	else
-	{
-		pthread_cond_wait(&barrier->cond, &(barrier->mutex));
-		pthread_mutex_unlock(&barrier->mutex);
-		return 0;
-	}
+	SDL_CondWait(barrier->cond, barrier->mutex);
+	SDL_UnlockMutex(barrier->mutex);
+	return 0;
 }
-
-#endif
 
 #if defined(__cplusplus) && !defined(NAMESPACE)
 extern "C" {
@@ -163,6 +141,7 @@
 
 	/* The interface number of the HID */
 	int interface;
+	int detached_driver;
 
 	/* Indexes of Strings */
 	int manufacturer_index;
@@ -173,10 +152,10 @@
 	int blocking; /* boolean */
 
 	/* Read thread objects */
-	pthread_t thread;
-	pthread_mutex_t mutex; /* Protects input_reports */
-	pthread_cond_t condition;
-	pthread_barrier_t barrier; /* Ensures correct startup sequence */
+	SDL_Thread *thread;
+	SDL_mutex *mutex; /* Protects input_reports */
+	SDL_cond *condition;
+	SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
 	int shutdown_thread;
 	int cancelled;
 	struct libusb_transfer *transfer;
@@ -192,12 +171,12 @@
 
 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;
 
-	pthread_mutex_init(&dev->mutex, NULL);
-	pthread_cond_init(&dev->condition, NULL);
-	pthread_barrier_init(&dev->barrier, NULL, 2);
+	dev->mutex = SDL_CreateMutex();
+	dev->condition = SDL_CreateCond();
+	SDL_CreateThreadBarrier(&dev->barrier, 2);
 
 	return dev;
 }
@@ -205,17 +184,17 @@
 static void free_hid_device(hid_device *dev)
 {
 	/* Clean up the thread objects */
-	pthread_barrier_destroy(&dev->barrier);
-	pthread_cond_destroy(&dev->condition);
-	pthread_mutex_destroy(&dev->mutex);
+	SDL_DestroyThreadBarrier(&dev->barrier);
+	SDL_DestroyCond(dev->condition);
+	SDL_DestroyMutex(dev->mutex);
 
 	/* Free the device itself */
 	free(dev);
 }
 
 #if 0
-/*TODO: Implement this funciton on hidapi/libusb.. */
-static void register_error(hid_device *device, const char *op)
+/*TODO: Implement this function on hidapi/libusb.. */
+static void register_error(hid_device *dev, const char *op)
 {
 
 }
@@ -400,20 +379,13 @@
 	int len;
 	wchar_t *str = NULL;
 
-#ifndef __ANDROID__ /* we don't use iconv on Android */
 	wchar_t wbuf[256];
-	/* iconv variables */
-	iconv_t ic;
+	SDL_iconv_t ic;
 	size_t inbytes;
 	size_t outbytes;
 	size_t res;
-#ifdef __FreeBSD__
 	const char *inptr;
-#else
-	char *inptr;
-#endif
 	char *outptr;
-#endif
 
 	/* Determine which language to use. */
 	uint16_t lang;
@@ -430,32 +402,13 @@
 	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. */
 
 	/* Initialize iconv. */
-	ic = iconv_open("WCHAR_T", "UTF-16LE");
-	if (ic == (iconv_t)-1) {
-		LOG("iconv_open() failed\n");
+	ic = SDL_iconv_open("WCHAR_T", "UTF-16LE");
+	if (ic == (SDL_iconv_t)-1) {
+		LOG("SDL_iconv_open() failed\n");
 		return NULL;
 	}
 
@@ -465,9 +418,9 @@
 	inbytes = len-2;
 	outptr = (char*) wbuf;
 	outbytes = sizeof(wbuf);
-	res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
+	res = SDL_iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
 	if (res == (size_t)-1) {
-		LOG("iconv() failed\n");
+		LOG("SDL_iconv() failed\n");
 		goto err;
 	}
 
@@ -480,9 +433,7 @@
 	str = wcsdup(wbuf);
 
 err:
-	iconv_close(ic);
-
-#endif
+	SDL_iconv_close(ic);
 
 	return str;
 }
@@ -531,7 +482,8 @@
 static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc)
 {
 	static const int XB360_IFACE_SUBCLASS = 93;
-	static const int XB360_IFACE_PROTOCOL = 1; /* Wired only */
+	static const int XB360_IFACE_PROTOCOL = 1; /* Wired */
+	static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
 	static const int SUPPORTED_VENDORS[] = {
 		0x0079, /* GPD Win 2 */
 		0x044f, /* Thrustmaster */
@@ -541,8 +493,9 @@
 		0x06a3, /* Saitek */
 		0x0738, /* Mad Catz */
 		0x07ff, /* Mad Catz */
-		0x0e6f, /* Unknown */
+		0x0e6f, /* PDP */
 		0x0f0d, /* Hori */
+		0x1038, /* SteelSeries */
 		0x11c9, /* Nacon */
 		0x12ab, /* Unknown */
 		0x1430, /* RedOctane */
@@ -555,10 +508,10 @@
 		0x24c6, /* PowerA */
 	};
 
-	if (intf_desc->bInterfaceNumber == 0 &&
-	    intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
+	if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
 	    intf_desc->bInterfaceSubClass == XB360_IFACE_SUBCLASS &&
-	    intf_desc->bInterfaceProtocol == XB360_IFACE_PROTOCOL) {
+	    (intf_desc->bInterfaceProtocol == XB360_IFACE_PROTOCOL ||
+	     intf_desc->bInterfaceProtocol == XB360W_IFACE_PROTOCOL)) {
 		int i;
 		for (i = 0; i < sizeof(SUPPORTED_VENDORS)/sizeof(SUPPORTED_VENDORS[0]); ++i) {
 			if (vendor_id == SUPPORTED_VENDORS[i]) {
@@ -576,10 +529,11 @@
         static const int SUPPORTED_VENDORS[] = {
             0x045e, /* Microsoft */
             0x0738, /* Mad Catz */
-            0x0e6f, /* Unknown */
+            0x0e6f, /* PDP */
             0x0f0d, /* Hori */
             0x1532, /* Razer Wildcat */
             0x24c6, /* PowerA */
+            0x2e24, /* Hyperkin */
         };
 
 	if (intf_desc->bInterfaceNumber == 0 &&
@@ -603,13 +557,7 @@
 
 	/* Also enumerate Xbox 360 controllers */
 	if (is_xbox360(vendor_id, intf_desc))
-	{
-		/* hid_write() to Xbox 360 controllers doesn't seem to work on Linux:
-		   - xpad 1-2:1.0: xpad_try_sending_next_out_packet - usb_submit_urb failed with result -2
-		   Xbox 360 controller support is good on Linux anyway, so we'll ignore this for now.
 		return 1;
-		*/
-	}
 
 	/* Also enumerate Xbox One controllers */
 	if (is_xboxone(vendor_id, intf_desc))
@@ -660,25 +608,25 @@
 						/* Check the VID/PID against the arguments */
 						if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
 						    (product_id == 0x0 || product_id == dev_pid)) {
-							struct hid_device_info *tmp;
-
-							/* VID/PID match. Create the record. */
-							tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
-							if (cur_dev) {
-								cur_dev->next = tmp;
-							}
-							else {
-								root = tmp;
-							}
-							cur_dev = tmp;
-
-							/* Fill out the record */
-							cur_dev->next = NULL;
-							cur_dev->path = make_path(dev, interface_num);
-
 							res = libusb_open(dev, &handle);
 
 							if (res >= 0) {
+								struct hid_device_info *tmp;
+
+								/* VID/PID match. Create the record. */
+								tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+								if (cur_dev) {
+									cur_dev->next = tmp;
+								}
+								else {
+									root = tmp;
+								}
+								cur_dev = tmp;
+
+								/* Fill out the record */
+								cur_dev->next = NULL;
+								cur_dev->path = make_path(dev, interface_num);
+
 								/* Serial Number */
 								if (desc.iSerialNumber > 0)
 									cur_dev->serial_number =
@@ -756,16 +704,22 @@
 #endif /* INVASIVE_GET_USAGE */
 
 								libusb_close(handle);
-							}
-							/* VID/PID */
-							cur_dev->vendor_id = dev_vid;
-							cur_dev->product_id = dev_pid;
 
-							/* Release Number */
-							cur_dev->release_number = desc.bcdDevice;
+								/* VID/PID */
+								cur_dev->vendor_id = dev_vid;
+								cur_dev->product_id = dev_pid;
 
-							/* Interface Number */
-							cur_dev->interface_number = interface_num;
+								/* Release Number */
+								cur_dev->release_number = desc.bcdDevice;
+
+								/* Interface Number */
+								cur_dev->interface_number = interface_num;
+								cur_dev->interface_class = intf_desc->bInterfaceClass;
+								cur_dev->interface_subclass = intf_desc->bInterfaceSubClass;
+								cur_dev->interface_protocol = intf_desc->bInterfaceProtocol;
+
+							} else
+								LOG("Can't open device 0x%.4x/0x%.4x during enumeration: %d\n", dev_vid, dev_pid, res);
 						}
 					}
 				} /* altsettings */
@@ -836,19 +790,19 @@
 
 	if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
 
-		struct input_report *rpt = (struct input_report *)malloc(sizeof(*rpt));
-		rpt->data = (uint8_t *)malloc(transfer->actual_length);
+		struct input_report *rpt = (struct input_report*) malloc(sizeof(*rpt));
+		rpt->data = (uint8_t*) malloc(transfer->actual_length);
 		memcpy(rpt->data, transfer->buffer, transfer->actual_length);
 		rpt->len = transfer->actual_length;
 		rpt->next = NULL;
 
-		pthread_mutex_lock(&dev->mutex);
+		SDL_LockMutex(dev->mutex);
 
 		/* Attach the new report object to the end of the list. */
 		if (dev->input_reports == NULL) {
 			/* The list is empty. Put it at the root. */
 			dev->input_reports = rpt;
-			pthread_cond_signal(&dev->condition);
+			SDL_CondSignal(dev->condition);
 		}
 		else {
 			/* Find the end of the list and attach. */
@@ -867,7 +821,7 @@
 				return_data(dev, NULL, 0);
 			}
 		}
-		pthread_mutex_unlock(&dev->mutex);
+		SDL_UnlockMutex(dev->mutex);
 	}
 	else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
 		dev->shutdown_thread = 1;
@@ -896,14 +850,14 @@
 }
 
 
-static void *read_thread(void *param)
+static int read_thread(void *param)
 {
 	hid_device *dev = (hid_device *)param;
-	unsigned char *buf;
+	uint8_t *buf;
 	const size_t length = dev->input_ep_max_packet_size;
 
 	/* Set up the transfer object. */
-	buf = (unsigned char *)malloc(length);
+	buf = (uint8_t*) malloc(length);
 	dev->transfer = libusb_alloc_transfer(0);
 	libusb_fill_interrupt_transfer(dev->transfer,
 		dev->device_handle,
@@ -919,7 +873,7 @@
 	libusb_submit_transfer(dev->transfer);
 
 	/* 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. */
 	while (!dev->shutdown_thread) {
@@ -951,9 +905,9 @@
 	   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
 	   signaled. */
-	pthread_mutex_lock(&dev->mutex);
-	pthread_cond_broadcast(&dev->condition);
-	pthread_mutex_unlock(&dev->mutex);
+	SDL_LockMutex(dev->mutex);
+	SDL_CondBroadcast(dev->condition);
+	SDL_UnlockMutex(dev->mutex);
 
 	/* The dev->transfer->buffer and dev->transfer objects are cleaned up
 	   in hid_close(). They are not cleaned up here because this thread
@@ -963,9 +917,42 @@
 	   since hid_close() calls libusb_cancel_transfer(), on these objects,
 	   they can not be cleaned up here. */
 
-	return NULL;
+	return 0;
 }
 
+static void init_xboxone(libusb_device_handle *device_handle, struct libusb_config_descriptor *conf_desc)
+{
+        static const int XB1_IFACE_SUBCLASS = 71;
+        static const int XB1_IFACE_PROTOCOL = 208;
+	int j, k, res;
+
+	for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+		const struct libusb_interface *intf = &conf_desc->interface[j];
+		for (k = 0; k < intf->num_altsetting; k++) {
+			const struct libusb_interface_descriptor *intf_desc;
+			intf_desc = &intf->altsetting[k];
+
+			if (intf_desc->bInterfaceNumber != 0 &&
+			    intf_desc->bAlternateSetting == 0 &&
+			    intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
+			    intf_desc->bInterfaceSubClass == XB1_IFACE_SUBCLASS &&
+			    intf_desc->bInterfaceProtocol == XB1_IFACE_PROTOCOL) {
+				res = libusb_claim_interface(device_handle, intf_desc->bInterfaceNumber);
+				if (res < 0) {
+					LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
+					continue;
+				}
+
+				res = libusb_set_interface_alt_setting(device_handle, intf_desc->bInterfaceNumber, intf_desc->bAlternateSetting);
+				if (res < 0) {
+					LOG("xbox init: can't set alt setting %d: %d\n", intf_desc->bInterfaceNumber, res);
+				}
+
+				libusb_release_interface(device_handle, intf_desc->bInterfaceNumber);
+			}
+		}
+	}
+}
 
 hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 {
@@ -987,9 +974,13 @@
 		struct libusb_device_descriptor desc;
 		struct libusb_config_descriptor *conf_desc = NULL;
 		int i,j,k;
+
 		libusb_get_device_descriptor(usb_dev, &desc);
 
-		if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)
+		res = libusb_get_active_config_descriptor(usb_dev, &conf_desc);
+		if (res < 0)
+			libusb_get_config_descriptor(usb_dev, 0, &conf_desc);
+		if (!conf_desc)
 			continue;
 		for (j = 0; j < conf_desc->bNumInterfaces; j++) {
 			const struct libusb_interface *intf = &conf_desc->interface[j];
@@ -999,6 +990,8 @@
 				if (should_enumerate_interface(desc.idVendor, intf_desc)) {
 					char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
 					if (!strcmp(dev_path, path)) {
+						int detached_driver = 0;
+
 						/* Matched Paths. Open this device */
 
 						/* OPEN HERE */
@@ -1009,6 +1002,7 @@
 							break;
 						}
 						good_open = 1;
+
 #ifdef DETACH_KERNEL_DRIVER
 						/* Detach the kernel driver, but only if the
 						   device is managed by the kernel */
@@ -1021,8 +1015,10 @@
 								good_open = 0;
 								break;
 							}
+							detached_driver = 1;
 						}
 #endif
+
 						res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
 						if (res < 0) {
 							LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
@@ -1032,6 +1028,11 @@
 							break;
 						}
 
+						/* Initialize XBox One controllers */
+						if (is_xboxone(desc.idVendor, intf_desc)) {
+							init_xboxone(dev->device_handle, conf_desc);
+						}
+
 						/* Store off the string descriptor indexes */
 						dev->manufacturer_index = desc.iManufacturer;
 						dev->product_index      = desc.iProduct;
@@ -1039,6 +1040,7 @@
 
 						/* Store off the interface number */
 						dev->interface = intf_desc->bInterfaceNumber;
+						dev->detached_driver = detached_driver;
 
 						/* Find the INPUT and OUTPUT endpoints. An
 						   OUTPUT endpoint is not required. */
@@ -1072,10 +1074,10 @@
 							}
 						}
 
-						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. */
-						pthread_barrier_wait(&dev->barrier);
+						SDL_WaitThreadBarrier(&dev->barrier);
 
 					}
 					free(dev_path);
@@ -1103,17 +1105,17 @@
 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
 {
 	int res;
-	int report_number = data[0];
-	int skipped_report_id = 0;
-
-	if (report_number == 0x0) {
-		data++;
-		length--;
-		skipped_report_id = 1;
-	}
-
 
 	if (dev->output_endpoint <= 0) {
+		int report_number = data[0];
+		int skipped_report_id = 0;
+
+		if (report_number == 0x0) {
+			data++;
+			length--;
+			skipped_report_id = 1;
+		}
+
 		/* No interrupt out endpoint. Use the Control Endpoint */
 		res = libusb_control_transfer(dev->device_handle,
 			LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
@@ -1143,9 +1145,6 @@
 		if (res < 0)
 			return -1;
 
-		if (skipped_report_id)
-			actual_length++;
-
 		return actual_length;
 	}
 }
@@ -1166,11 +1165,13 @@
 	return len;
 }
 
+#if 0 /* TODO: pthread_cleanup SDL? */
 static void cleanup_mutex(void *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)
@@ -1184,8 +1185,8 @@
 	return transferred;
 #endif
 
-	pthread_mutex_lock(&dev->mutex);
-	pthread_cleanup_push(&cleanup_mutex, dev);
+	SDL_LockMutex(dev->mutex);
+	/* TODO: pthread_cleanup SDL? */
 
 	/* There's an input report queued up. Return it. */
 	if (dev->input_reports) {
@@ -1204,7 +1205,7 @@
 	if (milliseconds == -1) {
 		/* Blocking */
 		while (!dev->input_reports && !dev->shutdown_thread) {
-			pthread_cond_wait(&dev->condition, &dev->mutex);
+			SDL_CondWait(dev->condition, dev->mutex);
 		}
 		if (dev->input_reports) {
 			bytes_read = return_data(dev, data, length);
@@ -1213,17 +1214,9 @@
 	else if (milliseconds > 0) {
 		/* Non-blocking, but called with timeout. */
 		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) {
-			res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
+			res = SDL_CondWaitTimeout(dev->condition, dev->mutex, milliseconds);
 			if (res == 0) {
 				if (dev->input_reports) {
 					bytes_read = return_data(dev, data, length);
@@ -1234,7 +1227,7 @@
 				   or the read thread was shutdown. Run the
 				   loop again (ie: don't break). */
 			}
-			else if (res == ETIMEDOUT) {
+			else if (res == SDL_MUTEX_TIMEDOUT) {
 				/* Timed out. */
 				bytes_read = 0;
 				break;
@@ -1252,8 +1245,8 @@
 	}
 
 ret:
-	pthread_mutex_unlock(&dev->mutex);
-	pthread_cleanup_pop(0);
+	SDL_UnlockMutex(dev->mutex);
+	/* TODO: pthread_cleanup SDL? */
 
 	return bytes_read;
 }
@@ -1334,6 +1327,8 @@
 
 void HID_API_EXPORT hid_close(hid_device *dev)
 {
+	int status;
+
 	if (!dev)
 		return;
 
@@ -1342,7 +1337,7 @@
 	libusb_cancel_transfer(dev->transfer);
 
 	/* 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(). */
 	free(dev->transfer->buffer);
@@ -1351,15 +1346,24 @@
 	/* release the interface */
 	libusb_release_interface(dev->device_handle, dev->interface);
 
+#ifdef DETACH_KERNEL_DRIVER
+	/* Re-attach kernel driver if necessary. */
+	if (dev->detached_driver) {
+		int res = libusb_attach_kernel_driver(dev->device_handle, dev->interface);
+		if (res < 0)
+			LOG("Couldn't re-attach kernel driver.\n");
+	}
+#endif
+
 	/* Close the handle */
 	libusb_close(dev->device_handle);
 
 	/* Clear out the queue of received reports. */
-	pthread_mutex_lock(&dev->mutex);
+	SDL_LockMutex(dev->mutex);
 	while (dev->input_reports) {
 		return_data(dev, NULL, 0);
 	}
-	pthread_mutex_unlock(&dev->mutex);
+	SDL_UnlockMutex(dev->mutex);
 
 	free_hid_device(dev);
 }
@@ -1452,7 +1456,7 @@
 	LANG("English - Ireland", "en_ie", 0x1809),
 	LANG("English - Jamaica", "en_jm", 0x2009),
 	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 - Trinidad", "en_tt", 0x2C09),
 	LANG("English - Great Britain", "en_gb", 0x0809),
@@ -1487,7 +1491,7 @@
 	LANG("Lithuanian", "lt", 0x0427),
 	LANG("F.Y.R.O. Macedonia", "mk", 0x042F),
 	LANG("Malay - Malaysia", "ms_my", 0x043E),
-	LANG("Malay – Brunei", "ms_bn", 0x083E),
+	LANG("Malay ??? Brunei", "ms_bn", 0x083E),
 	LANG("Maltese", "mt", 0x043A),
 	LANG("Marathi", "mr", 0x044E),
 	LANG("Norwegian - Bokml", "no_no", 0x0414),
@@ -1538,7 +1542,7 @@
 	LANG("Ukrainian", "uk", 0x0422),
 	LANG("Urdu", "ur", 0x0420),
 	LANG("Uzbek - Cyrillic", "uz_uz", 0x0843),
-	LANG("Uzbek – Latin", "uz_uz", 0x0443),
+	LANG("Uzbek ??? Latin", "uz_uz", 0x0443),
 	LANG("Vietnamese", "vi", 0x042A),
 	LANG("Xhosa", "xh", 0x0434),
 	LANG("Yiddish", "yi", 0x043D),

--
Gitblit v1.9.3