mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8235b5bb60 | ||
|
|
b8d4d3ca1f | ||
|
|
e07d72e2a7 | ||
|
|
d93a8bc474 | ||
|
|
1f4efda955 | ||
|
|
03afbe49f3 | ||
|
|
f9d1574841 | ||
|
|
b0f2779270 | ||
|
|
43f76eee67 | ||
|
|
54edb7e0a2 | ||
|
|
2fb9a701e8 | ||
|
|
805e7fb77f | ||
|
|
1e20248b6d | ||
|
|
d7bbed2eb1 | ||
|
|
874c01732a | ||
|
|
c5214d2633 | ||
|
|
b61da30205 | ||
|
|
e4184c2227 | ||
|
|
78d1124c3e | ||
|
|
65d07ae4d1 | ||
|
|
ca94a8a111 | ||
|
|
7bdca904f5 | ||
|
|
ad6540e39b | ||
|
|
df3c73e958 | ||
|
|
dcc5def3d6 |
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@@ -8,20 +8,24 @@ env:
|
|||||||
libjson-glib-dev libsystemd-dev libudev-dev libunistring-dev
|
libjson-glib-dev libsystemd-dev libudev-dev libunistring-dev
|
||||||
python3-dev python3-evdev swig python3-sphinx
|
python3-dev python3-evdev swig python3-sphinx
|
||||||
UBUNTU_DEP_TEST: check python3-gi python3-lxml valgrind
|
UBUNTU_DEP_TEST: check python3-gi python3-lxml valgrind
|
||||||
PIP_PACKAGES: meson ninja libevdev pyudev pytest sphinx_rtd_theme black ruff
|
PIP_PACKAGES: meson ninja libevdev pyudev pytest sphinx_rtd_theme black==25.12.0 ruff==0.15.12
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-dist:
|
build-and-dist:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
meson_args:
|
include:
|
||||||
- ''
|
- name: default
|
||||||
- '-Dbuildtype=plain'
|
meson_args: ''
|
||||||
- '-Dbuildtype=release'
|
- name: plain
|
||||||
- '-Ddocumentation=true'
|
meson_args: '-Dbuildtype=plain'
|
||||||
|
- name: release
|
||||||
|
meson_args: '-Dbuildtype=release'
|
||||||
|
- name: documentation
|
||||||
|
meson_args: '-Ddocumentation=true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: ./.github/actions/pkginstall
|
- uses: ./.github/actions/pkginstall
|
||||||
with:
|
with:
|
||||||
apt: $UBUNTU_DEP_BUILD $UBUNTU_DEP_TEST
|
apt: $UBUNTU_DEP_BUILD $UBUNTU_DEP_TEST
|
||||||
@@ -41,10 +45,10 @@ jobs:
|
|||||||
- name: check if any files are left after uninstall
|
- name: check if any files are left after uninstall
|
||||||
run: (test -d _instdir && tree _instdir && exit 1) || exit 0
|
run: (test -d _instdir && tree _instdir && exit 1) || exit 0
|
||||||
# Capture all the meson logs, even if we failed
|
# Capture all the meson logs, even if we failed
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ always() }} # even if we fail
|
if: ${{ always() }} # even if we fail
|
||||||
with:
|
with:
|
||||||
name: meson test logs
|
name: 'meson test logs ${{ matrix.name }}'
|
||||||
path: |
|
path: |
|
||||||
builddir/meson-logs/testlog*.txt
|
builddir/meson-logs/testlog*.txt
|
||||||
builddir/meson-logs/meson-log.txt
|
builddir/meson-logs/meson-log.txt
|
||||||
|
|||||||
2
.github/workflows/pages.yml
vendored
2
.github/workflows/pages.yml
vendored
@@ -11,7 +11,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/pkginstall
|
- uses: ./.github/actions/pkginstall
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=ASUS ROG Chakram X
|
Name=ASUS ROG Chakram X
|
||||||
DeviceMatch=usb:0b05:1a18
|
DeviceMatch=usb:0b05:1a18;usb:0b05:1a1a
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
Driver=asus
|
Driver=asus
|
||||||
|
|
||||||
[Driver/asus]
|
[Driver/asus]
|
||||||
Profiles=3
|
Profiles=5
|
||||||
Buttons=5
|
Buttons=14
|
||||||
Leds=3
|
Leds=3
|
||||||
Dpis=4
|
Dpis=4
|
||||||
Wireless=1
|
Wireless=1
|
||||||
DpiRange=100:36000@100
|
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
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=ASUS ROG Keris Wireless AimPoint
|
Name=ASUS ROG Keris Wireless AimPoint
|
||||||
DeviceMatch=usb:0b05:1a68
|
DeviceMatch=usb:0b05:1a66;usb:0b05:1a68
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
Driver=asus
|
Driver=asus
|
||||||
|
|
||||||
|
|||||||
13
data/devices/asus-rog-keris.device
Normal file
13
data/devices/asus-rog-keris.device
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS ROG Keris
|
||||||
|
DeviceMatch=usb:0b05:195c
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=3
|
||||||
|
Buttons=8
|
||||||
|
Leds=2
|
||||||
|
Dpis=4
|
||||||
|
DpiRange=100:16000@100
|
||||||
|
Quirks=DOUBLE_DPI
|
||||||
12
data/devices/asus-rog-omni-receiver.device
Normal file
12
data/devices/asus-rog-omni-receiver.device
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS ROG Omni Receiver
|
||||||
|
DeviceMatch=usb:0b05:1ace
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
# The Omni receiver is a shared USB device for multiple mice (all of them
|
||||||
|
# enumerate with the same usb id), so the actual model is identified during
|
||||||
|
# probe and resolved to the model-specific .device data. This file only
|
||||||
|
# exists to get the asus driver probed on the receiver's hidraw nodes.
|
||||||
|
[Driver/asus]
|
||||||
|
Quirks=OMNI_RECEIVER
|
||||||
@@ -11,3 +11,4 @@ Leds=3
|
|||||||
Dpis=2
|
Dpis=2
|
||||||
DpiRange=100:7200@100
|
DpiRange=100:7200@100
|
||||||
ButtonMapping=f0;f1;f2;e4;e5;e6;0;e8;e9;e1;e2
|
ButtonMapping=f0;f1;f2;e4;e5;e6;0;e8;e9;e1;e2
|
||||||
|
LedModes=ON;BREATHING;ON;CYCLE
|
||||||
|
|||||||
19
data/devices/asus-rog-strix-impact3-wireless.device
Normal file
19
data/devices/asus-rog-strix-impact3-wireless.device
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS ROG Strix Impact III Wireless
|
||||||
|
DeviceMatch=usb:0b05:1ad7
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
# This device enumerates as usb 0b05:1ad7 behind the ASUS Omni receiver
|
||||||
|
# (0b05:1ace). The usb id is resolved during probe: the receiver is
|
||||||
|
# identified first (asus-rog-omni-receiver.device) and the serial number
|
||||||
|
# signature prefix (OmniSignature) is matched against this file.
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=5
|
||||||
|
Buttons=8
|
||||||
|
Leds=1
|
||||||
|
Dpis=4
|
||||||
|
Wireless=1
|
||||||
|
DpiRange=100:36000@50
|
||||||
|
Quirks=OMNI_RECEIVER;SEPARATE_XY_DPI;LED_V2;SETTINGS_V2
|
||||||
|
OmniSignature=20
|
||||||
13
data/devices/asus-rog-strix-impact3.device
Normal file
13
data/devices/asus-rog-strix-impact3.device
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS ROG Strix Impact III
|
||||||
|
DeviceMatch=usb:0b05:1a88
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=3
|
||||||
|
Buttons=8
|
||||||
|
Leds=2
|
||||||
|
Dpis=4
|
||||||
|
DpiRange=100:12000@50
|
||||||
|
Quirks=LED_V2;SETTINGS_V2
|
||||||
12
data/devices/asus-tuf-gaming-m3-gen-ii.device
Normal file
12
data/devices/asus-tuf-gaming-m3-gen-ii.device
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUSTeK TUF GAMING M3 GEN II
|
||||||
|
DeviceMatch=usb:0b05:1a9b
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=3
|
||||||
|
Buttons=8
|
||||||
|
Leds=1
|
||||||
|
Dpis=4
|
||||||
|
DpiRange=100:8000@100
|
||||||
12
data/devices/asus-tuf-gaming-m4-air.device
Normal file
12
data/devices/asus-tuf-gaming-m4-air.device
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS TUF GAMING M4 AIR
|
||||||
|
DeviceMatch=usb:0b05:1a03
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=3
|
||||||
|
Buttons=6
|
||||||
|
Leds=0
|
||||||
|
Dpis=4
|
||||||
|
DpiRange=100:16000@100
|
||||||
14
data/devices/asus-tuf-gaming-mini-wl-miku.device
Normal file
14
data/devices/asus-tuf-gaming-mini-wl-miku.device
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[Device]
|
||||||
|
Name=ASUS TUF GAMING MINI WL MOUSE MIKU
|
||||||
|
DeviceMatch=usb:0b05:1c56;usb:0b05:1c57
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=asus
|
||||||
|
|
||||||
|
[Driver/asus]
|
||||||
|
Profiles=5
|
||||||
|
Buttons=8
|
||||||
|
Leds=1
|
||||||
|
Dpis=4
|
||||||
|
Wireless=1
|
||||||
|
DpiRange=100:12000@100
|
||||||
|
Quirks=SEPARATE_XY_DPI;RAW_BRIGHTNESS
|
||||||
11
data/devices/glorious-model-o-eternal.device
Normal file
11
data/devices/glorious-model-o-eternal.device
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Glorious Model O Eternal
|
||||||
|
DeviceMatch=usb:3794:a000
|
||||||
|
Driver=sinowealth
|
||||||
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/sinowealth/devices/1009]
|
||||||
|
Buttons=6
|
||||||
|
LedType=RBG
|
||||||
|
DeviceName=Glorious Model O Eternal
|
||||||
|
SensorType=PMW3360
|
||||||
5
data/devices/logitech-MX-Master-4.device
Normal file
5
data/devices/logitech-MX-Master-4.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Device]
|
||||||
|
DeviceMatch=bluetooth:046d:b042
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=hidpp20
|
||||||
|
Name=Logitech MX Master 4
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech MX Vertical
|
Name=Logitech MX Vertical
|
||||||
DeviceMatch=bluetooth:046d:b020;usb:046d:407b;usb:046d:c08a
|
DeviceMatch=bluetooth:046d:b020;usb:046d:407b;usb:046d:c08a;usb:046d:c077
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ Name=Logitech G502 Hero Wireless
|
|||||||
DeviceMatch=usb:046d:407f;usb:046d:c08d
|
DeviceMatch=usb:046d:407f;usb:046d:c08d
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ Name=Logitech G502 Hero
|
|||||||
DeviceMatch=usb:046d:c08b
|
DeviceMatch=usb:046d:c08b
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ Name=Logitech G502 Proteus Spectrum
|
|||||||
DeviceMatch=usb:046d:c332
|
DeviceMatch=usb:046d:c332
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
9
data/devices/logitech-g502-x-plus.device
Normal file
9
data/devices/logitech-g502-x-plus.device
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Logitech G502 X PLUS
|
||||||
|
DeviceMatch=usb:046d:4099;usb:046d:c095
|
||||||
|
DeviceType=mouse
|
||||||
|
Driver=hidpp20
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
# G502X_PLUS: LED is in the 2nd slot. INDEX_OFFSET: profile index is 1-indexed.
|
||||||
|
Quirk=G502X_PLUS;INDEX_OFFSET
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech G502 X Wireless
|
Name=Logitech G502 X Wireless
|
||||||
DeviceMatch=usb:046d:c098
|
DeviceMatch=usb:046d:c098;usb:046d:409f
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ Name=Logitech G502 X
|
|||||||
DeviceMatch=usb:046d:c099
|
DeviceMatch=usb:046d:c099
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ Name=Logitech G604
|
|||||||
DeviceMatch=usb:046d:4085;bluetooth:046d:b024
|
DeviceMatch=usb:046d:4085;bluetooth:046d:b024
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
DeviceType=mouse
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=INDEX_OFFSET
|
||||||
|
|||||||
8
data/devices/logitech-g705.device
Normal file
8
data/devices/logitech-g705.device
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Logitech G705
|
||||||
|
DeviceMatch=usb:046d:c096;usb:046d:409d;bluetooth:046d:b02e
|
||||||
|
Driver=hidpp20
|
||||||
|
DeviceType=mouse
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
Quirk=G502X_PLUS
|
||||||
169
src/asus.c
169
src/asus.c
@@ -26,6 +26,7 @@
|
|||||||
#include "asus.h"
|
#include "asus.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "libratbag-data.h"
|
#include "libratbag-data.h"
|
||||||
#include "libratbag-private.h"
|
#include "libratbag-private.h"
|
||||||
@@ -75,15 +76,18 @@ static const unsigned char ASUS_KEY_MAPPING[] = {
|
|||||||
/* 5E */ KEY_KP8, KEY_KP9, 0,
|
/* 5E */ KEY_KP8, KEY_KP9, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int ASUS_POLLING_RATES[] = { 125, 250, 500, 1000 };
|
static const uint8_t ASUS_JOYSTICK_CODES[] = { 0xd0, 0xd1, 0xd2, 0xd3, 0xd7, 0xd8, 0xda, 0xdb };
|
||||||
static unsigned int ASUS_DEBOUNCE_TIMES[] = { 4, 8, 12, 16, 20, 24, 28, 32 };
|
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 */
|
/* search for ASUS button by ratbag types */
|
||||||
const struct asus_button *
|
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;
|
const struct asus_button *asus_button;
|
||||||
ARRAY_FOR_EACH(ASUS_BUTTON_MAPPING, 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) ||
|
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))
|
(action.type == RATBAG_BUTTON_ACTION_TYPE_SPECIAL && asus_button->special == action.action.special))
|
||||||
return asus_button;
|
return asus_button;
|
||||||
@@ -113,6 +117,15 @@ asus_find_key_code(unsigned int linux_code)
|
|||||||
return -1;
|
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
|
int
|
||||||
asus_get_linux_key_code(uint8_t asus_code) {
|
asus_get_linux_key_code(uint8_t asus_code) {
|
||||||
if (asus_code > ARRAY_LENGTH(ASUS_KEY_MAPPING)) {
|
if (asus_code > ARRAY_LENGTH(ASUS_KEY_MAPPING)) {
|
||||||
@@ -126,15 +139,37 @@ asus_query(struct ratbag_device *device,
|
|||||||
union asus_request *request, union asus_response *response)
|
union asus_request *request, union asus_response *response)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
|
||||||
|
uint8_t omni_tx_buf[ASUS_PACKET_SIZE];
|
||||||
|
uint8_t omni_rx_buf[ASUS_PACKET_SIZE];
|
||||||
|
|
||||||
rc = ratbag_hidraw_output_report(device, request->raw, ASUS_PACKET_SIZE);
|
if (quirks & ASUS_QUIRK_OMNI_RECEIVER) {
|
||||||
if (rc < 0)
|
/* devices behind the Omni receiver use report ID 0x03 and a
|
||||||
return rc;
|
* 64-byte report, the payload is shifted by one byte */
|
||||||
|
memset(omni_tx_buf, 0, sizeof(omni_tx_buf));
|
||||||
|
omni_tx_buf[0] = 0x03;
|
||||||
|
memcpy(omni_tx_buf + 1, request->raw, ASUS_PACKET_SIZE - 1);
|
||||||
|
|
||||||
memset(response, 0, sizeof(union asus_response));
|
rc = ratbag_hidraw_output_report(device, omni_tx_buf, ASUS_PACKET_SIZE);
|
||||||
rc = ratbag_hidraw_read_input_report(device, response->raw, ASUS_PACKET_SIZE, NULL);
|
if (rc < 0)
|
||||||
if (rc < 0)
|
return rc;
|
||||||
return rc;
|
|
||||||
|
memset(response, 0, sizeof(union asus_response));
|
||||||
|
rc = ratbag_hidraw_read_input_report(device, omni_rx_buf, ASUS_PACKET_SIZE, NULL);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
memcpy(response->raw, omni_rx_buf + 1, ASUS_PACKET_SIZE - 1);
|
||||||
|
} else {
|
||||||
|
rc = ratbag_hidraw_output_report(device, request->raw, ASUS_PACKET_SIZE);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
memset(response, 0, sizeof(union asus_response));
|
||||||
|
rc = ratbag_hidraw_read_input_report(device, response->raw, ASUS_PACKET_SIZE, NULL);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* invalid state, disconnected or sleeping */
|
/* invalid state, disconnected or sleeping */
|
||||||
if (response->data.code == ASUS_STATUS_ERROR) {
|
if (response->data.code == ASUS_STATUS_ERROR) {
|
||||||
@@ -216,6 +251,11 @@ asus_get_profile_data(struct ratbag_device *device, struct asus_profile_data *da
|
|||||||
else
|
else
|
||||||
data->profile_id = response.data.results[8];
|
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_major = response.data.results[13];
|
||||||
data->version_primary_minor = response.data.results[12];
|
data->version_primary_minor = response.data.results[12];
|
||||||
data->version_primary_build = response.data.results[11];
|
data->version_primary_build = response.data.results[11];
|
||||||
@@ -246,12 +286,13 @@ asus_set_profile(struct ratbag_device *device, unsigned int index)
|
|||||||
|
|
||||||
/* read button bindings */
|
/* read button bindings */
|
||||||
int
|
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;
|
int rc;
|
||||||
union asus_response response;
|
union asus_response response;
|
||||||
union asus_request request = {
|
union asus_request request = {
|
||||||
.data.cmd = ASUS_CMD_GET_BUTTON_DATA,
|
.data.cmd = ASUS_CMD_GET_BUTTON_DATA,
|
||||||
|
.data.params[0] = (uint8_t)group,
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = asus_query(device, &request, &response);
|
rc = asus_query(device, &request, &response);
|
||||||
@@ -289,7 +330,7 @@ asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
int rc;
|
||||||
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
|
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
|
||||||
@@ -298,6 +339,7 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
union asus_request request = {
|
union asus_request request = {
|
||||||
.data.cmd = ASUS_CMD_GET_SETTINGS,
|
.data.cmd = ASUS_CMD_GET_SETTINGS,
|
||||||
|
.data.params[0] = sep_xy_dpi ? 2 : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = asus_query(device, &request, &response);
|
rc = asus_query(device, &request, &response);
|
||||||
@@ -319,13 +361,51 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: /* 4 DPI presets */
|
case 4: /* 4 DPI presets */
|
||||||
for (i = 0; i < dpi_count; i++) {
|
if (sep_xy_dpi) { /* separate X & Y values */
|
||||||
data->data4.dpi[i] = data->data4.dpi[i] * 50 + 50;
|
if (quirks & ASUS_QUIRK_SETTINGS_V2) {
|
||||||
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
|
/* new layout: data starts at offset 4, each preset
|
||||||
data->data4.dpi[i] *= 2;
|
* is x lo/hi, y lo/hi */
|
||||||
|
for (i = 0; i < dpi_count; i++) {
|
||||||
|
uint16_t x = data->raw[4 + i * 4] |
|
||||||
|
(data->raw[5 + i * 4] << 8);
|
||||||
|
uint16_t y = data->raw[6 + i * 4] |
|
||||||
|
(data->raw[7 + i * 4] << 8);
|
||||||
|
data->data_xy.dpi[i].x = x * 50 + 50;
|
||||||
|
data->data_xy.dpi[i].y = y * 50 + 50;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 {
|
||||||
|
if (quirks & ASUS_QUIRK_SETTINGS_V2) {
|
||||||
|
/* new layout: data starts at offset 4, dpi presets
|
||||||
|
* are 2 bytes each, rate/debounce/snapping are
|
||||||
|
* single bytes at offset 12/14/16 */
|
||||||
|
for (i = 0; i < dpi_count; i++) {
|
||||||
|
uint16_t dpi = data->raw[4 + i * 2] |
|
||||||
|
(data->raw[5 + i * 2] << 8);
|
||||||
|
data->data4.dpi[i] = dpi * 50 + 50;
|
||||||
|
}
|
||||||
|
data->data4.rate = ASUS_POLLING_RATES[data->raw[12] & 0x07];
|
||||||
|
data->data4.response = ASUS_DEBOUNCE_TIMES[data->raw[14]];
|
||||||
|
data->data4.snapping = data->raw[16];
|
||||||
|
} 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -348,10 +428,12 @@ asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi)
|
|||||||
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
|
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
|
||||||
idpi /= 2;
|
idpi /= 2;
|
||||||
|
|
||||||
|
idpi = (idpi - 50) / 50;
|
||||||
union asus_request request = {
|
union asus_request request = {
|
||||||
.data.cmd = ASUS_CMD_SET_SETTING,
|
.data.cmd = ASUS_CMD_SET_SETTING,
|
||||||
.data.params[0] = index,
|
.data.params[0] = index,
|
||||||
.data.params[2] = (idpi - 50) / 50,
|
.data.params[2] = idpi & 0xff,
|
||||||
|
.data.params[3] = (idpi >> 8) & 0xff,
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = asus_query(device, &request, &response);
|
rc = asus_query(device, &request, &response);
|
||||||
@@ -440,12 +522,13 @@ asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
int rc;
|
||||||
union asus_response response;
|
union asus_response response;
|
||||||
union asus_request request = {
|
union asus_request request = {
|
||||||
.data.cmd = ASUS_CMD_GET_LED_DATA,
|
.data.cmd = ASUS_CMD_GET_LED_DATA,
|
||||||
|
.data.params[0] = led,
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = asus_query(device, &request, &response);
|
rc = asus_query(device, &request, &response);
|
||||||
@@ -480,3 +563,49 @@ asus_set_led(struct ratbag_device *device,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ASUS Omni receiver: identify the mouse behind the shared receiver.
|
||||||
|
*
|
||||||
|
* All mice connected to an Omni receiver share the same USB id
|
||||||
|
* (0b05:1ace), so the model is queried with a signature request
|
||||||
|
* (03 12 12 02). The response carries a 12 byte ASCII serial number at
|
||||||
|
* offset 5 and the model is derived from its prefix.
|
||||||
|
*
|
||||||
|
* The serial number is matched against the OmniSignature field of the
|
||||||
|
* .device files, so supporting a new model does not require any code
|
||||||
|
* changes. On success the usb id of the identified model is returned in
|
||||||
|
* id, so that the caller can resolve the mouse-specific .device data.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
asus_omni_identify(struct ratbag_device *device, struct input_id *id)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
union asus_request request = {
|
||||||
|
.data.cmd = 0x1212,
|
||||||
|
.data.params[0] = 0x02,
|
||||||
|
};
|
||||||
|
union asus_response response;
|
||||||
|
char signature[13];
|
||||||
|
|
||||||
|
rc = asus_query(device, &request, &response);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* signature is 12 ASCII bytes at offset 5 of the raw report,
|
||||||
|
* which is offset 4 after the report id is stripped */
|
||||||
|
memcpy(signature, response.raw + 4, 12);
|
||||||
|
signature[12] = '\0';
|
||||||
|
|
||||||
|
rc = ratbag_device_data_omni_signature_match(device->ratbag, signature, id);
|
||||||
|
if (rc) {
|
||||||
|
log_debug(device->ratbag,
|
||||||
|
"Unknown ASUS Omni device serial '%s'. Please add an "
|
||||||
|
"OmniSignature entry to the .device file of the model.\n",
|
||||||
|
signature);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info(device->ratbag,
|
||||||
|
"ASUS Omni device identified (serial %s)\n", signature);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
47
src/asus.h
47
src/asus.h
@@ -9,6 +9,13 @@
|
|||||||
#define ASUS_QUIRK_DOUBLE_DPI 1 << 0
|
#define ASUS_QUIRK_DOUBLE_DPI 1 << 0
|
||||||
#define ASUS_QUIRK_STRIX_PROFILE 1 << 1
|
#define ASUS_QUIRK_STRIX_PROFILE 1 << 1
|
||||||
#define ASUS_QUIRK_BATTERY_V2 1 << 2
|
#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_QUIRK_OMNI_RECEIVER 1 << 7 /* device is behind an ASUS Omni receiver, transport uses report ID 0x03 */
|
||||||
|
#define ASUS_QUIRK_LED_V2 1 << 8 /* LED response is per-zone with data at offset 4, brightness is 0-100 */
|
||||||
|
#define ASUS_QUIRK_SETTINGS_V2 1 << 9 /* settings/DPI response data starts at offset 4, rate/debounce/snapping are single bytes */
|
||||||
|
|
||||||
#define ASUS_PACKET_SIZE 64
|
#define ASUS_PACKET_SIZE 64
|
||||||
#define ASUS_BUTTON_ACTION_TYPE_KEY 0 /* keyboard key */
|
#define ASUS_BUTTON_ACTION_TYPE_KEY 0 /* keyboard key */
|
||||||
@@ -18,6 +25,7 @@
|
|||||||
|
|
||||||
/* maximum number of buttons across all ASUS devices */
|
/* maximum number of buttons across all ASUS devices */
|
||||||
#define ASUS_MAX_NUM_BUTTON 17
|
#define ASUS_MAX_NUM_BUTTON 17
|
||||||
|
#define ASUS_MAX_NUM_BUTTON_GROUP 2
|
||||||
|
|
||||||
/* maximum number of DPI presets across all ASUS devices */
|
/* maximum number of DPI presets across all ASUS devices */
|
||||||
/* for 4 DPI devices: 0 - red, 1 - purple, 2 - blue (default), 3 - green */
|
/* for 4 DPI devices: 0 - red, 1 - purple, 2 - blue (default), 3 - green */
|
||||||
@@ -26,6 +34,7 @@
|
|||||||
|
|
||||||
/* maximum number of LEDs across all ASUS devices */
|
/* maximum number of LEDs across all ASUS devices */
|
||||||
#define ASUS_MAX_NUM_LED 3
|
#define ASUS_MAX_NUM_LED 3
|
||||||
|
#define ASUS_MAX_NUM_LED_MODES 7
|
||||||
|
|
||||||
/* base request */
|
/* base request */
|
||||||
|
|
||||||
@@ -57,6 +66,7 @@ union asus_response {
|
|||||||
|
|
||||||
struct asus_profile_data {
|
struct asus_profile_data {
|
||||||
unsigned int profile_id;
|
unsigned int profile_id;
|
||||||
|
int dpi_preset;
|
||||||
uint8_t version_primary_major;
|
uint8_t version_primary_major;
|
||||||
uint8_t version_primary_minor;
|
uint8_t version_primary_minor;
|
||||||
uint8_t version_primary_build;
|
uint8_t version_primary_build;
|
||||||
@@ -90,6 +100,7 @@ struct _asus_dpi2_data {
|
|||||||
uint16_t rate; /* polling rate */
|
uint16_t rate; /* polling rate */
|
||||||
uint16_t response; /* button response */
|
uint16_t response; /* button response */
|
||||||
uint16_t snapping; /* angle snapping (on/off) */
|
uint16_t snapping; /* angle snapping (on/off) */
|
||||||
|
uint16_t pad2;
|
||||||
} __attribute__((packed)); /* struct for storing 2 DPI presets and extra settings */
|
} __attribute__((packed)); /* struct for storing 2 DPI presets and extra settings */
|
||||||
|
|
||||||
struct _asus_dpi4_data {
|
struct _asus_dpi4_data {
|
||||||
@@ -98,11 +109,23 @@ struct _asus_dpi4_data {
|
|||||||
uint16_t rate;
|
uint16_t rate;
|
||||||
uint16_t response;
|
uint16_t response;
|
||||||
uint16_t snapping;
|
uint16_t snapping;
|
||||||
|
uint16_t pad2;
|
||||||
} __attribute__((packed)); /* struct for storing 4 DPI presets and extra settings */
|
} __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 {
|
union asus_resolution_data {
|
||||||
struct _asus_dpi2_data data2; /* data for 2 DPI presets */
|
struct _asus_dpi2_data data2; /* data for 2 DPI presets */
|
||||||
struct _asus_dpi4_data data4; /* data for 4 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)];
|
uint8_t raw[sizeof(struct _asus_dpi4_data)];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,10 +176,18 @@ static const struct asus_button ASUS_BUTTON_MAPPING[] = {
|
|||||||
{ 0xed, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button D */
|
{ 0xed, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button D */
|
||||||
{ 0xee, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button E */
|
{ 0xee, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button E */
|
||||||
{ 0xef, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* side button F */
|
{ 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 *
|
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 *
|
const struct asus_button *
|
||||||
asus_find_button_by_code(uint8_t asus_code);
|
asus_find_button_by_code(uint8_t asus_code);
|
||||||
@@ -164,6 +195,9 @@ asus_find_button_by_code(uint8_t asus_code);
|
|||||||
int
|
int
|
||||||
asus_find_key_code(unsigned int linux_code);
|
asus_find_key_code(unsigned int linux_code);
|
||||||
|
|
||||||
|
bool
|
||||||
|
asus_code_is_joystick(uint8_t asus_code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @param asus_code ASUS key code.
|
* @param asus_code ASUS key code.
|
||||||
* @return Linux key code (as defined defined in linux/input-event-codes.h) or
|
* @return Linux key code (as defined defined in linux/input-event-codes.h) or
|
||||||
@@ -191,6 +225,11 @@ asus_setup_led(struct ratbag_device *device, struct ratbag_led *led);
|
|||||||
int
|
int
|
||||||
asus_query(struct ratbag_device *device, union asus_request *request, union asus_response *response);
|
asus_query(struct ratbag_device *device, union asus_request *request, union asus_response *response);
|
||||||
|
|
||||||
|
/* ASUS Omni receiver: identify the mouse behind the shared receiver and
|
||||||
|
* return the usb id that matches its own .device file. */
|
||||||
|
int
|
||||||
|
asus_omni_identify(struct ratbag_device *device, struct input_id *id);
|
||||||
|
|
||||||
/* commit */
|
/* commit */
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -207,7 +246,7 @@ asus_set_profile(struct ratbag_device *device, unsigned int index);
|
|||||||
/* button bindings */
|
/* button bindings */
|
||||||
|
|
||||||
int
|
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
|
int
|
||||||
asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src,
|
asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src,
|
||||||
@@ -216,7 +255,7 @@ asus_set_button_action(struct ratbag_device *device, uint8_t asus_code_src,
|
|||||||
/* resolution settings */
|
/* resolution settings */
|
||||||
|
|
||||||
int
|
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
|
int
|
||||||
asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi);
|
asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi);
|
||||||
@@ -233,7 +272,7 @@ asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled);
|
|||||||
/* LED settings */
|
/* LED settings */
|
||||||
|
|
||||||
int
|
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
|
int
|
||||||
asus_set_led(struct ratbag_device *device,
|
asus_set_led(struct ratbag_device *device,
|
||||||
|
|||||||
@@ -46,17 +46,9 @@ static int ASUS_CONFIG_BUTTON_MAPPING[] = {
|
|||||||
0xe6, /* DPI */
|
0xe6, /* DPI */
|
||||||
0xe8, /* wheel up */
|
0xe8, /* wheel up */
|
||||||
0xe9, /* wheel down */
|
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[] = {
|
static unsigned int ASUS_LED_MODE[] = {
|
||||||
RATBAG_LED_ON,
|
RATBAG_LED_ON,
|
||||||
RATBAG_LED_BREATHING,
|
RATBAG_LED_BREATHING,
|
||||||
@@ -69,12 +61,13 @@ static unsigned int ASUS_LED_MODE[] = {
|
|||||||
|
|
||||||
struct asus_data {
|
struct asus_data {
|
||||||
uint8_t is_ready;
|
uint8_t is_ready;
|
||||||
int button_mapping[ASUS_MAX_NUM_BUTTON];
|
int button_mapping[ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP];
|
||||||
int button_indices[ASUS_MAX_NUM_BUTTON];
|
int button_indices[ASUS_MAX_NUM_BUTTON * ASUS_MAX_NUM_BUTTON_GROUP];
|
||||||
|
int led_modes[ASUS_MAX_NUM_LED_MODES];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
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;
|
int rc;
|
||||||
const struct _asus_binding *asus_binding;
|
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_led *led;
|
||||||
struct ratbag_resolution *resolution;
|
struct ratbag_resolution *resolution;
|
||||||
union asus_binding_data binding_data;
|
union asus_binding_data binding_data;
|
||||||
|
union asus_binding_data binding_data_secondary;
|
||||||
union asus_led_data led_data;
|
union asus_led_data led_data;
|
||||||
union asus_resolution_data resolution_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 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);
|
struct asus_data *drv_data = ratbag_get_drv_data(device);
|
||||||
|
|
||||||
/* get buttons */
|
/* get buttons */
|
||||||
|
|
||||||
log_debug(device->ratbag, "Loading buttons data\n");
|
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)
|
if (rc)
|
||||||
return 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) {
|
ratbag_profile_for_each_button(profile, button) {
|
||||||
int asus_index = drv_data->button_indices[button->index];
|
int asus_index = drv_data->button_indices[button->index];
|
||||||
if (asus_index == -1) {
|
if (asus_index == -1) {
|
||||||
@@ -103,7 +106,11 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
continue;
|
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 */
|
/* disabled */
|
||||||
if (asus_binding->action == ASUS_BUTTON_CODE_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 */
|
/* get DPIs */
|
||||||
|
|
||||||
log_debug(device->ratbag, "Loading resolutions data\n");
|
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)
|
if (rc)
|
||||||
return 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) {
|
switch (dpi_count) {
|
||||||
case 2: /* 2 DPI presets */
|
case 2: /* 2 DPI presets */
|
||||||
profile->hz = resolution_data.data2.rate;
|
profile->hz = resolution_data.data2.rate;
|
||||||
profile->angle_snapping = resolution_data.data2.snapping;
|
profile->angle_snapping = resolution_data.data2.snapping;
|
||||||
profile->debounce = resolution_data.data2.response;
|
profile->debounce = resolution_data.data2.response;
|
||||||
ratbag_profile_for_each_resolution(profile, resolution)
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
ratbag_resolution_set_resolution(
|
if (quirks & ASUS_QUIRK_SEPARATE_XY_DPI) {
|
||||||
resolution,
|
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||||
resolution_data.data2.dpi[resolution->index],
|
ratbag_resolution_set_resolution(
|
||||||
resolution_data.data2.dpi[resolution->index]);
|
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;
|
break;
|
||||||
|
|
||||||
case 4: /* 4 DPI presets */
|
case 4: /* 4 DPI presets */
|
||||||
profile->hz = resolution_data.data4.rate;
|
profile->hz = resolution_data.data4.rate;
|
||||||
profile->angle_snapping = resolution_data.data4.snapping;
|
profile->angle_snapping = resolution_data.data4.snapping;
|
||||||
profile->debounce = resolution_data.data4.response;
|
profile->debounce = resolution_data.data4.response;
|
||||||
ratbag_profile_for_each_resolution(profile, resolution)
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
ratbag_resolution_set_resolution(
|
if (quirks & ASUS_QUIRK_SEPARATE_XY_DPI) {
|
||||||
resolution,
|
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||||
resolution_data.data4.dpi[resolution->index],
|
ratbag_resolution_set_resolution(
|
||||||
resolution_data.data4.dpi[resolution->index]);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -177,16 +212,44 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
|
|
||||||
/* get LEDs */
|
/* get LEDs */
|
||||||
|
|
||||||
log_debug(device->ratbag, "Loading LEDs data\n");
|
if (!(quirks & (ASUS_QUIRK_SEPARATE_LEDS | ASUS_QUIRK_LED_V2)) && led_count) {
|
||||||
rc = asus_get_led_data(device, &led_data);
|
log_debug(device->ratbag, "Loading LEDs data\n");
|
||||||
if (rc)
|
rc = asus_get_led_data(device, &led_data, 0);
|
||||||
return rc;
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
ratbag_profile_for_each_led(profile, led) {
|
ratbag_profile_for_each_led(profile, led) {
|
||||||
asus_led = &led_data.data.led[led->index];
|
if (quirks & (ASUS_QUIRK_SEPARATE_LEDS | ASUS_QUIRK_LED_V2)) {
|
||||||
led->mode = ASUS_LED_MODE[asus_led->mode];
|
log_debug(device->ratbag, "Loading LED %d data\n", led->index);
|
||||||
/* convert brightness from 0-4 to 0-256 */
|
rc = asus_get_led_data(device, &led_data, led->index);
|
||||||
led->brightness = asus_led->brightness * 64;
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quirks & ASUS_QUIRK_LED_V2) {
|
||||||
|
/* new layout: a single zone per response with data at
|
||||||
|
* offset 4, brightness is 0-100 percent */
|
||||||
|
led->mode = drv_data->led_modes[led_data.raw[4]];
|
||||||
|
led->brightness = led_data.raw[5] * 255 / 100;
|
||||||
|
led->color.red = led_data.raw[6];
|
||||||
|
led->color.green = led_data.raw[7];
|
||||||
|
led->color.blue = led_data.raw[8];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quirks & ASUS_QUIRK_SEPARATE_LEDS)
|
||||||
|
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.red = asus_led->r;
|
||||||
led->color.green = asus_led->g;
|
led->color.green = asus_led->g;
|
||||||
led->color.blue = asus_led->b;
|
led->color.blue = asus_led->b;
|
||||||
@@ -203,6 +266,7 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
struct ratbag_led *led;
|
struct ratbag_led *led;
|
||||||
struct ratbag_resolution *resolution;
|
struct ratbag_resolution *resolution;
|
||||||
struct asus_data *drv_data = ratbag_get_drv_data(device);
|
struct asus_data *drv_data = ratbag_get_drv_data(device);
|
||||||
|
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
|
||||||
|
|
||||||
/* set buttons */
|
/* set buttons */
|
||||||
ratbag_profile_for_each_button(profile, button) {
|
ratbag_profile_for_each_button(profile, button) {
|
||||||
@@ -218,6 +282,7 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
const struct asus_button *asus_button;
|
const struct asus_button *asus_button;
|
||||||
uint8_t asus_code_src;
|
uint8_t asus_code_src;
|
||||||
uint8_t asus_code_dst;
|
uint8_t asus_code_dst;
|
||||||
|
bool is_joystick;
|
||||||
|
|
||||||
rc = drv_data->button_mapping[asus_index];
|
rc = drv_data->button_mapping[asus_index];
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
@@ -250,7 +315,18 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
|
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
|
||||||
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
|
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
|
||||||
/* ratbag action to ASUS code */
|
/* 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 */
|
if (asus_button != NULL) /* found button to bind to */
|
||||||
rc = asus_set_button_action(
|
rc = asus_set_button_action(
|
||||||
device, asus_code_src, asus_button->asus_code,
|
device, asus_code_src, asus_button->asus_code,
|
||||||
@@ -306,15 +382,23 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr
|
|||||||
|
|
||||||
log_debug(device->ratbag, "LED %d changed\n", led->index);
|
log_debug(device->ratbag, "LED %d changed\n", led->index);
|
||||||
uint8_t led_mode = 0;
|
uint8_t led_mode = 0;
|
||||||
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_LED_MODE); i++) {
|
for (unsigned int i = 0; i < ASUS_MAX_NUM_LED_MODES; i++) {
|
||||||
if (ASUS_LED_MODE[i] == led->mode) {
|
if (drv_data->led_modes[i] == (int) led->mode) {
|
||||||
led_mode = i;
|
led_mode = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert brightness from 0-256 to 0-4 */
|
uint8_t led_brightness;
|
||||||
uint8_t led_brightness = (uint8_t)round((double)led->brightness / 64.0);
|
if (quirks & ASUS_QUIRK_RAW_BRIGHTNESS) {
|
||||||
|
led_brightness = led->brightness;
|
||||||
|
} else if (quirks & ASUS_QUIRK_LED_V2) {
|
||||||
|
/* convert brightness from 0-255 to 0-100 percent */
|
||||||
|
led_brightness = (uint8_t)round((double)led->brightness * 100.0 / 255.0);
|
||||||
|
} 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);
|
rc = asus_set_led(device, led->index, led_mode, led_brightness, led->color);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
@@ -365,7 +449,7 @@ asus_driver_load_profiles(struct ratbag_device *device)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = asus_driver_load_profile(device, profile);
|
rc = asus_driver_load_profile(device, profile, profile_data.dpi_preset);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -447,17 +531,51 @@ asus_driver_probe(struct ratbag_device *device)
|
|||||||
struct ratbag_button *button;
|
struct ratbag_button *button;
|
||||||
struct ratbag_resolution *resolution;
|
struct ratbag_resolution *resolution;
|
||||||
struct ratbag_led *led;
|
struct ratbag_led *led;
|
||||||
|
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
|
||||||
|
|
||||||
rc = ratbag_open_hidraw(device);
|
rc = ratbag_open_hidraw(device);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = asus_get_profile_data(device, &profile_data);
|
/* The Omni receiver is a shared USB device for multiple mice, so the
|
||||||
if (rc) {
|
* actual model has to be identified and resolved to its own .device
|
||||||
ratbag_close_hidraw(device);
|
* data before anything else. Wrong hidraw nodes (keyboard, media
|
||||||
return -ENODEV;
|
* control, etc.) fail the identification and are rejected here. */
|
||||||
|
if (quirks & ASUS_QUIRK_OMNI_RECEIVER) {
|
||||||
|
struct ratbag_device_data *data;
|
||||||
|
struct input_id id = device->ids;
|
||||||
|
|
||||||
|
rc = asus_omni_identify(device, &id);
|
||||||
|
if (rc) {
|
||||||
|
log_debug(device->ratbag,
|
||||||
|
"Omni device is not a supported mouse\n");
|
||||||
|
ratbag_close_hidraw(device);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = ratbag_device_data_new_for_id(device->ratbag, &id);
|
||||||
|
if (!data) {
|
||||||
|
log_error(device->ratbag,
|
||||||
|
"No device data for Omni mouse %04x:%04x\n",
|
||||||
|
id.vendor, id.product);
|
||||||
|
ratbag_close_hidraw(device);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ratbag_device_data_unref(device->data);
|
||||||
|
device->data = data;
|
||||||
|
device->devicetype = ratbag_device_data_get_device_type(device->data);
|
||||||
|
free(device->name);
|
||||||
|
device->name = strdup_safe(ratbag_device_data_get_name(device->data));
|
||||||
|
log_info(device->ratbag,
|
||||||
|
"ASUS Omni receiver identified device: %s\n",
|
||||||
|
device->name);
|
||||||
|
|
||||||
|
quirks = ratbag_device_data_asus_get_quirks(device->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = asus_get_profile_data(device, &profile_data);
|
||||||
|
|
||||||
/* create device state data */
|
/* create device state data */
|
||||||
drv_data = zalloc(sizeof(*drv_data));
|
drv_data = zalloc(sizeof(*drv_data));
|
||||||
ratbag_set_drv_data(device, drv_data);
|
ratbag_set_drv_data(device, drv_data);
|
||||||
@@ -469,23 +587,37 @@ asus_driver_probe(struct ratbag_device *device)
|
|||||||
button_count = ratbag_device_data_asus_get_button_count(device->data);
|
button_count = ratbag_device_data_asus_get_button_count(device->data);
|
||||||
led_count = ratbag_device_data_asus_get_led_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 *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 */
|
/* merge ButtonMapping configuration property with defaults */
|
||||||
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++) {
|
||||||
drv_data->button_mapping[i] = bm[i] != -1 ? bm[i] : ASUS_CONFIG_BUTTON_MAPPING[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;
|
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 */
|
/* setup a lookup table for all defined buttons */
|
||||||
unsigned int button_index = 0;
|
unsigned int button_index = 0;
|
||||||
ARRAY_FOR_EACH(ASUS_BUTTON_MAPPING, asus_button) {
|
ARRAY_FOR_EACH(ASUS_BUTTON_MAPPING, asus_button) {
|
||||||
/* search for this button in the ButtonMapping by it's ASUS code */
|
/* 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) {
|
if (drv_data->button_mapping[i] == (int)asus_button->asus_code) {
|
||||||
/* add button to indices array */
|
/* add button to indices array */
|
||||||
drv_data->button_indices[button_index] = (int)i;
|
drv_data->button_indices[button_index] = (int)i;
|
||||||
log_debug(device->ratbag, "Button %d is mapped to 0x%02x\n",
|
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]);
|
button_index, (uint8_t)drv_data->button_mapping[i],
|
||||||
|
i % ASUS_MAX_NUM_BUTTON, i / ASUS_MAX_NUM_BUTTON);
|
||||||
button_index++;
|
button_index++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,7 +411,13 @@ hidpp20drv_read_led_8071(struct ratbag_led *led, struct hidpp20drv_data* drv_dat
|
|||||||
hidpp20_rgb_effects_get_device_info(drv_data->dev, &device_info);
|
hidpp20_rgb_effects_get_device_info(drv_data->dev, &device_info);
|
||||||
cluster_info = drv_data->led_infos.color_leds_8071[led->index];
|
cluster_info = drv_data->led_infos.color_leds_8071[led->index];
|
||||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||||
h_led = &profile->leds[led->index];
|
if (drv_data->dev->quirks & HIDPP20_QUIRK_G502X_PLUS) {
|
||||||
|
// On G502X+ the second slot controls the user configurable LED.
|
||||||
|
// (Note: There is only 1 reported LED, it just happens to use 2nd index though)
|
||||||
|
h_led = &profile->leds[1];
|
||||||
|
} else {
|
||||||
|
h_led = &profile->leds[led->index];
|
||||||
|
}
|
||||||
|
|
||||||
switch (h_led->mode) {
|
switch (h_led->mode) {
|
||||||
case HIDPP20_LED_ON:
|
case HIDPP20_LED_ON:
|
||||||
@@ -579,10 +585,12 @@ hidpp20drv_update_button_8100(struct ratbag_button *button)
|
|||||||
}
|
}
|
||||||
profile->buttons[button->index].subany.type = type;
|
profile->buttons[button->index].subany.type = type;
|
||||||
profile->buttons[button->index].subany.subtype = subtype;
|
profile->buttons[button->index].subany.subtype = subtype;
|
||||||
if (subtype == HIDPP20_BUTTON_HID_TYPE_KEYBOARD)
|
if (subtype == HIDPP20_BUTTON_HID_TYPE_KEYBOARD) {
|
||||||
|
profile->buttons[button->index].keyboard_keys.modifier_flags = 0;
|
||||||
profile->buttons[button->index].keyboard_keys.key = code;
|
profile->buttons[button->index].keyboard_keys.key = code;
|
||||||
else
|
} else {
|
||||||
profile->buttons[button->index].consumer_control.consumer_control = code;
|
profile->buttons[button->index].consumer_control.consumer_control = code;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
|
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
|
||||||
code = hidpp20_onboard_profiles_get_code_from_special(action->action.special);
|
code = hidpp20_onboard_profiles_get_code_from_special(action->action.special);
|
||||||
@@ -689,7 +697,13 @@ hidpp20drv_update_led_8070_8071(struct ratbag_led *led, struct ratbag_profile* p
|
|||||||
|
|
||||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||||
h_led = &(h_profile->leds[led->index]);
|
if (drv_data->dev->quirks & HIDPP20_QUIRK_G502X_PLUS) {
|
||||||
|
// On G502X+ the second slot controls the user configurable LED.
|
||||||
|
// (Note: There is only 1 reported LED, it just happens to use 2nd index though)
|
||||||
|
h_led = &(h_profile->leds[1]);
|
||||||
|
} else {
|
||||||
|
h_led = &(h_profile->leds[led->index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!h_led)
|
if (!h_led)
|
||||||
@@ -1420,7 +1434,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
|||||||
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
||||||
/* The 8070 feature implemented in the G602 doesn't follow the spec,
|
/* The 8070 feature implemented in the G602 doesn't follow the spec,
|
||||||
* so we ignore it */
|
* so we ignore it */
|
||||||
if (ratbag_device_data_hidpp20_get_quirk(device->data) == HIDPP20_QUIRK_G602)
|
if (ratbag_device_data_hidpp20_get_quirks(device->data) & HIDPP20_QUIRK_G602)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
log_debug(ratbag, "device has color effects\n");
|
log_debug(ratbag, "device has color effects\n");
|
||||||
@@ -1694,14 +1708,15 @@ hidpp20drv_probe(struct ratbag_device *device)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->quirk = ratbag_device_data_hidpp20_get_quirk(device->data);
|
dev->quirks = ratbag_device_data_hidpp20_get_quirks(device->data);
|
||||||
|
|
||||||
drv_data->dev = dev;
|
drv_data->dev = dev;
|
||||||
|
|
||||||
log_debug(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), dev->proto_major, dev->proto_minor);
|
log_debug(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), dev->proto_major, dev->proto_minor);
|
||||||
|
|
||||||
if(dev->quirk != HIDPP20_QUIRK_NONE)
|
/* quirks is a bitmask; log each flag that is set */
|
||||||
log_debug(device->ratbag, "'%s' is quirked (%s)\n", ratbag_device_get_name(device), hidpp20_get_quirk_string(dev->quirk));
|
for (uint32_t q = dev->quirks; q != 0; q &= q - 1)
|
||||||
|
log_debug(device->ratbag, "'%s' is quirked (%s)\n", ratbag_device_get_name(device), hidpp20_get_quirk_string(q & ~(q - 1)));
|
||||||
|
|
||||||
/* add some defaults that will be overwritten by the device */
|
/* add some defaults that will be overwritten by the device */
|
||||||
drv_data->num_profiles = 1;
|
drv_data->num_profiles = 1;
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ hidpp20_get_quirk_string(enum hidpp20_quirk quirk)
|
|||||||
CASE_RETURN_STRING(HIDPP20_QUIRK_NONE);
|
CASE_RETURN_STRING(HIDPP20_QUIRK_NONE);
|
||||||
CASE_RETURN_STRING(HIDPP20_QUIRK_G305);
|
CASE_RETURN_STRING(HIDPP20_QUIRK_G305);
|
||||||
CASE_RETURN_STRING(HIDPP20_QUIRK_G602);
|
CASE_RETURN_STRING(HIDPP20_QUIRK_G602);
|
||||||
|
CASE_RETURN_STRING(HIDPP20_QUIRK_G502X_PLUS);
|
||||||
|
CASE_RETURN_STRING(HIDPP20_QUIRK_INDEX_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
abort();
|
abort();
|
||||||
@@ -1530,7 +1532,7 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
|
|||||||
.msg.parameters[0] = sensor->index,
|
.msg.parameters[0] = sensor->index,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (device->quirk == HIDPP20_QUIRK_G602) {
|
if (device->quirks & HIDPP20_QUIRK_G602) {
|
||||||
msg.msg.parameters[0] = 1;
|
msg.msg.parameters[0] = 1;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
@@ -1546,7 +1548,7 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
|
|||||||
get_unaligned_be_u16(&msg.msg.parameters[i]) != 0) {
|
get_unaligned_be_u16(&msg.msg.parameters[i]) != 0) {
|
||||||
uint16_t value = get_unaligned_be_u16(&msg.msg.parameters[i]);
|
uint16_t value = get_unaligned_be_u16(&msg.msg.parameters[i]);
|
||||||
|
|
||||||
if (device->quirk == HIDPP20_QUIRK_G602 && i == 2)
|
if ((device->quirks & HIDPP20_QUIRK_G602) && i == 2)
|
||||||
value += 0xe000;
|
value += 0xe000;
|
||||||
|
|
||||||
if (value > 0xe000) {
|
if (value > 0xe000) {
|
||||||
@@ -1578,7 +1580,7 @@ hidpp20_adjustable_dpi_get_dpi(struct hidpp20_device *device,
|
|||||||
.msg.parameters[0] = sensor->index,
|
.msg.parameters[0] = sensor->index,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (device->quirk == HIDPP20_QUIRK_G602)
|
if (device->quirks & HIDPP20_QUIRK_G602)
|
||||||
msg.msg.parameters[0] = 1;
|
msg.msg.parameters[0] = 1;
|
||||||
|
|
||||||
rc = hidpp20_request_command(device, &msg);
|
rc = hidpp20_request_command(device, &msg);
|
||||||
@@ -1660,7 +1662,7 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
|||||||
.msg.parameters[0] = sensor->index,
|
.msg.parameters[0] = sensor->index,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (device->quirk == HIDPP20_QUIRK_G602)
|
if (device->quirks & HIDPP20_QUIRK_G602)
|
||||||
msg.msg.parameters[0] = 1;
|
msg.msg.parameters[0] = 1;
|
||||||
|
|
||||||
set_unaligned_be_u16(&msg.msg.parameters[1], dpi);
|
set_unaligned_be_u16(&msg.msg.parameters[1], dpi);
|
||||||
@@ -1802,6 +1804,7 @@ int hidpp20_adjustable_report_rate_set_report_rate(struct hidpp20_device *device
|
|||||||
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303 0x02
|
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303 0x02
|
||||||
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900 0x03
|
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900 0x03
|
||||||
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G915 0x04
|
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G915 0x04
|
||||||
|
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G502X 0x05
|
||||||
#define HIDPP20_ONBOARD_PROFILES_MACRO_TYPE_G402 0x01
|
#define HIDPP20_ONBOARD_PROFILES_MACRO_TYPE_G402 0x01
|
||||||
|
|
||||||
#define HIDPP20_USER_PROFILES_G402 0x0000
|
#define HIDPP20_USER_PROFILES_G402 0x0000
|
||||||
@@ -1831,7 +1834,8 @@ union hidpp20_internal_profile {
|
|||||||
} name;
|
} name;
|
||||||
struct hidpp20_internal_led leds[2]; /* G303, g502, g900 only */
|
struct hidpp20_internal_led leds[2]; /* G303, g502, g900 only */
|
||||||
struct hidpp20_internal_led alt_leds[2];
|
struct hidpp20_internal_led alt_leds[2];
|
||||||
uint8_t free[2];
|
uint8_t custom_animation_index; // G502X Plus, G705
|
||||||
|
uint8_t free; // unused
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
} __attribute__((packed)) profile;
|
} __attribute__((packed)) profile;
|
||||||
};
|
};
|
||||||
@@ -2220,7 +2224,8 @@ hidpp20_onboard_profiles_validate(struct hidpp20_device *device,
|
|||||||
if ((info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G402) &&
|
if ((info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G402) &&
|
||||||
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303) &&
|
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303) &&
|
||||||
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900) &&
|
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900) &&
|
||||||
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G915)) {
|
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G915) &&
|
||||||
|
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G502X)) {
|
||||||
hidpp_log_error(&device->base,
|
hidpp_log_error(&device->base,
|
||||||
"Profile layout not supported: 0x%02x.\n",
|
"Profile layout not supported: 0x%02x.\n",
|
||||||
info->profile_format_id);
|
info->profile_format_id);
|
||||||
@@ -2273,6 +2278,10 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
|
|||||||
|
|
||||||
active_profile_index = rc;
|
active_profile_index = rc;
|
||||||
|
|
||||||
|
/* Apply quirk for devices that return 1-indexed profile */
|
||||||
|
if ((device->quirks & HIDPP20_QUIRK_INDEX_OFFSET) && active_profile_index > 0)
|
||||||
|
active_profile_index--;
|
||||||
|
|
||||||
profiles = zalloc(sizeof(struct hidpp20_profiles));
|
profiles = zalloc(sizeof(struct hidpp20_profiles));
|
||||||
profiles->profiles = zalloc(info.profile_count * sizeof(struct hidpp20_profile));
|
profiles->profiles = zalloc(info.profile_count * sizeof(struct hidpp20_profile));
|
||||||
profiles->sector_size = info.sector_size;
|
profiles->sector_size = info.sector_size;
|
||||||
@@ -2793,7 +2802,7 @@ hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
|
|||||||
profiles->sector_size,
|
profiles->sector_size,
|
||||||
data);
|
data);
|
||||||
|
|
||||||
if (rc && device->quirk == HIDPP20_QUIRK_G305) {
|
if (rc && (device->quirks & HIDPP20_QUIRK_G305)) {
|
||||||
/* The G305 has a bug where it throws an ERR_INVALID_ARGUMENT
|
/* The G305 has a bug where it throws an ERR_INVALID_ARGUMENT
|
||||||
if the sector has not been written to yet. If this happens
|
if the sector has not been written to yet. If this happens
|
||||||
we will read the ROM profiles.*/
|
we will read the ROM profiles.*/
|
||||||
@@ -2959,6 +2968,18 @@ hidpp20_onboard_profiles_write_profile(struct hidpp20_device *device,
|
|||||||
|
|
||||||
memcpy(pdata->profile.name.txt, profile->name, sizeof(profile->name));
|
memcpy(pdata->profile.name.txt, profile->name, sizeof(profile->name));
|
||||||
|
|
||||||
|
// Mice like G502X can store custom animations onboard.
|
||||||
|
// ratbag does not support this, so we set it to disable it to ensure
|
||||||
|
// that the actual lighting matches the user's settings.
|
||||||
|
if (device->quirks & HIDPP20_QUIRK_G502X_PLUS)
|
||||||
|
{
|
||||||
|
// Note(sewer56): There are two known mice which use this field;
|
||||||
|
// G502X PLUS and G705. [And I only own one of these.] But it's not known how
|
||||||
|
// prevalent this is elsewhere, so in the interest of defensive programming;
|
||||||
|
// we're not setting this on unknown mice.
|
||||||
|
pdata->profile.custom_animation_index = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
rc = hidpp20_onboard_profiles_write_sector(device, sector, sector_size, data, true);
|
rc = hidpp20_onboard_profiles_write_sector(device, sector, sector_size, data, true);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
hidpp_log_error(&device->base, "failed to write profile\n");
|
hidpp_log_error(&device->base, "failed to write profile\n");
|
||||||
|
|||||||
@@ -51,10 +51,13 @@ struct hidpp20_feature {
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Combinable flags so a device can have several at once (stored as a bitmask). */
|
||||||
enum hidpp20_quirk {
|
enum hidpp20_quirk {
|
||||||
HIDPP20_QUIRK_NONE,
|
HIDPP20_QUIRK_NONE = 0,
|
||||||
HIDPP20_QUIRK_G305,
|
HIDPP20_QUIRK_G305 = (1 << 0),
|
||||||
HIDPP20_QUIRK_G602,
|
HIDPP20_QUIRK_G602 = (1 << 1),
|
||||||
|
HIDPP20_QUIRK_G502X_PLUS = (1 << 2), // G502X+ uses 2nd LED slot instead of 1st.
|
||||||
|
HIDPP20_QUIRK_INDEX_OFFSET = (1 << 3), // Device returns 1-indexed profile, decrement by 1.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hidpp20_device {
|
struct hidpp20_device {
|
||||||
@@ -64,7 +67,7 @@ struct hidpp20_device {
|
|||||||
unsigned proto_minor;
|
unsigned proto_minor;
|
||||||
unsigned feature_count;
|
unsigned feature_count;
|
||||||
struct hidpp20_feature *feature_list;
|
struct hidpp20_feature *feature_list;
|
||||||
enum hidpp20_quirk quirk;
|
uint32_t quirks; /* bitmask of enum hidpp20_quirk */
|
||||||
unsigned int led_ext_caps;
|
unsigned int led_ext_caps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ enum driver {
|
|||||||
|
|
||||||
struct data_hidpp20 {
|
struct data_hidpp20 {
|
||||||
int index;
|
int index;
|
||||||
enum hidpp20_quirk quirk;
|
uint32_t quirks; /* bitmask of enum hidpp20_quirk */
|
||||||
int led_count;
|
int led_count;
|
||||||
int report_rate;
|
int report_rate;
|
||||||
int button_count;
|
int button_count;
|
||||||
@@ -100,12 +100,14 @@ struct data_steelseries {
|
|||||||
struct data_asus {
|
struct data_asus {
|
||||||
int profile_count;
|
int profile_count;
|
||||||
int button_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 led_count;
|
||||||
int dpi_count;
|
int dpi_count;
|
||||||
int is_wireless;
|
int is_wireless;
|
||||||
struct dpi_range *dpi_range;
|
struct dpi_range *dpi_range;
|
||||||
uint32_t quirks;
|
uint32_t quirks;
|
||||||
|
int led_modes[ASUS_MAX_NUM_LED_MODES];
|
||||||
|
char *omni_signature; /* serial number prefix of mice behind an Omni receiver */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ratbag_device_data {
|
struct ratbag_device_data {
|
||||||
@@ -175,6 +177,20 @@ init_data_hidpp10(struct ratbag *ratbag,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
hidpp20_quirk_from_string(const char *str)
|
||||||
|
{
|
||||||
|
if (streq(str, "G305"))
|
||||||
|
return HIDPP20_QUIRK_G305;
|
||||||
|
if (streq(str, "G602"))
|
||||||
|
return HIDPP20_QUIRK_G602;
|
||||||
|
if (streq(str, "G502X_PLUS"))
|
||||||
|
return HIDPP20_QUIRK_G502X_PLUS;
|
||||||
|
if (streq(str, "INDEX_OFFSET"))
|
||||||
|
return HIDPP20_QUIRK_INDEX_OFFSET;
|
||||||
|
return HIDPP20_QUIRK_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_data_hidpp20(struct ratbag *ratbag,
|
init_data_hidpp20(struct ratbag *ratbag,
|
||||||
GKeyFile *keyfile,
|
GKeyFile *keyfile,
|
||||||
@@ -183,7 +199,6 @@ init_data_hidpp20(struct ratbag *ratbag,
|
|||||||
const char *group = "Driver/hidpp20";
|
const char *group = "Driver/hidpp20";
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
int num;
|
int num;
|
||||||
char *str;
|
|
||||||
|
|
||||||
data->hidpp20.button_count = -1;
|
data->hidpp20.button_count = -1;
|
||||||
data->hidpp20.index = -1;
|
data->hidpp20.index = -1;
|
||||||
@@ -217,14 +232,13 @@ init_data_hidpp20(struct ratbag *ratbag,
|
|||||||
if (error)
|
if (error)
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
|
||||||
str = g_key_file_get_string(keyfile, group, "Quirk", NULL);
|
/* Quirks are a bitmask: "Quirk" takes a ;-separated list. */
|
||||||
data->hidpp20.quirk = HIDPP20_QUIRK_NONE;
|
data->hidpp20.quirks = HIDPP20_QUIRK_NONE;
|
||||||
if (str) {
|
|
||||||
if (streq(str, "G305"))
|
gsize quirks_count = 0;
|
||||||
data->hidpp20.quirk = HIDPP20_QUIRK_G305;
|
_cleanup_(g_strfreevp) char **quirks = g_key_file_get_string_list(keyfile, group, "Quirk", &quirks_count, NULL);
|
||||||
else if(streq(str, "G602"))
|
for (gsize i = 0; quirks && i < quirks_count; i++)
|
||||||
data->hidpp20.quirk = HIDPP20_QUIRK_G602;
|
data->hidpp20.quirks |= hidpp20_quirk_from_string(quirks[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -375,8 +389,10 @@ init_data_asus(struct ratbag *ratbag,
|
|||||||
data->asus.dpi_range = NULL;
|
data->asus.dpi_range = NULL;
|
||||||
data->asus.is_wireless = -1;
|
data->asus.is_wireless = -1;
|
||||||
data->asus.quirks = 0;
|
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;
|
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);
|
int profiles = g_key_file_get_integer(keyfile, group, "Profiles", &error);
|
||||||
if (!error && profiles >= 0)
|
if (!error && profiles >= 0)
|
||||||
@@ -388,11 +404,20 @@ init_data_asus(struct ratbag *ratbag,
|
|||||||
data->asus.button_count = buttons;
|
data->asus.button_count = buttons;
|
||||||
g_clear_error(&error);
|
g_clear_error(&error);
|
||||||
|
|
||||||
gsize button_mapping_count = 0;
|
gsize btn_map_count = 0;
|
||||||
_cleanup_(g_strfreevp) char **button_mapping = g_key_file_get_string_list(keyfile, group, "ButtonMapping", &button_mapping_count, &error);
|
_cleanup_(g_strfreevp) char **btn_map = g_key_file_get_string_list(keyfile, group, "ButtonMapping", &btn_map_count, &error);
|
||||||
if (!error && button_mapping) {
|
if (!error && btn_map) {
|
||||||
for (unsigned int i = 0; i < button_mapping_count; i++) {
|
for (unsigned int i = 0; i < btn_map_count; i++) {
|
||||||
data->asus.button_mapping[i] = strtoul(button_mapping[i], NULL, 16);
|
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);
|
g_clear_error(&error);
|
||||||
@@ -417,6 +442,9 @@ init_data_asus(struct ratbag *ratbag,
|
|||||||
data->asus.is_wireless = wireless;
|
data->asus.is_wireless = wireless;
|
||||||
g_clear_error(&error);
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
data->asus.omni_signature = g_key_file_get_string(keyfile, group, "OmniSignature", &error);
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
gsize quirks_count = 0;
|
gsize quirks_count = 0;
|
||||||
_cleanup_(g_strfreevp) char **quirks = g_key_file_get_string_list(keyfile, group, "Quirks", &quirks_count, &error);
|
_cleanup_(g_strfreevp) char **quirks = g_key_file_get_string_list(keyfile, group, "Quirks", &quirks_count, &error);
|
||||||
if (!error && quirks) {
|
if (!error && quirks) {
|
||||||
@@ -425,8 +453,39 @@ init_data_asus(struct ratbag *ratbag,
|
|||||||
data->asus.quirks |= ASUS_QUIRK_DOUBLE_DPI;
|
data->asus.quirks |= ASUS_QUIRK_DOUBLE_DPI;
|
||||||
} else if (streq(quirks[i], "STRIX_PROFILE")) {
|
} else if (streq(quirks[i], "STRIX_PROFILE")) {
|
||||||
data->asus.quirks |= ASUS_QUIRK_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 if (streq(quirks[i], "OMNI_RECEIVER")) {
|
||||||
|
data->asus.quirks |= ASUS_QUIRK_OMNI_RECEIVER;
|
||||||
|
} else if (streq(quirks[i], "LED_V2")) {
|
||||||
|
data->asus.quirks |= ASUS_QUIRK_LED_V2;
|
||||||
|
} else if (streq(quirks[i], "SETTINGS_V2")) {
|
||||||
|
data->asus.quirks |= ASUS_QUIRK_SETTINGS_V2;
|
||||||
} else {
|
} 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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -704,7 +763,79 @@ out:
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ratbag_device_data_omni_signature_match(struct ratbag *ratbag,
|
||||||
|
const char *signature,
|
||||||
|
struct input_id *id)
|
||||||
|
{
|
||||||
|
struct dirent **files;
|
||||||
|
const char *datadir;
|
||||||
|
int n, nfiles;
|
||||||
|
size_t best_len = 0;
|
||||||
|
int rc = -ENODEV;
|
||||||
|
|
||||||
|
datadir = getenv("LIBRATBAG_DATA_DIR");
|
||||||
|
if (!datadir)
|
||||||
|
datadir = LIBRATBAG_DATA_DIR;
|
||||||
|
|
||||||
|
n = scandir(datadir, &files, filter_device_files, alphasort);
|
||||||
|
if (n <= 0) {
|
||||||
|
log_error(ratbag, "Unable to locate device files in %s: %s\n",
|
||||||
|
datadir, n == 0 ? "No files found" : strerror(errno));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfiles = n;
|
||||||
|
while (n--) {
|
||||||
|
_cleanup_(g_key_file_freep) GKeyFile *keyfile = NULL;
|
||||||
|
_cleanup_(g_error_freep) GError *error = NULL;
|
||||||
|
_cleanup_(g_strfreevp) char **match_strv = NULL;
|
||||||
|
_cleanup_free_ char *omni_signature = NULL;
|
||||||
|
_cleanup_(freep) char *file = NULL;
|
||||||
|
size_t len;
|
||||||
|
unsigned int vendor, product;
|
||||||
|
|
||||||
|
if (xasprintf(&file, "%s/%s", datadir, files[n]->d_name) == -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
keyfile = g_key_file_new();
|
||||||
|
if (!g_key_file_load_from_file(keyfile, file, G_KEY_FILE_NONE, &error)) {
|
||||||
|
log_error(ratbag, "Failed to parse keyfile %s: %s\n",
|
||||||
|
file, error->message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
omni_signature = g_key_file_get_string(keyfile, "Driver/asus",
|
||||||
|
"OmniSignature", NULL);
|
||||||
|
if (!omni_signature)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = strlen(omni_signature);
|
||||||
|
if (len <= best_len || strncmp(signature, omni_signature, len) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
match_strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE,
|
||||||
|
"DeviceMatch", NULL, NULL);
|
||||||
|
if (!match_strv)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* the device must have a usb id to be resolvable */
|
||||||
|
if (sscanf(match_strv[0], "usb:%x:%x", &vendor, &product) != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
id->vendor = vendor;
|
||||||
|
id->product = product;
|
||||||
|
best_len = len;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
while (nfiles--)
|
||||||
|
free(files[nfiles]);
|
||||||
|
free(files);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
/* HID++ 1.0 */
|
/* HID++ 1.0 */
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -789,12 +920,12 @@ ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data
|
|||||||
return data->hidpp20.report_rate;
|
return data->hidpp20.report_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum hidpp20_quirk
|
uint32_t
|
||||||
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data)
|
ratbag_device_data_hidpp20_get_quirks(const struct ratbag_device_data *data)
|
||||||
{
|
{
|
||||||
assert(data->drivertype == HIDPP20);
|
assert(data->drivertype == HIDPP20);
|
||||||
|
|
||||||
return data->hidpp20.quirk;
|
return data->hidpp20.quirks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SinoWealth */
|
/* SinoWealth */
|
||||||
@@ -895,6 +1026,13 @@ ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data)
|
|||||||
return data->asus.led_count;
|
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
|
int
|
||||||
ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data)
|
ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data);
|
|||||||
int
|
int
|
||||||
ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data);
|
ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data);
|
||||||
|
|
||||||
enum hidpp20_quirk
|
uint32_t
|
||||||
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data);
|
ratbag_device_data_hidpp20_get_quirks(const struct ratbag_device_data *data);
|
||||||
|
|
||||||
/* SinoWealth */
|
/* SinoWealth */
|
||||||
|
|
||||||
@@ -140,6 +140,19 @@ ratbag_device_data_steelseries_get_quirk(const struct ratbag_device_data *data);
|
|||||||
|
|
||||||
/* ASUS */
|
/* ASUS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the usb id of the device whose OmniSignature matches the serial
|
||||||
|
* number of a mouse behind an Omni receiver. The longest matching prefix
|
||||||
|
* wins. The bustype of id is left untouched, only vendor and product are
|
||||||
|
* set.
|
||||||
|
*
|
||||||
|
* @return 0 on success or -ENODEV if no .device file matches
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ratbag_device_data_omni_signature_match(struct ratbag *ratbag,
|
||||||
|
const char *signature,
|
||||||
|
struct input_id *id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Number of profiles
|
* @return Number of profiles
|
||||||
*/
|
*/
|
||||||
@@ -164,6 +177,12 @@ ratbag_device_data_asus_get_button_mapping(const struct ratbag_device_data *data
|
|||||||
int
|
int
|
||||||
ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data);
|
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
|
* @return Number of DPI presets
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,12 +21,12 @@
|
|||||||
$1 = (unsigned int *) malloc(($2 + 1) * sizeof(unsigned int));
|
$1 = (unsigned int *) malloc(($2 + 1) * sizeof(unsigned int));
|
||||||
for (i = 0; i < $2; i++) {
|
for (i = 0; i < $2; i++) {
|
||||||
PyObject *s = PyList_GetItem($input, i);
|
PyObject *s = PyList_GetItem($input, i);
|
||||||
if (!PyInt_Check(s)) {
|
if (!PyLong_Check(s)) {
|
||||||
free($1);
|
free($1);
|
||||||
PyErr_SetString(PyExc_ValueError, "List items must be integers");
|
PyErr_SetString(PyExc_ValueError, "List items must be integers");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
$1[i] = PyInt_AsLong(s);
|
$1[i] = PyLong_AsLong(s);
|
||||||
}
|
}
|
||||||
$1[i] = 0;
|
$1[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
%typemap(argout) (unsigned int *resolutions, size_t nres) {
|
%typemap(argout) (unsigned int *resolutions, size_t nres) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < $2; i++) {
|
for (i = 0; i < $2; i++) {
|
||||||
PyList_SetItem($input, i, PyInt_FromLong($1[i]));
|
PyList_SetItem($input, i, PyLong_FromLong($1[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,24 +61,24 @@
|
|||||||
|
|
||||||
/* uintXX_t mapping: Python -> C */
|
/* uintXX_t mapping: Python -> C */
|
||||||
%typemap(in) uint8_t {
|
%typemap(in) uint8_t {
|
||||||
$1 = (uint8_t) PyInt_AsLong($input);
|
$1 = (uint8_t) PyLong_AsLong($input);
|
||||||
}
|
}
|
||||||
%typemap(in) uint16_t {
|
%typemap(in) uint16_t {
|
||||||
$1 = (uint16_t) PyInt_AsLong($input);
|
$1 = (uint16_t) PyLong_AsLong($input);
|
||||||
}
|
}
|
||||||
%typemap(in) uint32_t {
|
%typemap(in) uint32_t {
|
||||||
$1 = (uint32_t) PyInt_AsLong($input);
|
$1 = (uint32_t) PyLong_AsLong($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* uintXX_t mapping: C -> Python */
|
/* uintXX_t mapping: C -> Python */
|
||||||
%typemap(out) uint8_t {
|
%typemap(out) uint8_t {
|
||||||
$result = PyInt_FromLong((long) $1);
|
$result = PyLong_FromLong((long) $1);
|
||||||
}
|
}
|
||||||
%typemap(out) uint16_t {
|
%typemap(out) uint16_t {
|
||||||
$result = PyInt_FromLong((long) $1);
|
$result = PyLong_FromLong((long) $1);
|
||||||
}
|
}
|
||||||
%typemap(out) uint32_t {
|
%typemap(out) uint32_t {
|
||||||
$result = PyInt_FromLong((long) $1);
|
$result = PyLong_FromLong((long) $1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the header file to generate wrappers */
|
/* Parse the header file to generate wrappers */
|
||||||
|
|||||||
@@ -108,11 +108,14 @@ def check_profile_type_str(string: str):
|
|||||||
def check_section_asus(section: configparser.SectionProxy):
|
def check_section_asus(section: configparser.SectionProxy):
|
||||||
permitted_keys = (
|
permitted_keys = (
|
||||||
"ButtonMapping",
|
"ButtonMapping",
|
||||||
|
"ButtonMappingSecondary",
|
||||||
"Buttons",
|
"Buttons",
|
||||||
"DpiRange",
|
"DpiRange",
|
||||||
"Dpis",
|
"Dpis",
|
||||||
"Leds",
|
"Leds",
|
||||||
|
"LedModes",
|
||||||
"Profiles",
|
"Profiles",
|
||||||
|
"OmniSignature",
|
||||||
"Quirks",
|
"Quirks",
|
||||||
"Wireless",
|
"Wireless",
|
||||||
)
|
)
|
||||||
@@ -129,6 +132,13 @@ def check_section_asus(section: configparser.SectionProxy):
|
|||||||
quirks = (
|
quirks = (
|
||||||
"DOUBLE_DPI",
|
"DOUBLE_DPI",
|
||||||
"STRIX_PROFILE",
|
"STRIX_PROFILE",
|
||||||
|
"RAW_BRIGHTNESS",
|
||||||
|
"SEPARATE_XY_DPI",
|
||||||
|
"SEPARATE_LEDS",
|
||||||
|
"BUTTONS_SECONDARY",
|
||||||
|
"OMNI_RECEIVER",
|
||||||
|
"LED_V2",
|
||||||
|
"SETTINGS_V2",
|
||||||
)
|
)
|
||||||
for quirk in section["Quirks"].split(";"):
|
for quirk in section["Quirks"].split(";"):
|
||||||
assert quirk in quirks
|
assert quirk in quirks
|
||||||
@@ -136,6 +146,18 @@ def check_section_asus(section: configparser.SectionProxy):
|
|||||||
# No such section - not an error.
|
# No such section - not an error.
|
||||||
pass
|
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):
|
def check_section_hidpp10(section: configparser.SectionProxy):
|
||||||
permitted = [
|
permitted = [
|
||||||
|
|||||||
Reference in New Issue
Block a user