-
-
Notifications
You must be signed in to change notification settings - Fork 181
/
Copy pathhid_utility.c
128 lines (107 loc) · 3.45 KB
/
hid_utility.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "hid_utility.h"
#include <stdio.h>
#include <string.h>
/**
* @brief Helper fetching a copied HID path for a given device description.
*
* This is a convenience function iterating over connected USB devices and
* returning a copy of the HID path belonging to the device described in the
* parameters.
*
* @param vid The device vendor ID.
* @param pid The device product ID.
* @param iid The device interface ID. A value of zero means to take the
* first enumerated (sub-) device. (Ignored on macOS)
* @param usagepageid The device usage page id, see usageid
* @param usageid The device usage id in context to usagepageid.
* Only used on Windows currently, and when not 0;
* ignores iid when set
*
* @return copy of the HID path or NULL on failure (copy must be freed)
*/
char* get_hid_path(uint16_t vid, uint16_t pid, int iid, uint16_t usagepageid, uint16_t usageid)
{
char* ret = NULL;
struct hid_device_info* devs = hid_enumerate(vid, pid);
if (!devs) {
fprintf(stderr, "HID enumeration failure.\n");
return ret;
}
// Because of a MacOS Bug beginning with Ventura 13.3, we ignore the interfaceid
// See https://github.com/Sapd/HeadsetControl/issues/281
#ifdef __APPLE__
iid = 0;
#endif
// usageid is more specific to interface id, so we try it first
// It is a good idea, to do it on all platforms, however googling shows
// that older versions of hidapi have a bug where the value is not correctly
// set on non-Windows.
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
if (usageid && usagepageid) // ignore when one of them 0
{
struct hid_device_info* cur_dev = devs;
while (cur_dev) {
if (cur_dev->usage_page == usagepageid && cur_dev->usage == usageid) {
ret = strdup(cur_dev->path);
if (!ret) {
fprintf(stderr, "Unable to copy HID path for usageid.\n");
hid_free_enumeration(devs);
devs = NULL;
return ret;
}
break;
}
cur_dev = cur_dev->next;
}
}
#else
// ignore unused parameter warning
(void)(usageid);
(void)(usagepageid);
#endif
if (ret == NULL) // only when we didn't yet found something
{
struct hid_device_info* cur_dev = devs;
while (cur_dev) {
if (!iid || cur_dev->interface_number == iid) {
ret = strdup(cur_dev->path);
if (!ret) {
fprintf(stderr, "Unable to copy HID path.\n");
hid_free_enumeration(devs);
devs = NULL;
return ret;
}
break;
}
cur_dev = cur_dev->next;
}
}
hid_free_enumeration(devs);
devs = NULL;
return ret;
}
/**
* Helper freeing HID data.
*/
void terminate_device_hid(hid_device** handle, char** path)
{
if (handle) {
if (*handle) {
hid_close(*handle);
}
*handle = NULL;
}
if (path) {
free(*path);
*path = NULL;
}
}
/**
* Helper freeing HID data and terminating HID usage.
*/
/* This function is explicitly called terminate_hid to avoid HIDAPI clashes. */
void terminate_hid(hid_device** handle, char** path)
{
terminate_device_hid(handle, path);
hid_exit();
}