forked from drath/libratbag
Compare commits
234 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1231415470 | ||
|
|
660da27021 | ||
|
|
481b6f029a | ||
|
|
768d93a45a | ||
|
|
1c6e039d01 | ||
|
|
d16df8d100 | ||
|
|
4b1e49d522 | ||
|
|
786cebcb0b | ||
|
|
d53454bcb3 | ||
|
|
a0def65b64 | ||
|
|
2a40279903 | ||
|
|
02c95422f0 | ||
|
|
4ce1cf2807 | ||
|
|
89168f2187 | ||
|
|
bb92337268 | ||
|
|
a8316c07f3 | ||
|
|
39769c57dd | ||
|
|
200a8af7a7 | ||
|
|
fcf9f7745d | ||
|
|
633c9fc55d | ||
|
|
ee73434ead | ||
|
|
d60b1c9d71 | ||
|
|
88a60f55b4 | ||
|
|
dba202ae8b | ||
|
|
6cdcce9de4 | ||
|
|
e2c3373145 | ||
|
|
02575a9008 | ||
|
|
1097b1ba68 | ||
|
|
77b67775da | ||
|
|
5b23c9ebae | ||
|
|
6d0974be25 | ||
|
|
ea9111a2a6 | ||
|
|
42787ee422 | ||
|
|
611dd9be0d | ||
|
|
fd20f9e642 | ||
|
|
9be5576967 | ||
|
|
9fe511fcc5 | ||
|
|
f0b69aab19 | ||
|
|
7610b80ced | ||
|
|
f0a05bb522 | ||
|
|
2669cc28b2 | ||
|
|
302702d94a | ||
|
|
e1136c4d30 | ||
|
|
0012853a1d | ||
|
|
afb85f868c | ||
|
|
b76fcdadde | ||
|
|
ba7c092ee2 | ||
|
|
3483bd8c14 | ||
|
|
0fb0eb3d42 | ||
|
|
5fb1f4429d | ||
|
|
5f5e294598 | ||
|
|
b4218737cd | ||
|
|
3875bb70fd | ||
|
|
e9d67b7235 | ||
|
|
8a476a8724 | ||
|
|
d67cbec5f8 | ||
|
|
f82c6f72b6 | ||
|
|
af30fc28cd | ||
|
|
3fb8a51456 | ||
|
|
ceaa3c3ad5 | ||
|
|
551b918ba8 | ||
|
|
3105428ba1 | ||
|
|
b3f2406180 | ||
|
|
902160f430 | ||
|
|
fd6d0b6198 | ||
|
|
5ed98fdb22 | ||
|
|
e0e73c2971 | ||
|
|
0d3b4f1b64 | ||
|
|
20b6e3deeb | ||
|
|
ffcdee912d | ||
|
|
5357d4cbc2 | ||
|
|
26c534cc74 | ||
|
|
904c7988bb | ||
|
|
7d255a2f93 | ||
|
|
d0a5cb1f0e | ||
|
|
71b1d66287 | ||
|
|
32ebbca42f | ||
|
|
a0afbfeb3f | ||
|
|
9dfd4fd03a | ||
|
|
b0ea75979a | ||
|
|
a5c1ca202e | ||
|
|
8d40ad6c0c | ||
|
|
72d11de597 | ||
|
|
47cc5fce92 | ||
|
|
5da791b268 | ||
|
|
e63802b01a | ||
|
|
cd89b123ce | ||
|
|
f6546b3222 | ||
|
|
cd8ddc8444 | ||
|
|
cdb3226ef1 | ||
|
|
ce377fc36c | ||
|
|
fe1308fe38 | ||
|
|
983d3e2a88 | ||
|
|
3a3d9e1148 | ||
|
|
afbba26feb | ||
|
|
8cc37047fb | ||
|
|
c8f56cc535 | ||
|
|
b6936ddd3b | ||
|
|
d4d9712316 | ||
|
|
2353af214b | ||
|
|
a4d19efb93 | ||
|
|
cb0b458824 | ||
|
|
48c476b28c | ||
|
|
d6c3bf881d | ||
|
|
1b000e627a | ||
|
|
75bcf39114 | ||
|
|
33ced3dfb7 | ||
|
|
906f17add2 | ||
|
|
016de548fc | ||
|
|
665c022382 | ||
|
|
81c7b42bec | ||
|
|
edb054c6f8 | ||
|
|
8ae995b72d | ||
|
|
a941b75ef2 | ||
|
|
8cb85da6be | ||
|
|
7ff59a636f | ||
|
|
6cd050f541 | ||
|
|
ab3f1df06e | ||
|
|
caa31e17cf | ||
|
|
b7e6103496 | ||
|
|
b1b6a2761e | ||
|
|
11f4f32947 | ||
|
|
4f5d0dffec | ||
|
|
d213bdb86e | ||
|
|
e69e1de17b | ||
|
|
cad05ffced | ||
|
|
196d53e65f | ||
|
|
c606b1abe3 | ||
|
|
b4009669b9 | ||
|
|
d458305f93 | ||
|
|
9c11960665 | ||
|
|
e8fc8b45d1 | ||
|
|
e64a121572 | ||
|
|
607e47953c | ||
|
|
a5816055dc | ||
|
|
62ac0772f5 | ||
|
|
fc9e63a5aa | ||
|
|
936a8f7a92 | ||
|
|
818e665853 | ||
|
|
3a3b11ade4 | ||
|
|
3bc31edd72 | ||
|
|
485df20a83 | ||
|
|
49291c4b45 | ||
|
|
02ec2442d3 | ||
|
|
a8b4d9c6f3 | ||
|
|
22a6ac1c7e | ||
|
|
42c302c860 | ||
|
|
e2b1581aef | ||
|
|
10a3e87980 | ||
|
|
2d465a63e1 | ||
|
|
c2315323f4 | ||
|
|
05d7e9b324 | ||
|
|
71a399f20f | ||
|
|
8259c2e706 | ||
|
|
89980a4a72 | ||
|
|
79e94b4a7e | ||
|
|
122f05c272 | ||
|
|
b06ac1035e | ||
|
|
647fe432b2 | ||
|
|
4e2e9f037b | ||
|
|
f92fee0b15 | ||
|
|
d7c394f379 | ||
|
|
7fec19f8f2 | ||
|
|
11c1e2d71a | ||
|
|
e2cbaf9dea | ||
|
|
bf9d86e228 | ||
|
|
f24a3bd441 | ||
|
|
df5742ebfe | ||
|
|
0c569e0bf7 | ||
|
|
5ea1731f38 | ||
|
|
572064aba8 | ||
|
|
da2764e78d | ||
|
|
4e56afae22 | ||
|
|
d46251900c | ||
|
|
43def1b3a5 | ||
|
|
247ff7695d | ||
|
|
7a14026f2d | ||
|
|
55925db29e | ||
|
|
87d4aed3ad | ||
|
|
7de944aaa0 | ||
|
|
488774d3ba | ||
|
|
0673af2991 | ||
|
|
0e84b63921 | ||
|
|
6e34f314f8 | ||
|
|
e3268f2ce6 | ||
|
|
47623654d0 | ||
|
|
94423769b9 | ||
|
|
4efe8f4830 | ||
|
|
ac06e7d0c8 | ||
|
|
f534cb55b0 | ||
|
|
bb3f386cca | ||
|
|
6393338d0f | ||
|
|
b225e4bd80 | ||
|
|
635257d6b8 | ||
|
|
b31a8c5355 | ||
|
|
412f3fef87 | ||
|
|
8f88573a08 | ||
|
|
c1265bc98a | ||
|
|
723d394c02 | ||
|
|
808f423600 | ||
|
|
ae9c639a74 | ||
|
|
932cbf0a5c | ||
|
|
486842b6cb | ||
|
|
2ae8233eeb | ||
|
|
cdd70105b5 | ||
|
|
6babb7b307 | ||
|
|
26843861c0 | ||
|
|
2eed8dbb92 | ||
|
|
a13ee32c61 | ||
|
|
dbe98ed5b9 | ||
|
|
c425780220 | ||
|
|
1e9839cb67 | ||
|
|
bbeaef749e | ||
|
|
240231b065 | ||
|
|
6f27053ab0 | ||
|
|
fc16a8dc7c | ||
|
|
6256e9046f | ||
|
|
563550c473 | ||
|
|
a04f2d1c24 | ||
|
|
d86933d746 | ||
|
|
55f7d75567 | ||
|
|
6ee1c0a591 | ||
|
|
94d32930e2 | ||
|
|
2b2d8e8980 | ||
|
|
10305a123c | ||
|
|
11db35edba | ||
|
|
836922b133 | ||
|
|
4d00a815a4 | ||
|
|
0e28d82a16 | ||
|
|
336440cddb | ||
|
|
b2a3d39122 | ||
|
|
4b7b9d2e48 | ||
|
|
57097ceddb | ||
|
|
c7ce1a96a7 |
@@ -1,5 +1,12 @@
|
||||
# vim: set expandtab shiftwidth=2 tabstop=8:
|
||||
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 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:
|
||||
@@ -13,6 +20,18 @@ libratbag_references:
|
||||
ninja -v -C build ${NINJA_ARGS}
|
||||
environment:
|
||||
MESON_PARAMS: --prefix=/usr
|
||||
build_buildtype_plain: &build_buildtype_plain
|
||||
run:
|
||||
<<: *build_default
|
||||
name: Build with buildtype plain
|
||||
environment:
|
||||
MESON_PARAMS: --prefix=/usr -Dbuildtype=plain
|
||||
build_buildtype_release: &build_buildtype_release
|
||||
run:
|
||||
<<: *build_default
|
||||
name: Build with buildtype release
|
||||
environment:
|
||||
MESON_PARAMS: --prefix=/usr -Dbuildtype=release
|
||||
build_and_test: &build_and_test
|
||||
run:
|
||||
<<: *build_default
|
||||
@@ -34,16 +53,13 @@ libratbag_references:
|
||||
name: Checking installation
|
||||
command: |
|
||||
PREFIX=/usr/local/
|
||||
diff -u <(cd data/devices; ls *.device) <(cd $PREFIX/share/libratbag/devices; ls *.device)
|
||||
diff -u <(cd data/devices; ls *.device) <(cd $PREFIX/share/libratbag; ls *.device)
|
||||
check_uninstall: &check_uninstall
|
||||
run:
|
||||
name: Checking if any files are left after uninstall
|
||||
command: |
|
||||
PREFIX=/root/test_install
|
||||
# workaround until https://github.com/mesonbuild/meson/pull/2033 is merged
|
||||
# and a new release appears
|
||||
git clone https://github.com/whot/meson -b wip/remove-directories-on-uninstall
|
||||
./meson/meson.py build_install --prefix=$PREFIX
|
||||
meson build_install --prefix=$PREFIX
|
||||
ninja -C build_install install
|
||||
ninja -C build_install uninstall
|
||||
if [ -d $PREFIX ]
|
||||
@@ -61,33 +77,34 @@ 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 libsolv tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel valgrind python3-gobject python3-evdev glib2-devel python3-lxml
|
||||
- persist_to_workspace:
|
||||
root: /var/cache/
|
||||
paths:
|
||||
- dnf/*
|
||||
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:
|
||||
name: Install prerequisites
|
||||
command: |
|
||||
echo keepcache=1 >> /etc/dnf/dnf.conf
|
||||
dnf upgrade -y libsolv
|
||||
dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel valgrind python3-gobject python3-evdev glib2-devel python3-lxml python3-devel swig
|
||||
|
||||
dnf install -y git ${FEDORA_DEP_BUILD} ${FEDORA_DEP_TEST}
|
||||
sed -i 's/systemd//' /etc/nsswitch.conf
|
||||
|
||||
fedora_settings: &fedora_settings
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- *save_date
|
||||
- *fedora_fetch_cache
|
||||
- *fedora_install
|
||||
- checkout
|
||||
@@ -96,8 +113,42 @@ fedora_settings: &fedora_settings
|
||||
- *install
|
||||
- *check_install
|
||||
- *check_uninstall
|
||||
- *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
|
||||
|
||||
ubuntu_settings: &ubuntu_settings
|
||||
<<: *default_settings
|
||||
@@ -107,16 +158,21 @@ ubuntu_settings: &ubuntu_settings
|
||||
command: |
|
||||
apt-get update
|
||||
apt-get install -y software-properties-common
|
||||
apt-get remove -y libnss-systemd
|
||||
add-apt-repository universe
|
||||
apt-get update
|
||||
apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev valgrind python3-gi python3-evdev libglib2.0-dev python3-lxml python3-dev swig systemd
|
||||
apt-get install -y git ${UBUNTU_DEP_BUILD} ${UBUNTU_DEP_TEST}
|
||||
- checkout
|
||||
- *start_dbus
|
||||
- *build_and_test
|
||||
- *install
|
||||
- *check_install
|
||||
- *check_uninstall
|
||||
- *build_buildtype_plain
|
||||
- *build_buildtype_release
|
||||
- *export_logs
|
||||
environment:
|
||||
*build_dependencies
|
||||
|
||||
doc_build: &doc_build
|
||||
<<: *default_settings
|
||||
@@ -125,7 +181,7 @@ doc_build: &doc_build
|
||||
- *fedora_install
|
||||
- run:
|
||||
name: Install documentation build-deps
|
||||
command: dnf install -y python3-sphinx python3-sphinx_rtd_theme
|
||||
command: dnf install -y ${FEDORA_DEP_DOC}
|
||||
- checkout
|
||||
- *build_with_docs
|
||||
- *export_logs
|
||||
@@ -135,6 +191,8 @@ doc_build: &doc_build
|
||||
root: build
|
||||
paths:
|
||||
- doc/html/*
|
||||
environment:
|
||||
*build_dependencies
|
||||
|
||||
docs_deploy: &docs_deploy
|
||||
<<: *default_settings
|
||||
@@ -176,48 +234,38 @@ docs_deploy: &docs_deploy
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
fedora_rawhide:
|
||||
fedora_31:
|
||||
<<: *fedora_settings
|
||||
docker:
|
||||
- image: fedora:rawhide
|
||||
fedora_cache:
|
||||
<<: *fedora_prep_cache
|
||||
- image: fedora:31
|
||||
arch:
|
||||
<<: *arch_settings
|
||||
docker:
|
||||
- image: fedora:28
|
||||
fedora_latest:
|
||||
<<: *fedora_settings
|
||||
docker:
|
||||
- image: fedora:28
|
||||
ubuntu_17_10:
|
||||
- image: archlinux
|
||||
ubuntu_19_10:
|
||||
<<: *ubuntu_settings
|
||||
docker:
|
||||
- image: ubuntu:artful
|
||||
- image: ubuntu:19.10
|
||||
doc_build:
|
||||
<<: *doc_build
|
||||
docker:
|
||||
- image: fedora:28
|
||||
- image: fedora:31
|
||||
doc_deploy:
|
||||
<<: *docs_deploy
|
||||
docker:
|
||||
- image: fedora:28
|
||||
- image: fedora:31
|
||||
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
compile_and_test:
|
||||
jobs:
|
||||
# - fedora_rawhide
|
||||
- fedora_cache
|
||||
- ubuntu_17_10
|
||||
- fedora_latest:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- doc_build:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- ubuntu_19_10
|
||||
- arch
|
||||
- fedora_31
|
||||
- doc_build
|
||||
- doc_deploy:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- doc_build
|
||||
filters:
|
||||
branches:
|
||||
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@@ -0,0 +1,20 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{c,h}]
|
||||
indent_style = tab
|
||||
tab_width = 8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.{py,py.in},tools/ratbagctl.*.in}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{yml,xsl}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Information**
|
||||
<!-- If your issue is related to a Logitech device please make sure you are running at least Linux 5.2 -->
|
||||
- `ratbagd` version (`ratbagd --version`):
|
||||
- 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.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Logs**
|
||||
Please start the daemon with verbosity and reproduce the issue.
|
||||
|
||||
First make sure it isn't running already.
|
||||
```
|
||||
$ ratbagd --verbose=raw
|
||||
OUTPUT HERE
|
||||
```
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
*.o
|
||||
*.pc
|
||||
*.swp
|
||||
*~
|
||||
*.sig
|
||||
*.tar.*
|
||||
*.announce
|
||||
*.patch
|
||||
*.rej
|
||||
*.trs
|
||||
tags
|
||||
@@ -3,9 +3,10 @@ libratbag
|
||||
|
||||
<img src="https://libratbag.github.io/_images/logo.svg" alt="" width="30%" align="right">
|
||||
|
||||
libratbag provides **ratbagd**, a DBus daemon to configure gaming mice.
|
||||
The daemon provides a generic way to access the various features exposed by
|
||||
these mice and abstracts away hardware-specific and kernel-specific quirks.
|
||||
libratbag provides **ratbagd**, a DBus daemon to configure input devices,
|
||||
mainly gaming mice. The daemon provides a generic way to access the various
|
||||
features exposed by these mice and abstracts away hardware-specific and
|
||||
kernel-specific quirks.
|
||||
|
||||
libratbag currently supports devices from Logitech, Etekcity, GSkill,
|
||||
Roccat, Steelseries. See [the device
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
libratbag data files
|
||||
====================
|
||||
|
||||
This directory contains the SVG files for each theme. In general, device SVGs
|
||||
should approximate the device to make it immediately recognizable. Detail work
|
||||
not required, the graphic is an illustration only.
|
||||
|
||||
For theme-specific requirements, consult the README in the subdirectories.
|
||||
|
||||
Technique
|
||||
---------
|
||||
|
||||
The simplest approach is to find a photo of the device and import it into
|
||||
inkscape. Put it on the lowest layer, create a new layer "Device" above it
|
||||
and start tracing the outlines and edges of the device. Fill in the shapes
|
||||
and your device should resemble the underlying photo. Delete the photo
|
||||
layer, add leaders and button labels and you're done.
|
||||
11
data/devices/README.md
Normal file
11
data/devices/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
libratbag data files
|
||||
====================
|
||||
|
||||
This directory contains the data files for each supported device. libratbag
|
||||
reads these files to identify the backend driver for any given device. If a
|
||||
device is not listed, libratbag will not support it.
|
||||
|
||||
See the device.example file for instructions on the various options.
|
||||
|
||||
See the libratbag wiki for more information:
|
||||
https://github.com/libratbag/libratbag/wiki/Adding-a-device/
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim: set expandtab shiftwidth=4 tabstop=4:
|
||||
#
|
||||
# Copyright © 2017 Red Hat, Inc.
|
||||
#
|
||||
@@ -26,8 +25,9 @@
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import configparser
|
||||
import re
|
||||
|
||||
|
||||
def assertIn(element, l):
|
||||
if element not in l:
|
||||
@@ -57,11 +57,11 @@ def check_match_str(string):
|
||||
|
||||
|
||||
def check_ledtypes_str(string):
|
||||
permitted_types = ['logo', 'side', 'battery', 'dpi']
|
||||
permitted_types = ['logo', 'side', 'battery', 'dpi', 'switches']
|
||||
|
||||
types = string.split(';')
|
||||
for t in types:
|
||||
if not t: # emtpy string if trailing ;
|
||||
if not t: # emtpy string if trailing ;
|
||||
continue
|
||||
|
||||
assertIn(t, permitted_types)
|
||||
@@ -88,7 +88,7 @@ def check_section_device(section):
|
||||
def check_dpi_range_str(string):
|
||||
import re
|
||||
|
||||
m = re.search('^([0-9]+):([0-9]+)@([0-9\.]+)$', string)
|
||||
m = re.search('^([0-9]+):([0-9]+)@([0-9.]+)$', string)
|
||||
assert(m is not None)
|
||||
min = int(m.group(1))
|
||||
max = int(m.group(2))
|
||||
@@ -137,9 +137,8 @@ def check_section_hidpp10(section):
|
||||
pass
|
||||
|
||||
try:
|
||||
index = int(section['DeviceIndex'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(index > 0 and index < 10)
|
||||
index = int(section['DeviceIndex'], 16)
|
||||
assert(index > 0 and index <= 0xff)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@@ -169,14 +168,13 @@ def check_section_hidpp10(section):
|
||||
|
||||
|
||||
def check_section_hidpp20(section):
|
||||
permitted = ['DeviceIndex']
|
||||
permitted = ['DeviceIndex', 'Leds', 'Quirk']
|
||||
for key in section.keys():
|
||||
assertIn(key, permitted)
|
||||
|
||||
try:
|
||||
index = int(section['DeviceIndex'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(index > 0 and index < 10)
|
||||
index = int(section['DeviceIndex'], 16)
|
||||
assert(index > 0 and index <= 0xff)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@@ -190,6 +188,15 @@ def check_section_driver(driver, section):
|
||||
assert('Unsupported driver section {}'.format(driver))
|
||||
|
||||
|
||||
def validate_data_file_name(path):
|
||||
# Matching any of the characters in the regular expression will throw an
|
||||
# error. Currently only tests the square brackets [], parentheses, and curly
|
||||
# braces.
|
||||
illegal_characters_regex = '([\[\]\{\}\(\)])'
|
||||
found_characters = re.findall(illegal_characters_regex, path)
|
||||
if found_characters:
|
||||
raise AssertionError("data file name '{}' contains illegal characters: '{}'".format(path, ''.join(found_characters)))
|
||||
|
||||
def parse_data_file(path):
|
||||
print('Parsing file {}'.format(path))
|
||||
data = configparser.ConfigParser(strict=True)
|
||||
@@ -216,4 +223,5 @@ if __name__ == "__main__":
|
||||
parser.add_argument('file', nargs='+')
|
||||
args = parser.parse_args()
|
||||
for path in args.file:
|
||||
validate_data_file_name(path)
|
||||
parse_data_file(path)
|
||||
|
||||
57
data/devices/duplicate-check.py
Executable file
57
data/devices/duplicate-check.py
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright © 2018 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import configparser
|
||||
|
||||
|
||||
def parse_data_file(path):
|
||||
data = configparser.ConfigParser(strict=True)
|
||||
# Don't convert to lowercase
|
||||
data.optionxform = lambda option: option
|
||||
data.read(path)
|
||||
|
||||
matches = data['Device']['DeviceMatch']
|
||||
return matches.split(';')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Device duplicate match checker')
|
||||
parser.add_argument('file', nargs='+')
|
||||
args = parser.parse_args()
|
||||
device_matches = {}
|
||||
duplicates = False
|
||||
for path in args.file:
|
||||
matches = parse_data_file(path)
|
||||
fname = os.path.basename(path)
|
||||
for m in matches:
|
||||
if m in device_matches:
|
||||
print('Duplicate DeviceMatch={} in {} and {}'.format(m, fname, device_matches[m]))
|
||||
duplicates = True
|
||||
device_matches[m] = fname
|
||||
|
||||
if duplicates:
|
||||
sys.exit(1)
|
||||
5
data/devices/logitech-M585-M590.device
Normal file
5
data/devices/logitech-M585-M590.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech M585/M590
|
||||
[Device]
|
||||
Name=Logitech M585/M590
|
||||
DeviceMatch=usb:046d:406b;bluetooth:046d:b01b
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-M720.device
Normal file
4
data/devices/logitech-M720.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech M720
|
||||
DeviceMatch=usb:046d:405e
|
||||
Driver=hidpp20
|
||||
@@ -1,4 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech MX Anywhere 2
|
||||
DeviceMatch=usb:046d:404a;bluetooth:046d:b013
|
||||
DeviceMatch=usb:046d:404a;bluetooth:046d:b013;bluetooth:046d:b018;bluetooth:046d:b01f
|
||||
Driver=hidpp20
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech MX Anywhere 2S
|
||||
DeviceMatch=usb:046d:406a
|
||||
DeviceMatch=bluetooth:046d:b01a;usb:046d:406a
|
||||
Driver=hidpp20
|
||||
|
||||
5
data/devices/logitech-MX-Ergo.device
Normal file
5
data/devices/logitech-MX-Ergo.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech MX Ergo
|
||||
[Device]
|
||||
Name=Logitech MX Ergo
|
||||
DeviceMatch=bluetooth:046d:b01d;usb:046d:406f
|
||||
Driver=hidpp20
|
||||
5
data/devices/logitech-MX-Master-3.device
Normal file
5
data/devices/logitech-MX-Master-3.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech MX Master 3
|
||||
[Device]
|
||||
Name=Logitech MX Master 3
|
||||
DeviceMatch=bluetooth:046d:b023;usb:046d:4082
|
||||
Driver=hidpp20
|
||||
@@ -1,5 +1,5 @@
|
||||
# Logitech MX Master
|
||||
[Device]
|
||||
Name=Logitech MX Master
|
||||
DeviceMatch=usb:046d:4041;bluetooth:046d:b012;usb:046d:4060
|
||||
DeviceMatch=usb:046d:4041;bluetooth:046d:b012;usb:046d:4060;bluetooth:046d:b017;bluetooth:046d:b01e;usb:046d:4071
|
||||
Driver=hidpp20
|
||||
|
||||
4
data/devices/logitech-MX-Vertical.device
Normal file
4
data/devices/logitech-MX-Vertical.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech MX Vertical
|
||||
DeviceMatch=usb:046d:407b
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-MX518.device
Normal file
4
data/devices/logitech-MX518.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=MX518
|
||||
DeviceMatch=usb:046d:c08e
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-Marathon-M705.device
Normal file
4
data/devices/logitech-Marathon-M705.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech Marathon M705
|
||||
DeviceMatch=usb:046d:406d
|
||||
Driver=hidpp20
|
||||
8
data/devices/logitech-g-powerplay.device
Normal file
8
data/devices/logitech-g-powerplay.device
Normal file
@@ -0,0 +1,8 @@
|
||||
[Device]
|
||||
Name=Logitech G Powerplay
|
||||
DeviceMatch=usb:046d:405f
|
||||
LedTypes=logo
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=7
|
||||
@@ -1,6 +1,6 @@
|
||||
[Device]
|
||||
Name=Logitech G Pro Wireless
|
||||
DeviceMatch=usb:046d:c539;usb:046d:c088
|
||||
DeviceMatch=usb:046d:4079;usb:046d:c088
|
||||
LedTypes=logo;battery;dpi;
|
||||
Driver=hidpp20
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech Gaming Mouse G Pro
|
||||
DeviceMatch=usb:046d:c085
|
||||
DeviceMatch=usb:046d:c085;usb:046d:c08c
|
||||
Driver=hidpp20
|
||||
LedTypes=logo;side
|
||||
|
||||
8
data/devices/logitech-g305.device
Normal file
8
data/devices/logitech-g305.device
Normal file
@@ -0,0 +1,8 @@
|
||||
[Device]
|
||||
Name=Logitech Gaming Mouse G305
|
||||
DeviceMatch=usb:046d:4074
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
Leds=0
|
||||
Quirk=G305
|
||||
@@ -2,4 +2,5 @@
|
||||
[Device]
|
||||
Name=Logitech G402 Gaming Mouse
|
||||
DeviceMatch=usb:046d:c07e
|
||||
LedTypes=logo
|
||||
Driver=hidpp20
|
||||
|
||||
4
data/devices/logitech-g403-hero.device
Normal file
4
data/devices/logitech-g403-hero.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G403 Hero
|
||||
DeviceMatch=usb:046d:c08f
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-g403-wireless.device
Normal file
4
data/devices/logitech-g403-wireless.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G403 Wireless
|
||||
DeviceMatch=usb:046d:405d;usb:046d:c082
|
||||
Driver=hidpp20
|
||||
@@ -1,5 +1,4 @@
|
||||
# Logitech G403
|
||||
[Device]
|
||||
Name=Logitech G403
|
||||
DeviceMatch=usb:046d:c082;usb:046d:c083
|
||||
DeviceMatch=usb:046d:c083
|
||||
Driver=hidpp20
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Logitech G502 HERO over USB
|
||||
[Device]
|
||||
Name=Logitech G502 HERO
|
||||
DeviceMatch=usb:046d:c08b
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-g502-hero-wireless.device
Normal file
4
data/devices/logitech-g502-hero-wireless.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G502 Hero Wireless
|
||||
DeviceMatch=usb:046d:407f;usb:046d:c08d
|
||||
Driver=hidpp20
|
||||
4
data/devices/logitech-g502-hero.device
Normal file
4
data/devices/logitech-g502-hero.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G502 Hero
|
||||
DeviceMatch=usb:046d:c08b
|
||||
Driver=hidpp20
|
||||
@@ -1,4 +1,3 @@
|
||||
# Logitech G502 Proteus Core over USB
|
||||
[Device]
|
||||
Name=Logitech G502 Proteus Core
|
||||
DeviceMatch=usb:046d:c07d
|
||||
@@ -1,4 +1,3 @@
|
||||
# Logitech G502 Proteus Spectrum over USB
|
||||
[Device]
|
||||
Name=Logitech G502 Proteus Spectrum
|
||||
DeviceMatch=usb:046d:c332
|
||||
5
data/devices/logitech-g513.device
Normal file
5
data/devices/logitech-g513.device
Normal file
@@ -0,0 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech G513
|
||||
DeviceMatch=usb:046d:c33c
|
||||
LedTypes=switches
|
||||
Driver=hidpp20
|
||||
@@ -1,8 +1,9 @@
|
||||
# Logitech G602 over wireless USB
|
||||
[Device]
|
||||
Name=Logitech G602
|
||||
DeviceMatch=usb:046d:c537
|
||||
DeviceMatch=usb:046d:402c
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
Quirk=G602
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Logitech G603
|
||||
[Device]
|
||||
Name=Logitech G603
|
||||
DeviceMatch=bluetooth:046d:b01c
|
||||
DeviceMatch=usb:046d:406c;bluetooth:046d:b01c
|
||||
Driver=hidpp20
|
||||
|
||||
4
data/devices/logitech-g604.device
Normal file
4
data/devices/logitech-g604.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G604
|
||||
DeviceMatch=usb:046d:4085;bluetooth:046d:b024
|
||||
Driver=hidpp20
|
||||
@@ -1,12 +0,0 @@
|
||||
# Logitech G700s over wireless USB
|
||||
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
|
||||
[Device]
|
||||
Name=Logitech G700s
|
||||
DeviceMatch=usb:046d:c531
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:8200@50
|
||||
ProfileType=G700
|
||||
DeviceIndex=1
|
||||
Profiles=5
|
||||
5
data/devices/logitech-g703-hero.device
Normal file
5
data/devices/logitech-g703-hero.device
Normal file
@@ -0,0 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech G703 Hero
|
||||
DeviceMatch=usb:046d:4086;usb:046d:c090
|
||||
Driver=hidpp20
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech G703
|
||||
DeviceMatch=usb:046d:c087
|
||||
DeviceMatch=usb:046d:c087;usb:046d:4070
|
||||
Driver=hidpp20
|
||||
|
||||
|
||||
5
data/devices/logitech-g815.device
Normal file
5
data/devices/logitech-g815.device
Normal file
@@ -0,0 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech G815
|
||||
DeviceMatch=usb:046d:c33f
|
||||
LedTypes=logo;switches
|
||||
Driver=hidpp20
|
||||
@@ -1,8 +0,0 @@
|
||||
# Logitech G900, G903, G603 and G403 over wireless USB
|
||||
[Device]
|
||||
Name=Logitech G900, G903, G603, G403
|
||||
DeviceMatch=usb:046d:c539
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
@@ -1,5 +1,5 @@
|
||||
# Logitech G900 over USB
|
||||
# Logitech G900
|
||||
[Device]
|
||||
Name=Logitech G900
|
||||
DeviceMatch=usb:046d:c081
|
||||
DeviceMatch=usb:046d:c081;usb:046d:4053
|
||||
Driver=hidpp20
|
||||
|
||||
4
data/devices/logitech-g903-hero.device
Normal file
4
data/devices/logitech-g903-hero.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Logitech G903 Hero
|
||||
DeviceMatch=usb:046d:c091;usb:046d:4087
|
||||
Driver=hidpp20
|
||||
@@ -1,5 +1,4 @@
|
||||
# Logitech G903 over USB
|
||||
[Device]
|
||||
Name=Logitech G903
|
||||
DeviceMatch=usb:046d:c086
|
||||
DeviceMatch=usb:046d:c086;usb:046d:4067
|
||||
Driver=hidpp20
|
||||
|
||||
8
data/devices/logitech-g910.device
Normal file
8
data/devices/logitech-g910.device
Normal file
@@ -0,0 +1,8 @@
|
||||
[Device]
|
||||
Name=Logitech G910
|
||||
DeviceMatch=usb:046d:c335
|
||||
LedTypes=logo;switches
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=ff
|
||||
8
data/devices/logitech-g915.device
Normal file
8
data/devices/logitech-g915.device
Normal file
@@ -0,0 +1,8 @@
|
||||
[Device]
|
||||
Name=Logitech G915
|
||||
DeviceMatch=usb:046d:c33e
|
||||
LedTypes=logo;switches
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
5
data/devices/logitech-g935.device
Normal file
5
data/devices/logitech-g935.device
Normal file
@@ -0,0 +1,5 @@
|
||||
[Device]
|
||||
Name=Logitech G935
|
||||
DeviceMatch=usb:046d:0a87
|
||||
LedTypes=logo;side
|
||||
Driver=hidpp20
|
||||
@@ -1,8 +0,0 @@
|
||||
# Logitech G PowerPlay mouse pad + wireless USB receiver.
|
||||
[Device]
|
||||
Name=Logitech G PowerPlay mouse pad.
|
||||
DeviceMatch=usb:046d:c53a
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
74
data/devices/receiver-check.py
Executable file
74
data/devices/receiver-check.py
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright © 2018 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import configparser
|
||||
|
||||
# see the IDs from
|
||||
# https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h#L772
|
||||
# https://github.com/torvalds/linux/blob/master/drivers/hid/hid-logitech-dj.c#L1826
|
||||
logitech_receivers = [
|
||||
0xc50c, # USB_DEVICE_ID_S510_RECEIVER
|
||||
0xc517, # USB_DEVICE_ID_S510_RECEIVER_2
|
||||
0xc512, # USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500
|
||||
0xc513, # USB_DEVICE_ID_MX3000_RECEIVER
|
||||
0xc51b, # USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER
|
||||
0xc52b, # USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER
|
||||
0xc52f, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER
|
||||
0xc532, # USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2
|
||||
0xc534, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2
|
||||
0xc539, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1
|
||||
0xc53f, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1
|
||||
0xc53a, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY
|
||||
]
|
||||
RECEIVERS = ['usb:046d:{}'.format(r) for r in logitech_receivers]
|
||||
|
||||
|
||||
def parse_data_file(path):
|
||||
data = configparser.ConfigParser(strict=True)
|
||||
# Don't convert to lowercase
|
||||
data.optionxform = lambda option: option
|
||||
data.read(path)
|
||||
|
||||
matches = data['Device']['DeviceMatch']
|
||||
return matches.split(';')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Checks that no unifying receiver ID is in the device files')
|
||||
parser.add_argument('file', nargs='+')
|
||||
args = parser.parse_args()
|
||||
receiver_found = False
|
||||
for path in args.file:
|
||||
matches = parse_data_file(path)
|
||||
fname = os.path.basename(path)
|
||||
for m in matches:
|
||||
if m in RECEIVERS:
|
||||
print('Receiver ID {} found in file {}'.format(m, fname))
|
||||
receiver_found = True
|
||||
|
||||
if receiver_found:
|
||||
sys.exit(1)
|
||||
4
data/devices/roccat-kone-pure.device
Normal file
4
data/devices/roccat-kone-pure.device
Normal file
@@ -0,0 +1,4 @@
|
||||
[Device]
|
||||
Name=Roccat Kone Pure
|
||||
DeviceMatch=usb:1e7d:2dc2
|
||||
Driver=roccat-kone-pure
|
||||
11
data/devices/steelseries-kinzu-v3.device
Normal file
11
data/devices/steelseries-kinzu-v3.device
Normal file
@@ -0,0 +1,11 @@
|
||||
[Device]
|
||||
Name=SteelSeries Kinzu V3
|
||||
DeviceMatch=usb:1038:1388
|
||||
Driver=steelseries
|
||||
|
||||
[Driver/steelseries]
|
||||
DeviceVersion=1
|
||||
Buttons=3
|
||||
Leds=0
|
||||
DpiList=400;800;1600;2000
|
||||
MacroLength=0
|
||||
194
data/logo.svg
194
data/logo.svg
@@ -1,182 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg class="ratbag-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<path class="ratbag-bag" d="M38.8 22.1a48.4 48.4 0 0 1 22.7 0s9-8.9 5-11.2c-6-3.2-3.9.8-16.3 3.5 15.5-7.5 5.4-5.7-16.3-3.5-5.3.5 5 11.2 5 11.2zm20.7 2.8c5.7 17.1-.8 4.7-2-.1-4 22.1-3.7 7.7-3-.6-5-.5-10.7-.4-15.7 1.3a47 47 0 0 0-17 32.7c0 13.3 5 7.9 28.4 7.9 28.8 0 28.4 5.4 28.4-7.9 0-9.8-9-25.9-19-33.3z" />
|
||||
<path class="ratbag-rats" fill="#fff" d="M35.8 62.3c3.3 3.4-1 2.4-1.9.1-5.6 1.9-16.9.7-3.8-16.3.5-.4.6.5.4 1-4 6.8-7.5 15.5.3 13.2-1-8.2 3.2-14.1 6.8-19.7 1.1-1.4 2.3-4.3 2.8-5.5-3-2.1-.8-2 1.2-1.5 1.7-1.6 3.5-2.5 6.6-3 1.7 2.5-2.7 8.2-2.7 8.2 0 2.3.1 3.7.4 4.9 3 6.5 1.2 7.3-1.4 2.9-.3.1.3 2.6-1.4 7.9.5 5.9-2.5 7-2.5 7 7.3 2.2 1 3-1 .5-.8-.5-2.9-.1-3.8.3zm15-9c.1-1.7 1.4-4 1.8-.4 2 2.1 7.5-3.4 13.3-2.2 3.7.8 5 3.3 4.5 7.4 11.7 3.8 4.3 7.9-4.6 6.9 11.8-2.5 9.3-4.1 3.5-5-.4.8-4.6 1.6-5.5 1.5-3.9 1.5-6.7 2.2-3.2-.2l-4.5-.4c-3.9 2.8-2.9 2.4-1.7-.3-2-1.4-6 1.9-6.3-.1 0-.6 1.6-5.9 2.6-7.2z"/>
|
||||
<path class="ratbag-eyes" d="M51 56.9c.6.4-1 1.2-1 1.2s.1-1.6 1-1.2zm-7-22.6c-.8-.4 1-1.2 1-1.2s-.3 1.7-1 1.2z"/>
|
||||
<path class="ratbag-logotype" d="M81.3 89.3c-.6.9-2.3 1.1-2.7 0 0-1.3.6-2.5.5-3.8-.5.5-1 1.6-1.6 2.3-1 1-1.8 2.4-3.4 2.3-1.3-.2-2.8-.7-3.3-2-1.3-1.8-.8-4-.5-6 .7-2.8 2.6-5.3 5.2-6.7 1.3-.4 3.2-.2 4 1.2 0 2.3-1.5 4.9-3.8 4.9-2.6-.7 1.4-3 .7-4.2-1.4-.3-1.8 1.8-2.4 2.8-.8 2-1.5 4.3-1 6.4 1.6 3.5 5-2.8 2.5-1.4-1 .7-2.9 0-1.5-1.2 1-1 2.4-1.3 3.6-2.1 5.6-2.2 3.5.3 3.7 7.5zm-18.3-6c-.1.6 2-.1 2.3.3.4.4-.4-2.2-.6-2.6zm3.6-8c1.2 4.7 2 9 3.4 13.2-.2 1-1.6 1.7-2.6 1.5-1.4-1.2-.2-2.8-1.6-4-.3-.4-3.7-.5-3.8.5l-1.4 3.2c-.6.6-2.9.9-2.5-.4.5-1.4 1-2.8 1.8-4l3.4-9.6c.5-1.3 2.3-1.2 3.3-.4zm-10.5 9.5c-.4-.8-1.3-1.5-2.3-1.4-.8-.3-.6.5-.7 1 0 1.1-.2 2.2-.4 3.3 1-.3 1.9-1 2.7-1.7.4-.2.7-.7.7-1.2zm-6.3 5.8c-1.3 0-1.2-2 0-2 0-3.5.3-7 1-10.3.6-.7 1.6-1 2.4-1.2 1 .4 1 1.4.6 2.2-.4.9 0 1.4.8.7.8-.6 1-1.6 1-2.5-.8-1.9-4.3-.3-4.8-.4-1.2-.6.3-1.5 1-1.7.8-.4 1.7-.9 2.7-.7 1.2 0 2.7-.1 3.6 1 .8 1.2.1 2.8-.6 4-.3.7-1.6 1.3-1.7 1.8 6.4 1.1.8 9.4-6 9zm-1.6-13.4c-2.1.6-.9 3.4-1.4 5-.4 2.7-.9 5.5-.8 8.3-1.3 1.3-3.5-.3-2.9-2 0-2.8.1-5.7.6-8.5.4-1.2.6-2.9-1.1-2-2 .3-2.2-2.5 0-2.2 3 .2.7-3.6 2.5-4.8 1.8-1 3.6 1 2.5 2.7.1.5-.6 1.7.4 1.5 2-.8 2.4 3 .2 2zm-12.3 5.2c-1 .6.6 1.1 1 1.5 1 1 .2-.8 0-1.2-.9-1.7-.4-2-1-.3zm3-7.2l2 9.9c.3 1.5 1.6 3.7 0 4.7-1.4.8-2.4-.5-3.3-1.4-.9-.7-1.9-1.2-2.6-2.1-1-.3-1.9 2.8-2.9 3.8-.8 0-3 .2-1.8-1 .5-1.8 1.2-3.5 1.8-5.3-1.3-1 .3-2 1-2.6a52 52 0 0 0 2.4-5.6c.7-1 2.6-1.3 3.3-.4zm-16.4 2.9v2.4c1.6-.4 4-2.4 2.2-4-1.5-1.4-2.5 0-2.2 1.6zm6.7 3.3c2 1.2.6 3.8.5 5.6-.2 2-2.5 4.1-4.3 2.3-1.2-1.1-3.7-4.3-4.1-1-.5 2.5-3.3 1.7-2.8-.6.3-2.3 1-4.6 1.2-7-.3-2.4-1-4.8-.3-7.2 1-2.7 4.4-2.5 6.4-1.3 2.3.9 3.8 3.7 2.3 6-.5 2-3.1 3.1-3.7 4.6 1.2 2 3.6 2.9 3.4-.3.3-.5.8-1 1.4-1z" />
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="180.65305mm"
|
||||
height="180.65305mm"
|
||||
viewBox="0 0 180.65305 180.65305"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
sodipodi:docname="logo.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="-156.7648"
|
||||
inkscape:cy="473.25323"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer2"
|
||||
showgrid="false"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1376"
|
||||
inkscape:window-x="2560"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-to-guides="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1058"
|
||||
originx="-15.590431"
|
||||
originy="-49.255695" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="rat right"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(-15.59043,-80.129979)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssssssssssssssccssscss"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1039"
|
||||
d="m 181.70318,102.59719 c -3.2499,1.24415 -5.70487,5.21773 -6.1731,8.64054 -0.46127,3.37194 1.06674,8.17528 5.17162,8.92716 1.88245,0.3448 5.75552,3.71382 1.56778,2.91866 -4.41092,-0.83753 -9.60561,-1.81767 -12.03434,-5.88833 -2.51189,-4.21004 -6.0824,-2.70094 -9.60946,-1.97697 -3.61649,0.74233 -3.34262,3.70961 -0.59483,4.79149 1.76651,0.69552 -4.7698,1.02182 -6.46586,-0.31589 -0.99074,-0.7814 -4.3093,0.86964 -6.03067,0.70651 -4.14705,-0.39301 -8.0988,0.0723 -12.42874,-0.59505 -2.75134,-0.42408 -6.23873,1.52773 -5.40472,-2.94355 0.41316,-2.21506 -1.53788,-7.95327 -0.25583,-12.08908 1.43935,-4.64326 2.78762,-6.554728 6.29989,-9.291599 2.96282,-2.308725 9.62529,-5.456849 13.27656,-6.171955 5.94327,-1.163997 13.69394,2.401773 15.47361,3.054918 2.51726,0.923848 7.67473,-3.278929 11.1961,-3.200515 2.07518,-1.437388 4.50939,-5.479552 6.03783,0.452639 3.26133,0.136438 5.00967,-0.06864 9.09359,2.312711 2.76398,1.611684 4.87236,1.538272 5.34391,2.873448 0.62005,1.755647 -2.69292,5.296383 -3.28547,5.288623 -0.8492,-0.0111 -0.81394,0.0819 -2.0197,0.17649 -0.32445,1.41613 -2.05245,1.97075 -5.1013,1.61048 -1.43172,-0.16918 -2.7495,0.21878 -4.05687,0.71927 z"
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1045"
|
||||
d="m 119.43296,119.1374 c -3.19754,-3.4816 -3.91548,-3.31073 -5.87228,-7.17694 -1.51881,-4.76902 -1.2579,-3.59102 -4.44899,-11.00554 2.31432,2.99141 3.84563,6.48437 5.56001,9.87162 2.19923,4.34517 4.03074,4.88595 7.22829,8.36756"
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
transform="translate(-4.1666665e-8,1.0416667e-6)"
|
||||
style="display:inline;fill:#ffffff;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||
d="m 183.59605,92.870943 c 0.70159,-0.65481 2.47893,-0.65481 2.89988,-0.187088 0.42095,0.467721 -1.82412,1.028987 -2.89988,0.187088 z"
|
||||
id="path833"
|
||||
inkscape:connector-curvature="0">
|
||||
<animate
|
||||
values="orange;red;orange"
|
||||
dur="7s"
|
||||
repeatCount="indefinite"
|
||||
attributeName="fill" />
|
||||
</path>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="rat left"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(-15.59043,-80.129979)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccsccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1298"
|
||||
d="m 86.198873,115.45536 c -0.640498,-1.90396 -0.324058,-5.87792 -2.548937,-9.26118 1.761266,-3.58236 5.461967,-1.0306 3.345989,-4.71668 -1.27974,-2.229332 -5.394303,-0.5453 -6.437336,0.67341 -2.968786,0.40847 -6.280299,-3.592034 -8.586349,-4.613758 -3.902419,-1.141693 -9.722226,-2.223874 -12.939723,-3.303186 -2.646277,1.694635 -1.446947,6.207524 -1.598912,7.088294 1.30852,3.28167 1.243822,1.80143 2.493275,5.51481 2.008262,2.23089 4.855928,4.59155 5.686271,9.4289 7.349678,-0.38854 9.558907,-0.59389 20.585722,-0.81061 z"
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccsc"
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 108.49567,117.83325 c -0.24901,-4.72058 -0.43574,-9.98729 -1.82782,-14.09082 -4.0267,-10.295998 -4.72401,-12.496029 -0.0129,-13.556767 -2.07044,-0.256651 -5.41881,-0.421857 -5.48281,2.489527 0.517,3.746632 1.94024,7.284981 3.15986,10.88015 1.56453,4.61189 1.00424,9.35889 1.25325,14.07947"
|
||||
id="path955"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="translate(-4.1666665e-8,1.0416667e-6)"
|
||||
style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 71.938542,102.84868 c -0.902446,-0.17526 -1.969377,-1.68007 -1.548427,-2.12186 0.867434,-0.27642 1.714682,0.92977 1.548427,2.12186 z"
|
||||
id="path833-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc">
|
||||
<animate
|
||||
values="green;yellow;green"
|
||||
dur="3s"
|
||||
repeatCount="indefinite"
|
||||
attributeName="fill" />
|
||||
</path>
|
||||
</g>
|
||||
<g
|
||||
inkscape:label="sack"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
style="display:inline"
|
||||
transform="translate(-15.59043,-80.129979)">
|
||||
<rect
|
||||
ry="0.44884709"
|
||||
y="172.18915"
|
||||
x="1150"
|
||||
height="4.8108511"
|
||||
width="6.0803819"
|
||||
id="rect1075"
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.16499996;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<g
|
||||
style="display:inline;opacity:1"
|
||||
id="g1316"
|
||||
transform="translate(-11.599497,6.3500003)">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccczzcczc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path815"
|
||||
d="m 71.911001,151.04073 c -13.545552,17.75365 -48.518606,24.46129 -42.445015,52.8882 4.987974,25.22201 13.988429,29.44417 56.008367,27.90906 47.288497,0.24745 47.307997,0.7217 90.436597,0.28592 14.07598,2.60143 28.63685,-20.8018 23.94043,-35.61574 -4.77259,-20.1552 -28.81931,-24.18426 -36.25354,-41.43822 -7.52218,-23.58108 1.99039,-35.03297 22.19568,-25.38895 20.20529,9.64403 26.03755,-15.82001 -11.10418,-15.33498 -37.14173,0.48503 -66.18409,-5.57956 -84.958574,-4.07459 -15.461428,0.81842 -41.712504,-2.86861 -44.765236,21.70932 2.422297,6.71408 19.985082,-12.15526 27.605897,-5.44801 7.620815,6.70724 20.413185,4.32379 -0.660426,24.50799 z"
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:3.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 79.716618,142.54753 c 0,0 63.912362,8.07113 81.488252,0.7006 0,0 -0.56974,-7.74657 1.60362,-10.91212 -17.57589,7.37053 -79.821755,-0.0115 -79.821755,-0.0115 3.474504,7.01583 -3.270117,10.22298 -3.270117,10.22298 z"
|
||||
id="path842"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer6"
|
||||
inkscape:label="rat bottom"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(-15.59043,-80.129979)">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccsccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1212"
|
||||
d="m 122.70428,243.35492 c 6.05524,1.14081 7.22067,1.31431 10.02264,2.72758 0,0.38071 -0.19945,0.89381 -1.01365,1.66697 -0.8142,0.77314 -2.6542,0.92241 -3.94953,1.25266 -0.67325,0.3643 -1.36184,1.00187 -1.50199,1.72727 3.97782,-1.45575 2.82486,-1.28103 2.75389,0.45072 0.20024,0.42037 1.54248,-1.05607 1.70256,-1.07661 1.00124,-0.41482 0.93822,0.001 1.55056,0.0319 0.20389,0.64546 -0.30382,1.34832 -0.26341,1.72391 0.84425,0.0769 1.57036,-1.33585 1.5884,-2.00591 0.34832,-0.5087 0.57096,-0.30966 1.0296,0 0.83149,0.862 0.93498,0.50569 1.95428,1.01599 2.24374,0.45044 -0.93235,-2.10713 -1.49797,-2.41992 -0.0737,-0.0369 1.39328,-2.39745 1.58909,-2.64425 2.32503,-0.403 4.75988,-1.00269 6.10414,-1.57594 v -1.2e-4 c 5.97825,1.84348 14.60207,1.47181 21.66926,1.7325 8.87347,0.60502 6.80866,4.81981 -11.94665,7.57383 29.43774,3.60709 24.29174,-11.42807 13.49975,-11.41332 -4.45874,0.0577 -12.7835,-0.12064 -21.26078,-1.9791 -1.35135,-2.33359 -1.8837,-5.9598 -1.12611,-9.63435 -2.49031,-11.667 -8.91489,-30.75707 -16.82134,-42.62455 -2.9074,-3.93147 -6.12061,-11.52979 -7.33913,-14.68828 7.81948,-5.62697 0.38705,-8.64346 -3.43515,-4.04735 -4.2835,-4.24158 -9.25924,-6.58986 -17.436457,-7.91069 -4.46939,6.75139 7.201157,21.8355 7.201157,21.8355 0.27261,11.69368 -1.47411,14.8979 -4.3435,23.39568 0.0471,0.3928 -0.49786,0.52092 -0.68357,0.83384 -0.19254,0.21312 -0.924097,1.82103 -1.179137,2.01487 -0.12771,0.23832 -0.38006,0.38366 -0.60384,0.59827 -0.23775,0.19619 -0.40433,0.49501 -0.42142,0.8292 -0.13385,0.31584 -0.17018,0.488 -0.19925,0.87639 -0.15645,0.29381 0.11002,0.40231 0.35386,0.34986 0.27783,-0.0135 0.56968,0.0505 0.82065,-0.10012 0.38688,-0.0135 0.824117,-0.32301 0.901337,-0.70099 0.0571,-0.34113 0.16568,-0.80155 0.62396,-0.6509 0.27636,0.006 0.58137,-0.16307 0.77806,0.15023 0.27193,0.12771 0.77421,0.23993 0.87876,-0.14883 0.16039,-0.42589 0.57357,-0.67322 0.67434,-1.12667 0.14254,-0.12321 0.37352,-0.19611 0.30974,-0.28545 0.26187,-0.26516 0.52474,-0.58479 0.89076,-0.74525 3.05534,-1.07719 3.51973,-4.67744 3.86462,-4.59812 0.67734,0.15577 -0.84342,6.82001 3.73079,20.85428 -1.4046,15.75023 6.7093,18.67126 6.7093,18.67126 0.17258,1.22487 -3.10226,1.32242 -3.80222,1.80721 -0.96512,0.31347 -2.42142,0.5571 -3.36241,0.16943 -0.41052,-0.20344 -1.14128,-0.10911 -0.6235,0.34889 -0.6851,0.62634 -1.75451,0.42589 -2.61368,0.63307 -0.84134,0.12395 -1.06409,1.07707 -0.0627,0.80147 -0.42125,1.18238 1.04775,0.72998 1.68923,0.70002 0.53648,-0.0399 0.30954,0.7577 0.96774,0.39958 0.92805,-0.19058 1.83353,-0.32154 2.75115,-0.51031 0.98245,-0.0454 1.60905,0.10657 2.586,0.18597 0.728,0.16342 2.43322,-0.53193 2.89833,-1.06277 0.62324,-0.55427 1.57699,-1.41676 2.07353,-2.11063 0.49656,-0.69386 0.66544,-0.53528 1.31986,-1.29795 z"
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.39657527px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path850"
|
||||
d="m 109.46587,169.42014 c -0.90244,-0.17526 -1.96937,-1.68007 -1.54842,-2.12186 0.86743,-0.27642 1.71468,0.92977 1.54842,2.12186 z"
|
||||
style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1">
|
||||
<animate
|
||||
values="red;blue;red"
|
||||
dur="5s"
|
||||
repeatCount="indefinite"
|
||||
attributeName="fill" />
|
||||
</path>
|
||||
</g>
|
||||
<!-- comment out style section to remove animated eyes-->
|
||||
<style>
|
||||
.ratbag-eyes{animation: color-cycle 5s linear infinite}
|
||||
@keyframes color-cycle{
|
||||
20%{fill: #27A269}
|
||||
40%{fill: #E5A50B}
|
||||
60%{fill: #EE323A}
|
||||
80%{fill: #C061CA}}
|
||||
</style>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -12,15 +12,15 @@
|
||||
<busconfig>
|
||||
|
||||
<policy user="root">
|
||||
<allow own="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
|
||||
<allow send_destination="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
|
||||
<allow receive_sender="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
|
||||
<allow own="org.freedesktop.ratbag_devel1"/>
|
||||
<allow send_destination="org.freedesktop.ratbag_devel1"/>
|
||||
<allow receive_sender="org.freedesktop.ratbag_devel1"/>
|
||||
</policy>
|
||||
|
||||
<!-- allow everyone to talk to the daemon -->
|
||||
<policy context="default">
|
||||
<allow send_destination="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
|
||||
<allow receive_sender="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
|
||||
<allow send_destination="org.freedesktop.ratbag_devel1"/>
|
||||
<allow receive_sender="org.freedesktop.ratbag_devel1"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
||||
|
||||
@@ -152,6 +152,3 @@ texinfo_documents = [
|
||||
author, '@PACKAGE_NAME@', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
13
doc/dbus.rst
13
doc/dbus.rst
@@ -80,6 +80,19 @@ org.freedesktop.ratbag1.Manager
|
||||
The **org.freedesktop.ratbag1.Manager** interface is the entry point to
|
||||
interact with ratbagd.
|
||||
|
||||
.. attribute:: APIVersion
|
||||
|
||||
: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.
|
||||
|
||||
This API will be removed once the DBus API is declared stable.
|
||||
|
||||
.. attribute:: Devices
|
||||
|
||||
:type: ao
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
if get_option('documentation')
|
||||
|
||||
cmd_sphinx = find_program('sphinx-build-3', 'sphinx-build3')
|
||||
cmd_sphinx = find_program('sphinx-build-3', 'sphinx-build3', 'sphinx-build')
|
||||
|
||||
doc_config = configuration_data()
|
||||
doc_config.set('PACKAGE_NAME', meson.project_name())
|
||||
|
||||
213
meson.build
213
meson.build
@@ -1,14 +1,14 @@
|
||||
project('libratbag', 'c', 'cpp',
|
||||
version : '0.9.905',
|
||||
project('libratbag', 'c',
|
||||
version : '0.14',
|
||||
license : 'MIT/Expat',
|
||||
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
|
||||
meson_version : '>= 0.40.0')
|
||||
|
||||
libratbag_version = meson.project_version().split('.')
|
||||
|
||||
git = find_program('git')
|
||||
r = run_command('tools/ratbag-git-sha.sh')
|
||||
ratbagd_sha = r.stdout().strip()
|
||||
# The DBus API version. Increase this every time the DBus API changes.
|
||||
# No backwards/forwards guarantee, clients are expected to understand
|
||||
# whatever ratbagd speaks or bail out. This should be removed if we ever
|
||||
# finish the API and declare it stable.
|
||||
ratbagd_api_version = 1
|
||||
|
||||
# We use libtool-version numbers because it's easier to understand.
|
||||
# Before making a release, the libratbag_so_* and liblur_so_*
|
||||
@@ -28,22 +28,24 @@ liblur_so_version = '@0@.@1@.@2@'.format((liblur_so_c-liblur_so_a),
|
||||
|
||||
# Compiler setup
|
||||
cc = meson.get_compiler('c')
|
||||
cpp = meson.get_compiler('cpp')
|
||||
cppflags = ['-Wno-unused-parameter', '-fvisibility=hidden']
|
||||
cflags = cppflags + ['-Wmissing-prototypes', '-Wstrict-prototypes']
|
||||
cflags = ['-Wno-unused-parameter',
|
||||
'-fvisibility=hidden',
|
||||
'-Wmissing-prototypes',
|
||||
'-Wformat', # required by format-security
|
||||
'-Werror=format-security',
|
||||
'-Wstrict-prototypes']
|
||||
add_project_arguments(cflags, language: 'c')
|
||||
add_project_arguments(cppflags, language: 'cpp')
|
||||
|
||||
# Initialize config.h, to be added to in the various options below, config.h
|
||||
# is generated at the end of this file
|
||||
config_h = configuration_data()
|
||||
config_h.set('_GNU_SOURCE', '1')
|
||||
config_h.set_quoted('RATBAG_VERSION', meson.project_version())
|
||||
config_h.set_quoted('FALLBACK_SVG_NAME', 'fallback.svg')
|
||||
config_h.set('RATBAGD_API_VERSION', ratbagd_api_version)
|
||||
libratbag_data_dir = join_paths(get_option('prefix'),
|
||||
get_option('datadir'),
|
||||
'libratbag')
|
||||
libratbag_data_dir_devel = join_paths(meson.source_root(), 'data')
|
||||
libratbag_data_dir_devel = join_paths(meson.source_root(), 'data', 'devices')
|
||||
config_h.set_quoted('LIBRATBAG_DATA_DIR', libratbag_data_dir)
|
||||
|
||||
# Coverity breaks because it doesn't define _Float128 correctly, you'll end
|
||||
@@ -70,12 +72,14 @@ pkgconfig = import('pkgconfig')
|
||||
dep_udev = dependency('libudev')
|
||||
dep_libevdev = dependency('libevdev')
|
||||
dep_glib = dependency('glib-2.0')
|
||||
dep_json_glib = dependency('json-glib-1.0')
|
||||
dep_lm = cc.find_library('m')
|
||||
dep_unistring = cc.find_library('unistring')
|
||||
|
||||
if get_option('logind-provider') == 'elogind'
|
||||
logind_dep = dependency('libelogind', version : '>=227')
|
||||
dep_logind = dependency('libelogind', version : '>=227')
|
||||
else
|
||||
logind_dep = dependency('libsystemd', version : '>=227')
|
||||
dep_logind = dependency('libsystemd', version : '>=227')
|
||||
endif
|
||||
|
||||
enable_systemd = get_option('systemd')
|
||||
@@ -117,7 +121,10 @@ lib_libhidpp = static_library('hidpp',
|
||||
dependencies : deps_libhidpp)
|
||||
dep_libhidpp = declare_dependency(link_with: lib_libhidpp)
|
||||
|
||||
### liblur.a ####
|
||||
### liblur ####
|
||||
#
|
||||
# liblur is the library to handle logitech unifying receivers.
|
||||
#
|
||||
install_headers('src/liblur.h')
|
||||
|
||||
src_liblur = [
|
||||
@@ -153,6 +160,9 @@ pkgconfig.generate (
|
||||
)
|
||||
|
||||
#### libratbag.so ####
|
||||
#
|
||||
# libratbag is an internal-only library and the bit that does the actual
|
||||
# work talking to the mouse. it's used by ratbagd.
|
||||
src_libratbag = [
|
||||
'src/libratbag-enums.h',
|
||||
'src/libratbag.h',
|
||||
@@ -162,6 +172,7 @@ src_libratbag = [
|
||||
'src/driver-logitech-g300.c',
|
||||
'src/driver-logitech-g600.c',
|
||||
'src/driver-roccat.c',
|
||||
'src/driver-roccat-kone-pure.c',
|
||||
'src/driver-gskill.c',
|
||||
'src/driver-steelseries.c',
|
||||
'src/driver-test.c',
|
||||
@@ -181,6 +192,7 @@ deps_libratbag = [
|
||||
dep_udev,
|
||||
dep_libevdev,
|
||||
dep_glib,
|
||||
dep_json_glib,
|
||||
dep_libutil,
|
||||
dep_libhidpp,
|
||||
]
|
||||
@@ -241,6 +253,8 @@ executable('hidpp20-reset',
|
||||
)
|
||||
|
||||
#### lur-command ####
|
||||
#
|
||||
# A tool to access and manipulate logitech unifying receivers.
|
||||
src_lur_command = [ 'tools/lur-command.c' ]
|
||||
executable('lur-command',
|
||||
src_lur_command,
|
||||
@@ -268,46 +282,65 @@ data_files = files(
|
||||
'data/devices/gskill-MX-780.device',
|
||||
'data/devices/logitech-M325.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',
|
||||
'data/devices/logitech-MX-Master-3.device',
|
||||
'data/devices/logitech-MX518.device',
|
||||
'data/devices/logitech-T650.device',
|
||||
'data/devices/logitech-Wireless-Touchpad.device',
|
||||
'data/devices/logitech-g-powerplay.device',
|
||||
'data/devices/logitech-g-pro-wireless.device',
|
||||
'data/devices/logitech-g-pro.device',
|
||||
'data/devices/logitech-g102-g203.device',
|
||||
'data/devices/logitech-g300.device',
|
||||
'data/devices/logitech-g302.device',
|
||||
'data/devices/logitech-g303.device',
|
||||
'data/devices/logitech-g305.device',
|
||||
'data/devices/logitech-g402.device',
|
||||
'data/devices/logitech-g403-hero.device',
|
||||
'data/devices/logitech-g403-wireless.device',
|
||||
'data/devices/logitech-g403.device',
|
||||
'data/devices/logitech-g5-2007.device',
|
||||
'data/devices/logitech-g5.device',
|
||||
'data/devices/logitech-g500.device',
|
||||
'data/devices/logitech-g500s.device',
|
||||
'data/devices/logitech-g502-HERO-over-USB.device',
|
||||
'data/devices/logitech-g502-Proteus-Core-over-USB.device',
|
||||
'data/devices/logitech-g502-Proteus-Spectrum-over-USB.device',
|
||||
'data/devices/logitech-g502-hero-wireless.device',
|
||||
'data/devices/logitech-g502-hero.device',
|
||||
'data/devices/logitech-g502-proteus-core.device',
|
||||
'data/devices/logitech-g502-proteus-spectrum.device',
|
||||
'data/devices/logitech-g513.device',
|
||||
'data/devices/logitech-g600.device',
|
||||
'data/devices/logitech-g602.device',
|
||||
'data/devices/logitech-g603.device',
|
||||
'data/devices/logitech-g604.device',
|
||||
'data/devices/logitech-g7.device',
|
||||
'data/devices/logitech-g700-wireless.device',
|
||||
'data/devices/logitech-g700.device',
|
||||
'data/devices/logitech-g700s-wireless.device',
|
||||
'data/devices/logitech-g700s.device',
|
||||
'data/devices/logitech-g703-hero.device',
|
||||
'data/devices/logitech-g703.device',
|
||||
'data/devices/logitech-g9.device',
|
||||
'data/devices/logitech-g900-wireless.device',
|
||||
'data/devices/logitech-g900.device',
|
||||
'data/devices/logitech-g903-hero.device',
|
||||
'data/devices/logitech-g903.device',
|
||||
'data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device',
|
||||
'data/devices/logitech-g9x-[Original].device',
|
||||
'data/devices/logitech-gpowerplay-wireless.device',
|
||||
'data/devices/logitech-g815.device',
|
||||
'data/devices/logitech-g910.device',
|
||||
'data/devices/logitech-g915.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-Vertical.device',
|
||||
'data/devices/roccat-kone-pure.device',
|
||||
'data/devices/roccat-kone-xtd.device',
|
||||
'data/devices/steelseries-kinzu-v2.device',
|
||||
'data/devices/steelseries-kinzu-v3.device',
|
||||
'data/devices/steelseries-rival-310.device',
|
||||
'data/devices/steelseries-rival-600.device',
|
||||
'data/devices/steelseries-rival.device',
|
||||
@@ -316,11 +349,17 @@ data_files = files(
|
||||
)
|
||||
|
||||
install_data(data_files,
|
||||
install_dir : join_paths(get_option('datadir'), 'libratbag', 'devices'))
|
||||
install_dir : join_paths(get_option('datadir'), 'libratbag'))
|
||||
|
||||
data_parse_test = find_program(join_paths(meson.source_root(), 'data/devices/data-parse-test.py'))
|
||||
test('data-parse-test', data_parse_test, args: data_files)
|
||||
|
||||
duplicate_test = find_program(join_paths(meson.source_root(), 'data/devices/duplicate-check.py'))
|
||||
test('duplicate-test', duplicate_test, args : data_files)
|
||||
|
||||
reciever_id_test = find_program(join_paths(meson.source_root(), 'data/devices/receiver-check.py'))
|
||||
test('receiver-id-test', reciever_id_test, args : data_files)
|
||||
|
||||
#### tests ####
|
||||
enable_tests = get_option('tests')
|
||||
if enable_tests
|
||||
@@ -365,33 +404,13 @@ if enable_tests
|
||||
'--error-exitcode=3',
|
||||
'--suppressions=' + valgrind_suppressions_file ],
|
||||
timeout_multiplier: 5)
|
||||
|
||||
executable('test-build-cxx',
|
||||
['test/build-cxx.cc'],
|
||||
dependencies : [ dep_libratbag ],
|
||||
include_directories : include_directories('src'),
|
||||
cpp_args : ['-Wall', '-Wextra', '-Wno-unused-parameter'],
|
||||
install : false)
|
||||
executable('test-build-linker',
|
||||
['test/build-pedantic.c'],
|
||||
dependencies : [ dep_libratbag ],
|
||||
include_directories : include_directories('src'),
|
||||
install : false)
|
||||
executable('test-build-gnuc90',
|
||||
['test/build-pedantic.c'],
|
||||
dependencies : [ dep_libratbag ],
|
||||
include_directories : include_directories('src'),
|
||||
c_args : ['-std=gnu90', '-Werror'],
|
||||
install : false)
|
||||
executable('test-build-pedantic',
|
||||
['test/build-pedantic.c'],
|
||||
dependencies : [ dep_libratbag ],
|
||||
include_directories : include_directories('src'),
|
||||
c_args : ['-std=c99', '-pedantic', '-Werror'],
|
||||
install : false)
|
||||
endif
|
||||
|
||||
#### ratbagd ####
|
||||
#
|
||||
# The main item of this repo, a DBus server that uses libratbag to talk to
|
||||
# the mice. The DBus API is the public-facing API.
|
||||
#
|
||||
src_ratbagd = [
|
||||
'src/shared-macro.h',
|
||||
'src/shared-rbtree.h',
|
||||
@@ -404,14 +423,17 @@ src_ratbagd = [
|
||||
'ratbagd/ratbagd-profile.c',
|
||||
'ratbagd/ratbagd-resolution.c',
|
||||
'ratbagd/ratbagd-test.c',
|
||||
'ratbagd/ratbagd-json.c',
|
||||
'ratbagd/ratbagd-json.h',
|
||||
'src/libratbag-util.h',
|
||||
'src/libratbag-util.c',
|
||||
]
|
||||
|
||||
deps_ratbagd = [
|
||||
dep_udev,
|
||||
logind_dep,
|
||||
dep_logind,
|
||||
dep_libratbag,
|
||||
dep_unistring,
|
||||
]
|
||||
|
||||
executable('ratbagd',
|
||||
@@ -424,21 +446,34 @@ executable('ratbagd',
|
||||
install_man('ratbagd/ratbagd.8')
|
||||
|
||||
#### ratbagd_devel ####
|
||||
#
|
||||
# A development ratbagd server that owns a different name on the bus
|
||||
# (org.freedesktop.ratbag_devel1). This server is used by ratbagdctl.devel.
|
||||
#
|
||||
|
||||
config_ratbagd_devel = configuration_data()
|
||||
dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
|
||||
output : 'org.freedesktop.ratbag_devel1.conf',
|
||||
configuration : config_ratbagd_devel)
|
||||
|
||||
# This is a hack. We always install the devel policy file into
|
||||
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise.
|
||||
# This should never be used outside of developer machines anyway, but
|
||||
# installations on those may use different prefixes for building.
|
||||
# This is not set in stone, suggest something better if you can.
|
||||
dbussystemdir = join_paths('/', get_option('sysconfdir'), 'dbus-1', 'system.d')
|
||||
|
||||
executable('ratbagd.devel',
|
||||
src_ratbagd,
|
||||
dependencies : deps_ratbagd,
|
||||
include_directories : include_directories('src'),
|
||||
install : false,
|
||||
c_args : ['-DRATBAG_DBUS_INTERFACE="ratbag_devel1_@0@"'.format(ratbagd_sha),
|
||||
c_args : ['-DRATBAG_DBUS_INTERFACE="ratbag_devel1"',
|
||||
'-DDBUS_POLICY_SRC="@0@/@1@"'.format(meson.build_root(), dbus_devel_policy),
|
||||
'-DDBUS_POLICY_DST="@0@/@1@"'.format(dbussystemdir, dbus_devel_policy),
|
||||
'-DDISABLE_COREDUMP=1'],
|
||||
)
|
||||
|
||||
config_ratbagd_devel = configuration_data()
|
||||
config_ratbagd_devel.set('ratbagd_sha', ratbagd_sha)
|
||||
configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
|
||||
output : 'org.freedesktop.ratbag_devel1.conf',
|
||||
configuration : config_ratbagd_devel)
|
||||
|
||||
#### unit file ####
|
||||
if enable_systemd
|
||||
@@ -477,7 +512,7 @@ endif
|
||||
|
||||
dbusdir = get_option('dbus-root-dir')
|
||||
if dbusdir == ''
|
||||
dbusdir = join_paths(get_option('datadir'), 'dbus-1')
|
||||
dbusdir = join_paths(get_option('prefix'), get_option('datadir'), 'dbus-1')
|
||||
endif
|
||||
|
||||
configure_file(input : 'dbus/org.freedesktop.ratbag1.service.in',
|
||||
@@ -504,23 +539,46 @@ 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()
|
||||
else
|
||||
pymod = import('python')
|
||||
py3 = pymod.find_installation()
|
||||
if meson.version().version_compare('>= 0.53.0')
|
||||
dep_python3 = py3.dependency(embed : true)
|
||||
endif
|
||||
endif
|
||||
|
||||
# ratbagctl calls ratbagd over DBus
|
||||
# From python 3.8 we neeed python3-embed
|
||||
py_version = py3.language_version()
|
||||
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()
|
||||
config_ratbagctl.set('RATBAGD_API_VERSION', ratbagd_api_version)
|
||||
config_ratbagctl.set('version', meson.project_version())
|
||||
|
||||
ratbagctl_in = configure_file(input : 'tools/ratbagctl.in.in',
|
||||
output : 'ratbagctl.in',
|
||||
configuration: config_ratbagctl)
|
||||
|
||||
# ratbagctl is the commandline tool to interact with ratbagd over DBus.
|
||||
custom_target('ratbagctl',
|
||||
output : 'ratbagctl',
|
||||
input : ['tools/ratbagctl.in', 'tools/ratbagd.py'],
|
||||
input : [ratbagctl_in, 'tools/ratbagd.py'],
|
||||
build_by_default : true,
|
||||
command : [py3, join_paths(meson.source_root(), 'tools', 'merge_ratbagd.py'),
|
||||
'@INPUT@',
|
||||
'--output', '@OUTPUT@',
|
||||
'--version', meson.project_version()],
|
||||
'--output', '@OUTPUT@'],
|
||||
install: true,
|
||||
install_dir: get_option('bindir'))
|
||||
|
||||
@@ -533,9 +591,9 @@ man_ratbagctl = configure_file (
|
||||
)
|
||||
|
||||
config_ratbagctl_devel = configuration_data()
|
||||
config_ratbagctl_devel.set('ratbagd_sha', ratbagd_sha)
|
||||
config_ratbagctl_devel.set('MESON_BUILD_ROOT', meson.build_root())
|
||||
config_ratbagctl_devel.set('LIBRATBAG_DATA_DIR', libratbag_data_dir_devel)
|
||||
config_ratbagctl_devel.set('RATBAGD_API_VERSION', ratbagd_api_version)
|
||||
|
||||
configure_file(input : 'tools/toolbox.py',
|
||||
output : 'toolbox.py',
|
||||
@@ -567,7 +625,7 @@ swig_gen = generator(
|
||||
)
|
||||
|
||||
wrapper_deps = [
|
||||
dependency('python3'),
|
||||
dep_python3,
|
||||
dep_libratbag,
|
||||
dep_libshared,
|
||||
]
|
||||
@@ -578,7 +636,25 @@ 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'),
|
||||
install: false,
|
||||
)
|
||||
|
||||
i_source = join_paths(meson.source_root(), 'src', 'hidpp.i')
|
||||
c_source = swig_gen.process(i_source)
|
||||
shared_library(
|
||||
'hidpp',
|
||||
c_source,
|
||||
name_prefix: '_',
|
||||
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'),
|
||||
@@ -591,14 +667,17 @@ ratbagc_py_conf.set('LIBRATBAG_DATA_DIR', libratbag_data_dir_devel)
|
||||
ratbagc_py = configure_file(input: 'tools/ratbagc.py.in',
|
||||
output: 'ratbagc.py',
|
||||
configuration: ratbagc_py_conf)
|
||||
|
||||
# ratbag-command is a commandline tool with the UI as ratbagctl but instead
|
||||
# of connecting to ratbagd over DBus, it uses libratbag directly. This is a
|
||||
# development tool for protocol debugging etc.
|
||||
custom_target('ratbag-command',
|
||||
output : 'ratbag-command',
|
||||
input : ['tools/ratbagctl.in', ratbagc_py],
|
||||
input : [ratbagctl_in, ratbagc_py],
|
||||
build_by_default : true,
|
||||
command : [py3, join_paths(meson.source_root(), 'tools', 'merge_ratbagd.py'),
|
||||
'@INPUT@',
|
||||
'--output', '@OUTPUT@',
|
||||
'--version', meson.project_version()],
|
||||
'--output', '@OUTPUT@'],
|
||||
install: false)
|
||||
|
||||
#### output files ####
|
||||
|
||||
12
ratbagd/.gitignore
vendored
12
ratbagd/.gitignore
vendored
@@ -1,12 +0,0 @@
|
||||
*.a
|
||||
*.log
|
||||
*.o
|
||||
*.stamp
|
||||
*.swp
|
||||
*.trs
|
||||
*~
|
||||
.dirstamp
|
||||
.libs/
|
||||
/*.tar.xz
|
||||
tags
|
||||
__pycache__
|
||||
@@ -87,17 +87,10 @@ static int ratbagd_button_set_button(sd_bus *bus,
|
||||
r = ratbag_button_set_button(button->lib_button, map);
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"ButtonMapping",
|
||||
NULL);
|
||||
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"ActionType",
|
||||
"Mapping",
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -146,17 +139,10 @@ static int ratbagd_button_set_special(sd_bus *bus,
|
||||
r = ratbag_button_set_special(button->lib_button, special);
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"SpecialMapping",
|
||||
NULL);
|
||||
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"ActionType",
|
||||
"Mapping",
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -261,17 +247,10 @@ static int ratbagd_button_set_macro(sd_bus *bus,
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"Macro",
|
||||
NULL);
|
||||
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"ActionType",
|
||||
"Mapping",
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "libratbag-util.h"
|
||||
|
||||
struct ratbagd_device {
|
||||
unsigned int refcount;
|
||||
|
||||
struct ratbagd *ctx;
|
||||
RBNode node;
|
||||
char *sysname;
|
||||
@@ -170,8 +172,11 @@ static void ratbagd_device_commit_pending(void *data)
|
||||
int r;
|
||||
|
||||
r = ratbag_device_commit(device->lib_device);
|
||||
if (r)
|
||||
log_error("error committing device (%d)\n", r);
|
||||
if (r < 0)
|
||||
ratbagd_device_resync(device, device->ctx->bus);
|
||||
ratbagd_device_unref(device);
|
||||
}
|
||||
|
||||
static int ratbagd_device_commit(sd_bus_message *m,
|
||||
@@ -182,7 +187,7 @@ static int ratbagd_device_commit(sd_bus_message *m,
|
||||
|
||||
ratbagd_schedule_task(device->ctx,
|
||||
ratbagd_device_commit_pending,
|
||||
device);
|
||||
ratbagd_device_ref(device));
|
||||
|
||||
CHECK_CALL(sd_bus_reply_method_return(m, "u", 0));
|
||||
|
||||
@@ -230,7 +235,7 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
const char *sysname,
|
||||
struct ratbag_device *lib_device)
|
||||
{
|
||||
_cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL;
|
||||
_cleanup_(ratbagd_device_unrefp) struct ratbagd_device *device = NULL;
|
||||
struct ratbag_profile *profile;
|
||||
unsigned int i;
|
||||
int r;
|
||||
@@ -240,6 +245,7 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
assert(sysname);
|
||||
|
||||
device = zalloc(sizeof(*device));
|
||||
device->refcount = 1;
|
||||
device->ctx = ctx;
|
||||
rbnode_init(&device->node);
|
||||
device->lib_device = ratbag_device_ref(lib_device);
|
||||
@@ -282,12 +288,12 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
|
||||
static void ratbagd_device_free(struct ratbagd_device *device)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
assert(!ratbagd_device_linked(device));
|
||||
|
||||
@@ -301,7 +307,26 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
|
||||
|
||||
assert(!device->lib_device); /* ratbag yields !NULL if still pinned */
|
||||
|
||||
return mfree(device);
|
||||
mfree(device);
|
||||
}
|
||||
|
||||
struct ratbagd_device *ratbagd_device_ref(struct ratbagd_device *device)
|
||||
{
|
||||
assert(device->refcount > 0);
|
||||
|
||||
++device->refcount;
|
||||
return device;
|
||||
}
|
||||
|
||||
struct ratbagd_device *ratbagd_device_unref(struct ratbagd_device *device)
|
||||
{
|
||||
assert(device->refcount > 0);
|
||||
|
||||
--device->refcount;
|
||||
if (device->refcount == 0)
|
||||
ratbagd_device_free(device);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device)
|
||||
|
||||
562
ratbagd/ratbagd-json.c
Normal file
562
ratbagd/ratbagd-json.c
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* JSON parser for ratbag test devices. The JSON format is not fixed and may
|
||||
change at any time, but basically looks like this:
|
||||
|
||||
{
|
||||
"profiles": [
|
||||
{
|
||||
"is_active": bool,
|
||||
"is_default": bool,
|
||||
"is_disabled": bool,
|
||||
"rate": int,
|
||||
"report_rates": [ int, ...],
|
||||
"capabilities": [int, ...] # profile capabilities
|
||||
"resolutions": [
|
||||
{
|
||||
"xres": int,
|
||||
"yres": int,
|
||||
"dpi_min", int,
|
||||
"dpi_max", int,
|
||||
"is_active": bool,
|
||||
"is_default": bool,
|
||||
"capabilities": [int, ...] # resolution capabilities
|
||||
}
|
||||
]
|
||||
"buttons": [
|
||||
"action_type": "<enum>" # none, button, key, special, macro, unknown
|
||||
"button": int, # if button
|
||||
"key": int, # if key
|
||||
"special": "<enum>", # if special, for values see see special_lookup()
|
||||
"macro": ["+B", "-B", "t400"] # if macro. uppercase only
|
||||
|
||||
]
|
||||
"leds": [ ]
|
||||
},
|
||||
{
|
||||
... next profile ...
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
ratbagd uses a minimum sane device (1 profile, 1 resolution, etc.) and any
|
||||
JSON instructions get merged into that device. Which means you usually
|
||||
only need to set those bits you care about being checked.
|
||||
*/
|
||||
|
||||
#include "libratbag-util.h"
|
||||
#include "ratbagd-json.h"
|
||||
#include "ratbagd-test.h"
|
||||
#include <json-glib/json-glib.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
|
||||
/* Hack because we don't do proper data passing */
|
||||
static int num_resolutions;
|
||||
static int num_buttons;
|
||||
static int num_leds;
|
||||
|
||||
static int parse_error = 0;
|
||||
|
||||
#define parser_error(element_) { \
|
||||
log_error("json: parser error: %s:%d: element '%s'\n", __func__, __LINE__, (element_)); \
|
||||
parse_error = -EINVAL; \
|
||||
goto out; \
|
||||
}
|
||||
|
||||
static void parse_resolution_member(JsonObject *obj, const gchar *name,
|
||||
JsonNode *node, void *data)
|
||||
{
|
||||
struct ratbag_test_resolution *resolution = data;
|
||||
|
||||
if (streq(name, "xres")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("xres");
|
||||
|
||||
resolution->xres = v;
|
||||
log_verbose("json: xres: %d\n", v);
|
||||
} else if (streq(name, "yres")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("yres");
|
||||
|
||||
resolution->yres = v;
|
||||
log_verbose("json: yres: %d\n", v);
|
||||
} else if (streq(name, "dpi_min")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("dpi_min");
|
||||
|
||||
resolution->dpi_min = v;
|
||||
log_verbose("json: dpi_min: %d\n", v);
|
||||
} else if (streq(name, "dpi_max")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("dpi_min");
|
||||
|
||||
resolution->dpi_max = v;
|
||||
log_verbose("json: dpi_max: %d\n", v);
|
||||
} else if (streq(name, "is_active")) {
|
||||
gboolean v = json_object_get_boolean_member(obj, name);
|
||||
resolution->active = v;
|
||||
log_verbose("json: is_active: %d\n", v);
|
||||
} else if (streq(name, "is_default")) {
|
||||
gboolean v = json_object_get_boolean_member(obj, name);
|
||||
resolution->dflt = v;
|
||||
log_verbose("json: is_default: %d\n", v);
|
||||
} else if (streq(name, "capabilities")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
|
||||
assert(json_array_get_length(a) < ARRAY_LENGTH(resolution->caps));
|
||||
for (size_t s = 0; s < json_array_get_length(a); s++) {
|
||||
int v = json_array_get_int_element(a, s);
|
||||
if (v > RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION)
|
||||
parser_error("capabilities");
|
||||
resolution->caps[s] = v;
|
||||
}
|
||||
|
||||
log_verbose("json: caps: %d %d %d %d %d...\n",
|
||||
resolution->caps[0],
|
||||
resolution->caps[1],
|
||||
resolution->caps[2],
|
||||
resolution->caps[3],
|
||||
resolution->caps[4]);
|
||||
} else {
|
||||
log_error("json: unknown resolution key '%s'\n", name);
|
||||
parse_error = -EINVAL;
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_resolution(JsonNode *node,
|
||||
struct ratbag_test_resolution *resolution)
|
||||
{
|
||||
JsonObject *obj = json_node_get_object(node);
|
||||
|
||||
json_object_foreach_member(obj, parse_resolution_member, resolution);
|
||||
}
|
||||
|
||||
static void parse_led_member(JsonObject *obj, const gchar *name,
|
||||
JsonNode *node, void *data)
|
||||
{
|
||||
struct ratbag_test_led *led = data;
|
||||
|
||||
if (streq(name, "type")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > RATBAG_LED_TYPE_SWITCHES)
|
||||
parser_error("type");
|
||||
|
||||
led->type = v;
|
||||
log_verbose("json: type: %d\n", v);
|
||||
} else if (streq(name, "mode")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > RATBAG_LED_BREATHING)
|
||||
parser_error("mode");
|
||||
|
||||
led->mode = v;
|
||||
log_verbose("json: mode: %d\n", v);
|
||||
} else if (streq(name, "duration")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 10000)
|
||||
parser_error("duration");
|
||||
|
||||
led->ms = v;
|
||||
log_verbose("json: duration: %d\n", v);
|
||||
} else if (streq(name, "brightness")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 100)
|
||||
parser_error("brightness");
|
||||
|
||||
led->brightness = v;
|
||||
log_verbose("json: brightness: %d\n", v);
|
||||
} else if (streq(name, "color")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
|
||||
assert(json_array_get_length(a) == 3);
|
||||
led->color.red = json_array_get_int_element(a, 0);
|
||||
led->color.green = json_array_get_int_element(a, 1);
|
||||
led->color.blue = json_array_get_int_element(a, 2);
|
||||
log_verbose("json: color: %02x%02x%02x\n",
|
||||
led->color.red,
|
||||
led->color.green,
|
||||
led->color.blue);
|
||||
} else {
|
||||
log_error("json: unknown led key '%s'\n", name);
|
||||
parse_error = -EINVAL;
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_led(JsonNode *node, struct ratbag_test_led *led)
|
||||
{
|
||||
JsonObject *obj = json_node_get_object(node);
|
||||
|
||||
json_object_foreach_member(obj, parse_led_member, led);
|
||||
}
|
||||
|
||||
static enum ratbag_button_action_special
|
||||
special_lookup(const char *string)
|
||||
{
|
||||
const struct {
|
||||
const char *key;
|
||||
enum ratbag_button_action_special special;
|
||||
} lut[] = {
|
||||
{ "invalid", RATBAG_BUTTON_ACTION_SPECIAL_INVALID},
|
||||
{ "unknown", RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN},
|
||||
{ "doubleclick", RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK},
|
||||
{ "wheel-left", RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT},
|
||||
{ "wheel-right", RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT},
|
||||
{ "wheel-up", RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP},
|
||||
{ "wheel-down", RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN},
|
||||
{ "ratchet-mode-switch", RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH},
|
||||
{ "resolution-cycle-up", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP},
|
||||
{ "resolution-cycledown", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN},
|
||||
{ "resolution-up", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP},
|
||||
{ "resolution-down", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN},
|
||||
{ "resolution-alternate", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE},
|
||||
{ "resolution-default", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT},
|
||||
{ "profile-cycle-up", RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP},
|
||||
{ "profile-cycle-down", RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN},
|
||||
{ "profile-up", RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP},
|
||||
{ "profile-down", RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN},
|
||||
{ "second-mode", RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE},
|
||||
{ "battery-level", RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(lut); i++) {
|
||||
if (streq(string, lut[i].key))
|
||||
return lut[i].special;
|
||||
}
|
||||
|
||||
parser_error("special");
|
||||
|
||||
out:
|
||||
return RATBAG_BUTTON_ACTION_SPECIAL_INVALID;
|
||||
}
|
||||
|
||||
static enum ratbag_button_action_type
|
||||
action_type_lookup(const char *string)
|
||||
{
|
||||
const struct {
|
||||
const char *key;
|
||||
enum ratbag_button_action_type type;
|
||||
} lut[] = {
|
||||
{ "none", RATBAG_BUTTON_ACTION_TYPE_NONE},
|
||||
{ "button", RATBAG_BUTTON_ACTION_TYPE_BUTTON},
|
||||
{ "special", RATBAG_BUTTON_ACTION_TYPE_SPECIAL},
|
||||
{ "key", RATBAG_BUTTON_ACTION_TYPE_KEY},
|
||||
{ "macro", RATBAG_BUTTON_ACTION_TYPE_MACRO},
|
||||
{ "unknown", RATBAG_BUTTON_ACTION_TYPE_UNKNOWN},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(lut); i++) {
|
||||
if (streq(string, lut[i].key))
|
||||
return lut[i].type;
|
||||
}
|
||||
|
||||
parser_error("action_type");
|
||||
|
||||
out:
|
||||
return RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline struct ratbag_test_macro_event
|
||||
parse_macro(const char *m)
|
||||
{
|
||||
struct ratbag_test_macro_event event = {
|
||||
.type = RATBAG_MACRO_EVENT_INVALID,
|
||||
.value = 0,
|
||||
};
|
||||
char keyname[32];
|
||||
|
||||
if (strlen(m) < 2)
|
||||
goto out;
|
||||
|
||||
switch(m[0]) {
|
||||
case '+':
|
||||
event.type = RATBAG_MACRO_EVENT_KEY_PRESSED;
|
||||
snprintf(keyname, sizeof(keyname), "KEY_%s", m + 1);
|
||||
event.value = libevdev_event_code_from_name(EV_KEY,
|
||||
keyname);
|
||||
log_verbose("json: macro: +%s\n", keyname);
|
||||
break;
|
||||
case '-':
|
||||
event.type = RATBAG_MACRO_EVENT_KEY_RELEASED;
|
||||
snprintf(keyname, sizeof(keyname), "KEY_%s", m + 1);
|
||||
event.value = libevdev_event_code_from_name(EV_KEY,
|
||||
keyname);
|
||||
log_verbose("json: macro: -%s\n", keyname);
|
||||
break;
|
||||
case 't':
|
||||
event.type = RATBAG_MACRO_EVENT_WAIT;
|
||||
event.value = atoi(m+1);
|
||||
log_verbose("json: macro: t%d\n", event.value);
|
||||
break;
|
||||
default:
|
||||
parser_error("macro");
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
static void parse_button_member(JsonObject *obj, const gchar *name,
|
||||
JsonNode *node, void *data)
|
||||
{
|
||||
struct ratbag_test_button *button = data;
|
||||
|
||||
if (streq(name, "action_type")) {
|
||||
const gchar* v = json_object_get_string_member(obj, name);
|
||||
button->action_type = action_type_lookup(v);
|
||||
log_verbose("json: action_type: %s\n", v);
|
||||
} else if (streq(name, "button")) {
|
||||
gint v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 32)
|
||||
parser_error("button");
|
||||
|
||||
button->button = v;
|
||||
log_verbose("json: button: %d\n", v);
|
||||
} else if (streq(name, "key")) {
|
||||
gint v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > KEY_MAX)
|
||||
parser_error("key");
|
||||
|
||||
button->key = v;
|
||||
log_verbose("json: key: %d\n", v);
|
||||
} else if (streq(name, "special")) {
|
||||
const gchar *v = json_object_get_string_member(obj, name);
|
||||
button->special = special_lookup(v);
|
||||
log_verbose("json: special: %s\n", v);
|
||||
} else if (streq(name, "macro")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
|
||||
assert(json_array_get_length(a) < ARRAY_LENGTH(button->macro));
|
||||
for (size_t s = 0; s < json_array_get_length(a); s++) {
|
||||
const gchar *v = json_array_get_string_element(a, s);
|
||||
button->macro[s] = parse_macro(v);
|
||||
}
|
||||
} else {
|
||||
log_error("json: unknown button key '%s'\n", name);
|
||||
parse_error = -EINVAL;
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_button(JsonNode *node, struct ratbag_test_button *button)
|
||||
{
|
||||
JsonObject *obj = json_node_get_object(node);
|
||||
|
||||
json_object_foreach_member(obj, parse_button_member, button);
|
||||
}
|
||||
|
||||
static void parse_profile_member(JsonObject *obj, const gchar *name,
|
||||
JsonNode *node, void *data)
|
||||
{
|
||||
struct ratbag_test_profile *profile = data;
|
||||
|
||||
if (streq(name, "name")) {
|
||||
const char *v = json_object_get_string_member(obj, name);
|
||||
|
||||
if (v == NULL)
|
||||
parser_error("name");
|
||||
|
||||
free(profile->name);
|
||||
profile->name = strdup_safe(v);
|
||||
log_verbose("name: %s\n", v);
|
||||
} else if (streq(name, "is_default")) {
|
||||
gboolean v = json_object_get_boolean_member(obj, name);
|
||||
profile->dflt = v;
|
||||
log_verbose("json: is_default: %d\n", v);
|
||||
} else if (streq(name, "is_active")) {
|
||||
gboolean v = json_object_get_boolean_member(obj, name);
|
||||
profile->active = v;
|
||||
log_verbose("json: is_active: %d\n", v);
|
||||
} else if (streq(name, "is_disabled")) {
|
||||
gboolean v = json_object_get_boolean_member(obj, name);
|
||||
profile->disabled = v;
|
||||
log_verbose("json: is_disabled: %d\n", v);
|
||||
} else if (streq(name, "rate")) {
|
||||
gboolean v = json_object_get_int_member(obj, name);
|
||||
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("rate");
|
||||
|
||||
profile->hz = v;
|
||||
log_verbose("json: rate: %d\n", v);
|
||||
} else if (streq(name, "report_rates")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
assert(json_array_get_length(a) < ARRAY_LENGTH(profile->report_rates));
|
||||
for (size_t s = 0; s < json_array_get_length(a); s++) {
|
||||
int v = json_array_get_int_element(a, s);
|
||||
if (v < 0 || v > 20000)
|
||||
parser_error("report_rate");
|
||||
profile->report_rates[s] = v;
|
||||
}
|
||||
|
||||
log_verbose("json: report rates: %d %d %d %d %d\n",
|
||||
profile->report_rates[0],
|
||||
profile->report_rates[1],
|
||||
profile->report_rates[2],
|
||||
profile->report_rates[3],
|
||||
profile->report_rates[4]);
|
||||
} else if (streq(name, "capabilities")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
|
||||
assert(json_array_get_length(a) < ARRAY_LENGTH(profile->caps));
|
||||
for (size_t s = 0; s < json_array_get_length(a); s++) {
|
||||
int v = json_array_get_int_element(a, s);
|
||||
profile->caps[s] = v;
|
||||
}
|
||||
|
||||
log_verbose("json: caps: %d %d %d %d %d...\n",
|
||||
profile->caps[0],
|
||||
profile->caps[1],
|
||||
profile->caps[2],
|
||||
profile->caps[3],
|
||||
profile->caps[4]);
|
||||
} else if (streq(name, "resolutions")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
GList *list = json_array_get_elements(a);
|
||||
GList *l = list;
|
||||
int idx = 0;
|
||||
while (l != NULL) {
|
||||
log_verbose("json: processing resolution %d\n", idx);
|
||||
parse_resolution(l->data, &profile->resolutions[idx]);
|
||||
l = g_list_next(l);
|
||||
idx++;
|
||||
}
|
||||
g_list_free(list);
|
||||
num_resolutions = max(idx, num_resolutions);
|
||||
} else if (streq(name, "leds")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
GList *list = json_array_get_elements(a);
|
||||
GList *l = list;
|
||||
int idx = 0;
|
||||
while (l != NULL) {
|
||||
log_verbose("json: processing LED %d\n", idx);
|
||||
parse_led(l->data, &profile->leds[idx]);
|
||||
l = g_list_next(l);
|
||||
idx++;
|
||||
}
|
||||
g_list_free(list);
|
||||
num_leds = max(idx, num_leds);
|
||||
} else if (streq(name, "buttons")) {
|
||||
JsonArray *a = json_object_get_array_member(obj, name);
|
||||
GList *list = json_array_get_elements(a);
|
||||
GList *l = list;
|
||||
int idx = 0;
|
||||
while (l != NULL) {
|
||||
log_verbose("json: processing button %d\n", idx);
|
||||
parse_button(l->data, &profile->buttons[idx]);
|
||||
l = g_list_next(l);
|
||||
idx++;
|
||||
}
|
||||
g_list_free(list);
|
||||
num_buttons = max(idx, num_buttons);
|
||||
} else {
|
||||
log_error("json: unknown profile key '%s'\n", name);
|
||||
parse_error = -EINVAL;
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_profile(JsonNode *node,
|
||||
struct ratbag_test_profile *profile)
|
||||
{
|
||||
JsonObject *obj = json_node_get_object(node);
|
||||
|
||||
json_object_foreach_member(obj, parse_profile_member, profile);
|
||||
}
|
||||
|
||||
/* declared here because this isn't really public API, we just need to
|
||||
* access it from the tests */
|
||||
int ratbagd_parse_json(const char *data, struct ratbag_test_device *device)
|
||||
{
|
||||
g_autoptr(JsonParser) parser = NULL;
|
||||
JsonNode *root;
|
||||
JsonObject *obj;
|
||||
JsonArray *arr;
|
||||
int r = -EINVAL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
error = 0;
|
||||
parser = json_parser_new();
|
||||
if (!json_parser_load_from_data(parser, data, strlen(data), &error)) {
|
||||
log_error("Failed to load JSON: %s\n", error->message);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_verbose("json: data: %s\n", data);
|
||||
|
||||
root = json_parser_get_root(parser);
|
||||
if (JSON_NODE_TYPE(root) != JSON_NODE_OBJECT)
|
||||
parser_error("root");
|
||||
|
||||
obj = json_node_get_object(root);
|
||||
arr = json_object_get_array_member(obj, "profiles");
|
||||
if (!arr)
|
||||
parser_error("profiles");
|
||||
|
||||
/* Our test device is preloaded with sane defaults, let's keep those */
|
||||
num_resolutions = device->num_resolutions;
|
||||
num_buttons = device->num_buttons;
|
||||
num_leds = device->num_leds;
|
||||
|
||||
g_autoptr(GList) list = json_array_get_elements(arr);
|
||||
GList *l = list;
|
||||
int idx = 0;
|
||||
while (l != NULL) {
|
||||
log_verbose("json: processing profile %d\n", idx);
|
||||
parse_profile(l->data, &device->profiles[idx]);
|
||||
if (parse_error != 0)
|
||||
goto out;;
|
||||
l = g_list_next(l);
|
||||
idx++;
|
||||
}
|
||||
device->num_profiles = idx;
|
||||
device->num_resolutions = num_resolutions;
|
||||
device->num_buttons = num_buttons;
|
||||
device->num_leds = num_leds;
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
28
ratbagd/ratbagd-json.h
Normal file
28
ratbagd/ratbagd-json.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libratbag-test.h"
|
||||
|
||||
int ratbagd_parse_json(const char *data, struct ratbag_test_device *device);
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistr.h>
|
||||
#include <uniconv.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "ratbagd.h"
|
||||
@@ -382,18 +384,23 @@ ratbagd_profile_get_name(sd_bus *bus,
|
||||
{
|
||||
struct ratbagd_profile *profile = userdata;
|
||||
const char *name = ratbag_profile_get_name(profile->lib_profile);
|
||||
_cleanup_free_ char *asciiname;
|
||||
_cleanup_free_ char *utf8 = NULL;
|
||||
|
||||
if (!name)
|
||||
asciiname = strdup("");
|
||||
else
|
||||
/* This should really be a UTF8 check and it should really be in
|
||||
* libratbag, but for now this will do to at least not kick us off
|
||||
* the bus. https://github.com/libratbag/libratbag/issues/617
|
||||
*/
|
||||
asciiname = strdup_ascii_only(name);
|
||||
if (name) {
|
||||
if (u8_check((const uint8_t*)name, strlen(name)) == NULL)
|
||||
utf8 = strdup(name);
|
||||
else
|
||||
utf8 = (char*)u8_strconv_from_encoding(name,
|
||||
"ISO-8859-1",
|
||||
iconveh_question_mark);
|
||||
if (!utf8)
|
||||
utf8 = (char*)strdup_ascii_only(name);
|
||||
} else {
|
||||
utf8 = strdup("");
|
||||
}
|
||||
|
||||
CHECK_CALL(sd_bus_message_append(reply, "s", asciiname));
|
||||
|
||||
CHECK_CALL(sd_bus_message_append(reply, "s", utf8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,159 +30,21 @@
|
||||
#include <systemd/sd-event.h>
|
||||
|
||||
#include "libratbag-test.h"
|
||||
#include "ratbagd-json.h"
|
||||
|
||||
/* A pre-setup sane device. Use for sanity testing by toggling the various
|
||||
* error conditions.
|
||||
*/
|
||||
static const struct ratbag_test_device ratbagd_test_device_descr = {
|
||||
.num_profiles = 4,
|
||||
.num_resolutions = 3,
|
||||
.num_buttons = 4,
|
||||
.num_leds = 3,
|
||||
.profiles = {
|
||||
{
|
||||
.name = NULL,
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 0 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = KEY_3 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_RIGHT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 300 },
|
||||
},
|
||||
}
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 100, .yres = 200,
|
||||
.dpi_min = 50, .dpi_max = 5000},
|
||||
{ .xres = 200, .yres = 300, .active = true, .dflt = true },
|
||||
{ .xres = 300, .yres = 400 },
|
||||
},
|
||||
.active = true,
|
||||
.dflt = false,
|
||||
.hz = 1000,
|
||||
.report_rates = {500, 1000},
|
||||
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_OFF,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20,
|
||||
.type = RATBAG_LED_TYPE_LOGO,
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20,
|
||||
.type = RATBAG_LED_TYPE_SIDE,
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.ms = 333,
|
||||
.brightness = 40,
|
||||
.type = RATBAG_LED_TYPE_SIDE,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 4 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 5 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 6 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 7 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 1100, .yres = 1200, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1200, .yres = 1300, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1300, .yres = 1400, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.hz = 2000,
|
||||
.active = false,
|
||||
.dflt = true,
|
||||
.name = "test profile 2",
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 150 },
|
||||
}
|
||||
},
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 2 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 3 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 2100, .yres = 2200, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2200, .yres = 2300, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2300, .yres = 2400, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.hz = 3000,
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.ms = 333,
|
||||
.brightness = 40
|
||||
}
|
||||
},
|
||||
.active = false,
|
||||
.dflt = false,
|
||||
},
|
||||
{
|
||||
.disabled = true,
|
||||
},
|
||||
},
|
||||
.destroyed = NULL,
|
||||
.destroyed_data = NULL,
|
||||
};
|
||||
|
||||
|
||||
int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
static int load_test_device(sd_bus_message *m,
|
||||
struct ratbagd *ctx,
|
||||
const struct ratbag_test_device *source)
|
||||
{
|
||||
static int count;
|
||||
static struct ratbagd_device *ratbagd_test_device = NULL;
|
||||
struct ratbagd *ctx = userdata;
|
||||
struct ratbag_device *device;
|
||||
int r;
|
||||
char devicename[64];
|
||||
|
||||
if (ratbagd_test_device) {
|
||||
ratbagd_device_unlink(ratbagd_test_device);
|
||||
ratbagd_device_free(ratbagd_test_device);
|
||||
ratbagd_device_unref(ratbagd_test_device);
|
||||
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
@@ -191,9 +53,10 @@ int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
NULL);
|
||||
}
|
||||
|
||||
device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr);
|
||||
device = ratbag_device_new_test_device(ctx->lib_ctx, source);
|
||||
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device);
|
||||
snprintf(devicename, sizeof(devicename), "testdevice%d", count++);
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, devicename, device);
|
||||
|
||||
/* the ratbagd_device takes its own reference, drop ours */
|
||||
ratbag_device_unref(device);
|
||||
@@ -216,6 +79,55 @@ int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ratbag_test_device default_device_descr = {
|
||||
.num_profiles = 1,
|
||||
.num_resolutions = 1,
|
||||
.num_buttons = 1,
|
||||
.num_leds = 0,
|
||||
.profiles = {
|
||||
{
|
||||
.name = NULL,
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 0 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 1000, .yres = 1000,
|
||||
.dpi_min = 1000, .dpi_max = 1000},
|
||||
},
|
||||
.disabled = false,
|
||||
.active = true,
|
||||
.dflt = true,
|
||||
.hz = 1000,
|
||||
.report_rates = {1000},
|
||||
},
|
||||
},
|
||||
.destroyed = NULL,
|
||||
.destroyed_data = NULL,
|
||||
};
|
||||
|
||||
|
||||
int ratbagd_load_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd *ctx = userdata;
|
||||
struct ratbag_test_device td = default_device_descr;
|
||||
char *data;
|
||||
int r = 0;
|
||||
|
||||
CHECK_CALL(sd_bus_message_read(m, "s", &data));
|
||||
|
||||
r = ratbagd_parse_json(data, &td);
|
||||
if (r != 0) {
|
||||
log_error("Failed to parse JSON data\n");
|
||||
} else {
|
||||
r = load_test_device(m, ctx, &td);
|
||||
}
|
||||
return sd_bus_reply_method_return(m, "i", r);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ratbagd_init_test_device(struct ratbagd *ctx)
|
||||
@@ -223,7 +135,7 @@ void ratbagd_init_test_device(struct ratbagd *ctx)
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
ratbagd_reset_test_device(NULL, ctx, NULL);
|
||||
load_test_device(NULL, ctx, &default_device_descr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -32,4 +32,7 @@ void ratbagd_init_test_device(struct ratbagd *ctx);
|
||||
int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error);
|
||||
int ratbagd_load_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error);
|
||||
#endif /* RATBAG_DEVELOPER_EDITION */
|
||||
|
||||
@@ -3,12 +3,27 @@
|
||||
ratbagd \- system daemon to introspect and modify configurable mice
|
||||
.SH SYNOPSIS
|
||||
.B ratbagd
|
||||
.RB [ \-\-verbose ]
|
||||
.RB [ \-\-verbose[=debug]|\-\-quiet|\-\-version|\-\-help]
|
||||
.SH DESCRIPTION
|
||||
.B ratbagd
|
||||
starts the daemon. It shouldn't be invoked directly;
|
||||
.B ratbagd
|
||||
is normally started through DBus activation.
|
||||
.SH OPTIONS
|
||||
.TP 8
|
||||
.B \-\-help
|
||||
Print help and exit
|
||||
.TP 8
|
||||
.B \-\-verbose, \-\-verbose=debug
|
||||
Enable verbose output, optionally including raw messages as sent and
|
||||
received from the device. This should be use to debug any issues with the
|
||||
device.
|
||||
.TP 8
|
||||
.B \-\-quiet
|
||||
Disable any output but error messages.
|
||||
.TP 8
|
||||
.B \-\-version
|
||||
Show the version number.
|
||||
.SH SEE ALSO
|
||||
.BR ratbagctl (1)
|
||||
.SH AUTHORS
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <libratbag.h>
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
@@ -166,9 +167,10 @@ static int ratbagd_get_devices(sd_bus *bus,
|
||||
|
||||
static const sd_bus_vtable ratbagd_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("APIVersion", "i", 0, offsetof(struct ratbagd, api_version), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
SD_BUS_METHOD("ResetTestDevice", "", "u", ratbagd_reset_test_device, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("LoadTestDevice", "s", "i", ratbagd_load_test_device, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
#endif /* RATBAG_DEVELOPER_EDITION */
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
@@ -200,7 +202,7 @@ static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
/* device was removed, unlink it and destroy our context */
|
||||
if (device) {
|
||||
ratbagd_device_unlink(device);
|
||||
ratbagd_device_free(device);
|
||||
ratbagd_device_unref(device);
|
||||
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
@@ -283,7 +285,7 @@ static struct ratbagd *ratbagd_free(struct ratbagd *ctx)
|
||||
|
||||
RATBAGD_DEVICE_FOREACH_SAFE(device, tmp, ctx) {
|
||||
ratbagd_device_unlink(device);
|
||||
ratbagd_device_free(device);
|
||||
ratbagd_device_unref(device);
|
||||
}
|
||||
|
||||
ctx->bus = sd_bus_flush_close_unref(ctx->bus);
|
||||
@@ -345,6 +347,7 @@ static int ratbagd_new(struct ratbagd **out)
|
||||
int r;
|
||||
|
||||
ctx = zalloc(sizeof(*ctx));
|
||||
ctx->api_version = RATBAGD_API_VERSION;
|
||||
|
||||
r = sd_event_default(&ctx->event);
|
||||
if (r < 0)
|
||||
@@ -354,6 +357,7 @@ static int ratbagd_new(struct ratbagd **out)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_verbose("Initializing libratbag\n");
|
||||
ctx->lib_ctx = ratbag_create_context(&ratbagd_lib_interface, ctx);
|
||||
if (!ctx->lib_ctx)
|
||||
return -ENOMEM;
|
||||
@@ -518,9 +522,95 @@ static int ratbagd_run(struct ratbagd *ctx)
|
||||
ctx);
|
||||
sd_event_add_post(ctx->event, NULL, before_idle_cb, ctx);
|
||||
|
||||
log_verbose("DBus server ready\n");
|
||||
|
||||
return sd_event_loop(ctx->event);
|
||||
}
|
||||
|
||||
static bool install_ratbagd_devel_dbus_policy(void)
|
||||
{
|
||||
bool rc = true;
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
_cleanup_close_ int in = -1, out = -1;
|
||||
int nread, nwrite;
|
||||
char buf[40960];
|
||||
int r;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus_message *m = NULL;
|
||||
sd_bus *bus = NULL;
|
||||
|
||||
rc = false;
|
||||
|
||||
log_verbose("Installing DBus policy file to %s\n", DBUS_POLICY_DST);
|
||||
|
||||
in = open(DBUS_POLICY_SRC, O_RDONLY);
|
||||
if (in == -1) {
|
||||
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");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
nread = read(in, buf, sizeof(buf));
|
||||
if (nread < 0) {
|
||||
log_error("Failed to read policy file: %m\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
nwrite = write(out, buf, nread);
|
||||
if (nread != nwrite) {
|
||||
log_error("Failed to write policy file: %m\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now poke DBus to reload itself */
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0) {
|
||||
log_error("Unable to open system bus: %s\n", strerror(-r));
|
||||
goto out;
|
||||
}
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"ReloadConfig",
|
||||
&error,
|
||||
&m,
|
||||
"");
|
||||
if (r < 0) {
|
||||
log_error("Failed to call DBus ReloadConfig: %s\n",
|
||||
error.message);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = true;
|
||||
|
||||
out:
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(m);
|
||||
sd_bus_unref(bus);
|
||||
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void remove_ratbagd_devel_dbus_policy(void)
|
||||
{
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
unlink(DBUS_POLICY_DST);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct ratbagd *ctx = NULL;
|
||||
@@ -538,18 +628,21 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
} else if (streq(argv[1], "--quiet")) {
|
||||
log_level = LL_QUIET;
|
||||
} else if (streq(argv[1], "--verbose=raw")) {
|
||||
} else if (streq(argv[1], "--verbose") || streq(argv[1], "--verbose=raw")) {
|
||||
log_level = LL_RAW;
|
||||
} else if (streq(argv[1], "--verbose")) {
|
||||
} else if (streq(argv[1], "--verbose=debug")) {
|
||||
log_level = LL_VERBOSE;
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s [--version | --quiet | --verbose[=raw]]\n",
|
||||
fprintf(stderr, "Usage: %s [--version | --quiet | --verbose[=debug]]\n",
|
||||
program_invocation_short_name);
|
||||
r = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!install_ratbagd_devel_dbus_policy())
|
||||
goto exit;
|
||||
|
||||
r = ratbagd_new(&ctx);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
@@ -558,6 +651,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
r = ratbagd_run(ctx);
|
||||
|
||||
remove_ratbagd_devel_dbus_policy();
|
||||
exit:
|
||||
ratbagd_free(ctx);
|
||||
|
||||
|
||||
@@ -170,7 +170,8 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
struct ratbagd *ctx,
|
||||
const char *sysname,
|
||||
struct ratbag_device *lib_device);
|
||||
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device);
|
||||
struct ratbagd_device *ratbagd_device_ref(struct ratbagd_device *device);
|
||||
struct ratbagd_device *ratbagd_device_unref(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_path(struct ratbagd_device *device);
|
||||
unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device);
|
||||
@@ -181,7 +182,7 @@ bool ratbagd_device_linked(struct ratbagd_device *device);
|
||||
void ratbagd_device_link(struct ratbagd_device *device);
|
||||
void ratbagd_device_unlink(struct ratbagd_device *device);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_unref);
|
||||
|
||||
struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx,
|
||||
const char *name);
|
||||
@@ -217,6 +218,8 @@ struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device);
|
||||
*/
|
||||
|
||||
struct ratbagd {
|
||||
int api_version;
|
||||
|
||||
sd_event *event;
|
||||
struct ratbag *lib_ctx;
|
||||
struct udev_monitor *monitor;
|
||||
|
||||
120
release.sh
120
release.sh
@@ -90,13 +90,11 @@ check_option_args() {
|
||||
#
|
||||
check_modules_specification() {
|
||||
|
||||
if [ x"$MODFILE" = x ]; then
|
||||
if [ x"${INPUT_MODULES}" = x ]; then
|
||||
echo ""
|
||||
echo "Error: no modules specified (blank command line)."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ x"${INPUT_MODULES}" = x ]; then
|
||||
echo ""
|
||||
echo "Error: no modules specified (blank command line)."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
@@ -112,7 +110,7 @@ Subject: [ANNOUNCE] $pkg_name $pkg_version
|
||||
To: $list_to
|
||||
Cc: $list_cc
|
||||
|
||||
libratbag $tag_name is out.
|
||||
$pkg_name $tag_name is out.
|
||||
|
||||
The list of interesting changes are:
|
||||
|
||||
@@ -129,43 +127,12 @@ RELEASE
|
||||
The libratbag project does not generate tarballs for releases, you can
|
||||
grab one directly from github:
|
||||
|
||||
https://github.com/libratbag/libratbag/archive/$tag_name/$tarball
|
||||
https://github.com/libratbag/$pkg_name/archive/$tag_name/$tarball
|
||||
|
||||
RELEASE
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: read_modfile
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Read the module names from the file and set a variable to hold them
|
||||
# This will be the same interface as cmd line supplied modules
|
||||
#
|
||||
read_modfile() {
|
||||
|
||||
if [ x"$MODFILE" != x ]; then
|
||||
# Make sure the file is sane
|
||||
if [ ! -r "$MODFILE" ]; then
|
||||
echo "Error: module file '$MODFILE' is not readable or does not exist."
|
||||
exit 1
|
||||
fi
|
||||
# read from input file, skipping blank and comment lines
|
||||
while read line; do
|
||||
# skip blank lines
|
||||
if [ x"$line" = x ]; then
|
||||
continue
|
||||
fi
|
||||
# skip comment lines
|
||||
if echo "$line" | $GREP -q "^#" ; then
|
||||
continue;
|
||||
fi
|
||||
INPUT_MODULES="$INPUT_MODULES $line"
|
||||
done <"$MODFILE"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: print_epilog
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -215,46 +182,6 @@ process_modules() {
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: get_section
|
||||
#------------------------------------------------------------------------------
|
||||
# Code 'return 0' on success
|
||||
# Code 'return 1' on error
|
||||
# Sets global variable $section
|
||||
get_section() {
|
||||
local module_url
|
||||
local full_module_url
|
||||
|
||||
# Obtain the git url in order to find the section to which this module belongs
|
||||
full_module_url=`git config --get remote.$remote_name.url | sed 's:\.git$::'`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to obtain git url for remote \"$remote_name\"."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# The last part of the git url will tell us the section. Look for xorg first
|
||||
echo "$full_module_url"
|
||||
module_url=`echo "$full_module_url" | $GREP -o "libratbag/.*"`
|
||||
if [ $? -eq 0 ]; then
|
||||
module_url=`echo $module_url | cut -d'/' -f2,3`
|
||||
else
|
||||
echo "Error: unable to locate a valid project url from \"$full_module_url\"."
|
||||
echo "Cannot establish url as one of libratbag"
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find the section (subdirs) where the tarballs are to be uploaded
|
||||
# The module relative path can be app/xfs, xserver, or mesa/drm for example
|
||||
section=`echo $module_url | cut -d'/' -f1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to extract section from $module_url first field."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: process_module
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -299,26 +226,27 @@ process_module() {
|
||||
current_branch=`git branch | $GREP "\*" | sed -e "s/\* //"`
|
||||
remote_name=`git config --get branch.$current_branch.remote`
|
||||
remote_branch=`git config --get branch.$current_branch.merge | cut -d'/' -f3,4`
|
||||
remote_url_root="https://github.com/libratbag/libratbag/archive"
|
||||
echo "Info: working off the \"$current_branch\" branch tracking the remote \"$remote_name/$remote_branch\"."
|
||||
|
||||
# Obtain the section
|
||||
get_section
|
||||
if [ $? -ne 0 ]; then
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find out the tarname from meson.build
|
||||
pkg_name=$($GREP '^project(' meson.build | sed 's|project(\([^\s,]*\).*|\1|' | sed "s/'//g")
|
||||
pkg_version=$($GREP -m 1 '^ version : ' meson.build | sed 's| version : \([^\s,]*\).*|\1|' | sed "s/'//g")
|
||||
pkg_version=$($GREP -m 1 '^[ ]*version \?: ' meson.build | sed 's|[ ]*version \?: \([^\s,]*\).*|\1|' | sed "s/'//g")
|
||||
tar_name="$pkg_name-$pkg_version"
|
||||
targz=$tar_name.tar.gz
|
||||
tag_name=$(echo "v$pkg_version" | sed 's|.0$||')
|
||||
# libratbag tags with v0.3 but piper user just 0.3
|
||||
case `git describe` in
|
||||
v*)
|
||||
tag_name=$(echo "v$pkg_version" | sed 's|\.0$||')
|
||||
;;
|
||||
*)
|
||||
tag_name=$(echo "$pkg_version" | sed 's|\.0$||')
|
||||
;;
|
||||
esac
|
||||
remote_url_root="https://github.com/libratbag/$pkg_name/archive"
|
||||
|
||||
# Now get the tarballs from github directly to compute their checksum
|
||||
remote_targz_url=$remote_url_root/$tag_name/$targz
|
||||
echo "downloading the tarbal from $remote_targz_url"
|
||||
echo "downloading the tarball from $remote_targz_url"
|
||||
curl $remote_targz_url > $targz
|
||||
|
||||
# Obtain the top commit SHA which should be the version bump
|
||||
@@ -513,13 +441,6 @@ do
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ x"${MODFILE}" != x ]; then
|
||||
echo ""
|
||||
echo "Error: specifying both modules and --modfile is not permitted"
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
INPUT_MODULES="${INPUT_MODULES} $1"
|
||||
;;
|
||||
esac
|
||||
@@ -530,9 +451,6 @@ done
|
||||
# If no modules specified (blank cmd line) display help
|
||||
check_modules_specification
|
||||
|
||||
# Read the module file and normalize input in INPUT_MODULES
|
||||
read_modfile
|
||||
|
||||
# Loop through each module to release
|
||||
# Exit on error if --no-quit no specified
|
||||
process_modules
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -412,9 +444,12 @@ hidpp10drv_read_profile(struct ratbag_profile *profile)
|
||||
|
||||
profile->is_enabled = p.enabled;
|
||||
|
||||
if (profile->name)
|
||||
if (profile->name) {
|
||||
free(profile->name);
|
||||
profile->name = strdup_safe((char*)p.name);
|
||||
profile->name = NULL;
|
||||
}
|
||||
if (p.name && p.name[0] != '\0')
|
||||
profile->name = strdup_safe((char*)p.name);
|
||||
|
||||
rc = hidpp10_get_current_profile(hidpp10, &idx);
|
||||
if (rc == 0 && (unsigned int)idx == profile->index)
|
||||
@@ -555,8 +590,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)
|
||||
@@ -564,8 +601,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 */
|
||||
@@ -573,8 +612,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;
|
||||
}
|
||||
@@ -628,9 +669,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);
|
||||
@@ -711,14 +752,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);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
#define HIDPP_CAP_ONBOARD_PROFILES_8100 (1 << 6)
|
||||
#define HIDPP_CAP_LED_SW_CONTROL_1300 (1 << 7)
|
||||
#define HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060 (1 << 8)
|
||||
#define HIDPP_CAP_BATTERY_VOLTAGE_1001 (1 << 9)
|
||||
#define HIDPP_CAP_RGB_EFFECTS_8071 (1 << 10)
|
||||
|
||||
#define HIDPP_HIDDEN_FEATURE (1 << 6)
|
||||
|
||||
struct hidpp20drv_data {
|
||||
struct hidpp20_device *dev;
|
||||
@@ -65,6 +69,7 @@ struct hidpp20drv_data {
|
||||
unsigned num_controls;
|
||||
struct hidpp20_control_id *controls;
|
||||
struct hidpp20_profiles *profiles;
|
||||
struct hidpp20_led *leds;
|
||||
union hidpp20_generic_led_zone_info led_infos;
|
||||
|
||||
unsigned int report_rates[4];
|
||||
@@ -330,14 +335,24 @@ static void
|
||||
hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_data)
|
||||
{
|
||||
struct hidpp20_profile *profile;
|
||||
struct hidpp20_led *h_led;
|
||||
struct hidpp20_led h_led_val;
|
||||
struct hidpp20_led *h_led = &h_led_val;
|
||||
struct hidpp20_color_led_zone_info* led_info;
|
||||
struct hidpp20_color_led_info info;
|
||||
int rc;
|
||||
|
||||
led_info = &drv_data->led_infos.color_leds[led->index];
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
h_led = &profile->leds[led->index];
|
||||
led_info = &drv_data->led_infos.color_leds_8070[led->index];
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
h_led = &profile->leds[led->index];
|
||||
} else {
|
||||
rc = hidpp20_color_led_effects_get_zone_effect(drv_data->dev, led->index, h_led);
|
||||
if (rc) {
|
||||
log_debug(led->profile->device->ratbag,
|
||||
"Failed to read led settings\n");
|
||||
}
|
||||
}
|
||||
|
||||
switch (h_led->mode) {
|
||||
case HIDPP20_LED_ON:
|
||||
@@ -356,7 +371,7 @@ hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_dat
|
||||
|
||||
/* pre-filled, only override if unknown */
|
||||
if (led->type == RATBAG_LED_TYPE_UNKNOWN)
|
||||
led->type = hidpp20_8070_get_location_mapping(led_info->location);
|
||||
led->type = hidpp20_led_get_location_mapping(led_info->location);
|
||||
led->color.red = h_led->color.red;
|
||||
led->color.green = h_led->color.green;
|
||||
led->color.blue = h_led->color.blue;
|
||||
@@ -393,10 +408,85 @@ hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_dat
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||
break;
|
||||
default:
|
||||
log_bug_libratbag(led->profile->device->ratbag,
|
||||
"%s: Unknown effect id %d\n",
|
||||
led->profile->device->name,
|
||||
ei.effect_id);
|
||||
log_debug(led->profile->device->ratbag,
|
||||
"%s: Unsupported effect (%d)\n",
|
||||
led->profile->device->name,
|
||||
ei.effect_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_led_8071(struct ratbag_led *led, struct hidpp20drv_data* drv_data)
|
||||
{
|
||||
struct hidpp20_profile *profile;
|
||||
struct hidpp20_led *h_led;
|
||||
struct hidpp20_rgb_device_info device_info;
|
||||
struct hidpp20_rgb_cluster_info cluster_info;
|
||||
int rc;
|
||||
|
||||
hidpp20_rgb_effects_get_device_info(drv_data->dev, &device_info);
|
||||
cluster_info = drv_data->led_infos.color_leds_8071[led->index];
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
h_led = &profile->leds[led->index];
|
||||
|
||||
switch (h_led->mode) {
|
||||
case HIDPP20_LED_ON:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
break;
|
||||
case HIDPP20_LED_CYCLE:
|
||||
led->mode = RATBAG_LED_CYCLE;
|
||||
break;
|
||||
case HIDPP20_LED_BREATHING:
|
||||
led->mode = RATBAG_LED_BREATHING;
|
||||
break;
|
||||
default:
|
||||
led->mode = RATBAG_LED_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* pre-filled, only override if unknown */
|
||||
if (led->type == RATBAG_LED_TYPE_UNKNOWN)
|
||||
led->type = hidpp20_led_get_location_mapping(cluster_info.location);
|
||||
led->color.red = h_led->color.red;
|
||||
led->color.green = h_led->color.green;
|
||||
led->color.blue = h_led->color.blue;
|
||||
led->ms = h_led->period;
|
||||
led->brightness = h_led->brightness * 255 / 100;
|
||||
|
||||
if (device_info.ext_caps & HIDPP20_COLOR_LED_INFO_EXT_CAP_MONOCHROME_ONLY)
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
|
||||
else
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||
|
||||
for (int i = 0; i < cluster_info.num_effects; i++) {
|
||||
struct hidpp20_rgb_effect_info ei;
|
||||
rc = hidpp20_rgb_effects_get_effect_info(drv_data->dev,
|
||||
cluster_info.index,
|
||||
i, &ei);
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
switch (ei.effect_id) {
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_DISABLED:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_FIXED:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_CYCLING:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_WAVE:
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_BREATHING:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||
break;
|
||||
default:
|
||||
log_debug(led->profile->device->ratbag,
|
||||
"%s: Unsupported effect (%d)\n",
|
||||
led->profile->device->name,
|
||||
ei.effect_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -410,6 +500,8 @@ hidpp20drv_read_led(struct ratbag_led *led)
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
hidpp20drv_read_led_8070(led, drv_data);
|
||||
else if (drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071)
|
||||
hidpp20drv_read_led_8071(led, drv_data);
|
||||
else if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300)
|
||||
hidpp20drv_read_led_1300(led, drv_data);
|
||||
}
|
||||
@@ -483,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;
|
||||
}
|
||||
@@ -606,15 +698,17 @@ hidpp20drv_update_led_1300(struct ratbag_led *led, struct hidpp20drv_data *data)
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_led_8070(struct ratbag_led *led, struct ratbag_profile* profile,
|
||||
struct hidpp20drv_data *drv_data)
|
||||
hidpp20drv_update_led_8070_8071(struct ratbag_led *led, struct ratbag_profile* profile,
|
||||
struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
struct hidpp20_profile *h_profile;
|
||||
struct hidpp20_led *h_led;
|
||||
struct hidpp20_led h_led_val;
|
||||
struct hidpp20_led *h_led = &h_led_val;
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
|
||||
h_led = &(h_profile->leds[led->index]);
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
h_led = &(h_profile->leds[led->index]);
|
||||
}
|
||||
|
||||
if (!h_led)
|
||||
return -EINVAL;
|
||||
@@ -639,6 +733,13 @@ hidpp20drv_update_led_8070(struct ratbag_led *led, struct ratbag_profile* profil
|
||||
h_led->period = led->ms;
|
||||
h_led->brightness = led->brightness * 100 / 255;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)) {
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
hidpp20_color_led_effects_set_zone_effect(drv_data->dev,
|
||||
led->index,
|
||||
h_led_val);
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -649,8 +750,9 @@ hidpp20drv_update_led(struct ratbag_led *led)
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
return hidpp20drv_update_led_8070(led, profile, drv_data);
|
||||
if ((drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070) |
|
||||
(drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071))
|
||||
return hidpp20drv_update_led_8070_8071(led, profile, drv_data);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300)
|
||||
return hidpp20drv_update_led_1300(led, drv_data);
|
||||
@@ -740,9 +842,12 @@ hidpp20drv_read_report_rate_8060(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
struct ratbag_profile *profile;
|
||||
uint8_t bitflags_ms;
|
||||
int nrates = 0;
|
||||
int rc;
|
||||
uint8_t rate_ms;
|
||||
unsigned rate_hz;
|
||||
|
||||
rc = hidpp20_adjustable_report_rate_get_report_rate_list(drv_data->dev,
|
||||
&bitflags_ms);
|
||||
@@ -761,6 +866,37 @@ hidpp20drv_read_report_rate_8060(struct ratbag_device *device)
|
||||
|
||||
drv_data->num_report_rates = nrates;
|
||||
|
||||
if (!hidpp20_adjustable_report_rate_get_report_rate(drv_data->dev, &rate_ms)) {
|
||||
switch (rate_ms)
|
||||
{
|
||||
case 1:
|
||||
rate_hz = 1000;
|
||||
break;
|
||||
case 2:
|
||||
case 3: /* 3ms = 333.(3)Hz, we round to 500Hz */
|
||||
rate_hz = 500;
|
||||
break;
|
||||
case 4:
|
||||
case 5: /* 5ms = 200Hz, we round to 250Hz */
|
||||
rate_hz = 250;
|
||||
break;
|
||||
case 6: /* 6ms = 166.(6)Hz, we round to 125Hz */
|
||||
case 7: /* 7ms = 142Hz, we round to 125Hz */
|
||||
case 8:
|
||||
rate_hz = 125;
|
||||
break;
|
||||
default:
|
||||
rate_hz = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rate_hz) {
|
||||
log_debug(ratbag, "report rate is %u\n", rate_hz);
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
profile->hz = rate_hz;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug(ratbag, "device has %d report rates\n", nrates);
|
||||
|
||||
return 0;
|
||||
@@ -777,7 +913,8 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
|
||||
unsigned int default_rate = 500;
|
||||
int rc;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_RESOLUTION_2200) {
|
||||
if ((drv_data->capabilities & HIDPP_CAP_RESOLUTION_2200) &&
|
||||
(drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201) == 0) {
|
||||
uint16_t resolution;
|
||||
uint8_t flags;
|
||||
|
||||
@@ -846,6 +983,9 @@ hidpp20drv_update_resolution_dpi_8100(struct ratbag_resolution *resolution,
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
h_profile->dpi[resolution->index] = dpi;
|
||||
|
||||
if (resolution->is_default)
|
||||
h_profile->default_dpi = resolution->index;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -857,7 +997,7 @@ hidpp20drv_update_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_sensor *sensor;
|
||||
int rc, i;
|
||||
int i;
|
||||
int dpi = dpi_x; /* dpi_x == dpi_y if we don't have the individual resolution cap */
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)
|
||||
@@ -873,14 +1013,13 @@ hidpp20drv_update_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
sensor = &drv_data->sensors[0];
|
||||
|
||||
/* validate that the sensor accepts the given DPI */
|
||||
rc = -EINVAL;
|
||||
if (dpi < sensor->dpi_min || dpi > sensor->dpi_max)
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
if (sensor->dpi_steps) {
|
||||
for (i = sensor->dpi_min; i < dpi; i += sensor->dpi_steps) {
|
||||
}
|
||||
if (i != dpi)
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
} else {
|
||||
i = 0;
|
||||
while (sensor->dpi_list[i]) {
|
||||
@@ -888,13 +1027,60 @@ hidpp20drv_update_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
break;
|
||||
}
|
||||
if (sensor->dpi_list[i] != dpi)
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = hidpp20_adjustable_dpi_set_sensor_dpi(drv_data->dev, sensor, dpi);
|
||||
return hidpp20_adjustable_dpi_set_sensor_dpi(drv_data->dev, sensor, dpi);
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
static int
|
||||
hidpp20drv_update_report_rate_8060(struct ratbag_profile *profile, int hz)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
int rc;
|
||||
|
||||
rc = hidpp20_adjustable_report_rate_set_report_rate(drv_data->dev, 1000/hz);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_report_rate_8100(struct ratbag_profile *profile, int hz)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *h_profile;
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
h_profile->report_rate = hz;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_report_rate(struct ratbag_profile *profile, int hz)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
int rc;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)
|
||||
return hidpp20drv_update_report_rate_8100(profile, hz);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060) {
|
||||
rc = hidpp20drv_update_report_rate_8060(profile, hz);
|
||||
|
||||
/* re-populate the profile with the correct value if we fail */
|
||||
if (rc)
|
||||
hidpp20drv_read_report_rate_8060(profile->device);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -940,19 +1126,15 @@ hidpp20drv_read_kbd_reprogrammable_key(struct ratbag_device *device)
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
hidpp20drv_read_color_leds_8070(struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
int rc;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
return 0;
|
||||
|
||||
free(drv_data->led_infos.color_leds);
|
||||
drv_data->led_infos.color_leds = NULL;
|
||||
free(drv_data->led_infos.color_leds_8070);
|
||||
drv_data->led_infos.color_leds_8070 = NULL;
|
||||
drv_data->num_leds = 0;
|
||||
|
||||
rc = hidpp20_color_led_effects_get_zone_infos(drv_data->dev, &drv_data->led_infos.color_leds);
|
||||
rc = hidpp20_color_led_effects_get_zone_infos(drv_data->dev, &drv_data->led_infos.color_leds_8070);
|
||||
|
||||
if (rc > 0) {
|
||||
drv_data->num_leds = rc;
|
||||
@@ -962,6 +1144,38 @@ hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_color_leds_8071(struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
free(drv_data->led_infos.color_leds_8071);
|
||||
drv_data->led_infos.color_leds_8071 = NULL;
|
||||
drv_data->num_leds = 0;
|
||||
|
||||
rc = hidpp20_rgb_effects_get_cluster_infos(drv_data->dev, &drv_data->led_infos.color_leds_8071);
|
||||
|
||||
if (rc > 0) {
|
||||
drv_data->num_leds = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
if(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
return hidpp20drv_read_color_leds_8070(drv_data);
|
||||
else if (drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071)
|
||||
return hidpp20drv_read_color_leds_8071(drv_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_leds(struct ratbag_device *device)
|
||||
{
|
||||
@@ -1037,6 +1251,60 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile)
|
||||
ratbag_profile_set_report_rate(profile, p->report_rate);
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_init_leds_8070_8071(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
|
||||
/* we only support 0x8071 via 0x8100 */
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) &&
|
||||
drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071) {
|
||||
log_debug(ratbag, "disabling 0x8071 (RGB Effects) feature because the device doesn't have 0x8100 (Onboard Memory Profiles)\n");
|
||||
drv_data->capabilities &= ~HIDPP_CAP_RGB_EFFECTS_8071;
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070 ||
|
||||
drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071) {
|
||||
/* we read the profile once to get the correct number of
|
||||
* supported leds. */
|
||||
if (hidpp20drv_read_color_leds(device))
|
||||
return 0;
|
||||
|
||||
device->num_leds = drv_data->num_leds;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_init_profile_8100(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
int rc;
|
||||
|
||||
log_debug(ratbag, "initializing onboard profiles\n");
|
||||
rc = hidpp20_onboard_profiles_allocate(drv_data->dev, &drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = hidpp20_onboard_profiles_initialize(drv_data->dev, drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
drv_data->num_profiles = drv_data->profiles->num_profiles;
|
||||
drv_data->num_buttons = drv_data->profiles->num_buttons;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201)
|
||||
drv_data->num_resolutions = drv_data->profiles->num_modes;
|
||||
/* We ignore the profile's num_leds and require
|
||||
* HIDPP_PAGE_COLOR_LED_EFFECTS to succeed instead
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
@@ -1078,6 +1346,10 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* check if it is a hidden feature */
|
||||
if (feature_type & HIDPP_HIDDEN_FEATURE)
|
||||
return 0;
|
||||
|
||||
switch (feature) {
|
||||
case HIDPP_PAGE_ROOT:
|
||||
case HIDPP_PAGE_FEATURE_SET:
|
||||
@@ -1121,6 +1393,22 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
drv_data->capabilities |= HIDPP_CAP_BATTERY_LEVEL_1000;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_BATTERY_VOLTAGE: {
|
||||
uint16_t voltage;
|
||||
enum hidpp20_battery_voltage_status status;
|
||||
|
||||
rc = hidpp20_batteryvoltage_get_battery_voltage(drv_data->dev, &voltage);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
status = rc;
|
||||
|
||||
log_debug(ratbag, "device battery voltage is %dmv, status %02x \n",
|
||||
voltage, status);
|
||||
|
||||
drv_data->capabilities |= HIDPP_CAP_BATTERY_VOLTAGE_1001;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_KBD_REPROGRAMMABLE_KEYS: {
|
||||
log_debug(ratbag, "device has programmable keys/buttons\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_KBD_REPROGRAMMABLE_KEYS_1b00;
|
||||
@@ -1144,15 +1432,18 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
||||
/* The 8070 feauture implemented in the G602 doesn't follow the spec,
|
||||
* so we ignore it */
|
||||
if (ratbag_device_data_hidpp20_get_quirk(device->data) == HIDPP20_QUIRK_G602)
|
||||
break;
|
||||
|
||||
log_debug(ratbag, "device has color effects\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_COLOR_LED_EFFECTS_8070;
|
||||
|
||||
/* we read the profile once to get the correct number of
|
||||
* supported leds. */
|
||||
if (hidpp20drv_read_color_leds(device))
|
||||
return 0;
|
||||
|
||||
device->num_leds = drv_data->num_leds;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_RGB_EFFECTS: {
|
||||
log_debug(ratbag, "device has color effects\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_RGB_EFFECTS_8071;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_LED_SW_CONTROL: {
|
||||
@@ -1170,22 +1461,6 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
case HIDPP_PAGE_ONBOARD_PROFILES: {
|
||||
log_debug(ratbag, "device has onboard profiles\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_ONBOARD_PROFILES_8100;
|
||||
|
||||
rc = hidpp20_onboard_profiles_allocate(drv_data->dev, &drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = hidpp20_onboard_profiles_initialize(drv_data->dev, drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
drv_data->num_profiles = drv_data->profiles->num_profiles;
|
||||
drv_data->num_resolutions = drv_data->profiles->num_modes;
|
||||
drv_data->num_buttons = drv_data->profiles->num_buttons;
|
||||
/* We ignore the profile's num_leds and require
|
||||
* HIDPP_PAGE_COLOR_LED_EFFECTS to succeed instead
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_MOUSE_BUTTON_SPY: {
|
||||
@@ -1207,21 +1482,27 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_resolution *resolution;
|
||||
int rc;
|
||||
unsigned int dpi_index = 0;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
continue;
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
if (resolution->is_active)
|
||||
dpi_index = resolution->index;
|
||||
if (profile->rate_dirty) {
|
||||
rc = hidpp20drv_update_report_rate(profile, profile->hz);
|
||||
if (rc) {
|
||||
log_error(device->ratbag, "hidpp20: failed to update report rate (%d)\n", rc);
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
rc = hidpp20drv_update_resolution_dpi(resolution,
|
||||
resolution->dpi_x,
|
||||
resolution->dpi_y);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
log_error(device->ratbag, "hidpp20: failed to update resolution (%d)\n", rc);
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
@@ -1229,8 +1510,10 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
continue;
|
||||
|
||||
rc = hidpp20drv_update_button(button);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
log_error(device->ratbag, "hidpp20: failed to update button (%d)\n", rc);
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(led, &profile->leds, link) {
|
||||
@@ -1238,10 +1521,11 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
continue;
|
||||
|
||||
rc = hidpp20drv_update_led(led);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
log_error(device->ratbag, "hidpp20: failed to update led (%d)\n", rc);
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
@@ -1250,13 +1534,19 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
|
||||
rc = hidpp20_onboard_profiles_commit(drv_data->dev,
|
||||
drv_data->profiles);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
log_error(device->ratbag, "hidpp20: failed to commit profile (%d)\n", rc);
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->is_active)
|
||||
hidpp20_onboard_profiles_set_current_dpi_index(drv_data->dev,
|
||||
dpi_index);
|
||||
if (profile->is_active) {
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
if (resolution->is_active)
|
||||
hidpp20_onboard_profiles_set_current_dpi_index(drv_data->dev,
|
||||
resolution->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,8 +1576,21 @@ hidpp20drv_20_probe(struct ratbag_device *device)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* initializations that depend on other features */
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070 ||
|
||||
drv_data->capabilities & HIDPP_CAP_RGB_EFFECTS_8071) {
|
||||
rc = hidpp20drv_init_leds_8070_8071(device);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
rc = hidpp20drv_init_profile_8100(device);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1318,9 +1621,10 @@ hidpp20drv_remove(struct ratbag_device *device)
|
||||
|
||||
if (drv_data->profiles)
|
||||
hidpp20_onboard_profiles_destroy(drv_data->profiles);
|
||||
free(drv_data->led_infos.color_leds);
|
||||
free(drv_data->led_infos.color_leds_8070);
|
||||
free(drv_data->controls);
|
||||
free(drv_data->sensors);
|
||||
free(drv_data->leds);
|
||||
if (drv_data->dev)
|
||||
hidpp20_device_destroy(drv_data->dev);
|
||||
free(drv_data);
|
||||
@@ -1331,6 +1635,12 @@ hidpp20drv_init_device(struct ratbag_device *device,
|
||||
struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
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,
|
||||
@@ -1340,6 +1650,18 @@ hidpp20drv_init_device(struct ratbag_device *device,
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
hidpp20drv_read_profile(profile);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
/* Fallback to the first profile if no profile is active */
|
||||
list_for_each(profile, &device->profiles, link)
|
||||
if (profile->is_active)
|
||||
active_profile = true;
|
||||
|
||||
if (!active_profile && device->num_profiles >= 1) {
|
||||
profile = ratbag_device_get_profile(device, 0);
|
||||
profile->is_active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1372,19 +1694,24 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
* If there is a special need like for G900, we can add this in the
|
||||
* device data file.
|
||||
*/
|
||||
dev = hidpp20_device_new(&base, device_idx);
|
||||
dev = hidpp20_device_new(&base, device_idx, (struct hidpp_hid_report*) device->hidraw[0].reports, device->hidraw[0].num_reports);
|
||||
if (!dev) {
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev->quirk = ratbag_device_data_hidpp20_get_quirk(device->data);
|
||||
|
||||
drv_data->dev = dev;
|
||||
|
||||
log_debug(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), dev->proto_major, dev->proto_minor);
|
||||
|
||||
if(dev->quirk != HIDPP20_QUIRK_NONE)
|
||||
log_debug(device->ratbag, "'%s' is quirked (%s)\n", ratbag_device_get_name(device), hidpp20_get_quirk_string(dev->quirk));
|
||||
|
||||
/* add some defaults that will be overwritten by the device */
|
||||
drv_data->num_profiles = 1;
|
||||
drv_data->num_resolutions = 1;
|
||||
drv_data->num_resolutions = 0;
|
||||
drv_data->num_buttons = 8;
|
||||
drv_data->num_leds = 0;
|
||||
|
||||
|
||||
845
src/driver-roccat-kone-pure.c
Normal file
845
src/driver-roccat-kone-pure.c
Normal file
@@ -0,0 +1,845 @@
|
||||
/*
|
||||
* Copyright © 2015 Red Hat, Inc.
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
|
||||
#define ROCCAT_PROFILE_MAX 4
|
||||
#define ROCCAT_BUTTON_MAX 17
|
||||
#define ROCCAT_NUM_DPI 5
|
||||
#define ROCCAT_LED_MAX 0
|
||||
|
||||
#define ROCCAT_MAX_RETRY_READY 10
|
||||
|
||||
#define ROCCAT_REPORT_ID_CONFIGURE_PROFILE 4
|
||||
#define ROCCAT_REPORT_ID_PROFILE 5
|
||||
#define ROCCAT_REPORT_ID_SETTINGS 6
|
||||
#define ROCCAT_REPORT_ID_KEY_MAPPING 7
|
||||
#define ROCCAT_REPORT_ID_MACRO 8
|
||||
|
||||
#define ROCCAT_REPORT_SIZE_PROFILE 59
|
||||
#define ROCCAT_REPORT_SIZE_SETTINGS 31
|
||||
#define ROCCAT_REPORT_SIZE_MACRO 2082
|
||||
|
||||
#define ROCCAT_CONFIG_SETTINGS 0x80
|
||||
#define ROCCAT_CONFIG_KEY_MAPPING 0x90
|
||||
|
||||
#define ROCCAT_MAX_MACRO_LENGTH 500
|
||||
|
||||
struct roccat_settings_report {
|
||||
uint8_t reportID;
|
||||
uint8_t twoB;
|
||||
uint8_t profileID;
|
||||
uint8_t x_y_linked;
|
||||
uint8_t x_sensitivity; /* 0x06 means 0 */
|
||||
uint8_t y_sensitivity; /* 0x06 means 0 */
|
||||
uint8_t dpi_mask;
|
||||
uint8_t xres[5];
|
||||
uint8_t current_dpi;
|
||||
uint8_t yres[5];
|
||||
uint8_t padding1;
|
||||
uint8_t report_rate;
|
||||
uint8_t padding2[11];
|
||||
// uint16_t checksum;
|
||||
// uint8_t padding2[4];
|
||||
// uint8_t light;
|
||||
// uint8_t light_heartbit;
|
||||
// uint8_t padding3[5];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct roccat_macro {
|
||||
uint8_t reportID;
|
||||
uint8_t twentytwo;
|
||||
uint8_t height;
|
||||
uint8_t profile;
|
||||
uint8_t button_index;
|
||||
uint8_t active;
|
||||
uint8_t padding[24];
|
||||
char group[24];
|
||||
char name[24];
|
||||
uint16_t length;
|
||||
struct {
|
||||
uint8_t keycode;
|
||||
uint8_t flag;
|
||||
uint16_t time;
|
||||
} keys[ROCCAT_MAX_MACRO_LENGTH];
|
||||
uint16_t checksum;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct roccat_data {
|
||||
uint8_t profiles[(ROCCAT_PROFILE_MAX + 1)][ROCCAT_REPORT_SIZE_PROFILE];
|
||||
struct roccat_settings_report settings[(ROCCAT_PROFILE_MAX + 1)];
|
||||
struct roccat_macro macros[(ROCCAT_PROFILE_MAX + 1)][(ROCCAT_BUTTON_MAX + 1)];
|
||||
};
|
||||
|
||||
struct roccat_button_type_mapping {
|
||||
uint8_t raw;
|
||||
enum ratbag_button_type type;
|
||||
};
|
||||
|
||||
static const struct roccat_button_type_mapping roccat_button_type_mapping[] = {
|
||||
{ 0, RATBAG_BUTTON_TYPE_LEFT },
|
||||
{ 1, RATBAG_BUTTON_TYPE_RIGHT },
|
||||
{ 2, RATBAG_BUTTON_TYPE_MIDDLE },
|
||||
{ 3, RATBAG_BUTTON_TYPE_EXTRA },
|
||||
{ 4, RATBAG_BUTTON_TYPE_SIDE },
|
||||
{ 5, RATBAG_BUTTON_TYPE_WHEEL_UP },
|
||||
{ 6, RATBAG_BUTTON_TYPE_WHEEL_DOWN },
|
||||
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_UP },
|
||||
{ 8, RATBAG_BUTTON_TYPE_RESOLUTION_DOWN },
|
||||
{ 9, RATBAG_BUTTON_TYPE_LEFT },
|
||||
{ 10, RATBAG_BUTTON_TYPE_RIGHT },
|
||||
{ 11, RATBAG_BUTTON_TYPE_MIDDLE },
|
||||
{ 12, RATBAG_BUTTON_TYPE_EXTRA },
|
||||
{ 13, RATBAG_BUTTON_TYPE_SIDE },
|
||||
{ 14, RATBAG_BUTTON_TYPE_WHEEL_UP },
|
||||
{ 15, RATBAG_BUTTON_TYPE_WHEEL_DOWN },
|
||||
{ 16, RATBAG_BUTTON_TYPE_RESOLUTION_UP },
|
||||
{ 17, RATBAG_BUTTON_TYPE_RESOLUTION_DOWN },
|
||||
};
|
||||
|
||||
static enum ratbag_button_type
|
||||
roccat_raw_to_button_type(uint8_t data)
|
||||
{
|
||||
const struct roccat_button_type_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(roccat_button_type_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return mapping->type;
|
||||
}
|
||||
|
||||
return RATBAG_BUTTON_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
struct roccat_button_mapping {
|
||||
uint8_t raw;
|
||||
struct ratbag_button_action action;
|
||||
};
|
||||
|
||||
static struct roccat_button_mapping roccat_button_mapping[] = {
|
||||
/* FIXME: { 0, Disabled }, */
|
||||
{ 1, BUTTON_ACTION_BUTTON(1) },
|
||||
{ 2, BUTTON_ACTION_BUTTON(2) },
|
||||
{ 3, BUTTON_ACTION_BUTTON(3) },
|
||||
{ 4, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK) },
|
||||
/* FIXME: { 5, Shortcut (modifier + key) }, */
|
||||
{ 6, BUTTON_ACTION_NONE },
|
||||
{ 7, BUTTON_ACTION_BUTTON(4) },
|
||||
{ 8, BUTTON_ACTION_BUTTON(5) },
|
||||
//{ 9, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT) },
|
||||
//{ 10, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT) },
|
||||
{ 13, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP) },
|
||||
{ 14, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN) },
|
||||
/* FIXME: { 15, quicklaunch }, -> hidraw report 03 00 60 07 01 00 00 00 */
|
||||
{ 16, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP) },
|
||||
{ 17, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP) },
|
||||
{ 18, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN) },
|
||||
{ 20, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP) },
|
||||
{ 21, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP) },
|
||||
{ 22, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN) },
|
||||
{ 26, BUTTON_ACTION_KEY(KEY_LEFTMETA) },
|
||||
/* FIXME: { 27, open driver }, -> hidraw report 02 83 01 00 00 00 00 00 */
|
||||
//{ 32, BUTTON_ACTION_KEY(KEY_CONFIG) },
|
||||
{ 33, BUTTON_ACTION_KEY(KEY_PREVIOUSSONG) },
|
||||
{ 34, BUTTON_ACTION_KEY(KEY_NEXTSONG) },
|
||||
{ 35, BUTTON_ACTION_KEY(KEY_PLAYPAUSE) },
|
||||
{ 36, BUTTON_ACTION_KEY(KEY_STOPCD) },
|
||||
{ 37, BUTTON_ACTION_KEY(KEY_MUTE) },
|
||||
{ 38, BUTTON_ACTION_KEY(KEY_VOLUMEUP) },
|
||||
{ 39, BUTTON_ACTION_KEY(KEY_VOLUMEDOWN) },
|
||||
{ 48, BUTTON_ACTION_MACRO },
|
||||
{ 65, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE) },
|
||||
/* FIXME: { 66, Easywheel sensitivity }, */
|
||||
/* FIXME: { 67, Easywheel profile }, */
|
||||
/* FIXME: { 68, Easywheel CPI }, */
|
||||
/* FIXME: { 81, Other Easyshift }, -> hidraw report 03 00 ff 05 01 00 00 00 */
|
||||
/* FIXME: { 82, Other Easyshift Lock }, -> hidraw report 03 00 ff 05 01 00 00 00 */
|
||||
/* FIXME: { 83, Both Easyshift }, -> hidraw report 03 00 ff 04 01 00 00 00 */
|
||||
};
|
||||
|
||||
static const struct ratbag_button_action*
|
||||
roccat_raw_to_button_action(uint8_t data)
|
||||
{
|
||||
struct roccat_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(roccat_button_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return &mapping->action;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
roccat_button_action_to_raw(const struct ratbag_button_action *action)
|
||||
{
|
||||
struct roccat_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(roccat_button_mapping, mapping) {
|
||||
if (ratbag_button_action_match(&mapping->action, action))
|
||||
return mapping->raw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
roccat_get_unaligned_u16(uint8_t *buf)
|
||||
{
|
||||
return (buf[1] << 8) | buf[0];
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
roccat_compute_crc(uint8_t *buf, unsigned int len)
|
||||
{
|
||||
unsigned i;
|
||||
uint16_t crc = 0;
|
||||
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < len - 2; i++) {
|
||||
crc += buf[i];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
roccat_crc_is_valid(struct ratbag_device *device, uint8_t *buf, unsigned int len)
|
||||
{
|
||||
uint16_t crc;
|
||||
uint16_t given_crc;
|
||||
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
crc = roccat_compute_crc(buf, len);
|
||||
|
||||
given_crc = roccat_get_unaligned_u16(&buf[len - 2]);
|
||||
|
||||
log_raw(device->ratbag,
|
||||
"checksum computed: 0x%04x, checksum given: 0x%04x\n",
|
||||
crc,
|
||||
given_crc);
|
||||
|
||||
return crc == given_crc;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_is_ready(struct ratbag_device *device)
|
||||
{
|
||||
uint8_t buf[3] = { 0 };
|
||||
int rc;
|
||||
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_CONFIGURE_PROFILE,
|
||||
buf, sizeof(buf));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
if (buf[1] == 0x03)
|
||||
msleep(100);
|
||||
|
||||
if (buf[1] == 0x02)
|
||||
return 2;
|
||||
|
||||
return buf[1] == 0x01;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_wait_ready(struct ratbag_device *device)
|
||||
{
|
||||
unsigned count = 0;
|
||||
int rc;
|
||||
|
||||
msleep(10);
|
||||
while (count < ROCCAT_MAX_RETRY_READY) {
|
||||
rc = roccat_is_ready(device);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc == 1)
|
||||
return 0;
|
||||
|
||||
if (rc == 2)
|
||||
return 2;
|
||||
|
||||
msleep(10);
|
||||
count++;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
int ret;
|
||||
|
||||
ret = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_PROFILE, buf,
|
||||
sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != 3)
|
||||
return -EIO;
|
||||
|
||||
return buf[2];
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {ROCCAT_REPORT_ID_PROFILE, 0x03, index};
|
||||
int ret;
|
||||
|
||||
if (index > ROCCAT_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_set_feature_report(device, buf[0], buf,
|
||||
sizeof(buf));
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
ret = roccat_wait_ready(device);
|
||||
if (ret)
|
||||
log_error(device->ratbag,
|
||||
"Error while waiting for the device to be ready: %s (%d)\n",
|
||||
strerror(-ret), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_set_config_profile(struct ratbag_device *device, uint8_t profile, uint8_t type)
|
||||
{
|
||||
uint8_t buf[] = {ROCCAT_REPORT_ID_CONFIGURE_PROFILE, profile, type};
|
||||
int ret;
|
||||
|
||||
if (profile > ROCCAT_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_set_feature_report(device, buf[0], buf,
|
||||
sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
ret = roccat_wait_ready(device);
|
||||
if (ret < 0)
|
||||
log_error(device->ratbag,
|
||||
"Error while waiting for the device to be ready: %s (%d)\n",
|
||||
strerror(-ret), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ratbag_button_action *
|
||||
roccat_button_to_action(struct ratbag_profile *profile,
|
||||
unsigned int button_index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data = ratbag_get_drv_data(device);
|
||||
uint8_t data;
|
||||
|
||||
data = drv_data->profiles[profile->index][3 + button_index * 3];
|
||||
return roccat_raw_to_button_action(data);
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
unsigned int index = profile->index;
|
||||
struct roccat_data *drv_data;
|
||||
int rc;
|
||||
uint8_t *buf;
|
||||
uint16_t *crc;
|
||||
|
||||
assert(index <= ROCCAT_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
buf = drv_data->profiles[index];
|
||||
crc = (uint16_t *)&buf[ROCCAT_REPORT_SIZE_PROFILE - 2];
|
||||
*crc = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
roccat_set_config_profile(device, index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_PROFILE)
|
||||
return -EIO;
|
||||
|
||||
log_raw(device->ratbag, "profile: %d written %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
|
||||
rc = roccat_wait_ready(device);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error while waiting for the device to be ready: %s (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
roccat_read_button(struct ratbag_button *button)
|
||||
{
|
||||
const struct ratbag_button_action *action;
|
||||
struct ratbag_device *device;
|
||||
struct roccat_macro *macro;
|
||||
struct roccat_data *drv_data;
|
||||
uint8_t *buf;
|
||||
unsigned j, time;
|
||||
int rc;
|
||||
|
||||
device = button->profile->device;
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
action = roccat_button_to_action(button->profile, button->index);
|
||||
if (action)
|
||||
ratbag_button_set_action(button, action);
|
||||
button->type = roccat_raw_to_button_type(button->index);
|
||||
// if (action == NULL)
|
||||
// log_error(device->ratbag, "button: %d -> %d %s:%d\n",
|
||||
// button->index, drv_data->profiles[button->profile->index][3 + button->index * 3],
|
||||
// __FILE__, __LINE__);
|
||||
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
|
||||
|
||||
if (action && action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) {
|
||||
struct ratbag_button_macro *m = NULL;
|
||||
|
||||
roccat_set_config_profile(device,
|
||||
button->profile->index,
|
||||
0);
|
||||
roccat_set_config_profile(device,
|
||||
button->profile->index,
|
||||
button->index);
|
||||
macro = &drv_data->macros[button->profile->index][button->index];
|
||||
buf = (uint8_t*)macro;
|
||||
buf[0] = ROCCAT_REPORT_ID_MACRO;
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
if (rc != ROCCAT_REPORT_SIZE_MACRO) {
|
||||
log_error(device->ratbag,
|
||||
"Unable to retrieve the macro for button %d of profile %d: %s (%d)\n",
|
||||
button->index, button->profile->index,
|
||||
rc < 0 ? strerror(-rc) : "not read enough", rc);
|
||||
} else {
|
||||
if (buf[0] != ROCCAT_REPORT_ID_MACRO) {
|
||||
log_error(device->ratbag,
|
||||
"Error while reading the macro of button %d of profile %d.\n",
|
||||
button->index,
|
||||
button->profile->index);
|
||||
goto out_macro;
|
||||
}
|
||||
if (!roccat_crc_is_valid(device, buf, ROCCAT_REPORT_SIZE_MACRO)) {
|
||||
log_error(device->ratbag,
|
||||
"wrong checksum while reading the macro of button %d of profile %d.\n",
|
||||
button->index,
|
||||
button->profile->index);
|
||||
goto out_macro;
|
||||
}
|
||||
|
||||
m = ratbag_button_macro_new(macro->name);
|
||||
log_raw(device->ratbag,
|
||||
"macro on button %d of profile %d is named '%s', and contains %d events:\n",
|
||||
button->index, button->profile->index,
|
||||
macro->name, macro->length);
|
||||
for (j = 0; j < macro->length; j++) {
|
||||
unsigned int keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device,
|
||||
macro->keys[j].keycode);
|
||||
ratbag_button_macro_set_event(m,
|
||||
j * 2,
|
||||
macro->keys[j].flag & 0x01 ? RATBAG_MACRO_EVENT_KEY_PRESSED : RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
keycode);
|
||||
if (macro->keys[j].time)
|
||||
time = macro->keys[j].time;
|
||||
else
|
||||
time = macro->keys[j].flag & 0x01 ? 10 : 50;
|
||||
ratbag_button_macro_set_event(m,
|
||||
j * 2 + 1,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
time);
|
||||
|
||||
log_raw(device->ratbag,
|
||||
" - %s %s\n",
|
||||
libevdev_event_code_get_name(EV_KEY, keycode),
|
||||
macro->keys[j].flag & 0x80 ? "released" : "pressed");
|
||||
}
|
||||
ratbag_button_copy_macro(button, m);
|
||||
}
|
||||
out_macro:
|
||||
msleep(10);
|
||||
ratbag_button_macro_unref(m);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_write_macro(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
{
|
||||
struct ratbag_device *device;
|
||||
struct roccat_macro *macro;
|
||||
struct roccat_data *drv_data;
|
||||
uint8_t *buf;
|
||||
unsigned i, count = 0;
|
||||
int rc;
|
||||
|
||||
if (action->type != RATBAG_BUTTON_ACTION_TYPE_MACRO)
|
||||
return 0;
|
||||
|
||||
device = button->profile->device;
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
macro = &drv_data->macros[button->profile->index][button->index];
|
||||
buf = (uint8_t*)macro;
|
||||
|
||||
memset(buf, 0, ROCCAT_REPORT_SIZE_MACRO);
|
||||
|
||||
for (i = 0; i < MAX_MACRO_EVENTS && count < ROCCAT_MAX_MACRO_LENGTH; i++) {
|
||||
if (action->macro->events[i].type == RATBAG_MACRO_EVENT_INVALID)
|
||||
return -EINVAL; /* should not happen, ever */
|
||||
|
||||
if (action->macro->events[i].type == RATBAG_MACRO_EVENT_NONE)
|
||||
break;
|
||||
|
||||
/* ignore the first wait */
|
||||
if (action->macro->events[i].type == RATBAG_MACRO_EVENT_WAIT &&
|
||||
!count)
|
||||
continue;
|
||||
|
||||
if (action->macro->events[i].type == RATBAG_MACRO_EVENT_KEY_PRESSED ||
|
||||
action->macro->events[i].type == RATBAG_MACRO_EVENT_KEY_RELEASED) {
|
||||
macro->keys[count].keycode = ratbag_hidraw_get_keyboard_usage_from_keycode(device, action->macro->events[i].event.key);
|
||||
}
|
||||
|
||||
switch (action->macro->events[i].type) {
|
||||
case RATBAG_MACRO_EVENT_KEY_PRESSED:
|
||||
macro->keys[count].flag = 0x01;
|
||||
break;
|
||||
case RATBAG_MACRO_EVENT_KEY_RELEASED:
|
||||
macro->keys[count].flag = 0x02;
|
||||
break;
|
||||
case RATBAG_MACRO_EVENT_WAIT:
|
||||
macro->keys[--count].time = action->macro->events[i].event.timeout;
|
||||
break;
|
||||
case RATBAG_MACRO_EVENT_INVALID:
|
||||
case RATBAG_MACRO_EVENT_NONE:
|
||||
/* should not happen */
|
||||
log_error(device->ratbag,
|
||||
"something went wrong while writing a macro.\n");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
macro->reportID = ROCCAT_REPORT_ID_MACRO;
|
||||
macro->twentytwo = 0x22;
|
||||
macro->height = 0x08;
|
||||
macro->profile = button->profile->index;
|
||||
macro->button_index = button->index;
|
||||
macro->active = 0x01;
|
||||
strcpy(macro->group, "g0");
|
||||
strncpy(macro->name, action->macro->name, 23);
|
||||
macro->length = count;
|
||||
macro->checksum = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc != ROCCAT_REPORT_SIZE_MACRO)
|
||||
return -EIO;
|
||||
|
||||
rc = roccat_wait_ready(device);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error while waiting for the device to be ready: %s (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_write_button(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
{
|
||||
struct ratbag_profile *profile = button->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data = ratbag_get_drv_data(device);
|
||||
uint8_t rc, *data;
|
||||
|
||||
data = &drv_data->profiles[profile->index][3 + button->index * 3];
|
||||
|
||||
rc = roccat_button_action_to_raw(action);
|
||||
if (!rc)
|
||||
return -EINVAL;
|
||||
|
||||
*data = rc;
|
||||
|
||||
rc = roccat_write_profile(button->profile);
|
||||
if (rc) {
|
||||
log_error(device->ratbag,
|
||||
"unable to write the profile to the device: '%s' (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = roccat_write_macro(button, action);
|
||||
if (rc) {
|
||||
log_error(device->ratbag,
|
||||
"unable to write the macro to the device: '%s' (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
int dpi_x, int dpi_y)
|
||||
{
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct roccat_settings_report *settings_report;
|
||||
uint8_t *buf;
|
||||
int rc;
|
||||
|
||||
if (dpi_x < 100 || dpi_x > 5000 || dpi_x % 50)
|
||||
return -EINVAL;
|
||||
if (dpi_y < 100 || dpi_y > 5000 || dpi_y % 50)
|
||||
return -EINVAL;
|
||||
|
||||
settings_report = &drv_data->settings[profile->index];
|
||||
|
||||
settings_report->xres[resolution->index] = dpi_x / 50;
|
||||
settings_report->yres[resolution->index] = dpi_y / 50;
|
||||
if (resolution->is_active)
|
||||
settings_report->current_dpi = resolution->index;
|
||||
|
||||
buf = (uint8_t*)settings_report;
|
||||
|
||||
// No checksum for settings report on Kone Pure.
|
||||
//settings_report->checksum = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc != ROCCAT_REPORT_SIZE_SETTINGS)
|
||||
return -EIO;
|
||||
|
||||
rc = roccat_wait_ready(device);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error while waiting for the device to be ready: %s (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
roccat_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct roccat_settings_report *setting_report;
|
||||
uint8_t *buf;
|
||||
unsigned int report_rate;
|
||||
int dpi_x, dpi_y;
|
||||
int rc;
|
||||
unsigned int report_rates[] = { 125, 250, 500, 1000 };
|
||||
|
||||
assert(profile->index <= ROCCAT_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
setting_report = &drv_data->settings[profile->index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
|
||||
/* first retrieve the report rate, it is set per profile */
|
||||
if (setting_report->report_rate < ARRAY_LENGTH(report_rates)) {
|
||||
report_rate = report_rates[setting_report->report_rate];
|
||||
} else {
|
||||
log_error(device->ratbag,
|
||||
"error while reading the report rate of the mouse (0x%02x)\n",
|
||||
buf[26]);
|
||||
report_rate = 0;
|
||||
}
|
||||
|
||||
ratbag_profile_set_report_rate_list(profile, report_rates,
|
||||
ARRAY_LENGTH(report_rates));
|
||||
ratbag_profile_set_report_rate(profile, report_rate);
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
dpi_x = setting_report->xres[resolution->index] * 50;
|
||||
dpi_y = setting_report->yres[resolution->index] * 50;
|
||||
if (!(setting_report->dpi_mask & (1 << resolution->index))) {
|
||||
/* the profile is disabled, overwrite it */
|
||||
dpi_x = 0;
|
||||
dpi_y = 0;
|
||||
}
|
||||
|
||||
ratbag_resolution_set_resolution(resolution, dpi_x, dpi_y);
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
resolution->is_active = (resolution->index == setting_report->current_dpi);
|
||||
|
||||
ratbag_resolution_set_dpi_list_from_range(resolution, 100, 5000);
|
||||
}
|
||||
|
||||
buf = drv_data->profiles[profile->index];
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_PROFILE)
|
||||
return;
|
||||
|
||||
// Buttons were read from the buffer that was yet un-initialized with the device data.
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
roccat_read_button(button);
|
||||
|
||||
if (!roccat_crc_is_valid(device, buf, ROCCAT_REPORT_SIZE_PROFILE))
|
||||
log_error(device->ratbag,
|
||||
"Error while reading profile %d, continuing...\n",
|
||||
profile->index);
|
||||
|
||||
log_raw(device->ratbag, "profile: %d %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_probe(struct ratbag_device *device)
|
||||
{
|
||||
int rc;
|
||||
struct ratbag_profile *profile;
|
||||
struct roccat_data *drv_data;
|
||||
int active_idx;
|
||||
|
||||
rc = ratbag_open_hidraw(device);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!ratbag_hidraw_has_report(device, ROCCAT_REPORT_ID_KEY_MAPPING)) {
|
||||
ratbag_close_hidraw(device);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
/* profiles are 0-indexed */
|
||||
ratbag_device_init_profiles(device,
|
||||
ROCCAT_PROFILE_MAX + 1,
|
||||
ROCCAT_NUM_DPI,
|
||||
ROCCAT_BUTTON_MAX + 1,
|
||||
ROCCAT_LED_MAX);
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
roccat_read_profile(profile);
|
||||
|
||||
active_idx = roccat_current_profile(device);
|
||||
if (active_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
"Can't talk to the mouse: '%s' (%d)\n",
|
||||
strerror(-active_idx),
|
||||
active_idx);
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->index == (unsigned int)active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_raw(device->ratbag,
|
||||
"'%s' is in profile %d\n",
|
||||
ratbag_device_get_name(device),
|
||||
profile->index);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(drv_data);
|
||||
ratbag_set_drv_data(device, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
roccat_remove(struct ratbag_device *device)
|
||||
{
|
||||
ratbag_close_hidraw(device);
|
||||
free(ratbag_get_drv_data(device));
|
||||
}
|
||||
|
||||
struct ratbag_driver roccat_driver = {
|
||||
.name = "Roccat Kone Pure",
|
||||
.id = "roccat",
|
||||
.probe = roccat_probe,
|
||||
.remove = roccat_remove,
|
||||
.write_profile = roccat_write_profile,
|
||||
.set_active_profile = roccat_set_current_profile,
|
||||
.write_button = roccat_write_button,
|
||||
.write_resolution_dpi = roccat_write_resolution_dpi,
|
||||
};
|
||||
@@ -267,9 +267,8 @@ roccat_is_ready(struct ratbag_device *device)
|
||||
uint8_t buf[3] = { 0 };
|
||||
int rc;
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_CONFIGURE_PROFILE,
|
||||
buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_CONFIGURE_PROFILE,
|
||||
buf, sizeof(buf));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc != sizeof(buf))
|
||||
@@ -315,8 +314,8 @@ roccat_current_profile(struct ratbag_device *device)
|
||||
uint8_t buf[3];
|
||||
int ret;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_PROFILE, buf,
|
||||
sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
ret = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_PROFILE, buf,
|
||||
sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -335,8 +334,8 @@ roccat_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
if (index > ROCCAT_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
ret = ratbag_hidraw_set_feature_report(device, buf[0], buf,
|
||||
sizeof(buf));
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -362,8 +361,8 @@ roccat_set_config_profile(struct ratbag_device *device, uint8_t profile, uint8_t
|
||||
if (profile > ROCCAT_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
ret = ratbag_hidraw_set_feature_report(device, buf[0], buf,
|
||||
sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -409,9 +408,8 @@ roccat_write_profile(struct ratbag_profile *profile)
|
||||
*crc = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
roccat_set_config_profile(device, index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_PROFILE)
|
||||
return -EIO;
|
||||
@@ -468,9 +466,8 @@ roccat_read_button(struct ratbag_button *button)
|
||||
macro = &drv_data->macros[button->profile->index][button->index];
|
||||
buf = (uint8_t*)macro;
|
||||
buf[0] = ROCCAT_REPORT_ID_MACRO;
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
if (rc != ROCCAT_REPORT_SIZE_MACRO) {
|
||||
log_error(device->ratbag,
|
||||
"Unable to retrieve the macro for button %d of profile %d: %s (%d)\n",
|
||||
@@ -594,9 +591,8 @@ roccat_write_macro(struct ratbag_button *button,
|
||||
macro->length = count;
|
||||
macro->checksum = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_MACRO,
|
||||
buf, ROCCAT_REPORT_SIZE_MACRO);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -673,9 +669,8 @@ roccat_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
|
||||
settings_report->checksum = roccat_compute_crc(buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
rc = ratbag_hidraw_set_feature_report(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
@@ -713,9 +708,8 @@ roccat_read_profile(struct ratbag_profile *profile)
|
||||
setting_report = &drv_data->settings[profile->index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
@@ -756,9 +750,8 @@ roccat_read_profile(struct ratbag_profile *profile)
|
||||
|
||||
buf = drv_data->profiles[profile->index];
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
rc = ratbag_hidraw_get_feature_report(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE);
|
||||
|
||||
msleep(10);
|
||||
|
||||
|
||||
@@ -271,8 +271,8 @@ steelseries_probe(struct ratbag_device *device)
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
int rc, button_count, led_count, device_version, mono_led, short_button;
|
||||
_cleanup_(dpi_list_freep) struct dpi_list *dpilist = NULL;
|
||||
_cleanup_(freep) struct dpi_range *dpirange = NULL;
|
||||
struct dpi_list *dpilist = NULL;
|
||||
struct dpi_range *dpirange = NULL;
|
||||
|
||||
unsigned int report_rates[] = { 125, 250, 500, 1000 };
|
||||
|
||||
@@ -366,10 +366,11 @@ steelseries_probe(struct ratbag_device *device)
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
steelseries_get_firmware_version(device);
|
||||
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
|
||||
drv_data->firmware_major,
|
||||
drv_data->firmware_minor);
|
||||
rc = steelseries_get_firmware_version(device);
|
||||
if(rc == 0)
|
||||
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
|
||||
drv_data->firmware_major,
|
||||
drv_data->firmware_minor);
|
||||
|
||||
steelseries_read_settings(device);
|
||||
|
||||
@@ -572,7 +573,7 @@ steelseries_write_buttons(struct ratbag_profile *profile)
|
||||
|
||||
msleep(10);
|
||||
if (device_version == 3)
|
||||
ret = ratbag_hidraw_raw_request(device, STEELSERIES_ID_BUTTONS,
|
||||
ret = ratbag_hidraw_raw_request(device, STEELSERIES_ID_BUTTONS,
|
||||
buf,sizeof(buf),HID_FEATURE_REPORT,HID_REQ_SET_REPORT);
|
||||
else
|
||||
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
|
||||
@@ -699,8 +700,8 @@ construct_cycle_buffer(struct steelseries_led_cycle *cycle,
|
||||
|
||||
/* this seems to be the minimum allowed */
|
||||
duration = max(buf[spec->point_count_idx] * 330, cycle->duration);
|
||||
|
||||
hidpp_set_unaligned_le_u16(&buf[spec->duration_idx], duration);
|
||||
|
||||
set_unaligned_le_u16(&buf[spec->duration_idx], duration);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -709,6 +710,7 @@ steelseries_write_led_cycle(struct ratbag_led *led,
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
int ret;
|
||||
|
||||
struct steelseries_led_cycle cycle;
|
||||
@@ -739,7 +741,7 @@ steelseries_write_led_cycle(struct ratbag_led *led,
|
||||
|
||||
list_append(&cycle.points, &point[0].link);
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
case RATBAG_LED_CYCLE:
|
||||
point[0].color = red;
|
||||
point[0].pos = 0x00;
|
||||
|
||||
@@ -768,7 +770,7 @@ steelseries_write_led_cycle(struct ratbag_led *led,
|
||||
|
||||
point[2].color = black;
|
||||
point[2].pos = 0x7F;
|
||||
|
||||
|
||||
list_append(&cycle.points, &point[0].link);
|
||||
list_append(&cycle.points, &point[1].link);
|
||||
list_append(&cycle.points, &point[2].link);
|
||||
@@ -782,8 +784,12 @@ steelseries_write_led_cycle(struct ratbag_led *led,
|
||||
construct_cycle_buffer(&cycle, cycle_spec, buf, sizeof(buf));
|
||||
|
||||
msleep(10);
|
||||
ret = ratbag_hidraw_raw_request(device, cycle_spec->cmd_val, buf,
|
||||
sizeof(buf), cycle_spec->hid_report_type, HID_REQ_SET_REPORT);
|
||||
if (device_version == 3)
|
||||
ret = ratbag_hidraw_raw_request(device, cycle_spec->cmd_val, buf,
|
||||
sizeof(buf), cycle_spec->hid_report_type, HID_REQ_SET_REPORT);
|
||||
else
|
||||
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -214,7 +214,10 @@ test_read_profile(struct ratbag_profile *profile)
|
||||
res->is_default = r->dflt;
|
||||
if (r->dflt)
|
||||
default_set = true;
|
||||
ratbag_resolution_set_cap(res, r->caps);
|
||||
|
||||
for (size_t j = 0; j < ARRAY_LENGTH(r->caps) && r->caps[j]; j++) {
|
||||
ratbag_resolution_set_cap(res, r->caps[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* special case triggered by the test suite when num_resolutions is 0 */
|
||||
|
||||
@@ -234,7 +234,7 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value)
|
||||
}
|
||||
|
||||
enum ratbag_led_type
|
||||
hidpp20_8070_get_location_mapping(uint16_t value)
|
||||
hidpp20_led_get_location_mapping(uint16_t value)
|
||||
{
|
||||
const struct hidpp20_8070_location_mapping *map;
|
||||
|
||||
@@ -247,7 +247,7 @@ hidpp20_8070_get_location_mapping(uint16_t value)
|
||||
}
|
||||
|
||||
const char *
|
||||
hidpp20_8070_get_location_mapping_name(uint16_t value)
|
||||
hidpp20_led_get_location_mapping_name(uint16_t value)
|
||||
{
|
||||
const struct hidpp20_8070_location_mapping *map;
|
||||
|
||||
@@ -306,6 +306,33 @@ hidpp_read_response(struct hidpp_device *dev, uint8_t *buf, size_t size)
|
||||
return rc >= 0 ? rc : -errno;
|
||||
}
|
||||
|
||||
void
|
||||
hidpp_get_supported_report_types(struct hidpp_device *dev, struct hidpp_hid_report *reports, unsigned int num_reports)
|
||||
{
|
||||
if (!reports) {
|
||||
hidpp_log_debug(dev, "hidpp: we don't have information about the hid reports, ignoring checks\n");
|
||||
dev->supported_report_types = 0xffff;
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset the bits we are gonna check */
|
||||
dev->supported_report_types &= (0xff & ~HIDPP_REPORT_SHORT);
|
||||
dev->supported_report_types &= (0xff & ~HIDPP_REPORT_LONG);
|
||||
|
||||
for (unsigned i = 0; i < num_reports; i++)
|
||||
if ((reports[i].usage_page & 0xff00) == 0xff00) /* vendor defined usage page (0xff00-0xffff) */
|
||||
switch (reports[i].report_id) {
|
||||
case REPORT_ID_SHORT:
|
||||
hidpp_log_debug(dev, "hidpp: device supports short reports\n");
|
||||
dev->supported_report_types |= HIDPP_REPORT_SHORT;
|
||||
break;
|
||||
case REPORT_ID_LONG:
|
||||
hidpp_log_debug(dev, "hidpp: device supports long reports\n");
|
||||
dev->supported_report_types |= HIDPP_REPORT_LONG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hidpp_log(struct hidpp_device *dev,
|
||||
enum hidpp_log_priority priority,
|
||||
@@ -322,6 +349,21 @@ hidpp_log(struct hidpp_device *dev,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char *
|
||||
hidpp_buffer_to_string(const uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t dstlen = len * 6;
|
||||
char *dst = zalloc(dstlen);
|
||||
unsigned int n = 0;
|
||||
char *sep = "";
|
||||
|
||||
for (unsigned i = 0; i < len; ++i) {
|
||||
n += snprintf_safe(&dst[n], dstlen - n, "%s%02x", sep, buf[i] & 0xFF);
|
||||
sep = " ";
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void
|
||||
hidpp_log_buffer(struct hidpp_device *dev,
|
||||
enum hidpp_log_priority priority,
|
||||
@@ -329,23 +371,10 @@ hidpp_log_buffer(struct hidpp_device *dev,
|
||||
uint8_t *buf, size_t len)
|
||||
{
|
||||
_cleanup_free_ char *output_buf = NULL;
|
||||
char *sep = "";
|
||||
unsigned int i, n;
|
||||
unsigned int buf_len;
|
||||
_cleanup_free_ char *bytes = NULL;
|
||||
|
||||
buf_len = header ? strlen(header) : 0;
|
||||
buf_len += len * 3;
|
||||
buf_len += 1; /* terminating '\0' */
|
||||
|
||||
output_buf = zalloc(buf_len);
|
||||
n = 0;
|
||||
if (header)
|
||||
n += snprintf_safe(output_buf, buf_len - n, "%s", header);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
n += snprintf_safe(&output_buf[n], buf_len - n, "%s%02x", sep, buf[i] & 0xFF);
|
||||
sep = " ";
|
||||
}
|
||||
bytes = hidpp_buffer_to_string(buf, len);
|
||||
asprintf(&output_buf, "%s %s", header ? header : "", bytes);
|
||||
|
||||
hidpp_log(dev, priority, "%s\n", output_buf);
|
||||
}
|
||||
@@ -361,6 +390,7 @@ hidpp_device_init(struct hidpp_device *dev, int fd)
|
||||
{
|
||||
dev->hidraw_fd = fd;
|
||||
hidpp_device_set_log_handler(dev, simple_log, HIDPP_LOG_PRIORITY_INFO, NULL);
|
||||
dev->supported_report_types = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libratbag-util.h"
|
||||
|
||||
#define HIDPP_RECEIVER_IDX 0xFF
|
||||
#define HIDPP_WIRED_DEVICE_IDX 0x00
|
||||
|
||||
@@ -93,13 +95,23 @@ typedef void (*hidpp_log_handler)(void *userdata,
|
||||
const char *format, va_list args)
|
||||
__attribute__ ((format (printf, 3, 0)));
|
||||
|
||||
struct hidpp_hid_report {
|
||||
unsigned int report_id;
|
||||
unsigned int usage_page;
|
||||
unsigned int usage;
|
||||
};
|
||||
|
||||
struct hidpp_device {
|
||||
int hidraw_fd;
|
||||
void *userdata;
|
||||
hidpp_log_handler log_handler;
|
||||
enum hidpp_log_priority log_priority;
|
||||
unsigned supported_report_types;
|
||||
};
|
||||
|
||||
#define HIDPP_REPORT_SHORT (1 << 0)
|
||||
#define HIDPP_REPORT_LONG (1 << 1)
|
||||
|
||||
void
|
||||
hidpp_device_init(struct hidpp_device *dev, int fd);
|
||||
void
|
||||
@@ -118,10 +130,10 @@ enum ratbag_button_type
|
||||
hidpp20_1b04_get_physical_mapping(uint16_t value);
|
||||
|
||||
enum ratbag_led_type
|
||||
hidpp20_8070_get_location_mapping(uint16_t value);
|
||||
hidpp20_led_get_location_mapping(uint16_t value);
|
||||
|
||||
const char *
|
||||
hidpp20_8070_get_location_mapping_name(uint16_t value);
|
||||
hidpp20_led_get_location_mapping_name(uint16_t value);
|
||||
|
||||
const char *
|
||||
hidpp20_1b04_get_logical_mapping_name(uint16_t value);
|
||||
@@ -138,6 +150,11 @@ hidpp_write_command(struct hidpp_device *dev, uint8_t *cmd, int size);
|
||||
int
|
||||
hidpp_read_response(struct hidpp_device *dev, uint8_t *buf, size_t size);
|
||||
|
||||
void
|
||||
hidpp_get_supported_report_types(struct hidpp_device *dev,
|
||||
struct hidpp_hid_report *reports,
|
||||
unsigned int num_reports);
|
||||
|
||||
void
|
||||
hidpp_log(struct hidpp_device *dev,
|
||||
enum hidpp_log_priority priority,
|
||||
@@ -145,6 +162,9 @@ hidpp_log(struct hidpp_device *dev,
|
||||
...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
|
||||
char *
|
||||
hidpp_buffer_to_string(const uint8_t *buf, size_t len);
|
||||
|
||||
void
|
||||
hidpp_log_buffer(struct hidpp_device *dev,
|
||||
enum hidpp_log_priority priority,
|
||||
@@ -163,62 +183,30 @@ hidpp_log_buffer(struct hidpp_device *dev,
|
||||
|
||||
uint16_t hidpp_crc_ccitt(uint8_t *data, unsigned int length);
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_get_unaligned_be_u16(uint8_t *buf)
|
||||
{
|
||||
return (buf[0] << 8) | buf[1];
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_be_u16_to_cpu(uint16_t data)
|
||||
{
|
||||
return hidpp_get_unaligned_be_u16((uint8_t *)&data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hidpp_set_unaligned_be_u16(uint8_t *buf, uint16_t value)
|
||||
{
|
||||
buf[0] = value >> 8;
|
||||
buf[1] = value & 0xFF;
|
||||
return get_unaligned_be_u16((uint8_t *)&data);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_cpu_to_be_u16(uint16_t data)
|
||||
{
|
||||
uint16_t result;
|
||||
hidpp_set_unaligned_be_u16((uint8_t *)&result, data);
|
||||
set_unaligned_be_u16((uint8_t *)&result, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_get_unaligned_le_u16(uint8_t *buf)
|
||||
{
|
||||
return (buf[1] << 8) | buf[0];
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_le_u16_to_cpu(uint16_t data)
|
||||
{
|
||||
return hidpp_get_unaligned_le_u16((uint8_t *)&data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hidpp_set_unaligned_le_u16(uint8_t *buf, uint16_t value)
|
||||
{
|
||||
buf[0] = value & 0xFF;
|
||||
buf[1] = value >> 8;
|
||||
return get_unaligned_le_u16((uint8_t *)&data);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
hidpp_cpu_to_le_u16(uint16_t data)
|
||||
{
|
||||
uint16_t result;
|
||||
hidpp_set_unaligned_le_u16((uint8_t *)&result, data);
|
||||
set_unaligned_le_u16((uint8_t *)&result, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
hidpp_get_unaligned_be_u32(uint8_t *buf)
|
||||
{
|
||||
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
}
|
||||
|
||||
23
src/hidpp.i
Normal file
23
src/hidpp.i
Normal file
@@ -0,0 +1,23 @@
|
||||
/* wrapping libratbag functions from hidpp*.h using SWIG. */
|
||||
|
||||
%module hidpp
|
||||
%{
|
||||
/* the resulting C file should be built as a python extension */
|
||||
#define SWIG_FILE_WITH_INIT
|
||||
/* Includes the header in the wrapper code */
|
||||
#include <shared.h>
|
||||
#include <hidpp-generic.h>
|
||||
#include <hidpp20.h>
|
||||
%}
|
||||
#define __attribute__(x)
|
||||
#define _Static_assert(a,b)
|
||||
|
||||
|
||||
/* Parse the header file to generate wrappers */
|
||||
%include "stdint.i"
|
||||
%include "cpointer.i"
|
||||
%pointer_functions(int, intp);
|
||||
%pointer_functions(uint8_t, uint8_tp);
|
||||
%pointer_functions(uint16_t, uint16_tp);
|
||||
%include "hidpp-generic.h"
|
||||
%include "hidpp20.h"
|
||||
169
src/hidpp10.c
169
src/hidpp10.c
@@ -161,7 +161,6 @@ hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
|
||||
{
|
||||
@@ -171,6 +170,7 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
|
||||
int ret;
|
||||
uint8_t hidpp_err = 0;
|
||||
int command_size;
|
||||
_cleanup_free_ char *rxdata = NULL, *txdata = NULL;
|
||||
|
||||
switch (msg->msg.report_id) {
|
||||
case REPORT_ID_SHORT:
|
||||
@@ -186,9 +186,19 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
|
||||
/* create the expected header */
|
||||
expected_header = *msg;
|
||||
|
||||
txdata = hidpp_buffer_to_string(&msg->data[4], command_size - 4);
|
||||
hidpp_log_raw(&dev->base, "hidpp10 tx: %02x | %02x | %02x | %02x | %s\n",
|
||||
msg->msg.report_id,
|
||||
msg->msg.device_idx,
|
||||
msg->msg.sub_id,
|
||||
msg->msg.address,
|
||||
txdata);
|
||||
|
||||
/* response message length doesn't depend on request length */
|
||||
#if 0
|
||||
hidpp_log_buf_raw(&dev->base, " expected_header: ?? ", &expected_header.data[1], 3);
|
||||
hidpp_log_buf_raw(&dev->base, " expected_error_dev: ", expected_error_dev.data, SHORT_MESSAGE_LENGTH);
|
||||
#endif
|
||||
|
||||
/* Send the message to the Device */
|
||||
ret = hidpp_write_command(&dev->base, msg->data, command_size);
|
||||
@@ -238,8 +248,15 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rxdata = hidpp_buffer_to_string(&read_buffer.data[4], ret - 4);
|
||||
hidpp_log_raw(&dev->base, "hidpp10 rx: %02x | %02x | %02x | %02x | %s\n",
|
||||
read_buffer.msg.report_id,
|
||||
read_buffer.msg.device_idx,
|
||||
read_buffer.msg.sub_id,
|
||||
read_buffer.msg.address,
|
||||
rxdata);
|
||||
|
||||
if (!hidpp_err) {
|
||||
hidpp_log_buf_raw(&dev->base, " received: ", read_buffer.data, ret);
|
||||
/* copy the answer for the caller */
|
||||
*msg = read_buffer;
|
||||
}
|
||||
@@ -277,7 +294,8 @@ hidpp10_get_hidpp_notifications(struct hidpp10_device *dev,
|
||||
union hidpp10_message notifications = CMD_HIDPP_NOTIFICATIONS(idx, GET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching HID++ notifications\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching HID++ notifications (%#02x)\n",
|
||||
__CMD_HIDPP_NOTIFICATIONS);
|
||||
|
||||
res = hidpp10_request_command(dev, ¬ifications);
|
||||
if (res)
|
||||
@@ -298,7 +316,8 @@ hidpp10_set_hidpp_notifications(struct hidpp10_device *dev,
|
||||
union hidpp10_message notifications = CMD_HIDPP_NOTIFICATIONS(idx, SET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting HID++ notifications\n");
|
||||
hidpp_log_raw(&dev->base, "Setting HID++ notifications (%#02x\n",
|
||||
__CMD_HIDPP_NOTIFICATIONS);
|
||||
|
||||
notifications.msg.parameters[0] = reporting_flags & 0xFF;
|
||||
notifications.msg.parameters[1] = (reporting_flags >> 8) & 0x1F;
|
||||
@@ -333,7 +352,8 @@ hidpp10_get_individual_features(struct hidpp10_device *dev,
|
||||
union hidpp10_message features = CMD_ENABLE_INDIVIDUAL_FEATURES(idx, GET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching individual features\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching individual features (%#02x)\n",
|
||||
__CMD_ENABLE_INDIVIDUAL_FEATURES);
|
||||
|
||||
res = hidpp10_request_command(dev, &features);
|
||||
if (res)
|
||||
@@ -356,7 +376,8 @@ hidpp10_set_individual_features(struct hidpp10_device *dev,
|
||||
union hidpp10_message mode = CMD_ENABLE_INDIVIDUAL_FEATURES(idx, SET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting individual features\n");
|
||||
hidpp_log_raw(&dev->base, "Setting individual features (%#02x)\n",
|
||||
__CMD_ENABLE_INDIVIDUAL_FEATURES);
|
||||
|
||||
mode.msg.device_idx = dev->index;
|
||||
|
||||
@@ -700,7 +721,7 @@ hidpp10_write_profile_directory(struct hidpp10_device *dev)
|
||||
}
|
||||
|
||||
crc = hidpp_crc_ccitt(bytes, HIDPP10_PAGE_SIZE - 2);
|
||||
hidpp_set_unaligned_be_u16(&bytes[HIDPP10_PAGE_SIZE - 2], crc);
|
||||
set_unaligned_be_u16(&bytes[HIDPP10_PAGE_SIZE - 2], crc);
|
||||
|
||||
res = hidpp10_send_hot_payload(dev,
|
||||
0x00, 0x0000, /* destination: RAM */
|
||||
@@ -782,7 +803,8 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile
|
||||
unsigned i;
|
||||
uint8_t type, page, offset;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching current profile\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching current profile (%#02x)\n",
|
||||
__CMD_PROFILE);
|
||||
|
||||
res = hidpp10_request_command(dev, &profile);
|
||||
if (res)
|
||||
@@ -811,6 +833,20 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile
|
||||
"unable to find the profile at (%d,%d) in the directory\n",
|
||||
page, offset);
|
||||
break;
|
||||
case PROFILE_TYPE_FACTORY:
|
||||
/* Factory profile is selected and profile switching is
|
||||
* disabled. Let's switch to the first profile because the
|
||||
* factory profile doesn't help anywone */
|
||||
res = hidpp10_set_current_profile(dev, 0);
|
||||
if (res == 0) {
|
||||
hidpp_log_info(&dev->base, "switched from factory profile to 0\n");
|
||||
*current_profile = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hidpp_log_error(&dev->base,
|
||||
"current profile is factory profile but switching to 0 failed.\n");
|
||||
break;
|
||||
default:
|
||||
hidpp_log_error(&dev->base,
|
||||
"Unexpected value: %02x\n",
|
||||
@@ -829,7 +865,8 @@ hidpp10_set_internal_current_profile(struct hidpp10_device *dev,
|
||||
union hidpp10_message profile = CMD_PROFILE(idx, SET_REGISTER_REQ);
|
||||
int8_t page, offset;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting current profile\n");
|
||||
hidpp_log_raw(&dev->base, "Setting current profile (%#02x)\n",
|
||||
__CMD_PROFILE);
|
||||
|
||||
profile.msg.parameters[0] = profile_type;
|
||||
|
||||
@@ -964,9 +1001,9 @@ hidpp10_fill_dpi_modes_16(struct hidpp10_device *dev,
|
||||
struct _hidpp10_dpi_mode_16 *dpi = &dpi_list[i];
|
||||
|
||||
be = (uint8_t*)&dpi->xres;
|
||||
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_be_u16(be));
|
||||
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, get_unaligned_be_u16(be));
|
||||
be = (uint8_t*)&dpi->yres;
|
||||
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_be_u16(be));
|
||||
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, get_unaligned_be_u16(be));
|
||||
|
||||
profile->dpi_modes[i].led[0] = dpi->led1 == 0x2;
|
||||
profile->dpi_modes[i].led[1] = dpi->led2 == 0x2;
|
||||
@@ -988,9 +1025,9 @@ hidpp10_write_dpi_modes_16(struct hidpp10_device *dev,
|
||||
struct _hidpp10_dpi_mode_16 *dpi = &dpi_list[i];
|
||||
|
||||
be = (uint8_t*)&dpi->xres;
|
||||
hidpp_set_unaligned_be_u16(be, hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].xres));
|
||||
set_unaligned_be_u16(be, hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].xres));
|
||||
be = (uint8_t*)&dpi->yres;
|
||||
hidpp_set_unaligned_be_u16(be, hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].yres));
|
||||
set_unaligned_be_u16(be, hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].yres));
|
||||
|
||||
dpi->led1 = profile->dpi_modes[i].led[0] ? 0x02 : 0x01;
|
||||
dpi->led2 = profile->dpi_modes[i].led[1] ? 0x02 : 0x01;
|
||||
@@ -1107,6 +1144,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--;
|
||||
@@ -1161,8 +1201,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, ¯o);
|
||||
if (rc < 0)
|
||||
if (rc) {
|
||||
hidpp_log_raw(&device->base, "hidpp10: failed to read macro\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
count = rc;
|
||||
|
||||
@@ -1532,57 +1574,62 @@ hidpp10_read_profile(struct hidpp10_device *dev, uint8_t number)
|
||||
}
|
||||
profile->initialized = 1;
|
||||
|
||||
hidpp_log_buf_raw(&dev->base,
|
||||
"+++++++++++++++++++ Profile data: +++++++++++++++++ \n",
|
||||
data->data, 78);
|
||||
hidpp_log_raw(&dev->base,
|
||||
"+++++++++++++++++++ Profile data: +++++++++++++++++ \n");
|
||||
for (size_t x = 0; x < 78; x += 8) {
|
||||
hidpp_log_buf_raw(&dev->base, NULL, &data->data[x], min(8, 78 - x));
|
||||
}
|
||||
hidpp_log_raw(&dev->base,
|
||||
"+++++++++++++++++++ Profile data end +++++++++++++++++ \n");
|
||||
|
||||
}
|
||||
|
||||
hidpp_log_raw(&dev->base, "Profile %d:\n", number);
|
||||
for (i = 0; i < 5; i++) {
|
||||
hidpp_log_raw(&dev->base,
|
||||
"DPI mode: %dx%d dpi\n",
|
||||
" DPI mode: %dx%d dpi\n",
|
||||
profile->dpi_modes[i].xres,
|
||||
profile->dpi_modes[i].yres);
|
||||
hidpp_log_raw(&dev->base,
|
||||
"LED status: 1:%s 2:%s 3:%s 4:%s\n",
|
||||
" LED status: 1:%s 2:%s 3:%s 4:%s\n",
|
||||
profile->dpi_modes[i].led[0] ? "on" : "off",
|
||||
profile->dpi_modes[i].led[1] ? "on" : "off",
|
||||
profile->dpi_modes[i].led[2] ? "on" : "off",
|
||||
profile->dpi_modes[i].led[3] ? "on" : "off");
|
||||
}
|
||||
hidpp_log_raw(&dev->base, "Angle correction: %d\n", profile->angle_correction);
|
||||
hidpp_log_raw(&dev->base, "Default DPI mode: %d\n", profile->default_dpi_mode);
|
||||
hidpp_log_raw(&dev->base, "Refresh rate: %d\n", profile->refresh_rate);
|
||||
hidpp_log_raw(&dev->base, " Angle correction: %d\n", profile->angle_correction);
|
||||
hidpp_log_raw(&dev->base, " Default DPI mode: %d\n", profile->default_dpi_mode);
|
||||
hidpp_log_raw(&dev->base, " Refresh rate: %d\n", profile->refresh_rate);
|
||||
for (i = 0; i < 13; i++) {
|
||||
union hidpp10_button *button = &profile->buttons[i];
|
||||
switch (button->any.type) {
|
||||
case PROFILE_BUTTON_TYPE_BUTTON:
|
||||
hidpp_log_raw(&dev->base,
|
||||
"Button %zd: button %d\n",
|
||||
" Button %zd: button %d\n",
|
||||
i,
|
||||
button->button.button);
|
||||
break;
|
||||
case PROFILE_BUTTON_TYPE_KEYS:
|
||||
hidpp_log_raw(&dev->base,
|
||||
"Button %zd: key %d modifier %x\n",
|
||||
" Button %zd: key %d modifier %x\n",
|
||||
i,
|
||||
button->keys.key,
|
||||
button->keys.modifier_flags);
|
||||
break;
|
||||
case PROFILE_BUTTON_TYPE_SPECIAL:
|
||||
hidpp_log_raw(&dev->base,
|
||||
"Button %zd: special %x\n",
|
||||
" Button %zd: special %x\n",
|
||||
i,
|
||||
button->special.special);
|
||||
break;
|
||||
case PROFILE_BUTTON_TYPE_CONSUMER_CONTROL:
|
||||
hidpp_log_raw(&dev->base,
|
||||
"Button %zd: consumer: %x\n",
|
||||
" Button %zd: consumer: %x\n",
|
||||
i,
|
||||
button->consumer_control.consumer_control);
|
||||
break;
|
||||
case PROFILE_BUTTON_TYPE_DISABLED:
|
||||
hidpp_log_raw(&dev->base, "Button %zd: disabled\n", i);
|
||||
hidpp_log_raw(&dev->base, " Button %zd: disabled\n", i);
|
||||
break;
|
||||
default:
|
||||
/* FIXME: this is the page number for the macro,
|
||||
@@ -1757,7 +1804,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, uint8_t number, struct hidpp10_p
|
||||
}
|
||||
|
||||
crc = hidpp_crc_ccitt(page_data, HIDPP10_PAGE_SIZE - 2);
|
||||
hidpp_set_unaligned_be_u16(&page_data[HIDPP10_PAGE_SIZE - 2], crc);
|
||||
set_unaligned_be_u16(&page_data[HIDPP10_PAGE_SIZE - 2], crc);
|
||||
|
||||
/*
|
||||
* writing the data in several steps to prevent shroedinger state
|
||||
@@ -1851,7 +1898,8 @@ hidpp10_get_led_status(struct hidpp10_device *dev,
|
||||
uint8_t *status = led_status.msg.parameters;
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching LED status\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching LED status (%#02x)\n",
|
||||
__CMD_LED_STATUS);
|
||||
|
||||
res = hidpp10_request_command(dev, &led_status);
|
||||
if (res)
|
||||
@@ -1877,7 +1925,8 @@ hidpp10_set_led_status(struct hidpp10_device *dev,
|
||||
int res;
|
||||
int i;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting LED status\n");
|
||||
hidpp_log_raw(&dev->base, "Setting LED status (%#02x)\n",
|
||||
__CMD_LED_STATUS);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
switch (led[i]) {
|
||||
@@ -1928,7 +1977,8 @@ hidpp10_get_led_intensity(struct hidpp10_device *dev,
|
||||
uint8_t *intensity = led_intensity.msg.parameters;
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching LED intensity\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching LED intensity (%#02x)\n",
|
||||
__CMD_LED_INTENSITY);
|
||||
|
||||
res = hidpp10_request_command(dev, &led_intensity);
|
||||
if (res)
|
||||
@@ -1953,7 +2003,8 @@ hidpp10_set_led_intensity(struct hidpp10_device *dev,
|
||||
uint8_t *intensity = led_intensity.msg.parameters;
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting LED intensity\n");
|
||||
hidpp_log_raw(&dev->base, "Setting LED intensity (%#02x)\n",
|
||||
__CMD_LED_INTENSITY);
|
||||
|
||||
intensity[0] = led_intensity_in_percent[0]/10 & 0xF;
|
||||
intensity[0] |= (led_intensity_in_percent[1]/10 & 0xF) << 4;
|
||||
@@ -1992,7 +2043,8 @@ hidpp10_get_led_color(struct hidpp10_device *dev,
|
||||
union hidpp10_message led_color = CMD_LED_COLOR(idx, GET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching LED color\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching LED color (%#02x)\n",
|
||||
__CMD_LED_COLOR);
|
||||
|
||||
res = hidpp10_request_command(dev, &led_color);
|
||||
if (res)
|
||||
@@ -2015,7 +2067,8 @@ hidpp10_set_led_color(struct hidpp10_device *dev,
|
||||
union hidpp10_message led_color = CMD_LED_COLOR(idx, SET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting LED color\n");
|
||||
hidpp_log_raw(&dev->base, "Setting LED color (%#02x)\n",
|
||||
__CMD_LED_COLOR);
|
||||
|
||||
led_color.msg.parameters[0] = red;
|
||||
led_color.msg.parameters[1] = green;
|
||||
@@ -2048,7 +2101,8 @@ hidpp10_get_optical_sensor_settings(struct hidpp10_device *dev,
|
||||
union hidpp10_message sensor = CMD_OPTICAL_SENSOR_SETTINGS(idx, GET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching optical sensor settings\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching optical sensor settings (%#02x)\n",
|
||||
__CMD_OPTICAL_SENSOR_SETTINGS);
|
||||
|
||||
res = hidpp10_request_command(dev, &sensor);
|
||||
if (res)
|
||||
@@ -2086,7 +2140,8 @@ hidpp10_get_current_resolution(struct hidpp10_device *dev,
|
||||
union hidpp10_message resolution_long = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, GET_LONG_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching current resolution\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching current resolution (%#02x)\n",
|
||||
__CMD_CURRENT_RESOLUTION);
|
||||
|
||||
switch (dev->profile_type) {
|
||||
case HIDPP10_PROFILE_G9:
|
||||
@@ -2094,15 +2149,15 @@ hidpp10_get_current_resolution(struct hidpp10_device *dev,
|
||||
if (res)
|
||||
return res;
|
||||
/* resolution is in 50dpi multiples */
|
||||
*xres = *yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[4]));
|
||||
*xres = *yres = hidpp10_get_dpi_value(dev, get_unaligned_le_u16(&resolution.data[4]));
|
||||
break;
|
||||
default:
|
||||
res = hidpp10_request_command(dev, &resolution_long);
|
||||
if (res)
|
||||
return res;
|
||||
/* resolution is in 50dpi multiples */
|
||||
*xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution_long.data[4]));
|
||||
*yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution_long.data[6]));
|
||||
*xres = hidpp10_get_dpi_value(dev, get_unaligned_le_u16(&resolution_long.data[4]));
|
||||
*yres = hidpp10_get_dpi_value(dev, get_unaligned_le_u16(&resolution_long.data[6]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2118,14 +2173,17 @@ hidpp10_set_current_resolution(struct hidpp10_device *dev,
|
||||
union hidpp10_message resolution_long = CMD_CURRENT_RESOLUTION(REPORT_ID_LONG, idx, SET_LONG_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting current resolution (%#02x)\n",
|
||||
__CMD_CURRENT_RESOLUTION);
|
||||
|
||||
switch (dev->profile_type) {
|
||||
case HIDPP10_PROFILE_G9:
|
||||
resolution.data[4] = hidpp10_get_dpi_mapping(dev, xres);
|
||||
res = hidpp10_request_command(dev, &resolution);
|
||||
break;
|
||||
default:
|
||||
hidpp_set_unaligned_le_u16(&resolution_long.data[4], hidpp10_get_dpi_mapping(dev, xres));
|
||||
hidpp_set_unaligned_le_u16(&resolution_long.data[6], hidpp10_get_dpi_mapping(dev, yres));
|
||||
set_unaligned_le_u16(&resolution_long.data[4], hidpp10_get_dpi_mapping(dev, xres));
|
||||
set_unaligned_le_u16(&resolution_long.data[6], hidpp10_get_dpi_mapping(dev, yres));
|
||||
|
||||
res = hidpp10_request_command(dev, &resolution_long);
|
||||
break;
|
||||
@@ -2157,7 +2215,8 @@ hidpp10_get_usb_refresh_rate(struct hidpp10_device *dev,
|
||||
union hidpp10_message refresh = CMD_USB_REFRESH_RATE(idx, GET_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_log_raw(&dev->base, "Fetching USB refresh rate\n");
|
||||
hidpp_log_raw(&dev->base, "Fetching USB refresh rate (%#02x)\n",
|
||||
__CMD_USB_REFRESH_RATE);
|
||||
|
||||
res = hidpp10_request_command(dev, &refresh);
|
||||
if (res)
|
||||
@@ -2178,7 +2237,8 @@ hidpp10_set_usb_refresh_rate(struct hidpp10_device *dev,
|
||||
unsigned idx = dev->index;
|
||||
union hidpp10_message refresh = CMD_USB_REFRESH_RATE(idx, GET_REGISTER_REQ);
|
||||
|
||||
hidpp_log_raw(&dev->base, "Setting USB refresh rate\n");
|
||||
hidpp_log_raw(&dev->base, "Setting USB refresh rate (%#02x)\n",
|
||||
__CMD_USB_REFRESH_RATE);
|
||||
|
||||
refresh.msg.parameters[0] = 1000/rate;
|
||||
|
||||
@@ -2483,7 +2543,7 @@ hidpp10_read_page(struct hidpp10_device *dev, uint8_t page,
|
||||
}
|
||||
|
||||
crc = hidpp_crc_ccitt(bytes, HIDPP10_PAGE_SIZE - 2);
|
||||
read_crc = hidpp_get_unaligned_be_u16(&bytes[HIDPP10_PAGE_SIZE - 2]);
|
||||
read_crc = get_unaligned_be_u16(&bytes[HIDPP10_PAGE_SIZE - 2]);
|
||||
|
||||
if (crc != read_crc)
|
||||
return -EILSEQ; /* return illegal sequence */
|
||||
@@ -2573,7 +2633,7 @@ hidpp10_get_pairing_information(struct hidpp10_device *dev,
|
||||
return -1;
|
||||
|
||||
*report_interval = pairing_information.msg.string[2];
|
||||
*wpid = hidpp_get_unaligned_be_u16(&pairing_information.msg.string[3]);
|
||||
*wpid = get_unaligned_be_u16(&pairing_information.msg.string[3]);
|
||||
*device_type = pairing_information.msg.string[7];
|
||||
|
||||
return 0;
|
||||
@@ -2613,7 +2673,7 @@ hidpp10_get_extended_pairing_information(struct hidpp10_device *dev,
|
||||
if (res)
|
||||
return -1;
|
||||
|
||||
*serial = hidpp_get_unaligned_be_u32(&info.msg.string[1]);
|
||||
*serial = get_unaligned_be_u32(&info.msg.string[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2665,7 +2725,7 @@ hidpp10_get_firmare_information(struct hidpp10_device *dev,
|
||||
res = hidpp10_request_command(dev, &build_information);
|
||||
if (res)
|
||||
return res;
|
||||
build = hidpp_get_unaligned_be_u16(&build_information.msg.string[1]);
|
||||
build = get_unaligned_be_u16(&build_information.msg.string[1]);
|
||||
|
||||
*major_out = maj;
|
||||
*minor_out = min;
|
||||
@@ -2696,16 +2756,17 @@ hidpp10_get_device_info(struct hidpp10_device *dev)
|
||||
|
||||
hidpp10_get_optical_sensor_settings(dev, &reflect);
|
||||
|
||||
hidpp10_get_current_profile(dev, ¤t_profile);
|
||||
return 0;
|
||||
return hidpp10_get_current_profile(dev, ¤t_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));
|
||||
@@ -2716,12 +2777,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
719
src/hidpp20.c
719
src/hidpp20.c
File diff suppressed because it is too large
Load Diff
233
src/hidpp20.h
233
src/hidpp20.h
@@ -51,6 +51,12 @@ struct hidpp20_feature {
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
enum hidpp20_quirk {
|
||||
HIDPP20_QUIRK_NONE,
|
||||
HIDPP20_QUIRK_G305,
|
||||
HIDPP20_QUIRK_G602,
|
||||
};
|
||||
|
||||
struct hidpp20_device {
|
||||
struct hidpp_device base;
|
||||
unsigned int index;
|
||||
@@ -58,18 +64,25 @@ struct hidpp20_device {
|
||||
unsigned proto_minor;
|
||||
unsigned feature_count;
|
||||
struct hidpp20_feature *feature_list;
|
||||
enum hidpp20_quirk quirk;
|
||||
unsigned int led_ext_caps;
|
||||
};
|
||||
|
||||
int hidpp20_request_command(struct hidpp20_device *dev, union hidpp20_message *msg);
|
||||
|
||||
#define CASE_RETURN_STRING(a) case a: return #a; break
|
||||
|
||||
const char *hidpp20_feature_get_name(uint16_t feature);
|
||||
|
||||
const char *hidpp20_get_quirk_string(enum hidpp20_quirk quirk);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* generic hidpp20 device operations */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct hidpp20_device *
|
||||
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx);
|
||||
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx,
|
||||
struct hidpp_hid_report *reports, unsigned int num_reports);
|
||||
|
||||
void
|
||||
hidpp20_device_destroy(struct hidpp20_device *device);
|
||||
@@ -138,6 +151,25 @@ int hidpp20_batterylevel_get_battery_level(struct hidpp20_device *device,
|
||||
uint16_t *level,
|
||||
uint16_t *next_level);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1001: Battery Voltage */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
#define HIDPP_PAGE_BATTERY_VOLTAGE 0x1001
|
||||
|
||||
enum hidpp20_battery_voltage_status {
|
||||
BATTERY_VOLTAGE_STATUS_DISCHARGING = 0,
|
||||
BATTERY_VOLTAGE_STATUS_WIRELESS_CHARGING = 0x10,
|
||||
BATTERY_VOLTAGE_STATUS_CHARGING = 0x80,
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the battery voltage
|
||||
*
|
||||
* @return the battery status or a negative errno on error
|
||||
*/
|
||||
int hidpp20_batteryvoltage_get_battery_voltage(struct hidpp20_device *device,
|
||||
uint16_t *voltage);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1300: LED software control */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -401,6 +433,12 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
int hidpp20_adjustable_report_rate_get_report_rate_list(struct hidpp20_device *device,
|
||||
uint8_t *bitflags_ms);
|
||||
|
||||
int hidpp20_adjustable_report_rate_get_report_rate(struct hidpp20_device *device,
|
||||
uint8_t *rate_ms);
|
||||
|
||||
int hidpp20_adjustable_report_rate_set_report_rate(struct hidpp20_device *device,
|
||||
uint8_t rate_ms);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8070v4 - Color LED effects */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -439,6 +477,43 @@ hidpp20_color_led_effect_get_zone_effect_info(struct hidpp20_device *device,
|
||||
uint8_t zone_effect_index,
|
||||
struct hidpp20_color_led_zone_effect_info *info);
|
||||
|
||||
struct hidpp20_rgb_device_info;
|
||||
|
||||
int
|
||||
hidpp20_rgb_effects_get_device_info(struct hidpp20_device *device,
|
||||
struct hidpp20_rgb_device_info *info);
|
||||
|
||||
struct hidpp20_rgb_cluster_info;
|
||||
|
||||
int
|
||||
hidpp20_rgb_effects_get_cluster_info(struct hidpp20_device *device,
|
||||
uint8_t cluster_index,
|
||||
struct hidpp20_rgb_cluster_info *info);
|
||||
|
||||
int
|
||||
hidpp20_rgb_effects_get_cluster_infos(struct hidpp20_device *device,
|
||||
struct hidpp20_rgb_cluster_info **infos_list);
|
||||
|
||||
struct hidpp20_rgb_effect_info;
|
||||
|
||||
int
|
||||
hidpp20_rgb_effects_get_effect_info(struct hidpp20_device *device,
|
||||
uint8_t cluster_index,
|
||||
uint8_t effect_index,
|
||||
struct hidpp20_rgb_effect_info *info);
|
||||
|
||||
struct hidpp20_led;
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_set_zone_effect(struct hidpp20_device *device,
|
||||
uint8_t zone_index,
|
||||
struct hidpp20_led led);
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_zone_effect(struct hidpp20_device *device,
|
||||
uint8_t zone_index,
|
||||
struct hidpp20_led *led);
|
||||
|
||||
enum hidpp20_color_led_location {
|
||||
HIDPP20_COLOR_LED_LOCATION_UNDEFINED = 0,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY,
|
||||
@@ -472,22 +547,72 @@ enum hidpp20_color_led_zone_effect {
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_BOOT_UP = 8,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_DEMO_MODE = 8,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_BREATHING = 10,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_RIPPLE = 11,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_CUSTOM = 12,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8071 - RGB Effects */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_RGB_EFFECTS 0x8071
|
||||
|
||||
#define HIDPP20_RGB_EFFECTS_INDEX_ALL 0xFF
|
||||
|
||||
/* type of info */
|
||||
#define HIDPP20_RGB_EFFECTS_TOI_GENERAL 0x00
|
||||
#define HIDPP20_RGB_EFFECTS_TOI_EFFECT 0x01
|
||||
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_STATE 0x00
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_DEFAULTS 0x01
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_UUID_0_10 0x02
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_UUID_11_16 0x03
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_0_10 0x04
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_11_21 0x05
|
||||
#define HIDPP20_RGB_EFFECTS_SLOT_INFO_EFCT_NAME_21_31 0x06
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8100 - Onboard Profiles */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_ONBOARD_PROFILES 0x8100
|
||||
|
||||
/* type */
|
||||
#define HIDPP20_BUTTON_HID_TYPE 0x80
|
||||
#define HIDPP20_BUTTON_SPECIAL 0x90
|
||||
|
||||
/* standard opcodes (0x80) */
|
||||
#define HIDPP20_BUTTON_HID_TYPE_NOOP 0x00
|
||||
#define HIDPP20_BUTTON_HID_TYPE_MOUSE 0x01
|
||||
#define HIDPP20_BUTTON_HID_TYPE_KEYBOARD 0x02
|
||||
#define HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL 0x03
|
||||
#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
|
||||
|
||||
@@ -521,6 +646,8 @@ union hidpp20_button_binding {
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_BUTTON_SPECIAL */
|
||||
uint8_t special;
|
||||
uint8_t reserved;
|
||||
uint8_t profile;
|
||||
} __attribute__((packed)) special;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_BUTTON_MACRO */
|
||||
@@ -559,11 +686,6 @@ struct hidpp20_color_led_zone_info {
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_zone_info) == 5, "Invalid size");
|
||||
|
||||
union hidpp20_generic_led_zone_info {
|
||||
struct hidpp20_led_sw_ctrl_led_info* leds;
|
||||
struct hidpp20_color_led_zone_info* color_leds;
|
||||
};
|
||||
|
||||
struct hidpp20_color_led_zone_effect_info {
|
||||
uint8_t zone_index;
|
||||
uint8_t zone_effect_index;
|
||||
@@ -573,6 +695,41 @@ struct hidpp20_color_led_zone_effect_info {
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_zone_effect_info) == 8, "Invalid size");
|
||||
|
||||
struct hidpp20_rgb_device_info {
|
||||
uint8_t cluster_index;
|
||||
uint8_t effect_index;
|
||||
uint8_t cluster_count;
|
||||
/* we don't care about NV capabilities for libratbag, they just
|
||||
* indicate sale demo effects */
|
||||
uint16_t nv_caps;
|
||||
uint16_t ext_caps;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_rgb_device_info) == 7, "Invalid size");
|
||||
|
||||
struct hidpp20_rgb_cluster_info {
|
||||
uint8_t index;
|
||||
uint8_t effect_index;
|
||||
uint16_t location;
|
||||
uint16_t num_effects;
|
||||
uint16_t persistency_caps;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_rgb_cluster_info) == 8, "Invalid size");
|
||||
|
||||
struct hidpp20_rgb_effect_info {
|
||||
uint8_t cluster_index;
|
||||
uint8_t effect_index;
|
||||
uint16_t effect_id;
|
||||
uint16_t capabilities;
|
||||
uint16_t effect_period;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_rgb_effect_info) == 8, "Invalid size");
|
||||
|
||||
union hidpp20_generic_led_zone_info {
|
||||
struct hidpp20_led_sw_ctrl_led_info* leds;
|
||||
struct hidpp20_color_led_zone_info* color_leds_8070;
|
||||
struct hidpp20_rgb_cluster_info* color_leds_8071;
|
||||
};
|
||||
|
||||
struct hidpp20_color {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
@@ -590,7 +747,11 @@ enum hidpp20_led_mode {
|
||||
HIDPP20_LED_OFF = 0x00,
|
||||
HIDPP20_LED_ON = 0x01,
|
||||
HIDPP20_LED_CYCLE = 0x03,
|
||||
HIDPP20_LED_COLOR_WAVE = 0x04,
|
||||
HIDPP20_LED_STARLIGHT = 0x05,
|
||||
HIDPP20_LED_BREATHING = 0x0a,
|
||||
HIDPP20_LED_RIPPLE = 0x0b,
|
||||
HIDPP20_LED_CUSTOM = 0x0c,
|
||||
};
|
||||
|
||||
enum hidpp20_led_waveform {
|
||||
@@ -615,35 +776,76 @@ struct hidpp20_internal_led {
|
||||
uint16_t period_or_speed; /* period in ms, speed is device dependent */
|
||||
uint8_t intensity; /* 1 - 100 percent, 0 means 100 */
|
||||
} __attribute__((packed)) cycle;
|
||||
struct hidpp20_led_starlight {
|
||||
struct hidpp20_color color_sky;
|
||||
struct hidpp20_color color_star;
|
||||
} __attribute__((packed)) starlight;
|
||||
struct hidpp20_led_breath {
|
||||
struct hidpp20_color color;
|
||||
uint16_t period_or_speed; /* period in ms, speed is device dependent */
|
||||
uint8_t waveform; /* enum hidpp20_led_waveform */
|
||||
uint8_t intensity; /* 1 - 100 percent, 0 means 100 */
|
||||
} __attribute__((packed)) breath;
|
||||
struct hidpp20_led_ripple {
|
||||
struct hidpp20_color color;
|
||||
uint8_t reserved;
|
||||
uint16_t period;
|
||||
} __attribute__((packed)) ripple;
|
||||
struct hidpp20_led_custom {
|
||||
uint8_t slot;
|
||||
uint16_t init_frame;
|
||||
uint16_t lenght;
|
||||
uint16_t frame_period;
|
||||
uint8_t intensity;
|
||||
} __attribute__((packed)) custom;
|
||||
uint8_t padding[10];
|
||||
} __attribute__((packed)) effect;
|
||||
};
|
||||
_Static_assert(sizeof(struct hidpp20_led_fixed) == 4, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_cycle) == 8, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_starlight) == 6, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_breath) == 7, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_internal_led) == 11, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_ripple) == 6, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_custom) == 8, "Invalid size");
|
||||
|
||||
typedef uint8_t percent_t;
|
||||
|
||||
struct hidpp20_led {
|
||||
enum hidpp20_led_mode mode;
|
||||
struct hidpp20_color color;
|
||||
struct hidpp20_color extra_color;
|
||||
uint16_t period;
|
||||
percent_t brightness;
|
||||
uint8_t original[sizeof(struct hidpp20_internal_led)];
|
||||
};
|
||||
|
||||
#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 {
|
||||
@@ -673,6 +875,8 @@ struct hidpp20_profile {
|
||||
uint16_t address;
|
||||
uint8_t enabled;
|
||||
char name[16 * 3];
|
||||
uint16_t powersave_timeout;
|
||||
uint16_t poweroff_timeout;
|
||||
unsigned report_rate;
|
||||
unsigned default_dpi;
|
||||
unsigned switched_dpi;
|
||||
@@ -681,6 +885,7 @@ struct hidpp20_profile {
|
||||
union hidpp20_button_binding buttons[32];
|
||||
union hidpp20_macro_data *macros[32];
|
||||
struct hidpp20_led leds[HIDPP20_LED_COUNT];
|
||||
struct hidpp20_led alt_leds[HIDPP20_LED_COUNT];
|
||||
};
|
||||
|
||||
struct hidpp20_onboard_profiles_info {
|
||||
@@ -808,6 +1013,14 @@ hidpp20_onboard_profiles_allocate_sector(struct hidpp20_profiles *profiles)
|
||||
return zalloc(profiles->sector_size);
|
||||
}
|
||||
|
||||
void
|
||||
hidpp20_onboard_profiles_read_led(struct hidpp20_led *led,
|
||||
struct hidpp20_internal_led internal_led);
|
||||
|
||||
void
|
||||
hidpp20_onboard_profiles_write_led(struct hidpp20_internal_led *internal_led,
|
||||
struct hidpp20_led *led);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8110 - Mouse Button Spy */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
16
src/liblur.c
16
src/liblur.c
@@ -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;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "libratbag.h"
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-data.h"
|
||||
#include "hidpp20.h"
|
||||
|
||||
#define GROUP_DEVICE "Device"
|
||||
|
||||
@@ -54,6 +55,8 @@ enum driver {
|
||||
|
||||
struct data_hidpp20 {
|
||||
int index;
|
||||
enum hidpp20_quirk quirk;
|
||||
int led_count;
|
||||
};
|
||||
|
||||
struct data_hidpp10 {
|
||||
@@ -152,14 +155,32 @@ init_data_hidpp20(struct ratbag *ratbag,
|
||||
const char *group = "Driver/hidpp20";
|
||||
GError *error = NULL;
|
||||
int num;
|
||||
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)
|
||||
data->hidpp20.index = num;
|
||||
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) {
|
||||
if (streq(str, "G305"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_G305;
|
||||
else if(streq(str, "G602"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_G602;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -334,6 +355,8 @@ parse_ledtypes(char **strv, enum ratbag_led_type *types, size_t ntypes)
|
||||
types[i] = RATBAG_LED_TYPE_SIDE;
|
||||
else if (streq(s, "wheel"))
|
||||
types[i] = RATBAG_LED_TYPE_WHEEL;
|
||||
else if (streq(s, "switches"))
|
||||
types[i] = RATBAG_LED_TYPE_SWITCHES;
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -465,18 +488,16 @@ ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
|
||||
struct dirent **files;
|
||||
int n, nfiles;
|
||||
const char *datadir;
|
||||
char devicedir[PATH_MAX] = {0};
|
||||
|
||||
datadir = getenv("LIBRATBAG_DATA_DIR");
|
||||
if (!datadir)
|
||||
datadir = LIBRATBAG_DATA_DIR;
|
||||
log_debug(ratbag, "Using data directory '%s'\n", datadir);
|
||||
|
||||
snprintf(devicedir, sizeof(devicedir), "%s/devices", datadir);
|
||||
|
||||
n = scandir(devicedir, &files, filter_device_files, alphasort);
|
||||
n = scandir(datadir, &files, filter_device_files, alphasort);
|
||||
if (n <= 0) {
|
||||
log_error(ratbag, "Unable to locate device files in %s: %s\n",
|
||||
devicedir, n == 0 ? "No files found" : strerror(errno));
|
||||
datadir, n == 0 ? "No files found" : strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -485,13 +506,16 @@ ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
|
||||
_cleanup_(freep) char *file = NULL;
|
||||
int rc;
|
||||
|
||||
rc = xasprintf(&file, "%s/%s", devicedir, files[n]->d_name);
|
||||
rc = xasprintf(&file, "%s/%s", datadir, files[n]->d_name);
|
||||
if (rc == -1)
|
||||
goto out;
|
||||
if (file_data_matches(ratbag, file, id, &data))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!data)
|
||||
log_debug(ratbag, "No data file found for %04x:%04x\n", id->vendor, id->product);
|
||||
|
||||
out:
|
||||
while(nfiles--)
|
||||
free(files[nfiles]);
|
||||
@@ -561,6 +585,22 @@ 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)
|
||||
{
|
||||
assert(data->drivertype == HIDPP20);
|
||||
|
||||
return data->hidpp20.quirk;
|
||||
}
|
||||
|
||||
/* SteelSeries */
|
||||
|
||||
int
|
||||
|
||||
@@ -80,6 +80,12 @@ 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);
|
||||
|
||||
/* SteelSeries */
|
||||
|
||||
/**
|
||||
|
||||
@@ -293,6 +293,7 @@ enum ratbag_led_type {
|
||||
RATBAG_LED_TYPE_BATTERY,
|
||||
RATBAG_LED_TYPE_DPI,
|
||||
RATBAG_LED_TYPE_WHEEL,
|
||||
RATBAG_LED_TYPE_SWITCHES,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1239,6 +1239,8 @@ ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
log_debug(device->ratbag, "Parsing HID report descriptor\n");
|
||||
|
||||
i = 0;
|
||||
usage_page = 0;
|
||||
usage = 0;
|
||||
@@ -1260,7 +1262,7 @@ ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device)
|
||||
switch (hid) {
|
||||
case HID_REPORT_ID:
|
||||
if (hidraw->reports) {
|
||||
log_debug(device->ratbag, "report ID %02x\n", content);
|
||||
log_debug(device->ratbag, "- HID report ID %02x\n", content);
|
||||
hidraw->reports[hidraw->num_reports].report_id = content;
|
||||
hidraw->reports[hidraw->num_reports].usage_page = usage_page;
|
||||
hidraw->reports[hidraw->num_reports].usage = usage;
|
||||
@@ -1328,6 +1330,10 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw
|
||||
goto err;
|
||||
}
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"hidraw info: bus %#04x vendor %#04x product %#04x\n",
|
||||
info.bustype, info.vendor, info.product);
|
||||
|
||||
/* check basic matching between the hidraw node and the ratbag device */
|
||||
if (info.bustype != device->ids.bustype ||
|
||||
(info.vendor & 0xFFFF )!= device->ids.vendor ||
|
||||
@@ -1582,6 +1588,23 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_hidraw_get_feature_report(struct ratbag_device *device, unsigned char reportnum,
|
||||
uint8_t *buf, size_t len)
|
||||
{
|
||||
return ratbag_hidraw_raw_request(device, reportnum, buf, len,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_hidraw_set_feature_report(struct ratbag_device *device, unsigned char reportnum,
|
||||
uint8_t *buf, size_t len)
|
||||
{
|
||||
return ratbag_hidraw_raw_request(device, reportnum, buf, len,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t len)
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ void ratbag_close_hidraw_index(struct ratbag_device *device, int idx);
|
||||
*
|
||||
* @param device the ratbag device
|
||||
* @param reportnum report ID
|
||||
* @param buf in/out data to transfer
|
||||
* @param buf[in/out] data to transfer
|
||||
* @param len length of buf
|
||||
* @param rtype HID report type
|
||||
* @param reqtype HID_REQ_GET_REPORT or HID_REQ_SET_REPORT
|
||||
@@ -114,6 +114,41 @@ int ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char report
|
||||
uint8_t *buf, size_t len, unsigned char rtype,
|
||||
int reqtype);
|
||||
|
||||
/**
|
||||
* Get feature report from device.
|
||||
*
|
||||
* This call sends a HID_REQ_GET_REPORT to the device for the given feature
|
||||
* and returns the data in the caller-allocated buffer buf of size len.
|
||||
*
|
||||
* @param device the ratbag device
|
||||
* @param reportnum report ID
|
||||
* @param buf[out] data returned from device
|
||||
* @param len length of buf
|
||||
*
|
||||
* @return count of data transfered, or a negative errno on error
|
||||
*
|
||||
* Convenience wrapper around ratbag_hidraw_raw_request()
|
||||
*/
|
||||
int ratbag_hidraw_get_feature_report(struct ratbag_device *device, unsigned char reportnum,
|
||||
uint8_t *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Set feature report on device.
|
||||
*
|
||||
* This call sends a HID_REQ_SET_REPORT to the device for the given feature
|
||||
* and the buffer buf of size len.
|
||||
*
|
||||
* @param device the ratbag device
|
||||
* @param reportnum report ID
|
||||
* @param buf[in] data returned from device
|
||||
* @param len length of buf
|
||||
*
|
||||
* @return count of data transfered, or a negative errno on error
|
||||
*
|
||||
* Convenience wrapper around ratbag_hidraw_raw_request()
|
||||
*/
|
||||
int ratbag_hidraw_set_feature_report(struct ratbag_device *device, unsigned char reportnum,
|
||||
uint8_t *buf, size_t len);
|
||||
/**
|
||||
* Send output report to device
|
||||
*
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
|
||||
#ifdef NDEBUG
|
||||
#error "libratbag relies on assert(). Do not define NDEBUG"
|
||||
#endif
|
||||
|
||||
#define RATBAG_LED_TYPE_UNKNOWN 0
|
||||
|
||||
void
|
||||
@@ -291,6 +295,7 @@ struct ratbag_profile {
|
||||
unsigned int hz; /**< report rate in Hz */
|
||||
unsigned int rates[8]; /**< report rates available */
|
||||
size_t nrates; /**< number of entries in rates */
|
||||
bool rate_dirty;
|
||||
|
||||
unsigned int num_resolutions;
|
||||
|
||||
@@ -567,7 +572,7 @@ ratbag_resolution_set_cap(struct ratbag_resolution *res,
|
||||
{
|
||||
assert(cap <= RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
|
||||
res->capabilities = (1 << cap);
|
||||
res->capabilities |= (1 << cap);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -581,14 +586,14 @@ ratbag_led_set_mode_capability(struct ratbag_led *led,
|
||||
}
|
||||
|
||||
/* list of all supported drivers */
|
||||
struct ratbag_driver etekcity_driver;
|
||||
struct ratbag_driver hidpp20_driver;
|
||||
struct ratbag_driver hidpp10_driver;
|
||||
struct ratbag_driver logitech_g300_driver;
|
||||
struct ratbag_driver logitech_g600_driver;
|
||||
struct ratbag_driver roccat_driver;
|
||||
struct ratbag_driver gskill_driver;
|
||||
struct ratbag_driver steelseries_driver;
|
||||
extern struct ratbag_driver etekcity_driver;
|
||||
extern struct ratbag_driver hidpp20_driver;
|
||||
extern struct ratbag_driver hidpp10_driver;
|
||||
extern struct ratbag_driver logitech_g300_driver;
|
||||
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;
|
||||
|
||||
struct ratbag_device*
|
||||
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-test.h"
|
||||
|
||||
struct ratbag_driver test_driver;
|
||||
extern struct ratbag_driver test_driver;
|
||||
|
||||
static inline void
|
||||
ratbag_register_test_drivers(struct ratbag *ratbag)
|
||||
|
||||
@@ -53,7 +53,7 @@ struct ratbag_test_resolution {
|
||||
int xres, yres;
|
||||
bool active;
|
||||
bool dflt;
|
||||
uint32_t caps;
|
||||
uint32_t caps[10];
|
||||
|
||||
int dpi_min, dpi_max;
|
||||
};
|
||||
@@ -73,7 +73,7 @@ struct ratbag_test_led {
|
||||
};
|
||||
|
||||
struct ratbag_test_profile {
|
||||
const char *name;
|
||||
char *name;
|
||||
struct ratbag_test_button buttons[RATBAG_TEST_MAX_BUTTONS];
|
||||
struct ratbag_test_resolution resolutions[RATBAG_TEST_MAX_RESOLUTIONS];
|
||||
struct ratbag_test_led leds[RATBAG_TEST_MAX_LEDS];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -328,3 +330,35 @@ err:
|
||||
dpi_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
get_unaligned_be_u16(uint8_t *buf)
|
||||
{
|
||||
return (buf[0] << 8) | buf[1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_unaligned_be_u16(uint8_t *buf, uint16_t value)
|
||||
{
|
||||
buf[0] = value >> 8;
|
||||
buf[1] = value & 0xFF;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
get_unaligned_le_u16(uint8_t *buf)
|
||||
{
|
||||
return (buf[1] << 8) | buf[0];
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_unaligned_le_u16(uint8_t *buf, uint16_t value)
|
||||
{
|
||||
buf[0] = value & 0xFF;
|
||||
buf[1] = value >> 8;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
get_unaligned_be_u32(uint8_t *buf)
|
||||
{
|
||||
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
}
|
||||
|
||||
@@ -71,17 +71,29 @@ ratbag_default_log_func(struct ratbag *ratbag,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
const char *prefix;
|
||||
FILE *out = stdout;
|
||||
|
||||
switch(priority) {
|
||||
case RATBAG_LOG_PRIORITY_RAW: prefix = "raw"; break;
|
||||
case RATBAG_LOG_PRIORITY_DEBUG: prefix = "debug"; break;
|
||||
case RATBAG_LOG_PRIORITY_INFO: prefix = "info"; break;
|
||||
case RATBAG_LOG_PRIORITY_ERROR: prefix = "error"; break;
|
||||
default: prefix="<invalid priority>"; break;
|
||||
case RATBAG_LOG_PRIORITY_RAW:
|
||||
prefix = "raw";
|
||||
break;
|
||||
case RATBAG_LOG_PRIORITY_DEBUG:
|
||||
prefix = "debug";
|
||||
break;
|
||||
case RATBAG_LOG_PRIORITY_INFO:
|
||||
prefix = "info";
|
||||
break;
|
||||
case RATBAG_LOG_PRIORITY_ERROR:
|
||||
prefix = "error";
|
||||
out = stderr;
|
||||
break;
|
||||
default:
|
||||
prefix="<invalid priority>";
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ratbag %s: ", prefix);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(out, "ratbag %s: ", prefix);
|
||||
vfprintf(out, format, args);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -256,7 +268,7 @@ ratbag_sanity_check_device(struct ratbag_device *device)
|
||||
}
|
||||
|
||||
nres = ratbag_profile_get_num_resolutions(profile);
|
||||
if (nres == 0 || nres > 16) {
|
||||
if (nres > 16) {
|
||||
log_bug_libratbag(ratbag,
|
||||
"%s: invalid number of resolutions (%d)\n",
|
||||
device->name,
|
||||
@@ -322,7 +334,7 @@ out:
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ratbag_test_driver(struct ratbag_device *device,
|
||||
ratbag_try_driver(struct ratbag_device *device,
|
||||
const struct input_id *dev_id,
|
||||
const char *driver_name,
|
||||
const struct ratbag_test_device *test_device)
|
||||
@@ -377,9 +389,9 @@ ratbag_driver_fallback_logitech(struct ratbag_device *device,
|
||||
if (dev_id->vendor != USB_VENDOR_ID_LOGITECH)
|
||||
return false;
|
||||
|
||||
rc = ratbag_test_driver(device, dev_id, "hidpp20", NULL);
|
||||
rc = ratbag_try_driver(device, dev_id, "hidpp20", NULL);
|
||||
if (!rc)
|
||||
rc = ratbag_test_driver(device, dev_id, "hidpp10", NULL);
|
||||
rc = ratbag_try_driver(device, dev_id, "hidpp10", NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -395,11 +407,13 @@ ratbag_assign_driver(struct ratbag_device *device,
|
||||
if (!test_device) {
|
||||
driver_name = ratbag_device_data_get_driver(device->data);
|
||||
} else {
|
||||
log_debug(device->ratbag, "This is a test device\n");
|
||||
driver_name = "test_driver";
|
||||
}
|
||||
|
||||
if (driver_name) {
|
||||
rc = ratbag_test_driver(device, dev_id, driver_name, test_device);
|
||||
log_debug(device->ratbag, "device assigned driver %s\n", driver_name);
|
||||
rc = ratbag_try_driver(device, dev_id, driver_name, test_device);
|
||||
} else {
|
||||
rc = ratbag_driver_fallback_logitech(device, dev_id);
|
||||
}
|
||||
@@ -456,6 +470,8 @@ ratbag_device_new_from_udev_device(struct ratbag *ratbag,
|
||||
if ((name = get_device_name(udev_device)) == 0)
|
||||
goto out_err;
|
||||
|
||||
log_debug(ratbag, "New device: %s\n", name);
|
||||
|
||||
device = ratbag_device_new(ratbag, udev_device, name, &id);
|
||||
if (!device || !device->data)
|
||||
goto out_err;
|
||||
@@ -624,7 +640,7 @@ ratbag_create_button(struct ratbag_profile *profile, unsigned int index)
|
||||
button->index = index;
|
||||
button->type = RATBAG_BUTTON_TYPE_UNKNOWN;
|
||||
|
||||
list_insert(&profile->buttons, &button->link);
|
||||
list_append(&profile->buttons, &button->link);
|
||||
|
||||
return button;
|
||||
}
|
||||
@@ -644,7 +660,7 @@ ratbag_create_led(struct ratbag_profile *profile, unsigned int index)
|
||||
if (device->data)
|
||||
led->type = ratbag_device_data_get_led_type(device->data, led->index);
|
||||
|
||||
list_insert(&profile->leds, &led->link);
|
||||
list_append(&profile->leds, &led->link);
|
||||
|
||||
return led;
|
||||
}
|
||||
@@ -669,7 +685,7 @@ ratbag_create_resolution(struct ratbag_profile *profile, int index)
|
||||
res->profile = profile;
|
||||
res->index = index;
|
||||
|
||||
list_insert(&profile->resolutions, &res->link);
|
||||
list_append(&profile->resolutions, &res->link);
|
||||
|
||||
profile->num_resolutions++;
|
||||
}
|
||||
@@ -693,7 +709,7 @@ ratbag_create_profile(struct ratbag_device *device,
|
||||
profile->is_enabled = true;
|
||||
profile->name = NULL;
|
||||
|
||||
list_insert(&device->profiles, &profile->link);
|
||||
list_append(&device->profiles, &profile->link);
|
||||
list_init(&profile->buttons);
|
||||
list_init(&profile->leds);
|
||||
list_init(&profile->resolutions);
|
||||
@@ -933,6 +949,8 @@ ratbag_device_commit(struct ratbag_device *device)
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
profile->dirty = false;
|
||||
|
||||
profile->rate_dirty = false;
|
||||
|
||||
list_for_each(button, &profile->buttons, link)
|
||||
button->dirty = false;
|
||||
|
||||
@@ -1101,6 +1119,7 @@ ratbag_profile_set_report_rate(struct ratbag_profile *profile,
|
||||
if (profile->hz != hz) {
|
||||
profile->hz = hz;
|
||||
profile->dirty = true;
|
||||
profile->rate_dirty = true;
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
|
||||
@@ -52,6 +52,28 @@
|
||||
%typemap(freearg) (unsigned int *rates, size_t nrates) = (unsigned int *resolutions, size_t nres);
|
||||
/* END OF custom typemap for handling ratbag_resolution_get_report_rate_list */
|
||||
|
||||
/* uintXX_t mapping: Python -> C */
|
||||
%typemap(in) uint8_t {
|
||||
$1 = (uint8_t) PyInt_AsLong($input);
|
||||
}
|
||||
%typemap(in) uint16_t {
|
||||
$1 = (uint16_t) PyInt_AsLong($input);
|
||||
}
|
||||
%typemap(in) uint32_t {
|
||||
$1 = (uint32_t) PyInt_AsLong($input);
|
||||
}
|
||||
|
||||
/* uintXX_t mapping: C -> Python */
|
||||
%typemap(out) uint8_t {
|
||||
$result = PyInt_FromLong((long) $1);
|
||||
}
|
||||
%typemap(out) uint16_t {
|
||||
$result = PyInt_FromLong((long) $1);
|
||||
}
|
||||
%typemap(out) uint32_t {
|
||||
$result = PyInt_FromLong((long) $1);
|
||||
}
|
||||
|
||||
/* Parse the header file to generate wrappers */
|
||||
%include "libratbag.h"
|
||||
%include "libratbag-enums.h"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <libratbag.h>
|
||||
|
||||
/* This is a build-test only */
|
||||
|
||||
using namespace std;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <libratbag.h>
|
||||
|
||||
/* This is a build-test only */
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user