Skip to content

Commit 1ffe07e

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

File tree

2 files changed

+137
-58
lines changed

2 files changed

+137
-58
lines changed

libusb/hid.c

Lines changed: 135 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,85 @@ 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+
typedef 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+
#define thread_state_push_cleanup pthread_cleanup_push
175+
#define thread_state_pop_cleanup pthread_cleanup_pop
176+
177+
static void thread_state_lock(hid_device_thread_state *state)
178+
{
179+
pthread_mutex_lock(&state->mutex);
180+
}
181+
182+
static void thread_state_unlock(hid_device_thread_state *state)
183+
{
184+
pthread_mutex_unlock(&state->mutex);
185+
}
186+
187+
static void thread_state_wait_condition(hid_device_thread_state *state)
188+
{
189+
pthread_cond_wait(&state->condition, &state->mutex);
190+
}
143191

192+
static int thread_state_wait_condition_timeout(hid_device_thread_state *state, struct timespec *ts)
193+
{
194+
return pthread_cond_timedwait(&state->condition, &state->mutex, ts);
195+
}
196+
197+
static void thread_state_signal_condition(hid_device_thread_state *state)
198+
{
199+
pthread_cond_signal(&state->condition);
200+
}
201+
202+
static void thread_state_broadcast_condition(hid_device_thread_state *state)
203+
{
204+
pthread_cond_broadcast(&state->condition);
205+
}
206+
207+
static void thread_state_wait_barrier(hid_device_thread_state *state)
208+
{
209+
pthread_barrier_wait(&state->barrier);
210+
}
211+
212+
static void thread_state_create_thread(hid_device_thread_state *state, void *(*func)(void*), void *func_arg)
213+
{
214+
pthread_create(&state->thread, NULL, func, func_arg);
215+
}
216+
217+
static void thread_state_join_thread(hid_device_thread_state *state)
218+
{
219+
pthread_join(state->thread, NULL);
220+
}
221+
222+
static void thread_state_get_current_time(struct timespec *ts)
223+
{
224+
clock_gettime(CLOCK_REALTIME, ts);
225+
}
226+
227+
#endif /* !HIDAPI_THREAD_STATE_DEFINED */
144228

145229
struct hid_device_ {
146230
/* Handle to the actual device. */
@@ -168,10 +252,7 @@ struct hid_device_ {
168252
int blocking; /* boolean */
169253

170254
/* 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 */
255+
hid_device_thread_state thread_state;
175256
int shutdown_thread;
176257
int transfer_loop_finished;
177258
struct libusb_transfer *transfer;
@@ -201,19 +282,15 @@ static hid_device *new_hid_device(void)
201282
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
202283
dev->blocking = 1;
203284

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

208287
return dev;
209288
}
210289

211290
static void free_hid_device(hid_device *dev)
212291
{
213292
/* Clean up the thread objects */
214-
pthread_barrier_destroy(&dev->barrier);
215-
pthread_cond_destroy(&dev->condition);
216-
pthread_mutex_destroy(&dev->mutex);
293+
thread_state_free(&dev->thread_state);
217294

218295
hid_free_enumeration(dev->device_info);
219296

@@ -912,13 +989,13 @@ static void read_callback(struct libusb_transfer *transfer)
912989
rpt->len = transfer->actual_length;
913990
rpt->next = NULL;
914991

915-
pthread_mutex_lock(&dev->mutex);
992+
thread_state_lock(&dev->thread_state);
916993

917994
/* Attach the new report object to the end of the list. */
918995
if (dev->input_reports == NULL) {
919996
/* The list is empty. Put it at the root. */
920997
dev->input_reports = rpt;
921-
pthread_cond_signal(&dev->condition);
998+
thread_state_signal_condition(&dev->thread_state);
922999
}
9231000
else {
9241001
/* Find the end of the list and attach. */
@@ -937,7 +1014,7 @@ static void read_callback(struct libusb_transfer *transfer)
9371014
return_data(dev, NULL, 0);
9381015
}
9391016
}
940-
pthread_mutex_unlock(&dev->mutex);
1017+
thread_state_unlock(&dev->thread_state);
9411018
}
9421019
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
9431020
dev->shutdown_thread = 1;
@@ -996,7 +1073,7 @@ static void *read_thread(void *param)
9961073
}
9971074

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

