1
0
forked from drath/libratbag
Files
libratbag-plus/src/hidpp20.h
Ilya Guterman 48bccf4c98 hidpp20: fetch active profile index only once
currently the active profile index is fetched for each profile,
this adds unnecessary overhead.

change the behavior to fetch the active profile only once during the driver data initialization.
2022-06-06 15:11:02 +10:00

1030 lines
32 KiB
C

/*
* HID++ 2.0 library - headers file.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
* Based on the HID++ 2.0 documentation provided by Nestor Lopez Casado at:
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#pragma once
#include <stdint.h>
#include "hidpp-generic.h"
#include "libratbag-util.h"
struct _hidpp20_message {
uint8_t report_id;
uint8_t device_idx;
uint8_t sub_id;
uint8_t address;
uint8_t parameters[LONG_MESSAGE_LENGTH - 4U];
} __attribute__((packed));
union hidpp20_message {
struct _hidpp20_message msg;
uint8_t data[LONG_MESSAGE_LENGTH];
};
struct hidpp20_feature {
uint16_t feature;
uint8_t type;
};
enum hidpp20_quirk {
HIDPP20_QUIRK_NONE,
HIDPP20_QUIRK_G305,
HIDPP20_QUIRK_G602,
};
struct hidpp20_device {
struct hidpp_device base;
unsigned int index;
unsigned proto_major;
unsigned proto_minor;
unsigned feature_count;
struct hidpp20_feature *feature_list;
enum hidpp20_quirk quirk;
unsigned int led_ext_caps;
};
int hidpp20_request_command(struct hidpp20_device *dev, union hidpp20_message *msg);
#define CASE_RETURN_STRING(a) case a: return #a; break
const char *hidpp20_feature_get_name(uint16_t feature);
const char *hidpp20_get_quirk_string(enum hidpp20_quirk quirk);
/* -------------------------------------------------------------------------- */
/* generic hidpp20 device operations */
/* -------------------------------------------------------------------------- */
struct hidpp20_device *
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx,
struct hidpp_hid_report *reports, unsigned int num_reports);
void
hidpp20_device_destroy(struct hidpp20_device *device);
/* -------------------------------------------------------------------------- */
/* 0x0000: Root */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_ROOT 0x0000
int hidpp_root_get_feature(struct hidpp20_device *device,
uint16_t feature,
uint8_t *feature_index,
uint8_t *feature_type,
uint8_t *feature_version);
int hidpp20_root_get_protocol_version(struct hidpp20_device *dev,
unsigned *major,
unsigned *minor);
/* -------------------------------------------------------------------------- */
/* 0x0001: Feature Set */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_FEATURE_SET 0x0001
/* -------------------------------------------------------------------------- */
/* 0x0003: Device Info */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_DEVICE_INFO 0x0003
/* -------------------------------------------------------------------------- */
/* 0x0005: Device Name */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_DEVICE_NAME 0x0005
/* -------------------------------------------------------------------------- */
/* 0x0020: Reset */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_RESET 0x0020
/* -------------------------------------------------------------------------- */
/* 0x1000: Battery level status */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_BATTERY_LEVEL_STATUS 0x1000
enum hidpp20_battery_status {
BATTERY_STATUS_DISCHARGING = 0,
BATTERY_STATUS_RECHARGING,
BATTERY_STATUS_CHARGING_IN_FINAL_STATE,
BATTERY_STATUS_CHARGE_COMPLETE,
BATTERY_STATUS_RECHARGING_BELOW_OPTIMAL_SPEED,
BATTERY_STATUS_INVALID_BATTERY_TYPE,
BATTERY_STATUS_THERMAL_ERROR,
BATTERY_STATUS_OTHER_CHARGING_ERROR,
BATTERY_STATUS_INVALID,
};
/**
* Retrieves the battery level status.
*
* @return the battery status or a negative errno on error
*/
int hidpp20_batterylevel_get_battery_level(struct hidpp20_device *device,
uint16_t *level,
uint16_t *next_level);
/* -------------------------------------------------------------------------- */
/* 0x1001: Battery Voltage */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_BATTERY_VOLTAGE 0x1001
enum hidpp20_battery_voltage_status {
BATTERY_VOLTAGE_STATUS_DISCHARGING = 0,
BATTERY_VOLTAGE_STATUS_WIRELESS_CHARGING = 0x10,
BATTERY_VOLTAGE_STATUS_CHARGING = 0x80,
};
/**
* Retrieves the battery voltage
*
* @return the battery status or a negative errno on error
*/
int hidpp20_batteryvoltage_get_battery_voltage(struct hidpp20_device *device,
uint16_t *voltage);
/* -------------------------------------------------------------------------- */
/* 0x1300: LED software control */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_LED_SW_CONTROL 0x1300
enum hidpp20_led_sw_ctrl_led_type {
HIDPP20_LED_TYPE_BATTERY = 0x01,
HIDPP20_LED_TYPE_DPI,
HIDPP20_LED_TYPE_PROFILE,
HIDPP20_LED_TYPE_LOGO,
HIDPP20_LED_TYPE_COSMETIC
};
enum hidpp20_led_sw_ctrl_led_mode {
HIDPP20_LED_MODE_OFF = 0x01,
HIDPP20_LED_MODE_ON = 0x02,
HIDPP20_LED_MODE_BLINK = 0x04,
HIDPP20_LED_MODE_TRAVEL = 0x08,
HIDPP20_LED_MODE_RAMP_UP = 0x10,
HIDPP20_LED_MODE_RAMP_DOWN = 0x20,
HIDPP20_LED_MODE_HEARTBEAT = 0x40,
HIDPP20_LED_MODE_BREATHING = 0x80
};
#define HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL 0xff
struct hidpp20_led_sw_ctrl_led_info {
uint8_t index;
uint8_t type;
uint8_t physical_count;
uint16_t caps;
uint8_t nvconfig_caps;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_led_sw_ctrl_led_info) == 6, "Invalid size");
struct hidpp20_led_sw_ctrl_led_state {
uint8_t index;
uint16_t mode;
union {
struct hidpp20_led_breathing {
uint16_t brightness;
uint16_t period;
uint16_t timeout;
} breathing;
struct hidpp20_led_traveling {
uint16_t unused;
uint16_t delay;
} traveling;
struct hidpp20_led_blink {
uint16_t index;
uint16_t on_time;
uint16_t off_time;
} blink;
struct hidpp20_led_on {
/* Logical information to display on the LED
* Meaning and value range depend on the LED
*/
uint16_t index;
} on;
};
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_led_sw_ctrl_led_state) == 9, "Invalid size");
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
struct hidpp20_led_sw_ctrl_led_info** info_list);
const char*
hidpp20_sw_led_control_get_mode_string(const enum hidpp20_led_sw_ctrl_led_mode mode);
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
struct hidpp20_led_sw_ctrl_led_info** info_list);
/**
* Retrieves the number of non-RGB logical leds from the mouse
* @return the led count or a negative errno
*/
int hidpp20_led_sw_control_get_led_count(struct hidpp20_device* device);
/**
* Retrieves the info for a given logical led
* @return 0 or a negative errno in case of error
*/
int hidpp20_led_sw_control_get_led_info(struct hidpp20_device* device,
uint8_t led_idx,
struct hidpp20_led_sw_ctrl_led_info* info);
/**
* Reads all LEDs on the device for their current state
* @return 0 on success or a negative errno
*/
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
struct hidpp20_led_sw_ctrl_led_info** info_list);
/**
* Get the current sw control value
* @return 0 if the leds are sofware-controlled 1 if they are firmware controlled
*/
bool hidpp20_led_sw_control_get_sw_ctrl(struct hidpp20_device* device);
/**
* Sets who controls the LEDs
* ctrl = 0, the software controls the LEDs
* ctrl = 1, the firmware controls the LEDs
* @return 0 on success or a negative errno
*/
int hidpp20_led_sw_control_set_sw_ctrl(struct hidpp20_device* device, bool ctrl);
/**
* Gets the state of a LED
* @return 0 on success or a negative errno
*/
int hidpp20_led_sw_control_get_led_state(struct hidpp20_device* device,
uint8_t led_idx,
struct hidpp20_led_sw_ctrl_led_state* state);
/**
* Sets the state of a LED
* The LED index should be passed in the state structure
* @return 0 on success or a negative errno
*/
int hidpp20_led_sw_control_set_led_state(struct hidpp20_device* device,
const struct hidpp20_led_sw_ctrl_led_state* state);
/* -------------------------------------------------------------------------- */
/* 0x1b00: KBD reprogrammable keys and mouse buttons */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_KBD_REPROGRAMMABLE_KEYS 0x1b00
enum hidpp2_controL_id_flags {
HIDPP20_CONTROL_ID_FLAG_NONE = 0,
HIDPP20_CONTROL_ID_FLAG_MOUSE_BUTTON = (1 << 0), /**< Is a mouse button */
HIDPP20_CONTROL_ID_FLAG_FN_KEY = (1 << 1), /**< Is a fn button */
HIDPP20_CONTROL_ID_FLAG_HOTKEY = (1 << 2), /**< Is a Hot key, not a standard kbd key */
HIDPP20_CONTROL_ID_FLAG_FN_TOGGLE_AFFECTED = (1 << 3), /**< Fn toggle affects this key */
HIDPP20_CONTROL_ID_FLAG_REPROGRAMMABLE = (1 << 4), /**< Key can be reprogrammed */
};
struct hidpp20_control_id {
uint8_t index;
uint16_t control_id;
uint16_t task_id;
uint8_t flags;
/* fields below are only set for 0x1b04, not for 0x1b00 */
uint8_t position;
uint8_t group;
uint8_t group_mask;
uint8_t raw_XY;
struct {
uint8_t raw_XY;
uint8_t persist;
uint8_t divert;
uint16_t remapped;
int updated;
} reporting;
};
int hidpp20_kbd_reprogrammable_keys_get_controls(struct hidpp20_device *device,
struct hidpp20_control_id **controls_list);
/* -------------------------------------------------------------------------- */
/* 0x1b04: Special keys and mouse buttons */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_SPECIAL_KEYS_BUTTONS 0x1b04
/**
* allocates a list of controls that has to be freed by the caller.
*
* returns the elements in the list or a negative error
*/
int hidpp20_special_key_mouse_get_controls(struct hidpp20_device *device,
struct hidpp20_control_id **controls_list);
/**
* commit a control previously allocated by
* hidpp20_special_key_mouse_get_controls().
*
* returns 0 or a negative error
*/
int hidpp20_special_key_mouse_set_control(struct hidpp20_device *device,
struct hidpp20_control_id *control);
const struct ratbag_button_action *hidpp20_1b04_get_logical_mapping(uint16_t value);
uint16_t hidpp20_1b04_get_logical_control_id(const struct ratbag_button_action *action);
const char *hidpp20_1b04_get_logical_mapping_name(uint16_t value);
enum ratbag_button_type hidpp20_1b04_get_physical_mapping(uint16_t value);
const char *hidpp20_1b04_get_physical_mapping_name(uint16_t value);
/* -------------------------------------------------------------------------- */
/* 0x1d4b: Wireless Device Status */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_WIRELESS_DEVICE_STATUS 0x1d4b
/* -------------------------------------------------------------------------- */
/* 0x2200: Mouse Pointer Basic Optical Sensors */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_MOUSE_POINTER_BASIC 0x2200
#define HIDDP20_MOUSE_POINTER_FLAGS_VERTICAL_TUNING (1 << 4)
#define HIDDP20_MOUSE_POINTER_FLAGS_OS_BALLISTICS (1 << 3)
#define HIDDP20_MOUSE_POINTER_FLAGS_ACCELERATION_MASK 0x03
#define HIDDP20_MOUSE_POINTER_ACCELERATION_NONE 0x00
#define HIDDP20_MOUSE_POINTER_ACCELERATION_LOW 0x01
#define HIDDP20_MOUSE_POINTER_ACCELERATION_MEDIUM 0x02
#define HIDDP20_MOUSE_POINTER_ACCELERATION_HIGH 0x03
int hidpp20_mousepointer_get_mousepointer_info(struct hidpp20_device *device,
uint16_t *resolution,
uint8_t *flags);
/* -------------------------------------------------------------------------- */
/* 0x2201: Adjustable DPI */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_ADJUSTABLE_DPI 0x2201
/**
* 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 hidpp20_device *device,
struct hidpp20_sensor **sensors_list);
/**
* set the current dpi of the provided sensor. sensor must have been
* allocated by hidpp20_adjustable_dpi_get_sensors()
*/
int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
struct hidpp20_sensor *sensor, uint16_t dpi);
/* -------------------------------------------------------------------------- */
/* 0x8060 - Adjustable Report Rate */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_ADJUSTABLE_REPORT_RATE 0x8060
/**
* set the bitmap_ms to the supported report rates. Bits enabled reflect a
* supported report rate, where bit 0 equals 1ms, bit 1 2ms, bit 2 3ms, etc.
*/
int hidpp20_adjustable_report_rate_get_report_rate_list(struct hidpp20_device *device,
uint8_t *bitflags_ms);
int hidpp20_adjustable_report_rate_get_report_rate(struct hidpp20_device *device,
uint8_t *rate_ms);
int hidpp20_adjustable_report_rate_set_report_rate(struct hidpp20_device *device,
uint8_t rate_ms);
/* -------------------------------------------------------------------------- */
/* 0x8070v4 - Color LED effects */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_COLOR_LED_EFFECTS 0x8070
enum hidpp20_color_led_info_ext_caps {
HIDPP20_COLOR_LED_INFO_EXT_CAP_HAS_ZONE_EFFECT = 0x01,
HIDPP20_COLOR_LED_INFO_EXT_CAP_NO_GET_EFFECT_SETTINGS = 0x02,
HIDPP20_COLOR_LED_INFO_EXT_CAP_HAS_SET_LED_BIN_INFO = 0x04,
HIDPP20_COLOR_LED_INFO_EXT_CAP_MONOCHROME_ONLY = 0x08,
};
struct hidpp20_color_led_info;
int
hidpp20_color_led_effects_get_info(struct hidpp20_device *device,
struct hidpp20_color_led_info *info);
struct hidpp20_color_led_zone_info;
int
hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device,
uint8_t reg, struct hidpp20_color_led_zone_info *info);
int
hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device,
struct hidpp20_color_led_zone_info **infos_list);
struct hidpp20_color_led_zone_effect_info;
int
hidpp20_color_led_effect_get_zone_effect_info(struct hidpp20_device *device,
uint8_t zone_index,
uint8_t zone_effect_index,
struct hidpp20_color_led_zone_effect_info *info);
struct hidpp20_rgb_device_info;
int
hidpp20_rgb_effects_get_device_info(struct hidpp20_device *device,
struct hidpp20_rgb_device_info *info);
struct hidpp20_rgb_cluster_info;
int
hidpp20_rgb_effects_get_cluster_info(struct hidpp20_device *device,
uint8_t cluster_index,
struct hidpp20_rgb_cluster_info *info);
int
hidpp20_rgb_effects_get_cluster_infos(struct hidpp20_device *device,
struct hidpp20_rgb_cluster_info **infos_list);
struct hidpp20_rgb_effect_info;
int
hidpp20_rgb_effects_get_effect_info(struct hidpp20_device *device,
uint8_t cluster_index,
uint8_t effect_index,
struct hidpp20_rgb_effect_info *info);
struct hidpp20_led;
int
hidpp20_color_led_effects_set_zone_effect(struct hidpp20_device *device,
uint8_t zone_index,
struct hidpp20_led led);
int
hidpp20_color_led_effects_get_zone_effect(struct hidpp20_device *device,
uint8_t zone_index,
struct hidpp20_led *led);
enum hidpp20_color_led_location {
HIDPP20_COLOR_LED_LOCATION_UNDEFINED = 0,
HIDPP20_COLOR_LED_LOCATION_PRIMARY,
HIDPP20_COLOR_LED_LOCATION_LOGO,
HIDPP20_COLOR_LED_LOCATION_LEFT,
HIDPP20_COLOR_LED_LOCATION_RIGHT,
HIDPP20_COLOR_LED_LOCATION_COMBINED,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_1,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_2,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_3,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_4,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_5,
HIDPP20_COLOR_LED_LOCATION_PRIMARY_6,
};
enum hidpp20_color_led_persistency {
HIDPP20_COLOR_LED_PERSISTENCY_UNSUPPORTED,
HIDPP20_COLOR_LED_PERSISTENCY_ON,
HIDPP20_COLOR_LED_PERSISTENCY_OFF,
HIDPP20_COLOR_LED_PERSISTENCY_ON_OFF,
};
enum hidpp20_color_led_zone_effect {
HIDPP20_COLOR_LED_ZONE_EFFECT_DISABLED = 0,
HIDPP20_COLOR_LED_ZONE_EFFECT_FIXED = 1,
HIDPP20_COLOR_LED_ZONE_EFFECT_CYCLING = 3,
HIDPP20_COLOR_LED_ZONE_EFFECT_WAVE = 4,
HIDPP20_COLOR_LED_ZONE_EFFECT_STARLIGHT = 5,
HIDPP20_COLOR_LED_ZONE_EFFECT_LIGHT_ON_PRESS = 6,
HIDPP20_COLOR_LED_ZONE_EFFECT_AUDIO_VISUALIZER = 7,
HIDPP20_COLOR_LED_ZONE_EFFECT_BOOT_UP = 8,
HIDPP20_COLOR_LED_ZONE_EFFECT_DEMO_MODE = 8,
HIDPP20_COLOR_LED_ZONE_EFFECT_BREATHING = 10,
HIDPP20_COLOR_LED_ZONE_EFFECT_RIPPLE = 11,
HIDPP20_COLOR_LED_ZONE_EFFECT_CUSTOM = 12,
};
/* -------------------------------------------------------------------------- */
/* 0x8071 - RGB Effects */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_RGB_EFFECTS 0x8071
#define HIDPP20_RGB_EFFECTS_INDEX_ALL 0xFF
/* type of info */
#define HIDPP20_RGB_EFFECTS_TOI_GENERAL 0x00
#define HIDPP20_RGB_EFFECTS_TOI_EFFECT 0x01
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_STATE 0x00
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_DEFAULTS 0x01
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_UUID_0_10 0x02
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_UUID_11_16 0x03
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_0_10 0x04
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_11_21 0x05
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_21_31 0x06
/* -------------------------------------------------------------------------- */
/* 0x8100 - Onboard Profiles */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_ONBOARD_PROFILES 0x8100
/* type */
#define HIDPP20_BUTTON_HID_TYPE 0x80
#define HIDPP20_BUTTON_SPECIAL 0x90
/* standard opcodes (0x80) */
#define HIDPP20_BUTTON_HID_TYPE_NOOP 0x00
#define HIDPP20_BUTTON_HID_TYPE_MOUSE 0x01
#define HIDPP20_BUTTON_HID_TYPE_KEYBOARD 0x02
#define HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL 0x03
/* special opcodes (0x90) */
#define HIDPP20_BUTTON_SPECIAL_NOOP 0x00
#define HIDPP20_BUTTON_SPECIAL_TILT_LEFT 0x01
#define HIDPP20_BUTTON_SPECIAL_TILT_RIGHT 0x02
#define HIDPP20_BUTTON_SPECIAL_NEXT_DPI 0x03
#define HIDPP20_BUTTON_SPECIAL_PREV_DPI 0x04
#define HIDPP20_BUTTON_SPECIAL_CYCLE_DPI 0x05
#define HIDPP20_BUTTON_SPECIAL_DEFAULT_DPI 0x06
#define HIDPP20_BUTTON_SPECIAL_SHIFT_DPI 0x07
#define HIDPP20_BUTTON_SPECIAL_NEXT_PROFILE 0x08
#define HIDPP20_BUTTON_SPECIAL_PREV_PROFILE 0x09
#define HIDPP20_BUTTON_SPECIAL_CYCLE_PROFILE 0x0a
#define HIDPP20_BUTTON_SPECIAL_GSHIFT 0x0b
/* memory model >= 3 */
#define HIDPP20_BUTTON_SPECIAL_BATTERY_INDICATOR 0x0c
#define HIDPP20_BUTTON_SPECIAL_ENABLE_PROFILE 0x0d
#define HIDPP20_BUTTON_SPECIAL_PERFORMANCE_SWITCH 0x0e
#define HIDPP20_BUTTON_SPECIAL_HOST 0x0f
#define HIDPP20_BUTTON_SPECIAL_SCROLL_DOWN 0x10
#define HIDPP20_BUTTON_SPECIAL_SCROLL_UP 0x11
/* buttons */
#define HIDPP20_BUTTON_MACRO 0x00
#define HIDPP20_BUTTON_DISABLED 0xFF
/* modifiers */
#define HIDPP20_MODIFIER_KEY_CTRL 0x01
#define HIDPP20_MODIFIER_KEY_SHIFT 0x02
#define HIDPP20_DPI_COUNT 5
#define HIDPP20_LED_COUNT 2
union hidpp20_button_binding {
struct {
uint8_t type;
} any;
struct {
uint8_t type;
uint8_t subtype;
} subany;
struct {
uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */
uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_MOUSE */
uint16_t buttons; /* flags when internal */
} __attribute__((packed)) button;
struct {
uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */
uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_KEYBOARD */
uint8_t modifier_flags;
uint8_t key;
} __attribute__((packed)) keyboard_keys;
struct {
uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */
uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL */
uint16_t consumer_control;
} __attribute__((packed)) consumer_control;
struct {
uint8_t type; /* HIDPP20_BUTTON_SPECIAL */
uint8_t special;
uint8_t reserved;
uint8_t profile;
} __attribute__((packed)) special;
struct {
uint8_t type; /* HIDPP20_BUTTON_MACRO */
uint8_t page;
uint8_t zero;
uint8_t offset;
} __attribute__((packed)) macro;
struct {
uint8_t type; /* PROFILE_BUTTON_TYPE_DISABLED */
} disabled;
} __attribute__((packed));
_Static_assert(sizeof(union hidpp20_button_binding) == 4, "Invalid size");
struct hidpp20_color_led_info {
uint8_t zone_count;
/* we don't care about NV capabilities for libratbag, they just
* indicate sale demo effects */
uint16_t nv_caps;
uint16_t ext_caps;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_color_led_info) == 5, "Invalid size");
struct hidpp20_non_color_led_zone_info {
uint8_t index;
uint8_t type;
uint16_t capabilities;
uint8_t nv_config;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_non_color_led_zone_info) == 5, "Invalid size");
struct hidpp20_color_led_zone_info {
uint8_t index;
uint16_t location;
uint8_t num_effects;
uint8_t persistency_caps;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_color_led_zone_info) == 5, "Invalid size");
struct hidpp20_color_led_zone_effect_info {
uint8_t zone_index;
uint8_t zone_effect_index;
uint16_t effect_id;
uint16_t effect_caps;
uint16_t effect_period;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_color_led_zone_effect_info) == 8, "Invalid size");
struct hidpp20_rgb_device_info {
uint8_t cluster_index;
uint8_t effect_index;
uint8_t cluster_count;
/* we don't care about NV capabilities for libratbag, they just
* indicate sale demo effects */
uint16_t nv_caps;
uint16_t ext_caps;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_rgb_device_info) == 7, "Invalid size");
struct hidpp20_rgb_cluster_info {
uint8_t index;
uint8_t effect_index;
uint16_t location;
uint16_t num_effects;
uint16_t persistency_caps;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_rgb_cluster_info) == 8, "Invalid size");
struct hidpp20_rgb_effect_info {
uint8_t cluster_index;
uint8_t effect_index;
uint16_t effect_id;
uint16_t capabilities;
uint16_t effect_period;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_rgb_effect_info) == 8, "Invalid size");
union hidpp20_generic_led_zone_info {
struct hidpp20_led_sw_ctrl_led_info* leds;
struct hidpp20_color_led_zone_info* color_leds_8070;
struct hidpp20_rgb_cluster_info* color_leds_8071;
};
struct hidpp20_color {
uint8_t red;
uint8_t green;
uint8_t blue;
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_color) == 3, "Invalid size");
enum hidpp20_led_type {
HIDPP20_LED_UNKNOWN = -1,
HIDPP20_LED_LOGO = 0,
HIDPP20_LED_SIDE,
};
enum hidpp20_led_mode {
HIDPP20_LED_OFF = 0x00,
HIDPP20_LED_ON = 0x01,
HIDPP20_LED_CYCLE = 0x03,
HIDPP20_LED_COLOR_WAVE = 0x04,
HIDPP20_LED_STARLIGHT = 0x05,
HIDPP20_LED_BREATHING = 0x0a,
HIDPP20_LED_RIPPLE = 0x0b,
HIDPP20_LED_CUSTOM = 0x0c,
};
enum hidpp20_led_waveform {
HIDPP20_LED_WF_DEFAULT = 0x00,
HIDPP20_LED_WF_SINE = 0x01,
HIDPP20_LED_WF_SQUARE = 0x02,
HIDPP20_LED_WF_TRIANGLE = 0x03,
HIDPP20_LED_WF_SAWTOOTH = 0x04,
HIDPP20_LED_WF_SHARKFIN = 0x05,
HIDPP20_LED_WF_EXPONENTIAL = 0x06,
};
struct hidpp20_internal_led {
uint8_t mode; /* enum hidpp20_led_mode */
union {
struct hidpp20_led_fixed {
struct hidpp20_color color;
uint8_t effect;
} __attribute__((packed)) fixed;
struct hidpp20_led_cycle {
uint8_t unused[5];
uint16_t period_or_speed; /* period in ms, speed is device dependent */
uint8_t intensity; /* 1 - 100 percent, 0 means 100 */
} __attribute__((packed)) cycle;
struct hidpp20_led_starlight {
struct hidpp20_color color_sky;
struct hidpp20_color color_star;
} __attribute__((packed)) starlight;
struct hidpp20_led_breath {
struct hidpp20_color color;
uint16_t period_or_speed; /* period in ms, speed is device dependent */
uint8_t waveform; /* enum hidpp20_led_waveform */
uint8_t intensity; /* 1 - 100 percent, 0 means 100 */
} __attribute__((packed)) breath;
struct hidpp20_led_ripple {
struct hidpp20_color color;
uint8_t reserved;
uint16_t period;
} __attribute__((packed)) ripple;
struct hidpp20_led_custom {
uint8_t slot;
uint16_t init_frame;
uint16_t lenght;
uint16_t frame_period;
uint8_t intensity;
} __attribute__((packed)) custom;
uint8_t padding[10];
} __attribute__((packed)) effect;
};
_Static_assert(sizeof(struct hidpp20_led_fixed) == 4, "Invalid size");
_Static_assert(sizeof(struct hidpp20_led_cycle) == 8, "Invalid size");
_Static_assert(sizeof(struct hidpp20_led_starlight) == 6, "Invalid size");
_Static_assert(sizeof(struct hidpp20_led_breath) == 7, "Invalid size");
_Static_assert(sizeof(struct hidpp20_internal_led) == 11, "Invalid size");
_Static_assert(sizeof(struct hidpp20_led_ripple) == 6, "Invalid size");
_Static_assert(sizeof(struct hidpp20_led_custom) == 8, "Invalid size");
typedef uint8_t percent_t;
struct hidpp20_led {
enum hidpp20_led_mode mode;
struct hidpp20_color color;
struct hidpp20_color extra_color;
uint16_t period;
percent_t brightness;
uint8_t original[sizeof(struct hidpp20_internal_led)];
};
/* macro opcodes */
/* control commands */
#define HIDPP20_MACRO_WAIT_FOR_RELEASE 0x01
#define HIDPP20_MACRO_REPEAT_WHILE_PRESSED 0x02
#define HIDPP20_MACRO_REPEAT_UNTIL_CANCELED 0x03
#define HIDPP20_MACRO_END 0xff
/* delay & jump commands */
#define HIDPP20_MACRO_NOOP 0x00 /* wait the duration of a macro step */
#define HIDPP20_MACRO_DELAY 0x40
#define HIDPP20_MACRO_JUMP 0x60
/* button & key event generation */
#define HIDPP20_MACRO_BUTTON_DOWN 0x41
#define HIDPP20_MACRO_BUTTON_UP 0x42
#define HIDPP20_MACRO_KEY_PRESS 0x43
#define HIDPP20_MACRO_KEY_RELEASE 0x44
#define HIDPP20_MACRO_CONS_DOWN 0x45
#define HIDPP20_MACRO_CONS_UP 0x46
/* analog commands */
#define HIDPP20_MACRO_ROLLER 0x20
#define HIDPP20_MACRO_ACPAN 0x21
#define HIDPP20_MACRO_XY 0x61
union hidpp20_macro_data {
struct {
uint8_t type;
} __attribute__((packed)) any;
struct {
uint8_t type; /* HIDPP20_MACRO_DELAY */
uint16_t time;
} __attribute__((packed)) delay;
struct {
uint8_t type; /* HIDPP20_MACRO_KEY_PRESS or HIDPP20_MACRO_KEY_RELEASE */
uint8_t modifier;
uint8_t key;
} __attribute__((packed)) key;
struct {
uint8_t type; /* HIDPP20_MACRO_JUMP */
uint8_t offset;
uint8_t page;
} __attribute__((packed)) jump;
struct {
uint8_t type; /* HIDPP20_MACRO_END */
} __attribute__((packed)) end;
} __attribute__((packed));
_Static_assert(sizeof(union hidpp20_macro_data) == 3, "Invalid size");
struct hidpp20_profile {
uint16_t address;
uint8_t enabled;
char name[16 * 3];
uint16_t powersave_timeout;
uint16_t poweroff_timeout;
unsigned report_rate;
unsigned default_dpi;
unsigned switched_dpi;
unsigned current_dpi;
uint16_t dpi[HIDPP20_DPI_COUNT];
union hidpp20_button_binding buttons[32];
union hidpp20_macro_data *macros[32];
struct hidpp20_led leds[HIDPP20_LED_COUNT];
struct hidpp20_led alt_leds[HIDPP20_LED_COUNT];
};
struct hidpp20_onboard_profiles_info {
uint8_t memory_model_id;
uint8_t profile_format_id;
uint8_t macro_format_id;
uint8_t profile_count;
uint8_t profile_count_oob;
uint8_t button_count;
uint8_t sector_count;
uint16_t sector_size;
uint8_t mechanical_layout;
uint8_t various_info;
uint8_t reserved[5];
} __attribute__((packed));
_Static_assert(sizeof(struct hidpp20_onboard_profiles_info) == 16, "Invalid size");
struct hidpp20_profiles {
uint8_t num_profiles;
uint8_t num_rom_profiles;
uint8_t num_buttons;
uint8_t num_modes;
uint8_t num_leds;
uint8_t has_g_shift;
uint8_t has_dpi_shift;
uint8_t corded;
uint8_t wireless;
uint8_t sector_count;
uint16_t sector_size;
uint8_t active_profile_index;
struct hidpp20_profile *profiles;
};
/**
* fetches the profiles description as reported by the mouse.
*
* returns 0 or a negative error.
*/
int
hidpp20_onboard_profiles_get_profiles_desc(struct hidpp20_device *device,
struct hidpp20_onboard_profiles_info *info);
/**
* allocates a list of profiles that has to be destroyed by the caller.
* The caller must use hidpp20_onboard_profiles_destroy() to free the memory.
*
* returns the number of profiles in the list or a negative error
*/
int hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
struct hidpp20_profiles **profiles_list);
/**
* free a list of profiles allocated by hidpp20_onboard_profiles_allocate()
*/
void
hidpp20_onboard_profiles_destroy(struct hidpp20_profiles *profiles_list);
/**
* initialize a struct hidpp20_profiles previous allocated with
* hidpp20_onboard_profiles_allocate().
*/
int
hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
struct hidpp20_profiles *profiles);
/**
* return the current profile index or a negative error.
*/
int hidpp20_onboard_profiles_get_current_profile(struct hidpp20_device *device);
/**
* Sets the current profile index.
* Indexes are 1-indexed.
*
* return 0 or a negative error.
*/
int
hidpp20_onboard_profiles_set_current_profile(struct hidpp20_device *device,
uint8_t index);
/**
* return the current dpi index of the current active profile
* or a negative error.
*/
int hidpp20_onboard_profiles_get_current_dpi_index(struct hidpp20_device *device);
/**
* Sets the current dpi index on the current active profile.
* Indexes are 0-indexed.
*
* return 0 or a negative error.
*/
int
hidpp20_onboard_profiles_set_current_dpi_index(struct hidpp20_device *device,
uint8_t index);
/**
* Write the internal state of the device onto the FLASH.
*/
int
hidpp20_onboard_profiles_commit(struct hidpp20_device *device,
struct hidpp20_profiles *profiles_list);
enum ratbag_button_action_special
hidpp20_onboard_profiles_get_special(uint8_t code);
uint8_t
hidpp20_onboard_profiles_get_code_from_special(enum ratbag_button_action_special special);
int
hidpp20_onboard_profiles_read_sector(struct hidpp20_device *device,
uint16_t sector,
uint16_t sector_size,
uint8_t *data);
int
hidpp20_onboard_profiles_write_sector(struct hidpp20_device *device,
uint16_t sector,
uint16_t sector_size,
uint8_t *data,
bool write_crc);
static inline uint8_t *
hidpp20_onboard_profiles_allocate_sector(struct hidpp20_profiles *profiles)
{
return zalloc(profiles->sector_size);
}
void
hidpp20_onboard_profiles_read_led(struct hidpp20_led *led,
struct hidpp20_internal_led internal_led);
void
hidpp20_onboard_profiles_write_led(struct hidpp20_internal_led *internal_led,
struct hidpp20_led *led);
/* -------------------------------------------------------------------------- */
/* 0x8110 - Mouse Button Spy */
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_MOUSE_BUTTON_SPY 0x8110