2 Commits

Author SHA1 Message Date
Thomas H.P. Andersen
84b1519ebd steelseries: port to using the firmware field in device 2020-09-29 00:54:01 +02:00
Thomas H.P. Andersen
99b8c80aee device: add firmware major/minor
This adds fields to the device struct to store the
firmware version on the device. It is also exposed
over dbus to the clients.

The firmware of a device can define the protocol
or memory layout that should be used to talk to
the device. Several devices can query the firmware
version via separate commands and we can use this
information in the drivers to change behavior of the
driver based on the device firmware.

The firmware version is also exposed over dbus so that
it is easily available for users via e.g. ratbagctl. It
can also be used in piper to warn users that a known bug
in a firmware version can cause problems when trying to
configure with libratbag.
2020-09-29 00:53:52 +02:00
17 changed files with 174 additions and 477 deletions

View File

@@ -231,10 +231,10 @@ docs_deploy: &docs_deploy
version: 2 version: 2
jobs: jobs:
fedora_32: fedora_31:
<<: *fedora_settings <<: *fedora_settings
docker: docker:
- image: fedora:32 - image: fedora:31
arch: arch:
<<: *arch_settings <<: *arch_settings
docker: docker:
@@ -246,11 +246,11 @@ jobs:
doc_build: doc_build:
<<: *doc_build <<: *doc_build
docker: docker:
- image: fedora:32 - image: fedora:31
doc_deploy: doc_deploy:
<<: *docs_deploy <<: *docs_deploy
docker: docker:
- image: fedora:32 - image: fedora:31
workflows: workflows:
@@ -259,7 +259,7 @@ workflows:
jobs: jobs:
- ubuntu_20_04 - ubuntu_20_04
- arch - arch
- fedora_32 - fedora_31
- doc_build - doc_build
- doc_deploy: - doc_deploy:
requires: requires:

View File

@@ -1,10 +0,0 @@
[Device]
Name=Dream Machines DM5 Blink
DeviceMatch=usb:258a:0027
Driver=sinowealth
[Driver/sinowealth]
Buttons=8
Leds=1
LedType=RGB
DpiRange=100:16000@100

View File

@@ -3,7 +3,3 @@ Name=Glorious Model D
DeviceMatch=usb:258a:0033 DeviceMatch=usb:258a:0033
Driver=sinowealth Driver=sinowealth
[Driver/sinowealth]
Buttons=6
Leds=2
DpiRange=100:12000@100

View File

@@ -3,8 +3,3 @@ Name=Glorious Model O
DeviceMatch=usb:258a:0036 DeviceMatch=usb:258a:0036
Driver=sinowealth Driver=sinowealth
[Driver/sinowealth]
Buttons=6
Leds=2
LedType=RBG
DpiRange=100:12000@100

View File

@@ -151,6 +151,20 @@ known to ratbagd.
Vendor or product IDs of 0 are valid IDs (e.g. used used by test Vendor or product IDs of 0 are valid IDs (e.g. used used by test
devices). devices).
.. attribute:: FirmwareMajor
:type: i
:flags: read-only, constant
The device's firmware major version.
.. attribute:: FirmwareMinor
:type: i
:flags: read-only, constant
The device's firmware minor version.
.. attribute:: Name .. attribute:: Name
:type: s :type: s

View File

@@ -2,7 +2,7 @@ project('libratbag', 'c',
version : '0.15', version : '0.15',
license : 'MIT/Expat', license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ], default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.53.0') meson_version : '>= 0.40.0')
# The DBus API version. Increase this every time the DBus API changes. # The DBus API version. Increase this every time the DBus API changes.
# No backwards/forwards guarantee, clients are expected to understand # No backwards/forwards guarantee, clients are expected to understand
@@ -351,7 +351,6 @@ data_files = files(
'data/devices/glorious-model-d.device', 'data/devices/glorious-model-d.device',
'data/devices/glorious-model-o.device', 'data/devices/glorious-model-o.device',
'data/devices/nubwo-x7-spectrum.device', 'data/devices/nubwo-x7-spectrum.device',
'data/devices/dream-machines-dm5-blink.device',
) )
install_data(data_files, install_data(data_files,
@@ -457,9 +456,10 @@ install_man('ratbagd/ratbagd.8')
# (org.freedesktop.ratbag_devel1). This server is used by ratbagdctl.devel. # (org.freedesktop.ratbag_devel1). This server is used by ratbagdctl.devel.
# #
config_ratbagd_devel = configuration_data()
dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in', dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
output : 'org.freedesktop.ratbag_devel1.conf', output : 'org.freedesktop.ratbag_devel1.conf',
copy : true) configuration : config_ratbagd_devel)
# This is a hack. We always install the devel policy file into # This is a hack. We always install the devel policy file into
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise. # /etc/dbus-1/system.d, independent of any prefixes we use otherwise.

