Compare commits

..

94 Commits
v0.13 ... v0.16

Author SHA1 Message Date
Filipe Laíns
952bd9dc07 libratbag 0.16
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-06-24 15:11:34 +01:00
staticssleever668
6b97d94a2f sinowealth: print out firmware version when probing 2021-06-23 15:40:38 +00:00
Thomas Weißschuh
ccaa8d1b6c ratbagd: register task to run as soon as possible
Previously the scheduled task would only have been executed after some
other event woke up the mainloop.
If no such event happens, the task will be delayed significantly.

Fixes #1121
2021-06-21 22:47:42 +01:00
Elián Hanisch
abe451df33 sinowealth-nubwo: fix implicit declaration of function ‘vasprintf’
driver-sinowealth-nubwo.c was missing to include "config.h" so
_GNU_SOURCE wasn't defined soon enough.

Co-authored-by: Elián Hanisch <elian.hanisch@ing.unlp.edu.ar>
2021-04-29 01:38:03 +01:00
Sethox
a3fa876c3d data: add SEL variant to Roccat Kone Pure
The last part added is for a variant called "Roccat Kone Pure SEL".

PR #1152
2021-04-21 03:45:25 +01:00
Filipe Laíns
230647c7f3 openinput: fail probe if we can't enumerate
These functions are mandatory[1], fail to probe if they fail.

[1] https://github.com/openinput-fw/openinput-protocol/tree/master/specification/device-protocol#mandatory-functions

Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-04-04 15:08:21 +01:00
Filipe Laíns
3f99446a1b ci: temporarily disable arch
See my description of the problem in [1].
Essentially, docker is mishandling the failuire when a syscall is not
available, returning EPERM instead of ENOSYS, and making code misbehave.
The current issue with arch is glibc, which explodes on EPERM, causing
pacman to misbehave.

Once the fix hits CircleCI, we will re-enable.

[1] https://github.com/fwupd/fwupd/issues/2894

Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-03-01 10:34:10 +10:00
Filip Laurentiu
a766f8e909 data: add new identifier for DeviceMatch to match MX Anywhere2 mouse
PR #1137
2021-02-28 19:02:52 +00:00
Pavel Kovar
9ae975f9a9 data: add support for Logitech M500s mouse 2021-02-17 17:53:27 +00:00
Filipe Laíns
780934b1a1 data: add openinput device
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
337fb935c4 openinput: refactor function discovery
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
c9cf5fe90c openinput: add function discovery
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
18af0f97d2 openinput: print device protocol name
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
286f13c654 openinput: read firmware information
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
c6b9cc0c2a openinput: add error support
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
7d82bb51a6 openinput: save protocol version
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
8976033da7 openinput: add openinput_send_report
Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
Filipe Laíns
c9c6a1675f openinput: add barebones driver
This is the minimal code required to have a working driver, now we just
need a .device file.

Note the hardcoding of `profile->is_active = true` in
openinput_read_profile, this works because we just have one profile.

Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-02-16 00:15:59 +00:00
the Weld
f1e2a4ccff data: add extra USB device ID for MX Vertical
Fixes #1132, for my own model of MX Vertical at the least.
2021-02-15 20:00:34 +00:00
Filipe Laíns
104543fdf1 data: add G Pro X Wireless Superlight
Support for this receiver, and for the device using the powerplay
receiver, still needs to be added to the kernel driver. For now, you can
used the wired connection to configure the device.

You should also not try to use with the powerplay receiver as the kernel
driver does not support the connection and won't forward any input
events to userspace.

Signed-off-by: Filipe Laíns <lains@riseup.net>
2021-01-30 10:59:37 +00:00
Matt
b3275e10d7 data: add Logitech M545 2020-12-30 17:43:52 +00:00
Filipe Laíns
120908bda8 data: add G915 TKL
Closes #1008

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-10-22 20:20:04 +01:00
Filipe Laíns
32d6443553 data: add an ID to the MX Anywhere 2
Fixes #1078

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-10-17 18:22:54 +01:00
Calvin Walton
ae943eaee7 data: Add configuration for SteelSeries Kinzu V2 Pro Edition
Appears to be basically the same as the V2 - the differences were
mostly in hardware (upgraded switches & image sensor). I've verified
that the list of DPI settings is correct and matches the Windows
software. Adjusting DPI config in both profiles works correctly.
2020-10-15 01:50:44 +01:00
Calvin Walton
4a9503f2da data: add device IDs for Logitech MX Anywhere 3 2020-10-14 21:57:19 +01:00
Filipe Laíns
e268100d31 libratbag-data: log message if the device is a Logitech receiver
We have been receiving countless issues and PRs reporting or "fixing"
the device IDs because they think it's wrong. Hopefully this will give
them an hint that is intended behavior. If they look closely at the log,
on a recent enough kernel, they should see their device show up with the
internal ID.

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-10-09 17:37:44 +01:00
Filipe Laíns
8ec0e8bbc5 Revert "meson: bump required meson version"
This reverts commit e753db72f9.

The new version is too recent for lgtm.com.
See https://lgtm.com/projects/g/libratbag/libratbag/logs/rev/pr-c8dd47f8b4d0c40fc0a27b13e031bbb8e6c76987/lang:cpp/stage:Build%20merge_7b2f50275451a899db1bf70b6eaae9d88ecc56d0

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-10-08 01:46:03 +01:00
bluemner
e6a9fba498 Update add support for G-Shift keys on g600 2020-10-05 00:44:27 +01:00
Thomas H.P. Andersen
e753db72f9 meson: bump required meson version
Bump the required meson version to match the features that we make
use of.

We now also make use of the 'copy:' keyword in configure_file that
is available in version 0.47.
2020-10-05 00:39:43 +01:00
Thomas H.P. Andersen
e1f4fac9a2 ratbagd-json: fix compilation with clang
Compilation on clang failed as we would try to jump to
the 'out' label and then jump over the initialization
of a variable with __attribute__((cleanup)).

We move the initaliztion up to make sure it happens before
the goto.
2020-09-29 02:11:09 +01:00
Thomas H.P. Andersen
8f981c8b87 circleci: bump to fedora 32
Bump to fedora 32 to updated meson version
2020-09-29 02:08:17 +01:00
Thomas H.P. Andersen
01d2cf8477 sinowealth: silence warning 2020-09-29 01:07:12 +02:00
Filipe Laíns
f7c22ed88c libratbag 0.15
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-09-25 21:38:01 +01:00
Thomas H.P. Andersen
aeda65cbfa sinowealth: remove per-resolution led
The glorious mice uses a single profile. To differentiate between
resolutions each one has customizable color. A led on the bottom
of the mouse shows the active resolution color.

Libratbag does not support a per-resolution color.

To allow adjusting these colors the sinowealth driver defines a led
for each resolution. This is a misuse of the model and will cause
problems when the mouse is added to Piper.

This patch removes the per-resolution leds and hardcodes the led
count to one.
2020-09-25 20:51:45 +01:00
Pipat Saengow
ed2439e5e2 sinowealthnubwo: more reasonable default and refactor 2020-09-21 17:39:28 +02:00
Pipat Saengow
f407521e8f Add driver for Nubwo X7 Spectrum
Nubwo X7 Spectrum is a sinowealth-based gaming mouse.
The sinowealth-nubwo driver included in this commit provides

- LED support (except color mode that are not available in libratbag)
- DPI and reporting support
- NO button mapping/macros support
2020-09-21 17:39:28 +02:00
heimer16
3c4fe23f70 data: update Logitech g9x (#913)
* add LED for Logitech g9x
* update min dpi range and step for Logitech g9x

Co-authored-by: Erin Heimer <heimer16@gmail.com>
2020-09-11 22:28:57 +02:00
Mike Crowe
9e2ac55dbc libratbag-private.h: Ensure that _GNU_SOURCE is defined early enough
When compiling on Ubuntu 20.04 with GCC 9.3.0 and glibc 2.31, I get:

In file included from ../src/libratbag-private.h:32,
                 from ../src/driver-sinowealth.c:24:
../src/libratbag-util.h: In function ‘asprintf_safe’:
../src/libratbag-util.h:154:7: warning: implicit declaration of function ‘vasprintf’; did you mean ‘vsprintf’? [-Wimplicit-function-declaration]
  154 |  rc = vasprintf(&result, fmt, args);
      |       ^~~~~~~~~
      |       vsprintf

This appears to be because <features.h> is being included by another
header before config.h has been included. If _GNU_SOURCE has not been
defined at that point, then the other macros that control whether
vasprintf is declared are not set correctly.

Include config.h right at the top of libratbag-private.h to ensure
that _GNU_SOURCE is defined before any system headers are included to
avoid this problem.
2020-08-30 19:16:51 +02:00
Nguyễn Chính Hữu
1e72ebaa7b data: add the G203 name to the .device file 2020-08-29 22:23:35 +01:00
peelz
920bc2b993 driver-hidpp10: fix segfault when committing unnamed profiles 2020-08-23 16:21:05 +01:00
TurkeyTheGobbler
20b573668e g300: use the correct step size 2020-07-25 17:26:37 +01:00
Daniel Lehmann
49acc11db3 Fix enumeration of Logitech G5 (2007)
Before this patch, ratbagd would abort initialization of the device because
no profiles are returned.

Once that was handled more gracefully, ratbagd would fail because it doesn't
read the DpiList from its own config file, as no ProfileType is specified.
Specifying G500 as the closest match.
2020-07-23 01:04:14 +01:00
Stephan Lachnit
364e3fd965 data: add additional USB-ID for the M720 Thriatlon
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-07-23 01:00:33 +01:00
Marian Beermann
bb230d390d sinowealth: fix reading RGB brightness from device 2020-07-23 00:45:29 +01:00
Marian Beermann
93a076bed9 sinowealth: code style changes 2020-07-23 00:45:29 +01:00
Marian Beermann
e7b50c9061 sinowealth: rewrite RGB LED mode conversions 2020-07-23 00:45:29 +01:00
Marian Beermann
9d533bdc3e sinowealth: fix dpi_count not being updated
The firmware of these mice only considers the first dpi_count zero bits
in dpi_enabled.
2020-07-23 00:45:29 +01:00
Marian Beermann
d7906b54b4 sinowealth: code cleanup and style changes 2020-07-23 00:45:29 +01:00
Marian Beermann
f1eba370ed sinowealth: do not typedef structs 2020-07-23 00:45:29 +01:00
Marian Beermann
7b5ab2ed99 sinowealth: separate capability setting logic from read_profile 2020-07-23 00:45:29 +01:00
Marian Beermann
d2d5471836 sinowealth: implement brightness and speed controls 2020-07-23 00:45:29 +01:00
Marian Beermann
9cfc1e98e3 sinowealth: fixed rgb
Turns out it was caused by two mistakes:
1.) While writing the struct I overlooked a changed offset in my notes,
    so a bunch of padding was missing in the middle of the struct (unk4[33]);
    that padding is probably the set of colors (11) used by tail mode
