23 #include "../../SDL_internal.h" 25 #ifdef SDL_JOYSTICK_HIDAPI 40 #include <sys/types.h> 42 #include <sys/ioctl.h> 43 #include <sys/utsname.h> 48 #include <linux/hidraw.h> 49 #include <linux/version.h> 50 #include <linux/input.h> 62 #ifndef HIDIOCSFEATURE 63 #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) 65 #ifndef HIDIOCGFEATURE 66 #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) 70 const char *device_string_names[] = {
77 enum device_string_id {
78 DEVICE_STRING_MANUFACTURER,
79 DEVICE_STRING_PRODUCT,
88 int uses_numbered_reports;
93 static __u32 kernel_version = 0;
95 static __u32 detect_kernel_version(
void)
98 int major, minor, release;
102 ret = sscanf(
name.release,
"%d.%d.%d", &major, &minor, &release);
104 return KERNEL_VERSION(major, minor, release);
107 ret = sscanf(
name.release,
"%d.%d", &major, &minor);
109 return KERNEL_VERSION(major, minor, 0);
112 printf(
"Couldn't determine kernel version from version string \"%s\"\n",
name.release);
116 static hid_device *new_hid_device(
void)
118 hid_device *dev = (hid_device *)calloc(1,
sizeof(hid_device));
119 dev->device_handle = -1;
121 dev->uses_numbered_reports = 0;
122 dev->is_bluetooth = 0;
129 static wchar_t *utf8_to_wchar_t(
const char *utf8)
134 size_t wlen = mbstowcs(
NULL, utf8, 0);
135 if ((
size_t) -1 == wlen) {
138 ret = (
wchar_t *)calloc(wlen+1,
sizeof(
wchar_t));
139 mbstowcs(ret, utf8, wlen+1);
148 static wchar_t *copy_udev_string(
struct udev_device *dev,
const char *udev_name)
150 return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));
155 static int uses_numbered_reports(__u8 *report_descriptor, __u32
size) {
158 int data_len, key_size;
161 int key = report_descriptor[
i];
172 if ((key & 0xf0) == 0xf0) {
178 data_len = report_descriptor[i+1];
189 size_code = key & 0x3;
194 data_len = size_code;
208 i += data_len + key_size;
220 parse_uevent_info(
const char *uevent,
int *bus_type,
221 unsigned short *vendor_id,
unsigned short *product_id,
222 char **serial_number_utf8,
char **product_name_utf8)
224 char *tmp = strdup(uevent);
225 char *saveptr =
NULL;
231 int found_serial = 0;
234 line = strtok_r(tmp,
"\n", &saveptr);
235 while (line !=
NULL) {
238 value = strchr(line,
'=');
245 if (strcmp(key,
"HID_ID") == 0) {
250 int ret = sscanf(value,
"%x:%hx:%hx", bus_type, vendor_id, product_id);
254 }
else if (strcmp(key,
"HID_NAME") == 0) {
256 *product_name_utf8 = strdup(value);
258 }
else if (strcmp(key,
"HID_UNIQ") == 0) {
260 *serial_number_utf8 = strdup(value);
265 line = strtok_r(
NULL,
"\n", &saveptr);
269 return (found_id && found_name && found_serial);
272 static int is_bluetooth(hid_device *dev)
275 struct udev_device *udev_dev, *hid_dev;
282 printf(
"Can't create udev\n");
287 ret = fstat(dev->device_handle, &
s);
294 udev_dev = udev_device_new_from_devnum(udev,
'c',
s.st_rdev);
296 hid_dev = udev_device_get_parent_with_subsystem_devtype(
301 unsigned short dev_vid;
302 unsigned short dev_pid;
304 char *serial_number_utf8 =
NULL;
305 char *product_name_utf8 =
NULL;
307 ret = parse_uevent_info(
308 udev_device_get_sysattr_value(hid_dev,
"uevent"),
314 free(serial_number_utf8);
315 free(product_name_utf8);
317 ret = (bus_type == BUS_BLUETOOTH);
322 udev_device_unref(udev_dev);
331 static int get_device_string(hid_device *dev,
enum device_string_id key,
wchar_t *
string,
size_t maxlen)
334 struct udev_device *udev_dev, *parent, *hid_dev;
337 char *serial_number_utf8 =
NULL;
338 char *product_name_utf8 =
NULL;
344 printf(
"Can't create udev\n");
349 ret = fstat(dev->device_handle, &
s);
355 udev_dev = udev_device_new_from_devnum(udev,
'c',
s.st_rdev);
357 hid_dev = udev_device_get_parent_with_subsystem_devtype(
362 unsigned short dev_vid;
363 unsigned short dev_pid;
367 ret = parse_uevent_info(
368 udev_device_get_sysattr_value(hid_dev,
"uevent"),
375 if (bus_type == BUS_BLUETOOTH) {
377 case DEVICE_STRING_MANUFACTURER:
378 wcsncpy(
string, L
"", maxlen);
381 case DEVICE_STRING_PRODUCT:
382 retm = mbstowcs(
string, product_name_utf8, maxlen);
383 ret = (retm == (
size_t)-1)? -1: 0;
385 case DEVICE_STRING_SERIAL:
390 while ((tmp = strchr(serial_number_utf8,
':')) !=
NULL) {
391 memmove(tmp, tmp+1, strlen(tmp));
393 retm = mbstowcs(
string, serial_number_utf8, maxlen);
394 ret = (retm == (
size_t)-1)? -1: 0;
396 case DEVICE_STRING_COUNT:
404 parent = udev_device_get_parent_with_subsystem_devtype(
410 const char *key_str =
NULL;
412 if (key >= 0 && key < DEVICE_STRING_COUNT) {
413 key_str = device_string_names[
key];
419 str = udev_device_get_sysattr_value(parent, key_str);
422 retm = mbstowcs(
string, str, maxlen);
423 ret = (retm == (
size_t)-1)? -1: 0;
432 free(serial_number_utf8);
433 free(product_name_utf8);
435 udev_device_unref(udev_dev);
448 locale = setlocale(LC_CTYPE,
NULL);
450 setlocale(LC_CTYPE,
"");
452 kernel_version = detect_kernel_version();
467 struct udev_enumerate *enumerate;
468 struct udev_list_entry *
devices, *dev_list_entry;
479 printf(
"Can't create udev\n");
484 enumerate = udev_enumerate_new(udev);
485 udev_enumerate_add_match_subsystem(enumerate,
"hidraw");
486 udev_enumerate_scan_devices(enumerate);
487 devices = udev_enumerate_get_list_entry(enumerate);
490 udev_list_entry_foreach(dev_list_entry, devices) {
491 const char *sysfs_path;
492 const char *dev_path;
494 struct udev_device *raw_dev;
495 struct udev_device *hid_dev;
496 struct udev_device *usb_dev;
497 struct udev_device *intf_dev;
498 unsigned short dev_vid;
499 unsigned short dev_pid;
500 char *serial_number_utf8 =
NULL;
501 char *product_name_utf8 =
NULL;
507 sysfs_path = udev_list_entry_get_name(dev_list_entry);
508 raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
509 dev_path = udev_device_get_devnode(raw_dev);
511 hid_dev = udev_device_get_parent_with_subsystem_devtype(
521 result = parse_uevent_info(
522 udev_device_get_sysattr_value(hid_dev,
"uevent"),
534 if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
539 if (
access(dev_path, R_OK|W_OK) != 0) {
545 if ((vendor_id == 0
x0 || vendor_id == dev_vid) &&
546 (product_id == 0
x0 || product_id == dev_pid)) {
562 cur_dev->
path = dev_path? strdup(dev_path):
NULL;
569 cur_dev->
serial_number = utf8_to_wchar_t(serial_number_utf8);
585 usb_dev = udev_device_get_parent_with_subsystem_devtype(
602 cur_dev = root =
NULL;
609 cur_dev->
manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);
610 cur_dev->
product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);
613 str = udev_device_get_sysattr_value(usb_dev,
"bcdDevice");
617 intf_dev = udev_device_get_parent_with_subsystem_devtype(
622 str = udev_device_get_sysattr_value(intf_dev,
"bInterfaceNumber");
643 free(serial_number_utf8);
644 free(product_name_utf8);
645 udev_device_unref(raw_dev);
651 udev_enumerate_unref(enumerate);
671 hid_device *
hid_open(
unsigned short vendor_id,
unsigned short product_id,
const wchar_t *
serial_number)
674 const char *path_to_open =
NULL;
684 path_to_open = cur_dev->
path;
689 path_to_open = cur_dev->
path;
693 cur_dev = cur_dev->
next;
708 hid_device *dev =
NULL;
712 dev = new_hid_device();
715 dev->device_handle = open(path, O_RDWR);
718 if (dev->device_handle > 0) {
721 int res, desc_size = 0;
722 struct hidraw_report_descriptor rpt_desc;
724 memset(&rpt_desc, 0
x0,
sizeof(rpt_desc));
727 res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
729 perror(
"HIDIOCGRDESCSIZE");
733 rpt_desc.size = desc_size;
734 res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
736 perror(
"HIDIOCGRDESC");
739 dev->uses_numbered_reports =
740 uses_numbered_reports(rpt_desc.value,
744 dev->is_bluetooth = (is_bluetooth(dev) == 1);
760 bytes_written = write(dev->device_handle, data, length);
762 return bytes_written;
770 if (milliseconds >= 0) {
780 fds.fd = dev->device_handle;
783 ret = poll(&
fds, 1, milliseconds);
784 if (ret == -1 || ret == 0) {
791 if (
fds.revents & (POLLERR | POLLHUP | POLLNVAL))
796 bytes_read = read(dev->device_handle, data, length);
797 if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))
800 if (bytes_read >= 0 &&
801 kernel_version != 0 &&
802 kernel_version < KERNEL_VERSION(2,6,34) &&
803 dev->uses_numbered_reports) {
805 memmove(data, data+1, bytes_read);
823 dev->blocking = !nonblock;
832 res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
834 perror(
"ioctl (SFEATURE)");
844 if (dev->is_bluetooth) {
849 res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
851 perror(
"ioctl (GFEATURE)");
852 else if (dev->is_bluetooth)
863 close(dev->device_handle);
870 return get_device_string(dev, DEVICE_STRING_MANUFACTURER,
string, maxlen);
875 return get_device_string(dev, DEVICE_STRING_PRODUCT,
string, maxlen);
880 return get_device_string(dev, DEVICE_STRING_SERIAL,
string, maxlen);
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *device)
Get a string describing the last error which occurred.
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
Free an enumeration Linked List.
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.
GLuint GLint GLboolean GLint GLenum access
GLuint const GLchar * name
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
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
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.
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.
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.