Skip to content

Commit 16715c4

Browse files
committed
Allow building using the SDL C runtime on Windows
1 parent d3013f0 commit 16715c4

File tree

2 files changed

+144
-58
lines changed

2 files changed

+144
-58
lines changed

libusb/hid.c

Lines changed: 142 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
https://github.com/libusb/hidapi .
2121
********************************************************/
2222

23+
#ifndef HIDAPI_USING_SDL_RUNTIME
2324
#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
2425

2526
/* C */
@@ -37,7 +38,6 @@
3738
#include <sys/ioctl.h>
3839
#include <sys/utsname.h>
3940
#include <fcntl.h>
40-
#include <pthread.h>
4141
#include <wchar.h>
4242

4343
/* GNU / LibUSB */
@@ -48,9 +48,43 @@
4848
#define ICONV_CONST
4949
#endif
5050
#endif
51+
#endif /* HIDAPI_USING_SDL_RUNTIME */
5152

5253
#include "hidapi_libusb.h"
5354

55+
#ifdef __cplusplus
56+
extern "C" {
57+
#endif
58+
59+
#ifdef DEBUG_PRINTF
60+
#define LOG(...) fprintf(stderr, __VA_ARGS__)
61+
#else
62+
#define LOG(...) do {} while (0)
63+
#endif
64+
65+
#ifndef __FreeBSD__
66+
#define DETACH_KERNEL_DRIVER
67+
#endif
68+
69+
/* Uncomment to enable the retrieval of Usage and Usage Page in
70+
hid_enumerate(). Warning, on platforms different from FreeBSD
71+
this is very invasive as it requires the detach
72+
and re-attach of the kernel driver. See comments inside hid_enumerate().
73+
libusb HIDAPI programs are encouraged to use the interface number
74+
instead to differentiate between interfaces on a composite HID device. */
75+
/*#define INVASIVE_GET_USAGE*/
76+
77+
/* Linked List of input reports received from the device. */
78+
struct input_report {
79+
uint8_t *data;
80+
size_t len;
81+
struct input_report *next;
82+
};
83+
84+
#ifndef HIDAPI_THREAD_STATE_DEFINED
85+
86+
#include <pthread.h>
87+
5488
#if defined(__ANDROID__) && __ANDROID_API__ < __ANDROID_API_N__
5589

5690
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
@@ -112,35 +146,92 @@ static int pthread_barrier_wait(pthread_barrier_t *barrier)
112146

113147
#endif
114148

115-
#ifdef __cplusplus
116-
extern "C" {
117-
#endif
149+
#define THREAD_STATE_WAIT_TIMED_OUT ETIMEDOUT
118150

119-
#ifdef DEBUG_PRINTF
120-
#define LOG(...) fprintf(stderr, __VA_ARGS__)
121-
#else
122-
#define LOG(...) do {} while (0)
123-
#endif
151+
typdef struct
152+
{
153+
pthread_t thread;
154+
pthread_mutex_t mutex; /* Protects input_reports */
155+
pthread_cond_t condition;
156+
pthread_barrier_t barrier; /* Ensures correct startup sequence */
124157

125-
#ifndef __FreeBSD__
126-
#define DETACH_KERNEL_DRIVER
127-
#endif
158+
} hid_device_thread_state;
128159

129-
/* Uncomment to enable the retrieval of Usage and Usage Page in
130-
hid_enumerate(). Warning, on platforms different from FreeBSD
131-
this is very invasive as it requires the detach
132-
and re-attach of the kernel driver. See comments inside hid_enumerate().
133-
libusb HIDAPI programs are encouraged to use the interface number
134-
instead to differentiate between interfaces on a composite HID device. */
135-
/*#define INVASIVE_GET_USAGE*/
160+
static void thread_state_init(hid_device_thread_state *state)
161+
{
162+
pthread_mutex_init(&state->mutex, NULL);
163+
pthread_cond_init(&state->condition, NULL);
164+
pthread_barrier_init(&state->barrier, NULL, 2);
165+
}
136166

137-
/* Linked List of input reports received from the device. */
138-
struct input_report {
139-
uint8_t *data;
140-
size_t len;
141-
struct input_report *next;
142-
};
167+
static void thread_state_free(hid_device_thread_state *state)
168+
{
169+
pthread_barrier_destroy(&state->barrier);
170+
pthread_cond_destroy(&state->condition);
171+
pthread_mutex_destroy(&state->mutex);
172+
}
173+
174+
static void thread_state_push_cleanup(void (*routine)(void *), void *arg)
175+
{
176+
pthread_cleanup_push(&cleanup_mutex, dev);
177+
}
178+
179+
static void thread_state_pop_cleanup(int execute)
180+
{
181+
pthread_cleanup_pop(execute);
182+
}
183+
184+
static void thread_state_lock(hid_device_thread_state *state)
185+
{
186+
pthread_mutex_lock(&state->mutex);
187+
}
188+
189+
static void thread_state_unlock(hid_device_thread_state *state)
190+
{
191+
pthread_mutex_unlock(&state->mutex);
192+
}
193+
194+
static void thread_state_wait_condition(hid_device_thread_state *state)
195+
{
196+
pthread_cond_wait(&state->condition, &state->mutex);
197+
}
198+
199+
static int thread_state_wait_condition_timeout(hid_device_thread_state *state, struct timespec *ts)
200+
{
201+
return pthread_cond_timedwait(&state->condition, &state->mutex, ts);
202+
}
203+
204+
static void thread_state_signal_condition(hid_device_thread_state *state)
205+
{
206+
pthread_cond_signal(&state->condition);
207+
}
143208

209+
static void thread_state_broadcast_condition(hid_device_thread_state *state)
210+
{
211+
pthread_cond_broadcast(&state->condition);
212+
}
213+
214+
static void thread_state_wait_barrier(hid_device_thread_state *state)
215+
{
216+
pthread_barrier_wait(&state->barrier);
217+
}
218+
219+
static void thread_state_create_thread(hid_device_thread_state *state, void *(*func)(void*), void *func_arg)
220+
{
221+
pthread_create(&dev->thread, NULL, func, param);
222+
}
223+
224+
static void thread_state_join_thread(hid_device_thread_state *state)
225+
{
226+
pthread_join(state->thread, NULL);
227+
}
228+
229+
static void thread_state_get_current_time(struct timespec *ts)
230+
{
231+
clock_gettime(CLOCK_REALTIME, ts);
232+
}
233+
234+
#endif /* !HIDAPI_THREAD_STATE_DEFINED */
144235

145236
struct hid_device_ {
146237
/* Handle to the actual device. */
@@ -168,10 +259,7 @@ struct hid_device_ {
168259
int blocking; /* boolean */
169260

170261
/* Read thread objects */
171-
pthread_t thread;
172-
pthread_mutex_t mutex; /* Protects input_reports */
173-
pthread_cond_t condition;
174-
pthread_barrier_t barrier; /* Ensures correct startup sequence */
262+
hid_device_thread_state thread_state;
175263
int shutdown_thread;
176264
int transfer_loop_finished;
177265
struct libusb_transfer *transfer;
@@ -201,19 +289,15 @@ static hid_device *new_hid_device(void)
201289
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
202290
dev->blocking = 1;
203291

204-
pthread_mutex_init(&dev->mutex, NULL);
205-
pthread_cond_init(&dev->condition, NULL);
206-
pthread_barrier_init(&dev->barrier, NULL, 2);
292+
thread_state_init(&dev->thread_state);
207293

208294
return dev;
209295
}
210296

211297
static void free_hid_device(hid_device *dev)
212298
{
213299
/* Clean up the thread objects */
214-
pthread_barrier_destroy(&dev->barrier);
215-
pthread_cond_destroy(&dev->condition);
216-
pthread_mutex_destroy(&dev->mutex);
300+
thread_state_free(&dev->thread_state);
217301

218302
hid_free_enumeration(dev->device_info);
219303

@@ -912,13 +996,13 @@ static void read_callback(struct libusb_transfer *transfer)
912996
rpt->len = transfer->actual_length;
913997
rpt->next = NULL;
914998

915-
pthread_mutex_lock(&dev->mutex);
999+
thread_state_lock(&dev->thread_state);
9161000

9171001
/* Attach the new report object to the end of the list. */
9181002
if (dev->input_reports == NULL) {
9191003
/* The list is empty. Put it at the root. */
9201004
dev->input_reports = rpt;
921-
pthread_cond_signal(&dev->condition);
1005+
thread_state_signal_condition(&dev->thread_state);
9221006
}
9231007
else {
9241008
/* Find the end of the list and attach. */
@@ -937,7 +1021,7 @@ static void read_callback(struct libusb_transfer *transfer)
9371021
return_data(dev, NULL, 0);
9381022
}
9391023
}
940-
pthread_mutex_unlock(&dev->mutex);
1024+
thread_state_unlock(&dev->thread_state);
9411025
}
9421026
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
9431027
dev->shutdown_thread = 1;
@@ -996,7 +1080,7 @@ static void *read_thread(void *param)
9961080
}
9971081

9981082
/* Notify the main thread that the read thread is up and running. */
999-
pthread_barrier_wait(&dev->barrier);
1083+
thread_state_wait_barrier(&dev->thread_state);
10001084

10011085
/* Handle all the events. */
10021086
while (!dev->shutdown_thread) {
@@ -1028,15 +1112,15 @@ static void *read_thread(void *param)
10281112
make sure that a thread which is about to go to sleep waiting on
10291113
the condition actually will go to sleep before the condition is
10301114
signaled. */
1031-
pthread_mutex_lock(&dev->mutex);
1032-
pthread_cond_broadcast(&dev->condition);
1033-
pthread_mutex_unlock(&dev->mutex);
1115+
thread_state_lock(&dev->thread_state);
1116+
thread_state_broadcast_condition(&dev->thread_state);
1117+
thread_state_unlock(&dev->thread_state);
10341118

10351119
/* The dev->transfer->buffer and dev->transfer objects are cleaned up
10361120
in hid_close(). They are not cleaned up here because this thread
10371121
could end either due to a disconnect or due to a user
10381122
call to hid_close(). In both cases the objects can be safely
1039-
cleaned up after the call to pthread_join() (in hid_close()), but
1123+
cleaned up after the call to thread_state_join() (in hid_close()), but
10401124
since hid_close() calls libusb_cancel_transfer(), on these objects,
10411125
they can not be cleaned up here. */
10421126

@@ -1128,15 +1212,15 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st
11281212
}
11291213
}
11301214

