hidpp20: implement 0x2201, adjustable dpi

only the getter right now.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
Benjamin Tissoires
2015-08-20 15:32:21 -04:00
parent 88a54e7acf
commit fdd47609cf
3 changed files with 210 additions and 2 deletions

View File

@@ -49,6 +49,7 @@
#include "libratbag-hidraw.h"
#define HIDPP_CAP_RESOLUTION_2200 (1 << 0)
#define HIDPP_CAP_SWITCHABLE_RESOLUTION_2201 (1 << 1)
struct unifying_data {
unsigned proto_major;
@@ -100,6 +101,7 @@ static int
unifying_init_feature(struct ratbag_device *device, uint16_t feature)
{
struct unifying_data *drv_data = ratbag_get_drv_data(device);
struct ratbag *ratbag = device->ratbag;
int rc;
switch (feature) {
@@ -115,11 +117,28 @@ unifying_init_feature(struct ratbag_device *device, uint16_t feature)
rc = hidpp20_mousepointer_get_mousepointer_info(device, &resolution, &flags);
if (rc)
return rc;
log_info(device->ratbag, "device is at %d dpi\n", resolution);
log_info(ratbag, "device is at %d dpi\n", resolution);
break;
}
case 0x2201: {
struct hidpp20_sensor *sensors;
log_info(ratbag, "device has adjustable dpi\n");
rc = hidpp20_adjustable_dpi_get_sensors(device, &sensors);
if (rc < 0)
return rc;
if (rc > 0)
log_info(ratbag,
"device is at %d dpi (variable between %d and %d).\n",
sensors[0].dpi,
sensors[0].dpi_min,
sensors[0].dpi_max);
free(sensors);
drv_data->capabilities |= HIDPP_CAP_SWITCHABLE_RESOLUTION_2201;
break;
}
default:
log_info(device->ratbag, "unknown feature 0x%04x\n", feature);
log_debug(device->ratbag, "unknown feature 0x%04x\n", feature);
}
return 0;
}

View File

@@ -29,6 +29,7 @@
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -119,6 +120,12 @@ out_err:
return ret;
}
static inline uint16_t
hidpp20_get_unaligned_u16(uint8_t *buf)
{
return (buf[0] << 8) | buf[1];
}
/* -------------------------------------------------------------------------- */
/* 0x0000: Root */
/* -------------------------------------------------------------------------- */
@@ -330,3 +337,159 @@ hidpp20_mousepointer_get_mousepointer_info(struct ratbag_device *device,
return 0;
}
/* -------------------------------------------------------------------------- */
/* 0x2201: Adjustable DPI */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_ADJUSTABLE_DPI 0x2201
#define CMD_ADJUSTABLE_DPI_GET_SENSOR_COUNT 0x08
#define CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI_LIST 0x18
#define CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI 0x28
#define CMD_ADJUSTABLE_DPI_SET_SENSOR_DPI 0x38
static int
hidpp20_adjustable_dpi_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_ADJUSTABLE_DPI_GET_SENSOR_COUNT,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return msg.msg.parameters[0];
}
static int
hidpp20_adjustable_dpi_get_dpi_list(struct ratbag_device *device,
uint8_t reg,
struct hidpp20_sensor *sensor)
{
int rc;
unsigned i = 1, dpi_index = 0;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.device_idx = 0xff,
.msg.sub_id = reg,
.msg.address = CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI_LIST,
.msg.parameters[0] = sensor->index,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
sensor->dpi_min = 0xffff;
sensor->index = msg.msg.parameters[0];
while (i < LONG_MESSAGE_LENGTH - 1 &&
hidpp20_get_unaligned_u16(&msg.msg.parameters[i]) != 0) {
uint16_t value = hidpp20_get_unaligned_u16(&msg.msg.parameters[i]);
if (value > 0xe000) {
sensor->dpi_steps = value - 0xe000;
} else {
sensor->dpi_min = value < sensor->dpi_min ? value : sensor->dpi_min;
sensor->dpi_max = value > sensor->dpi_max ? value : sensor->dpi_max;
sensor->dpi_list[dpi_index++] = value;
}
assert(sensor->dpi_list[dpi_index] == 0x0000);
i += 2;
}
return 0;
}
static int
hidpp20_adjustable_dpi_get_dpi(struct ratbag_device *device,
uint8_t reg,
struct hidpp20_sensor *sensor)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.device_idx = 0xff,
.msg.sub_id = reg,
.msg.address = CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI,
.msg.parameters[0] = sensor->index,
};
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
sensor->dpi = hidpp20_get_unaligned_u16(&msg.msg.parameters[1]);
sensor->default_dpi = hidpp20_get_unaligned_u16(&msg.msg.parameters[3]);
return 0;
}
int hidpp20_adjustable_dpi_get_sensors(struct ratbag_device *device,
struct hidpp20_sensor **sensors_list)
{
uint8_t feature_index, feature_type, feature_version;
struct hidpp20_sensor *s_list, *sensor;
uint8_t num_sensors;
unsigned i;
int rc;
rc = hidpp_root_get_feature(device,
HIDPP_PAGE_ADJUSTABLE_DPI,
&feature_index,
&feature_type,
&feature_version);
if (rc)
return rc;
rc = hidpp20_adjustable_dpi_get_count(device, feature_index);
if (rc < 0)
return rc;
num_sensors = rc;
if (num_sensors == 0) {
*sensors_list = NULL;
return 0;
}
s_list = zalloc(num_sensors * sizeof(struct hidpp20_sensor));
if (!s_list)
return -ENOMEM;
for (i = 0; i < num_sensors; i++) {
sensor = &s_list[i];
sensor->index = i;
rc = hidpp20_adjustable_dpi_get_dpi_list(device,
feature_index,
sensor);
if (rc)
goto err;
rc = hidpp20_adjustable_dpi_get_dpi(device, feature_index, sensor);
if (rc)
goto err;
log_debug(device->ratbag,
"sensor %d: current dpi: %d (default: %d) min: %d max: %d steps: %d\n",
sensor->index,
sensor->dpi,
sensor->default_dpi,
sensor->dpi_min,
sensor->dpi_max,
sensor->dpi_steps);
}
*sensors_list = s_list;
return num_sensors;
err:
free(s_list);
return rc;
}

View File

@@ -94,4 +94,30 @@ int hidpp20_mousepointer_get_mousepointer_info(struct ratbag_device *device,
uint16_t *resolution,
uint8_t *flags);
/* -------------------------------------------------------------------------- */
/* 0x2201: Adjustable DPI */
/* -------------------------------------------------------------------------- */
/**
* either dpi_steps is not null or the values are stored in the null terminated
* array dpi_list.
*/
struct hidpp20_sensor {
uint8_t index;
uint16_t dpi;
uint16_t dpi_min;
uint16_t dpi_max;
uint16_t dpi_steps;
uint16_t default_dpi;
uint16_t dpi_list[LONG_MESSAGE_LENGTH / 2 + 1];
};
/**
* allocates a list of sensors that has to be freed by the caller.
*
* returns the elements in the list or a negative error
*/
int hidpp20_adjustable_dpi_get_sensors(struct ratbag_device *device,
struct hidpp20_sensor **sensors_list);
#endif /* HIDPP_20_H */