2.) The LED bodies actually use RBG ordering instead of RGB
2020-07-23 00:45:29 +01:00
Marian Beermann
691661276f pad struct sinowealth_config_report to full size of report 2020-07-23 00:45:29 +01:00
Marian Beermann
25ed99db84 Add sinowealth driver 2020-07-23 00:45:29 +01:00
Dejan
02226d0428 data: add another device ID for G203 mouse 2020-07-09 21:54:56 +01:00
Stephan Lachnit
f822fb0fa7 remove unused string format to fix flake8 (#1024)
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-07-06 11:48:47 +02:00
Stephan Lachnit
b88be0add0 ci: bump Ubuntu to 20.04
This also removes the manual addition of the universe repository, since it's already enabled in the circleci image.
Because of this, software-properties-common doesn't need to be installed anymore, and libnss-systemd isn't going to be installed (see c425780220).
However, DEBIAN_FRONTEND=noninteractive needs to be set, else the image will loop while trying to configure tzdata (aka the timezome).

Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-06-09 10:55:31 +10:00
Stephan Lachnit
9fc6d12486 data: add additional USB-ID for Roccat Kone Pure
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-06-07 20:58:41 +02:00
Stephan Lachnit
0c64dad9e1 fix wrong driver id for Roccat Kone Pure
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-06-07 20:58:41 +02:00
Farid Gh
f61485c603 data: add bluetooth ID to the MX Vertical 2020-05-29 13:57:21 +01:00
Filipe Laíns
8c295479d8 hidpp20: keep unsupported button mappings
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-05-25 18:08:40 +01:00
Dylan Baker
e55b04ec7d meson: Fix python3 version detection with python3 module
I misread the documentation about the python3 module. The newer python
module puts the language_version in the object returned by
`pymod.find_installation()`, while the python3 module has the same
method in the *module*.

Fixes #985
2020-05-19 19:47:24 +01:00
Filipe Laíns
1231415470 libratbag 0.14
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-05-17 21:23:57 +01:00
Filipe Laíns
660da27021 data: add Logitech G935
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-05-17 21:19:32 +01:00
Dylan Baker
481b6f029a meson: make finding python more robust
This code assumes that there is a python3 or python3-embed pkg-config
file on the system, which may or may not be true. On Gentoo for example,
only python-X.Y pkg-config files are available and this will fail to
build.

This makes use of the new py_installation.dependency(embed : true) if
possible, and falls back to trying to find a python that matches the
version of python found by the python3 or python module.
2020-05-17 19:19:42 +01:00
Filipe Laíns
768d93a45a github: add device info to bug report template
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-29 14:23:47 +01:00
ksv1986
1c6e039d01 hidpp10: fix handling of hidpp10_device_new() failures
Signed-off-by: ksv1986 <ksv0x07c2@gmail.com>
2020-04-26 15:07:23 +01:00
ksv1986
d16df8d100 hidpp10: fix crash if device failed to initialize properly
Signed-off-by: ksv1986 <ksv0x07c2@gmail.com>
2020-04-26 15:07:23 +01:00
Filipe Laíns
4b1e49d522 hidpp20: fix report type in ColorLedEffects (0x8070) set_zone_effect
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-26 15:07:06 +01:00
Filipe Laíns
786cebcb0b hidpp20: cleanup, use short reports when possible
libratbag has a quite communication-intensive setup routine. This patch
uses short reports when possible. Using short reports will speed up the
setup process and have a lower power consumption, which is relevant for
wireless devices.

We now check the report descriptor for the supported report IDs and
adjust the report type used based on the device capabilities. Because of
that, this patch should work without any issues as the report type will
get overwritten if it not supported.

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-26 15:07:06 +01:00
Filipe Laíns
d53454bcb3 hidpp10: fix circular loop on hidpp10_onboard_profiles_read_macro
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-26 15:06:25 +01:00
Filipe Laíns
a0def65b64 hidpp10: add debug log on hidpp10_onboard_profiles_parse_macro fail
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-26 15:06:25 +01:00
Stephan Lachnit
2a40279903 doc: replace some tabs with spaces
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-04-26 15:06:08 +01:00
Filipe Laíns
02c95422f0 hidpp20: fix mapping button to consumer usages
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-18 02:31:17 +01:00
Filipe Laíns
4ce1cf2807 hidpp10: convert key actions to macro
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-18 02:31:17 +01:00
Filipe Laíns
89168f2187 hidpp10: add support from writting simple macro actions
Fixes #900

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-18 02:31:17 +01:00
Filipe Laíns
bb92337268 ci: remove dbus policy dir hack in arch
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-18 02:29:05 +01:00
Filipe Laíns
a8316c07f3 ratbagd: create path if not present before installing dbus policy dir
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-18 02:29:05 +01:00
Filipe Laíns
39769c57dd ci: save cache between jobs for fedora and arch
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-17 05:57:38 +01:00
Filipe Laíns
200a8af7a7 ci: cache packages in arch
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-17 05:57:38 +01:00
FFY00
fcf9f7745d ci: add arch
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-17 05:57:38 +01:00
Filipe Laíns
633c9fc55d libratbag-data: add missing header entry (#958)
Dicovered in #957

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-16 15:59:50 +02:00
Peter Hutterer
ee73434ead circleci: bump to use ubuntu 19.10
The 19.04 repos give us 404s, so let's update to the next version.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-04-16 08:01:53 +10:00
Filipe Laíns
d60b1c9d71 data: overwrite led count in G305
Fixes #949

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-14 19:00:12 +01:00
Filipe Laíns
88a60f55b4 hidpp20: allow overwritting the led count
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-14 19:00:12 +01:00
D33M0N
dba202ae8b data: added bluetooth ID to the MX Anywhere 2 2020-04-03 19:27:02 +01:00
Filipe Laíns
6cdcce9de4 hidpp20: log error number when commiting
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-03 17:02:44 +02:00
Filipe Laíns
e2c3373145 hidpp10: log errors when comitting
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-04-03 17:02:44 +02:00
Filipe Laíns
02575a9008 hidpp20: add button/macro opcodes
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-22 19:17:47 +00:00
Filipe Laíns
1097b1ba68 meson: silence swig warnings
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-22 19:13:58 +00:00
Filipe Laíns
77b67775da ratbagctl: don't print empty properties
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-22 19:08:58 +00:00
Filipe Laíns
5b23c9ebae data: add Logitech M720
Fixes #939

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-22 18:58:07 +00:00
Stephan Lachnit
6d0974be25 circleci: add diffutils dependency for fedora
Signed-off-by: Stephan Lachnit <stephanlachnit@protonmail.com>
2020-02-21 15:21:42 +01:00
simrat39
ea9111a2a6 devices: Set g402 LedTypes
Signed-off-by: simrat39 <simrats169169@gmail.com>
2020-02-10 15:49:45 +00:00
49 changed files with 1792 additions and 159 deletions

View File

@@ -1,10 +1,12 @@
libratbag_references:
build_dependencies: &build_dependencies
FEDORA_DEP_BUILD: gcc gcc-c++ meson dbus-daemon glib2-devel json-glib-devel libevdev-devel libudev-devel libunistring-devel python3-devel python3-evdev swig
FEDORA_DEP_TEST: check-devel python3-gobject python3-lxml valgrind
FEDORA_DEP_TEST: check-devel python3-gobject python3-lxml valgrind diffutils
FEDORA_DEP_DOC: python3-sphinx python3-sphinx_rtd_theme
UBUNTU_DEP_BUILD: gcc g++ meson pkg-config systemd libevdev-dev libglib2.0-dev libjson-glib-dev libsystemd-dev libudev-dev libunistring-dev python3-dev python3-evdev swig
UBUNTU_DEP_TEST: check python3-gi python3-lxml valgrind
ARCH_DEP_BUILD: meson swig glib2 libevdev libudev.so libunistring json-glib python python-evdev python-gobject
ARCH_DEP_TEST: check valgrind python-lxml
default_settings: &default_settings
working_directory: ~/libratbag
environment:
@@ -75,22 +77,21 @@ libratbag_references:
mkdir /run/dbus
/usr/bin/dbus-daemon --system --fork
fedora_prep_cache: &fedora_prep_cache
<<: *default_settings
steps:
- run:
name: Initializing Fedora dnf cache
command: dnf install -y --downloadonly git ${FEDORA_DEP_BUILD} ${FEDORA_DEP_TEST} ${FEDORA_DEP_DOC}
- persist_to_workspace:
root: /var/cache/
paths:
- dnf/*
environment:
*build_dependencies
save_date: &save_date
run:
name: Save date
command: date +%F > /tmp/date
fedora_save_cache: &fedora_save_cache
save_cache:
key: fedora-cache-v1-{{ checksum "/tmp/date" }}
paths:
- /var/cache/dnf
fedora_fetch_cache: &fedora_fetch_cache
attach_workspace:
at: /var/cache/
restore_cache:
keys:
- fedora-cache-v1
fedora_install: &fedora_install
run:
@@ -103,6 +104,7 @@ fedora_install: &fedora_install
fedora_settings: &fedora_settings
<<: *default_settings
steps:
- *save_date
- *fedora_fetch_cache
- *fedora_install
- checkout
@@ -114,6 +116,37 @@ fedora_settings: &fedora_settings
- *build_buildtype_plain
- *build_buildtype_release
- *export_logs
- *fedora_save_cache
environment:
*build_dependencies
arch_save_cache: &arch_save_cache
save_cache:
key: arch-cache-v1-{{ checksum "/tmp/date" }}
paths:
- /var/cache/pacman/pkg
arch_fetch_cache: &arch_fetch_cache
restore_cache:
keys:
- arch-cache-v1
arch_settings: &arch_settings
<<: *default_settings
steps:
- *save_date
- *arch_fetch_cache
- run:
name: Install prerequisites
command: pacman -Syu --noconfirm --noprogressbar --needed base-devel git tree ${ARCH_DEP_BUILD} ${ARCH_DEP_TEST}
- *start_dbus
- checkout
- *build_and_test
- *install
- *check_install
- *check_uninstall
- *export_logs
- *arch_save_cache
environment:
*build_dependencies
@@ -123,10 +156,7 @@ ubuntu_settings: &ubuntu_settings
- run:
name: Install prerequisites
command: |
apt-get update
apt-get install -y software-properties-common
apt-get remove -y libnss-systemd
add-apt-repository universe
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y git ${UBUNTU_DEP_BUILD} ${UBUNTU_DEP_TEST}
- checkout
@@ -201,43 +231,38 @@ docs_deploy: &docs_deploy
version: 2
jobs:
fedora_cache:
<<: *fedora_prep_cache
docker:
- image: fedora:31
fedora_31:
fedora_32:
<<: *fedora_settings
docker:
- image: fedora:31
ubuntu_19_04:
- image: fedora:32
arch:
<<: *arch_settings
docker:
- image: archlinux
ubuntu_20_04:
<<: *ubuntu_settings
docker:
- image: ubuntu:19.04
- image: ubuntu:20.04
doc_build:
<<: *doc_build
docker:
- image: fedora:31
- image: fedora:32
doc_deploy:
<<: *docs_deploy
docker:
- image: fedora:31
- image: fedora:32
workflows:
version: 2
compile_and_test:
jobs:
- fedora_cache
- ubuntu_19_04
- fedora_31:
requires:
- fedora_cache
- doc_build:
requires:
- fedora_cache
- ubuntu_20_04
# - arch
- fedora_32
- doc_build
- doc_deploy:
requires:
- fedora_cache
- doc_build
filters:
branches:

View File

@@ -13,6 +13,12 @@ assignees: ''
- Distribution:
- Kernel version (ex. `uname -srmo`): `KERNEL VERSION HERE`
Device info (if applicable):
```
$ ratbagctl <device> info
OUTPUT HERE
```
**Describe the bug**
A clear and concise description of what the bug is.

View File

@@ -168,7 +168,7 @@ def check_section_hidpp10(section):
def check_section_hidpp20(section):
permitted = ['DeviceIndex', 'Quirk']
permitted = ['DeviceIndex', 'Leds', 'Quirk']
for key in section.keys():
assertIn(key, permitted)

View File

@@ -0,0 +1,5 @@
[Device]
Name=Glorious Model D
DeviceMatch=usb:258a:0033
Driver=sinowealth

View File

@@ -0,0 +1,5 @@
[Device]
Name=Glorious Model O
DeviceMatch=usb:258a:0036
Driver=sinowealth

View File

@@ -0,0 +1,5 @@
# Logitech M500s
[Device]
Name=Logitech M500s
DeviceMatch=usb:046d:c093
Driver=hidpp20

View File

@@ -0,0 +1,5 @@
# Logitech M545
[Device]
Name=Logitech M545
DeviceMatch=usb:046d:4052
Driver=hidpp20

View File

@@ -0,0 +1,4 @@
[Device]
Name=Logitech M720
DeviceMatch=usb:046d:405e;bluetooth:046d:b015
Driver=hidpp20

View File

@@ -0,0 +1,5 @@
# Logitech MX Anywhere 3
[Device]
Name=Logitech MX Anywhere 3
DeviceMatch=bluetooth:046d:b025;usb:046d:4090
Driver=hidpp20

View File

@@ -1,4 +1,4 @@
[Device]
Name=Logitech MX Anywhere 2
DeviceMatch=usb:046d:404a;bluetooth:046d:b013;bluetooth:046d:b018
DeviceMatch=usb:046d:404a;usb:046d:4072;usb:046d:4063;bluetooth:046d:b013;bluetooth:046d:b018;bluetooth:046d:b01f
Driver=hidpp20

View File

@@ -1,4 +1,4 @@
[Device]
Name=Logitech MX Vertical
DeviceMatch=usb:046d:407b
DeviceMatch=bluetooth:046d:b020;usb:046d:407b;usb:046d:c08a
Driver=hidpp20

View File

@@ -0,0 +1,5 @@
[Device]
Name=Logitech G Pro X Wireless Superlight
DeviceMatch=usb:046d:4093;usb:046d:c094
LedTypes=logo;battery;dpi;
Driver=hidpp20

View File

@@ -1,6 +1,6 @@
# G102 and G203 (USB)
# G102, G103 and G203 (USB)
[Device]
Name=Logitech Gaming Mouse G102/G103
DeviceMatch=usb:046d:c084
Name=Logitech Gaming Mouse G102/G103/G203
DeviceMatch=usb:046d:c084;usb:046d:c092
Driver=hidpp20
LedTypes=logo;side;

View File

@@ -4,4 +4,5 @@ DeviceMatch=usb:046d:4074
Driver=hidpp20
[Driver/hidpp20]
Leds=0
Quirk=G305

View File

@@ -2,4 +2,5 @@
[Device]
Name=Logitech G402 Gaming Mouse
DeviceMatch=usb:046d:c07e
LedTypes=logo
Driver=hidpp20

View File

@@ -7,3 +7,4 @@ Driver=hidpp10
[Driver/hidpp10]
DpiList=400;800;1600;2000
Profiles=1
ProfileType=G500

View File

@@ -0,0 +1,8 @@
[Device]
Name=Logitech G915 TKL
DeviceMatch=usb:046d:c343;bluetooth:046d:b35f
LedTypes=logo;switches
Driver=hidpp20
[Driver/hidpp20]
DeviceIndex=1

View File

@@ -0,0 +1,5 @@
[Device]
Name=Logitech G935
DeviceMatch=usb:046d:0a87
LedTypes=logo;side
Driver=hidpp20

View File

@@ -4,8 +4,10 @@
Name=G9x [Original]
DeviceMatch=usb:046d:c066
Driver=hidpp10
LedTypes=dpi
[Driver/hidpp10]
DpiRange=0:5700@23.53
DpiRange=200:5700@50
ProfileType=G500
Profiles=5
Leds=1

View File

@@ -0,0 +1,5 @@
[Device]
Name=Nubwo x7 spectrum
DeviceMatch=usb:258a:0012
Driver=sinowealth_nubwo

View File

@@ -0,0 +1,4 @@
[Device]
Name=openinput
DeviceMatch=usb:1d50:616a
Driver=openinput

View File

@@ -1,4 +1,4 @@
[Device]
Name=Roccat Kone Pure
DeviceMatch=usb:1e7d:2dc2
DeviceMatch=usb:1e7d:2dc2;usb:1e7d:2dbe;usb:1e7d:2dcb
Driver=roccat-kone-pure

View File

@@ -0,0 +1,11 @@
[Device]
Name=SteelSeries Kinzu V2 Pro Edition
DeviceMatch=usb:1038:1366
Driver=steelseries
[Driver/steelseries]
DeviceVersion=1
Buttons=3
Leds=0
DpiList=400;800;1600;3200
MacroLength=0

View File

@@ -85,13 +85,13 @@ interact with ratbagd.
:type: i
:flags: read-only,constant
The DBus API version. This is a stopgap feature while the DBus API
is still in flux. The version has no backwards or
forward-compatibilty guarantees - your client must understand
**exactly** the same version, it is not enough to support an older
or a newer version.
The DBus API version. This is a stopgap feature while the DBus API
is still in flux. The version has no backwards or
forward-compatibilty guarantees - your client must understand
**exactly** the same version, it is not enough to support an older
or a newer version.
This API will be removed once the DBus API is declared stable.
This API will be removed once the DBus API is declared stable.
.. attribute:: Devices

View File

@@ -1,5 +1,5 @@
project('libratbag', 'c',
version : '0.13',
version : '0.16',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.40.0')
@@ -174,7 +174,10 @@ src_libratbag = [
'src/driver-roccat.c',
'src/driver-roccat-kone-pure.c',
'src/driver-gskill.c',
'src/driver-openinput.c',
'src/driver-steelseries.c',
'src/driver-sinowealth.c',
'src/driver-sinowealth-nubwo.c',
'src/driver-test.c',
'src/libratbag.c',
'src/libratbag.h',
@@ -281,9 +284,12 @@ data_files = files(
'data/devices/etekcity-scroll-alpha.device',
'data/devices/gskill-MX-780.device',
'data/devices/logitech-M325.device',
'data/devices/logitech-M500s.device',
'data/devices/logitech-M545.device',
'data/devices/logitech-M570.device',
'data/devices/logitech-M585-M590.device',
'data/devices/logitech-M705.device',
'data/devices/logitech-M720.device',
'data/devices/logitech-MX-Ergo.device',
'data/devices/logitech-MX-Master.device',
'data/devices/logitech-MX-Master-2S.device',
@@ -293,6 +299,7 @@ data_files = files(
'data/devices/logitech-Wireless-Touchpad.device',
'data/devices/logitech-g-powerplay.device',
'data/devices/logitech-g-pro-wireless.device',
'data/devices/logitech-g-pro-x-wireless-superlight.device',
'data/devices/logitech-g-pro.device',
'data/devices/logitech-g102-g203.device',
'data/devices/logitech-g300.device',
@@ -329,21 +336,29 @@ data_files = files(
'data/devices/logitech-g815.device',
'data/devices/logitech-g910.device',
'data/devices/logitech-g915.device',
'data/devices/logitech-g915-tkl.device',
'data/devices/logitech-g935.device',
'data/devices/logitech-g9x-Call-of-Duty-MW3-Edition.device',
'data/devices/logitech-g9x-Original.device',
'data/devices/logitech-Marathon-M705.device',
'data/devices/logitech-MX-Anywhere2.device',
'data/devices/logitech-MX-Anywhere2S.device',
'data/devices/logitech-MX-Anywhere-3.device',
'data/devices/logitech-MX-Vertical.device',
'data/devices/openinput.device',
'data/devices/roccat-kone-pure.device',
'data/devices/roccat-kone-xtd.device',
'data/devices/steelseries-kinzu-v2.device',
'data/devices/steelseries-kinzu-v2-pro.device',
'data/devices/steelseries-kinzu-v3.device',
'data/devices/steelseries-rival-310.device',
'data/devices/steelseries-rival-600.device',
'data/devices/steelseries-rival.device',
'data/devices/steelseries-sensei-310.device',
'data/devices/steelseries-sensei-raw.device',
'data/devices/glorious-model-d.device',
'data/devices/glorious-model-o.device',
'data/devices/nubwo-x7-spectrum.device',
)
install_data(data_files,
@@ -537,12 +552,29 @@ configure_file(input : 'dbus/org.freedesktop.ratbag1.conf.in',
#### tools ####
# This is a special idiomatic construct in meson to get a fast dependency that
# doesn't exist and isn't logged as "not found".
dep_python3 = dependency('', required : false)
if meson.version().version_compare('<0.48.0')
python = import('python3')
py3 = python.find_python()
py_version = python.language_version()
else
pymod = import('python')
py3 = pymod.find_installation()
if meson.version().version_compare('>= 0.53.0')
dep_python3 = py3.dependency(embed : true)
endif
py_version = py3.language_version()
endif
# From python 3.8 we neeed python3-embed
embed = py_version.version_compare('>= 3.8') ? '-embed' : ''
if not dep_python3.found()
dep_python3 = dependency('python-@0@@1@'.format(py_version, embed), required : false)
if not dep_python3.found()
dep_python3 = dependency('python3@0@'.format(embed))
endif
endif
config_ratbagctl = configuration_data()
@@ -606,12 +638,6 @@ swig_gen = generator(
'@INPUT@'],
)
# From python 3.8 we neeed python3-embed
dep_python3 = dependency('python3-embed', required: false)
if not dep_python3.found()
dep_python3 = dependency('python3')
endif
wrapper_deps = [
dep_python3,
dep_libratbag,
@@ -624,7 +650,9 @@ shared_library(
'libratbag',
c_source,
name_prefix: '_',
c_args : ['-Wno-missing-prototypes', '-Wno-format-nonliteral'],
c_args : ['-Wno-missing-prototypes',
'-Wno-format-nonliteral',
'-Wno-missing-field-initializers'],
extra_files: [ i_source ] + src_libratbag ,
dependencies: deps_libratbag + wrapper_deps,
include_directories : include_directories('src', 'tools'),
@@ -637,7 +665,10 @@ shared_library(
'hidpp',
c_source,
name_prefix: '_',
c_args : ['-Wno-missing-prototypes', '-Wno-format-nonliteral'],
c_args : ['-Wno-missing-prototypes',
'-Wno-format-nonliteral',
'-Wno-missing-field-initializers',
'-Wno-strict-prototypes'],
extra_files: [ i_source ] + src_libratbag ,
dependencies: deps_libratbag + wrapper_deps,
include_directories : include_directories('src', 'tools'),

View File

@@ -515,6 +515,7 @@ int ratbagd_parse_json(const char *data, struct ratbag_test_device *device)
JsonArray *arr;
int r = -EINVAL;
g_autoptr(GError) error = NULL;
g_autoptr(GList) list = NULL;
error = 0;
parser = json_parser_new();
@@ -540,7 +541,7 @@ int ratbagd_parse_json(const char *data, struct ratbag_test_device *device)
num_buttons = device->num_buttons;
num_leds = device->num_leds;
g_autoptr(GList) list = json_array_get_elements(arr);
list = json_array_get_elements(arr);
GList *l = list;
int idx = 0;
while (l != NULL) {

View File

@@ -29,6 +29,7 @@
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <libratbag.h>
#include <libudev.h>
#include <stdio.h>
@@ -547,6 +548,13 @@ static bool install_ratbagd_devel_dbus_policy(void)
log_error("Failed to source policy file: %m\n");
goto out;
}
if (mkdir_p(dirname(strdupa(DBUS_POLICY_DST)), 0755)) {
log_error("Failed to create destination path: %m\n");
goto out;
}
out = open(DBUS_POLICY_DST, O_CREAT|O_WRONLY, 0644);
if (out == -1) {
log_error("Failed to open destination: %m\n");
@@ -689,5 +697,5 @@ void ratbagd_schedule_task(struct ratbagd *ctx,
cb->callback = callback;
cb->userdata = userdata;
sd_event_add_post(ctx->event, &source, ratbagd_callback_handler, cb);
sd_event_add_defer(ctx->event, &source, ratbagd_callback_handler, cb);
}

View File

@@ -164,6 +164,7 @@ hidpp10drv_map_button(struct ratbag_device *device,
{
struct hidpp10_profile profile;
int ret;
unsigned int modifiers = 0;
ret = hidpp10_get_profile(hidpp10, button->profile->index, &profile);
if (ret)
@@ -178,6 +179,7 @@ hidpp10drv_map_button(struct ratbag_device *device,
button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
button->action.action.key.key = ratbag_hidraw_get_keycode_from_keyboard_usage(device,
profile.buttons[button->index].keys.key);
modifiers = profile.buttons[button->index].keys.modifier_flags;
break;
case PROFILE_BUTTON_TYPE_CONSUMER_CONTROL:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
@@ -199,6 +201,14 @@ hidpp10drv_map_button(struct ratbag_device *device,
}
}
if (button->action.type == RATBAG_BUTTON_ACTION_TYPE_KEY) {
ret = ratbag_button_macro_new_from_keycode(button, button->action.action.key.key, modifiers);
if (ret < 0) {
log_error(device->ratbag, "hidpp10: error while reading button %d\n", button->index);
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
}
}
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
}
@@ -299,6 +309,8 @@ hidpp10drv_write_button(struct hidpp10_profile *profile,
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp10_device *hidpp10 = drv_data->dev;
uint8_t code;
unsigned int modifiers, key;
int rc;
if (hidpp10->profile_type == HIDPP10_PROFILE_UNKNOWN)
return -ENOTSUP;
@@ -330,6 +342,26 @@ hidpp10drv_write_button(struct hidpp10_profile *profile,
profile->buttons[button->index].special.special = code;
break;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
rc = ratbag_action_keycode_from_macro(action, &key, &modifiers);
if (rc < 0) {
log_error(device->ratbag, "hidpp10: can't convert macro action to keycode in button %d\n", button->index);
return -EINVAL;
}
code = ratbag_hidraw_get_keyboard_usage_from_keycode(device, key);
if (code == 0) {
code = ratbag_hidraw_get_consumer_usage_from_keycode(device, key);
if (code == 0)
return -EINVAL;
profile->buttons[button->index].consumer_control.type = PROFILE_BUTTON_TYPE_CONSUMER_CONTROL;
profile->buttons[button->index].consumer_control.consumer_control = code;
} else {
profile->buttons[button->index].keys.type = PROFILE_BUTTON_TYPE_KEYS;
profile->buttons[button->index].keys.key = code;
profile->buttons[button->index].keys.modifier_flags = modifiers;
}
break;
default:
return -ENOTSUP;
}
@@ -541,7 +573,8 @@ hidpp10drv_commit(struct ratbag_device *device)
return rc;
p.enabled = profile->is_enabled;
strncpy_safe((char*)p.name, profile->name, 24);
if (profile->name != NULL)
strncpy_safe((char*)p.name, profile->name, 24);
ratbag_profile_for_each_resolution(profile, resolution) {
p.dpi_modes[resolution->index].xres = resolution->dpi_x;
@@ -558,8 +591,10 @@ hidpp10drv_commit(struct ratbag_device *device)
continue;
rc = hidpp10drv_write_button(&p, button, &action);
if (rc)
if (rc) {
log_error(device->ratbag, "hidpp10: failed to update buttons (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
ratbag_profile_for_each_led(profile, led)
@@ -567,8 +602,10 @@ hidpp10drv_commit(struct ratbag_device *device)
if (dev->profile_type != HIDPP10_PROFILE_UNKNOWN) {
rc = hidpp10_set_profile(dev, profile->index, &p);
if (rc)
if (rc) {
log_error(device->ratbag, "hidpp10: failed to set profile (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
/* Update the current resolution in case it changed */
@@ -576,8 +613,10 @@ hidpp10drv_commit(struct ratbag_device *device)
rc = hidpp10_set_current_resolution(dev,
active_resolution->dpi_x,
active_resolution->dpi_y);
if (rc)
if (rc) {
log_error(device->ratbag, "hidpp10: failed to set active resolution (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
active_resolution = NULL;
}
@@ -631,9 +670,9 @@ hidpp10drv_probe(struct ratbag_device *device)
* If there is a special need like for G700(s), then add a DeviceIndex
* entry to the .device file.
*/
dev = hidpp10_device_new(&base, device_idx, type, profile_count);
rc = hidpp10_device_new(&base, device_idx, type, profile_count, &dev);
if (!dev) {
if (rc) {
log_error(device->ratbag,
"Failed to get HID++1.0 device for %s\n",
device->name);
@@ -714,14 +753,14 @@ static void
hidpp10drv_remove(struct ratbag_device *device)
{
struct hidpp10drv_data *drv_data;
struct hidpp10_device *dev;
ratbag_close_hidraw(device);
drv_data = ratbag_get_drv_data(device);
dev = drv_data->dev;
if (!drv_data)
return;
hidpp10_device_destroy(dev);
hidpp10_device_destroy(drv_data->dev);
free(drv_data);
}

View File

@@ -575,7 +575,7 @@ hidpp20drv_update_button_8100(struct ratbag_button *button)
code = ratbag_hidraw_get_keyboard_usage_from_keycode(device, key);
if (code == 0) {
subtype = HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL;
code = ratbag_hidraw_get_consumer_usage_from_keycode(device, action->action.key.key);
code = ratbag_hidraw_get_consumer_usage_from_keycode(device, key);
if (code == 0)
return -EINVAL;
}
@@ -1490,7 +1490,7 @@ hidpp20drv_commit(struct ratbag_device *device)
if (profile->rate_dirty) {
rc = hidpp20drv_update_report_rate(profile, profile->hz);
if (rc) {
log_error(device->ratbag, "hidpp20: failed to update report rate\n");
log_error(device->ratbag, "hidpp20: failed to update report rate (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
@@ -1500,7 +1500,7 @@ hidpp20drv_commit(struct ratbag_device *device)
resolution->dpi_x,
resolution->dpi_y);
if (rc) {
log_error(device->ratbag, "hidpp20: failed to update resolution\n");
log_error(device->ratbag, "hidpp20: failed to update resolution (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
@@ -1511,7 +1511,7 @@ hidpp20drv_commit(struct ratbag_device *device)
rc = hidpp20drv_update_button(button);
if (rc) {
log_error(device->ratbag, "hidpp20: failed to update button\n");
log_error(device->ratbag, "hidpp20: failed to update button (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
@@ -1522,7 +1522,7 @@ hidpp20drv_commit(struct ratbag_device *device)
rc = hidpp20drv_update_led(led);
if (rc) {
log_error(device->ratbag, "hidpp20: failed to update led\n");
log_error(device->ratbag, "hidpp20: failed to update led (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
}
@@ -1535,7 +1535,7 @@ hidpp20drv_commit(struct ratbag_device *device)
rc = hidpp20_onboard_profiles_commit(drv_data->dev,
drv_data->profiles);
if (rc) {
log_error(device->ratbag, "hidpp20: failed to commit profile\n");
log_error(device->ratbag, "hidpp20: failed to commit profile (%d)\n", rc);
return RATBAG_ERROR_DEVICE;
}
@@ -1636,6 +1636,11 @@ hidpp20drv_init_device(struct ratbag_device *device,
{
struct ratbag_profile *profile;
bool active_profile = false;
int num;
num = ratbag_device_data_hidpp20_get_led_count(device->data);
if (num >= 0)
drv_data->num_leds = num;
ratbag_device_init_profiles(device,
drv_data->num_profiles,

View File

@@ -37,7 +37,7 @@
#define LOGITECH_G300_BUTTON_MAX 8
#define LOGITECH_G300_NUM_DPI 4
#define LOGITECH_G300_NUM_LED 1
#define LOGITECH_G300_DPI_MIN 250
#define LOGITECH_G300_DPI_MIN 100
#define LOGITECH_G300_DPI_MAX 2500
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE 0xF0
@@ -51,7 +51,7 @@
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
struct logitech_g300_resolution {
uint8_t dpi :7; /* Range 1-10. dpi = 250*value */
uint8_t dpi :7; /* Range 1-10. dpi = 100*value */
uint8_t is_default :1;
} __attribute__((packed));
@@ -449,11 +449,10 @@ logitech_g300_read_profile(struct ratbag_profile *profile)
ratbag_profile_for_each_resolution(profile, resolution) {
struct logitech_g300_resolution *res =
&report->dpi_levels[resolution->index];
unsigned int dpis[10] = { 250, 500, 750, 1000, 1250, 1500, 1750,
2000, 2250, 2500 };
unsigned int dpis[49] = { 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950, 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350, 2400, 2450, 2500, };
resolution->dpi_x = res->dpi * 250;
resolution->dpi_y = res->dpi * 250;
resolution->dpi_x = res->dpi * 50;
resolution->dpi_y = res->dpi * 50;
resolution->is_default = res->is_default;
resolution->is_active = res->is_default;
@@ -546,7 +545,7 @@ logitech_g300_write_profile(struct ratbag_profile *profile)
struct logitech_g300_resolution *res =
&report->dpi_levels[resolution->index];
res->dpi = resolution->dpi_x / 250;
res->dpi = resolution->dpi_x / 50;
res->is_default = resolution->is_default;
if (profile->is_active && resolution->is_active)

View File

@@ -34,7 +34,7 @@
#include "libratbag-hidraw.h"
#define LOGITECH_G600_NUM_PROFILES 3
#define LOGITECH_G600_NUM_BUTTONS 20
#define LOGITECH_G600_NUM_BUTTONS 41 // 20 buttons + 1 color buffer + 20 G-shift
#define LOGITECH_G600_NUM_DPI 4
#define LOGITECH_G600_NUM_LED 1
#define LOGITECH_G600_DPI_MIN 200
@@ -109,20 +109,41 @@ static const struct logitech_g600_button_type_mapping logitech_g600_button_type_
{ 3, RATBAG_BUTTON_TYPE_WHEEL_LEFT },
{ 4, RATBAG_BUTTON_TYPE_WHEEL_RIGHT },
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
{ 6, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP },
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP },
{ 8, RATBAG_BUTTON_TYPE_SIDE }, // 8 = G9 ... 19 = G20
{ 9, RATBAG_BUTTON_TYPE_SIDE },
{ 10, RATBAG_BUTTON_TYPE_SIDE },
{ 11, RATBAG_BUTTON_TYPE_SIDE },
{ 12, RATBAG_BUTTON_TYPE_SIDE },
{ 13, RATBAG_BUTTON_TYPE_SIDE },
{ 14, RATBAG_BUTTON_TYPE_SIDE },
{ 15, RATBAG_BUTTON_TYPE_SIDE },
{ 16, RATBAG_BUTTON_TYPE_SIDE },
{ 17, RATBAG_BUTTON_TYPE_SIDE },
{ 18, RATBAG_BUTTON_TYPE_SIDE },
{ 19, RATBAG_BUTTON_TYPE_SIDE },
{ 6, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP }, // G07
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP }, // G08
{ 8, RATBAG_BUTTON_TYPE_SIDE }, // G09
{ 9, RATBAG_BUTTON_TYPE_SIDE }, // G10
{ 10, RATBAG_BUTTON_TYPE_SIDE }, // G11
{ 11, RATBAG_BUTTON_TYPE_SIDE }, // G12
{ 12, RATBAG_BUTTON_TYPE_SIDE }, // G13
{ 13, RATBAG_BUTTON_TYPE_SIDE }, // G14
{ 14, RATBAG_BUTTON_TYPE_SIDE }, // G15
{ 15, RATBAG_BUTTON_TYPE_SIDE }, // G16
{ 16, RATBAG_BUTTON_TYPE_SIDE }, // G17
{ 17, RATBAG_BUTTON_TYPE_SIDE }, // G18
{ 18, RATBAG_BUTTON_TYPE_SIDE }, // G19
{ 19, RATBAG_BUTTON_TYPE_SIDE }, // G20
{ 20, RATBAG_BUTTON_TYPE_UNKNOWN }, //HACK is where the G-shift color information is located
{ 21, RATBAG_BUTTON_TYPE_LEFT }, // G-shift + left
{ 22, RATBAG_BUTTON_TYPE_RIGHT }, // G-shift + right click
{ 23, RATBAG_BUTTON_TYPE_MIDDLE }, // G-shift + middle
{ 24, RATBAG_BUTTON_TYPE_WHEEL_LEFT}, // G-shift + scroll left
{ 25, RATBAG_BUTTON_TYPE_WHEEL_RIGHT}, // G-shift + scroll right
{ 26, RATBAG_BUTTON_TYPE_PINKIE }, // G-shift + Pinky(shift modifer)
{ 27, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP }, // G-shift + 07
{ 28, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP }, // G-shift + G08
{ 29, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G09
{ 30, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G10
{ 31, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G11
{ 32, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G12
{ 33, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G13
{ 34, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G14
{ 35, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G15
{ 36, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G16
{ 37, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G17
{ 38, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G18
{ 39, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G19
{ 40, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G20
};
static enum ratbag_button_type
@@ -144,7 +165,7 @@ struct logitech_g600_button_mapping {
};
static struct logitech_g600_button_mapping logitech_g600_button_mapping[] = {
/* 0x00 is either key or unassigned. Must be handled separatly */
/* 0x00 is either key or unassigned. Must be handled separately */
{ 0x01, BUTTON_ACTION_BUTTON(1) },
{ 0x02, BUTTON_ACTION_BUTTON(2) },
{ 0x03, BUTTON_ACTION_BUTTON(3) },
@@ -600,6 +621,12 @@ logitech_g600_write_profile(struct ratbag_profile *profile)
report->led_duration = 0x0f;
}
// For now the default will copy over the main color into the g-shift color
// future update may add support to set this via cli command
report->g_shift_color[0] = report->led_red;
report->g_shift_color[1] = report->led_green;
report->g_shift_color[2] = report->led_blue;
buf = (uint8_t*)report;
rc = ratbag_hidraw_raw_request(device, report->id,

482
src/driver-openinput.c Normal file
View File

@@ -0,0 +1,482 @@
/*
* Copyright © 2021 Filipe Laíns
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include "libratbag-private.h"
/* reports */
#define OI_REPORT_SHORT 0x20
#define OI_REPORT_LONG 0x21
#define OI_REPORT_SHORT_SIZE 8
#define OI_REPORT_LONG_SIZE 32
#define OI_REPORT_MAX_SIZE OI_REPORT_LONG_SIZE
#define OI_REPORT_DATA_INDEX 3
#define OI_REPORT_DATA_MAX_SIZE OI_REPORT_LONG_SIZE - OI_REPORT_DATA_INDEX
/* protocol function pages */
#define OI_PAGE_INFO 0x00
#define OI_PAGE_GIMMICKS 0xFD
#define OI_PAGE_DEBUG 0xFE
#define OI_PAGE_ERROR 0xFF
/* info page (0x00) functions */
#define OI_FUNCTION_VERSION 0x00
#define OI_FUNCTION_FW_INFO 0x01
#define OI_FUNCTION_SUPPORTED_FUNCTION_PAGES 0x02
#define OI_FUNCTION_SUPPORTED_FUNCTIONS 0x03
/* error page (0xFF) */
#define OI_ERROR_INVALID_VALUE 0x01
#define OI_ERROR_UNSUPPORTED_FUNCTION 0x02
#define OI_ERROR_CUSTOM 0xFE
static unsigned int report_rates[] = { 125, 250, 500, 750, 1000 };
struct openinput_drv_data {
unsigned int num_profiles;
unsigned int num_resolutions;
unsigned int num_buttons;
unsigned int num_leds;
unsigned int fw_major;
unsigned int fw_minor;
unsigned int fw_patch;
uint64_t supported;
};
struct oi_report_t {
uint8_t id;
uint8_t function_page;
uint8_t function;
uint8_t data[29];
} __attribute__((__packed__));
#define CASE_RETURN_STRING(a) case a: return #a; break
static const char*
openinput_function_page_get_name(uint8_t page)
{
static char numeric[16];
char *str;
switch(page) {
CASE_RETURN_STRING(OI_PAGE_INFO);
CASE_RETURN_STRING(OI_PAGE_GIMMICKS);
CASE_RETURN_STRING(OI_PAGE_DEBUG);
CASE_RETURN_STRING(OI_PAGE_ERROR);
default:
sprintf_safe(numeric, "0x%02x", page);
str = numeric;
break;
}
return str;
}
static const char*
openinput_function_get_name(uint8_t page, uint8_t function)
{
static char numeric[32];
char *str = NULL;
switch(page) {
case OI_PAGE_INFO:
switch (function) {
CASE_RETURN_STRING(OI_FUNCTION_VERSION);
CASE_RETURN_STRING(OI_FUNCTION_FW_INFO);
CASE_RETURN_STRING(OI_FUNCTION_SUPPORTED_FUNCTION_PAGES);
CASE_RETURN_STRING(OI_FUNCTION_SUPPORTED_FUNCTIONS);
}
}
if (!str) {
sprintf_safe(numeric, "0x%02x 0x%02x", page, function);
str = numeric;
}
return str;
}
#undef CASE_RETURN_STRING
static const char*
openinput_get_error_string(struct oi_report_t *report)
{
char help_str[OI_REPORT_LONG_SIZE - OI_REPORT_DATA_INDEX + 1] = {0};
char *str;
switch (report->function) {
case OI_ERROR_INVALID_VALUE:
xasprintf(&str, "Invalid value (in position %u)", report->data[2]);
break;
case OI_ERROR_CUSTOM:
memcpy(help_str, report->data, sizeof(help_str)-1); /* copy error string */
xasprintf(&str, "Custom error (%s)", help_str);
break;
case OI_ERROR_UNSUPPORTED_FUNCTION:
xasprintf(&str, "Unsupported function (0x%02x, 0x%02x)", report->data[0], report->data[1]);
break;
default:
xasprintf(&str, "Unkown error (%u)", report->function);
break;
}
return str;
}
static size_t
openinput_get_report_size(unsigned int report)
{
switch (report) {
case OI_REPORT_SHORT:
return OI_REPORT_SHORT_SIZE;
case OI_REPORT_LONG:
return OI_REPORT_LONG_SIZE;
default:
return 0;
}
}
static int
openinput_send_report(struct ratbag_device *device, struct oi_report_t *report)
{
int ret;
uint8_t buffer[OI_REPORT_MAX_SIZE];
size_t size = openinput_get_report_size(report->id);
memcpy(buffer, report, size);
ret = ratbag_hidraw_output_report(device, buffer, size);
if (ret < 0) {
log_error(device->ratbag, "openinput: failed to send data to device (%s)\n",
strerror(-ret));
return ret;
}
ret = ratbag_hidraw_read_input_report(device, buffer, OI_REPORT_MAX_SIZE);
if (ret < 0) {
log_error(device->ratbag, "openinput: failed to read data from device (%s)\n",
strerror(-ret));
return ret;
}
memcpy(report, buffer, openinput_get_report_size(buffer[0]));
/* check for error */
if (report->function_page == OI_PAGE_ERROR) {
log_error(device->ratbag, "openinput: %s\n", openinput_get_error_string(report));
return report->function;
}
return 0;
}
static int
openinput_info_version(struct ratbag_device *device)
{
int ret;
struct openinput_drv_data *drv_data = ratbag_get_drv_data(device);
struct oi_report_t report = {
.id = OI_REPORT_SHORT,
.function_page = OI_PAGE_INFO,
.function = OI_FUNCTION_VERSION
};
ret = openinput_send_report(device, &report);
if (ret)
return ret;
drv_data->fw_major = report.data[0];
drv_data->fw_minor = report.data[1];
drv_data->fw_patch = report.data[2];
log_info(device->ratbag, "openinput: protocol version %u.%u.%u\n",
drv_data->fw_major, drv_data->fw_minor, drv_data->fw_patch);
return 0;
}
#define OI_FUNCTION_FW_INFO_VENDOR 0x00
#define OI_FUNCTION_FW_INFO_VERSION 0x01
#define OI_FUNCTION_FW_INFO_DEVICE_NAME 0x02
static int
openinput_info_fw_info(struct ratbag_device *device,
uint8_t field_id,
unsigned char *description,
size_t description_size)
{
int ret;
struct oi_report_t report = {
.id = OI_REPORT_SHORT,
.function_page = OI_PAGE_INFO,
.function = OI_FUNCTION_FW_INFO,
.data = {field_id}
};
ret = openinput_send_report(device, &report);
if (ret)
return ret;
memcpy(description, report.data, min(sizeof(report.data), description_size));
return 0;
}
static int
openinput_info_supported_function_pages(struct ratbag_device *device,
uint8_t start_index,
uint8_t *pages_count,
uint8_t *pages_left,
uint8_t *pages,
size_t pages_size)
{
int ret;
struct oi_report_t report = {
.id = OI_REPORT_SHORT,
.function_page = OI_PAGE_INFO,
.function = OI_FUNCTION_SUPPORTED_FUNCTION_PAGES,
.data = {start_index}
};
ret = openinput_send_report(device, &report);
if (ret)
return ret;
*pages_count = report.data[0];
*pages_left = report.data[1];
memcpy(pages, report.data + 2, min(sizeof(report.data), pages_size));
return 0;
}
static int
openinput_info_supported_functions(struct ratbag_device *device,
uint8_t function_page,
uint8_t start_index,
uint8_t *functions_count,
uint8_t *functions_left,
uint8_t *functions,
size_t functions_size)
{
int ret;
struct oi_report_t report = {
.id = OI_REPORT_SHORT,
.function_page = OI_PAGE_INFO,
.function = OI_FUNCTION_SUPPORTED_FUNCTIONS,
.data = {function_page, start_index}
};
ret = openinput_send_report(device, &report);
if (ret)
return ret;
*functions_count = report.data[0];
*functions_left = report.data[1];
memcpy(functions, report.data + 2, min(sizeof(report.data), functions_size));
return 0;
}
static int
openinput_read_supported_functions(struct ratbag_device *device, uint8_t page)
{
struct ratbag *ratbag = device->ratbag;
int ret;
uint8_t i, total, read = 0, count = 0, left = 0;
uint8_t buffer[OI_REPORT_DATA_MAX_SIZE];
ret = openinput_info_supported_functions(device,
page,
read,
&count, &left,
buffer, sizeof(buffer));
if (ret)
return ret;
total = count + left;
uint8_t functions[total];
memcpy(functions, buffer, count);
/* there are still functions left to read! */
while (left) {
ret = openinput_info_supported_functions(device,
page,
read,
&count, &left,
buffer, sizeof(buffer));
if (ret)
return ret;
/* make sure the new size values make sense, to avoid deadlocks */
if (total != (read + count + left)) {
log_error(ratbag, "openinput: invalid number of functions left to read (%u)\n", left);
return -EINVAL;
}
log_debug(ratbag, "openinput: read %u functions, %u left\n", count, left);
memcpy(functions + read, buffer, count);
read += count;
}
/* iterate over read functions */
for (i = 0; i < total; i++) {
log_debug(ratbag, "openinput: found function %s\n", openinput_function_get_name(page, functions[i]));
/* TODO: set bits in drv_data->supported when we implement support for certain capabilities */
}
return 0;
}
static int
openinput_read_supported_function_pages(struct ratbag_device *device)
{
struct ratbag *ratbag = device->ratbag;
int ret;
uint8_t i, total, read = 0, count = 0, left = 0;
uint8_t buffer[OI_REPORT_DATA_MAX_SIZE];
log_debug(ratbag, "openinput: starting reading device functions...\n");
ret = openinput_info_supported_function_pages(device,
read,
&count, &left,
buffer, sizeof(buffer));
if (ret)
return ret;
total = count + left;
uint8_t pages[total];
memcpy(pages, buffer, count);
/* there are still function pages left to read! */
while (left) {
ret = openinput_info_supported_function_pages(device,
read,
&count, &left,
buffer, sizeof(buffer));
if (ret)
return ret;
/* make sure the new size values make sense, to avoid deadlocks */
if (total != (read + count + left)) {
log_error(ratbag, "openinput: invalid number of function pages left to read (%u)\n", left);
return -EINVAL;
}
log_debug(ratbag, "openinput: read %u pages, %u left\n", count, left);
memcpy(pages + read, buffer, count);
read += count;
}
/* iterate over read function pages, and read their functions */
for (i = 0; i < total; i++) {
log_debug(ratbag, "openinput: found function page %s\n", openinput_function_page_get_name(pages[i]));
openinput_read_supported_functions(device, pages[i]);
}
return 0;
}
static void
openinput_read_profile(struct ratbag_profile *profile)
{
ratbag_profile_set_report_rate_list(profile, report_rates, sizeof(*report_rates));
profile->is_active = true;
}
static int
openinput_test_hidraw(struct ratbag_device *device)
{
return ratbag_hidraw_has_report(device, OI_REPORT_SHORT);
}
static int
openinput_probe(struct ratbag_device *device)
{
int ret;
struct openinput_drv_data *drv_data;
struct ratbag_profile *profile;
unsigned char str[OI_REPORT_DATA_MAX_SIZE];
ret = ratbag_find_hidraw(device, openinput_test_hidraw);
if (ret)
return ret;
drv_data = zalloc(sizeof(*drv_data));
drv_data->num_profiles = 1;
ratbag_set_drv_data(device, drv_data);
openinput_info_version(device);
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_VENDOR, str, sizeof(str));
if (ret)
return ret;
log_info(device->ratbag, "openinput: firmware vendor: %s\n", str);
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_VERSION, str, sizeof(str));
if (ret)
return ret;
log_info(device->ratbag, "openinput: firmware version: %s\n", str);
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_DEVICE_NAME, str, sizeof(str));
if (ret)
return ret;
log_info(device->ratbag, "openinput: device: %s\n", str);
ret = openinput_read_supported_function_pages(device);
if (ret)
return ret;
ratbag_device_init_profiles(device,
drv_data->num_profiles,
drv_data->num_resolutions,
drv_data->num_buttons,
drv_data->num_leds);
ratbag_device_for_each_profile(device, profile)
openinput_read_profile(profile);
return 0;
}
static void
openinput_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
free(ratbag_get_drv_data(device));
}
struct ratbag_driver openinput_driver = {
.name = "openinput",
.id = "openinput",
.probe = openinput_probe,
.remove = openinput_remove,
};

View File

@@ -835,7 +835,7 @@ roccat_remove(struct ratbag_device *device)
struct ratbag_driver roccat_driver = {
.name = "Roccat Kone Pure",
.id = "roccat",
.id = "roccat-kone-pure",
.probe = roccat_probe,
.remove = roccat_remove,
.write_profile = roccat_write_profile,

View File

@@ -0,0 +1,320 @@
/*
* Copyright © 2020 Pipat Saengow
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include "libratbag-enums.h"
#include "libratbag-hidraw.h"
#include "libratbag-private.h"
#include "libratbag-util.h"
#include "shared-macro.h"
#include <stdint.h>
#include <string.h>
#define SINOWEALTHNUBWO_PERF_CMD_REPORTID 0x02
#define SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID 0x03
#define SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID 0x04
#define SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE 256
#define SINOWEALTHNUBWO_GET_FIRMWARE_MSGOFFSET 48
#define SINOWEALTHNUBWO_PERF_CMD_MSGSIZE 16
// Actually more but I only implemented one
#define SINOWEALTHNUBWO_NUM_PROFILES 1
#define SINOWEALTHNUBWO_NUM_RESOLUTIONS 1
// Actually 8 but I am not going to implement macros.
#define SINOWEALTHNUBWO_NUM_BUTTONS 0
#define SINOWEALTHNUBWO_NUM_LEDS 1
//Magic set_feature that must be called before requesting firmware string
static uint8_t PREFIRMWARE_QUERY_MSG[] = {0x02, 0x01, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static unsigned int REPORT_RATES[] = { 125, 250, 333, 500, 1000 };
static uint8_t REPORT_RATES_ENCODED[] = {0x08, 0x04, 0x03, 0x02, 0x01};
static uint8_t REPORT_RATES_CMD[] = {0x02, 0x06, 0xbb, 0xaa, 0x28, 0x00, 0x01, 0x00};
static unsigned int DPILIST[] = { 1000, 2000, 3000, 5000, 15000};
static uint8_t DPI_ENCODED[] = {0x04, 0x03, 0x02, 0x01, 0x00};
static uint8_t DPI_CMD[] = { 0x02, 0x06, 0xbb, 0xaa, 0x32, 0x00, 0x01, 0x00 };
enum
sinowealthnubwo_color_mode {
SINOWEALTHNUBWO_COLOR_OFF = 0x00,
SINOWEALTHNUBWO_COLOR_ON = 0x01,
SINOWEALTHNUBWO_COLOR_BREATHING = 0x02,
SINOWEALTHNUBWO_COLOR_COLOR_SHIFT = 0x03,
SINOWEALTHNUBWO_COLOR_SPECTRUM = 0x04,
SINOWEALTHNUBWO_COLOR_MARQUEE = 0x05,
};
struct
sinowealthnubwo_aesthetic_report {
uint8_t report_id; //0x03
uint8_t cmd[7];
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t color_mode;
uint8_t padzero; // 0x00
uint8_t brightness; // 0x01 to 0x03
uint8_t tempo; // 0x05 0x03 0x01
uint8_t padzero2[16*3+1];
} __packed__;
static uint8_t AESTHETIC_CMD[] = {0x06, 0xbb, 0xaa, 0x2a, 0x00, 0x0a, 0x00};
static int
sinowealthnubwo_test_hidraw(struct ratbag_device *device)
{
return
ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID)
&& ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID)
&& ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID);
}
static int
sinowealth_get_firmware_string(struct ratbag_device *device, char **output)
{
uint8_t buff[SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE + 1] = {0}; //Purposefully overalloacate to prevent buffer overrun
int size;
size = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, PREFIRMWARE_QUERY_MSG, ARRAY_LENGTH(PREFIRMWARE_QUERY_MSG));
if (size < 0) {
log_error(device->ratbag, "Error while sending pre-firmware request message: %d\n", size);
return size;
}
size = ratbag_hidraw_get_feature_report(device, SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID, buff, SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE);
if (size != SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE) {
log_error(device->ratbag ,"Firmware report reply size mismatch expected %d got %d\n", SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE, size);
return size;
}
*output = strdup_ascii_only((char *) buff + SINOWEALTHNUBWO_GET_FIRMWARE_MSGOFFSET);
return 0;
}
static int
sinowealthnubwo_probe(struct ratbag_device *device)
{
int error;
struct ratbag_profile *profile;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
error = ratbag_find_hidraw(device, sinowealthnubwo_test_hidraw);
if (error)
return error;
char *fwstr;
error = sinowealth_get_firmware_string(device, &fwstr);
if (error)
return error;
log_info(device->ratbag, "Firmware: %s\n", fwstr);
free(fwstr);
ratbag_device_init_profiles(device,
SINOWEALTHNUBWO_NUM_PROFILES,
SINOWEALTHNUBWO_NUM_RESOLUTIONS,
SINOWEALTHNUBWO_NUM_BUTTONS,
SINOWEALTHNUBWO_NUM_LEDS);
ratbag_device_for_each_profile(device, profile) {
profile->is_active = true;
ratbag_profile_set_cap(profile, RATBAG_PROFILE_CAP_WRITE_ONLY);
ratbag_profile_set_report_rate_list(profile, REPORT_RATES, ARRAY_LENGTH(REPORT_RATES));
ratbag_profile_for_each_resolution(profile, resolution) {
ratbag_resolution_set_dpi_list(resolution, DPILIST, ARRAY_LENGTH(DPILIST));
resolution->dpi_x = resolution->dpi_y = DPILIST[ARRAY_LENGTH(DPILIST)-1];
resolution->is_active = true;
resolution->is_default = true;
}
ratbag_profile_for_each_led(profile, led) {
led->mode = RATBAG_LED_OFF;
led->color.red = led->color.green = led->color.blue = 0xFF;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
led->type = RATBAG_LED_TYPE_SIDE;
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
//Actually more
}
}
return 0;
}
static uint8_t
encode_dpi(unsigned int dpi)
{
for (size_t i = 0; i < ARRAY_LENGTH(DPILIST); i++)
if (DPILIST[i] == dpi)
return DPI_ENCODED[i];
return DPI_ENCODED[0];
}
static uint8_t
encode_report_rate(unsigned int reportrate)
{
for (size_t i = 0; i < ARRAY_LENGTH(REPORT_RATES); i++)
if (REPORT_RATES[i] == reportrate)
return REPORT_RATES_ENCODED[i];
return REPORT_RATES_ENCODED[0];
}
static int
sinowealthnubwo_set_dpi(struct ratbag_device *device, int dpi)
{
uint8_t buf[SINOWEALTHNUBWO_PERF_CMD_MSGSIZE] = {0};
memcpy(buf, DPI_CMD, ARRAY_LENGTH(DPI_CMD));
buf[ARRAY_LENGTH(DPI_CMD)] = encode_dpi(dpi);
int error = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, buf, SINOWEALTHNUBWO_PERF_CMD_MSGSIZE);
if (error < 0)
return error;
return 0;
}
static int
sinowealthnubwo_set_report_rate(struct ratbag_device *device, int reportrate)
{
uint8_t buf[SINOWEALTHNUBWO_PERF_CMD_MSGSIZE] = {0};
memcpy(buf, REPORT_RATES_CMD, ARRAY_LENGTH(REPORT_RATES_CMD));
buf[ARRAY_LENGTH(REPORT_RATES_CMD)] = encode_report_rate(reportrate);
int error = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, buf, SINOWEALTHNUBWO_PERF_CMD_MSGSIZE);
if (error < 0)
return error;
return 0;
}
static enum sinowealthnubwo_color_mode encode_color(enum ratbag_led_mode mode)
{
switch (mode) {
case RATBAG_LED_OFF:
return SINOWEALTHNUBWO_COLOR_OFF;
case RATBAG_LED_ON:
return SINOWEALTHNUBWO_COLOR_ON;
case RATBAG_LED_CYCLE:
return SINOWEALTHNUBWO_COLOR_MARQUEE;
case RATBAG_LED_BREATHING:
return SINOWEALTHNUBWO_COLOR_BREATHING;
default:
return SINOWEALTHNUBWO_COLOR_OFF;
}
}
static uint8_t normalize_duration(int duration)
{
const int MAX_DURATION = 10000;
const uint8_t avail_dura[] = {0x01, 0x03, 0x05};
const int selected = (duration * ((int) ARRAY_LENGTH(avail_dura)) - 1) / MAX_DURATION;
return avail_dura[selected];
}
static uint8_t normalize_brightness(int brightness)
{
const int MAX_BRIGHTNESS = 255;
return 1 + (brightness * 3 - 1) / MAX_BRIGHTNESS;
}
static int
sinowealthnubwo_set_aesthetic(struct ratbag_device *device, struct ratbag_led *led) {
struct sinowealthnubwo_aesthetic_report report;
memset(&report, 0, sizeof(struct sinowealthnubwo_aesthetic_report));
report.report_id = SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID;
memcpy(report.cmd, AESTHETIC_CMD, ARRAY_LENGTH(AESTHETIC_CMD));
report.r = led->color.red;
report.g = led->color.green;
report.b = led->color.blue;
report.color_mode = encode_color(led->mode);
report.tempo = normalize_duration(led->ms);
report.brightness = normalize_brightness(led->brightness);
int size = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID, (uint8_t *) &report, sizeof(report));
if (size < 0)
return size;
return 0;
}
static int
sinowealthnubwo_write_profile(struct ratbag_device *device, struct ratbag_profile *profile)
{
struct ratbag_resolution *resolution;
struct ratbag_led *led;
int error;
log_debug(device->ratbag, "Writing updates\n");
log_debug(device->ratbag, "Setting report rate\n");
error = sinowealthnubwo_set_report_rate(device, profile->hz);
if (error)
return error;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)
continue;
log_debug(device->ratbag, "Setting DPI\n");
error = sinowealthnubwo_set_dpi(device, resolution->dpi_x);
if (error)
return error;
}
ratbag_profile_for_each_led(profile, led) {
if (!led->dirty)
continue;
log_debug(device->ratbag, "Setting aesthetic\n");
error = sinowealthnubwo_set_aesthetic(device, led);
if (error)
return error;
}
return 0;
}
static int
sinowealthnubwo_commit(struct ratbag_device *device)
{
struct ratbag_profile *profile;
list_for_each(profile, &device->profiles, link) {
if (!profile->dirty) continue;
int error = sinowealthnubwo_write_profile(device, profile);
if (error)
return error;
}
return 0;
}
static void
sinowealthnubwo_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
}
struct ratbag_driver sinowealth_nubwo_driver = {
.name = "Sinowealth Nubwo",
.id = "sinowealth_nubwo",
.probe = sinowealthnubwo_probe,
.remove = sinowealthnubwo_remove,
.commit = sinowealthnubwo_commit,
};

494
src/driver-sinowealth.c Normal file
View File

@@ -0,0 +1,494 @@
/*
* Copyright © 2020 Marian Beermann
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
#define SINOWEALTH_REPORT_ID_CONFIG 0x4
#define SINOWEALTH_REPORT_ID_CMD 0x5
#define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1
#define SINOWEALTH_CMD_GET_CONFIG 0x11
#define SINOWEALTH_CONFIG_SIZE 520
#define SINOWEALTH_CONFIG_SIZE_USED 131
#define SINOWEALTH_XY_INDEPENDENT 0x80
/* The PC software only goes down to 400, but the PMW3360 doesn't care */
#define SINOWEALTH_DPI_MIN 100
#define SINOWEALTH_DPI_MAX 12000
#define SINOWEALTH_DPI_STEP 100
/* other models might have up to eight */
#define SINOWEALTH_NUM_DPIS 6
#define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0
#define SINOWEALTH_RGB_SPEED_BITS 0x0F
struct sinowealth_rgb8 {
uint8_t r, g, b;
} __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_rgb8) == 3, "Invalid size");
struct sinowealth_rbg8 {
uint8_t r, b, g;
} __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_rbg8) == 3, "Invalid size");
enum rgb_effect {
RGB_OFF = 0,
RGB_GLORIOUS = 0x1, /* unicorn mode */
RGB_SINGLE = 0x2, /* single constant color */
RGB_BREATHING = 0x5, /* Full RGB breathing */
RGB_BREATHING7 = 0x3, /* breathing with seven user-defined colors */
RGB_BREATHING1 = 0xa, /* single color breathing */
RGB_TAIL = 0x4,
RGB_RAVE = 0x7,
RGB_WAVE = 0x9
};
struct sinowealth_config_report {
uint8_t report_id; /* SINOWEALTH_REPORT_ID_CONFIG */
uint8_t command_id;
uint8_t unknown1;
/* always 0 when config is read from device,
* has to be 0x7b when writing config to device
*/
uint8_t config_write;
uint8_t unknown2[6];
/* 0x80 - SINOWEALTH_XY_INDEPENDENT */
uint8_t config;
uint8_t dpi_count:4;
uint8_t active_dpi:4;
/* bit set: disabled, unset: enabled
* this structure has support for eight DPI slots,
* but the glorious software only exposes six
*/
uint8_t dpi_enabled;
/* DPI/CPI is encoded in the way the PMW3360 sensor accepts it
* value = (DPI - 100) / 100
* If XY are identical, dpi[0-6] contain the sensitivities,
* while in XY independent mode each entry takes two chars for X and Y.
*/
uint8_t dpi[16];
struct sinowealth_rgb8 dpi_color[8];
uint8_t rgb_effect; /* see enum rgb_effect */
/* 0x40 - brightness (constant)
* 0x1/2/3 - speed
*/
uint8_t glorious_mode;
uint8_t glorious_direction;
uint8_t single_mode;
struct sinowealth_rbg8 single_color;
/* 0x40 - brightness (constant)
* 0x1/2/3 - speed
*/
uint8_t breathing7_mode;
uint8_t breathing7_colorcount; /* 7, constant */
struct sinowealth_rbg8 breathing7_colors[7];
/* 0x10/20/30/40 - brightness
* 0x1/2/3 - speed
*/
uint8_t tail_mode;
uint8_t unknown3[33];
/* 0x10/20/30/40 - brightness
* 0x1/2/3 - speed
*/
uint8_t rave_mode;
struct sinowealth_rbg8 rave_colors[2];
/* 0x10/20/30/40 - brightness
* 0x1/2/3 - speed
*/
uint8_t wave_mode;
/* 0x1/2/3 - speed */
uint8_t breathing1_mode;
struct sinowealth_rbg8 breathing1_color;
uint8_t unknown4;
/* 0x1 - 2 mm
* 0x2 - 3 mm
*/
uint8_t lift_off_distance;
uint8_t padding[SINOWEALTH_CONFIG_SIZE - SINOWEALTH_CONFIG_SIZE_USED];
} __attribute__((packed));
_Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
struct sinowealth_data {
/* this is kinda unnecessary at this time, but all the other drivers do it too ;) */
struct sinowealth_config_report config;
};
static int
sinowealth_raw_to_dpi(int raw)
{
return (raw + 1) * 100;
}
static int
sinowealth_dpi_to_raw(int dpi)
{
assert(dpi >= SINOWEALTH_DPI_MIN && dpi <= SINOWEALTH_DPI_MAX);
return dpi / 100 - 1;
}
static struct ratbag_color
sinowealth_raw_to_color(struct sinowealth_rgb8 raw)
{
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
}
static struct sinowealth_rgb8
sinowealth_color_to_raw(struct ratbag_color color)
{
return (struct sinowealth_rgb8) {.r = color.red, .g = color.green, .b = color.blue};
}
static struct ratbag_color
sinowealth_rbg_to_color(struct sinowealth_rbg8 raw)
{
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
}
static struct sinowealth_rbg8
sinowealth_color_to_rbg(struct ratbag_color color)
{
return (struct sinowealth_rbg8) {.r = color.red, .g = color.green, .b = color.blue};
}
static int
sinowealth_rgb_mode_to_brightness(uint8_t mode)
{
/* brightness is 0-4 in the upper nibble of mode,
* while libratbag uses 0-255.
*/
return min((mode >> 4) * 64, 255);
}
static uint8_t
sinowealth_brightness_to_rgb_mode(int brightness)
{
/* convert 0-255 to 0-4 in the upper nibble of mode */
return ((brightness + 1) / 64) << 4;
}
static int
sinowealth_rgb_mode_to_duration(uint8_t mode)
{
switch (mode & SINOWEALTH_RGB_SPEED_BITS) {
case 0: return 10000; /* static: does not translate to duration */
case 1: return 1500;
case 2: return 1000;
case 3: return 500;
default: return 0;
}
}
static uint8_t
sinowealth_duration_to_rgb_mode(int duration_ms)
{
uint8_t mode = 0;
if (duration_ms <= 500) {
mode |= 3;
} else if (duration_ms <= 1000) {
mode |= 2;
} else {
mode |= 1;
}
return mode;
}
static void
sinowealth_set_led_from_rgb_mode(struct ratbag_led *led, uint8_t mode)
{
led->brightness = sinowealth_rgb_mode_to_brightness(mode);
led->ms = sinowealth_rgb_mode_to_duration(mode);
}
static uint8_t
sinowealth_led_to_rgb_mode(const struct ratbag_led *led)
{
uint8_t mode;
mode = sinowealth_brightness_to_rgb_mode(led->brightness);
mode |= sinowealth_duration_to_rgb_mode(led->ms);
return mode;
}
static int
sinowealth_read_profile(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct sinowealth_data *drv_data = device->drv_data;
struct sinowealth_config_report *config = &drv_data->config;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
unsigned int hz = 1000; /* TODO */
int rc;
/* Print firmware version */
uint8_t version[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_FIRMWARE_VERSION};
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, version, sizeof(version));
if (rc != sizeof(version)) {
log_error(device->ratbag, "Error while sending read firmware version command: %d\n", rc);
return -1;
}
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CMD, version, sizeof(version));
if (rc != sizeof(version)) {
log_error(device->ratbag, "Could not read firmware version: %d\n", rc);
return -1;
}
log_debug(device->ratbag, "firmware version: %.4s\n", version + 2);
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_CONFIG};
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
if (rc != sizeof(cmd)) {
log_error(device->ratbag, "Error while sending read config command: %d\n", rc);
return -1;
}
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
(uint8_t*) config, SINOWEALTH_CONFIG_SIZE);
/* The GET_FEATURE report length has to be 520, but the actual data returned is less */
if (rc != SINOWEALTH_CONFIG_SIZE_USED) {
log_error(device->ratbag, "Could not read device configuration: %d\n", rc);
return -1;
}
/* TODO */
ratbag_profile_set_report_rate_list(profile, &hz, 1);
ratbag_profile_set_report_rate(profile, hz);
ratbag_profile_for_each_resolution(profile, resolution) {
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2]);
resolution->dpi_y = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2 + 1]);
} else {
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index]);
resolution->dpi_y = resolution->dpi_x;
}
if (config->dpi_enabled & (1<<resolution->index)) {
/* DPI step is disabled, fake it by setting DPI to 0 */
resolution->dpi_x = 0;
resolution->dpi_y = 0;
}
resolution->is_active = resolution->index == config->active_dpi - 1u;
resolution->is_default = resolution->is_active;
}
/* Body lighting */
led = ratbag_profile_get_led(profile, 0);
switch (config->rgb_effect) {
case RGB_OFF:
led->mode = RATBAG_LED_OFF;
break;
case RGB_SINGLE:
led->mode = RATBAG_LED_ON;
led->color = sinowealth_rbg_to_color(config->single_color);
led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode);
break;
case RGB_GLORIOUS:
case RGB_BREATHING:
case RGB_BREATHING7:
case RGB_TAIL:
case RGB_RAVE:
case RGB_WAVE:
led->mode = RATBAG_LED_CYCLE;
sinowealth_set_led_from_rgb_mode(led, config->glorious_mode);
break;
case RGB_BREATHING1:
led->mode = RATBAG_LED_BREATHING;
led->color = sinowealth_rbg_to_color(config->breathing1_color);
sinowealth_set_led_from_rgb_mode(led, config->breathing1_mode);
break;
}
ratbag_led_unref(led);
profile->is_active = true;
return 0;
}
static void
sinowealth_init_profile(struct ratbag_device *device)
{
struct ratbag_profile *profile;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
/* number of DPIs = all DPIs from min to max (inclusive) and "0 DPI" as a special value
* to signal a disabled DPI step.
*/
int num_dpis = (SINOWEALTH_DPI_MAX - SINOWEALTH_DPI_MIN) / SINOWEALTH_DPI_STEP + 2;
unsigned int dpis[num_dpis];
/* TODO: Button remapping */
ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, 0, 1);
profile = ratbag_device_get_profile(device, 0);
/* Generate DPI list */
dpis[0] = 0; /* 0 DPI = disabled */
for (int i = 1; i < num_dpis; i++) {
dpis[i] = SINOWEALTH_DPI_MIN + (i - 1) * SINOWEALTH_DPI_STEP;
}
ratbag_profile_for_each_resolution(profile, resolution) {
ratbag_resolution_set_dpi_list(resolution, dpis, num_dpis);
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
}
/* Set up LED capabilities */
led = ratbag_profile_get_led(profile, 0);
led->type = RATBAG_LED_TYPE_SIDE;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
ratbag_led_unref(led);
ratbag_profile_unref(profile);
}
static int
sinowealth_test_hidraw(struct ratbag_device *device)
{
/* Only the keyboard interface has this report */
return ratbag_hidraw_has_report(device, SINOWEALTH_REPORT_ID_CONFIG);
}
static int
sinowealth_probe(struct ratbag_device *device)
{
int rc;
struct sinowealth_data *drv_data = 0;
struct ratbag_profile *profile = 0;
rc = ratbag_find_hidraw(device, sinowealth_test_hidraw);
if (rc)
goto err;
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
sinowealth_init_profile(device);
profile = ratbag_device_get_profile(device, 0);
rc = sinowealth_read_profile(profile);
if (rc) {
rc = -ENODEV;
goto err;
}
return 0;
err:
free(drv_data);
ratbag_set_drv_data(device, 0);
return rc;
}
static int
sinowealth_commit(struct ratbag_device *device)
{
struct ratbag_profile *profile = ratbag_device_get_profile(device, 0);
struct sinowealth_data *drv_data = device->drv_data;
struct sinowealth_config_report *config = &drv_data->config;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
int rc;
uint8_t dpi_enabled = 0;
/* Check if any resolution requires independent XY DPIs */
config->config &= ~SINOWEALTH_XY_INDEPENDENT;
ratbag_profile_for_each_resolution(profile, resolution) {
if (resolution->dpi_x != resolution->dpi_y && resolution->dpi_x && resolution->dpi_y) {
config->config |= SINOWEALTH_XY_INDEPENDENT;
break;
}
}
config->dpi_count = 0;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dpi_x || !resolution->dpi_y)
continue;
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(resolution->dpi_x);
config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(resolution->dpi_y);
} else {
config->dpi[resolution->index] = sinowealth_dpi_to_raw(resolution->dpi_x);
}
dpi_enabled |= 1<<resolution->index;
config->dpi_count++;
}
config->dpi_enabled = ~dpi_enabled; /* config->dpi_enabled is inverted */
/* Body lighting */
led = ratbag_profile_get_led(profile, 0);
switch(led->mode) {
case RATBAG_LED_OFF:
config->rgb_effect = RGB_OFF;
break;
case RATBAG_LED_ON:
config->rgb_effect = RGB_SINGLE;
config->single_color = sinowealth_color_to_rbg(led->color);
break;
case RATBAG_LED_CYCLE:
config->rgb_effect = RGB_GLORIOUS;
config->glorious_mode = sinowealth_led_to_rgb_mode(led);
break;
case RATBAG_LED_BREATHING:
config->rgb_effect = RGB_BREATHING1;
config->breathing1_color = sinowealth_color_to_rbg(led->color);
config->breathing1_mode = sinowealth_led_to_rgb_mode(led);
break;
}
ratbag_led_unref(led);
config->config_write = 0x7b; /* magic */
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
(uint8_t*) config, SINOWEALTH_CONFIG_SIZE);
if (rc != SINOWEALTH_CONFIG_SIZE) {
log_error(device->ratbag, "Error while writing config: %d\n", rc);
ratbag_profile_unref(profile);
return -1;
}
ratbag_profile_unref(profile);
return 0;
}
static void
sinowealth_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
free(ratbag_get_drv_data(device));
}
struct ratbag_driver sinowealth_driver = {
.name = "Sinowealth",
.id = "sinowealth",
.probe = sinowealth_probe,
.remove = sinowealth_remove,
.commit = sinowealth_commit
};

View File

@@ -807,8 +807,12 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile
__CMD_PROFILE);
res = hidpp10_request_command(dev, &profile);
if (res)
return res;
if (res) {
/* Profiles not supported */
hidpp_log_debug(&dev->base, "Profiles not supported\n");
*current_profile = 0;
return 0;
}
type = profile.msg.parameters[0];
page = profile.msg.parameters[1];
@@ -1144,6 +1148,9 @@ hidpp10_onboard_profiles_read_macro(struct hidpp10_device *device,
}
if (rc == -ENOMEM) {
if ((unsigned) offset + mem_index > 0xff)
goto out_err;
offset += mem_index;
if (offset & 0x01)
offset--;
@@ -1198,8 +1205,10 @@ hidpp10_onboard_profiles_parse_macro(struct hidpp10_device *device,
hidpp_log_raw(&device->base, "*** macro starts at (0x%02x, 0x%04x) ***\n", page, offset);
rc = hidpp10_onboard_profiles_read_macro(device, page, offset, &macro);
if (rc)
if (rc) {
hidpp_log_raw(&device->base, "hidpp10: failed to read macro\n");
return rc;
}
count = rc;
@@ -2754,12 +2763,14 @@ hidpp10_get_device_info(struct hidpp10_device *dev)
return hidpp10_get_current_profile(dev, &current_profile);
}
struct hidpp10_device*
int
hidpp10_device_new(const struct hidpp_device *base,
int idx,
enum hidpp10_profile_type type,
unsigned int profile_count)
unsigned int profile_count,
struct hidpp10_device **out)
{
int rc;
struct hidpp10_device *dev;
dev = zalloc(sizeof(*dev));
@@ -2770,12 +2781,14 @@ hidpp10_device_new(const struct hidpp_device *base,
dev->profile_count = profile_count;
dev->profiles = zalloc(dev->profile_count * sizeof(struct hidpp10_profile));
if (hidpp10_get_device_info(dev) != 0) {
if ((rc = hidpp10_get_device_info(dev)) != 0) {
hidpp10_device_destroy(dev);
dev = NULL;
}
return dev;
*out = dev;
return rc;
}
int

View File

@@ -69,11 +69,12 @@ struct hidpp10_device {
unsigned int profile_count;
};
struct hidpp10_device*
int
hidpp10_device_new(const struct hidpp_device *base,
int idx,
enum hidpp10_profile_type type,
unsigned int profile_count);
unsigned int profile_count,
struct hidpp10_device **out);
int
hidpp10_device_read_profiles(struct hidpp10_device *dev);

View File

@@ -260,7 +260,7 @@ hidpp_root_get_feature(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = HIDPP_PAGE_ROOT_IDX,
.msg.address = CMD_ROOT_GET_FEATURE,
@@ -287,7 +287,7 @@ hidpp20_root_get_protocol_version(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = HIDPP_PAGE_ROOT_IDX,
.msg.address = CMD_ROOT_GET_PROTOCOL_VERSION,
@@ -321,7 +321,7 @@ hidpp20_feature_set_get_count(struct hidpp20_device *device, uint8_t reg)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_FEATURE_SET_GET_COUNT,
@@ -343,7 +343,7 @@ hidpp20_feature_set_get_feature_id(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_FEATURE_SET_GET_FEATURE_ID,
@@ -429,7 +429,7 @@ hidpp20_batterylevel_get_battery_level(struct hidpp20_device *device,
{
uint8_t feature_index;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
};
@@ -566,7 +566,7 @@ int hidpp20_led_sw_control_get_led_count(struct hidpp20_device* device)
{
union hidpp20_message msg = {
.msg = {
.report_id = REPORT_ID_LONG,
.report_id = REPORT_ID_SHORT,
.address = CMD_LED_SW_CONTROL_GET_LED_COUNT,
.device_idx = device->index,
},
@@ -594,7 +594,7 @@ int hidpp20_led_sw_control_get_led_info(struct hidpp20_device* device,
{
union hidpp20_message msg = {
.msg = {
.report_id = REPORT_ID_LONG,
.report_id = REPORT_ID_SHORT,
.address = CMD_LED_SW_CONTROL_GET_LED_INFO,
.device_idx = device->index,
},
@@ -682,7 +682,7 @@ int hidpp20_led_sw_control_get_led_state(struct hidpp20_device* device,
uint8_t feature_idx;
union hidpp20_message msg = {
.msg = {
.report_id = REPORT_ID_LONG,
.report_id = REPORT_ID_SHORT,
.address = CMD_LED_SW_CONTROL_GET_LED_STATE,
.device_idx = device->index,
}
@@ -767,7 +767,7 @@ static int
hidpp20_kbd_reprogrammable_keys_get_count(struct hidpp20_device *device, uint8_t reg)
{
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_KBD_REPROGRAMMABLE_KEYS_GET_COUNT,
@@ -788,7 +788,7 @@ hidpp20_kbd_reprogrammable_keys_get_info(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_KBD_REPROGRAMMABLE_KEYS_GET_CTRL_ID_INFO,
@@ -908,7 +908,7 @@ hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device,
int rc;
struct hidpp20_color_led_zone_info *msg_info;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_COLOR_LED_EFFECTS_GET_ZONE_INFO,
@@ -1022,7 +1022,7 @@ hidpp20_color_led_effects_set_zone_effect(struct hidpp20_device *device,
{
uint8_t feature_index;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.report_id = REPORT_ID_LONG,
.msg.address = CMD_COLOR_LED_EFFECTS_SET_ZONE_EFFECT,
.msg.device_idx = device->index,
.msg.parameters[0] = zone_index,
@@ -1109,7 +1109,7 @@ hidpp20_rgb_effects_get_device_info(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_RGB_EFFECTS_GET_INFO,
.msg.parameters[0] = HIDPP20_RGB_EFFECTS_INDEX_ALL,
@@ -1146,7 +1146,7 @@ hidpp20_rgb_effects_get_cluster_info(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_RGB_EFFECTS_GET_INFO,
.msg.parameters[0] = cluster_index,
@@ -1229,7 +1229,7 @@ hidpp20_rgb_effects_get_effect_info(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_RGB_EFFECTS_GET_INFO,
.msg.parameters[0] = cluster_index,
@@ -1273,7 +1273,7 @@ hidpp20_special_keys_buttons_get_count(struct hidpp20_device *device, uint8_t re
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_SPECIAL_KEYS_BUTTONS_GET_COUNT,
@@ -1293,7 +1293,7 @@ hidpp20_special_keys_buttons_get_info(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_SPECIAL_KEYS_BUTTONS_GET_INFO,
@@ -1323,7 +1323,7 @@ hidpp20_special_keys_buttons_get_reporting(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_SPECIAL_KEYS_BUTTONS_GET_REPORTING,
@@ -1464,7 +1464,7 @@ hidpp20_mousepointer_get_mousepointer_info(struct hidpp20_device *device,
{
uint8_t feature_index;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_MOUSE_POINTER_BASIC_GET_INFO,
};
@@ -1501,7 +1501,7 @@ hidpp20_adjustable_dpi_get_count(struct hidpp20_device *device, uint8_t reg)
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_ADJUSTABLE_DPI_GET_SENSOR_COUNT,
@@ -1522,7 +1522,7 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
int rc;
unsigned i = 1, dpi_index = 0;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI_LIST,
@@ -1570,7 +1570,7 @@ hidpp20_adjustable_dpi_get_dpi(struct hidpp20_device *device,
{
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.sub_id = reg,
.msg.address = CMD_ADJUSTABLE_DPI_GET_SENSOR_DPI,
@@ -1653,7 +1653,7 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
uint16_t returned_parameters;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ADJUSTABLE_DPI_SET_SENSOR_DPI,
.msg.parameters[0] = sensor->index,
@@ -1698,10 +1698,9 @@ int hidpp20_adjustable_report_rate_get_report_rate_list(struct hidpp20_device *d
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_LONG,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ADJUSTABLE_REPORT_RATE_GET_REPORT_RATE_LIST,
.msg.parameters[0] = 0,
};
feature_index = hidpp_root_get_feature_idx(device,
@@ -2593,6 +2592,7 @@ hidpp20_buttons_to_cpu(struct hidpp20_device *device,
case HIDPP20_BUTTON_DISABLED:
break;
default:
memcpy(b, button, sizeof(*b));
break;
}
}
@@ -2643,6 +2643,7 @@ hidpp20_buttons_from_cpu(struct hidpp20_profile *profile,
button->macro.zero = 0;
break;
default:
memcpy(b, button, sizeof(*b));
break;
}
}

View File

@@ -577,14 +577,42 @@ enum hidpp20_color_led_zone_effect {
#define HIDPP_PAGE_ONBOARD_PROFILES 0x8100
/* type */
#define HIDPP20_BUTTON_HID_TYPE 0x80
#define HIDPP20_BUTTON_SPECIAL 0x90
/* standard opcodes (0x80) */
#define HIDPP20_BUTTON_HID_TYPE_NOOP 0x00
#define HIDPP20_BUTTON_HID_TYPE_MOUSE 0x01
#define HIDPP20_BUTTON_HID_TYPE_KEYBOARD 0x02
#define HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL 0x03
#define HIDPP20_BUTTON_SPECIAL 0x90
/* special opcodes (0x90) */
#define HIDPP20_BUTTON_SPECIAL_NOOP 0x00
#define HIDPP20_BUTTON_SPECIAL_TILT_LEFT 0x01
#define HIDPP20_BUTTON_SPECIAL_TILT_RIGHT 0x02
#define HIDPP20_BUTTON_SPECIAL_NEXT_DPI 0x03
#define HIDPP20_BUTTON_SPECIAL_PREV_DPI 0x04
#define HIDPP20_BUTTON_SPECIAL_CYCLE_DPI 0x05
#define HIDPP20_BUTTON_SPECIAL_DEFAULT_DPI 0x06
#define HIDPP20_BUTTON_SPECIAL_SHIFT_DPI 0x07
#define HIDPP20_BUTTON_SPECIAL_NEXT_PROFILE 0x08
#define HIDPP20_BUTTON_SPECIAL_PREV_PROFILE 0x09
#define HIDPP20_BUTTON_SPECIAL_CYCLE_PROFILE 0x0a
#define HIDPP20_BUTTON_SPECIAL_GSHIFT 0x0b
/* memory model >= 3 */
#define HIDPP20_BUTTON_SPECIAL_BATTERY_INDICATOR 0x0c
#define HIDPP20_BUTTON_SPECIAL_ENABLE_PROFILE 0x0d
#define HIDPP20_BUTTON_SPECIAL_PERFORMANCE_SWITCH 0x0e
#define HIDPP20_BUTTON_SPECIAL_HOST 0x0f
#define HIDPP20_BUTTON_SPECIAL_SCROLL_DOWN 0x10
#define HIDPP20_BUTTON_SPECIAL_SCROLL_UP 0x11
/* buttons */
#define HIDPP20_BUTTON_MACRO 0x00
#define HIDPP20_BUTTON_DISABLED 0xFF
/* modifiers */
#define HIDPP20_MODIFIER_KEY_CTRL 0x01
#define HIDPP20_MODIFIER_KEY_SHIFT 0x02
@@ -792,12 +820,32 @@ struct hidpp20_led {
uint8_t original[sizeof(struct hidpp20_internal_led)];
};
#define HIDPP20_MACRO_NOOP 0x01
/* macro opcodes */
/* control commands */
#define HIDPP20_MACRO_WAIT_FOR_RELEASE 0x01
#define HIDPP20_MACRO_REPEAT_WHILE_PRESSED 0x02
#define HIDPP20_MACRO_REPEAT_UNTIL_CANCELED 0x03
#define HIDPP20_MACRO_END 0xff
/* delay & jump commands */
#define HIDPP20_MACRO_NOOP 0x00 /* wait the duration of a macro step */
#define HIDPP20_MACRO_DELAY 0x40
#define HIDPP20_MACRO_JUMP 0x60
/* button & key event generation */
#define HIDPP20_MACRO_BUTTON_DOWN 0x41
#define HIDPP20_MACRO_BUTTON_UP 0x42
#define HIDPP20_MACRO_KEY_PRESS 0x43
#define HIDPP20_MACRO_KEY_RELEASE 0x44
#define HIDPP20_MACRO_JUMP 0x60
#define HIDPP20_MACRO_END 0xff
#define HIDPP20_MACRO_CONS_DOWN 0x45
#define HIDPP20_MACRO_CONS_UP 0x46
/* analog commands */
#define HIDPP20_MACRO_ROLLER 0x20
#define HIDPP20_MACRO_ACPAN 0x21
#define HIDPP20_MACRO_XY 0x61
union hidpp20_macro_data {
struct {

View File

@@ -140,20 +140,21 @@ hidraw_is_receiver(int fd)
return true;
}
static struct hidpp10_device *
hidpp10_init(int fd)
static int
hidpp10_init(int fd, struct hidpp10_device **out)
{
struct hidpp_device base;
hidpp_device_init(&base, fd);
return hidpp10_device_new(&base, HIDPP_RECEIVER_IDX,
HIDPP10_PROFILE_UNKNOWN, 1);
HIDPP10_PROFILE_UNKNOWN, 1, out);
}
_EXPORT_ int
lur_receiver_new_from_hidraw(int fd, void *userdata, struct lur_receiver **out)
{
int rc;
struct lur_receiver *receiver;
if (!hidraw_is_receiver(fd))
@@ -165,8 +166,8 @@ lur_receiver_new_from_hidraw(int fd, void *userdata, struct lur_receiver **out)
receiver->userdata = userdata;
list_init(&receiver->devices);
receiver->hidppdev = hidpp10_init(fd);
if (!receiver->hidppdev)
rc = hidpp10_init(fd, &receiver->hidppdev);
if (rc)
goto error;
*out = receiver;
@@ -174,8 +175,7 @@ lur_receiver_new_from_hidraw(int fd, void *userdata, struct lur_receiver **out)
error:
free(receiver);
return -errno;
return rc;
}
_EXPORT_ int
@@ -203,7 +203,7 @@ lur_receiver_enumerate(struct lur_receiver *lur,
uint32_t serial;
bool is_new_device = true;
d = hidpp10_device_new(&base, i, HIDPP10_PROFILE_UNKNOWN, 1);
rc = hidpp10_device_new(&base, i, HIDPP10_PROFILE_UNKNOWN, 1, &d);
if (!d)
continue;

View File

@@ -34,6 +34,7 @@
#include "libratbag-private.h"
#include "libratbag-data.h"
#include "hidpp20.h"
#include "usb-ids.h"
#define GROUP_DEVICE "Device"
@@ -51,11 +52,15 @@ enum driver {
LOGITECH_G300,
LOGITECH_G600,
STEELSERIES,
SINOWEALTH,
SINOWEALTH_NUBWO,
OPENINPUT,
};
struct data_hidpp20 {
int index;
enum hidpp20_quirk quirk;
int led_count;
};
struct data_hidpp10 {
@@ -157,6 +162,7 @@ init_data_hidpp20(struct ratbag *ratbag,
char *str;
data->hidpp20.index = -1;
data->hidpp20.led_count = -1;
num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error);
if (num != 0 || !error)
@@ -164,6 +170,13 @@ init_data_hidpp20(struct ratbag *ratbag,
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
if (!error)
data->hidpp20.led_count = num;
if (error)
g_error_free(error);
str = g_key_file_get_string(keyfile, group, "Quirk", NULL);
data->hidpp20.quirk = HIDPP20_QUIRK_NONE;
if (str) {
@@ -258,6 +271,9 @@ static const struct driver_map {
{ LOGITECH_G300, "logitech_g300", NULL},
{ LOGITECH_G600, "logitech_g600", NULL},
{ STEELSERIES, "steelseries", init_data_steelseries },
{ SINOWEALTH, "sinowealth", NULL },
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
{ OPENINPUT, "openinput", NULL },
};
const char *
@@ -504,7 +520,9 @@ ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
goto out;
}
if (!data)
if (id->vendor == USB_VENDOR_ID_LOGITECH && (id->product & 0xff00) == 0xc500)
log_debug(ratbag, "%04x:%04x is a Logitech receiver, not a device. Ignoring...\n", id->vendor, id->product);
else if (!data)
log_debug(ratbag, "No data file found for %04x:%04x\n", id->vendor, id->product);
out:
@@ -576,6 +594,14 @@ ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data)
return data->hidpp20.index;
}
int
ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == HIDPP20);
return data->hidpp20.led_count;
}
enum hidpp20_quirk
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data)
{

View File

@@ -80,6 +80,9 @@ ratbag_device_data_hidpp10_get_led_count(const struct ratbag_device_data *data);
int
ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data);
int
ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data);
enum hidpp20_quirk
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data);

View File

@@ -23,6 +23,7 @@
#pragma once
#include "config.h"
#include <linux/input.h>
#include <stdint.h>
#include <stdbool.h>
@@ -594,6 +595,9 @@ extern struct ratbag_driver logitech_g600_driver;
extern struct ratbag_driver roccat_driver;
extern struct ratbag_driver gskill_driver;
extern struct ratbag_driver steelseries_driver;
extern struct ratbag_driver sinowealth_driver;
extern struct ratbag_driver sinowealth_nubwo_driver;
extern struct ratbag_driver openinput_driver;
struct ratbag_device*
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,

View File

@@ -37,6 +37,8 @@
#include <stdlib.h>
#include <iconv.h>
#include <errno.h>
#include <libgen.h>
#include <sys/stat.h>
#include "libratbag-util.h"
#include "libratbag-private.h"
@@ -188,3 +190,18 @@ err:
iconv_close(converter);
return ret;
}
int mkdir_p(char *dir, mode_t mode)
{
struct stat sb;
if (!dir)
return EINVAL;
if (!stat(dir, &sb))
return 0;
mkdir_p(dirname(strdupa(dir)), mode);
return mkdir(dir, mode);
}

View File

@@ -62,6 +62,8 @@ int list_empty(const struct list *list);
pos = tmp, \
tmp = container_of(pos->member.next, tmp, member))
int mkdir_p(char *dir, mode_t mode);
static inline char*
strncpy_safe(char *dest, const char *src, size_t n)
{

View File

@@ -602,6 +602,9 @@ ratbag_create_context(const struct ratbag_interface *interface,
ratbag_register_driver(ratbag, &roccat_driver);
ratbag_register_driver(ratbag, &gskill_driver);
ratbag_register_driver(ratbag, &steelseries_driver);
ratbag_register_driver(ratbag, &sinowealth_driver);
ratbag_register_driver(ratbag, &sinowealth_nubwo_driver);
ratbag_register_driver(ratbag, &openinput_driver);
return ratbag;
}

View File

@@ -98,7 +98,9 @@ main(int argc, char **argv)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp10_device_new(&base, HIDPP_WIRED_DEVICE_IDX, HIDPP10_PROFILE_UNKNOWN, 5);
rc = hidpp10_device_new(&base, HIDPP_WIRED_DEVICE_IDX, HIDPP10_PROFILE_UNKNOWN, 5, &dev);
if (rc)
return rc;
if (argc == 2)
rc = dump_all_pages(dev);

View File

@@ -193,14 +193,18 @@ def print_profile(d, p, level):
" (active)" if p.is_active else ""))
if p.enabled:
print(" " * level + "Name: {}".format(p.name or 'n/a'))
print(" " * level + "Report Rate: {}Hz".format(p.report_rate))
print(" " * level + "Resolutions:")
for r in p.resolutions:
print_resolution(d, p, r, level + 2)
for b in p.buttons:
print_button(d, p, b, level)
for l in p.leds:
print_led(d, p, l, level)
if p.report_rate:
print(" " * level + "Report Rate: {}Hz".format(p.report_rate))
if p.resolutions:
print(" " * level + "Resolutions:")
for r in p.resolutions:
print_resolution(d, p, r, level + 2)
if p.buttons:
for b in p.buttons:
print_button(d, p, b, level)
if p.leds:
for l in p.leds:
print_led(d, p, l, level)
def print_device(d, level):

View File

@@ -193,7 +193,7 @@ class _RatbagdDBus(GObject.GObject):
# args to .Set are "interface name", "function name", value-variant
val = GLib.Variant("{}".format(type), value)
if readwrite:
pval = GLib.Variant("(ssv)".format(type), (self._interface, property, val))
pval = GLib.Variant("(ssv)", (self._interface, property, val))
self._proxy.call_sync("org.freedesktop.DBus.Properties.Set",
pval, Gio.DBusCallFlags.NO_AUTO_START,
2000, None)