unifying: retrieve the list of features available on HID++ 2.0 devices

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
Benjamin Tissoires
2015-08-20 14:12:56 -04:00
parent b8637f0bc3
commit 9754810c38
3 changed files with 180 additions and 1 deletions

View File

@@ -93,6 +93,29 @@ unifying_write_profile(struct ratbag_profile *profile)
return -1;
}
static int
unifying_20_probe(struct ratbag_device *device, const struct ratbag_id id)
{
struct hidpp20_feature *feature_list;
int rc, i;
rc = hidpp20_feature_set_get(device, &feature_list);
if (rc < 0)
return rc;
if (rc > 0) {
log_info(device->ratbag, "'%s' has %d features:\n", ratbag_device_get_name(device), rc);
for (i = 0; i < rc; i++) {
log_info(device->ratbag, "0x%04x\n", feature_list[i].feature);
}
}
free(feature_list);
return 0;
}
static int
unifying_probe(struct ratbag_device *device, const struct ratbag_id id)
{
@@ -122,10 +145,16 @@ unifying_probe(struct ratbag_device *device, const struct ratbag_id id)
goto err;
}
log_info(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), drv_data->proto_major, drv_data->proto_minor);
log_debug(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), drv_data->proto_major, drv_data->proto_minor);
ratbag_set_drv_data(device, drv_data);
if (drv_data->proto_major >= 2) {
rc = unifying_20_probe(device, id);
if (rc)
goto err;
}
device->num_profiles = 1;
device->num_buttons = 8;

View File

@@ -129,6 +129,35 @@ out_err:
#define CMD_ROOT_GET_FEATURE 0x08
#define CMD_ROOT_GET_PROTOCOL_VERSION 0x18
int
hidpp_root_get_feature(struct ratbag_device *device,
uint16_t feature,
uint8_t *feature_index,
uint8_t *feature_type,
uint8_t *feature_version)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.device_idx = 0xff,
.msg.sub_id = HIDPP_PAGE_ROOT_IDX,
.msg.address = CMD_ROOT_GET_FEATURE,
.msg.parameters[0] = feature >> 8,
.msg.parameters[1] = feature & 0xff,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
*feature_index = msg.msg.parameters[0];
*feature_type = msg.msg.parameters[1];
*feature_version = msg.msg.parameters[2];
log_debug(device->ratbag, "feature 0x%04x is at 0x%02x\n", feature, *feature_index);
return 0;
}
int
hidpp20_root_get_protocol_version(struct ratbag_device *device,
unsigned *major,
@@ -158,3 +187,104 @@ hidpp20_root_get_protocol_version(struct ratbag_device *device,
return rc;
}
/* -------------------------------------------------------------------------- */
/* 0x0001: Feature Set */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_FEATURE_SET 0x0001
#define CMD_FEATURE_SET_GET_COUNT 0x08
#define CMD_FEATURE_SET_GET_FEATURE_ID 0x18
static int
hidpp20_feature_set_get_count(struct ratbag_device *device, uint8_t reg)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.device_idx = 0xff,
.msg.sub_id = reg,
.msg.address = CMD_FEATURE_SET_GET_COUNT,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return msg.msg.parameters[0];
}
static int
hidpp20_feature_set_get_feature_id(struct ratbag_device *device,
uint8_t reg,
uint8_t feature_index,
uint16_t *feature,
uint8_t *type)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.device_idx = 0xff,
.msg.sub_id = reg,
.msg.address = CMD_FEATURE_SET_GET_FEATURE_ID,
.msg.parameters[0] = feature_index,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
*feature = (msg.msg.parameters[0] << 8) | msg.msg.parameters[1];
*type = msg.msg.parameters[2];
return 0;
}
int hidpp20_feature_set_get(struct ratbag_device *device,
struct hidpp20_feature **feature_list)
{
uint8_t feature_index, feature_type, feature_version;
struct hidpp20_feature *flist;
int rc;
uint8_t feature_count;
unsigned int i;
rc = hidpp_root_get_feature(device,
HIDPP_PAGE_FEATURE_SET,
&feature_index,
&feature_type,
&feature_version);
if (rc)
return rc;
rc = hidpp20_feature_set_get_count(device, feature_index);
if (rc < 0)
return rc;
feature_count = (uint8_t)rc;
if (!feature_count) {
*feature_list = NULL;
return 0;
}
flist = zalloc(feature_count * sizeof(struct hidpp20_feature));
if (!flist)
return -ENOMEM;
for (i = 0; i < feature_count; i++) {
rc = hidpp20_feature_set_get_feature_id(device,
feature_index,
i,
&flist[i].feature,
&flist[i].type);
if (rc)
goto err;
}
*feature_list = flist;
return feature_count;
err:
free(flist);
return rc;
}

View File

@@ -52,9 +52,29 @@ int hidpp20_request_command(struct ratbag_device *device, union hidpp20_message
/* 0x0000: Root */
/* -------------------------------------------------------------------------- */
int hidpp_root_get_feature(struct ratbag_device *device,
uint16_t feature,
uint8_t *feature_index,
uint8_t *feature_type,
uint8_t *feature_version);
int hidpp20_root_get_protocol_version(struct ratbag_device *device,
unsigned *major,
unsigned *minor);
/* -------------------------------------------------------------------------- */
/* 0x0001: Feature Set */
/* -------------------------------------------------------------------------- */
struct hidpp20_feature {
uint16_t feature;
uint8_t type;
};
/**
* allocates a list of features that has to be freed by the caller.
*
* returns the elements in the list or a negative error
*/
int hidpp20_feature_set_get(struct ratbag_device *device,
struct hidpp20_feature **feature_list);
#endif /* HIDPP_20_H */