1131-
pthread_create(&dev->thread, NULL, read_thread, dev);
1215+
thread_state_create_thread(&dev->thread_state, read_thread, dev);
11321216

11331217
/* Wait here for the read thread to be initialized. */
1134-
pthread_barrier_wait(&dev->barrier);
1218+
thread_state_wait_barrier(&dev->thread_state);
11351219
return 1;
11361220
}
11371221

11381222

1139-
hid_device * HID_API_EXPORT hid_open_path(const char *path)
1223+
HID_API_EXPORT hid_device *hid_open_path(const char *path)
11401224
{
11411225
hid_device *dev = NULL;
11421226

@@ -1347,7 +1431,7 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length)
13471431
static void cleanup_mutex(void *param)
13481432
{
13491433
hid_device *dev = param;
1350-
pthread_mutex_unlock(&dev->mutex);
1434+
thread_state_unlock(&dev->thread_state);
13511435
}
13521436

13531437

@@ -1363,8 +1447,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13631447
/* error: variable ‘bytes_read’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered] */
13641448
int bytes_read; /* = -1; */
13651449

1366-
pthread_mutex_lock(&dev->mutex);
1367-
pthread_cleanup_push(&cleanup_mutex, dev);
1450+
thread_state_lock(&dev->thread_state);
1451+
thread_state_push_cleanup(cleanup_mutex, dev);
13681452

