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:
Lyude
2016-11-09 14:42:31 -05:00
committed by Peter Hutterer
parent a1a3750bc8
commit 52d4e35192
6 changed files with 185 additions and 38 deletions

View File

@@ -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)

View File

@@ -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 */
};

View File

@@ -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)
{

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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,