10011078
/* Handle all the events. */
10021079
while (!dev->shutdown_thread) {
@@ -1028,15 +1105,15 @@ static void *read_thread(void *param)
10281105
make sure that a thread which is about to go to sleep waiting on
10291106
the condition actually will go to sleep before the condition is
10301107
signaled. */
1031-
pthread_mutex_lock(&dev->mutex);
1032-
pthread_cond_broadcast(&dev->condition);
1033-
pthread_mutex_unlock(&dev->mutex);
1108+
thread_state_lock(&dev->thread_state);
1109+
thread_state_broadcast_condition(&dev->thread_state);
1110+
thread_state_unlock(&dev->thread_state);
10341111

10351112
/* The dev->transfer->buffer and dev->transfer objects are cleaned up
10361113
in hid_close(). They are not cleaned up here because this thread
10371114
could end either due to a disconnect or due to a user
10381115
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
1116+
cleaned up after the call to thread_state_join() (in hid_close()), but
10401117
since hid_close() calls libusb_cancel_transfer(), on these objects,
10411118
they can not be cleaned up here. */
10421119

@@ -1128,15 +1205,15 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st
11281205
}
11291206
}
11301207

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

11331210
/* Wait here for the read thread to be initialized. */
1134-
pthread_barrier_wait(&dev->barrier);
1211+
thread_state_wait_barrier(&dev->thread_state);
11351212
return 1;
11361213
}
11371214

11381215

1139-
hid_device * HID_API_EXPORT hid_open_path(const char *path)
1216+
HID_API_EXPORT hid_device *hid_open_path(const char *path)
11401217
{
11411218
hid_device *dev = NULL;
11421219

@@ -1347,7 +1424,7 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length)
13471424
static void cleanup_mutex(void *param)
13481425
{
13491426
hid_device *dev = param;
1350-
pthread_mutex_unlock(&dev->mutex);
1427+
thread_state_unlock(&dev->thread_state);
13511428
}
13521429

13531430

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

1366-
pthread_mutex_lock(&dev->mutex);
1367-
pthread_cleanup_push(&cleanup_mutex, dev);
1443+
thread_state_lock(&dev->thread_state);
1444+
thread_state_push_cleanup(cleanup_mutex, dev);
13681445

13691446
bytes_read = -1;
13701447

@@ -1385,7 +1462,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13851462
if (milliseconds == -1) {
13861463
/* Blocking */
13871464
while (!dev->input_reports && !dev->shutdown_thread) {
1388-
pthread_cond_wait(&dev->condition, &dev->mutex);
1465+
thread_state_wait_condition(&dev->thread_state);
13891466
}
13901467
if (dev->input_reports) {
13911468
bytes_read = return_data(dev, data, length);
@@ -1395,7 +1472,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13951472
/* Non-blocking, but called with timeout. */
13961473
int res;
13971474
struct timespec ts;
1398-
clock_gettime(CLOCK_REALTIME, &ts);
1475+
thread_state_get_current_time(&ts);
13991476
ts.tv_sec += milliseconds / 1000;
14001477
ts.tv_nsec += (milliseconds % 1000) * 1000000;
14011478
if (ts.tv_nsec >= 1000000000L) {
@@ -1404,7 +1481,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14041481
}
14051482

14061483
while (!dev->input_reports && !dev->shutdown_thread) {
1407-
res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
1484+
res = thread_state_wait_condition_timeout(&dev->thread_state, &ts);
14081485
if (res == 0) {
14091486
if (dev->input_reports) {
14101487
bytes_read = return_data(dev, data, length);
@@ -1415,7 +1492,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14151492
or the read thread was shutdown. Run the
14161493
loop again (ie: don't break). */
14171494
}
1418-
else if (res == ETIMEDOUT) {
1495+
else if (res == THREAD_STATE_WAIT_TIMED_OUT) {
14191496
/* Timed out. */
14201497
bytes_read = 0;
14211498
break;
@@ -1433,8 +1510,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
14331510
}
14341511

14351512
ret:
1436-
pthread_mutex_unlock(&dev->mutex);
1437-
pthread_cleanup_pop(0);
1513+
thread_state_unlock(&dev->thread_state);
1514+
thread_state_pop_cleanup(0);
14381515

14391516
return bytes_read;
14401517
}
@@ -1552,7 +1629,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
15521629
libusb_cancel_transfer(dev->transfer);
15531630

15541631
/* Wait for read_thread() to end. */
1555-
pthread_join(dev->thread, NULL);
1632+
thread_state_join_thread(&dev->thread_state);
15561633

15571634
/* Clean up the Transfer objects allocated in read_thread(). */
15581635
free(dev->transfer->buffer);
@@ -1575,11 +1652,11 @@ void HID_API_EXPORT hid_close(hid_device *dev)
15751652
libusb_close(dev->device_handle);
15761653

15771654
/* Clear out the queue of received reports. */
1578-
pthread_mutex_lock(&dev->mutex);
1655+
thread_state_lock(&dev->thread_state);
15791656
while (dev->input_reports) {
15801657
return_data(dev, NULL, 0);
15811658
}
1582-
pthread_mutex_unlock(&dev->mutex);
1659+
thread_state_unlock(&dev->thread_state);
15831660

15841661
free_hid_device(dev);
15851662
}

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)