summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2014-12-13 00:02:12 +0100
committerPeter Wu <peter@lekensteyn.nl>2014-12-13 00:02:12 +0100
commit692e5d592a7c88765b9cbb29612729d2987cfcba (patch)
tree33ee569d9bdfce654d7c453062dca7f46d6dac0e
parent9e13e4aac322bf23a9fa1eaf7d7a8d5e605233cb (diff)
downloadltunify-692e5d592a7c88765b9cbb29612729d2987cfcba.tar.gz
lib/hidpp20: support feature retrieval
-rw-r--r--lib/hidpp20.c121
-rw-r--r--lib/hidpp20.h29
2 files changed, 144 insertions, 6 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 }
};
diff --git a/lib/hidpp20.h b/lib/hidpp20.h
index 49181e1..696d729 100644
--- a/lib/hidpp20.h
+++ b/lib/hidpp20.h
@@ -39,35 +39,56 @@ typedef struct {
uint16_t feature_id;
uint8_t feature_type;
} FeatureInfo;
-
+/* TODO: HID++ 1.0 vs 2.0 errors? */
/**
* Retrieves the number of HID++ 2.0 features.
*
* @param fd File descriptor of the hidraw device.
+ * @param device_index Device index (between 1 and 6).
+ * @param ifeatureset[in] The IFeatureSet feature to call this method on.
* @param count[out] The number of HID++ 2.0 features.
* @return Zero on success, a HID++ error code otherwise.
*/
-int hidpp20_get_features_count(int fd, uint8_t *count);
+int hidpp20_get_features_count(int fd, uint8_t device_index,
+ const FeatureInfo *ifeatureset,
+ uint8_t *count);
/**
* Retrieves feature information from a feature index.
*
* @param fd File descriptor of the hidraw device.
+ * @param device_index Device index (between 1 and 6).
+ * @param ifeatureset[in] The IFeatureSet feature to call this method on.
* @param feature_index A feature index to find information for.
* @param fi[out] Feature information on success.
* @return Zero on success, a HID++ error code otherwise.
*/
-int hidpp20_get_feature(int fd, uint8_t feature_index, FeatureInfo *fi);
+int hidpp20_get_feature(int fd, uint8_t device_index,
+ const FeatureInfo *ifeatureset,
+ uint8_t feature_index, FeatureInfo *fi);
/**
* Retrieves the feature index for a given feature ID.
*
* @param fd File descriptor of the hidraw device.
+ * @param device_index Device index (between 1 and 6).
* @param feature_id A 16-bit feature identifier.
* @param fi[out] Feature information on success.
* @return Zero on success, a HID++ error code otherwise.
*/
-int hidpp20_get_feature_by_id(int fd, uint16_t feature_id, FeatureInfo *fi);
+int hidpp20_get_feature_by_id(int fd, uint8_t device_index, uint16_t feature_id,
+ FeatureInfo *fi);
+
+/**
+ * Retrieves all features of a connected device.
+ *
+ * @param fd File descriptor of the hidraw device.
+ * @param device_index Device index (between 1 and 6).
+ * @param count[out] The number of discovered features or 0 if an error occured
+ * (in that case, NULL is returned too).
+ * @return NULL on error or an array of features supported by the device.
+ */
+FeatureInfo *hidpp20_get_features(int fd, uint8_t device_index, unsigned *count);
/**
* Retrieves the HID++ version for the device.