13691453
bytes_read = -1;
13701454

@@ -1385,7 +1469,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13851469
if (milliseconds == -1) {
13861470
/* Blocking */
13871471
while (!dev->input_reports && !dev->shutdown_thread) {
1388-
pthread_cond_wait(&dev->condition, &dev->mutex);
1472+
thread_state_wait_condition(&dev->thread_state);
13891473
}
13901474
if (dev->input_reports) {
13911475
bytes_read = return_data(dev, data, length);
@@ -1395,7 +1479,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13951479
/* Non-blocking, but called with timeout. */
13961480
int res;
13971481
struct timespec ts;
1398-
clock_gettime(CLOCK_REALTIME, &ts);
1482+
thread_state_get_current_time(&ts);
13991483
ts.tv_sec += milliseconds / 1000;
14001484
ts.tv_nsec += (milliseconds % 1000) * 1000000;
14011485
if (ts.tv_nsec >= 1000000000L) {
@@ -1404,7 +1488,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14041488
}
14051489

14061490
while (!dev->input_reports && !dev->shutdown_thread) {
1407-
res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
1491+
res = thread_state_wait_condition_timeout(&dev->thread_state, &ts);
14081492
if (res == 0) {
14091493
if (dev->input_reports) {
14101494
bytes_read = return_data(dev, data, length);
@@ -1415,7 +1499,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14151499
or the read thread was shutdown. Run the
14161500
loop again (ie: don't break). */
14171501
}
1418-
else if (res == ETIMEDOUT) {
1502+
else if (res == THREAD_STATE_WAIT_TIMED_OUT) {
14191503
/* Timed out. */
14201504
bytes_read = 0;
14211505
break;
@@ -1433,8 +1517,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14331517
}
14341518

14351519
ret:
1436-
pthread_mutex_unlock(&dev->mutex);
1437-
pthread_cleanup_pop(0);
1520+
thread_state_unlock(&dev->thread_state);
1521+
thread_state_pop_cleanup(0);
14381522

14391523
return bytes_read;
14401524
}
@@ -1552,7 +1636,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
15521636
libusb_cancel_transfer(dev->transfer);
15531637

15541638
/* Wait for read_thread() to end. */
1555-
pthread_join(dev->thread, NULL);
1639+
thread_state_join_thread(&dev->thread_state);
15561640

15571641
/* Clean up the Transfer objects allocated in read_thread(). */
15581642
free(dev->transfer->buffer);
@@ -1575,11 +1659,11 @@ void HID_API_EXPORT hid_close(hid_device *dev)
15751659
libusb_close(dev->device_handle);
15761660

15771661
/* Clear out the queue of received reports. */
1578-
pthread_mutex_lock(&dev->mutex);
1662+
thread_state_lock(&dev->thread_state);
15791663
while (dev->input_reports) {
15801664
return_data(dev, NULL, 0);
15811665
}
1582-
pthread_mutex_unlock(&dev->mutex);
1666+
thread_state_unlock(&dev->thread_state);
15831667

15841668
free_hid_device(dev);
15851669
}

windows/hid.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ typedef LONG NTSTATUS;
5656
#include "hidapi_hidclass.h"
5757
#include "hidapi_hidsdi.h"
5858

59+
#ifndef HIDAPI_USING_SDL_RUNTIME
5960
#include <stdio.h>
6061
#include <stdlib.h>
6162
#include <string.h>
63+
#endif
6264

6365
#ifdef MIN
6466
#undef MIN

0 commit comments

Comments
 (0)