Skip to content

Commit 698e430

Browse files
committed
hidapi/libusb: allow building on Windows, using the SDL C runtime
Signed-off-by: Sam Lantinga <slouken@libsdl.org>
1 parent a910b98 commit 698e430

File tree

2 files changed

+348
-58
lines changed

2 files changed

+348
-58
lines changed

src/hidapi/SDL_hidapi_libusb.h

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@
1919
3. This notice may not be removed or altered from any source distribution.
2020
*/
2121

22+
/* Define standard library functions in terms of SDL */
23+
#define HIDAPI_USING_SDL_RUNTIME
24+
#define free SDL_free
25+
#define iconv_t SDL_iconv_t
26+
#define ICONV_CONST
27+
#define iconv SDL_iconv
28+
#define iconv_open SDL_iconv_open
29+
#define iconv_close SDL_iconv_close
30+
#define malloc SDL_malloc
31+
#define realloc SDL_realloc
32+
#define setlocale(X, Y) NULL
33+
#define snprintf SDL_snprintf
34+
#define strcmp SDL_strcmp
35+
#define strdup SDL_strdup
36+
#define strncpy SDL_strlcpy
37+
#define tolower SDL_tolower
38+
#define wcsdup SDL_wcsdup
39+
40+
2241
#ifndef __FreeBSD__
2342
/* this is awkwardly inlined, so we need to re-implement it here
2443
* so we can override the libusb_control_transfer call */
@@ -32,5 +51,192 @@ static int SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
3251
#define libusb_get_string_descriptor SDL_libusb_get_string_descriptor
3352
#endif /* __FreeBSD__ */
3453

