-
Notifications
You must be signed in to change notification settings - Fork 4
/
dev_hidraw.c
149 lines (118 loc) · 3.77 KB
/
dev_hidraw.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "dev_hidraw.h"
#define MAX_PATH_LEN 512
static const char *const hidraw_path = "/dev/";
static bool hidraw_matches(
const hidraw_filters_t *const in_filters,
dev_hidraw_t *const in_dev
) {
if (in_dev->info.product != in_filters->pid) {
return false;
} else if (in_dev->info.vendor != in_filters->vid) {
return false;
} else if (in_dev->rdesc.size != in_filters->rdesc_size) {
return false;
}
return true;
}
static int dev_hidraw_new_from_fd(int fd, dev_hidraw_t **const out_dev) {
int res = -EINVAL;
*out_dev = malloc(sizeof(dev_hidraw_t));
if (out_dev == NULL) {
fprintf(stderr, "Cannot allocate memory for hidraw device\n");
res = -ENOMEM;
goto dev_hidraw_new_from_fd_err;
}
(*out_dev)->fd = fd;
memset(&(*out_dev)->info, 0, sizeof(struct hidraw_devinfo));
memset(&(*out_dev)->rdesc, 0, sizeof(struct hidraw_report_descriptor));
res = ioctl((*out_dev)->fd, HIDIOCGRAWINFO, &(*out_dev)->info);
if (res < 0) {
fprintf(stderr, "Error getting device info: %d\n", errno);
goto dev_hidraw_new_from_fd_err;
}
res = ioctl((*out_dev)->fd, HIDIOCGRDESC, &(*out_dev)->rdesc);
if (res < 0) {
perror("Error getting Report Descriptor");
goto dev_hidraw_new_from_fd_err;
}
res = ioctl((*out_dev)->fd, HIDIOCGRDESCSIZE, &(*out_dev)->rdesc.size);
if (res < 0) {
perror("Error getting Report Descriptor");
goto dev_hidraw_new_from_fd_err;
}
dev_hidraw_new_from_fd_err:
if (res < 0) {
free(*out_dev);
*out_dev = NULL;
}
return res;
}
int dev_hidraw_open(
const hidraw_filters_t *const in_filters,
dev_hidraw_t **const out_dev
) {
int res = -ENOENT;
char path[MAX_PATH_LEN] = "\0";
DIR *d;
struct dirent *dir;
d = opendir(hidraw_path);
if (d) {
while ((dir = readdir(d)) != NULL) {
if (strstr(dir->d_name, "hidraw") == NULL) {
continue;
}
snprintf(path, MAX_PATH_LEN - 1, "%s%s", hidraw_path, dir->d_name);
//printf("Testing for device %s\n", path);
// try to open the device, if it cannot be opened to go the next
int fd = open(path, O_RDWR | O_NONBLOCK);
if (fd < 0) {
//fprintf(stderr, "Cannot open %s, device skipped.\n", path);
continue;
}
const int hidraw_open_res = dev_hidraw_new_from_fd(fd, out_dev);
if (hidraw_open_res != 0) {
close(fd);
continue;
}
if (!hidraw_matches(in_filters, *out_dev)) {
dev_hidraw_close(*out_dev);
continue;
}
// the device has been found
res = 0;
break;
}
closedir(d);
}
return res;
}
void dev_hidraw_close(dev_hidraw_t *const inout_dev) {
close(inout_dev->fd);
free(inout_dev);
}
int dev_hidraw_get_fd(const dev_hidraw_t *const in_dev) {
if (in_dev == NULL) {
return -EINVAL;
}
return in_dev->fd;
}
int16_t dev_hidraw_get_pid(const dev_hidraw_t *const in_dev) {
return in_dev->info.product;
}
int16_t dev_hidraw_get_vid(const dev_hidraw_t *const in_dev) {
return in_dev->info.vendor;
}
int dev_hidraw_get_rdesc(const dev_hidraw_t *const in_dev, uint8_t *const out_buf_sz, size_t in_buf_sz, size_t *const out_rdesc_size) {
int res = -EINVAL;
if (in_dev == NULL) {
goto dev_hidraw_get_rdesc;
}
if (in_dev->rdesc.size > in_buf_sz) {
goto dev_hidraw_get_rdesc;
}
memcpy((void*)out_buf_sz, (const void*)in_dev->rdesc.value, in_dev->rdesc.size);
*out_rdesc_size = in_dev->rdesc.size;
res = 0;
dev_hidraw_get_rdesc:
return res;
}