summaryrefslogtreecommitdiff
path: root/lib/hidpp20.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hidpp20.c')
-rw-r--r--lib/hidpp20.c121
1 files changed, 119 insertions, 2 deletions
diff --git a/lib/hidpp20.c b/lib/hidpp20.c
index 25e7a43..f8a2374 100644
--- a/lib/hidpp20.c
+++ b/lib/hidpp20.c
@@ -20,11 +20,128 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdlib.h>
#include "debug.h"
#include "hidpp.h"
#include "hidpp10.h"
#include "hidpp20.h"
+int hidpp20_get_features_count(int fd, uint8_t device_index,
+ const FeatureInfo *ifeatureset,
+ uint8_t *count)
+{
+ int r;
+ HidppMessage req = {
+ .report_id = HIDPP_SHORT,
+ .device_index = device_index,
+ .feature_index = ifeatureset->feature_index,
+ .func = HIDPP20_FUNC(0),
+ };
+ r = hidpp10_request(fd, &req, NULL, NULL);
+ if (r == 0) {
+ *count = req.params[0];
+ } else {
+ trace_log("[ix=%02x] IFeatureSet.GetCount failed with %#x\n",
+ device_index, r);
+ }
+ return r;
+}
+
+int hidpp20_get_feature(int fd, uint8_t device_index,
+ const FeatureInfo *ifeatureset,
+ uint8_t feature_index, FeatureInfo *fi)
+{
+ int r;
+ HidppMessage req = {
+ .report_id = HIDPP_SHORT,
+ .device_index = device_index,
+ .feature_index = ifeatureset->feature_index,
+ .func = HIDPP20_FUNC(1), /* GetFeatureId */
+ .params = { feature_index }
+ };
+ assert(device_index >= 1 && device_index <= MAX_DEVICES);
+
+ r = hidpp10_request(fd, &req, NULL, NULL);
+ if (r == 0) {
+ fi->feature_index = feature_index;
+ fi->feature_id = (req.params[0] << 8) | req.params[1];
+ fi->feature_type = req.params[2];
+ } else {
+ trace_log("[ix=%02x] failed to get feature %i, error=%i\n",
+ device_index, feature_index, r);
+ }
+ return r;
+}
+
+int hidpp20_get_feature_by_id(int fd, uint8_t device_index, uint16_t feature_id,
+ FeatureInfo *fi)
+{
+ int r;
+ HidppMessage req = {
+ .report_id = HIDPP_SHORT,
+ .device_index = device_index,
+ .feature_index = 0x00, /* IRoot */
+ .func = HIDPP20_FUNC(0), /* GetFeature */
+ .params = { feature_id >> 8, (uint8_t) feature_id }
+ };
+ assert(device_index >= 1 && device_index <= MAX_DEVICES);
+
+ r = hidpp10_request(fd, &req, NULL, NULL);
+ if (r == 0) {
+ fi->feature_index = req.params[0];
+ fi->feature_id = feature_id;
+ fi->feature_type = req.params[1];
+ } else {
+ trace_log("[ix=%02x] failed to get feature id %#06x, error=%i\n",
+ device_index, feature_id, r);
+ }
+ return r;
+}
+
+FeatureInfo *hidpp20_get_features(int fd, uint8_t device_index, unsigned *count)
+{
+ int r, i;
+ FeatureInfo fi;
+ FeatureInfo *infos;
+ uint8_t count_nonroot; /* features count not including root feature */
+
+ assert(device_index >= 1 && device_index <= MAX_DEVICES);
+
+ *count = 0;
+ r = hidpp20_get_version(fd, device_index);
+ if (r < 0x0200) {
+ trace_log("[ix=%02x] HID++ 2.0 required for features, got %#4x\n",
+ device_index, r);
+ return NULL;
+ }
+
+ r = hidpp20_get_feature_by_id(fd, device_index, 0x0001, &fi);
+ if (r) {
+ trace_log("[ix=%02x] FeatureSet not found, error=%#x\n",
+ device_index, r);
+ return NULL;
+ }
+ r = hidpp20_get_features_count(fd, device_index, &fi, &count_nonroot);
+ if (r)
+ return NULL;
+ infos = calloc(*count, sizeof(FeatureInfo));
+
+ /* infos[0] is the Root feature which has index=0, id=0, type=0 */
+
+ for (i = 1; i <= count_nonroot; i++) {
+ r = hidpp20_get_feature(fd, device_index, &fi, i, &infos[i]);
+ if (r) {
+ trace_log("[ix=%02x] feature %i not found, error=%#x\n",
+ device_index, i, r);
+ free(infos);
+ return NULL;
+ }
+ }
+ /* maybe qsort(infos); here? */
+ *count = count_nonroot + 1;
+ return infos;
+}
+
uint16_t hidpp20_get_version(int fd, uint8_t device_index)
{
int r;
@@ -33,8 +150,8 @@ uint16_t hidpp20_get_version(int fd, uint8_t device_index)
HidppMessage req = {
.report_id = HIDPP_SHORT,
.device_index = device_index,
- .feature_id = 0x00,
- .func = 0x14,
+ .feature_index = 0x00, /* IRoot */
+ .func = HIDPP20_FUNC(1),
.params = { 0, 0, pingData }
};