forked from drath/libratbag
hidpp10: build a table of available dpi settings
Each hidpp10 device should have a udev property named either RATBAG_HIDPP10_DPI or RATBAG_HIDPP10_DPI_LIST. These properties ensure that we know the mapping between the raw value of the dpi reported by the mouse and the actual value. Older devices (using the scheme 1 or 2 of hidpp10_get_current_resolution) have to use the DPI_LIST to be able to map 0x80+. Newer devices (using scheme 3) use the DPI setting with min, max, step. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
committed by
Benjamin Tissoires
parent
ef96a8649e
commit
3e8bf85c04
@@ -66,10 +66,12 @@ mouse:usb:v046dp1028:name:*:
|
||||
# G5
|
||||
mouse:usb:v046dpc041:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
|
||||
|
||||
# G5 2007
|
||||
mouse:usb:v046dpc049:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
|
||||
|
||||
# G7
|
||||
mouse:usb:v046dpc51a:name:*:
|
||||
@@ -78,23 +80,28 @@ mouse:usb:v046dpc51a:name:*:
|
||||
# G9
|
||||
mouse:usb:v046dpc048:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=0;200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200
|
||||
|
||||
# G9x [Original]
|
||||
mouse:usb:v046dpc066:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
|
||||
# G9x [Call of Duty MW3 Edition]
|
||||
mouse:usb:v046dpc249:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
|
||||
# G500
|
||||
mouse:usb:v046dpc068:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
|
||||
# G500s
|
||||
mouse:usb:v046dpc24e:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g500s.svg
|
||||
RATBAG_HIDPP10_DPI=0:8200@50
|
||||
|
||||
# G502 over USB
|
||||
mouse:usb:v046dpc07d:name:*:
|
||||
|
||||
@@ -50,6 +50,7 @@ libhidpp_la_SOURCES = \
|
||||
hidpp10.c \
|
||||
hidpp20.h \
|
||||
hidpp20.c
|
||||
libhidpp_la_LDFLAGS = -lm
|
||||
libutil_la_SOURCES = \
|
||||
libratbag-util.c \
|
||||
libratbag-util.h
|
||||
|
||||
@@ -212,6 +212,7 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
struct hidpp10drv_data *drv_data = NULL;
|
||||
struct hidpp10_device *dev = NULL;
|
||||
struct hidpp_device base;
|
||||
const char *prop;
|
||||
|
||||
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
|
||||
if (rc == -ENODEV) {
|
||||
@@ -243,6 +244,33 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
goto err;
|
||||
}
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI");
|
||||
if (prop) {
|
||||
rc = hidpp10_build_dpi_table_from_dpi_info(dev, prop);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP10_DPI: '%s' for %s\n",
|
||||
prop,
|
||||
device->name);
|
||||
}
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI_LIST");
|
||||
if (prop) {
|
||||
rc = hidpp10_build_dpi_table_from_list(dev, prop);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP10_DPI_LIST: '%s' for %s\n",
|
||||
prop,
|
||||
device->name);
|
||||
}
|
||||
|
||||
if (!dev->dpi_count)
|
||||
log_info(device->ratbag,
|
||||
"Device %s might have wrong dpi settings. "
|
||||
"Please add RATBAG_HIDPP10_DPI or RATBAG_HIDPP10_DPI_LIST "
|
||||
"to the udev properties.\n",
|
||||
device->name);
|
||||
|
||||
drv_data->dev = dev;
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
|
||||
152
src/hidpp10.c
152
src/hidpp10.c
@@ -37,6 +37,8 @@
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "hidpp10.h"
|
||||
|
||||
@@ -83,6 +85,98 @@ const char *device_types[0xFF] = {
|
||||
[0x0A ... 0xFE] = NULL,
|
||||
};
|
||||
|
||||
int
|
||||
hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
|
||||
const char *str_list)
|
||||
{
|
||||
unsigned int i, count, index;
|
||||
int nread, dpi = 0;
|
||||
char c;
|
||||
/*
|
||||
* str_list is in the form:
|
||||
* "0;200;400;600;800;1000;1200"
|
||||
*/
|
||||
|
||||
/* first, count how many elements do we have in the table */
|
||||
count = 1;
|
||||
i = 0;
|
||||
while (str_list[i] != 0) {
|
||||
c = str_list[i++];
|
||||
if (c == ';')
|
||||
count++;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
/* check that the max raw value fits in a uint8_t */
|
||||
if (count + 0x80 - 1> 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dpi_count = count;
|
||||
dev->dpi_table = zalloc(count * sizeof(*dev->dpi_table));
|
||||
|
||||
while (*str_list != 0 && index < count) {
|
||||
if (*str_list == ';') {
|
||||
str_list++;
|
||||
continue;
|
||||
}
|
||||
|
||||
nread = 0;
|
||||
sscanf(str_list, "%d%n", &dpi, &nread);
|
||||
if (!nread || dpi < 0)
|
||||
goto err;
|
||||
|
||||
dev->dpi_table[index].raw_value = index + 0x80;
|
||||
dev->dpi_table[index].dpi = dpi;
|
||||
|
||||
str_list += nread;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index != count)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev->dpi_count = 0;
|
||||
free(dev->dpi_table);
|
||||
dev->dpi_table = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
|
||||
const char *str_dpi)
|
||||
{
|
||||
float min, max, step;
|
||||
unsigned raw_max, i;
|
||||
int rc;
|
||||
/*
|
||||
* str_list is in the form:
|
||||
* "MIN:MAX@STEP"
|
||||
*/
|
||||
|
||||
rc = sscanf(str_dpi, "%f:%f@%f", &min, &max, &step);
|
||||
if (rc != 3)
|
||||
return -EINVAL;
|
||||
|
||||
raw_max = (max - min) / step;
|
||||
if (raw_max > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dpi_count = raw_max + 1;
|
||||
dev->dpi_table = zalloc((raw_max + 1) * sizeof(*dev->dpi_table));
|
||||
|
||||
for (i = 1; i <= raw_max; i++) {
|
||||
dev->dpi_table[i].raw_value = i;
|
||||
dev->dpi_table[i].dpi = round((min + step * i) / 25.0f) * 25;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
|
||||
{
|
||||
@@ -479,6 +573,50 @@ union _hidpp10_profile_data {
|
||||
};
|
||||
_Static_assert((sizeof(union _hidpp10_profile_data) % 16) == 0, "Invalid size");
|
||||
|
||||
static uint8_t
|
||||
hidpp10_get_dpi_mapping(struct hidpp10_device *dev, unsigned int value)
|
||||
{
|
||||
struct hidpp10_dpi_mapping *m;
|
||||
unsigned int i, delta, min_delta;
|
||||
uint8_t result = 0;
|
||||
|
||||
if (!dev->dpi_table)
|
||||
return value / 50;
|
||||
|
||||
m = dev->dpi_table;
|
||||
|
||||
min_delta = INT_MAX;
|
||||
|
||||
for (i = 0; i < dev->dpi_count; i++) {
|
||||
delta = abs(value - m[i].dpi);
|
||||
if (delta < min_delta) {
|
||||
result = m[i].raw_value;
|
||||
min_delta = delta;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hidpp10_get_dpi_value(struct hidpp10_device *dev, uint8_t raw_value)
|
||||
{
|
||||
struct hidpp10_dpi_mapping *m;
|
||||
unsigned int i;
|
||||
|
||||
if (!dev->dpi_table)
|
||||
return raw_value * 50;
|
||||
|
||||
m = dev->dpi_table;
|
||||
|
||||
for (i = 0; i < dev->dpi_count; i++) {
|
||||
if (raw_value == m[i].raw_value)
|
||||
return m[i].dpi;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
|
||||
{
|
||||
@@ -540,9 +678,9 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
|
||||
struct _hidpp10_dpi_mode *dpi = &p->dpi_modes[i];
|
||||
|
||||
be = (uint8_t*)&dpi->xres;
|
||||
profile.dpi_modes[i].xres = hidpp_get_unaligned_be_u16(be) * 50;
|
||||
profile.dpi_modes[i].xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_be_u16(be));
|
||||
be = (uint8_t*)&dpi->yres;
|
||||
profile.dpi_modes[i].yres = hidpp_get_unaligned_be_u16(be) * 50;
|
||||
profile.dpi_modes[i].yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_be_u16(be));
|
||||
|
||||
profile.dpi_modes[i].led[0] = dpi->led1 == 0x2;
|
||||
profile.dpi_modes[i].led[1] = dpi->led2 == 0x2;
|
||||
@@ -908,8 +1046,8 @@ hidpp10_get_current_resolution(struct hidpp10_device *dev,
|
||||
return res;
|
||||
|
||||
/* resolution is in 50dpi multiples */
|
||||
*xres = hidpp_get_unaligned_le_u16(&resolution.data[4]) * 50;
|
||||
*yres = hidpp_get_unaligned_le_u16(&resolution.data[6]) * 50;
|
||||
*xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[4]));
|
||||
*yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[6]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -922,8 +1060,8 @@ hidpp10_set_current_resolution(struct hidpp10_device *dev,
|
||||
unsigned idx = dev->index;
|
||||
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_LONG, idx, SET_LONG_REGISTER_REQ);
|
||||
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[4], xres / 50);
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[6], yres / 50);
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[4], hidpp10_get_dpi_mapping(dev, xres));
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[6], hidpp10_get_dpi_mapping(dev, yres));
|
||||
|
||||
return hidpp10_request_command(dev, &resolution);
|
||||
}
|
||||
@@ -1255,5 +1393,7 @@ hidpp10_device_new(const struct hidpp_device *base, int idx)
|
||||
void
|
||||
hidpp10_device_destroy(struct hidpp10_device *dev)
|
||||
{
|
||||
if (dev->dpi_table)
|
||||
free(dev->dpi_table);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
@@ -40,9 +40,16 @@
|
||||
|
||||
#define HIDPP10_MAX_PAGE_NUMBER 31
|
||||
|
||||
struct hidpp10_dpi_mapping {
|
||||
uint8_t raw_value;
|
||||
unsigned dpi;
|
||||
};
|
||||
|
||||
struct hidpp10_device {
|
||||
struct hidpp_device base;
|
||||
unsigned index;
|
||||
uint8_t dpi_count;
|
||||
struct hidpp10_dpi_mapping *dpi_table; /* must be null terminated */
|
||||
};
|
||||
|
||||
struct hidpp10_device*
|
||||
@@ -51,6 +58,35 @@ hidpp10_device_new(const struct hidpp_device *base, int idx);
|
||||
void
|
||||
hidpp10_device_destroy(struct hidpp10_device *dev);
|
||||
|
||||
/**
|
||||
* Builds the table of dpi for the device from the given string.
|
||||
*
|
||||
* @param dev a struct hidpp10_device previously allocated
|
||||
* @param str_list a string representing the dpi table
|
||||
*
|
||||
* The given string contains only positive integer values, separated by
|
||||
* semicolons (';'). The n-th element in the list corresponds to the
|
||||
* raw value (0x80 + n - 1)
|
||||
*/
|
||||
int
|
||||
hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
|
||||
const char *str_list);
|
||||
|
||||
/**
|
||||
* Builds the table of dpi for the device from the given dpi description.
|
||||
*
|
||||
* @param dev a struct hidpp10_device previously allocated
|
||||
* @param str_dpi a string representing the dpi parameters
|
||||
*
|
||||
* The given string contains 3 float values, separated by colons (':').
|
||||
* The format is MIN:MAX@STEP
|
||||
* MIN corresponds to the raw_value '0'
|
||||
* MAX corresponds to the raw_value floor((MAX - MIN) / STEP)
|
||||
*/
|
||||
int
|
||||
hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
|
||||
const char *str_dpi);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x00: Enable HID++ Notifications */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user