View File

@@ -220,9 +220,45 @@ ratbag_device_get_model(sd_bus *bus,
return sd_bus_message_append(reply, "s", model); return sd_bus_message_append(reply, "s", model);
} }
static int
ratbag_device_get_firmware_major(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
int version = ratbag_device_get_firmware_major_version(device->lib_device);
CHECK_CALL(sd_bus_message_append(reply, "i", version));
return 0;
}
static int
ratbag_device_get_firmware_minor(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
int version = ratbag_device_get_firmware_minor_version(device->lib_device);
CHECK_CALL(sd_bus_message_append(reply, "i", version));
return 0;
}
const sd_bus_vtable ratbagd_device_vtable[] = { const sd_bus_vtable ratbagd_device_vtable[] = {
SD_BUS_VTABLE_START(0), SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Model", "s", ratbag_device_get_model, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Model", "s", ratbag_device_get_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareMajor", "i", ratbag_device_get_firmware_major, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareMinor", "i", ratbag_device_get_firmware_minor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@@ -515,7 +515,6 @@ int ratbagd_parse_json(const char *data, struct ratbag_test_device *device)
JsonArray *arr; JsonArray *arr;
int r = -EINVAL; int r = -EINVAL;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GList) list = NULL;
error = 0; error = 0;
parser = json_parser_new(); parser = json_parser_new();
@@ -541,7 +540,7 @@ int ratbagd_parse_json(const char *data, struct ratbag_test_device *device)
num_buttons = device->num_buttons; num_buttons = device->num_buttons;
num_leds = device->num_leds; num_leds = device->num_leds;
list = json_array_get_elements(arr); g_autoptr(GList) list = json_array_get_elements(arr);
GList *l = list; GList *l = list;
int idx = 0; int idx = 0;
while (l != NULL) { while (l != NULL) {

View File

@@ -23,36 +23,38 @@
#include "libratbag-private.h" #include "libratbag-private.h"
#include "libratbag-hidraw.h" #include "libratbag-hidraw.h"
#include "libratbag-data.h"
#define SINOWEALTH_REPORT_ID_CONFIG 0x4 #define SINOWEALTH_REPORT_ID_CONFIG 0x4
#define SINOWEALTH_REPORT_ID_CMD 0x5 #define SINOWEALTH_REPORT_ID_CMD 0x5
#define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1 #define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1
#define SINOWEALTH_CMD_GET_CONFIG 0x11 #define SINOWEALTH_CMD_GET_CONFIG 0x11
#define SINOWEALTH_CMD_GET_BUTTONS 0x12
#define SINOWEALTH_CONFIG_SIZE 520 #define SINOWEALTH_CONFIG_SIZE 520
#define SINOWEALTH_CONFIG_SIZE_USED 131 #define SINOWEALTH_CONFIG_SIZE_USED 131
#define SINOWEALTH_BUTTON_SIZE 88
#define SINOWEALTH_XY_INDEPENDENT 0x80 #define SINOWEALTH_XY_INDEPENDENT 0x80
/* The PC software only goes down to 400, but the PMW3360 doesn't care */
#define SINOWEALTH_DPI_MIN 100
#define SINOWEALTH_DPI_MAX 12000
#define SINOWEALTH_DPI_STEP 100
/* other models might have up to eight */ /* other models might have up to eight */
#define SINOWEALTH_NUM_DPIS 6 #define SINOWEALTH_NUM_DPIS 6
#define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0 #define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0
#define SINOWEALTH_RGB_SPEED_BITS 0x0F #define SINOWEALTH_RGB_SPEED_BITS 0x0F
#define SINOWEALTH_BUTTON_TYPE_BUTTON 0x11 struct sinowealth_rgb8 {
#define SINOWEALTH_BUTTON_TYPE_KEY 0x21 uint8_t r, g, b;
#define SINOWEALTH_BUTTON_TYPE_REPEATED 0x31
#define SINOWEALTH_BUTTON_TYPE_SWITCH_DPI 0x41
#define SINOWEALTH_BUTTON_TYPE_DISABLED 0x50
struct sinowealth_color {
uint8_t data[3];
} __attribute__((packed)); } __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_color) == 3, "Invalid size"); _Static_assert(sizeof(struct sinowealth_rgb8) == 3, "Invalid size");
struct sinowealth_rbg8 {
uint8_t r, b, g;
} __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_rbg8) == 3, "Invalid size");
enum rgb_effect { enum rgb_effect {
RGB_OFF = 0, RGB_OFF = 0,
@@ -86,13 +88,11 @@ struct sinowealth_config_report {
uint8_t dpi_enabled; uint8_t dpi_enabled;
/* DPI/CPI is encoded in the way the PMW3360 sensor accepts it /* DPI/CPI is encoded in the way the PMW3360 sensor accepts it
* value = (DPI - 100) / 100 * value = (DPI - 100) / 100
* or the way the PMW3389 sensor accepts it
* value = DPI / 100
* If XY are identical, dpi[0-6] contain the sensitivities, * If XY are identical, dpi[0-6] contain the sensitivities,
* while in XY independent mode each entry takes two chars for X and Y. * while in XY independent mode each entry takes two chars for X and Y.
*/ */
uint8_t dpi[16]; uint8_t dpi[16];
struct sinowealth_color dpi_color[8]; struct sinowealth_rgb8 dpi_color[8];
uint8_t rgb_effect; /* see enum rgb_effect */ uint8_t rgb_effect; /* see enum rgb_effect */
/* 0x40 - brightness (constant) /* 0x40 - brightness (constant)
* 0x1/2/3 - speed * 0x1/2/3 - speed
@@ -100,13 +100,13 @@ struct sinowealth_config_report {
uint8_t glorious_mode; uint8_t glorious_mode;
uint8_t glorious_direction; uint8_t glorious_direction;
uint8_t single_mode; uint8_t single_mode;
struct sinowealth_color single_color; struct sinowealth_rbg8 single_color;
/* 0x40 - brightness (constant) /* 0x40 - brightness (constant)
* 0x1/2/3 - speed * 0x1/2/3 - speed
*/ */
uint8_t breathing7_mode; uint8_t breathing7_mode;
uint8_t breathing7_colorcount; /* 7, constant */ uint8_t breathing7_colorcount; /* 7, constant */
struct sinowealth_color breathing7_colors[7]; struct sinowealth_rbg8 breathing7_colors[7];
/* 0x10/20/30/40 - brightness /* 0x10/20/30/40 - brightness
* 0x1/2/3 - speed * 0x1/2/3 - speed
*/ */
@@ -116,14 +116,14 @@ struct sinowealth_config_report {
* 0x1/2/3 - speed * 0x1/2/3 - speed
*/ */
uint8_t rave_mode; uint8_t rave_mode;
struct sinowealth_color rave_colors[2]; struct sinowealth_rbg8 rave_colors[2];
/* 0x10/20/30/40 - brightness /* 0x10/20/30/40 - brightness
* 0x1/2/3 - speed * 0x1/2/3 - speed
*/ */
uint8_t wave_mode; uint8_t wave_mode;
/* 0x1/2/3 - speed */ /* 0x1/2/3 - speed */
uint8_t breathing1_mode; uint8_t breathing1_mode;
struct sinowealth_color breathing1_color; struct sinowealth_rbg8 breathing1_color;
uint8_t unknown4; uint8_t unknown4;
/* 0x1 - 2 mm /* 0x1 - 2 mm
* 0x2 - 3 mm * 0x2 - 3 mm
@@ -134,96 +134,46 @@ struct sinowealth_config_report {
_Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size"); _Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
struct sinowealth_button_data {
uint8_t type;
uint8_t data[3];
} __attribute__((packed));
struct sinowealth_button_report {
uint8_t report_id;
uint8_t command_id;
uint8_t unknown1[6];
struct sinowealth_button_data buttons[20];
uint8_t padding[SINOWEALTH_CONFIG_SIZE - SINOWEALTH_BUTTON_SIZE];
} __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_button_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
enum sinowealth_sensor {
PWM3360,
PWM3389,
};
enum sinowealth_led_format {
LED_RGB,
LED_RBG,
};
struct sinowealth_data { struct sinowealth_data {
/* this is kinda unnecessary at this time, but all the other drivers do it too ;) */ /* this is kinda unnecessary at this time, but all the other drivers do it too ;) */
struct sinowealth_config_report config; struct sinowealth_config_report config;
/* holds button data so we can send back unchanged values for the buttons we do not parse yet */
struct sinowealth_button_report buttons;
/* Specifies sensor used in the device */
enum sinowealth_sensor sensor;
/* whether the devices stores the main LED in RGB or RBG format */
enum sinowealth_led_format led_type;
}; };
static int static int
sinowealth_raw_to_dpi(struct ratbag_device *device, int raw) sinowealth_raw_to_dpi(int raw)
{ {
struct sinowealth_data *drv_data = device->drv_data; return (raw + 1) * 100;
int dpi;
if (drv_data->sensor == PWM3360)
dpi = (raw + 1) * 100;
else
dpi = raw * 100;
return dpi;
} }
static int static int
sinowealth_dpi_to_raw(struct ratbag_device *device, unsigned int dpi) sinowealth_dpi_to_raw(int dpi)
{ {
struct sinowealth_data *drv_data = device->drv_data; assert(dpi >= SINOWEALTH_DPI_MIN && dpi <= SINOWEALTH_DPI_MAX);
struct dpi_range *dpirange = NULL; return dpi / 100 - 1;
int raw;
dpirange = ratbag_device_data_sinowealth_get_dpi_range(device->data);
assert(dpi >= dpirange->min && dpi <= dpirange->max);
if (drv_data->sensor == PWM3360)
raw = dpi / 100 - 1;
else
raw = dpi / 100;
return raw;
} }
static struct ratbag_color static struct ratbag_color
sinowealth_raw_to_color(struct sinowealth_color raw) sinowealth_raw_to_color(struct sinowealth_rgb8 raw)
{ {
return (struct ratbag_color) {.red = raw.data[0], .green = raw.data[1], .blue = raw.data[2]}; return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
} }
static struct sinowealth_color static struct sinowealth_rgb8
sinowealth_color_to_raw(struct ratbag_color color) sinowealth_color_to_raw(struct ratbag_color color)
{ {
return (struct sinowealth_color) {.data[0] = color.red, .data[1] = color.green, .data[2] = color.blue}; return (struct sinowealth_rgb8) {.r = color.red, .g = color.green, .b = color.blue};
} }
static struct ratbag_color static struct ratbag_color
sinowealth_rbg_to_color(struct sinowealth_color raw) sinowealth_rbg_to_color(struct sinowealth_rbg8 raw)
{ {
return (struct ratbag_color) {.red = raw.data[0], .green = raw.data[2], .blue = raw.data[1]}; return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
} }
static struct sinowealth_color static struct sinowealth_rbg8
sinowealth_color_to_rbg(struct ratbag_color color) sinowealth_color_to_rbg(struct ratbag_color color)
{ {
return (struct sinowealth_color) {.data[0] = color.red, .data[2] = color.green, .data[1] = color.blue}; return (struct sinowealth_rbg8) {.r = color.red, .g = color.green, .b = color.blue};
} }
static int static int
@@ -316,10 +266,10 @@ sinowealth_read_profile(struct ratbag_profile *profile)
ratbag_profile_for_each_resolution(profile, resolution) { ratbag_profile_for_each_resolution(profile, resolution) {
if (config->config & SINOWEALTH_XY_INDEPENDENT) { if (config->config & SINOWEALTH_XY_INDEPENDENT) {
resolution->dpi_x = sinowealth_raw_to_dpi(device, config->dpi[resolution->index * 2]); resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2]);
resolution->dpi_y = sinowealth_raw_to_dpi(device, config->dpi[resolution->index * 2 + 1]); resolution->dpi_y = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2 + 1]);
} else { } else {
resolution->dpi_x = sinowealth_raw_to_dpi(device, config->dpi[resolution->index]); resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index]);
resolution->dpi_y = resolution->dpi_x; resolution->dpi_y = resolution->dpi_x;
} }
if (config->dpi_enabled & (1<<resolution->index)) { if (config->dpi_enabled & (1<<resolution->index)) {
@@ -327,7 +277,7 @@ sinowealth_read_profile(struct ratbag_profile *profile)
resolution->dpi_x = 0; resolution->dpi_x = 0;
resolution->dpi_y = 0; resolution->dpi_y = 0;
} }
resolution->is_active = resolution->index == config->active_dpi - 1u; resolution->is_active = resolution->index == config->active_dpi - 1;
resolution->is_default = resolution->is_active; resolution->is_default = resolution->is_active;
} }
@@ -339,10 +289,7 @@ sinowealth_read_profile(struct ratbag_profile *profile)
break; break;
case RGB_SINGLE: case RGB_SINGLE:
led->mode = RATBAG_LED_ON; led->mode = RATBAG_LED_ON;
if (drv_data->led_type == LED_RGB) led->color = sinowealth_rbg_to_color(config->single_color);
led->color = sinowealth_raw_to_color(config->single_color);
else
led->color = sinowealth_rbg_to_color(config->single_color);
led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode); led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode);
break; break;
case RGB_GLORIOUS: case RGB_GLORIOUS:
@@ -367,243 +314,43 @@ sinowealth_read_profile(struct ratbag_profile *profile)
return 0; return 0;
} }
struct sinowealth_button_mapping {
uint8_t raw;
struct ratbag_button_action action;
};
static struct sinowealth_button_mapping sinowealth_button_mapping[] = {
{ 0x01, BUTTON_ACTION_BUTTON(1) },
{ 0x02, BUTTON_ACTION_BUTTON(2) },
{ 0x04, BUTTON_ACTION_BUTTON(3) },
{ 0x08, BUTTON_ACTION_BUTTON(5) },
{ 0x10, BUTTON_ACTION_BUTTON(4) },
};
static const struct ratbag_button_action*
sinowealth_raw_to_button_action(uint8_t data)
{
struct sinowealth_button_mapping *mapping;
ARRAY_FOR_EACH(sinowealth_button_mapping, mapping) {
if (mapping->raw == data)
return &mapping->action;
}
return NULL;
}
static uint8_t
sinowealth_button_action_to_raw(const struct ratbag_button_action *action)
{
struct sinowealth_button_mapping *mapping;
ARRAY_FOR_EACH(sinowealth_button_mapping, mapping) {
if (ratbag_button_action_match(&mapping->action, action))
return mapping->raw;
}
return 0x00;
}
static int
sinowealth_read_buttons(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct sinowealth_data *drv_data = device->drv_data;
struct sinowealth_button_report *buf = &drv_data->buttons;
struct ratbag_button *button;
struct sinowealth_button_data button_data;
enum ratbag_button_type button_types[8] = {RATBAG_BUTTON_TYPE_UNKNOWN};
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_BUTTONS};
int rc;
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
if (rc != sizeof(cmd)) {
log_error(device->ratbag, "Error while sending read config command: %d\n", rc);
return -1;
}
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG, (uint8_t*) buf, SINOWEALTH_CONFIG_SIZE);
if (rc != SINOWEALTH_BUTTON_SIZE) {
log_error(device->ratbag, "Could not read device button configuration: %d\n", rc);
return -1;
}
button_types[0] = RATBAG_BUTTON_TYPE_LEFT;
button_types[1] = RATBAG_BUTTON_TYPE_RIGHT;
button_types[2] = RATBAG_BUTTON_TYPE_MIDDLE;
button_types[3] = RATBAG_BUTTON_TYPE_THUMB;
button_types[4] = RATBAG_BUTTON_TYPE_THUMB2;
button_types[5] = RATBAG_BUTTON_TYPE_RESOLUTION_UP;
button_types[6] = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN;
button_types[7] = RATBAG_BUTTON_TYPE_THUMB3;
ratbag_profile_for_each_button(profile, button) {
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
button->type = button_types[button->index];
button_data = buf->buttons[button->index];
if (button_data.type == SINOWEALTH_BUTTON_TYPE_BUTTON) {
const struct ratbag_button_action *action;
action = sinowealth_raw_to_button_action(button_data.data[0]);
if (action)
ratbag_button_set_action(button, action);
} else if (button_data.type == SINOWEALTH_BUTTON_TYPE_KEY) {
unsigned int key, modifiers;
int rc;
key = ratbag_hidraw_get_keycode_from_keyboard_usage(device, button_data.data[1]);
modifiers = 0;
if (button_data.data[0] & 0x01)
modifiers |= MODIFIER_LEFTCTRL;
if (button_data.data[0] & 0x02)
modifiers |= MODIFIER_LEFTSHIFT;
if (button_data.data[0] & 0x04)
modifiers |= MODIFIER_LEFTALT;
if (button_data.data[0] & 0x08)
modifiers |= MODIFIER_LEFTMETA;
rc = ratbag_button_macro_new_from_keycode(button, key, modifiers);
if (rc < 0) {
log_error(device->ratbag,
"Error while reading button %d\n",
button->index);
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
}
}
}
return 0;
}
static int
sinowealth_write_buttons(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct sinowealth_data *drv_data = device->drv_data;
struct sinowealth_button_report *buf = &drv_data->buttons;
struct ratbag_button *button;
int rc;
buf->report_id = 0x04;
buf->command_id = 0x12;
buf->unknown1[1] = 0x50;
ratbag_profile_for_each_button(profile, button) {
struct sinowealth_button_data *button_data;
struct ratbag_button_action *action = &button->action;
button_data = &buf->buttons[button->index];
if (action->type == RATBAG_BUTTON_ACTION_TYPE_BUTTON) {
button_data->type = SINOWEALTH_BUTTON_TYPE_BUTTON;
button_data->data[0] = sinowealth_button_action_to_raw(action);
} else if (action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) {
unsigned int key, modifiers;
rc = ratbag_action_keycode_from_macro(action,
&key,
&modifiers);
if (rc < 0) {
log_error(device->ratbag,
"Error while writing macro for button %d\n",
button->index);
}
button_data->type = SINOWEALTH_BUTTON_TYPE_KEY;
button_data->data[0] = modifiers;
button_data->data[1] = ratbag_hidraw_get_keyboard_usage_from_keycode(device, key);
}
}
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
(uint8_t*) buf, SINOWEALTH_CONFIG_SIZE);
if (rc != SINOWEALTH_CONFIG_SIZE) {
log_error(device->ratbag, "Error while writing buttons: %d\n", rc);
return -1;
}
return 0;
}
static void static void
sinowealth_init_profile(struct ratbag_device *device) sinowealth_init_profile(struct ratbag_device *device)
{ {
struct ratbag_profile *profile; struct ratbag_profile *profile;
struct ratbag_resolution *resolution; struct ratbag_resolution *resolution;
struct ratbag_led *led; struct ratbag_led *led;
struct sinowealth_data *drv_data = device->drv_data; /* number of DPIs = all DPIs from min to max (inclusive) and "0 DPI" as a special value
struct dpi_range *dpirange = NULL; * to signal a disabled DPI step.
int button_count, led_count; */
const char *led_type; int num_dpis = (SINOWEALTH_DPI_MAX - SINOWEALTH_DPI_MIN) / SINOWEALTH_DPI_STEP + 2;
unsigned int dpis[num_dpis];
dpirange = ratbag_device_data_sinowealth_get_dpi_range(device->data); /* TODO: Button remapping */
button_count = ratbag_device_data_sinowealth_get_button_count(device->data); ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, 0, 1);
led_count = ratbag_device_data_sinowealth_get_led_count(device->data);
led_type = ratbag_device_data_sinowealth_get_led_type(device->data);
if (!dpirange)
{
log_error(device->ratbag, "DpiRange must be defined in .device file\n");
}
if (button_count < 0)
{
log_error(device->ratbag, "Button count must be defined in .device file\n");
button_count = 0;
}
if (led_count < 0)
{
log_error(device->ratbag, "Led count must be defined in .device file\n");
led_count = 0;
}
if (!led_type)
log_error(device->ratbag, "Led type must be defined in .device file. Defaulting to RGB.\n");
if (dpirange->max == 12000)
drv_data->sensor = PWM3360;
else
drv_data->sensor = PWM3389;
if (led_type && streq(led_type, "RBG"))
drv_data->led_type = LED_RBG;
else
drv_data->led_type = LED_RGB;
ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, button_count, led_count);
profile = ratbag_device_get_profile(device, 0); profile = ratbag_device_get_profile(device, 0);
/* Generate DPI list */
dpis[0] = 0; /* 0 DPI = disabled */
for (int i = 1; i < num_dpis; i++) {
dpis[i] = SINOWEALTH_DPI_MIN + (i - 1) * SINOWEALTH_DPI_STEP;
}
ratbag_profile_for_each_resolution(profile, resolution) { ratbag_profile_for_each_resolution(profile, resolution) {
ratbag_resolution_set_dpi_list_from_range(resolution, ratbag_resolution_set_dpi_list(resolution, dpis, num_dpis);
dpirange->min,
dpirange->max);
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
} }
/* Set up LED capabilities */ /* Set up LED capabilities */
ratbag_profile_for_each_led(profile, led) { led = ratbag_profile_get_led(profile, 0);
if (led->index == 0) { led->type = RATBAG_LED_TYPE_SIDE;
led->type = RATBAG_LED_TYPE_SIDE; led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888; ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF); ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_ON); ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE); ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING); ratbag_led_unref(led);
} else {
led->type = RATBAG_LED_TYPE_DPI;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
}
}
ratbag_profile_unref(profile); ratbag_profile_unref(profile);
} }
@@ -638,12 +385,6 @@ sinowealth_probe(struct ratbag_device *device)
goto err; goto err;
} }
rc = sinowealth_read_buttons(profile);
if (rc) {
rc = -ENODEV;
goto err;
}
return 0; return 0;
err: err:
@@ -677,10 +418,10 @@ sinowealth_commit(struct ratbag_device *device)
if (!resolution->dpi_x || !resolution->dpi_y) if (!resolution->dpi_x || !resolution->dpi_y)
continue; continue;
if (config->config & SINOWEALTH_XY_INDEPENDENT) { if (config->config & SINOWEALTH_XY_INDEPENDENT) {
config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(device, resolution->dpi_x); config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(resolution->dpi_x);
config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(device, resolution->dpi_y); config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(resolution->dpi_y);
} else { } else {
config->dpi[resolution->index] = sinowealth_dpi_to_raw(device, resolution->dpi_x); config->dpi[resolution->index] = sinowealth_dpi_to_raw(resolution->dpi_x);
} }
dpi_enabled |= 1<<resolution->index; dpi_enabled |= 1<<resolution->index;
config->dpi_count++; config->dpi_count++;
@@ -695,17 +436,14 @@ sinowealth_commit(struct ratbag_device *device)
break; break;
case RATBAG_LED_ON: case RATBAG_LED_ON:
config->rgb_effect = RGB_SINGLE; config->rgb_effect = RGB_SINGLE;
if (drv_data->led_type == LED_RGB) config->single_color = sinowealth_color_to_rbg(led->color);
config->single_color = sinowealth_color_to_raw(led->color);
else
config->single_color = sinowealth_color_to_rbg(led->color);
break; break;
case RATBAG_LED_CYCLE: case RATBAG_LED_CYCLE:
config->rgb_effect = RGB_GLORIOUS; config->rgb_effect = RGB_GLORIOUS;
config->glorious_mode = sinowealth_led_to_rgb_mode(led); config->glorious_mode = sinowealth_led_to_rgb_mode(led);
break; break;
case RATBAG_LED_BREATHING: case RATBAG_LED_BREATHING:
config->rgb_effect = RGB_BREATHING7; config->rgb_effect = RGB_BREATHING1;
config->breathing1_color = sinowealth_color_to_rbg(led->color); config->breathing1_color = sinowealth_color_to_rbg(led->color);
config->breathing1_mode = sinowealth_led_to_rgb_mode(led); config->breathing1_mode = sinowealth_led_to_rgb_mode(led);
break; break;
@@ -722,10 +460,8 @@ sinowealth_commit(struct ratbag_device *device)
return -1; return -1;
} }
rc = sinowealth_write_buttons(profile);
ratbag_profile_unref(profile); ratbag_profile_unref(profile);
return rc; return 0;
} }
static void static void