54+
#define HIDAPI_THREAD_STATE_DEFINED
55+
56+
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
57+
This implementation came from Brent Priddy and was posted on
58+
StackOverflow. It is used with his permission. */
59+
60+
typedef struct _SDL_ThreadBarrier
61+
{
62+
SDL_Mutex *mutex;
63+
SDL_Condition *cond;
64+
Uint32 count;
65+
Uint32 trip_count;
66+
} SDL_ThreadBarrier;
67+
68+
static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count)
69+
{
70+
SDL_assert(barrier != NULL);
71+
SDL_assert(count != 0);
72+
73+
barrier->mutex = SDL_CreateMutex();
74+
if (barrier->mutex == NULL) {
75+
return -1; /* Error set by CreateMutex */
76+
}
77+
barrier->cond = SDL_CreateCondition();
78+
if (barrier->cond == NULL) {
79+
return -1; /* Error set by CreateCond */
80+
}
81+
82+
barrier->trip_count = count;
83+
barrier->count = 0;
84+
85+
return 0;
86+
}
87+
88+
static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
89+
{
90+
SDL_DestroyCondition(barrier->cond);
91+
SDL_DestroyMutex(barrier->mutex);
92+
}
93+
94+
static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
95+
{
96+
SDL_LockMutex(barrier->mutex);
97+
barrier->count += 1;
98+
if (barrier->count >= barrier->trip_count) {
99+
barrier->count = 0;
100+
SDL_BroadcastCondition(barrier->cond);
101+
SDL_UnlockMutex(barrier->mutex);
102+
return 1;
103+
}
104+
SDL_WaitCondition(barrier->cond, barrier->mutex);
105+
SDL_UnlockMutex(barrier->mutex);
106+
return 0;
107+
}
108+
109+
#include "../thread/SDL_systhread.h"
110+
111+
#define THREAD_STATE_WAIT_TIMED_OUT SDL_MUTEX_TIMEDOUT
112+
113+
typedef struct
114+
{
115+
SDL_Thread *thread;
116+
SDL_Mutex *mutex; /* Protects input_reports */
117+
SDL_Condition *condition;
118+
SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
119+
120+
} hid_device_thread_state;
121+
122+
static void thread_state_init(hid_device_thread_state *state)
123+
{
124+
state->mutex = SDL_CreateMutex();
125+
state->condition = SDL_CreateCondition();
126+
SDL_CreateThreadBarrier(&state->barrier, 2);
127+
}
128+
129+
static void thread_state_free(hid_device_thread_state *state)
130+
{
131+
SDL_DestroyThreadBarrier(&state->barrier);
132+
SDL_DestroyCondition(state->condition);
133+
SDL_DestroyMutex(state->mutex);
134+
}
135+
136+
static SDL_TLSID libusb_thread_cleanup_routine;
137+
138+
static void thread_state_push_cleanup(void (*routine)(void *), void *arg)
139+
{
140+
/* This is only called in one place, so we can set a single thread-local value */
141+
if (!libusb_thread_cleanup_routine) {
142+
libusb_thread_cleanup_routine = SDL_TLSCreate();
143+
}
144+
SDL_TLSSet(libusb_thread_cleanup_routine, arg, routine);
145+
}
146+
147+
static void thread_state_pop_cleanup(int execute)
148+
{
149+
SDL_TLSSet(libusb_thread_cleanup_routine, NULL, NULL);
150+
}
151+
152+
static void thread_state_lock(hid_device_thread_state *state)
153+
{
154+
SDL_LockMutex(state->mutex);
155+
}
156+
157+
static void thread_state_unlock(hid_device_thread_state *state)
158+
{
159+
SDL_UnlockMutex(state->mutex);
160+
}
161+
162+
static void thread_state_wait_condition(hid_device_thread_state *state)
163+
{
164+
SDL_WaitCondition(state->condition, state->mutex);
165+
}
166+
167+
static int thread_state_wait_condition_timeout(hid_device_thread_state *state, struct timespec *ts)
168+
{
169+
Uint64 end_time;
170+
Sint64 timeout_ns;
171+
Sint32 timeout_ms;
172+
173+
end_time = ts->tv_sec;
174+
end_time *= 1000000000L;
175+
end_time += ts->tv_nsec;
176+
timeout_ns = (Sint64)(end_time - SDL_GetTicksNS());
177+
if (timeout_ns <= 0) {
178+
timeout_ms = 0;
179+
} else {
180+
timeout_ms = (Sint32)SDL_NS_TO_MS(timeout_ns);
181+
}
182+
return SDL_WaitConditionTimeout(state->condition, state->mutex, timeout_ms);
183+
}
184+
185+
static void thread_state_signal_condition(hid_device_thread_state *state)
186+
{
187+
SDL_SignalCondition(state->condition);
188+
}
189+
190+
static void thread_state_broadcast_condition(hid_device_thread_state *state)
191+
{
192+
SDL_BroadcastCondition(state->condition);
193+
}
194+
195+
static void thread_state_wait_barrier(hid_device_thread_state *state)
196+
{
197+
SDL_WaitThreadBarrier(&state->barrier);
198+
}
199+
200+
typedef struct
201+
{
202+
void *(*func)(void*);
203+
void *func_arg;
204+
205+
} RunInputThreadParam;
206+
207+
static int RunInputThread(void *param)
208+
{
209+
RunInputThreadParam *data = (RunInputThreadParam *)param;
210+
void *(*func)(void*) = data->func;
211+
void *func_arg = data->func_arg;
212+
SDL_free(data);
213+
func(func_arg);
214+
return 0;
215+
}
216+
217+
static void thread_state_create_thread(hid_device_thread_state *state, void *(*func)(void*), void *func_arg)
218+
{
219+
RunInputThreadParam *param = (RunInputThreadParam *)malloc(sizeof(*param));
220+
/* Note that the hidapi code didn't check for thread creation failure.
221+
* We'll crash if malloc() fails
222+
*/
223+
param->func = func;
224+
param->func_arg = func_arg;
225+
state->thread = SDL_CreateThreadInternal(RunInputThread, "libusb", 0, param);
226+
}
227+
228+
static void thread_state_join_thread(hid_device_thread_state *state)
229+
{
230+
SDL_WaitThread(state->thread, NULL);
231+
}
232+
233+
static void thread_state_get_current_time(struct timespec *ts)
234+
{
235+
Uint64 ns = SDL_GetTicksNS();
236+
237+
ts->tv_sec = ns / 1000000000L;
238+
ts->tv_nsec = ns % 1000000000L;
239+
}
240+
35241
#undef HIDAPI_H__
36242
#include "libusb/hid.c"

0 commit comments

Comments
 (0)