diff options
Diffstat (limited to 'lib/hidpp20.c')
-rw-r--r-- | lib/hidpp20.c | 121 |
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 } }; |