22 #include "../../SDL_internal.h" 24 #ifdef SDL_JOYSTICK_HIDAPI 28 #include <IOKit/hid/IOHIDManager.h> 29 #include <IOKit/hid/IOHIDKeys.h> 30 #include <CoreFoundation/CoreFoundation.h> 43 typedef int pthread_barrierattr_t;
44 typedef struct pthread_barrier {
45 pthread_mutex_t
mutex;
51 static int pthread_barrier_init(pthread_barrier_t *barrier,
const pthread_barrierattr_t *attr,
unsigned int count)
58 if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
61 if(pthread_cond_init(&barrier->cond, 0) < 0) {
62 pthread_mutex_destroy(&barrier->mutex);
65 barrier->trip_count =
count;
71 static int pthread_barrier_destroy(pthread_barrier_t *barrier)
73 pthread_cond_destroy(&barrier->cond);
74 pthread_mutex_destroy(&barrier->mutex);
78 static int pthread_barrier_wait(pthread_barrier_t *barrier)
80 pthread_mutex_lock(&barrier->mutex);
82 if(barrier->count >= barrier->trip_count)
85 pthread_cond_broadcast(&barrier->cond);
86 pthread_mutex_unlock(&barrier->mutex);
91 pthread_cond_wait(&barrier->cond, &(barrier->mutex));
92 pthread_mutex_unlock(&barrier->mutex);
97 static int return_data(hid_device *dev,
unsigned char *
data,
size_t length);
100 struct input_report {
103 struct input_report *next;
107 IOHIDDeviceRef device_handle;
109 int uses_numbered_reports;
111 CFStringRef run_loop_mode;
112 CFRunLoopRef run_loop;
113 CFRunLoopSourceRef
source;
115 CFIndex max_input_report_len;
116 struct input_report *input_reports;
119 pthread_mutex_t
mutex;
121 pthread_barrier_t barrier;
122 pthread_barrier_t shutdown_barrier;
131 static hid_device *device_list =
NULL;
132 static pthread_mutex_t device_list_mutex = PTHREAD_MUTEX_INITIALIZER;
134 static hid_device *new_hid_device(
void)
136 hid_device *dev = (hid_device*)calloc(1,
sizeof(hid_device));
137 dev->device_handle =
NULL;
139 dev->uses_numbered_reports = 0;
140 dev->disconnected = 0;
141 dev->run_loop_mode =
NULL;
142 dev->run_loop =
NULL;
144 dev->input_report_buf =
NULL;
145 dev->input_reports =
NULL;
146 dev->shutdown_thread = 0;
150 pthread_mutex_init(&dev->mutex,
NULL);
151 pthread_cond_init(&dev->condition,
NULL);
152 pthread_barrier_init(&dev->barrier,
NULL, 2);
153 pthread_barrier_init(&dev->shutdown_barrier,
NULL, 2);
156 pthread_mutex_lock(&device_list_mutex);
160 hid_device *
d = device_list;
169 pthread_mutex_unlock(&device_list_mutex);
174 static void free_hid_device(hid_device *dev)
180 struct input_report *rpt = dev->input_reports;
182 struct input_report *next = rpt->next;
191 if (dev->run_loop_mode)
192 CFRelease(dev->run_loop_mode);
194 CFRelease(dev->source);
195 free(dev->input_report_buf);
198 pthread_barrier_destroy(&dev->shutdown_barrier);
199 pthread_barrier_destroy(&dev->barrier);
200 pthread_cond_destroy(&dev->condition);
201 pthread_mutex_destroy(&dev->mutex);
204 pthread_mutex_lock(&device_list_mutex);
205 hid_device *d = device_list;
207 device_list = d->next;
211 if (d->next == dev) {
212 d->next = d->next->next;
219 pthread_mutex_unlock(&device_list_mutex);
225 static IOHIDManagerRef hid_mgr = 0x0;
229 static void register_error(hid_device *
device,
const char *op)
241 ref = IOHIDDeviceGetProperty(device, key);
243 if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
244 CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);
251 static unsigned short get_vendor_id(IOHIDDeviceRef device)
253 return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
256 static unsigned short get_product_id(IOHIDDeviceRef device)
258 return get_int_property(device, CFSTR(kIOHIDProductIDKey));
262 static int32_t get_max_report_length(IOHIDDeviceRef device)
264 return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
267 static int get_string_property(IOHIDDeviceRef device, CFStringRef prop,
wchar_t *
buf,
size_t len)
274 str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
281 CFIndex str_len = CFStringGetLength(str);
284 range.length = (str_len >
len)? len: str_len;
285 CFIndex used_buf_len;
286 CFIndex chars_copied;
287 chars_copied = CFStringGetBytes(str,
289 kCFStringEncodingUTF32LE,
296 buf[chars_copied] = 0;
297 return (
int)chars_copied;
304 static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop,
char *buf,
size_t len)
310 str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
317 CFIndex str_len = CFStringGetLength(str);
320 range.length = (str_len >
len)? len: str_len;
321 CFIndex used_buf_len;
322 CFIndex chars_copied;
323 chars_copied = CFStringGetBytes(str,
325 kCFStringEncodingUTF8,
332 buf[chars_copied] = 0;
333 return (
int)used_buf_len;
340 static int get_serial_number(IOHIDDeviceRef device,
wchar_t *buf,
size_t len)
342 return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
345 static int get_manufacturer_string(IOHIDDeviceRef device,
wchar_t *buf,
size_t len)
347 return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);
350 static int get_product_string(IOHIDDeviceRef device,
wchar_t *buf,
size_t len)
352 return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);
357 static wchar_t *dup_wcs(
const wchar_t *
s)
359 size_t len = wcslen(s);
360 wchar_t *ret = (
wchar_t *)
malloc((len+1)*
sizeof(wchar_t));
367 static int make_path(IOHIDDeviceRef device,
char *buf,
size_t len)
370 unsigned short vid, pid;
375 res = get_string_property_utf8(
376 device, CFSTR(kIOHIDTransportKey),
377 transport,
sizeof(transport));
382 vid = get_vendor_id(device);
383 pid = get_product_id(device);
385 res = snprintf(buf, len,
"%s_%04hx_%04hx_%p",
386 transport, vid, pid, device);
394 static int init_hid_manager(
void)
398 hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
400 IOHIDManagerSetDeviceMatching(hid_mgr,
NULL);
401 IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
414 return init_hid_manager();
425 IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
433 static void process_pending_events() {
436 res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001,
FALSE);
437 }
while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
447 setlocale(LC_ALL,
"");
454 process_pending_events();
457 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
462 num_devices = CFSetGetCount(device_set);
464 CFRelease(device_set);
467 IOHIDDeviceRef *device_array = (IOHIDDeviceRef*)calloc(num_devices,
sizeof(IOHIDDeviceRef));
468 CFSetGetValues(device_set, (
const void **) device_array);
472 unsigned short dev_vid;
473 unsigned short dev_pid;
475 wchar_t buf[BUF_LEN];
478 IOHIDDeviceRef dev = device_array[
i];
483 dev_vid = get_vendor_id(dev);
484 dev_pid = get_product_id(dev);
487 if ((vendor_id == 0
x0 && product_id == 0
x0) ||
488 (vendor_id == dev_vid && product_id == dev_pid)) {
503 cur_dev->
usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
504 cur_dev->
usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
508 len = make_path(dev, cbuf,
sizeof(cbuf));
509 cur_dev->
path = strdup(cbuf);
512 get_serial_number(dev, buf, BUF_LEN);
516 get_manufacturer_string(dev, buf, BUF_LEN);
518 get_product_string(dev, buf, BUF_LEN);
526 cur_dev->
release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
534 CFRelease(device_set);
558 const char *path_to_open =
NULL;
568 path_to_open = cur_dev->
path;
573 path_to_open = cur_dev->
path;
577 cur_dev = cur_dev->
next;
590 static void hid_device_removal_callback(
void *
context, IOReturn
result,
591 void *sender, IOHIDDeviceRef dev_ref)
594 pthread_mutex_lock(&device_list_mutex);
595 hid_device *d = device_list;
597 if (d->device_handle == dev_ref) {
599 CFRunLoopStop(d->run_loop);
604 pthread_mutex_unlock(&device_list_mutex);
610 static void hid_report_callback(
void *context, IOReturn result,
void *sender,
611 IOHIDReportType report_type,
uint32_t report_id,
612 uint8_t *report, CFIndex report_length)
614 struct input_report *rpt;
615 hid_device *dev = (hid_device *)context;
618 rpt = (
struct input_report *)calloc(1,
sizeof(
struct input_report));
619 rpt->data = (
uint8_t *)calloc(1, report_length);
620 memcpy(rpt->data, report, report_length);
621 rpt->len = report_length;
625 pthread_mutex_lock(&dev->mutex);
628 if (dev->input_reports ==
NULL) {
630 dev->input_reports = rpt;
634 struct input_report *cur = dev->input_reports;
636 while (cur->next !=
NULL) {
645 if (num_queued > 30) {
646 return_data(dev,
NULL, 0);
651 pthread_cond_signal(&dev->condition);
654 pthread_mutex_unlock(&dev->mutex);
660 static void perform_signal_callback(
void *context)
662 hid_device *dev = (hid_device *)context;
663 CFRunLoopStop(dev->run_loop);
666 static void *read_thread(
void *
param)
668 hid_device *dev = (hid_device *)param;
671 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
675 CFRunLoopSourceContext
ctx;
676 memset(&ctx, 0,
sizeof(ctx));
679 ctx.perform = &perform_signal_callback;
680 dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctx);
681 CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
685 dev->run_loop = CFRunLoopGetCurrent();
688 pthread_barrier_wait(&dev->barrier);
693 while (!dev->shutdown_thread && !dev->disconnected) {
694 code = CFRunLoopRunInMode(dev->run_loop_mode, 1000,
FALSE);
696 if (code == kCFRunLoopRunFinished) {
697 dev->disconnected = 1;
703 if (code != kCFRunLoopRunTimedOut &&
704 code != kCFRunLoopRunHandledSource) {
708 dev->shutdown_thread = 1;
718 pthread_mutex_lock(&dev->mutex);
719 pthread_cond_broadcast(&dev->condition);
720 pthread_mutex_unlock(&dev->mutex);
725 pthread_barrier_wait(&dev->shutdown_barrier);
733 hid_device *dev =
NULL;
736 dev = new_hid_device();
743 process_pending_events();
745 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
747 num_devices = CFSetGetCount(device_set);
748 IOHIDDeviceRef *device_array = (IOHIDDeviceRef *)calloc(num_devices,
sizeof(IOHIDDeviceRef));
749 CFSetGetValues(device_set, (
const void **) device_array);
753 IOHIDDeviceRef os_dev = device_array[
i];
755 len = make_path(os_dev, cbuf,
sizeof(cbuf));
756 if (!strcmp(cbuf, path)) {
758 IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
759 if (ret == kIOReturnSuccess) {
763 CFRelease(device_set);
764 dev->device_handle = os_dev;
767 dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
768 dev->input_report_buf = (
uint8_t *)calloc(dev->max_input_report_len,
sizeof(
uint8_t));
772 sprintf(str,
"HIDAPI_%p", os_dev);
774 CFStringCreateWithCString(
NULL, str, kCFStringEncodingASCII);
777 IOHIDDeviceRegisterInputReportCallback(
778 os_dev, dev->input_report_buf, dev->max_input_report_len,
779 &hid_report_callback, dev);
780 IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback,
NULL);
783 pthread_create(&dev->thread,
NULL, read_thread, dev);
786 pthread_barrier_wait(&dev->barrier);
798 CFRelease(device_set);
799 free_hid_device(dev);
803 static int set_report(hid_device *dev, IOHIDReportType
type,
const unsigned char *
data,
size_t length)
805 const char *pass_through_magic =
"MAGIC0";
806 size_t pass_through_magic_length = strlen(pass_through_magic);
807 unsigned char report_id = data[0];
808 const unsigned char *data_to_send;
809 size_t length_to_send;
813 if (dev->disconnected)
816 if (report_id == 0
x0) {
819 data_to_send = data+1;
820 length_to_send = length-1;
822 else if (length > 6 && memcmp(data, pass_through_magic, pass_through_magic_length) == 0) {
823 report_id = data[pass_through_magic_length];
824 data_to_send = data+pass_through_magic_length;
825 length_to_send = length-pass_through_magic_length;
834 if (!dev->disconnected) {
835 res = IOHIDDeviceSetReport(dev->device_handle,
838 data_to_send, length_to_send);
840 if (res == kIOReturnSuccess) {
843 else if (res == kIOReturnUnsupported) {
858 return set_report(dev, kIOHIDReportTypeOutput, data, length);
862 static int return_data(hid_device *dev,
unsigned char *data,
size_t length)
866 struct input_report *rpt = dev->input_reports;
867 size_t len = (length < rpt->len)? length: rpt->len;
868 memcpy(data, rpt->data, len);
869 dev->input_reports = rpt->next;
875 static int cond_wait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *
mutex)
877 while (!dev->input_reports) {
878 int res = pthread_cond_wait(cond, mutex);
888 if (dev->shutdown_thread || dev->disconnected)
895 static int cond_timedwait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime)
897 while (!dev->input_reports) {
898 int res = pthread_cond_timedwait(cond, mutex, abstime);
908 if (dev->shutdown_thread || dev->disconnected)
921 pthread_mutex_lock(&dev->mutex);
924 if (dev->input_reports) {
926 bytes_read = return_data(dev, data, length);
931 if (dev->disconnected) {
936 if (dev->shutdown_thread) {
946 if (milliseconds == -1) {
949 res = cond_wait(dev, &dev->condition, &dev->mutex);
951 bytes_read = return_data(dev, data, length);
957 else if (milliseconds > 0) {
962 gettimeofday(&tv,
NULL);
963 TIMEVAL_TO_TIMESPEC(&tv, &ts);
964 ts.tv_sec += milliseconds / 1000;
965 ts.tv_nsec += (milliseconds % 1000) * 1000000;
966 if (ts.tv_nsec >= 1000000000L) {
968 ts.tv_nsec -= 1000000000L;
971 res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
973 bytes_read = return_data(dev, data, length);
974 else if (res == ETIMEDOUT)
986 pthread_mutex_unlock(&dev->mutex);
998 dev->blocking = !nonblock;
1005 return set_report(dev, kIOHIDReportTypeFeature, data, length);
1014 if (dev->disconnected)
1017 int skipped_report_id = 0;
1018 int report_number = data[0];
1019 if (report_number == 0
x0) {
1024 skipped_report_id = 1;
1027 res = IOHIDDeviceGetReport(dev->device_handle,
1028 kIOHIDReportTypeFeature,
1031 if (res != kIOReturnSuccess)
1034 if (skipped_report_id)
1047 if (!dev->disconnected) {
1048 IOHIDDeviceRegisterInputReportCallback(
1049 dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
1051 IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr,
NULL, dev);
1052 IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
1053 IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
1057 dev->shutdown_thread = 1;
1060 CFRunLoopSourceSignal(dev->source);
1061 CFRunLoopWakeUp(dev->run_loop);
1064 pthread_barrier_wait(&dev->shutdown_barrier);
1067 pthread_join(dev->thread,
NULL);
1072 if (!dev->disconnected) {
1073 IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
1077 pthread_mutex_lock(&dev->mutex);
1078 while (dev->input_reports) {
1079 return_data(dev,
NULL, 0);
1081 pthread_mutex_unlock(&dev->mutex);
1083 free_hid_device(dev);
1088 return get_manufacturer_string(dev->device_handle,
string, maxlen);
1093 return get_product_string(dev->device_handle,
string, maxlen);
1098 return get_serial_number(dev->device_handle,
string, maxlen);
1122 static int32_t get_location_id(IOHIDDeviceRef device)
1124 return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
1127 static int32_t get_usage(IOHIDDeviceRef device)
1130 res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
1132 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
1136 static int32_t get_usage_page(IOHIDDeviceRef device)
1139 res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
1141 res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
1145 static int get_transport(IOHIDDeviceRef device,
wchar_t *buf,
size_t len)
1147 return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
1153 IOHIDManagerRef mgr;
1156 mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1157 IOHIDManagerSetDeviceMatching(mgr,
NULL);
1158 IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1160 CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1162 CFIndex num_devices = CFSetGetCount(device_set);
1163 IOHIDDeviceRef *device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
1164 CFSetGetValues(device_set, (
const void **) device_array);
1166 setlocale(LC_ALL,
"");
1169 IOHIDDeviceRef dev = device_array[
i];
1170 printf(
"Device: %p\n", dev);
1171 printf(
" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1173 wchar_t serial[256], buf[256];
1175 get_serial_number(dev, serial, 256);
1178 printf(
" Serial: %ls\n", serial);
1179 printf(
" Loc: %ld\n", get_location_id(dev));
1180 get_transport(dev, buf, 256);
1181 printf(
" Trans: %ls\n", buf);
1182 make_path(dev, cbuf, 256);
1183 printf(
" Path: %s\n", cbuf);
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *device)
Get a string describing the last error which occurred.
GLuint GLuint GLsizei count
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
Free an enumeration Linked List.
static screen_context_t context
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
wchar_t * manufacturer_string
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen)
Get a string from a HID device, based on its string index.
static SDL_AudioDeviceID device
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
struct hid_device_info * next
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock)
Set the device handle to be non-blocking.
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
Close a HID device.
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen)
Get The Product String from a HID device.
unsigned short product_id
EGLImageKHR EGLint EGLint * handle
EGLDeviceEXT EGLint * num_devices
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
int hid_exit(void)
Finalize the HIDAPI library.
HID_API_EXPORT hid_device *HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
Open a HID device using a Vendor ID (VID), Product ID (PID) and optionally a serial number...
GLsizei const GLfloat * value
GLsizei GLsizei GLchar * source
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
Get a feature report from a HID device.
GLenum GLuint GLenum GLsizei const GLchar * buf
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen)
Get The Serial Number String from a HID device.
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define HID_API_EXPORT_CALL
int hid_init(void)
Initialize the HIDAPI library.
unsigned short usage_page
GLuint GLuint GLsizei GLenum type
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path, int bExclusive)
Open a HID device by its path name.
GLsizei const GLchar *const * path
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length)
Send a Feature report to the device.
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen)
Get The Manufacturer String from a HID device.
GLuint GLsizei GLsizei * length
struct hid_device_info HID_API_EXPORT *HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
Enumerate the HID Devices.
unsigned short release_number
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length)
Read an Input report from a HID device.