mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
Add the ability to enable or disable profiles
This is especially important for the mx780, so we can get rid of the rude workaround we currently have in the driver for it. Signed-off-by: Lyude <lyude@redhat.com> Changes since v1: - Just have profile enable/disable in ratbag-command - Use bool instead of int Changes since v2: - Remove leftover function, whoops - Fix leftover ints to bools - Lots of style fixes
This commit is contained in:
@@ -310,6 +310,7 @@ struct gskill_profile_data {
|
||||
};
|
||||
|
||||
struct gskill_data {
|
||||
uint8_t profile_count;
|
||||
struct gskill_profile_data profile_data[GSKILL_PROFILE_MAX];
|
||||
};
|
||||
|
||||
@@ -499,6 +500,8 @@ gskill_get_profile_count(struct ratbag_device *device)
|
||||
return rc;
|
||||
}
|
||||
|
||||
log_debug(device->ratbag, "Profile count: %d\n", buf[3]);
|
||||
|
||||
return buf[3];
|
||||
}
|
||||
|
||||
@@ -509,6 +512,8 @@ gskill_set_profile_count(struct ratbag_device *device, unsigned int count)
|
||||
count, 0x0 };
|
||||
int rc;
|
||||
|
||||
log_debug(device->ratbag, "Setting profile count to %d\n", count);
|
||||
|
||||
rc = gskill_general_cmd(device, buf);
|
||||
if (rc) {
|
||||
log_error(device->ratbag,
|
||||
@@ -613,10 +618,6 @@ gskill_write_profile(struct ratbag_device *device,
|
||||
return rc < 0 ? rc : -EPROTO;
|
||||
}
|
||||
|
||||
rc = gskill_reload_profile_data(device);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -960,30 +961,6 @@ gskill_write_button_macro(struct ratbag_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Unfortunately if we ever try to get a profile that's above the
|
||||
* current profile limit of the mouse, we end up making it cry and barf up
|
||||
* garbage. No one likes barfing up garbage, so we unfortunately have to work
|
||||
* around this until we have the ability to enable/disable profiles in ratbag.
|
||||
*/
|
||||
static int
|
||||
gskill_workaround_profile_count(struct ratbag_device *device)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gskill_get_profile_count(device);
|
||||
if (ret == GSKILL_PROFILE_MAX)
|
||||
return 0;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
log_info(device->ratbag,
|
||||
"We don't support dynamically enabling/disabling profiles yet, sorry! Setting profile count of mouse to 5\n");
|
||||
|
||||
ret = gskill_set_profile_count(device, GSKILL_PROFILE_MAX);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gskill_probe(struct ratbag_device *device)
|
||||
{
|
||||
@@ -999,10 +976,6 @@ gskill_probe(struct ratbag_device *device)
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
ret = gskill_workaround_profile_count(device);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = gskill_get_firmware_version(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
@@ -1010,12 +983,18 @@ gskill_probe(struct ratbag_device *device)
|
||||
log_debug(device->ratbag,
|
||||
"Firmware version: %d\n", ret);
|
||||
|
||||
ret = gskill_get_profile_count(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
drv_data->profile_count = ret;
|
||||
|
||||
ratbag_device_init_profiles(device, GSKILL_PROFILE_MAX, GSKILL_NUM_DPI,
|
||||
GSKILL_BUTTON_MAX);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
|
||||
|
||||
ret = gskill_get_active_profile_idx(device);
|
||||
if (ret < 0)
|
||||
@@ -1100,6 +1079,11 @@ gskill_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
uint8_t checksum;
|
||||
int rc, retries;
|
||||
|
||||
if (index >= drv_data->profile_count) {
|
||||
profile->is_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There's a couple of situations where after various commands, the
|
||||
* mouse will get confused and send the wrong profile. Keep trying
|
||||
@@ -1215,17 +1199,25 @@ gskill_read_button(struct ratbag_button *button)
|
||||
&profile_to_pdata(profile)->report;
|
||||
struct gskill_macro_report *macro_report;
|
||||
struct ratbag_button_macro *macro;
|
||||
struct gskill_button_cfg *bcfg;
|
||||
struct gskill_button_cfg *bcfg = &report->btn_cfgs[button->index];
|
||||
struct ratbag_button_action *act = &button->action;
|
||||
|
||||
button->type = gskill_button_type_mapping[button->index];
|
||||
bcfg = &report->btn_cfgs[button->index];
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* G.Skill mice can't save disabled profiles, so buttons from disabled
|
||||
* profiles shouldn't be set to anything
|
||||
*/
|
||||
if (!profile->is_enabled) {
|
||||
act->type = RATBAG_BUTTON_ACTION_TYPE_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse any parameters that might accompany the action type */
|
||||
switch (bcfg->type) {
|
||||
case GSKILL_BUTTON_FUNCTION_WHEEL:
|
||||
@@ -1428,17 +1420,52 @@ static int
|
||||
gskill_commit(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
struct gskill_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct gskill_profile_report *report;
|
||||
uint8_t profile_count = 0, new_idx, i;
|
||||
bool reload = false;
|
||||
int rc;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
/*
|
||||
* G.Skill mice only have a concept of how many profiles are enabled,
|
||||
* not which ones are and aren't enabled. So in order to provide the
|
||||
* ability to disable individual profiles we need to only write the
|
||||
* enabled profiles and make sure no holes are left inbetween profiles
|
||||
*/
|
||||
for (i = 0; i < GSKILL_PROFILE_MAX; i++) {
|
||||
profile = ratbag_device_get_profile(device, i);
|
||||
|
||||
if (!profile->is_enabled)
|
||||
continue;
|
||||
|
||||
reload = true;
|
||||
report = &drv_data->profile_data[profile->index].report;
|
||||
new_idx = profile_count++;
|
||||
|
||||
if (new_idx == report->profile_num)
|
||||
continue;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Profile %d remapped to %d\n",
|
||||
profile->index, new_idx);
|
||||
|
||||
profile->dirty = true;
|
||||
report->profile_num = new_idx;
|
||||
}
|
||||
|
||||
if (profile_count != drv_data->profile_count) {
|
||||
rc = gskill_set_profile_count(device, profile_count);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
drv_data->profile_count = profile_count;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->is_enabled || !profile->dirty)
|
||||
continue;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Profile %d changed, rewriting\n", profile->index);
|
||||
reload = true;
|
||||
|
||||
rc = gskill_update_profile(profile);
|
||||
if (rc)
|
||||
|
||||
@@ -231,6 +231,7 @@ struct ratbag_profile {
|
||||
} resolution;
|
||||
|
||||
bool is_active; /**< profile is the currently active one */
|
||||
bool is_enabled;
|
||||
bool dirty; /**< profile changed since last commit */
|
||||
};
|
||||
|
||||
|
||||
@@ -610,6 +610,7 @@ ratbag_create_profile(struct ratbag_device *device,
|
||||
profile->resolution.modes = zalloc(num_resolutions *
|
||||
sizeof(*profile->resolution.modes));
|
||||
profile->resolution.num_modes = num_resolutions;
|
||||
profile->is_enabled = true;
|
||||
|
||||
list_insert(&device->profiles, &profile->link);
|
||||
list_init(&profile->buttons);
|
||||
@@ -714,12 +715,31 @@ ratbag_device_get_profile(struct ratbag_device *device, unsigned int index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_profile_set_enabled(struct ratbag_profile *profile, bool enabled)
|
||||
{
|
||||
if (!ratbag_device_has_capability(profile->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
profile->is_enabled = enabled;
|
||||
profile->dirty = true;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_is_active(struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->is_active;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT bool
|
||||
ratbag_profile_is_enabled(const struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->is_enabled;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
ratbag_device_get_num_profiles(struct ratbag_device *device)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@ extern "C" {
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#define LIBRATBAG_ATTRIBUTE_PRINTF(_format, _args) \
|
||||
@@ -519,6 +520,15 @@ enum ratbag_device_capability {
|
||||
* libratbag can be used to query the device as normal.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
|
||||
|
||||
/**
|
||||
* The device has the capability to disable and enable profiles. While
|
||||
* profiles are not immediately deleted after being disabled, it is not
|
||||
* guaranteed that the device will remember any disabled profiles the
|
||||
* next time ratbag runs. Furthermore, the order of profiles may get
|
||||
* changed the next time ratbag runs if profiles are disabled.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -603,6 +613,34 @@ ratbag_profile_ref(struct ratbag_profile *profile);
|
||||
struct ratbag_profile *
|
||||
ratbag_profile_unref(struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Enable/disable the ratbag profile. For this to work, the device must support
|
||||
* @ref RATBAG_DEVICE_CAP_DISABLE_PROFILE.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
* @param enable Whether to enable or disable the profile
|
||||
*
|
||||
* @return 0 on success or an error code otherwise
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_profile_set_enabled(struct ratbag_profile *profile, bool enabled);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Check whether the ratbag profile is enabled or not. For devices that don't
|
||||
* support @ref RATBAG_DEVICE_CAP_DISABLE_PROFILE the profile will always be
|
||||
* set to enabled.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
*
|
||||
* @return Whether the profile is enabled or not.
|
||||
*/
|
||||
bool
|
||||
ratbag_profile_is_enabled(const struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
|
||||
@@ -50,9 +50,11 @@ global:
|
||||
ratbag_profile_get_resolution;
|
||||
ratbag_profile_get_user_data;
|
||||
ratbag_profile_is_active;
|
||||
ratbag_profile_is_enabled;
|
||||
ratbag_profile_ref;
|
||||
ratbag_profile_set_user_data;
|
||||
ratbag_profile_set_active;
|
||||
ratbag_profile_set_enabled;
|
||||
ratbag_profile_unref;
|
||||
ratbag_resolution_get_dpi;
|
||||
ratbag_resolution_get_dpi_x;
|
||||
|
||||
@@ -101,6 +101,8 @@ usage(void)
|
||||
"Profile Commands:\n"
|
||||
" profile active get Print the currently active profile\n"
|
||||
" profile active set N Set profile N as to the active profile\n"
|
||||
" profile enable N Enable profile N\n"
|
||||
" profile disable N Disable profile N\n"
|
||||
" profile N {COMMAND} Use profile N for COMMAND\n"
|
||||
"\n"
|
||||
"Resolution Commands\n"
|
||||
@@ -351,7 +353,8 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
|
||||
if (!profile)
|
||||
continue;
|
||||
|
||||
printf(" Profile %d%s\n", i,
|
||||
printf(" Profile %d (%s)%s\n", i,
|
||||
ratbag_profile_is_enabled(profile) ? "enabled" : "disabled",
|
||||
ratbag_profile_is_active(profile) ? " (active)" : "");
|
||||
printf(" Resolutions:\n");
|
||||
for (j = 0; j < ratbag_profile_get_num_resolutions(profile); j++) {
|
||||
@@ -1562,6 +1565,60 @@ static const struct ratbag_cmd cmd_profile_active = {
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile_enable(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ratbag_device_has_capability(options->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return ERR_UNSUPPORTED;
|
||||
|
||||
ratbag_profile_set_enabled(options->profile, true);
|
||||
rc = ratbag_device_commit(options->device);
|
||||
|
||||
return rc ? ERR_DEVICE : SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_profile_enable = {
|
||||
.name = "enable",
|
||||
.cmd = ratbag_cmd_profile_enable,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile_disable(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ratbag_device_has_capability(options->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return ERR_UNSUPPORTED;
|
||||
|
||||
ratbag_profile_set_enabled(options->profile, false);
|
||||
rc = ratbag_device_commit(options->device);
|
||||
|
||||
return rc ? ERR_DEVICE : SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_profile_disable = {
|
||||
.name = "disable",
|
||||
.cmd = ratbag_cmd_profile_disable,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
@@ -1613,6 +1670,8 @@ static const struct ratbag_cmd cmd_profile = {
|
||||
.flags = FLAG_NEED_DEVICE,
|
||||
.subcommands = {
|
||||
&cmd_profile_active,
|
||||
&cmd_profile_enable,
|
||||
&cmd_profile_disable,
|
||||
&cmd_resolution,
|
||||
&cmd_button,
|
||||
NULL,
|
||||
|
||||
Reference in New Issue
Block a user