From 7bdca904f5684a8521ec0b21a0e8a57a334c1f4f Mon Sep 17 00:00:00 2001 From: Kyoken Date: Fri, 10 May 2024 20:10:42 +0300 Subject: [PATCH] asus: new quirks for Chakram X and other mice --- data/devices/asus-rog-chakram-x.device | 10 +- data/devices/asus-rog-pugio.device | 1 + src/asus.c | 55 ++++++-- src/asus.h | 39 +++++- src/driver-asus.c | 170 ++++++++++++++++++------- src/libratbag-data.c | 60 +++++++-- src/libratbag-data.h | 6 + test/data-parse-test.py | 18 +++ 8 files changed, 287 insertions(+), 72 deletions(-) diff --git a/data/devices/asus-rog-chakram-x.device b/data/devices/asus-rog-chakram-x.device index b586fdbd..a6a0fb27 100644 --- a/data/devices/asus-rog-chakram-x.device +++ b/data/devices/asus-rog-chakram-x.device @@ -1,14 +1,16 @@ [Device] Name=ASUS ROG Chakram X -DeviceMatch=usb:0b05:1a18 +DeviceMatch=usb:0b05:1a18;usb:0b05:1a1a DeviceType=mouse Driver=asus [Driver/asus] -Profiles=3 -Buttons=5 +Profiles=5 +Buttons=14 Leds=3 Dpis=4 Wireless=1 DpiRange=100:36000@100 -Quirks=DOUBLE_DPI +Quirks=DOUBLE_DPI;RAW_BRIGHTNESS;SEPARATE_XY_DPI;SEPARATE_LEDS;BUTTONS_SECONDARY +ButtonMapping=f0;f1;f2;0;0;e6;e8;e9;d0;d1;d2;d3 +ButtonMappingSecondary=0;0;ea;eb;ec;ed diff --git a/data/devices/asus-rog-pugio.device b/data/devices/asus-rog-pugio.device index f7c7664b..ffbcc805 100644 --- a/data/devices/asus-rog-pugio.device +++ b/data/devices/asus-rog-pugio.device @@ -11,3 +11,4 @@ Leds=3 Dpis=2 DpiRange=100:7200@100 ButtonMapping=f0;f1;f2;e4;e5;e6;0;e8;e9;e1;e2 +LedModes=ON;BREATHING;ON;CYCLE diff --git a/src/asus.c b/src/asus.c index cc279a1e..b8f96716 100644 --- a/src/asus.c +++ b/src/asus.c @@ -75,15 +75,18 @@ static const unsigned char ASUS_KEY_MAPPING[] = { /* 5E */ KEY_KP8, KEY_KP9, 0, }; -static unsigned int ASUS_POLLING_RATES[] = { 125, 250, 500, 1000 }; -static unsigned int ASUS_DEBOUNCE_TIMES[] = { 4, 8, 12, 16, 20, 24, 28, 32 }; +static const uint8_t ASUS_JOYSTICK_CODES[] = { 0xd0, 0xd1, 0xd2, 0xd3, 0xd7, 0xd8, 0xda, 0xdb }; +static const unsigned int ASUS_POLLING_RATES[] = { 125, 250, 500, 1000 }; +static const unsigned int ASUS_DEBOUNCE_TIMES[] = { 4, 8, 12, 16, 20, 24, 28, 32 }; /* search for ASUS button by ratbag types */ const struct asus_button * -asus_find_button_by_action(struct ratbag_button_action action) +asus_find_button_by_action(struct ratbag_button_action action, bool is_joystick) { const struct asus_button *asus_button; ARRAY_FOR_EACH(ASUS_BUTTON_MAPPING, asus_button) { + if (is_joystick != asus_code_is_joystick(asus_button->asus_code)) + continue; if ((action.type == RATBAG_BUTTON_ACTION_TYPE_BUTTON && asus_button->button == action.action.button) || (action.type == RATBAG_BUTTON_ACTION_TYPE_SPECIAL && asus_button->special == action.action.special)) return asus_button; @@ -113,6 +116,15 @@ asus_find_key_code(unsigned int linux_code) return -1; } +bool +asus_code_is_joystick(uint8_t asus_code) { + for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_JOYSTICK_CODES); i++) { + if (ASUS_JOYSTICK_CODES[i] == asus_code) + return true; + } + return false; +} + int asus_get_linux_key_code(uint8_t asus_code) { if (asus_code > ARRAY_LENGTH(ASUS_KEY_MAPPING)) { @@ -216,6 +228,11 @@ asus_get_profile_data(struct ratbag_device *device, struct asus_profile_data *da else data->profile_id = response.data.results[8]; + if (response.data.results[9]) + data->dpi_preset = response.data.results[9] - 1; + else + data->dpi_preset = -1; + data->version_primary_major = response.data.results[13]; data->version_primary_minor = response.data.results[12]; data->version_primary_build = response.data.results[11]; @@ -246,12 +263,13 @@ asus_set_profile(struct ratbag_device *device, unsigned int index) /* read button bindings */ int -asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data) +asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data, unsigned int group) { int rc; union asus_response response; union asus_request request = { .data.cmd = ASUS_CMD_GET_BUTTON_DATA, + .data.params[0] = (uint8_t)group, }; rc = asus_query(device, &request, &response); @@ -289,7 +307,7 @@ asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src, } int -asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data) +asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data, bool sep_xy_dpi) { int rc; uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data); @@ -298,6 +316,7 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat unsigned int i; union asus_request request = { .data.cmd = ASUS_CMD_GET_SETTINGS, + .data.params[0] = sep_xy_dpi ? 2 : 0, }; rc = asus_query(device, &request, &response); @@ -319,13 +338,24 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat break; case 4: /* 4 DPI presets */ - for (i = 0; i < dpi_count; i++) { - data->data4.dpi[i] = data->data4.dpi[i] * 50 + 50; - if (quirks & ASUS_QUIRK_DOUBLE_DPI) - data->data4.dpi[i] *= 2; + if (sep_xy_dpi) { /* separate X & Y values */ + for (i = 0; i < dpi_count; i++) { + data->data_xy.dpi[i].x = data->data_xy.dpi[i].x * 50 + 50; + data->data_xy.dpi[i].y = data->data_xy.dpi[i].y * 50 + 50; + if (quirks & ASUS_QUIRK_DOUBLE_DPI) { + data->data_xy.dpi[i].x *= 2; + data->data_xy.dpi[i].y *= 2; + } + } + } else { + for (i = 0; i < dpi_count; i++) { + data->data4.dpi[i] = data->data4.dpi[i] * 50 + 50; + if (quirks & ASUS_QUIRK_DOUBLE_DPI) + data->data4.dpi[i] *= 2; + } + data->data4.rate = ASUS_POLLING_RATES[data->data4.rate]; + data->data4.response = ASUS_DEBOUNCE_TIMES[data->data4.response]; } - data->data4.rate = ASUS_POLLING_RATES[data->data4.rate]; - data->data4.response = ASUS_DEBOUNCE_TIMES[data->data4.response]; break; default: @@ -440,12 +470,13 @@ asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled) } int -asus_get_led_data(struct ratbag_device *device, union asus_led_data *data) +asus_get_led_data(struct ratbag_device *device, union asus_led_data *data, unsigned int led) { int rc; union asus_response response; union asus_request request = { .data.cmd = ASUS_CMD_GET_LED_DATA, + .data.params[0] = led, }; rc = asus_query(device, &request, &response); diff --git a/src/asus.h b/src/asus.h index 95c0d643..69befdca 100644 --- a/src/asus.h +++ b/src/asus.h @@ -9,6 +9,10 @@ #define ASUS_QUIRK_DOUBLE_DPI 1 << 0 #define ASUS_QUIRK_STRIX_PROFILE 1 << 1 #define ASUS_QUIRK_BATTERY_V2 1 << 2 +#define ASUS_QUIRK_RAW_BRIGHTNESS 1 << 3 +#define ASUS_QUIRK_SEPARATE_XY_DPI 1 << 4 +#define ASUS_QUIRK_SEPARATE_LEDS 1 << 5 +#define ASUS_QUIRK_BUTTONS_SECONDARY 1 << 6 #define ASUS_PACKET_SIZE 64 #define ASUS_BUTTON_ACTION_TYPE_KEY 0 /* keyboard key */ @@ -18,6 +22,7 @@ /* maximum number of buttons across all ASUS devices */ #define ASUS_MAX_NUM_BUTTON 17 +#define ASUS_MAX_NUM_BUTTON_GROUP 2 /* maximum number of DPI presets across all ASUS devices */ /* for 4 DPI devices: 0 - red, 1 - purple, 2 - blue (default), 3 - green */ @@ -26,6 +31,7 @@ /* maximum number of LEDs across all ASUS devices */ #define ASUS_MAX_NUM_LED 3 +#define ASUS_MAX_NUM_LED_MODES 7 /* base request */ @@ -57,6 +63,7 @@ union asus_response { struct asus_profile_data { unsigned int profile_id; + int dpi_preset; uint8_t version_primary_major; uint8_t version_primary_minor; uint8_t version_primary_build; @@ -90,6 +97,7 @@ struct _asus_dpi2_data { uint16_t rate; /* polling rate */ uint16_t response; /* button response */ uint16_t snapping; /* angle snapping (on/off) */ + uint16_t pad2; } __attribute__((packed)); /* struct for storing 2 DPI presets and extra settings */ struct _asus_dpi4_data { @@ -98,11 +106,23 @@ struct _asus_dpi4_data { uint16_t rate; uint16_t response; uint16_t snapping; + uint16_t pad2; } __attribute__((packed)); /* struct for storing 4 DPI presets and extra settings */ +struct _asus_dpi_xy { + uint16_t x; + uint16_t y; +}; + +struct _asus_dpi_xy_data { + uint32_t pad; + struct _asus_dpi_xy dpi[4]; +} __attribute__((packed)); /* struct for storing 4 DPI presets with separate X & Y */ + union asus_resolution_data { struct _asus_dpi2_data data2; /* data for 2 DPI presets */ struct _asus_dpi4_data data4; /* data for 4 DPI presets */ + struct _asus_dpi_xy_data data_xy; /* data for 4 DPI presets with separate X & Y */ uint8_t raw[sizeof(struct _asus_dpi4_data)]; }; @@ -153,10 +173,18 @@ static const struct asus_button ASUS_BUTTON_MAPPING[] = { { 0xed, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button D */ { 0xee, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button E */ { 0xef, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button F */ + { 0xd0, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* joystick up */ + { 0xd1, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* joystick down */ + { 0xd2, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* joystick forward */ + { 0xd3, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* joystick backward */ + { 0xd7, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN }, /* joystick axis -Y */ + { 0xd8, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP }, /* joystick axis +Y */ + { 0xda, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT }, /* joystick axis -X */ + { 0xdb, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT }, /* joystick axis +X */ }; const struct asus_button * -asus_find_button_by_action(struct ratbag_button_action action); +asus_find_button_by_action(struct ratbag_button_action action, bool is_joystick); const struct asus_button * asus_find_button_by_code(uint8_t asus_code); @@ -164,6 +192,9 @@ asus_find_button_by_code(uint8_t asus_code); int asus_find_key_code(unsigned int linux_code); +bool +asus_code_is_joystick(uint8_t asus_code); + /* * @param asus_code ASUS key code. * @return Linux key code (as defined defined in linux/input-event-codes.h) or @@ -207,7 +238,7 @@ asus_set_profile(struct ratbag_device *device, unsigned int index); /* button bindings */ int -asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data); +asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data, unsigned int group); int asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src, @@ -216,7 +247,7 @@ asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src, /* resolution settings */ int -asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data); +asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data, bool sep_xy_dpi); int asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi); @@ -233,7 +264,7 @@ asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled); /* LED settings */ int -asus_get_led_data(struct ratbag_device *device, union asus_led_data *data); +asus_get_led_data(struct ratbag_device *device, union asus_led_data *data, unsigned int led); int asus_set_led(struct ratbag_device *device, diff --git a/src/driver-asus.c b/src/driver-asus.c index 57431114..e6f9d4db 100644 --- a/src/driver-asus.c +++ b/src/driver-asus.c @@ -46,17 +46,9 @@ static int ASUS_CONFIG_BUTTON_MAPPING[] = { 0xe6, /* DPI */ 0xe8, /* wheel up */ 0xe9, /* wheel down */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ - -1, /* placeholder */ }; +/* LedModes configuration property defaults */ static unsigned int ASUS_LED_MODE[] = { RATBAG_LED_ON, RATBAG_LED_BREATHING, @@ -69,12 +61,13 @@ static unsigned int ASUS_LED_MODE[] = { struct asus_data { uint8_t is_ready; - int button_mapping[ASUS_MAX_NUM_BUTTON]; - int button_indices[ASUS_MAX_NUM_BUTTON]; + int button_mapping[ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP]; + int button_indices[ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP]; + int led_modes[ASUS_MAX_NUM_LED_MODES]; }; static int -asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *profile) +asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *profile, int dpi_preset) { int rc; const struct _asus_binding *asus_binding; @@ -84,18 +77,28 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr struct ratbag_led *led; struct ratbag_resolution *resolution; union asus_binding_data binding_data; + union asus_binding_data binding_data_secondary; union asus_led_data led_data; union asus_resolution_data resolution_data; + union asus_resolution_data xy_resolution_data; unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions; + unsigned int led_count = ratbag_device_get_num_leds(device); + uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data); struct asus_data *drv_data = ratbag_get_drv_data(device); /* get buttons */ log_debug(device->ratbag, "Loading buttons data\n"); - rc = asus_get_binding_data(device, &binding_data); + rc = asus_get_binding_data(device, &binding_data, 0); if (rc) return rc; + if (quirks & ASUS_QUIRK_BUTTONS_SECONDARY) { + rc = asus_get_binding_data(device, &binding_data_secondary, 1); + if (rc) + return rc; + } + ratbag_profile_for_each_button(profile, button) { int asus_index = drv_data->button_indices[button->index]; if (asus_index == -1) { @@ -103,7 +106,11 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr continue; } - asus_binding = &binding_data.data.binding[asus_index]; + if (asus_index < ASUS_MAX_NUM_BUTTON) { + asus_binding = &binding_data.data.binding[asus_index]; + } else { + asus_binding = &binding_data_secondary.data.binding[asus_index % ASUS_MAX_NUM_BUTTON]; + } /* disabled */ if (asus_binding->action == ASUS_BUTTON_CODE_DISABLED) { @@ -144,31 +151,59 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr /* get DPIs */ log_debug(device->ratbag, "Loading resolutions data\n"); - rc = asus_get_resolution_data(device, &resolution_data); + rc = asus_get_resolution_data(device, &resolution_data, false); if (rc) return rc; + if (quirks & ASUS_QUIRK_SEPARATE_XY_DPI) { + rc = asus_get_resolution_data(device, &xy_resolution_data, true); + if (rc) + return rc; + } + switch (dpi_count) { case 2: /* 2 DPI presets */ profile->hz = resolution_data.data2.rate; profile->angle_snapping = resolution_data.data2.snapping; profile->debounce = resolution_data.data2.response; - ratbag_profile_for_each_resolution(profile, resolution) - ratbag_resolution_set_resolution( - resolution, - resolution_data.data2.dpi[resolution->index], - resolution_data.data2.dpi[resolution->index]); + ratbag_profile_for_each_resolution(profile, resolution) { + if (quirks & ASUS_QUIRK_SEPARATE_XY_DPI) { + ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); + ratbag_resolution_set_resolution( + resolution, + xy_resolution_data.data_xy.dpi[resolution->index].x, + xy_resolution_data.data_xy.dpi[resolution->index].y); + } else { + ratbag_resolution_set_resolution( + resolution, + resolution_data.data2.dpi[resolution->index], + resolution_data.data2.dpi[resolution->index]); + } + if (dpi_preset != -1 && (unsigned int)dpi_preset == resolution->index) + resolution->is_active = true; + } break; case 4: /* 4 DPI presets */ profile->hz = resolution_data.data4.rate; profile->angle_snapping = resolution_data.data4.snapping; profile->debounce = resolution_data.data4.response; - ratbag_profile_for_each_resolution(profile, resolution) - ratbag_resolution_set_resolution( - resolution, - resolution_data.data4.dpi[resolution->index], - resolution_data.data4.dpi[resolution->index]); + ratbag_profile_for_each_resolution(profile, resolution) { + if (quirks & ASUS_QUIRK_SEPARATE_XY_DPI) { + ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); + ratbag_resolution_set_resolution( + resolution, + xy_resolution_data.data_xy.dpi[resolution->index].x, + xy_resolution_data.data_xy.dpi[resolution->index].y); + } else { + ratbag_resolution_set_resolution( + resolution, + resolution_data.data4.dpi[resolution->index], + resolution_data.data4.dpi[resolution->index]); + } + if (dpi_preset != -1 && (unsigned int)dpi_preset == resolution->index) + resolution->is_active = true; + } break; default: @@ -177,16 +212,31 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr /* get LEDs */ - log_debug(device->ratbag, "Loading LEDs data\n"); - rc = asus_get_led_data(device, &led_data); - if (rc) - return rc; + if (!(quirks & ASUS_QUIRK_SEPARATE_LEDS) && led_count) { + log_debug(device->ratbag, "Loading LEDs data\n"); + rc = asus_get_led_data(device, &led_data, 0); + if (rc) + return rc; + } ratbag_profile_for_each_led(profile, led) { - asus_led = &led_data.data.led[led->index]; - led->mode = ASUS_LED_MODE[asus_led->mode]; - /* convert brightness from 0-4 to 0-256 */ - led->brightness = asus_led->brightness * 64; + if (quirks & ASUS_QUIRK_SEPARATE_LEDS) { + log_debug(device->ratbag, "Loading LED %d data\n", led->index); + rc = asus_get_led_data(device, &led_data, led->index); + if (rc) + return rc; + asus_led = &led_data.data.led[0]; + } else { + asus_led = &led_data.data.led[led->index]; + } + + led->mode = drv_data->led_modes[asus_led->mode]; + if (quirks & ASUS_QUIRK_RAW_BRIGHTNESS) { + led->brightness = asus_led->brightness; + } else { + /* convert brightness from 0-4 to 0-256 */ + led->brightness = asus_led->brightness * 64; + } led->color.red = asus_led->r; led->color.green = asus_led->g; led->color.blue = asus_led->b; @@ -203,6 +253,7 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr struct ratbag_led *led; struct ratbag_resolution *resolution; struct asus_data *drv_data = ratbag_get_drv_data(device); + uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data); /* set buttons */ ratbag_profile_for_each_button(profile, button) { @@ -218,6 +269,7 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr const struct asus_button *asus_button; uint8_t asus_code_src; uint8_t asus_code_dst; + bool is_joystick; rc = drv_data->button_mapping[asus_index]; if (rc == -1) { @@ -250,7 +302,18 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr case RATBAG_BUTTON_ACTION_TYPE_BUTTON: case RATBAG_BUTTON_ACTION_TYPE_SPECIAL: /* ratbag action to ASUS code */ - asus_button = asus_find_button_by_action(button->action); + is_joystick = asus_code_is_joystick(asus_code_src); + if (is_joystick) { + asus_button = asus_find_button_by_action(button->action, true); + if (asus_button != NULL) { /* found button to bind to */ + rc = asus_set_button_action( + device, asus_code_src, asus_button->asus_code, + ASUS_BUTTON_ACTION_TYPE_BUTTON); + break; + } + } + + asus_button = asus_find_button_by_action(button->action, false); if (asus_button != NULL) /* found button to bind to */ rc = asus_set_button_action( device, asus_code_src, asus_button->asus_code, @@ -306,15 +369,20 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr log_debug(device->ratbag, "LED %d changed\n", led->index); uint8_t led_mode = 0; - for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_LED_MODE); i++) { - if (ASUS_LED_MODE[i] == led->mode) { + for (unsigned int i = 0; i < ASUS_MAX_NUM_LED_MODES; i++) { + if (drv_data->led_modes[i] == (int) led->mode) { led_mode = i; break; } } - /* convert brightness from 0-256 to 0-4 */ - uint8_t led_brightness = (uint8_t)round((double)led->brightness / 64.0); + uint8_t led_brightness; + if (quirks & ASUS_QUIRK_RAW_BRIGHTNESS) { + led_brightness = led->brightness; + } else { + /* convert brightness from 0-256 to 0-4 */ + led_brightness = (uint8_t)round((double)led->brightness / 64.0); + } rc = asus_set_led(device, led->index, led_mode, led_brightness, led->color); if (rc) return rc; @@ -365,7 +433,7 @@ asus_driver_load_profiles(struct ratbag_device *device) return rc; } - rc = asus_driver_load_profile(device, profile); + rc = asus_driver_load_profile(device, profile, profile_data.dpi_preset); if (rc) return rc; } @@ -469,23 +537,37 @@ asus_driver_probe(struct ratbag_device *device) button_count = ratbag_device_data_asus_get_button_count(device->data); led_count = ratbag_device_data_asus_get_led_count(device->data); const int *bm = ratbag_device_data_asus_get_button_mapping(device->data); + const int *led_modes = ratbag_device_data_asus_get_led_modes(device->data); /* merge ButtonMapping configuration property with defaults */ - for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON; i++) { - drv_data->button_mapping[i] = bm[i] != -1 ? bm[i] : ASUS_CONFIG_BUTTON_MAPPING[i]; + for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP; i++) { + if (bm[i] != -1) { + drv_data->button_mapping[i] = bm[i]; + } else { + if (i < ARRAY_LENGTH(ASUS_CONFIG_BUTTON_MAPPING)) { + drv_data->button_mapping[i] = ASUS_CONFIG_BUTTON_MAPPING[i]; + } else { + drv_data->button_mapping[i] = -1; + } + } drv_data->button_indices[i] = -1; } + /* merge LedModes configuration property with defaults */ + for (unsigned int i = 0; i < ASUS_MAX_NUM_LED_MODES; i++) + drv_data->led_modes[i] = (led_modes[i] != -1) ? led_modes[i] : (int) ASUS_LED_MODE[i]; + /* setup a lookup table for all defined buttons */ unsigned int button_index = 0; ARRAY_FOR_EACH(ASUS_BUTTON_MAPPING, asus_button) { /* search for this button in the ButtonMapping by it's ASUS code */ - for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON; i++) { + for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP; i++) { if (drv_data->button_mapping[i] == (int)asus_button->asus_code) { /* add button to indices array */ drv_data->button_indices[button_index] = (int)i; - log_debug(device->ratbag, "Button %d is mapped to 0x%02x\n", - button_index, (uint8_t)drv_data->button_mapping[i]); + log_debug(device->ratbag, "Button %d is mapped to 0x%02x at position %d group %d\n", + button_index, (uint8_t)drv_data->button_mapping[i], + i % ASUS_MAX_NUM_BUTTON, i / ASUS_MAX_NUM_BUTTON); button_index++; break; } diff --git a/src/libratbag-data.c b/src/libratbag-data.c index 4f4bf2c4..0eb43c86 100644 --- a/src/libratbag-data.c +++ b/src/libratbag-data.c @@ -100,12 +100,13 @@ struct data_steelseries { struct data_asus { int profile_count; int button_count; - int button_mapping[ASUS_MAX_NUM_BUTTON]; + int button_mapping[ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP]; int led_count; int dpi_count; int is_wireless; struct dpi_range *dpi_range; uint32_t quirks; + int led_modes[ASUS_MAX_NUM_LED_MODES]; }; struct ratbag_device_data { @@ -375,8 +376,10 @@ init_data_asus(struct ratbag *ratbag, data->asus.dpi_range = NULL; data->asus.is_wireless = -1; data->asus.quirks = 0; - for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON; i++) + for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP; i++) data->asus.button_mapping[i] = -1; + for (unsigned int i = 0; i < ASUS_MAX_NUM_LED_MODES; i++) + data->asus.led_modes[i] = -1; int profiles = g_key_file_get_integer(keyfile, group, "Profiles", &error); if (!error && profiles >= 0) @@ -388,11 +391,20 @@ init_data_asus(struct ratbag *ratbag, data->asus.button_count = buttons; g_clear_error(&error); - gsize button_mapping_count = 0; - _cleanup_(g_strfreevp) char **button_mapping = g_key_file_get_string_list(keyfile, group, "ButtonMapping", &button_mapping_count, &error); - if (!error && button_mapping) { - for (unsigned int i = 0; i < button_mapping_count; i++) { - data->asus.button_mapping[i] = strtoul(button_mapping[i], NULL, 16); + gsize btn_map_count = 0; + _cleanup_(g_strfreevp) char **btn_map = g_key_file_get_string_list(keyfile, group, "ButtonMapping", &btn_map_count, &error); + if (!error && btn_map) { + for (unsigned int i = 0; i < btn_map_count; i++) { + data->asus.button_mapping[i] = strtoul(btn_map[i], NULL, 16); + } + } + g_clear_error(&error); + + gsize btn_map_2nd_count = 0; + _cleanup_(g_strfreevp) char **btn_map_2nd = g_key_file_get_string_list(keyfile, group, "ButtonMappingSecondary", &btn_map_2nd_count, &error); + if (!error && btn_map_2nd) { + for (unsigned int i = 0; i < btn_map_2nd_count; i++) { + data->asus.button_mapping[i + ASUS_MAX_NUM_BUTTON] = strtoul(btn_map_2nd[i], NULL, 16); } } g_clear_error(&error); @@ -425,8 +437,33 @@ init_data_asus(struct ratbag *ratbag, data->asus.quirks |= ASUS_QUIRK_DOUBLE_DPI; } else if (streq(quirks[i], "STRIX_PROFILE")) { data->asus.quirks |= ASUS_QUIRK_STRIX_PROFILE; + } else if (streq(quirks[i], "RAW_BRIGHTNESS")) { + data->asus.quirks |= ASUS_QUIRK_RAW_BRIGHTNESS; + } else if (streq(quirks[i], "SEPARATE_XY_DPI")) { + data->asus.quirks |= ASUS_QUIRK_SEPARATE_XY_DPI; + } else if (streq(quirks[i], "SEPARATE_LEDS")) { + data->asus.quirks |= ASUS_QUIRK_SEPARATE_LEDS; + } else if (streq(quirks[i], "BUTTONS_SECONDARY")) { + data->asus.quirks |= ASUS_QUIRK_BUTTONS_SECONDARY; } else { - log_debug(ratbag, "%s is invalid quirk. Ignoring...\n", quirks[i]); + log_error(ratbag, "%s is invalid quirk. Ignoring...\n", quirks[i]); + } + } + } + g_clear_error(&error); + + gsize led_modes_count = 0; + _cleanup_(g_strfreevp) char **led_modes = g_key_file_get_string_list(keyfile, group, "LedModes", &led_modes_count, &error); + if (!error && led_modes) { + for (unsigned int i = 0; i < led_modes_count; i++) { + if (streq(led_modes[i], "ON")) { + data->asus.led_modes[i] = RATBAG_LED_ON; + } else if (streq(led_modes[i], "BREATHING")) { + data->asus.led_modes[i] = RATBAG_LED_BREATHING; + } else if (streq(led_modes[i], "CYCLE")) { + data->asus.led_modes[i] = RATBAG_LED_CYCLE; + } else { + log_error(ratbag, "%s is invalid LED mode. Ignoring...\n", led_modes[i]); } } } @@ -895,6 +932,13 @@ ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data) return data->asus.led_count; } +const int * +ratbag_device_data_asus_get_led_modes(const struct ratbag_device_data *data) +{ + assert(data->drivertype == ASUS); + return data->asus.led_modes; +} + int ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data) { diff --git a/src/libratbag-data.h b/src/libratbag-data.h index 1999a98e..c51a7bf5 100644 --- a/src/libratbag-data.h +++ b/src/libratbag-data.h @@ -164,6 +164,12 @@ ratbag_device_data_asus_get_button_mapping(const struct ratbag_device_data *data int ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data); +/** + * @return Array of LED modes + */ +const int * +ratbag_device_data_asus_get_led_modes(const struct ratbag_device_data *data); + /** * @return Number of DPI presets */ diff --git a/test/data-parse-test.py b/test/data-parse-test.py index 1c081801..bd325799 100755 --- a/test/data-parse-test.py +++ b/test/data-parse-test.py @@ -108,10 +108,12 @@ def check_profile_type_str(string: str): def check_section_asus(section: configparser.SectionProxy): permitted_keys = ( "ButtonMapping", + "ButtonMappingSecondary", "Buttons", "DpiRange", "Dpis", "Leds", + "LedModes", "Profiles", "Quirks", "Wireless", @@ -129,6 +131,10 @@ def check_section_asus(section: configparser.SectionProxy): quirks = ( "DOUBLE_DPI", "STRIX_PROFILE", + "RAW_BRIGHTNESS", + "SEPARATE_XY_DPI", + "SEPARATE_LEDS", + "BUTTONS_SECONDARY", ) for quirk in section["Quirks"].split(";"): assert quirk in quirks @@ -136,6 +142,18 @@ def check_section_asus(section: configparser.SectionProxy): # No such section - not an error. pass + try: + led_modes = ( + "ON", + "BREATHING", + "CYCLE", + ) + for led_mode in section["LedModes"].split(";"): + assert led_mode in led_modes + except KeyError: + # No such section - not an error. + pass + def check_section_hidpp10(section: configparser.SectionProxy): permitted = [