View File

@@ -78,11 +78,6 @@
#define STEELSERIES_BUTTON_KBD 0x51 #define STEELSERIES_BUTTON_KBD 0x51
#define STEELSERIES_BUTTON_CONSUMER 0x61 #define STEELSERIES_BUTTON_CONSUMER 0x61
struct steelseries_data {
int firmware_major;
int firmware_minor;
};
struct steelseries_point { struct steelseries_point {
struct list link; struct list link;
@@ -177,7 +172,6 @@ button_defaults_for_layout(struct ratbag_button *button, int button_count)
static int static int
steelseries_get_firmware_version(struct ratbag_device *device) steelseries_get_firmware_version(struct ratbag_device *device)
{ {
struct steelseries_data *drv_data = device->drv_data;
int device_version = ratbag_device_data_steelseries_get_device_version(device->data); int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
size_t buf_len = STEELSERIES_REPORT_SIZE; size_t buf_len = STEELSERIES_REPORT_SIZE;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0}; uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
@@ -199,8 +193,8 @@ steelseries_get_firmware_version(struct ratbag_device *device)
if (ret < 0) if (ret < 0)
return ret; return ret;
drv_data->firmware_major = buf[1]; device->firmware_major = buf[1];
drv_data->firmware_minor = buf[0]; device->firmware_minor = buf[0];
return 0; return 0;
} }
@@ -265,7 +259,6 @@ steelseries_read_settings(struct ratbag_device *device)
static int static int
steelseries_probe(struct ratbag_device *device) steelseries_probe(struct ratbag_device *device)
{ {
struct steelseries_data *drv_data = NULL;
struct ratbag_profile *profile = NULL; struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution; struct ratbag_resolution *resolution;
struct ratbag_button *button; struct ratbag_button *button;
@@ -363,14 +356,11 @@ steelseries_probe(struct ratbag_device *device)
} }
} }
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
rc = steelseries_get_firmware_version(device); rc = steelseries_get_firmware_version(device);
if(rc == 0) if(rc == 0)
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n", log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
drv_data->firmware_major, device->firmware_major,
drv_data->firmware_minor); device->firmware_minor);
steelseries_read_settings(device); steelseries_read_settings(device);
@@ -960,7 +950,6 @@ steelseries_remove(struct ratbag_device *device)
{ {
ratbag_close_hidraw_index(device, 0); ratbag_close_hidraw_index(device, 0);
ratbag_close_hidraw_index(device, 1); ratbag_close_hidraw_index(device, 1);
free(ratbag_get_drv_data(device));
} }
struct ratbag_driver steelseries_driver = { struct ratbag_driver steelseries_driver = {

View File

@@ -82,13 +82,6 @@ struct data_steelseries {
int short_button; int short_button;
}; };
struct data_sinowealth {
int button_count;
int led_count;
char *led_type;
struct dpi_range *dpi_range;
};
struct ratbag_device_data { struct ratbag_device_data {
int refcount; int refcount;
char *name; char *name;
@@ -100,7 +93,6 @@ struct ratbag_device_data {
struct data_hidpp20 hidpp20; struct data_hidpp20 hidpp20;
struct data_hidpp10 hidpp10; struct data_hidpp10 hidpp10;
struct data_steelseries steelseries; struct data_steelseries steelseries;
struct data_sinowealth sinowealth;
}; };
enum ratbag_led_type led_types[20]; enum ratbag_led_type led_types[20];
@@ -262,50 +254,6 @@ init_data_steelseries(struct ratbag *ratbag,
g_error_free(error); g_error_free(error);
} }
static void
init_data_sinowealth(struct ratbag *ratbag,
GKeyFile *keyfile,
struct ratbag_device_data *data)
{
const char *group = "Driver/sinowealth";
GError *error = NULL;
_cleanup_(freep) char *str = NULL;
int num;
char *led_type;
data->sinowealth.button_count = -1;
data->sinowealth.led_count = -1;
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (num != 0 || !error)
data->sinowealth.button_count = num;
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
if (num > 0 || !error)
data->sinowealth.led_count = num;
if (error)
g_error_free(error);
error = NULL;
led_type = g_key_file_get_string(keyfile, group, "LedType", NULL);
if (led_type)
data->sinowealth.led_type = led_type;
if (error)
g_error_free(error);
error = NULL;
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
if (str)
data->sinowealth.dpi_range = dpi_range_from_string(str);
error = NULL;
}
static const struct driver_map { static const struct driver_map {
enum driver map; enum driver map;
const char *driver; const char *driver;
@@ -321,7 +269,7 @@ static const struct driver_map {
{ LOGITECH_G300, "logitech_g300", NULL}, { LOGITECH_G300, "logitech_g300", NULL},
{ LOGITECH_G600, "logitech_g600", NULL}, { LOGITECH_G600, "logitech_g600", NULL},
{ STEELSERIES, "steelseries", init_data_steelseries }, { STEELSERIES, "steelseries", init_data_steelseries },
{ SINOWEALTH, "sinowealth", init_data_sinowealth }, { SINOWEALTH, "sinowealth", NULL },
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL}, { SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
}; };
@@ -722,35 +670,3 @@ ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data
return data->steelseries.short_button; return data->steelseries.short_button;
} }
int
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.button_count;
}
int
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.led_count;
}
struct dpi_range *
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data)
{
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.dpi_range;
}
const char *
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data)
{
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.led_type;
}

