Port libusb hid.c to SDL, add to MinGW configure
authorEthan Lee <flibitijibibo@flibitijibibo.com>
Sun, 04 Aug 2019 00:01:38 -0400
changeset 12999a7ca9815bc79
parent 12998 b87ba0fad17e
child 13000 e6407f3ddba3
Port libusb hid.c to SDL, add to MinGW configure
configure
configure.ac
src/hidapi/libusb/hid.c
     1.1 --- a/configure	Mon Aug 05 12:35:32 2019 -0300
     1.2 +++ b/configure	Sun Aug 04 00:01:38 2019 -0400
     1.3 @@ -24121,10 +24121,6 @@
     1.4      # The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
     1.5      # so we'll just use libusb when it's available.
     1.6      case "$host" in
     1.7 -        # TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
     1.8 -        *-*-cygwin* | *-*-mingw32* )
     1.9 -            skiplibusb=yes
    1.10 -            ;;
    1.11          # libusb does not support iOS
    1.12          arm*-apple-darwin* | *-ios-* )
    1.13              skiplibusb=yes
     2.1 --- a/configure.ac	Mon Aug 05 12:35:32 2019 -0300
     2.2 +++ b/configure.ac	Sun Aug 04 00:01:38 2019 -0400
     2.3 @@ -3205,10 +3205,6 @@
     2.4      # The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
     2.5      # so we'll just use libusb when it's available.
     2.6      case "$host" in
     2.7 -        # TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
     2.8 -        *-*-cygwin* | *-*-mingw32* )
     2.9 -            skiplibusb=yes
    2.10 -            ;;
    2.11          # libusb does not support iOS
    2.12          arm*-apple-darwin* | *-ios-* )
    2.13              skiplibusb=yes
     3.1 --- a/src/hidapi/libusb/hid.c	Mon Aug 05 12:35:32 2019 -0300
     3.2 +++ b/src/hidapi/libusb/hid.c	Sun Aug 04 00:01:38 2019 -0400
     3.3 @@ -22,37 +22,18 @@
     3.4   code repository located at:
     3.5          https://github.com/libusb/hidapi .
     3.6  ********************************************************/
     3.7 +
     3.8 +/* This file is heavily modified from the original libusb.c, for portability.
     3.9 + * Last upstream update was from July 25, 2019, Git commit 93dca807.
    3.10 + */
    3.11 +
    3.12  #include "../../SDL_internal.h"
    3.13 +#include "SDL_thread.h"
    3.14 +#include "SDL_mutex.h"
    3.15  
    3.16  #ifdef SDL_JOYSTICK_HIDAPI
    3.17  
    3.18 -#ifndef _GNU_SOURCE
    3.19 -#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
    3.20 -#endif
    3.21 -
    3.22 -/* C */
    3.23 -#include <stdio.h>
    3.24 -#include <string.h>
    3.25 -#include <stdlib.h>
    3.26 -#include <ctype.h>
    3.27 -#include <locale.h>
    3.28 -#include <errno.h>
    3.29 -
    3.30 -/* Unix */
    3.31 -#include <unistd.h>
    3.32 -#include <sys/types.h>
    3.33 -#include <sys/stat.h>
    3.34 -#include <sys/ioctl.h>
    3.35 -#include <sys/utsname.h>
    3.36 -#include <fcntl.h>
    3.37 -#include <pthread.h>
    3.38 -#include <wchar.h>
    3.39 -
    3.40 -/* GNU / LibUSB */
    3.41  #include <libusb.h>
    3.42 -#ifndef __ANDROID__
    3.43 -#include <iconv.h>
    3.44 -#endif
    3.45  
    3.46  #include "hidapi.h"
    3.47  
    3.48 @@ -61,67 +42,63 @@
    3.49  {
    3.50  #endif
    3.51  
    3.52 -#ifdef __ANDROID__
    3.53 -
    3.54  /* Barrier implementation because Android/Bionic don't have pthread_barrier.
    3.55     This implementation came from Brent Priddy and was posted on
    3.56     StackOverflow. It is used with his permission. */
    3.57 -typedef int pthread_barrierattr_t;
    3.58 -typedef struct pthread_barrier {
    3.59 -    pthread_mutex_t mutex;
    3.60 -    pthread_cond_t cond;
    3.61 -    int count;
    3.62 -    int trip_count;
    3.63 -} pthread_barrier_t;
    3.64  
    3.65 -static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
    3.66 +typedef struct _SDL_ThreadBarrier
    3.67  {
    3.68 -	if(count == 0) {
    3.69 -		errno = EINVAL;
    3.70 -		return -1;
    3.71 +	SDL_mutex *mutex;
    3.72 +	SDL_cond *cond;
    3.73 +	Uint32 count;
    3.74 +	Uint32 trip_count;
    3.75 +} SDL_ThreadBarrier;
    3.76 +
    3.77 +static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count)
    3.78 +{
    3.79 +	if (barrier == NULL) {
    3.80 +		return SDL_SetError("barrier must be non-NULL");
    3.81 +	}
    3.82 +	if (count == 0) {
    3.83 +		return SDL_SetError("count must be > 0");
    3.84  	}
    3.85  
    3.86 -	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
    3.87 -		return -1;
    3.88 +	barrier->mutex = SDL_CreateMutex();
    3.89 +	if (barrier->mutex == NULL) {
    3.90 +		return -1; /* Error set by CreateMutex */
    3.91  	}
    3.92 -	if(pthread_cond_init(&barrier->cond, 0) < 0) {
    3.93 -		pthread_mutex_destroy(&barrier->mutex);
    3.94 -		return -1;
    3.95 +	barrier->cond = SDL_CreateCond();
    3.96 +	if (barrier->cond == NULL) {
    3.97 +		return -1; /* Error set by CreateCond */
    3.98  	}
    3.99 +
   3.100  	barrier->trip_count = count;
   3.101  	barrier->count = 0;
   3.102  
   3.103  	return 0;
   3.104  }
   3.105  
   3.106 -static int pthread_barrier_destroy(pthread_barrier_t *barrier)
   3.107 +static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
   3.108  {
   3.109 -	pthread_cond_destroy(&barrier->cond);
   3.110 -	pthread_mutex_destroy(&barrier->mutex);
   3.111 +	SDL_DestroyCond(barrier->cond);
   3.112 +	SDL_DestroyMutex(barrier->mutex);
   3.113 +}
   3.114 +
   3.115 +static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
   3.116 +{
   3.117 +	SDL_LockMutex(barrier->mutex);
   3.118 +	barrier->count += 1;
   3.119 +	if (barrier->count >= barrier->trip_count) {
   3.120 +		barrier->count = 0;
   3.121 +		SDL_CondBroadcast(barrier->cond);
   3.122 +		SDL_UnlockMutex(barrier->mutex);
   3.123 +		return 1;
   3.124 +	}
   3.125 +	SDL_CondWait(barrier->cond, barrier->mutex);
   3.126 +	SDL_UnlockMutex(barrier->mutex);
   3.127  	return 0;
   3.128  }
   3.129  
   3.130 -static int pthread_barrier_wait(pthread_barrier_t *barrier)
   3.131 -{
   3.132 -	pthread_mutex_lock(&barrier->mutex);
   3.133 -	++(barrier->count);
   3.134 -	if(barrier->count >= barrier->trip_count)
   3.135 -	{
   3.136 -		barrier->count = 0;
   3.137 -		pthread_cond_broadcast(&barrier->cond);
   3.138 -		pthread_mutex_unlock(&barrier->mutex);
   3.139 -		return 1;
   3.140 -	}
   3.141 -	else
   3.142 -	{
   3.143 -		pthread_cond_wait(&barrier->cond, &(barrier->mutex));
   3.144 -		pthread_mutex_unlock(&barrier->mutex);
   3.145 -		return 0;
   3.146 -	}
   3.147 -}
   3.148 -
   3.149 -#endif
   3.150 -
   3.151  #if defined(__cplusplus) && !defined(NAMESPACE)
   3.152  extern "C" {
   3.153  #endif
   3.154 @@ -173,10 +150,10 @@
   3.155  	int blocking; /* boolean */
   3.156  
   3.157  	/* Read thread objects */
   3.158 -	pthread_t thread;
   3.159 -	pthread_mutex_t mutex; /* Protects input_reports */
   3.160 -	pthread_cond_t condition;
   3.161 -	pthread_barrier_t barrier; /* Ensures correct startup sequence */
   3.162 +	SDL_Thread *thread;
   3.163 +	SDL_mutex *mutex; /* Protects input_reports */
   3.164 +	SDL_cond *condition;
   3.165 +	SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
   3.166  	int shutdown_thread;
   3.167  	int cancelled;
   3.168  	struct libusb_transfer *transfer;
   3.169 @@ -192,12 +169,12 @@
   3.170  
   3.171  static hid_device *new_hid_device(void)
   3.172  {
   3.173 -	hid_device *dev = (hid_device *)calloc(1, sizeof(hid_device));
   3.174 +	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
   3.175  	dev->blocking = 1;
   3.176  
   3.177 -	pthread_mutex_init(&dev->mutex, NULL);
   3.178 -	pthread_cond_init(&dev->condition, NULL);
   3.179 -	pthread_barrier_init(&dev->barrier, NULL, 2);
   3.180 +	dev->mutex = SDL_CreateMutex();
   3.181 +	dev->condition = SDL_CreateCond();
   3.182 +	SDL_CreateThreadBarrier(&dev->barrier, 2);
   3.183  
   3.184  	return dev;
   3.185  }
   3.186 @@ -205,17 +182,17 @@
   3.187  static void free_hid_device(hid_device *dev)
   3.188  {
   3.189  	/* Clean up the thread objects */
   3.190 -	pthread_barrier_destroy(&dev->barrier);
   3.191 -	pthread_cond_destroy(&dev->condition);
   3.192 -	pthread_mutex_destroy(&dev->mutex);
   3.193 +	SDL_DestroyThreadBarrier(&dev->barrier);
   3.194 +	SDL_DestroyCond(dev->condition);
   3.195 +	SDL_DestroyMutex(dev->mutex);
   3.196  
   3.197  	/* Free the device itself */
   3.198  	free(dev);
   3.199  }
   3.200  
   3.201  #if 0
   3.202 -/*TODO: Implement this funciton on hidapi/libusb.. */
   3.203 -static void register_error(hid_device *device, const char *op)
   3.204 +/*TODO: Implement this function on hidapi/libusb.. */
   3.205 +static void register_error(hid_device *dev, const char *op)
   3.206  {
   3.207  
   3.208  }
   3.209 @@ -400,20 +377,13 @@
   3.210  	int len;
   3.211  	wchar_t *str = NULL;
   3.212  
   3.213 -#ifndef __ANDROID__ /* we don't use iconv on Android */
   3.214  	wchar_t wbuf[256];
   3.215 -	/* iconv variables */
   3.216 -	iconv_t ic;
   3.217 +	SDL_iconv_t ic;
   3.218  	size_t inbytes;
   3.219  	size_t outbytes;
   3.220  	size_t res;
   3.221 -#ifdef __FreeBSD__
   3.222  	const char *inptr;
   3.223 -#else
   3.224 -	char *inptr;
   3.225 -#endif
   3.226  	char *outptr;
   3.227 -#endif
   3.228  
   3.229  	/* Determine which language to use. */
   3.230  	uint16_t lang;
   3.231 @@ -430,32 +400,13 @@
   3.232  	if (len < 0)
   3.233  		return NULL;
   3.234  
   3.235 -#ifdef __ANDROID__
   3.236 -
   3.237 -	/* Bionic does not have iconv support nor wcsdup() function, so it
   3.238 -	   has to be done manually.  The following code will only work for
   3.239 -	   code points that can be represented as a single UTF-16 character,
   3.240 -	   and will incorrectly convert any code points which require more
   3.241 -	   than one UTF-16 character.
   3.242 -
   3.243 -	   Skip over the first character (2-bytes).  */
   3.244 -	len -= 2;
   3.245 -	str = malloc((len / 2 + 1) * sizeof(wchar_t));
   3.246 -	int i;
   3.247 -	for (i = 0; i < len / 2; i++) {
   3.248 -		str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
   3.249 -	}
   3.250 -	str[len / 2] = 0x00000000;
   3.251 -
   3.252 -#else
   3.253 -
   3.254  	/* buf does not need to be explicitly NULL-terminated because
   3.255  	   it is only passed into iconv() which does not need it. */
   3.256  
   3.257  	/* Initialize iconv. */
   3.258 -	ic = iconv_open("WCHAR_T", "UTF-16LE");
   3.259 -	if (ic == (iconv_t)-1) {
   3.260 -		LOG("iconv_open() failed\n");
   3.261 +	ic = SDL_iconv_open("WCHAR_T", "UTF-16LE");
   3.262 +	if (ic == (SDL_iconv_t)-1) {
   3.263 +		LOG("SDL_iconv_open() failed\n");
   3.264  		return NULL;
   3.265  	}
   3.266  
   3.267 @@ -465,9 +416,9 @@
   3.268  	inbytes = len-2;
   3.269  	outptr = (char*) wbuf;
   3.270  	outbytes = sizeof(wbuf);
   3.271 -	res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
   3.272 +	res = SDL_iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
   3.273  	if (res == (size_t)-1) {
   3.274 -		LOG("iconv() failed\n");
   3.275 +		LOG("SDL_iconv() failed\n");
   3.276  		goto err;
   3.277  	}
   3.278  
   3.279 @@ -480,9 +431,7 @@
   3.280  	str = wcsdup(wbuf);
   3.281  
   3.282  err:
   3.283 -	iconv_close(ic);
   3.284 -
   3.285 -#endif
   3.286 +	SDL_iconv_close(ic);
   3.287  
   3.288  	return str;
   3.289  }
   3.290 @@ -503,16 +452,20 @@
   3.291  int HID_API_EXPORT hid_init(void)
   3.292  {
   3.293  	if (!usb_context) {
   3.294 +#ifndef _WIN32 /* TODO: Win32 setlocale */
   3.295  		const char *locale;
   3.296 +#endif /* _WIN32 */
   3.297  
   3.298  		/* Init Libusb */
   3.299  		if (libusb_init(&usb_context))
   3.300  			return -1;
   3.301  
   3.302 +#ifndef _WIN32 /* TODO: Win32 setlocale */
   3.303  		/* Set the locale if it's not set. */
   3.304  		locale = setlocale(LC_CTYPE, NULL);
   3.305  		if (!locale)
   3.306  			setlocale(LC_CTYPE, "");
   3.307 +#endif /* _WIN32 */
   3.308  	}
   3.309  
   3.310  	return 0;
   3.311 @@ -663,7 +616,7 @@
   3.312  							struct hid_device_info *tmp;
   3.313  
   3.314  							/* VID/PID match. Create the record. */
   3.315 -							tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
   3.316 +							tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
   3.317  							if (cur_dev) {
   3.318  								cur_dev->next = tmp;
   3.319  							}
   3.320 @@ -836,19 +789,19 @@
   3.321  
   3.322  	if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
   3.323  
   3.324 -		struct input_report *rpt = (struct input_report *)malloc(sizeof(*rpt));
   3.325 -		rpt->data = (uint8_t *)malloc(transfer->actual_length);
   3.326 +		struct input_report *rpt = (struct input_report*) malloc(sizeof(*rpt));
   3.327 +		rpt->data = (uint8_t*) malloc(transfer->actual_length);
   3.328  		memcpy(rpt->data, transfer->buffer, transfer->actual_length);
   3.329  		rpt->len = transfer->actual_length;
   3.330  		rpt->next = NULL;
   3.331  
   3.332 -		pthread_mutex_lock(&dev->mutex);
   3.333 +		SDL_LockMutex(dev->mutex);
   3.334  
   3.335  		/* Attach the new report object to the end of the list. */
   3.336  		if (dev->input_reports == NULL) {
   3.337  			/* The list is empty. Put it at the root. */
   3.338  			dev->input_reports = rpt;
   3.339 -			pthread_cond_signal(&dev->condition);
   3.340 +			SDL_CondSignal(dev->condition);
   3.341  		}
   3.342  		else {
   3.343  			/* Find the end of the list and attach. */
   3.344 @@ -867,7 +820,7 @@
   3.345  				return_data(dev, NULL, 0);
   3.346  			}
   3.347  		}
   3.348 -		pthread_mutex_unlock(&dev->mutex);
   3.349 +		SDL_UnlockMutex(dev->mutex);
   3.350  	}
   3.351  	else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
   3.352  		dev->shutdown_thread = 1;
   3.353 @@ -896,14 +849,14 @@
   3.354  }
   3.355  
   3.356  
   3.357 -static void *read_thread(void *param)
   3.358 +static int read_thread(void *param)
   3.359  {
   3.360  	hid_device *dev = (hid_device *)param;
   3.361 -	unsigned char *buf;
   3.362 +	uint8_t *buf;
   3.363  	const size_t length = dev->input_ep_max_packet_size;
   3.364  
   3.365  	/* Set up the transfer object. */
   3.366 -	buf = (unsigned char *)malloc(length);
   3.367 +	buf = (uint8_t*) malloc(length);
   3.368  	dev->transfer = libusb_alloc_transfer(0);
   3.369  	libusb_fill_interrupt_transfer(dev->transfer,
   3.370  		dev->device_handle,
   3.371 @@ -919,7 +872,7 @@
   3.372  	libusb_submit_transfer(dev->transfer);
   3.373  
   3.374  	/* Notify the main thread that the read thread is up and running. */
   3.375 -	pthread_barrier_wait(&dev->barrier);
   3.376 +	SDL_WaitThreadBarrier(&dev->barrier);
   3.377  
   3.378  	/* Handle all the events. */
   3.379  	while (!dev->shutdown_thread) {
   3.380 @@ -951,9 +904,9 @@
   3.381  	   make sure that a thread which is about to go to sleep waiting on
   3.382  	   the condition actually will go to sleep before the condition is
   3.383  	   signaled. */
   3.384 -	pthread_mutex_lock(&dev->mutex);
   3.385 -	pthread_cond_broadcast(&dev->condition);
   3.386 -	pthread_mutex_unlock(&dev->mutex);
   3.387 +	SDL_LockMutex(dev->mutex);
   3.388 +	SDL_CondBroadcast(dev->condition);
   3.389 +	SDL_UnlockMutex(dev->mutex);
   3.390  
   3.391  	/* The dev->transfer->buffer and dev->transfer objects are cleaned up
   3.392  	   in hid_close(). They are not cleaned up here because this thread
   3.393 @@ -963,7 +916,7 @@
   3.394  	   since hid_close() calls libusb_cancel_transfer(), on these objects,
   3.395  	   they can not be cleaned up here. */
   3.396  
   3.397 -	return NULL;
   3.398 +	return 0;
   3.399  }
   3.400  
   3.401  
   3.402 @@ -1072,10 +1025,10 @@
   3.403  							}
   3.404  						}
   3.405  
   3.406 -						pthread_create(&dev->thread, NULL, read_thread, dev);
   3.407 +						dev->thread = SDL_CreateThread(read_thread, NULL, dev);
   3.408  
   3.409  						/* Wait here for the read thread to be initialized. */
   3.410 -						pthread_barrier_wait(&dev->barrier);
   3.411 +						SDL_WaitThreadBarrier(&dev->barrier);
   3.412  
   3.413  					}
   3.414  					free(dev_path);
   3.415 @@ -1166,11 +1119,13 @@
   3.416  	return len;
   3.417  }
   3.418  
   3.419 +#if 0 /* TODO: pthread_cleanup SDL? */
   3.420  static void cleanup_mutex(void *param)
   3.421  {
   3.422  	hid_device *dev = (hid_device *)param;
   3.423 -	pthread_mutex_unlock(&dev->mutex);
   3.424 +	SDL_UnlockMutex(dev->mutex);
   3.425  }
   3.426 +#endif
   3.427  
   3.428  
   3.429  int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
   3.430 @@ -1184,8 +1139,8 @@
   3.431  	return transferred;
   3.432  #endif
   3.433  
   3.434 -	pthread_mutex_lock(&dev->mutex);
   3.435 -	pthread_cleanup_push(&cleanup_mutex, dev);
   3.436 +	SDL_LockMutex(dev->mutex);
   3.437 +	/* TODO: pthread_cleanup SDL? */
   3.438  
   3.439  	/* There's an input report queued up. Return it. */
   3.440  	if (dev->input_reports) {
   3.441 @@ -1204,7 +1159,7 @@
   3.442  	if (milliseconds == -1) {
   3.443  		/* Blocking */
   3.444  		while (!dev->input_reports && !dev->shutdown_thread) {
   3.445 -			pthread_cond_wait(&dev->condition, &dev->mutex);
   3.446 +			SDL_CondWait(dev->condition, dev->mutex);
   3.447  		}
   3.448  		if (dev->input_reports) {
   3.449  			bytes_read = return_data(dev, data, length);
   3.450 @@ -1213,17 +1168,9 @@
   3.451  	else if (milliseconds > 0) {
   3.452  		/* Non-blocking, but called with timeout. */
   3.453  		int res;
   3.454 -		struct timespec ts;
   3.455 -		clock_gettime(CLOCK_REALTIME, &ts);
   3.456 -		ts.tv_sec += milliseconds / 1000;
   3.457 -		ts.tv_nsec += (milliseconds % 1000) * 1000000;
   3.458 -		if (ts.tv_nsec >= 1000000000L) {
   3.459 -			ts.tv_sec++;
   3.460 -			ts.tv_nsec -= 1000000000L;
   3.461 -		}
   3.462  
   3.463  		while (!dev->input_reports && !dev->shutdown_thread) {
   3.464 -			res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
   3.465 +			res = SDL_CondWaitTimeout(dev->condition, dev->mutex, milliseconds);
   3.466  			if (res == 0) {
   3.467  				if (dev->input_reports) {
   3.468  					bytes_read = return_data(dev, data, length);
   3.469 @@ -1234,7 +1181,7 @@
   3.470  				   or the read thread was shutdown. Run the
   3.471  				   loop again (ie: don't break). */
   3.472  			}
   3.473 -			else if (res == ETIMEDOUT) {
   3.474 +			else if (res == SDL_MUTEX_TIMEDOUT) {
   3.475  				/* Timed out. */
   3.476  				bytes_read = 0;
   3.477  				break;
   3.478 @@ -1252,8 +1199,8 @@
   3.479  	}
   3.480  
   3.481  ret:
   3.482 -	pthread_mutex_unlock(&dev->mutex);
   3.483 -	pthread_cleanup_pop(0);
   3.484 +	SDL_UnlockMutex(dev->mutex);
   3.485 +	/* TODO: pthread_cleanup SDL? */
   3.486  
   3.487  	return bytes_read;
   3.488  }
   3.489 @@ -1334,6 +1281,8 @@
   3.490  
   3.491  void HID_API_EXPORT hid_close(hid_device *dev)
   3.492  {
   3.493 +	int status;
   3.494 +
   3.495  	if (!dev)
   3.496  		return;
   3.497  
   3.498 @@ -1342,7 +1291,7 @@
   3.499  	libusb_cancel_transfer(dev->transfer);
   3.500  
   3.501  	/* Wait for read_thread() to end. */
   3.502 -	pthread_join(dev->thread, NULL);
   3.503 +	SDL_WaitThread(dev->thread, &status);
   3.504  
   3.505  	/* Clean up the Transfer objects allocated in read_thread(). */
   3.506  	free(dev->transfer->buffer);
   3.507 @@ -1355,11 +1304,11 @@
   3.508  	libusb_close(dev->device_handle);
   3.509  
   3.510  	/* Clear out the queue of received reports. */
   3.511 -	pthread_mutex_lock(&dev->mutex);
   3.512 +	SDL_LockMutex(dev->mutex);
   3.513  	while (dev->input_reports) {
   3.514  		return_data(dev, NULL, 0);
   3.515  	}
   3.516 -	pthread_mutex_unlock(&dev->mutex);
   3.517 +	SDL_UnlockMutex(dev->mutex);
   3.518  
   3.519  	free_hid_device(dev);
   3.520  }
   3.521 @@ -1408,6 +1357,7 @@
   3.522  	uint16_t usb_code;
   3.523  };
   3.524  
   3.525 +#ifndef _WIN32 /* TODO: Win32 setlocale */
   3.526  #define LANG(name,code,usb_code) { name, code, usb_code }
   3.527  static struct lang_map_entry lang_map[] = {
   3.528  	LANG("Afrikaans", "af", 0x0436),
   3.529 @@ -1452,7 +1402,7 @@
   3.530  	LANG("English - Ireland", "en_ie", 0x1809),
   3.531  	LANG("English - Jamaica", "en_jm", 0x2009),
   3.532  	LANG("English - New Zealand", "en_nz", 0x1409),
   3.533 -	LANG("English - Phillippines", "en_ph", 0x3409),
   3.534 +	LANG("English - Philippines", "en_ph", 0x3409),
   3.535  	LANG("English - Southern Africa", "en_za", 0x1C09),
   3.536  	LANG("English - Trinidad", "en_tt", 0x2C09),
   3.537  	LANG("English - Great Britain", "en_gb", 0x0809),
   3.538 @@ -1545,9 +1495,11 @@
   3.539  	LANG("Zulu", "zu", 0x0435),
   3.540  	LANG(NULL, NULL, 0x0),
   3.541  };
   3.542 +#endif /* _WIN32 */
   3.543  
   3.544  uint16_t get_usb_code_for_current_locale(void)
   3.545  {
   3.546 +#ifndef _WIN32 /* TODO: Win32 setlocale? */
   3.547  	char *locale;
   3.548  	char search_string[64];
   3.549  	char *ptr;
   3.550 @@ -1605,6 +1557,7 @@
   3.551  	}
   3.552  #endif
   3.553  
   3.554 +#endif /* _WIN32 */
   3.555  	/* Found nothing. */
   3.556  	return 0x0;
   3.557  }