/* * HID++ 1.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++ 1.0 documentation provided by Nestor Lopez Casado at: * https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing */ #pragma once #include #include #include "hidpp-generic.h" struct dpi_list; struct dpi_range; /* FIXME: that's what my G500s supports, but only pages 3-5 are valid. * 0 is zeroed, 1 and 2 are garbage, all above 6 is garbage */ #define HIDPP10_NUM_PROFILES 5 #define HIDPP10_MAX_PAGE_NUMBER 31 enum hidpp10_profile_type { HIDPP10_PROFILE_UNKNOWN = -1, HIDPP10_PROFILE_G500, HIDPP10_PROFILE_G700, HIDPP10_PROFILE_G9, }; struct hidpp10_directory; struct hidpp10_profile; struct hidpp10_dpi_mapping { uint8_t raw_value; unsigned dpi; }; struct hidpp10_device { struct hidpp_device base; unsigned index; bool dpi_table_is_range; uint8_t dpi_count; struct hidpp10_dpi_mapping *dpi_table; enum hidpp10_profile_type profile_type; struct hidpp10_profile *profiles; unsigned int profile_count; }; int hidpp10_device_new(const struct hidpp_device *base, int idx, enum hidpp10_profile_type type, unsigned int profile_count, struct hidpp10_device **out); int hidpp10_device_read_profiles(struct hidpp10_device *dev); void hidpp10_device_destroy(struct hidpp10_device *dev); /** * Builds the table of dpi for the device from the given string. * * @param dev a struct hidpp10_device previously allocated * @param str_list a string representing the dpi table * * The given string contains only positive integer values, separated by * semicolons (';'). The n-th element in the list corresponds to the * raw value (0x80 + n - 1) */ int hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev, const struct dpi_list *list); /** * Builds the table of dpi for the device from the given dpi description. * * @param dev a struct hidpp10_device previously allocated * @param str_dpi a string representing the dpi parameters * * The given string contains 3 float values, separated by colons (':'). * The format is MIN:MAX@STEP * MIN corresponds to the raw_value '0' * MAX corresponds to the raw_value floor((MAX - MIN) / STEP) */ int hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev, const struct dpi_range *range); /** * Returns the lowest dpi stored in the dpi mapping table generated by * hidpp10_build_dpi_table_from_list() or * hidpp10_build_dpi_table_from_dpi_info() */ unsigned int hidpp10_dpi_table_get_min_dpi(struct hidpp10_device *dev); /** * Returns the highest dpi stored in the dpi mapping table generated by * hidpp10_build_dpi_table_from_list() or * hidpp10_build_dpi_table_from_dpi_info() */ unsigned int hidpp10_dpi_table_get_max_dpi(struct hidpp10_device *dev); /* -------------------------------------------------------------------------- */ /* 0x00: Enable HID++ Notifications */ /* -------------------------------------------------------------------------- */ /** * All notifications are disabled by default on powerup. */ enum hidpp10_hidpp_notifications { /** * enabled: Multimedia and MS vendor specific keys are reported as * HID++ notification 0x03 * disabled: reported as normal HID reports */ HIDPP10_NOTIFICATIONS_CONSUMER_VENDOR_SPECIFIC_CONTROL = (1 << 0), /** * enabled: power keys are reported as HID++ notification 0x04 * disabled: reported as normal HID reports */ HIDPP10_NOTIFICATIONS_POWER_KEYS = (1 << 1), /** * enabled: Vertical scroll wheel/iNav are reported as HID++ * notification 0x05 * disabled: reported as normal HID reports */ HIDPP10_NOTIFICATIONS_ROLLER_V = (1 << 2), /** * enabled: buttons not available in standard HID are reported as * HID++ notification 0x06 * disabled: buttons not available in standard HID are not reported */ HIDPP10_NOTIFICATIONS_MOUSE_EXTRA_BUTTONS = (1 << 3), /** * enabled: battery status/milage are reported as HID++ notification * 0x07 or 0x0D (device-dependent) * disabled: battery status/milage are not reported */ HIDPP10_NOTIFICATIONS_BATTERY_STATUS = (1 << 4), /** * enabled: Horizontal scroll wheel/iNav are reported as HID++ * notification 0x05 * disabled: reported as normal HID reports */ HIDPP10_NOTIFICATIONS_ROLLER_H = (1 << 5), /** * enabled: F-Lock status is reported as HID++ notification 0x09 * disabled: F-Lock status is not reported */ HIDPP10_NOTIFICATIONS_F_LOCK_STATUS = (1 << 6), /** * enabled: Numpad keys are reported as buttons in HID++ * notification 0x03 * disabled: reported as normal keys */ HIDPP10_NOTIFICATIONS_NUMPAD_NUMERIC_KEYS = (1 << 7), /** * enabled: Device arrival/removal/... are reported as HID++ * notifications 0x40, 0x41, 0x46 or 0x78 * disabled: these events are not reported */ HIDPP10_NOTIFICATIONS_WIRELESS_NOTIFICATIONS = (1 << 8), /** * enabled: User interface events are reported as HID++ notification * 0x08 * disabled: these events are not reported */ HIDPP10_NOTIFICATIONS_UI_NOTIFICATIONS = (1 << 9), /** * enabled: Quad link quality info events are reported as HID++ notification * 0x49 * disabled: these events are not reported */ HIDPP10_NOTIFICATIONS_QUAD_LINK_QUALITY_INFO = (1 << 10), HIDPP10_NOTIFICATIONS_SOFTWARE_PRESENT = (1 << 11), HIDPP10_NOTIFICATIONS_TOUCHPAD_MULTITOUCH_NOTIFICATIONS = (1 << 12), /* 1 << 13 is reserved */ /* 1 << 14 is reserved */ /* 1 << 15 is reserved */ /** * enabled: 3D gestures are reported as HID++ notification 0x65 * disabled: these events are not reported */ HIDPP10_NOTIFICATIONS_3D_GESTURE = (1 << 16), HIDPP10_NOTIFICATIONS_VOIP_TELEPHONY = (1 << 17), HIDPP10_NOTIFICATIONS_CONFIGURATION_COMPLETE = (1 << 18), /* 1 << 19 is reserved */ /* 1 << 20 is reserved */ /* 1 << 21 is reserved */ /* 1 << 22 is reserved */ /* 1 << 23 is reserved */ }; int hidpp10_get_hidpp_notifications(struct hidpp10_device *dev, uint32_t *reporting_flags); int hidpp10_set_hidpp_notifications(struct hidpp10_device *dev, uint32_t reporting_flags); /* -------------------------------------------------------------------------- */ /* 0x01: Enable Individual Features */ /* -------------------------------------------------------------------------- */ enum hidpp10_individual_features { HIDPP10_FEATURE_BIT_MOUSE_SENSOR_RESOLUTION = (1 << 0), /** * disabled: buttons send button codes * enabled: buttons have special functions (default) * @note Do not use, use 0x63 instead */ HIDPP10_FEATURE_BIT_SPECIAL_BUTTON_FUNCTION = (1 << 1), /** * disabled: normal key usage (default) * enabled: enhanced key usage */ HIDPP10_FEATURE_BIT_ENHANCED_KEY_USAGE = (1 << 2), /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_FAST_FORWARD_REWIND = (1 << 3), /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_SEND_CALCULATOR_RESULT = (1 << 4), /** * disabled: * enabled: (default) */ HIDPP10_FEATURE_BIT_MOTION_WAKEUP = (1 << 5), /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_FAST_SCROLLING = (1 << 6), /** * disabled: work as buttons * enabled: control the resolution (default) */ HIDPP10_FEATURE_BIT_BUTTONS_CONTROL_RESOLUTION = (1 << 7), /* 1 << 8 is reserved */ /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_RECEIVER_MULTIPLE_RF_LOCK = (1 << 9), /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_RECEIVER_DISABLE_RFSCAN_IN_SUSPEND = (1 << 10), /** * disabled: (default) * enabled: * * When enabled,removes all compatibility checks. */ HIDPP10_FEATURE_BIT_RECEIVER_ACCEPT_ALL_DEVICES_IN_PAIRING = (1 << 11), /* 1 << 12 is reserved */ /* 1 << 13 is reserved */ /* 1 << 14 is reserved */ /* 1 << 15 is reserved */ /** * disabled: (default) * enabled: no sound */ HIDPP10_FEATURE_BIT_INHIBIT_LOCK_KEY_SOUND = (1 << 16), /** * disabled: (default) * enabled: */ HIDPP10_FEATURE_BIT_INHIBIT_TOUCHPAD = (1 << 17), /** * disabled: * enabled: (default) */ HIDPP10_FEATURE_BIT_3D_ENGINE = (1 << 18), /** * disabled: (disabled) * enabled: */ HIDPP10_FEATURE_BIT_SW_CONTROLS_LEDS = (1 << 19), /** * disabled: (disabled) * enabled: */ HIDPP10_FEATURE_BIT_NO_NUMLOCK_TOGGLE = (1 << 20), /** * disabled: (disabled) * enabled: */ HIDPP10_FEATURE_BIT_INHIBIT_PRESENCE_DETECTION = (1 << 21), }; int hidpp10_get_individual_features(struct hidpp10_device *dev, uint32_t *feature_mask); int hidpp10_set_individual_features(struct hidpp10_device *dev, uint32_t feature_mask); /* -------------------------------------------------------------------------- */ /* 0x07: Battery Status */ /* -------------------------------------------------------------------------- */ enum hidpp10_battery_level { HIDPP10_BATTERY_LEVEL_UNKNOWN = 0x00, HIDPP10_BATTERY_LEVEL_CRITICAL = 0x01, HIDPP10_BATTERY_LEVEL_CRITICAL_LEGACY = 0x02, HIDPP10_BATTERY_LEVEL_LOW = 0x03, HIDPP10_BATTERY_LEVEL_LOW_LEGACY = 0x04, HIDPP10_BATTERY_LEVEL_GOOD = 0x05, HIDPP10_BATTERY_LEVEL_GOOD_LEGACY = 0x06, HIDPP10_BATTERY_LEVEL_FULL_LEGACY = 0x07, /* 0x08..0xFF ... reserved */ }; enum hidpp10_battery_charge_state { HIDPP10_BATTERY_CHARGE_STATE_NOT_CHARGING = 0x00, /* 0x01 ... 0x1F ... reserved (not charging) */ HIDPP10_BATTERY_CHARGE_STATE_UNKNOWN = 0x20, HIDPP10_BATTERY_CHARGE_STATE_CHARGING = 0x21, HIDPP10_BATTERY_CHARGE_STATE_CHARGING_COMPLETE = 0x22, HIDPP10_BATTERY_CHARGE_STATE_CHARGING_ERROR = 0x23, HIDPP10_BATTERY_CHARGE_STATE_CHARGING_FAST = 0x24, HIDPP10_BATTERY_CHARGE_STATE_CHARGING_SLOW = 0x25, HIDPP10_BATTERY_CHARGE_STATE_TOPPING_CHARGE = 0x26, /* 0x27 .. 0xff ... reserved */ }; int hidpp10_get_battery_status(struct hidpp10_device *dev, enum hidpp10_battery_level *level, enum hidpp10_battery_charge_state *charge_state, uint8_t *low_threshold_in_percent); /* -------------------------------------------------------------------------- */ /* 0x0D: Battery Mileage */ /* -------------------------------------------------------------------------- */ int hidpp10_get_battery_mileage(struct hidpp10_device *dev, uint8_t *level_in_percent, uint32_t *max_seconds, enum hidpp10_battery_charge_state *state); /* -------------------------------------------------------------------------- */ /* 0x0F: Profile queries */ /* -------------------------------------------------------------------------- */ #define PROFILE_NUM_BUTTONS 13 #define PROFILE_NUM_BUTTONS_G9 10 #define PROFILE_NUM_DPI_MODES 5 #define PROFILE_BUTTON_TYPE_BUTTON 0x81 #define PROFILE_BUTTON_TYPE_KEYS 0x82 #define PROFILE_BUTTON_TYPE_SPECIAL 0x83 #define PROFILE_BUTTON_TYPE_CONSUMER_CONTROL 0x84 #define PROFILE_BUTTON_TYPE_DISABLED 0x8F #define PROFILE_BUTTON_SPECIAL_PAN_LEFT 0x1 #define PROFILE_BUTTON_SPECIAL_PAN_RIGHT 0x2 #define PROFILE_BUTTON_SPECIAL_DPI_NEXT 0x4 #define PROFILE_BUTTON_SPECIAL_DPI_PREV 0x8 #define HIDPP10_MACRO_NOOP 0x00 #define HIDPP10_MACRO_WAIT_FOR_BUTTON_RELEASE 0x01 #define HIDPP10_MACRO_REPEAT_UNTIL_BUTTON_RELEASE 0x02 #define HIDPP10_MACRO_REPEAT 0x03 #define HIDPP10_MACRO_KEY_PRESS 0x20 #define HIDPP10_MACRO_KEY_RELEASE 0x21 #define HIDPP10_MACRO_MOD_PRESS 0x22 #define HIDPP10_MACRO_MOD_RELEASE 0x23 #define HIDPP10_MACRO_MOUSE_WHEEL 0x24 #define HIDPP10_MACRO_MOUSE_BUTTON_PRESS 0x40 #define HIDPP10_MACRO_MOUSE_BUTTON_RELEASE 0x41 #define HIDPP10_MACRO_KEY_CONSUMER_CONTROL 0x42 #define HIDPP10_MACRO_DELAY 0x43 #define HIDPP10_MACRO_JUMP 0x44 #define HIDPP10_MACRO_JUMP_IF_PRESSED 0x45 #define HIDPP10_MACRO_MOUSE_POINTER_MOVE 0x60 #define HIDPP10_MACRO_JUMP_IF_RELEASED_TIMEOUT 0x61 #define HIDPP10_MACRO_END 0xff union hidpp10_macro_data { struct { uint8_t type; } __attribute__((packed)) any; struct { uint8_t type; /* HIDPP10_MACRO_KEY_PRESS or HIDPP10_MACRO_KEY_RELEASE */ uint8_t key; } __attribute__((packed)) key; struct { uint8_t type; /* HIDPP10_MACRO_MOD_PRESS or HIDPP10_MACRO_MOD_RELEASE */ uint8_t key; } __attribute__((packed)) modifier; struct { uint8_t type; /* HIDPP10_MACRO_MOUSE_WHEEL */ int8_t value; } __attribute__((packed)) wheel; struct { uint8_t type; /* HIDPP10_MACRO_MOUSE_BUTTON_PRESS or HIDPP10_MACRO_MOUSE_BUTTON_RELEASE */ uint16_t flags; } __attribute__((packed)) button; struct { uint8_t type; /* HIDPP10_MACRO_KEY_CONSUMER_CONTROL */ uint16_t key; } __attribute__((packed)) consumer_control; struct { uint8_t type; /* HIDPP10_MACRO_DELAY */ uint16_t time; } __attribute__((packed)) delay; struct { uint8_t type; /* HIDPP10_MACRO_JUMP or HIDPP10_MACRO_JUMP_IF_PRESSED */ uint8_t page; uint8_t offset; } __attribute__((packed)) jump; struct { uint8_t type; /* HIDPP10_MACRO_MOUSE_POINTER_MOVE */ int16_t x_rel; uint16_t y_rel; } __attribute__((packed)) pointer; struct { uint8_t type; /* HIDPP10_MACRO_JUMP_IF_RELEASED_TIMEOUT */ int16_t timeout; uint8_t page; uint8_t offset; } __attribute__((packed)) jump_timeout; struct { uint8_t type; /* HIDPP10_MACRO_END */ } __attribute__((packed)) end; } __attribute__((packed)); _Static_assert(sizeof(union hidpp10_macro_data) == 5, "Invalid size"); struct hidpp10_profile { uint8_t page; uint8_t offset; struct { uint16_t xres; uint16_t yres; bool led[4]; } dpi_modes[5]; size_t num_dpi_modes; unsigned char name[24]; /* the G700 has 23 chars, add one for terminating 0 */ unsigned char macro_names[11][18]; /* adding one extra terminating 0 per name */ uint8_t red; uint8_t green; uint8_t blue; bool angle_correction; uint8_t default_dpi_mode; uint16_t refresh_rate; union hidpp10_button { struct { uint8_t type; } any; struct { uint8_t type; uint16_t button; } button; struct { uint8_t type; uint8_t modifier_flags; uint8_t key; } keys; struct { uint8_t type; uint16_t special; } special; struct { uint8_t type; uint16_t consumer_control; } consumer_control; struct { uint8_t type; } disabled; struct { uint8_t page; uint8_t offset; uint8_t address; } macro; } buttons[PROFILE_NUM_BUTTONS]; union hidpp10_macro_data *macros[PROFILE_NUM_BUTTONS]; size_t num_buttons; size_t num_leds; unsigned int initialized; bool enabled; }; struct hidpp10_directory { uint8_t page; uint8_t offset; uint8_t led_mask; } __attribute__((packed)); int hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile); int hidpp10_set_current_profile(struct hidpp10_device *dev, uint16_t current_profile); int hidpp10_get_profile(struct hidpp10_device *dev, uint8_t number, struct hidpp10_profile *profile); int hidpp10_set_profile(struct hidpp10_device *dev, uint8_t number, struct hidpp10_profile *profile); enum ratbag_button_action_special hidpp10_onboard_profiles_get_special(uint8_t code); uint8_t hidpp10_onboard_profiles_get_code_from_special(enum ratbag_button_action_special special); /* -------------------------------------------------------------------------- */ /* 0x51: LED Status */ /* -------------------------------------------------------------------------- */ enum hidpp10_led_status { HIDPP10_LED_STATUS_NO_CHANGE = 0x0, /**< LED does not exist, or should not change */ HIDPP10_LED_STATUS_OFF = 0x1, HIDPP10_LED_STATUS_ON = 0x2, HIDPP10_LED_STATUS_BLINK = 0x3, HIDPP10_LED_STATUS_HEARTBEAT = 0x4, HIDPP10_LED_STATUS_SLOW_ON = 0x5, HIDPP10_LED_STATUS_SLOW_OFF = 0x6, }; int hidpp10_get_led_status(struct hidpp10_device *dev, enum hidpp10_led_status led[6]); int hidpp10_set_led_status(struct hidpp10_device *dev, const enum hidpp10_led_status led[6]); /* -------------------------------------------------------------------------- */ /* 0x54: LED Intensity */ /* -------------------------------------------------------------------------- */ int hidpp10_get_led_intensity(struct hidpp10_device *dev, uint8_t led_intensity_in_percent[6]); /* Granularity for the led intensity is 10% increments. A value of 0 leaves * the intensity unchanged */ int hidpp10_set_led_intensity(struct hidpp10_device *dev, const uint8_t led_intensity_in_percent[6]); /* -------------------------------------------------------------------------- */ /* 0x57: LED Color */ /* -------------------------------------------------------------------------- */ /* Note: this changes the color of the LED only, use 0x51 to turn the LED * on/off */ int hidpp10_get_led_color(struct hidpp10_device *dev, uint8_t *red, uint8_t *green, uint8_t *blue); int hidpp10_set_led_color(struct hidpp10_device *dev, uint8_t red, uint8_t green, uint8_t blue); /* -------------------------------------------------------------------------- */ /* 0x61: Optical Sensor Settings */ /* -------------------------------------------------------------------------- */ int hidpp10_get_optical_sensor_settings(struct hidpp10_device *dev, uint8_t *surface_reflectivity); /* -------------------------------------------------------------------------- */ /* 0x63: Current Resolution */ /* -------------------------------------------------------------------------- */ int hidpp10_get_current_resolution(struct hidpp10_device *dev, uint16_t *xres, uint16_t *yres); int hidpp10_set_current_resolution(struct hidpp10_device *dev, uint16_t xres, uint16_t yres); /* -------------------------------------------------------------------------- */ /* 0x64: USB Refresh Rate */ /* -------------------------------------------------------------------------- */ int hidpp10_get_usb_refresh_rate(struct hidpp10_device *dev, uint16_t *rate); int hidpp10_set_usb_refresh_rate(struct hidpp10_device *dev, uint16_t rate); /* -------------------------------------------------------------------------- */ /* 0xA0: Generic Memory Management */ /* -------------------------------------------------------------------------- */ int hidpp10_erase_memory(struct hidpp10_device *dev, uint8_t page); int hidpp10_write_flash(struct hidpp10_device *dev, uint8_t src_page, uint16_t src_offset, uint8_t dst_page, uint16_t dst_offset, uint16_t size); /* -------------------------------------------------------------------------- */ /* 0x9x: HOT payload */ /* 0xA1: HOT Control Register */ /* -------------------------------------------------------------------------- */ int hidpp10_send_hot_payload(struct hidpp10_device *dev, uint8_t dst_page, uint16_t dst_offset, uint8_t *data, unsigned size); /* -------------------------------------------------------------------------- */ /* 0xA2: Read Sector */ /* -------------------------------------------------------------------------- */ #define HIDPP10_PAGE_SIZE (16 * 2 * 16) int hidpp10_read_memory(struct hidpp10_device *dev, uint8_t page, uint16_t offset, uint8_t bytes[16]); int hidpp10_read_page(struct hidpp10_device *dev, uint8_t page, uint8_t bytes[HIDPP10_PAGE_SIZE]); /* -------------------------------------------------------------------------- */ /* 0xB2: Device Connection and Disconnection (Pairing) */ /* -------------------------------------------------------------------------- */ /** * Open the receiver's lock to allow new devices be paired with this * receiver. The timeout is in seconds, a value of 0 uses the device's * default value (30s). */ int hidpp10_open_lock(struct hidpp10_device *device, uint8_t timeout); int hidpp10_close_lock(struct hidpp10_device *device); int hidpp10_disconnect(struct hidpp10_device *device, int idx); /* -------------------------------------------------------------------------- */ /* 0xB5: Pairing Information */ /* -------------------------------------------------------------------------- */ int hidpp10_get_pairing_information(struct hidpp10_device *dev, uint8_t *report_interval, uint16_t *wpid, uint8_t *device_type); int hidpp10_get_pairing_information_device_name(struct hidpp10_device *dev, char *name, size_t *name_sz); int hidpp10_get_extended_pairing_information(struct hidpp10_device *dev, uint32_t *serial); /* -------------------------------------------------------------------------- */ /* 0xF1: Device Firmware Information */ /* -------------------------------------------------------------------------- */ int hidpp10_get_firmare_information(struct hidpp10_device *dev, uint8_t *major, uint8_t *minor, uint8_t *build_number);