View File

@@ -120,22 +120,3 @@ ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *dat
int int
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data); ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data);
/**
* @return The button count or -1 if not set
*/
int
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data);
/**
* @return The led count or -1 if not set
*/
int
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data);
struct dpi_range *
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data);
const char *
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data);

View File

@@ -147,6 +147,9 @@ struct ratbag_device {
unsigned num_buttons; unsigned num_buttons;
unsigned num_leds; unsigned num_leds;
int firmware_major;
int firmware_minor;
void *drv_data; void *drv_data;
struct list link; struct list link;

View File

@@ -545,6 +545,18 @@ ratbag_device_get_product_id(const struct ratbag_device *device)
return device->ids.product; return device->ids.product;
} }
LIBRATBAG_EXPORT int32_t
ratbag_device_get_firmware_major_version(const struct ratbag_device *device)
{
return device->firmware_major;
}
LIBRATBAG_EXPORT int32_t
ratbag_device_get_firmware_minor_version(const struct ratbag_device *device)
{
return device->firmware_minor;
}
LIBRATBAG_EXPORT uint32_t LIBRATBAG_EXPORT uint32_t
ratbag_device_get_product_version(const struct ratbag_device *device) ratbag_device_get_product_version(const struct ratbag_device *device)
{ {

View File

@@ -421,6 +421,24 @@ ratbag_device_set_user_data(struct ratbag_device *device, void *userdata);
void* void*
ratbag_device_get_user_data(const struct ratbag_device *device); ratbag_device_get_user_data(const struct ratbag_device *device);
/**
* @ingroup device
*
* @param device A previously initialized ratbag device
* @return The firmware major version of the device.
*/
int32_t
ratbag_device_get_firmware_major_version(const struct ratbag_device *device);
/**
* @ingroup device
*
* @param device A previously initialized ratbag device
* @return The firmware minor version of the device.
*/
int32_t
ratbag_device_get_firmware_minor_version(const struct ratbag_device *device);
/** /**
* @ingroup device * @ingroup device
* *

View File

@@ -212,6 +212,8 @@ def print_device(d, level):
print(" " * level + "{} - {}".format(d.id, d.name)) print(" " * level + "{} - {}".format(d.id, d.name))
print(" " * level + " Model: {}".format(d.model)) print(" " * level + " Model: {}".format(d.model))
if d.firmware_major > 0 or d.firmware_minor > 0:
print(" " * level + " Firmware version: {}.{}".format(d.firmware_major, d.firmware_minor))
print(" " * level + " Number of Buttons: {}".format(len(p.buttons))) print(" " * level + " Number of Buttons: {}".format(len(p.buttons)))
print(" " * level + " Number of Leds: {}".format(len(p.leds))) print(" " * level + " Number of Leds: {}".format(len(p.leds)))
print(" " * level + "Number of Profiles: {}".format(len(d.profiles))) print(" " * level + "Number of Profiles: {}".format(len(d.profiles)))

View File

@@ -342,6 +342,16 @@ class RatbagdDevice(_RatbagdDBus):
"""The unique identifier for this device model.""" """The unique identifier for this device model."""
return self._get_dbus_property("Model") return self._get_dbus_property("Model")
@GObject.Property
def firmware_major(self):
"""The firmware major version."""
return self._get_dbus_property("FirmwareMajor")
@GObject.Property
def firmware_minor(self):
"""The firmware minor version."""
return self._get_dbus_property("FirmwareMinor")
@GObject.Property @GObject.Property
def name(self): def name(self):
"""The device name, usually provided by the kernel.""" """The device name, usually provided by the kernel."""