14 Commits
v0.17 ... dm5

Author SHA1 Message Date
Thomas H.P. Andersen
e28a6a92d6 sinowealth: add definition for repeated clicks 2020-10-05 01:49:34 +02:00
Thomas H.P. Andersen
381de107be sinowealth: add .device option for led RGB vs RBG 2020-10-05 01:49:34 +02:00
Marian Beermann
f474776a4d sinowealth: working button remapping 2020-10-05 01:40:36 +02:00
Marian Beermann
fd99aa29a7 sinowealth: SINOWEALTH_BUTTON_TPYE_SWITCH_DPI 2020-10-05 01:40:36 +02:00
Marian Beermann
53bc81f6fe sinowealth: use macro action with keycode_from_macro() 2020-10-05 01:40:36 +02:00
Marian Beermann
ff215126b2 sinowealth: fix button_data being discarded 2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
78793296a2 WIP: sinowealth: button write support
Seems like it should work - but it does not...
2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
a6cb7f8301 sinowealth: revamp button reading 2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
9cb444bb07 sinowealth: use enum for sensor 2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
121a843071 WIP: sinowealth: read button mapping 2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
62a620c056 sinowealth: use commonly available breathing mode
The DM5 does not have the RGB_BREATHING1 mode, but
does have the RGB_BREATHING7 mode. This changes the
driver to map to the commonly available mode.
2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
9d30ec5437 sinowealth: read device-specific from .device file
This moves device-specific specifications to the
.device files. The number of LEDs and buttons varies
as well as sensor (dpi specs)
2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
e570e29a1e sinowealth: parse led color as RGB
This was parsed as RBG but this is not the layout used on the
DM5. The RBG-parsing seems intentional, so this might need to
flip on either device or firmware version.
2020-10-05 01:40:36 +02:00
Thomas H.P. Andersen
1f79d8e6e2 add device file for Dream Machines DM5 Blink 2020-10-05 01:40:36 +02:00
82 changed files with 1319 additions and 5874 deletions

269
.circleci/config.yml Normal file
View File

@@ -0,0 +1,269 @@
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:
LANG: C.UTF-8
build_default: &build_default
name: Build
command: |
rm -rf build
meson build ${MESON_PARAMS}
meson configure build
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
name: Build and test
environment:
NINJA_ARGS: test
build_with_docs: &build_with_docs
run:
<<: *build_default
name: Build with documentation
environment:
MESON_PARAMS: -Ddocumentation=true
install: &install
run:
name: Installing
command: ninja -C build install
check_install: &check_install
run:
name: Checking installation
command: |
PREFIX=/usr/local/
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
meson build_install --prefix=$PREFIX
ninja -C build_install install
ninja -C build_install uninstall
if [ -d $PREFIX ]
then
tree $PREFIX
exit 1
fi
export_logs: &export_logs
store_artifacts:
path: ~/libratbag/build/meson-logs
start_dbus: &start_dbus
run:
name: Start dbus daemon
command: |
mkdir /run/dbus
/usr/bin/dbus-daemon --system --fork
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
restore_cache:
keys:
- fedora-cache-v1
fedora_install: &fedora_install
run:
name: Install prerequisites
command: |
echo keepcache=1 >> /etc/dnf/dnf.conf
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
- *start_dbus
- *build_and_test
- *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
steps:
- run:
name: Install prerequisites
command: |
export DEBIAN_FRONTEND=noninteractive
apt-get update
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
steps:
- *fedora_fetch_cache
- *fedora_install
- run:
name: Install documentation build-deps
command: dnf install -y ${FEDORA_DEP_DOC}
- checkout
- *build_with_docs
- *export_logs
- store_artifacts:
path: ~/libratbag/build/doc/html
- persist_to_workspace:
root: build
paths:
- doc/html/*
environment:
*build_dependencies
docs_deploy: &docs_deploy
<<: *default_settings
steps:
- *fedora_fetch_cache
- run:
name: Install prerequisites
command: dnf install -y git tree
- checkout
- attach_workspace:
at: build
- run:
name: Setup the deploy SSH key
command: |
ssh-add -L | tail -n1 > ~/.ssh/deploy.pub
cat <<EOF > ~/.ssh/config
Host github.com
IdentityFile /root/.ssh/deploy.pub
IdentitiesOnly yes
EOF
- run:
name: Clone doc repository
command: |
cd ~
git clone ssh://git@github.com/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_PROJECT_REPONAME}.github.io
- run:
name: Copy the doc, commit and push
command: |
set +e
cd ~/${CIRCLE_PROJECT_REPONAME}.github.io
\cp -r ~/${CIRCLE_PROJECT_REPONAME}/build/doc/html/* .
if ! git diff-index --quiet HEAD --; then
git config --global user.email "libratbag@librabtag.github.io"
git config --global user.name "The libratbag crew"
git add .
git commit -m "update docs from ${CIRCLE_SHA1}"
git push
fi
version: 2
jobs:
fedora_32:
<<: *fedora_settings
docker:
- image: fedora:32
arch:
<<: *arch_settings
docker:
- image: archlinux
ubuntu_20_04:
<<: *ubuntu_settings
docker:
- image: ubuntu:20.04
doc_build:
<<: *doc_build
docker:
- image: fedora:32
doc_deploy:
<<: *docs_deploy
docker:
- image: fedora:32
workflows:
version: 2
compile_and_test:
jobs:
- ubuntu_20_04
- arch
- fedora_32
- doc_build
- doc_deploy:
requires:
- doc_build
filters:
branches:
only: master

View File

@@ -1,39 +0,0 @@
# A Github Action to build a repository with meson
name: "Setup and run meson"
description: "Setup and run meson"
inputs:
builddir:
description: "The build directory"
default: "builddir"
srcdir:
description: "The source directory"
default: "."
meson_args:
description: "Arguments passed to meson setup"
default: ""
meson_skip_test:
description: "Set to a nonempty string to skip meson test"
default: ""
meson_test_args:
description: "Arguments passed to meson test"
default: ""
meson_precmd:
description: "Set to 'sudo' to run with sudo"
default: ""
ninja_args:
description: "Arguments passed to ninja"
default: ""
ninja_precmd:
description: "Set to 'sudo' to run with sudo"
default: ""
runs:
using: "composite"
steps:
- run: |
${{inputs.meson_precmd}} meson setup ${{inputs.builddir}} ${{inputs.srcdir}} ${{inputs.meson_args}}
${{inputs.meson_precmd}} meson configure ${{inputs.builddir}}
${{inputs.ninja_precmd}} ninja -C ${{inputs.builddir}} ${{inputs.ninja_args}}
if [[ -z "${{inputs.meson_skip_test}}" ]]; then
${{inputs.meson_precmd}} meson test -C ${{inputs.builddir}} --print-errorlogs ${{inputs.meson_test_args}};
fi
shell: bash

View File

@@ -1,17 +0,0 @@
name: "Install packages"
description: "Install a set of packages from sources"
inputs:
apt:
description: "The package list to install with apt"
pip:
description: "The package list to install with pip"
pip_precmd:
description: "Set to the string 'sudo' to run through sudo"
default: ""
runs:
using: "composite"
steps:
- run: sudo ${{ github.action_path }}/install-apt.sh ${{ inputs.apt }}
shell: bash
- run: ${{inputs.pip_precmd}} ${{ github.action_path }}/install-pip.sh ${{ inputs.pip }}
shell: bash

View File

@@ -1,14 +0,0 @@
#!/bin/bash -x
# If called without arguments, just skip the rest
if [[ -z "$@" ]]; then
exit
fi
# Don't care about these bits
echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
echo 'path-exclude=/usr/share/locale/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
apt-get update
apt-get install -yq --no-install-suggests --no-install-recommends $@

View File

@@ -1,9 +0,0 @@
#!/bin/bash -x
# If called without arguments, just skip the rest
if [[ -z "$@" ]]; then
exit
fi
python -m pip install --upgrade pip
python -m pip install --upgrade "$@"

View File

@@ -1,50 +0,0 @@
name: linux
on: [ push, pull_request ]
env:
UBUNTU_DEP_BUILD: |
gcc g++ pkg-config systemd libevdev-dev libglib2.0-dev
libjson-glib-dev libsystemd-dev libudev-dev libunistring-dev
python3-dev python3-evdev swig python3-sphinx
UBUNTU_DEP_TEST: check python3-gi python3-lxml valgrind
PIP_PACKAGES: meson ninja libevdev pyudev pytest sphinx_rtd_theme
jobs:
build-and-dist:
runs-on: ubuntu-20.04
strategy:
matrix:
meson_args:
- ''
- '-Dbuildtype=plain'
- '-Dbuildtype=release'
- '-Ddocumentation=true'
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/pkginstall
with:
apt: $UBUNTU_DEP_BUILD $UBUNTU_DEP_TEST
pip: $PIP_PACKAGES
- name: meson test ${{matrix.meson_args}}
uses: ./.github/actions/meson
with:
meson_args: --prefix=$PWD/_instdir ${{matrix.meson_args}}
ninja_args: install
- name: check installation of data files
run: diff -u <(cd data/devices; ls *.device) <(cd _instdir/share/libratbag; ls *.device)
- name: ninja uninstall
uses: ./.github/actions/meson
with:
meson_args: --prefix=$PWD/_instdir
ninja_args: uninstall
- name: check if any files are left after uninstall
run: (test -d _instdir && tree _instdir && exit 1) || exit 0
# Capture all the meson logs, even if we failed
- uses: actions/upload-artifact@v3
if: ${{ always() }} # even if we fail
with:
name: meson test logs
path: |
builddir/meson-logs/testlog*.txt
builddir/meson-logs/meson-log.txt

View File

@@ -1,31 +0,0 @@
name: pages
on:
push:
branches:
- master
env:
UBUNTU_DEP_BUILD: gcc g++ pkg-config systemd libevdev-dev libglib2.0-dev libjson-glib-dev libsystemd-dev libudev-dev libunistring-dev python3-dev python3-evdev python3-pip swig python3-sphinx python3-sphinx-rtd-theme
PIP_PACKAGES: meson ninja
jobs:
deploy:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/pkginstall
with:
apt: $UBUNTU_DEP_BUILD
pip: $PIP_PACKAGES
- name: Build docs
uses: ./.github/actions/meson
with:
meson_args: -Ddocumentation=true -Dtests=false
meson_skip_test: yes
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./builddir/doc/html/
allow_empty_commit: true

View File

@@ -45,10 +45,6 @@ And to build or re-build after code-changes, run:
ninja -C builddir
sudo ninja -C builddir install
To remove/uninstal simply run:
sudo ninja -C builddir uninstall
Note: `builddir` is the build output directory and can be changed to any
other directory name. To set configure-time options, use e.g.
@@ -173,3 +169,5 @@ libratbag is licensed under the MIT license.
> Software is furnished to do so, subject to the following conditions: [...]
See the COPYING file for the full license information.
[![Build Status](https://circleci.com/gh/libratbag/libratbag.svg?style=shield&circle-token=d7c782e10d2d934b176da754f11b5105ea074f4a)](https://circleci.com/gh/libratbag/libratbag)

View File

@@ -1,11 +0,0 @@
[Device]
Name=ASUS ROG GX860 Buzzard Mouse
DeviceMatch=usb:0b05:1816
Driver=asus
[Driver/asus]
Profiles=3
Buttons=10
Leds=0
Dpis=2
DpiRange=100:8200@100

View File

@@ -1,13 +0,0 @@
[Device]
Name=ASUS ROG Chakram
DeviceMatch=usb:0b05:18e3;usb:0b05:18e5
Driver=asus
[Driver/asus]
Profiles=3
Buttons=5
Leds=3
Dpis=4
Wireless=1
DpiRange=100:16000@100
Quirks=DOUBLE_DPI;STRIX_PROFILE

View File

@@ -1,13 +0,0 @@
[Device]
Name=ASUS ROG Gladius II Origin PNK LTD
DeviceMatch=usb:0b05:18cd
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=3
Dpis=2
DpiRange=100:12000@100
ButtonMapping=0;1;2;7;8;5;3;4
Quirks=DOUBLE_DPI

View File

@@ -1,14 +0,0 @@
# "ASUS ROG Gladius II" without "DPI target button"
[Device]
Name=ASUS ROG Gladius II Origin
DeviceMatch=usb:0b05:1877
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=3
Dpis=2
DpiRange=100:12000@100
ButtonMapping=0;1;2;7;8;5;3;4
Quirks=DOUBLE_DPI

View File

@@ -1,12 +0,0 @@
[Device]
Name=ASUS ROG Gladius II
DeviceMatch=usb:0b05:1845
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=3
Dpis=2
DpiRange=100:12000@100
ButtonMapping=0;1;2;7;8;5;3;4

View File

@@ -1,13 +0,0 @@
[Device]
Name=ASUS ROG Keris Wireless
DeviceMatch=usb:0b05:195e;usb:0b05:1960
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=2
Dpis=4
Wireless=1
DpiRange=100:16000@100
Quirks=DOUBLE_DPI

View File

@@ -1,14 +0,0 @@
[Device]
Name=ASUS ROG Pugio
DeviceMatch=usb:0b05:1846
Driver=asus
[Driver/asus]
Profiles=3
Buttons=10
Leds=3
Dpis=2
DpiRange=100:7200@100
# Mappings the same as the Gladius II but with an extra 2 buttons
ButtonMapping=0;1;2;7;8;5;3;4;9;10

View File

@@ -1,13 +0,0 @@
[Device]
Name=ASUS ROG Strix Carry
DeviceMatch=usb:0b05:18b4
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=0
Dpis=2
Wireless=1
DpiRange=100:7200@100
Quirks=STRIX_PROFILE

View File

@@ -1,11 +0,0 @@
[Device]
Name=ASUS ROG Strix Impact
DeviceMatch=usb:0b05:1847
Driver=asus
[Driver/asus]
Profiles=0
Buttons=6
Leds=1
Dpis=2
DpiRange=100:5000@100

View File

@@ -1,12 +0,0 @@
[Device]
Name=ASUS ROG Strix Impact II Wireless
DeviceMatch=usb:0b05:1947;usb:0b05:1949
Driver=asus
[Driver/asus]
Profiles=3
Buttons=8
Leds=3
Dpis=4
Wireless=1
DpiRange=100:16000@100

View File

@@ -26,7 +26,6 @@
import argparse
import configparser
import pathlib
import re
@@ -169,7 +168,7 @@ def check_section_hidpp10(section):
def check_section_hidpp20(section):
permitted = ['Buttons', 'DeviceIndex', 'Leds', 'ReportRate', 'Quirk']
permitted = ['DeviceIndex', 'Leds', 'Quirk']
for key in section.keys():
assertIn(key, permitted)
@@ -221,8 +220,8 @@ def parse_data_file(path):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Device data-file checker")
parser.add_argument("directory")
parser.add_argument('file', nargs='+')
args = parser.parse_args()
for path in pathlib.Path(args.directory).glob("*.device"):
for path in args.file:
validate_data_file_name(path)
parse_data_file(path)

View File

@@ -52,29 +52,3 @@ Leds=1
# The HID++ 2.0 device index
# Should be unset unless required
# DeviceIndex=1
[Driver/asus]
# Number of profiles
Profiles=3
# Number of buttons
Buttons=8
# Number of LEDs
Leds=3
# Number of DPI presets
Dpis=2
# Set if device is wireless
# Wireless=1
# DPI range in format min:max@step
DpiRange=100:16000@100
# Button index mapping
# ButtonMapping=0;1;2;6;7;5;3;4
# Device quirks
# Quirk=DOUBLE_DPI;STRIX_PROFILE

View File

@@ -0,0 +1,10 @@
[Device]
Name=Dream Machines DM5 Blink
DeviceMatch=usb:258a:0027
Driver=sinowealth
[Driver/sinowealth]
Buttons=8
Leds=1
LedType=RGB
DpiRange=100:16000@100

View File

@@ -24,7 +24,6 @@
import argparse
import os
import pathlib
import sys
import configparser
@@ -41,11 +40,11 @@ def parse_data_file(path):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Device duplicate match checker')
parser.add_argument("directory")
parser.add_argument('file', nargs='+')
args = parser.parse_args()
device_matches = {}
duplicates = False
for path in pathlib.Path(args.directory).glob("*.device"):
for path in args.file:
matches = parse_data_file(path)
fname = os.path.basename(path)
for m in matches:

View File

@@ -3,9 +3,7 @@ Name=Glorious Model D
DeviceMatch=usb:258a:0033
Driver=sinowealth
[Driver/sinowealth/devices/GloriousModelD]
ButtonCount=6
DeviceName=Glorious Model D
FwVersion=V102
LedType=RBG
SensorType=PMW3360
[Driver/sinowealth]
Buttons=6
Leds=2
DpiRange=100:12000@100

View File

@@ -1,11 +1,10 @@
[Device]
Name=Glorious Model O/O-
Name=Glorious Model O
DeviceMatch=usb:258a:0036
Driver=sinowealth
[Driver/sinowealth/devices/GloriousModelO]
ButtonCount=6
DeviceName=Glorious Model O/O- (updated firmware)
FwVersion=V103
[Driver/sinowealth]
Buttons=6
Leds=2
LedType=RBG
SensorType=PMW3360
DpiRange=100:12000@100

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +0,0 @@
# Logitech MX Anywhere 3B
[Device]
Name=Logitech MX Anywhere 3B
DeviceMatch=bluetooth:046d:b02d

View File

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

View File

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

View File

@@ -1,4 +0,0 @@
[Device]
Name=Logitech G502 X Wireless
DeviceMatch=usb:046d:c098
Driver=hidpp20

View File

@@ -1,4 +0,0 @@
[Device]
Name=Logitech G502 X
DeviceMatch=usb:046d:c099
Driver=hidpp20

View File

@@ -1,8 +0,0 @@
[Device]
Name=Logitech G635
DeviceMatch=usb:046d:0a89
LedTypes=logo;side
Driver=hidpp20
[Driver/hidpp20]
Buttons=0

View File

@@ -1,7 +0,0 @@
[Device]
Name=Logitech G733 Gaming Headset
DeviceMatch=usb:046d:0ab5
Driver=hidpp20
[Driver/hidpp20]
Buttons=0

View File

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

View File

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

View File

@@ -24,14 +24,12 @@
import argparse
import os
import pathlib
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
# https://pwr-solaar.github.io/Solaar/devices.html
logitech_receivers = [
0xc50c, # USB_DEVICE_ID_S510_RECEIVER
0xc517, # USB_DEVICE_ID_S510_RECEIVER_2
@@ -45,9 +43,6 @@ logitech_receivers = [
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
0xc545, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2
0xc547, # USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_3
0xc548, # Bolt receiver
]
RECEIVERS = ['usb:046d:{}'.format(r) for r in logitech_receivers]
@@ -64,10 +59,10 @@ def parse_data_file(path):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Checks that no unifying receiver ID is in the device files')
parser.add_argument("directory")
parser.add_argument('file', nargs='+')
args = parser.parse_args()
receiver_found = False
for path in pathlib.Path(args.directory).glob("*.device"):
for path in args.file:
matches = parse_data_file(path)
fname = os.path.basename(path)
for m in matches:

View File

@@ -1,4 +0,0 @@
[Device]
Name=Roccat Kone EMP
DeviceMatch=usb:1e7d:2e24
Driver=roccat-kone-emp

View File

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

View File

@@ -1,38 +0,0 @@
[Device]
DeviceMatch=usb:258a:0027
Driver=sinowealth
Name=SinoWealth Generic Mouse (0027)
[Driver/sinowealth/devices/DreamMachinesDM5Blink]
ButtonCount=8
DeviceName=DreamMachines DM5 Blink
FwVersion=3106
LedType=RGB
SensorType=PMW3389
[Driver/sinowealth/devices/GWolvesHatiHTM]
ButtonCount=6
# Can be both `Ace` and `Classic` version.
DeviceName=G-Wolves Hati HT-M Wired
FwVersion=V161
LedType=None
# Can also be PMW3389
SensorType=PMW3360
[Driver/sinowealth/devices/GenesysXenon770]
# There are 5 main buttons.
# Side buttons are detachable.
# There can be either 3 or 9 buttons on the side.
# Going for the maximum count: 5 + 9 = 14.
ButtonCount=14
DeviceName=Genesys Xenon 770
FwVersion=3110
LedType=RGB
SensorType=PMW3327
[Driver/sinowealth/devices/GloriousModelOOld]
ButtonCount=6
DeviceName=Glorious Model O (old firmware)
FwVersion=V102
LedType=RBG
SensorType=PMW3360

View File

@@ -1,12 +0,0 @@
[Device]
DeviceMatch=usb:258a:0029
Driver=sinowealth
Name=SinoWealth Generic Mouse (0029)
# Configuration data size is 131 bytes.
[Driver/sinowealth/devices/MachenikeM620]
ButtonCount=6
DeviceName=Machenike M620
FwVersion=V127
LedType=RGB
SensorType=PMW3389

View File

@@ -1,20 +0,0 @@
[Device]
DeviceMatch=usb:258a:1007
Driver=sinowealth
Name=SinoWealth Generic Mouse (1007)
# This does NOT work. See libratbag/libratbag#1296.
# For future: ID of A3050 sensor is 0x2, and maximum DPI is 4000.
#[Driver/sinowealth/devices/AntEsportsGM500]
#ButtonCount=7
#DeviceName=Ant Esports GM500
#FwVersion=0910
#LedType=RBG
#SensorType=A3050
[Driver/sinowealth/devices/MarvoScorpionG961]
ButtonCount=6
DeviceName=Marvo Scorpion G961
FwVersion=9677
LedType=RGB
SensorType=PMW3327

View File

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

View File

@@ -1,13 +0,0 @@
[Device]
# 100; 100 (Dell China); 100 Dota 2 Edition (retail); 100 Dota 2 Edition (Lenovo); 105.
DeviceMatch=usb:1038:1702;usb:1038:170a;usb:1038:170b;usb:1038:170c;usb:1038:1814
Driver=steelseries
Name=SteelSeries Rival 100/105
[Driver/steelseries]
# Actually 6.
Buttons=0
DeviceVersion=1
DpiList=250;500;1000;1250;1500;1750;2000;4000
Leds=1
Quirk=Rival100

View File

@@ -1,6 +1,6 @@
[Device]
Name=SteelSeries Rival
DeviceMatch=usb:1038:1384;usb:1038:1392;usb:1038:1710;usb:1038:1712;usb:1038:171c;usb:1038:1394;usb:1038:171a;usb:1038:1716;usb:1038:1714;usb:1038:1718
DeviceMatch=usb:1038:1384
Driver=steelseries
[Driver/steelseries]

View File

@@ -10,4 +10,5 @@ Buttons=8
Leds=1
DpiRange=90:5670@90
MacroLength=1
Quirk=SenseiRAW
MonoLed=1
ShortButton=1

View File

@@ -1,8 +1,8 @@
project('libratbag', 'c',
version : '0.17',
version : '0.15',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.50.0')
meson_version : '>= 0.53.0')
# The DBus API version. Increase this every time the DBus API changes.
# No backwards/forwards guarantee, clients are expected to understand
@@ -121,18 +121,6 @@ lib_libhidpp = static_library('hidpp',
dependencies : deps_libhidpp)
dep_libhidpp = declare_dependency(link_with: lib_libhidpp)
### libasus.a ####
src_libasus = [
'src/asus.c',
]
deps_libasus = [ ]
lib_libasus = static_library('asus',
src_libasus,
dependencies : deps_libasus)
dep_libasus = declare_dependency(link_with: lib_libasus)
### liblur ####
#
# liblur is the library to handle logitech unifying receivers.
@@ -147,7 +135,6 @@ src_liblur = [
deps_liblur = [
dep_libutil,
dep_libhidpp,
dep_libasus,
]
lur_mapfile = 'src/liblur.sym'
@@ -179,21 +166,16 @@ pkgconfig.generate (
src_libratbag = [
'src/libratbag-enums.h',
'src/libratbag.h',
'src/driver-asus.c',
'src/driver-etekcity.c',
'src/driver-hidpp20.c',
'src/driver-hidpp10.c',
'src/driver-logitech-g300.c',
'src/driver-logitech-g600.c',
'src/driver-roccat.c',
'src/driver-roccat-kone-emp.c',
'src/driver-roccat-kone-pure.c',
'src/driver-gskill.c',
'src/driver-openinput.c',
'src/driver-steelseries.c',
'src/driver-steelseries.h',
'src/driver-sinowealth.c',
'src/driver-sinowealth.h',
'src/driver-sinowealth-nubwo.c',
'src/driver-test.c',
'src/libratbag.c',
@@ -215,7 +197,6 @@ deps_libratbag = [
dep_json_glib,
dep_libutil,
dep_libhidpp,
dep_libasus,
]
lib_libratbag = static_library('ratbag',
@@ -297,19 +278,93 @@ man_lur_command = configure_file (
)
#### data files ####
install_subdir('data/devices',
strip_directory : true,
exclude_files : ['device.example', 'README.md'],
install_dir : join_paths(get_option('datadir'), 'libratbag'))
# list ordered by git ls-files data/devices/*.device
data_files = files(
'data/devices/etekcity-scroll-alpha.device',
'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-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.device',
'data/devices/logitech-g703-hero.device',
'data/devices/logitech-g703.device',
'data/devices/logitech-g9.device',
'data/devices/logitech-g900.device',
'data/devices/logitech-g903-hero.device',
'data/devices/logitech-g903.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',
'data/devices/steelseries-sensei-310.device',
'data/devices/steelseries-sensei-raw.device',
'data/devices/glorious-model-d.device',
'data/devices/glorious-model-o.device',
'data/devices/nubwo-x7-spectrum.device',
'data/devices/dream-machines-dm5-blink.device',
)
data_parse_test = find_program(join_paths(meson.source_root(), 'test/data-parse-test.py'))
test('data-parse-test', data_parse_test, args: 'data/devices')
install_data(data_files,
install_dir : join_paths(get_option('datadir'), 'libratbag'))
duplicate_test = find_program(join_paths(meson.source_root(), 'test/duplicate-check.py'))
test('duplicate-test', duplicate_test, args : 'data/devices')
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)
receiver_id_test = find_program(join_paths(meson.source_root(), 'test/receiver-check.py'))
test('receiver-id-test', receiver_id_test, args : 'data/devices')
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')
@@ -345,18 +400,16 @@ if enable_tests
test('test-util', test_util)
test('test-iconv-helper', test_iconv_helper)
valgrind = find_program('valgrind', required : false)
if valgrind.found()
valgrind_suppressions_file = join_paths(meson.source_root(), 'test', 'valgrind.suppressions')
add_test_setup('valgrind',
exe_wrapper : [
valgrind,
'--leak-check=full',
'--quiet',
'--error-exitcode=3',
'--suppressions=' + valgrind_suppressions_file ],
timeout_multiplier: 5)
endif
valgrind = find_program('valgrind')
valgrind_suppressions_file = join_paths(meson.source_root(), 'test', 'valgrind.suppressions')
add_test_setup('valgrind',
exe_wrapper : [
valgrind,
'--leak-check=full',
'--quiet',
'--error-exitcode=3',
'--suppressions=' + valgrind_suppressions_file ],
timeout_multiplier: 5)
endif
#### ratbagd ####
@@ -406,7 +459,7 @@ install_man('ratbagd/ratbagd.8')
dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
output : 'org.freedesktop.ratbag_devel1.conf',
copy: true)
copy : true)
# This is a hack. We always install the devel policy file into
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise.
@@ -494,12 +547,18 @@ configure_file(input : 'dbus/org.freedesktop.ratbag1.conf.in',
# 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)
pymod = import('python')
py3 = pymod.find_installation()
if meson.version().version_compare('>= 0.53.0')
dep_python3 = py3.dependency(embed : true)
if meson.version().version_compare('<0.48.0')
python = import('python3')
py3 = python.find_python()
py_version = python.language_version()
else
pymod = import('python')
py3 = pymod.find_installation()
if meson.version().version_compare('>= 0.53.0')
dep_python3 = py3.dependency(embed : true)
endif
py_version = py3.language_version()
endif
py_version = py3.language_version()
# From python 3.8 we neeed python3-embed
embed = py_version.version_compare('>= 3.8') ? '-embed' : ''

View File

@@ -241,7 +241,7 @@ special_lookup(const char *string)
{ "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-cycle-down", RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN},
{ "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},

View File

@@ -507,8 +507,10 @@ ratbagd_profile_set_report_rate(sd_bus *bus,
return r;
/* basic sanity check */
if (rate > 8000)
rate = 8000;
if (rate > 5000)
rate = 5000;
else if (rate % 100)
rate = rate - (rate % 100);
r = ratbag_profile_set_report_rate(profile->lib_profile, rate);
if (r == 0) {

View File

@@ -614,7 +614,7 @@ static void remove_ratbagd_devel_dbus_policy(void)
int main(int argc, char *argv[])
{
struct ratbagd *ctx = NULL;
int r = 0;
int r;
#if DISABLE_COREDUMP
const struct rlimit corelimit = { 0, 0 };
@@ -697,5 +697,5 @@ void ratbagd_schedule_task(struct ratbagd *ctx,
cb->callback = callback;
cb->userdata = userdata;
sd_event_add_defer(ctx->event, &source, ratbagd_callback_handler, cb);
sd_event_add_post(ctx->event, &source, ratbagd_callback_handler, cb);
}

View File

@@ -1,496 +0,0 @@
/*
* Copyright (C) 2021 Kyoken, kyoken@kyoken.ninja
*
* 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 "asus.h"
#include <assert.h>
#include "libratbag-data.h"
#include "libratbag-private.h"
/* ASUS commands */
#define ASUS_CMD_GET_LED_DATA 0x0312 /* get all LEDs */
#define ASUS_CMD_GET_SETTINGS 0x0412 /* dpi, rate, button response, angle snapping */
#define ASUS_CMD_GET_BUTTON_DATA 0x0512 /* get all buttons */
#define ASUS_CMD_GET_PROFILE_DATA 0x0012 /* get current profile info */
#define ASUS_CMD_SET_LED 0x2851 /* set single led */
#define ASUS_CMD_SET_SETTING 0x3151 /* dpi / rate / button response / angle snapping */
#define ASUS_CMD_SET_BUTTON 0x2151 /* set single button */
#define ASUS_CMD_SET_PROFILE 0x0250 /* switch profile */
#define ASUS_CMD_SAVE 0x0350 /* save settings */
/* fields order in _asus_dpiX_data, used for setting with ASUS_CMD_SET_SETTING */
#define ASUS_FIELD_RATE 0
#define ASUS_FIELD_RESPONSE 1
#define ASUS_FIELD_SNAPPING 2
/* order is mandatory because index is mapped from ButtonMapping configuration property */
static struct asus_button ASUS_BUTTON_MAPPING[] = {
{ 0xf0, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 1, 0 }, /* left */
{ 0xf1, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 2, 0 }, /* right (button 3 in xev) */
{ 0xf2, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 3, 0 }, /* middle (button 2 in xev) */
{ 0xe4, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 4, 0 }, /* backward (on left side) */
{ 0xe5, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 5, 0 }, /* forward (on left side) */
{ 0xe6, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP },
{ 0xe8, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP },
{ 0xe9, RATBAG_BUTTON_ACTION_TYPE_SPECIAL, 0, RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN },
{ 0xe1, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 4, 0 }, /* backward on right side */
{ 0xe2, RATBAG_BUTTON_ACTION_TYPE_BUTTON, 5, 0 }, /* forward on right side */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
{ 0xff, RATBAG_BUTTON_ACTION_TYPE_NONE, 0, 0 }, /* placeholder */
};
/* key mapping, the index is actual ASUS code */
static unsigned char ASUS_KEY_MAPPING[] = {
/* 00 */ 0, 0, 0, 0,
/* 04 */ KEY_A, KEY_B, KEY_C, KEY_D,
/* 08 */ KEY_E, KEY_F, KEY_G, KEY_H,
/* 0C */ KEY_I, KEY_J, KEY_K, KEY_L,
/* 0E */ KEY_M, KEY_N, KEY_O, KEY_P,
/* 14 */ KEY_Q, KEY_R, KEY_S, KEY_T,
/* 18 */ KEY_U, KEY_V, KEY_W, KEY_X,
/* 1C */ KEY_Y, KEY_Z, KEY_1, KEY_2,
/* 1E */ KEY_3, KEY_4, KEY_5, KEY_6,
/* 24 */ KEY_7, KEY_8, KEY_9, KEY_0,
/* 28 */ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB,
/* 2C */ KEY_SPACE, KEY_MINUS, KEY_KPPLUS, 0,
/* 2E */ 0, 0, 0, 0,
/* 34 */ 0, KEY_GRAVE, KEY_EQUAL, 0,
/* 38 */ KEY_SLASH, 0, KEY_F1, KEY_F2,
/* 3C */ KEY_F3, KEY_F4, KEY_F5, KEY_F6,
/* 3E */ KEY_F7, KEY_F8, KEY_F9, KEY_F10,
/* 44 */ KEY_F11, KEY_F12, 0, 0,
/* 48 */ 0, 0, KEY_HOME, KEY_PAGEUP,
/* 4C */ KEY_DELETE, 0, KEY_PAGEDOWN, KEY_RIGHT,
/* 4E */ KEY_LEFT, KEY_DOWN, KEY_UP, 0,
/* 54 */ 0, 0, 0, 0,
/* 58 */ 0, KEY_KP1, KEY_KP2, KEY_KP3,
/* 5C */ KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7,
/* 5E */ KEY_KP8, KEY_KP9, 0,
};
static unsigned int ASUS_LED_TYPE[] = {
RATBAG_LED_TYPE_LOGO, /* Mouse logo */
RATBAG_LED_TYPE_WHEEL, /* Mouse wheel */
RATBAG_LED_TYPE_SIDE, /* Bottom of the mouse */
};
static unsigned int ASUS_POLLING_RATES[] = { 125, 250, 500, 1000 };
/* search for ASUS button by ratbag types */
struct asus_button *
asus_find_button_by_action(struct ratbag_button_action action)
{
struct asus_button *asus_button;
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_BUTTON_MAPPING); i++) {
asus_button = &ASUS_BUTTON_MAPPING[i];
if ((action.type == RATBAG_BUTTON_ACTION_TYPE_BUTTON && asus_button->button == action.action.button) ||
(action.type == RATBAG_BUTTON_ACTION_TYPE_SPECIAL && asus_button->special == action.action.special))
return asus_button;
}
return NULL;
}
/* search for ASUS button by ASUS button code */
struct asus_button *
asus_find_button_by_code(uint8_t asus_code)
{
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_BUTTON_MAPPING); i++) {
if (ASUS_BUTTON_MAPPING[i].asus_code == asus_code)
return &ASUS_BUTTON_MAPPING[i];
}
return NULL;
}
/* search for ASUS key code by Linux key code */
int
asus_find_key_code(unsigned int linux_code)
{
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_KEY_MAPPING); i++) {
if (ASUS_KEY_MAPPING[i] == linux_code)
return i;
}
return -1;
}
/* convert ASUS key code to Linux key code */
int
asus_get_linux_key_code(uint8_t asus_code) {
assert(asus_code <= ARRAY_LENGTH(ASUS_KEY_MAPPING));
return ASUS_KEY_MAPPING[asus_code];
}
int
asus_query(struct ratbag_device *device,
union asus_request *request, union asus_response *response)
{
int rc;
rc = ratbag_hidraw_output_report(device, request->raw, ASUS_PACKET_SIZE);
if (rc < 0)
return rc;
memset(response, 0, sizeof(union asus_response));
rc = ratbag_hidraw_read_input_report(device, response->raw, ASUS_PACKET_SIZE, NULL);
if (rc < 0)
return rc;
/* invalid state, disconnected or sleeping */
if (response->data.code == 0xaaff) {
return ASUS_STATUS_ERROR;
}
return 0;
}
void
asus_setup_profile(struct ratbag_device *device, struct ratbag_profile *profile)
{
ratbag_profile_set_report_rate_list(
profile, ASUS_POLLING_RATES, ARRAY_LENGTH(ASUS_POLLING_RATES));
}
void
asus_setup_button(struct ratbag_device *device, struct ratbag_button *button)
{
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
}
void
asus_setup_resolution(struct ratbag_device *device, struct ratbag_resolution *resolution)
{
const struct dpi_range *dpirange = ratbag_device_data_asus_get_dpi_range(device->data);
if (!dpirange)
return;
ratbag_resolution_set_dpi_list_from_range(
resolution, dpirange->min, dpirange->max);
}
void
asus_setup_led(struct ratbag_device *device, struct ratbag_led *led)
{
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
led->type = ASUS_LED_TYPE[led->index];
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
}
int
asus_save_profile(struct ratbag_device *device)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_SAVE,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
int
asus_get_profile_data(struct ratbag_device *device, struct asus_profile_data *data)
{
int rc;
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_GET_PROFILE_DATA,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
if (quirks & ASUS_QUIRK_STRIX_PROFILE)
data->profile_id = response.data.results[7];
else
data->profile_id = response.data.results[8];
data->version_primary_major = response.data.results[13];
data->version_primary_minor = response.data.results[12];
data->version_primary_build = response.data.results[11];
data->version_secondary_major = response.data.results[4];
data->version_secondary_minor = response.data.results[3];
data->version_secondary_build = response.data.results[2];
return 0;
}
int
asus_set_profile(struct ratbag_device *device, unsigned int index)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_PROFILE,
.data.params[0] = index,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
/* read button bindings using ButtonMapping configuration property */
int
asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_GET_BUTTON_DATA,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
memcpy(data->raw, response.raw, sizeof(data->raw));
return 0;
}
/* set button binding using ASUS code of the button */
int
asus_set_button_action(struct ratbag_device *device, unsigned int asus_index, uint8_t asus_code, uint8_t asus_type)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_BUTTON,
};
/* source (physical mouse button) */
request.data.params[2] = ASUS_BUTTON_MAPPING[asus_index].asus_code;
request.data.params[3] = ASUS_BUTTON_ACTION_TYPE_BUTTON;
/* destination (mouse button or keyboard key action) */
request.data.params[4] = asus_code;
request.data.params[5] = asus_type;
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
int
asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data)
{
int rc;
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
union asus_response response;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
unsigned int i;
union asus_request request = {
.data.cmd = ASUS_CMD_GET_SETTINGS,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
memcpy(data->raw, response.raw, sizeof(data->raw));
/* convert DPI rates */
switch (dpi_count) {
case 2: /* 2 DPI presets */
for (i = 0; i < dpi_count; i++) {
data->data2.dpi[i] = data->data2.dpi[i] * 50 + 50;
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
data->data2.dpi[i] *= 2;
}
data->data2.rate = ASUS_POLLING_RATES[data->data2.rate];
break;
case 4: /* 4 DPI presets */
for (i = 0; i < dpi_count; i++) {
data->data4.dpi[i] = data->data4.dpi[i] * 50 + 50;
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
data->data4.dpi[i] *= 2;
}
data->data4.rate = ASUS_POLLING_RATES[data->data4.rate];
break;
default:
break;
}
return 0;
}
/* set DPI for the specified preset */
int
asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi)
{
int rc;
uint32_t quirks = ratbag_device_data_asus_get_quirks(device->data);
union asus_response response;
unsigned int idpi;
idpi = dpi;
if (quirks & ASUS_QUIRK_DOUBLE_DPI)
idpi /= 2;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_SETTING,
.data.params[0] = index,
.data.params[2] = (idpi - 50) / 50,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
/* set polling rate in Hz */
int
asus_set_polling_rate(struct ratbag_device *device, unsigned int hz)
{
int rc;
union asus_response response;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
unsigned int i;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_SETTING,
.data.params[0] = dpi_count + ASUS_FIELD_RATE, /* field index to set */
};
for (i = 0; i < ARRAY_LENGTH(ASUS_POLLING_RATES); i++) {
if (ASUS_POLLING_RATES[i] == hz) {
request.data.params[2] = i;
break;
}
}
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
/* set button response/debounce in ms (from 4 to 32 with step of 4) */
int
asus_set_button_response(struct ratbag_device *device, unsigned int ms)
{
assert(ms >= 4);
int rc;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_SETTING,
.data.params[0] = dpi_count + ASUS_FIELD_RESPONSE, /* field index to set */
.data.params[2] = ms / 4 - 1,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
int
asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled)
{
int rc;
union asus_response response;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_SETTING,
.data.params[0] = dpi_count + ASUS_FIELD_SNAPPING, /* field index to set */
.data.params[2] = is_enabled ? 1 : 0,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}
int
asus_get_led_data(struct ratbag_device *device, union asus_led_data *data)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_GET_LED_DATA,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
memcpy(data->raw, response.raw, sizeof(data->raw));
return 0;
}
/* set LED mode, brightness (0-4) and color */
int
asus_set_led(struct ratbag_device *device,
uint8_t index, uint8_t mode, uint8_t brightness,
struct ratbag_color color)
{
int rc;
union asus_response response;
union asus_request request = {
.data.cmd = ASUS_CMD_SET_LED,
.data.params[0] = index,
.data.params[2] = mode,
.data.params[3] = brightness,
.data.params[4] = color.red,
.data.params[5] = color.green,
.data.params[6] = color.blue,
};
rc = asus_query(device, &request, &response);
if (rc)
return rc;
return 0;
}

View File

@@ -1,214 +0,0 @@
#pragma once
#include <linux/input.h>
#include <stdint.h>
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
#define ASUS_QUIRK_DOUBLE_DPI 1 << 0
#define ASUS_QUIRK_STRIX_PROFILE 1 << 1
#define ASUS_PACKET_SIZE 64
#define ASUS_BUTTON_ACTION_TYPE_KEY 0 /* keyboard key */
#define ASUS_BUTTON_ACTION_TYPE_BUTTON 1 /* mouse button */
#define ASUS_BUTTON_CODE_DISABLED 0xff /* disabled mouse button */
#define ASUS_STATUS_ERROR 0xffaa /* invalid state/request, disconnected or sleeping */
/* maximum number of buttons across all ASUS devices */
#define ASUS_MAX_NUM_BUTTON 16
/* maximum number of DPI presets across all ASUS devices */
/* for 4 DPI devices: 0 - red, 1 - purple, 2 - blue (default), 3 - green */
/* for 2 DPI devices: 0 - main (default), 1 - alternative */
#define ASUS_MAX_NUM_DPI 4
/* maximum number of LEDs across all ASUS devices */
#define ASUS_MAX_NUM_LED 3
/* base request */
struct _asus_request {
uint16_t cmd;
uint8_t params[ASUS_PACKET_SIZE - 2];
} __attribute__((packed));
_Static_assert(sizeof(struct _asus_request) == ASUS_PACKET_SIZE, "The size of `_asus_request` is wrong.");
union asus_request {
struct _asus_request data;
uint8_t raw[ASUS_PACKET_SIZE];
};
/* base response */
struct _asus_response {
uint16_t code;
uint8_t results[ASUS_PACKET_SIZE - 2];
} __attribute__((packed));
_Static_assert(sizeof(struct _asus_response) == ASUS_PACKET_SIZE, "The size of `_asus_response` is wrong.");
union asus_response {
struct _asus_response data;
uint8_t raw[ASUS_PACKET_SIZE];
};
/* current profile ID and firmware info */
struct asus_profile_data {
unsigned int profile_id;
uint8_t version_primary_major;
uint8_t version_primary_minor;
uint8_t version_primary_build;
uint8_t version_secondary_major;
uint8_t version_secondary_minor;
uint8_t version_secondary_build;
} __attribute__((packed));
/* button bindings */
struct _asus_binding {
uint8_t action; /* ASUS code (for both keyboard keys and mouse buttons) */
uint8_t type; /* ASUS action type */
} __attribute__((packed));
struct _asus_binding_data {
uint32_t pad;
struct _asus_binding binding[ASUS_MAX_NUM_BUTTON];
} __attribute__((packed));
union asus_binding_data {
struct _asus_binding_data data;
uint8_t raw[ASUS_PACKET_SIZE];
};
/* DPI data */
struct _asus_dpi2_data {
uint32_t pad;
uint16_t dpi[2]; /* DPI presets */
uint16_t rate; /* polling rate */
uint16_t response; /* button response */
uint16_t snapping; /* angle snapping (on/off) */
} __attribute__((packed)); /* struct for storing 2 DPI presets and extra settings */
struct _asus_dpi4_data {
uint32_t pad;
uint16_t dpi[4];
uint16_t rate;
uint16_t response;
uint16_t snapping;
} __attribute__((packed)); /* struct for storing 4 DPI presets and extra settings */
union asus_resolution_data {
struct _asus_dpi2_data data2; /* data for 2 DPI presets */
struct _asus_dpi4_data data4; /* data for 4 DPI presets */
uint8_t raw[sizeof(struct _asus_dpi4_data)];
};
/* LED data */
struct _asus_led {
uint8_t mode;
uint8_t brightness; /* 0-4 */
uint8_t r;
uint8_t g;
uint8_t b;
} __attribute__((packed));
struct _asus_led_data {
uint32_t pad;
struct _asus_led led[ASUS_MAX_NUM_LED]; /* LEDs */
} __attribute__((packed));
union asus_led_data {
struct _asus_led_data data;
uint8_t raw[sizeof(struct _asus_led_data)];
};
/* button define */
struct asus_button {
uint8_t asus_code; /* used for button action */
enum ratbag_button_action_type type;
uint8_t button; /* mouse button number, optional */
enum ratbag_button_action_special special; /* special action, optional */
};
struct asus_button *
asus_find_button_by_action(struct ratbag_button_action action);
struct asus_button *
asus_find_button_by_code(uint8_t asus_code);
int
asus_find_key_code(unsigned int linux_code);
int
asus_get_linux_key_code(uint8_t asus_code);
/* initializers of ratbag data */
void
asus_setup_profile(struct ratbag_device *device, struct ratbag_profile *profile);
void
asus_setup_button(struct ratbag_device *device, struct ratbag_button *button);
void
asus_setup_resolution(struct ratbag_device *device, struct ratbag_resolution *resolution);
void
asus_setup_led(struct ratbag_device *device, struct ratbag_led *led);
/* generic i/o */
int
asus_query(struct ratbag_device *device, union asus_request *request, union asus_response *response);
/* commit */
int
asus_save_profile(struct ratbag_device *device);
/* profiles */
int
asus_get_profile_data(struct ratbag_device *device, struct asus_profile_data *data);
int
asus_set_profile(struct ratbag_device *device, unsigned int index);
/* button bindings */
int
asus_get_binding_data(struct ratbag_device *device, union asus_binding_data *data);
int
asus_set_button_action(struct ratbag_device *device, unsigned int index,
uint8_t asus_code, uint8_t asus_type);
/* resolution settings */
int
asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_data *data);
int
asus_set_dpi(struct ratbag_device *device, unsigned int index, unsigned int dpi);
int
asus_set_polling_rate(struct ratbag_device *device, unsigned int hz);
int
asus_set_button_response(struct ratbag_device *device, unsigned int ms);
int
asus_set_angle_snapping(struct ratbag_device *device, bool is_enabled);
/* LED settings */
int
asus_get_led_data(struct ratbag_device *device, union asus_led_data *data);
int
asus_set_led(struct ratbag_device *device,
uint8_t index, uint8_t mode, uint8_t brightness,
struct ratbag_color color);

View File

@@ -1,517 +0,0 @@
/*
* Copyright (C) 2021 Kyoken, kyoken@kyoken.ninja
*
* 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 <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
#include "libratbag-data.h"
#include "asus.h"
/* ButtonMapping configuration property defaults, stores indices for ASUS_BUTTON_MAPPING */
static int8_t ASUS_BUTTON_MAPPING_INDEX[] = {
0, /* left */
1, /* right (button 3 in xev) */
2, /* middle (button 2 in xev) */
6, /* wheel up */
7, /* wheel down */
5, /* DPI */
3, /* backward */
4, /* forward */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
-1, /* placeholder */
};
static unsigned int ASUS_LED_MODE[] = {
RATBAG_LED_ON,
RATBAG_LED_BREATHING,
RATBAG_LED_CYCLE,
RATBAG_LED_ON, /* rainbow wave */
RATBAG_LED_ON, /* reactive - react to clicks */
RATBAG_LED_ON, /* custom - depends on mouse type */
RATBAG_LED_ON, /* battery - battery indicator */
};
struct asus_data {
uint8_t is_ready;
};
static int
asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *profile)
{
int rc;
const int8_t *bmi = ratbag_device_data_asus_get_button_mapping(device->data);
struct _asus_binding *asus_binding;
struct _asus_led *asus_led;
struct asus_button *asus_button;
struct ratbag_button *button;
struct ratbag_led *led;
struct ratbag_resolution *resolution;
union asus_binding_data binding_data;
union asus_led_data led_data;
union asus_resolution_data resolution_data;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
/* get buttons */
log_debug(device->ratbag, "Loading buttons data\n");
rc = asus_get_binding_data(device, &binding_data);
if (rc)
return rc;
ratbag_profile_for_each_button(profile, button) {
int asus_index = bmi[button->index] != -1 ? bmi[button->index] : ASUS_BUTTON_MAPPING_INDEX[button->index];
if (asus_index == -1) {
log_debug(device->ratbag, "No mapping for button %d\n", button->index);
continue;
}
asus_binding = &binding_data.data.binding[asus_index];
/* disabled */
if (asus_binding->action == ASUS_BUTTON_CODE_DISABLED) {
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
continue;
}
/* got action */
switch (asus_binding->type) {
case ASUS_BUTTON_ACTION_TYPE_KEY:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
/* ASUS code to Linux code */
button->action.action.key.key = asus_get_linux_key_code(asus_binding->action);
break;
case ASUS_BUTTON_ACTION_TYPE_BUTTON:
asus_button = asus_find_button_by_code(asus_binding->action);
if (asus_button != NULL) { /* found button to bind to */
button->action.type = asus_button->type;
if (asus_button->type == RATBAG_BUTTON_ACTION_TYPE_BUTTON)
button->action.action.button = asus_button->button;
else if (asus_button->type == RATBAG_BUTTON_ACTION_TYPE_SPECIAL)
button->action.action.special = asus_button->special;
} else {
log_debug(device->ratbag, "Unknown action code %02x\n", asus_binding->action);
}
break;
default:
break;
}
}
/* get DPIs */
log_debug(device->ratbag, "Loading resolutions data\n");
rc = asus_get_resolution_data(device, &resolution_data);
if (rc)
return rc;
switch (dpi_count) {
case 2: /* 2 DPI presets */
ratbag_profile_set_report_rate(profile, resolution_data.data2.rate);
ratbag_profile_for_each_resolution(profile, resolution)
ratbag_resolution_set_resolution(
resolution,
resolution_data.data2.dpi[resolution->index],
resolution_data.data2.dpi[resolution->index]);
break;
case 4: /* 4 DPI presets */
ratbag_profile_set_report_rate(profile, resolution_data.data4.rate);
ratbag_profile_for_each_resolution(profile, resolution)
ratbag_resolution_set_resolution(
resolution,
resolution_data.data4.dpi[resolution->index],
resolution_data.data4.dpi[resolution->index]);
break;
default:
break;
}
/* get LEDs */
log_debug(device->ratbag, "Loading LEDs data\n");
rc = asus_get_led_data(device, &led_data);
if (rc)
return rc;
ratbag_profile_for_each_led(profile, led) {
asus_led = &led_data.data.led[led->index];
led->mode = ASUS_LED_MODE[asus_led->mode];
/* convert brightness from 0-4 to 0-256 */
led->brightness = asus_led->brightness * 64;
led->color.red = asus_led->r;
led->color.green = asus_led->g;
led->color.blue = asus_led->b;
}
return 0;
}
static int
asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *profile)
{
int rc = 0;
const int8_t *bmi = ratbag_device_data_asus_get_button_mapping(device->data);
struct asus_button *asus_button;
struct ratbag_button *button;
struct ratbag_led *led;
struct ratbag_resolution *resolution;
/* set buttons */
ratbag_profile_for_each_button(profile, button) {
if (!button->dirty)
continue;
int asus_index = bmi[button->index] != -1 ? bmi[button->index] : ASUS_BUTTON_MAPPING_INDEX[button->index];
int asus_code;
if (asus_index == -1) {
log_debug(device->ratbag, "No mapping for button %d\n", button->index);
continue;
}
log_debug(device->ratbag, "Button %d (%d) changed\n", button->index, asus_index);
switch (button->action.type) {
case RATBAG_BUTTON_ACTION_TYPE_NONE:
rc = asus_set_button_action(
device, asus_index,
ASUS_BUTTON_CODE_DISABLED,
ASUS_BUTTON_ACTION_TYPE_BUTTON);
break;
case RATBAG_BUTTON_ACTION_TYPE_KEY:
/* Linux code to ASUS code */
asus_code = asus_find_key_code(button->action.action.key.key);
if (asus_code >= 0)
rc = asus_set_button_action(
device, asus_index,
asus_code,
ASUS_BUTTON_ACTION_TYPE_KEY);
break;
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
asus_button = asus_find_button_by_action(button->action);
if (asus_button != NULL) /* found button to bind to */
rc = asus_set_button_action(
device, asus_index,
asus_button->asus_code,
ASUS_BUTTON_ACTION_TYPE_BUTTON);
break;
default:
break;
}
if (rc)
return rc;
}
/* set extra settings */
if (profile->rate_dirty) {
log_debug(device->ratbag, "Polling rate changed to %d Hz\n", profile->hz);
rc = asus_set_polling_rate(device, profile->hz);
if (rc)
return rc;
}
/* set DPIs */
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)
continue;
log_debug(
device->ratbag, "Resolution %d changed to %d\n",
resolution->index, resolution->dpi_x);
rc = asus_set_dpi(device, resolution->index, resolution->dpi_x);
if (rc)
return rc;
}
/* set LEDs */
ratbag_profile_for_each_led(profile, led) {
if (!led->dirty)
continue;
log_debug(device->ratbag, "LED %d changed\n", led->index);
uint8_t led_mode = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_LED_MODE); i++) {
if (ASUS_LED_MODE[i] == led->mode) {
led_mode = i;
break;
}
}
/* convert brightness from 0-256 to 0-4 */
uint8_t led_brightness = (uint8_t)round((double)led->brightness / 64.0);
rc = asus_set_led(device, led->index, led_mode, led_brightness, led->color);
if (rc)
return rc;
}
return 0;
}
static int
asus_driver_load_profiles(struct ratbag_device *device)
{
int rc;
struct asus_profile_data profile_data;
struct ratbag_profile *profile;
unsigned int current_profile_id;
/* get current profile id */
rc = asus_get_profile_data(device, &profile_data);
if (rc)
return rc;
current_profile_id = profile_data.profile_id;
log_debug(device->ratbag, "Initial profile is %d\n", current_profile_id);
log_debug(
device->ratbag, "Primary version %02X.%02X.%02X\n",
profile_data.version_primary_major,
profile_data.version_primary_minor,
profile_data.version_primary_build);
log_debug(
device->ratbag, "Secondary version %02X.%02X.%02X\n",
profile_data.version_secondary_major,
profile_data.version_secondary_minor,
profile_data.version_secondary_build);
/* read ratbag profiles */
ratbag_device_for_each_profile(device, profile) {
if (profile->index == current_profile_id) { /* profile is already selected */
profile->is_active = true;
} else { /* switch profile */
profile->is_active = false;
log_debug(device->ratbag, "Switching to profile %d\n", profile->index);
rc = asus_set_profile(device, profile->index);
if (rc)
return rc;
}
rc = asus_driver_load_profile(device, profile);
if (rc)
return rc;
}
/* back to initial profile */
if (device->num_profiles > 1) {
log_debug(device->ratbag, "Switching back to initial profile %d\n", current_profile_id);
rc = asus_set_profile(device, current_profile_id);
if (rc)
return rc;
}
return 0;
}
static int
asus_driver_save_profiles(struct ratbag_device *device)
{
int rc;
struct asus_profile_data profile_data;
struct ratbag_profile *profile;
unsigned int current_profile_id;
/* get current profile id */
rc = asus_get_profile_data(device, &profile_data);
if (rc)
return rc;
current_profile_id = profile_data.profile_id;
log_debug(device->ratbag, "Initial profile is %d\n", current_profile_id);
ratbag_device_for_each_profile(device, profile) {
if (!profile->dirty)
continue;
log_debug(device->ratbag, "Profile %d changed\n", profile->index);
/* switch profile */
if (profile->index != current_profile_id) {
log_debug(device->ratbag, "Switching to profile %d\n", profile->index);
rc = asus_set_profile(device, profile->index);
if (rc)
return rc;
}
rc = asus_driver_save_profile(device, profile);
if (rc)
return rc;
/* save profile */
log_debug(device->ratbag, "Saving profile\n");
rc = asus_save_profile(device);
if (rc)
return rc;
}
/* back to initial profile */
if (device->num_profiles > 1) {
log_debug(device->ratbag, "Switching back to initial profile %d\n", current_profile_id);
rc = asus_set_profile(device, current_profile_id);
if (rc)
return rc;
}
return 0;
}
static int
asus_driver_probe(struct ratbag_device *device)
{
int rc;
unsigned int profile_count, dpi_count, button_count, led_count;
struct asus_data *drv_data;
struct ratbag_profile *profile;
struct ratbag_button *button;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
rc = ratbag_open_hidraw(device);
if (rc)
return rc;
/* create device state data */
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
drv_data->is_ready = 1;
/* get device properties from configuration file */
profile_count = ratbag_device_data_asus_get_profile_count(device->data);
dpi_count = ratbag_device_data_asus_get_dpi_count(device->data);
button_count = ratbag_device_data_asus_get_button_count(device->data);
led_count = ratbag_device_data_asus_get_led_count(device->data);
/* init profiles */
ratbag_device_init_profiles(
device,
max(profile_count, 1),
max(dpi_count, 2),
max(button_count, 8),
max(led_count, 0));
/* setup profiles */
ratbag_device_for_each_profile(device, profile) {
if (profile->index == 0) {
profile->is_active = true;
}
asus_setup_profile(device, profile);
ratbag_profile_for_each_button(profile, button)
asus_setup_button(device, button);
ratbag_profile_for_each_resolution(profile, resolution)
asus_setup_resolution(device, resolution);
ratbag_profile_for_each_led(profile, led)
asus_setup_led(device, led);
}
/* load profiles */
rc = asus_driver_load_profiles(device);
if (rc == ASUS_STATUS_ERROR) { /* mouse in invalid state */
drv_data->is_ready = 0;
} else if (rc) { /* other errors */
log_error(
device->ratbag, "Can't talk to the mouse: '%s' (%d)\n",
strerror(-rc), rc);
free(drv_data);
ratbag_set_drv_data(device, NULL);
return -ENODEV;
}
return 0;
}
static void
asus_driver_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
free(ratbag_get_drv_data(device));
}
static int
asus_driver_commit(struct ratbag_device *device)
{
int rc;
struct asus_data *drv_data;
/* check last device state */
drv_data = ratbag_get_drv_data(device);
if (!drv_data->is_ready) { /* device was not ready */
log_error(device->ratbag, "Device was not ready, trying to reload\n");
rc = asus_driver_load_profiles(device);
if (rc) {
log_error(device->ratbag, "Device reloading failed (%d)\n", rc);
if (rc != ASUS_STATUS_ERROR)
return rc;
} else {
drv_data->is_ready = 1;
log_error(device->ratbag, "Device was successfully reloaded\n");
}
return RATBAG_ERROR_DEVICE; /* fail in any case because we tried to rollback instead of commit */
}
/* save profiles */
rc = asus_driver_save_profiles(device);
if (rc) {
log_error(device->ratbag, "Commit failed (%d)\n", rc);
if (rc != ASUS_STATUS_ERROR)
return rc;
return RATBAG_ERROR_DEVICE;
}
return 0;
}
struct ratbag_driver asus_driver = {
.name = "ASUS",
.id = "asus",
.probe = asus_driver_probe,
.remove = asus_driver_remove,
.commit = asus_driver_commit,
.set_active_profile = asus_set_profile,
};

View File

@@ -496,9 +496,9 @@ etekcity_read_profile(struct ratbag_profile *profile)
}
static int
etekcity_write_macro(struct ratbag_button *button)
etekcity_write_macro(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
const struct ratbag_button_action *action = &button->action;
struct ratbag_device *device;
struct etekcity_macro *macro;
struct etekcity_data *drv_data;
@@ -555,9 +555,9 @@ etekcity_write_macro(struct ratbag_button *button)
}
static int
etekcity_write_button(struct ratbag_button *button)
etekcity_write_button(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
const struct ratbag_button_action *action = &button->action;
struct ratbag_profile *profile = button->profile;
struct ratbag_device *device = profile->device;
struct etekcity_data *drv_data = ratbag_get_drv_data(device);
@@ -572,7 +572,15 @@ etekcity_write_button(struct ratbag_button *button)
*data = rc;
rc = etekcity_write_macro(button);
rc = etekcity_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 = etekcity_write_macro(button, action);
if (rc) {
log_error(device->ratbag,
"unable to write the macro to the device: '%s' (%d)\n",
@@ -584,7 +592,8 @@ etekcity_write_button(struct ratbag_button *button)
}
static int
etekcity_write_resolution(struct ratbag_resolution *resolution)
etekcity_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;
@@ -593,9 +602,6 @@ etekcity_write_resolution(struct ratbag_resolution *resolution)
uint8_t *buf;
int rc;
const unsigned int dpi_x = resolution->dpi_x;
const unsigned int dpi_y = resolution->dpi_y;
if (dpi_x < 50 || dpi_x > 8200 || dpi_x % 50)
return -EINVAL;
if (dpi_y < 50 || dpi_y > 8200 || dpi_y % 50)
@@ -699,49 +705,13 @@ etekcity_remove(struct ratbag_device *device)
free(ratbag_get_drv_data(device));
}
static int
etekcity_commit(struct ratbag_device *device)
{
int rc = 0;
struct ratbag_button *button = NULL;
struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution = NULL;
ratbag_device_for_each_profile(device, profile) {
if (!profile->dirty)
continue;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)
continue;
rc = etekcity_write_resolution(resolution);
if (rc)
return rc;
}
ratbag_profile_for_each_button(profile, button) {
if (!button->dirty)
continue;
rc = etekcity_write_button(button);
if (rc)
return rc;
}
rc = etekcity_write_profile(profile);
if (rc)
return rc;
}
return 0;
}
struct ratbag_driver etekcity_driver = {
.name = "EtekCity",
.id = "etekcity",
.probe = etekcity_probe,
.remove = etekcity_remove,
.commit = etekcity_commit,
.write_profile = etekcity_write_profile,
.set_active_profile = etekcity_set_current_profile,
.write_button = etekcity_write_button,
.write_resolution_dpi = etekcity_write_resolution_dpi,
};

View File

@@ -448,7 +448,7 @@ hidpp10drv_read_profile(struct ratbag_profile *profile)
free(profile->name);
profile->name = NULL;
}
if (p.name[0] != '\0')
if (p.name && p.name[0] != '\0')
profile->name = strdup_safe((char*)p.name);
rc = hidpp10_get_current_profile(hidpp10, &idx);
@@ -548,7 +548,7 @@ hidpp10_log(void *userdata, enum hidpp_log_priority priority, const char *format
{
struct ratbag_device *device = userdata;
log_msg_va(device->ratbag, (enum ratbag_log_priority)priority, format, args);
log_msg_va(device->ratbag, priority, format, args);
}
static int

View File

@@ -957,7 +957,7 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
if (drv_data->capabilities & HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060) {
rc = hidpp20drv_read_report_rate_8060(device);
if (rc < 0 && drv_data->report_rates[0] == 0)
if (rc < 0)
return rc;
ratbag_profile_set_report_rate_list(profile,
@@ -1096,7 +1096,6 @@ hidpp20drv_read_special_key_mouse(struct ratbag_device *device)
drv_data->controls = NULL;
drv_data->num_controls = 0;
rc = hidpp20_special_key_mouse_get_controls(drv_data->dev, &drv_data->controls);
log_raw(device->ratbag, "num_control %d\n", rc);
if (rc > 0) {
drv_data->num_controls = rc;
rc = 0;
@@ -1209,7 +1208,9 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile)
profile->is_enabled = drv_data->profiles->profiles[profile->index].enabled;
profile->is_active = (profile->index == drv_data->profiles->active_profile_index);
profile->is_active = false;
if ((int)profile->index == hidpp20drv_current_profile(device))
profile->is_active = true;
if (profile->is_active)
dpi_index = hidpp20_onboard_profiles_get_current_dpi_index(drv_data->dev);
@@ -1603,7 +1604,7 @@ hidpp20_log(void *userdata, enum hidpp_log_priority priority, const char *format
{
struct ratbag_device *device = userdata;
log_msg_va(device->ratbag, (enum ratbag_log_priority)priority, format, args);
log_msg_va(device->ratbag, priority, format, args);
}
static void
@@ -1641,14 +1642,6 @@ hidpp20drv_init_device(struct ratbag_device *device,
if (num >= 0)
drv_data->num_leds = num;
num = ratbag_device_data_hidpp20_get_button_count(device->data);
if (num >= 0)
drv_data->num_buttons = num;
num = ratbag_device_data_hidpp20_get_report_rate(device->data);
if (num >= 0)
drv_data->report_rates[0] = num;
ratbag_device_init_profiles(device,
drv_data->num_profiles,
drv_data->num_resolutions,

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -603,9 +603,9 @@ roccat_write_macro(struct ratbag_button *button,
}
static int
roccat_write_button(struct ratbag_button *button)
roccat_write_button(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
const struct ratbag_button_action *action = &button->action;
struct ratbag_profile *profile = button->profile;
struct ratbag_device *device = profile->device;
struct roccat_data *drv_data = ratbag_get_drv_data(device);
@@ -639,7 +639,8 @@ roccat_write_button(struct ratbag_button *button)
}
static int
roccat_write_resolution(struct ratbag_resolution *resolution)
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;
@@ -648,10 +649,7 @@ roccat_write_resolution(struct ratbag_resolution *resolution)
uint8_t *buf;
int rc;
const unsigned int dpi_x = resolution->dpi_x;
const unsigned int dpi_y = resolution->dpi_y;
if (dpi_x < 200 || dpi_x > 8200 || dpi_x % 50)
if (dpi_x < 100 || dpi_x > 5000 || dpi_x % 50)
return -EINVAL;
if (dpi_y < 100 || dpi_y > 5000 || dpi_y % 50)
return -EINVAL;
@@ -835,50 +833,13 @@ roccat_remove(struct ratbag_device *device)
free(ratbag_get_drv_data(device));
}
static int
roccat_commit(struct ratbag_device *device)
{
int rc = 0;
struct ratbag_button *button = NULL;
struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution = NULL;
ratbag_device_for_each_profile(device, profile) {
if (!profile->dirty)
continue;
rc = roccat_write_profile(profile);
if (rc)
return rc;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)
continue;
rc = roccat_write_resolution(resolution);
if (rc)
return rc;
}
ratbag_profile_for_each_button(profile, button) {
if (!button->dirty)
continue;
rc = roccat_write_button(button);
if (rc)
return rc;
}
}
return 0;
}
struct ratbag_driver roccat_kone_pure_driver = {
struct ratbag_driver roccat_driver = {
.name = "Roccat Kone Pure",
.id = "roccat-kone-pure",
.probe = roccat_probe,
.remove = roccat_remove,
.commit = roccat_commit,
.write_profile = roccat_write_profile,
.set_active_profile = roccat_set_current_profile,
.write_button = roccat_write_button,
.write_resolution_dpi = roccat_write_resolution_dpi,
};

View File

@@ -57,7 +57,7 @@
struct roccat_settings_report {
uint8_t reportID;
uint8_t report_length;
uint8_t twoB;
uint8_t profileID;
uint8_t x_y_linked;
uint8_t x_sensitivity; /* 0x06 means 0 */
@@ -78,7 +78,8 @@ struct roccat_settings_report {
struct roccat_macro {
uint8_t reportID;
uint16_t report_length;
uint8_t twentytwo;
uint8_t height;
uint8_t profile;
uint8_t button_index;
uint8_t active;
@@ -580,7 +581,8 @@ roccat_write_macro(struct ratbag_button *button,
}
macro->reportID = ROCCAT_REPORT_ID_MACRO;
macro->report_length = 0x0822;
macro->twentytwo = 0x22;
macro->height = 0x08;
macro->profile = button->profile->index;
macro->button_index = button->index;
macro->active = 0x01;
@@ -607,9 +609,9 @@ roccat_write_macro(struct ratbag_button *button,
}
static int
roccat_write_button(struct ratbag_button *button)
roccat_write_button(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
const struct ratbag_button_action *action = &button->action;
struct ratbag_profile *profile = button->profile;
struct ratbag_device *device = profile->device;
struct roccat_data *drv_data = ratbag_get_drv_data(device);
@@ -643,7 +645,8 @@ roccat_write_button(struct ratbag_button *button)
}
static int
roccat_write_resolution(struct ratbag_resolution *resolution)
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;
@@ -652,9 +655,6 @@ roccat_write_resolution(struct ratbag_resolution *resolution)
uint8_t *buf;
int rc;
const unsigned int dpi_x = resolution->dpi_x;
const unsigned int dpi_y = resolution->dpi_y;
if (dpi_x < 200 || dpi_x > 8200 || dpi_x % 50)
return -EINVAL;
if (dpi_y < 200 || dpi_y > 8200 || dpi_y % 50)
@@ -835,50 +835,13 @@ roccat_remove(struct ratbag_device *device)
free(ratbag_get_drv_data(device));
}
static int
roccat_commit(struct ratbag_device *device)
{
int rc = 0;
struct ratbag_button *button = NULL;
struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution = NULL;
ratbag_device_for_each_profile(device, profile) {
if (!profile->dirty)
continue;
rc = roccat_write_profile(profile);
if (rc)
return rc;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)
continue;
rc = roccat_write_resolution(resolution);
if (rc)
return rc;
}
ratbag_profile_for_each_button(profile, button) {
if (!button->dirty)
continue;
rc = roccat_write_button(button);
if (rc)
return rc;
}
}
return 0;
}
struct ratbag_driver roccat_driver = {
.name = "Roccat Kone XTD",
.id = "roccat",
.probe = roccat_probe,
.remove = roccat_remove,
.commit = roccat_commit,
.write_profile = roccat_write_profile,
.set_active_profile = roccat_set_current_profile,
.write_button = roccat_write_button,
.write_resolution_dpi = roccat_write_resolution_dpi,
};

View File

@@ -21,7 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include "libratbag-enums.h"
#include "libratbag-hidraw.h"
#include "libratbag-private.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +0,0 @@
/*
* Copyright © 2022 Yaroslav Chvanov
*
* 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-util.h"
enum sinowealth_led_format {
SINOWEALTH_LED_TYPE_NONE,
SINOWEALTH_LED_TYPE_RBG,
SINOWEALTH_LED_TYPE_RGB,
};
struct sinowealth_device_data {
char *fw_version;
char *device_name;
enum sinowealth_led_format led_type;
unsigned int button_count;
struct list link;
};

View File

@@ -30,7 +30,6 @@
#include <stdint.h>
#include <string.h>
#include "driver-steelseries.h"
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
#include "libratbag-data.h"
@@ -42,7 +41,6 @@
#define STEELSERIES_INPUT_HIDRAW 1
/* not sure these two are used for */
#define STEELSERIES_REPORT_ID 0x00 // steelseries doesn't use numbered reports
#define STEELSERIES_REPORT_ID_1 0x01
#define STEELSERIES_REPORT_ID_2 0x02
@@ -55,16 +53,14 @@
#define STEELSERIES_ID_LED_INTENSITY_SHORT 0x05
#define STEELSERIES_ID_LED_EFFECT_SHORT 0x07
#define STEELSERIES_ID_LED_COLOR_SHORT 0x08
#define STEELSERIES_ID_LED_COLOR_SHORT_RIVAL100 0x05
#define STEELSERIES_ID_SAVE_SHORT 0x09
#define STEELSERIES_ID_FIRMWARE_PROTOCOL1 0x10
#define STEELSERIES_ID_BUTTONS 0x31
#define STEELSERIES_ID_DPI 0x53
#define STEELSERIES_ID_REPORT_RATE 0x54
#define STEELSERIES_ID_LED 0x5b
#define STEELSERIES_ID_SAVE 0x59
#define STEELSERIES_ID_FIRMWARE_PROTOCOL2 0x90
#define STEELSERIES_ID_FIRMWARE 0x90
#define STEELSERIES_ID_SETTTINGS 0x92
#define STEELSERIES_ID_DPI_PROTOCOL3 0x03
@@ -116,31 +112,11 @@ struct steelseries_led_cycle_spec {
int point_count_idx; /* index of the point counter field */
};
struct _steelseries_message {
uint8_t report_id;
uint8_t parameters[STEELSERIES_REPORT_SIZE - 1];
} __attribute__((packed));
union steelseries_message {
struct _steelseries_message msg;
uint8_t data[STEELSERIES_REPORT_SIZE];
};
_Static_assert(sizeof(union steelseries_message) == STEELSERIES_REPORT_SIZE,
"Size of union steelseries_message is wrong");
static int
steelseries_test_hidraw(struct ratbag_device *device)
{
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
/* Rival mice are composite devices with multiple HID devices
* and only the HID vendor device can be used to configure the
* device.
*/
if (!ratbag_hidraw_has_vendor_page(device))
return false;
if (device_version > 1)
return ratbag_hidraw_has_report(device, STEELSERIES_REPORT_ID_1);
else
@@ -203,38 +179,23 @@ steelseries_get_firmware_version(struct ratbag_device *device)
{
struct steelseries_data *drv_data = device->drv_data;
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
size_t msg_len;
uint8_t buf[2] = {0};
size_t buf_len = STEELSERIES_REPORT_SIZE;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
int ret;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
switch (device_version) {
case 1:
msg.msg.parameters[0] = STEELSERIES_ID_FIRMWARE_PROTOCOL1;
msg_len = STEELSERIES_REPORT_SIZE_SHORT;
break;
case 2:
msg.msg.parameters[0] = STEELSERIES_ID_FIRMWARE_PROTOCOL2;
msg_len = STEELSERIES_REPORT_SIZE;
break;
case 3:
msg.msg.parameters[0] = STEELSERIES_ID_FIRMWARE_PROTOCOL3;
msg_len = STEELSERIES_REPORT_SIZE;
break;
default:
if (device_version == 2)
buf[0] = STEELSERIES_ID_FIRMWARE;
else if (device_version == 3)
buf[0] = STEELSERIES_ID_FIRMWARE_PROTOCOL3;
else
return -ENOTSUP;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, msg_len);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, sizeof(buf), STEELSERIES_INPUT_HIDRAW, NULL);
ret = ratbag_hidraw_read_input_report_index(device, buf, buf_len, STEELSERIES_INPUT_HIDRAW);
if (ret < 0)
return ret;
@@ -252,33 +213,24 @@ steelseries_read_settings(struct ratbag_device *device)
struct ratbag_resolution *resolution;
struct ratbag_led *led;
size_t buf_len = STEELSERIES_REPORT_SIZE;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
int ret;
unsigned int active_resolution;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
switch (device_version) {
case 2:
msg.msg.parameters[0] = STEELSERIES_ID_SETTTINGS;
break;
case 3:
msg.msg.parameters[0] = STEELSERIES_ID_SETTTINGS_PROTOCOL3;
break;
case 1:
default:
if (device_version == 2)
buf[0] = STEELSERIES_ID_SETTTINGS;
else if (device_version == 3)
buf[0] = STEELSERIES_ID_SETTTINGS_PROTOCOL3;
else
return -ENOTSUP;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, STEELSERIES_REPORT_SIZE);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, STEELSERIES_REPORT_SIZE, STEELSERIES_INPUT_HIDRAW, NULL);
ret = ratbag_hidraw_read_input_report_index(device, buf, buf_len, STEELSERIES_INPUT_HIDRAW);
if (ret < 0)
return ret;
@@ -318,7 +270,7 @@ steelseries_probe(struct ratbag_device *device)
struct ratbag_resolution *resolution;
struct ratbag_button *button;
struct ratbag_led *led;
int rc, button_count, led_count, device_version, quirk;
int rc, button_count, led_count, device_version, mono_led, short_button;
struct dpi_list *dpilist = NULL;
struct dpi_range *dpirange = NULL;
@@ -335,22 +287,12 @@ steelseries_probe(struct ratbag_device *device)
return rc;
device_version = ratbag_device_data_steelseries_get_device_version(device->data);
if (device_version == -1) {
log_error(device->ratbag, "Device version not set\n");
return -EINVAL;
}
button_count = ratbag_device_data_steelseries_get_button_count(device->data);
if (button_count == -1)
button_count = 0;
led_count = ratbag_device_data_steelseries_get_led_count(device->data);
if (led_count == -1)
led_count = 0;
dpirange = ratbag_device_data_steelseries_get_dpi_range(device->data);
dpilist = ratbag_device_data_steelseries_get_dpi_list(device->data);
quirk = ratbag_device_data_steelseries_get_quirk(device->data);
mono_led = ratbag_device_data_steelseries_get_mono_led(device->data);
short_button = ratbag_device_data_steelseries_get_short_button(device->data);
ratbag_device_init_profiles(device,
STEELSERIES_NUM_PROFILES,
@@ -394,7 +336,7 @@ steelseries_probe(struct ratbag_device *device)
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
if (quirk != STEELSERIES_QUIRK_SENSEIRAW) {
if (short_button == 0) {
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
}
@@ -404,7 +346,7 @@ steelseries_probe(struct ratbag_device *device)
ratbag_profile_for_each_led(profile, led) {
led->type = led->index == 0 ? RATBAG_LED_TYPE_LOGO : RATBAG_LED_TYPE_WHEEL;
led->mode = RATBAG_LED_ON;
if (quirk == STEELSERIES_QUIRK_SENSEIRAW) {
if (mono_led) {
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
led->brightness = 255;
} else {
@@ -443,19 +385,15 @@ steelseries_write_dpi(struct ratbag_resolution *resolution)
struct dpi_list *dpilist = NULL;
struct dpi_range *dpirange = NULL;
int ret;
int i = 0;
size_t buf_len;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
dpirange = ratbag_device_data_steelseries_get_dpi_range(device->data);
dpilist = ratbag_device_data_steelseries_get_dpi_list(device->data);
switch (device_version) {
case 1:
if (device_version == 1) {
int i = 0;
/* when using lists the entries are enumerated in reverse */
if (dpilist) {
for (i = 0; i < (int)resolution->ndpis; i++) {
@@ -468,30 +406,27 @@ steelseries_write_dpi(struct ratbag_resolution *resolution)
}
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
msg.msg.parameters[0] = STEELSERIES_ID_DPI_SHORT;
msg.msg.parameters[1] = resolution->index + 1;
msg.msg.parameters[2] = i;
break;
case 2:
buf[0] = STEELSERIES_ID_DPI_SHORT;
buf[1] = resolution->index + 1;
buf[2] = i;
} else if (device_version == 2) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_DPI;
msg.msg.parameters[2] = resolution->index + 1;
msg.msg.parameters[3] = resolution->dpi_x / dpirange->step - 1;
msg.msg.parameters[6] = 0x42; /* not sure if needed */
break;
case 3:
buf[0] = STEELSERIES_ID_DPI;
buf[2] = resolution->index + 1;
buf[3] = resolution->dpi_x / dpirange->step - 1;
buf[6] = 0x42; /* not sure if needed */
} else if (device_version == 3) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_DPI_PROTOCOL3;
msg.msg.parameters[2] = resolution->index + 1;
msg.msg.parameters[3] = resolution->dpi_x / dpirange->step - 1;
msg.msg.parameters[5] = 0x42; /* not sure if needed */
break;
default:
buf[0] = STEELSERIES_ID_DPI_PROTOCOL3;
buf[2] = resolution->index + 1;
buf[3] = resolution->dpi_x / dpirange->step - 1;
buf[5] = 0x42; /* not sure if needed */
} else {
return -ENOTSUP;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, buf_len);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
@@ -505,49 +440,26 @@ steelseries_write_report_rate(struct ratbag_profile *profile)
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
int ret;
size_t buf_len;
uint8_t reported_rate = 0;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
switch (device_version) {
case 1:
if (profile->hz >= 1000) {
profile->hz = 1000;
reported_rate = 0x01;
} else if (profile->hz >= 375) {
profile->hz = 500;
reported_rate = 0x02;
} else if (profile->hz <= 125) {
profile->hz = 125;
reported_rate = 0x04;
} else {
profile->hz = 250;
reported_rate = 0x03;
}
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
if (device_version == 1) {
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
msg.msg.parameters[0] = STEELSERIES_ID_REPORT_RATE_SHORT;
msg.msg.parameters[2] = reported_rate;
break;
case 2:
buf[0] = STEELSERIES_ID_REPORT_RATE_SHORT;
buf[2] = 1000 / profile->hz;
} else if (device_version == 2) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_REPORT_RATE;
msg.msg.parameters[2] = 1000 / profile->hz;
break;
case 3:
buf[0] = STEELSERIES_ID_REPORT_RATE;
buf[2] = 1000 / profile->hz;
} else if (device_version == 3) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_REPORT_RATE_PROTOCOL3;
msg.msg.parameters[2] = 1000 / profile->hz;
break;
default:
buf[0] = STEELSERIES_ID_REPORT_RATE_PROTOCOL3;
buf[2] = 1000 / profile->hz;
} else {
return -ENOTSUP;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, buf_len);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
@@ -565,17 +477,15 @@ steelseries_write_buttons(struct ratbag_profile *profile)
if (ratbag_device_data_steelseries_get_macro_length(device->data) == 0)
return 0;
const bool is_senseiraw = ratbag_device_data_steelseries_get_quirk(device->data) == STEELSERIES_QUIRK_SENSEIRAW;
const int button_size = is_senseiraw ? 3 : 5;
const int report_size = is_senseiraw ? STEELSERIES_REPORT_SIZE_SHORT : STEELSERIES_REPORT_LONG_SIZE;
const int max_modifiers = is_senseiraw ? 0 : 3;
int short_button = ratbag_device_data_steelseries_get_short_button(device->data);
int button_size = (short_button == 0) ? 5 : 3;
int report_size = (short_button == 0) ? STEELSERIES_REPORT_LONG_SIZE : STEELSERIES_REPORT_SIZE_SHORT;
int max_modifiers = (short_button == 0) ? 3 : 0;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
uint8_t buf[report_size];
memset(buf, 0, report_size);
msg.msg.parameters[0] = STEELSERIES_ID_BUTTONS;
buf[0] = STEELSERIES_ID_BUTTONS;
ratbag_profile_for_each_button(profile, button) {
struct ratbag_button_action *action = &button->action;
@@ -588,7 +498,7 @@ steelseries_write_buttons(struct ratbag_profile *profile)
switch (action->type) {
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
msg.msg.parameters[idx] = action->action.button;
buf[idx] = action->action.button;
break;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
@@ -605,48 +515,48 @@ steelseries_write_buttons(struct ratbag_profile *profile)
code = ratbag_hidraw_get_keyboard_usage_from_keycode(
device, key);
if (code) {
if (is_senseiraw) {
msg.msg.parameters[idx] = STEELSERIES_BUTTON_KEY;
if (short_button) {
buf[idx] = STEELSERIES_BUTTON_KEY;
} else {
msg.msg.parameters[idx] = STEELSERIES_BUTTON_KBD;
buf[idx] = STEELSERIES_BUTTON_KBD;
if (modifiers & MODIFIER_LEFTCTRL)
msg.msg.parameters[++idx] = 0xE0;
buf[++idx] = 0xE0;
if (modifiers & MODIFIER_LEFTSHIFT)
msg.msg.parameters[++idx] = 0xE1;
buf[++idx] = 0xE1;
if (modifiers & MODIFIER_LEFTALT)
msg.msg.parameters[++idx] = 0xE2;
buf[++idx] = 0xE2;
if (modifiers & MODIFIER_LEFTMETA)
msg.msg.parameters[++idx] = 0xE3;
buf[++idx] = 0xE3;
if (modifiers & MODIFIER_RIGHTCTRL)
msg.msg.parameters[++idx] = 0xE4;
buf[++idx] = 0xE4;
if (modifiers & MODIFIER_RIGHTSHIFT)
msg.msg.parameters[++idx] = 0xE5;
buf[++idx] = 0xE5;
if (modifiers & MODIFIER_RIGHTALT)
msg.msg.parameters[++idx] = 0xE6;
buf[++idx] = 0xE6;
if (modifiers & MODIFIER_RIGHTMETA)
msg.msg.parameters[++idx] = 0xE7;
buf[++idx] = 0xE7;
}
msg.msg.parameters[idx + 1] = code;
buf[idx + 1] = code;
} else {
code = ratbag_hidraw_get_consumer_usage_from_keycode(
device, action->action.key.key);
msg.msg.parameters[idx] = STEELSERIES_BUTTON_CONSUMER;
msg.msg.parameters[idx + 1] = code;
buf[idx] = STEELSERIES_BUTTON_CONSUMER;
buf[idx + 1] = code;
}
break;
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
switch (action->action.special) {
case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP:
msg.msg.parameters[idx] = STEELSERIES_BUTTON_RES_CYCLE;
buf[idx] = STEELSERIES_BUTTON_RES_CYCLE;
break;
case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP:
msg.msg.parameters[idx] = STEELSERIES_BUTTON_WHEEL_UP;
buf[idx] = STEELSERIES_BUTTON_WHEEL_UP;
break;
case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN:
msg.msg.parameters[idx] = STEELSERIES_BUTTON_WHEEL_DOWN;
buf[idx] = STEELSERIES_BUTTON_WHEEL_DOWN;
break;
default:
break;
@@ -656,7 +566,7 @@ steelseries_write_buttons(struct ratbag_profile *profile)
case RATBAG_BUTTON_ACTION_TYPE_KEY:
case RATBAG_BUTTON_ACTION_TYPE_NONE:
default:
msg.msg.parameters[idx] = STEELSERIES_BUTTON_OFF;
buf[idx] = STEELSERIES_BUTTON_OFF;
break;
}
}
@@ -664,10 +574,9 @@ steelseries_write_buttons(struct ratbag_profile *profile)
msleep(10);
if (device_version == 3)
ret = ratbag_hidraw_raw_request(device, STEELSERIES_ID_BUTTONS,
msg.msg.parameters, report_size - 1,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
buf,sizeof(buf),HID_FEATURE_REPORT,HID_REQ_SET_REPORT);
else
ret = ratbag_hidraw_output_report(device, msg.data, report_size);
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
if (ret < 0)
return ret;
@@ -679,34 +588,19 @@ static int
steelseries_write_led_v1(struct ratbag_led *led)
{
struct ratbag_device *device = led->profile->device;
const enum steelseries_quirk quirk = ratbag_device_data_steelseries_get_quirk(device->data);
uint8_t buf[STEELSERIES_REPORT_SIZE_SHORT] = {0};
int ret;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
msg.msg.parameters[0] = STEELSERIES_ID_LED_EFFECT_SHORT;
msg.msg.parameters[1] = quirk == STEELSERIES_QUIRK_RIVAL100 ? 0x00 : led->index + 1;
buf[0] = STEELSERIES_ID_LED_EFFECT_SHORT;
buf[1] = led->index + 1;
switch(led->mode) {
case RATBAG_LED_OFF:
case RATBAG_LED_ON:
msg.msg.parameters[2] = 0x01;
buf[2] = 0x01;
break;
case RATBAG_LED_BREATHING:
/* 0x2/3/4 - speed (by eye it's 3, 5 and 7 seconds) */
if (led->ms <= 3000) {
led->ms = 3000;
msg.msg.parameters[2] = 0x04;
} else if (led->ms <= 5000) {
led->ms = 5000;
msg.msg.parameters[2] = 0x03;
} else {
led->ms = 7000;
msg.msg.parameters[2] = 0x02;
}
buf[2] = 0x03; /* 0x02: slow, 0x03: medium, 0x04: fast */
break;
case RATBAG_LED_CYCLE:
/* Cycle mode is not supported on this version */
@@ -715,36 +609,31 @@ steelseries_write_led_v1(struct ratbag_led *led)
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, STEELSERIES_REPORT_SIZE_SHORT);
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
if (ret < 0)
return ret;
memset(msg.data, 0, STEELSERIES_REPORT_SIZE); // reset the msg buffer before reusing
int mono_led = ratbag_device_data_steelseries_get_mono_led(device->data);
if (quirk == STEELSERIES_QUIRK_SENSEIRAW) {
msg.msg.parameters[0] = STEELSERIES_ID_LED_INTENSITY_SHORT;
msg.msg.parameters[1] = led->index + 1;
if (mono_led) {
buf[0] = STEELSERIES_ID_LED_INTENSITY_SHORT;
buf[1] = led->index + 1;
if (led->mode == RATBAG_LED_OFF || led->brightness == 0) {
msg.msg.parameters[2] = 1;
buf[2] = 1;
} else {
//split the brightness into roughly 3 equal intensities
msg.msg.parameters[2] = (led->brightness / 86) + 2;
buf[2] = (led->brightness / 86) + 2;
}
} else {
if (quirk != STEELSERIES_QUIRK_RIVAL100) {
msg.msg.parameters[0] = STEELSERIES_ID_LED_COLOR_SHORT;
msg.msg.parameters[1] = led->index + 1;
} else {
msg.msg.parameters[0] = STEELSERIES_ID_LED_COLOR_SHORT_RIVAL100;
msg.msg.parameters[1] = 0x00;
}
msg.msg.parameters[2] = led->color.red;
msg.msg.parameters[3] = led->color.green;
msg.msg.parameters[4] = led->color.blue;
buf[0] = STEELSERIES_ID_LED_COLOR_SHORT;
buf[1] = led->index + 1;
buf[2] = led->color.red;
buf[3] = led->color.green;
buf[4] = led->color.blue;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, msg.data, STEELSERIES_REPORT_SIZE_SHORT);
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
if (ret < 0)
return ret;
@@ -820,14 +709,10 @@ steelseries_write_led_cycle(struct ratbag_led *led,
struct steelseries_led_cycle_spec *cycle_spec)
{
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;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
struct steelseries_led_cycle cycle;
struct steelseries_point point[4];
@@ -896,15 +781,14 @@ steelseries_write_led_cycle(struct ratbag_led *led,
return -EINVAL;
}
construct_cycle_buffer(&cycle, cycle_spec, msg.msg.parameters, sizeof(msg.msg.parameters));
construct_cycle_buffer(&cycle, cycle_spec, buf, sizeof(buf));
msleep(10);
if (device_version == 3)
ret = ratbag_hidraw_raw_request(device, cycle_spec->cmd_val, msg.msg.parameters,
sizeof(msg.msg.parameters), cycle_spec->hid_report_type,
HID_REQ_SET_REPORT);
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, msg.data, sizeof(msg.data));
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
if (ret < 0)
return ret;
@@ -971,27 +855,23 @@ steelseries_write_save(struct ratbag_device *device)
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
int ret;
size_t buf_len;
union steelseries_message msg = {
.msg.report_id = STEELSERIES_REPORT_ID,
.msg.parameters = {0},
};
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
if (device_version == 1) {
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
msg.msg.parameters[0] = STEELSERIES_ID_SAVE_SHORT;
buf[0] = STEELSERIES_ID_SAVE_SHORT;
} else if (device_version == 2) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_SAVE;
buf[0] = STEELSERIES_ID_SAVE;
} else if (device_version == 3) {
buf_len = STEELSERIES_REPORT_SIZE;
msg.msg.parameters[0] = STEELSERIES_ID_SAVE_PROTOCOL3;
buf[0] = STEELSERIES_ID_SAVE_PROTOCOL3;
} else {
return -ENOTSUP;
}
msleep(20);
ret = ratbag_hidraw_output_report(device, msg.data, buf_len);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
@@ -1007,11 +887,9 @@ steelseries_write_profile(struct ratbag_profile *profile)
int rc;
bool buttons_dirty = false;
if (profile->rate_dirty) {
rc = steelseries_write_report_rate(profile);
if (rc != 0)
return rc;
}
rc = steelseries_write_report_rate(profile);
if (rc != 0)
return rc;
ratbag_profile_for_each_resolution(profile, resolution) {
if (!resolution->dirty)

View File

@@ -1,7 +0,0 @@
#pragma once
enum steelseries_quirk {
STEELSERIES_QURIK_NONE,
STEELSERIES_QUIRK_RIVAL100,
STEELSERIES_QUIRK_SENSEIRAW,
};

View File

@@ -29,6 +29,14 @@
#include "libratbag-private.h"
#include "libratbag-test.h"
static int
test_write_profile(struct ratbag_profile *profile)
{
/* check if the device is still valid */
assert(ratbag_get_drv_data(profile->device) != NULL);
return 0;
}
static int
test_set_active_profile(struct ratbag_device *device, unsigned int index)
{
@@ -128,6 +136,26 @@ test_read_led(struct ratbag_led *led)
led->type = d->profiles[0].leds[led->index].type;
}
static int
test_write_button(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
/* check if the device is still valid */
assert(ratbag_get_drv_data(button->profile->device) != NULL);
return 0;
}
static int
test_write_led(struct ratbag_led *led,
enum ratbag_led_mode mode,
struct ratbag_color color, unsigned int ms,
unsigned int brightness)
{
/* check if the device is still valid */
assert(ratbag_get_drv_data(led->profile->device) != NULL);
return 0;
}
static int
test_fake_probe(struct ratbag_device *device)
{
@@ -257,21 +285,15 @@ test_remove(struct ratbag_device *device)
free(d);
}
static int
test_commit(struct ratbag_device *device)
{
/* check if the device is still valid */
assert(ratbag_get_drv_data(device) != NULL);
return 0;
}
struct ratbag_driver test_driver = {
.name = "Test driver",
.id = "test_driver",
.probe = test_fake_probe,
.test_probe = test_probe,
.remove = test_remove,
.commit = test_commit,
.write_profile = test_write_profile,
.set_active_profile = test_set_active_profile,
.write_button = test_write_button,
.write_resolution_dpi = NULL,
.write_led = test_write_led,
};

View File

@@ -58,7 +58,6 @@ hidpp20_feature_get_name(uint16_t feature)
CASE_RETURN_STRING(HIDPP_PAGE_RESET);
CASE_RETURN_STRING(HIDPP_PAGE_BATTERY_LEVEL_STATUS);
CASE_RETURN_STRING(HIDPP_PAGE_BATTERY_VOLTAGE);
CASE_RETURN_STRING(HIDPP_PAGE_LED_SW_CONTROL);
CASE_RETURN_STRING(HIDPP_PAGE_KBD_REPROGRAMMABLE_KEYS);
CASE_RETURN_STRING(HIDPP_PAGE_SPECIAL_KEYS_BUTTONS);
CASE_RETURN_STRING(HIDPP_PAGE_WIRELESS_DEVICE_STATUS);
@@ -2083,7 +2082,7 @@ hidpp20_onboard_profiles_set_onboard_mode(struct hidpp20_device *device,
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_SET_ONBOARD_MODE,
.msg.parameters[0] = onboard_mode,
.msg.parameters[1] = onboard_mode,
};
feature_index = hidpp_root_get_feature_idx(device,
@@ -2103,7 +2102,7 @@ hidpp20_onboard_profiles_set_onboard_mode(struct hidpp20_device *device,
int
hidpp20_onboard_profiles_get_current_profile(struct hidpp20_device *device)
{
uint8_t feature_index, unknown_0, active_profile_index;
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
@@ -2122,15 +2121,7 @@ hidpp20_onboard_profiles_get_current_profile(struct hidpp20_device *device)
if (rc)
return rc;
unknown_0 = msg.msg.parameters[0];
active_profile_index = msg.msg.parameters[1];
hidpp_log_raw(
&device->base,
"current active profile is index: %d unknown_0: %d\n",
active_profile_index, unknown_0);
return active_profile_index;
return msg.msg.parameters[1];
}
int
@@ -2252,7 +2243,8 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
{
struct hidpp20_onboard_profiles_info info = { 0 };
struct hidpp20_profiles *profiles;
int onboard_mode, active_profile_index, rc;
int onboard_mode;
int rc;
rc = hidpp20_onboard_profiles_get_profiles_desc(device, &info);
if (rc)
@@ -2276,12 +2268,6 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
return rc;
}
rc = hidpp20_onboard_profiles_get_current_profile(device);
if (rc < 0)
return rc;
active_profile_index = rc;
profiles = zalloc(sizeof(struct hidpp20_profiles));
profiles->profiles = zalloc(info.profile_count * sizeof(struct hidpp20_profile));
profiles->sector_size = info.sector_size;
@@ -2293,7 +2279,6 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
profiles->num_leds = HIDPP20_LED_COUNT;
profiles->has_g_shift = (info.mechanical_layout & 0x03) == 0x02;
profiles->has_dpi_shift = ((info.mechanical_layout & 0x0c) >> 2) == 0x02;
profiles->active_profile_index = active_profile_index;
switch(info.various_info & 0x07) {
case 1:
profiles->corded = 1;

View File

@@ -210,21 +210,21 @@ struct hidpp20_led_sw_ctrl_led_state {
uint8_t index;
uint16_t mode;
union {
struct hidpp20_led_breathing {
struct {
uint16_t brightness;
uint16_t period;
uint16_t timeout;
} breathing;
struct hidpp20_led_traveling {
struct {
uint16_t unused;
uint16_t delay;
} traveling;
struct hidpp20_led_blink {
struct {
uint16_t index;
uint16_t on_time;
uint16_t off_time;
} blink;
struct hidpp20_led_on {
struct {
/* Logical information to display on the LED
* Meaning and value range depend on the LED
*/
@@ -915,7 +915,6 @@ struct hidpp20_profiles {
uint8_t wireless;
uint8_t sector_count;
uint16_t sector_size;
uint8_t active_profile_index;
struct hidpp20_profile *profiles;
};

View File

@@ -30,15 +30,10 @@
#include <glib.h>
#include <limits.h>
#include "asus.h"
#include "driver-sinowealth.h"
#include "driver-steelseries.h"
#include "libratbag.h"
#include "libratbag-private.h"
#include "libratbag-data.h"
#include "hidpp20.h"
#include "shared-macro.h"
#include "usb-ids.h"
#define GROUP_DEVICE "Device"
@@ -51,25 +46,19 @@ enum driver {
HIDPP10,
HIDPP20,
ROCCAT,
ROCCAT_KONE_PURE,
ROCCAT_EMP,
ETEKCITY,
GSKILL,
LOGITECH_G300,
LOGITECH_G600,
STEELSERIES,
ASUS,
SINOWEALTH,
SINOWEALTH_NUBWO,
OPENINPUT,
};
struct data_hidpp20 {
int index;
enum hidpp20_quirk quirk;
int led_count;
int report_rate;
int button_count;
};
struct data_hidpp10 {
@@ -82,10 +71,6 @@ struct data_hidpp10 {
int led_count;
};
struct data_sinowealth {
struct list supported_devices;
};
struct data_steelseries {
int device_version;
int button_count;
@@ -93,18 +78,15 @@ struct data_steelseries {
struct dpi_list *dpi_list;
struct dpi_range *dpi_range;
int macro_length;
enum steelseries_quirk quirk;
int mono_led;
int short_button;
};
struct data_asus {
int profile_count;
struct data_sinowealth {
int button_count;
int8_t button_mapping[ASUS_MAX_NUM_BUTTON];
int led_count;
int dpi_count;
int is_wireless;
char *led_type;
struct dpi_range *dpi_range;
uint32_t quirks;
};
struct ratbag_device_data {
@@ -117,9 +99,8 @@ struct ratbag_device_data {
union {
struct data_hidpp20 hidpp20;
struct data_hidpp10 hidpp10;
struct data_sinowealth sinowealth;
struct data_steelseries steelseries;
struct data_asus asus;
struct data_sinowealth sinowealth;
};
enum ratbag_led_type led_types[20];
@@ -186,18 +167,9 @@ init_data_hidpp20(struct ratbag *ratbag,
int num;
char *str;
data->hidpp20.button_count = -1;
data->hidpp20.index = -1;
data->hidpp20.led_count = -1;
data->hidpp20.report_rate = -1;
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (num > 0 || !error)
data->hidpp20.button_count = num;
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error);
if (num != 0 || !error)
data->hidpp20.index = num;
@@ -211,13 +183,6 @@ init_data_hidpp20(struct ratbag *ratbag,
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "ReportRate", &error);
if (num > 0 || !error)
data->hidpp20.report_rate = 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) {
@@ -228,56 +193,6 @@ init_data_hidpp20(struct ratbag *ratbag,
}
}
static void
init_data_sinowealth(struct ratbag *ratbag,
GKeyFile *keyfile,
struct ratbag_device_data *data)
{
const char *devices_group = "Driver/sinowealth/devices/";
GError *error = NULL;
size_t group_count = 0;
_cleanup_(g_strfreevp) char **groups = g_key_file_get_groups(keyfile, &group_count);
list_init(&data->sinowealth.supported_devices);
for (size_t i = 0; i < group_count; ++i) {
const char *device_group = groups[i];
if (startswith(device_group, devices_group) == NULL)
continue;
struct sinowealth_device_data *device = zalloc(sizeof(struct sinowealth_device_data));
device->button_count = g_key_file_get_integer(keyfile, device_group, "ButtonCount", &error);
g_clear_error(&error);
device->device_name = g_key_file_get_string(keyfile, device_group, "DeviceName", &error);
g_clear_error(&error);
device->fw_version = g_key_file_get_string(keyfile, device_group, "FwVersion", &error);
g_clear_error(&error);
_cleanup_free_ char *led_type_str = g_key_file_get_string(keyfile, device_group, "LedType", &error);
if (led_type_str) {
if (streq(led_type_str, "RGB")) {
device->led_type = SINOWEALTH_LED_TYPE_RGB;
} else if (streq(led_type_str, "RBG")) {
device->led_type = SINOWEALTH_LED_TYPE_RBG;
} else if (streq(led_type_str, "None")) {
device->led_type = SINOWEALTH_LED_TYPE_NONE;
} else {
log_error(ratbag, "Unknown LED type '%s' in group '%s'\n", led_type_str, device_group);
device->led_type = SINOWEALTH_LED_TYPE_NONE;
}
}
g_clear_error(&error);
list_insert(&data->sinowealth.supported_devices, &device->link);
}
}
static void
init_data_steelseries(struct ratbag *ratbag,
GKeyFile *keyfile,
@@ -285,8 +200,7 @@ init_data_steelseries(struct ratbag *ratbag,
{
const char *group = "Driver/steelseries";
GError *error = NULL;
_cleanup_(freep) char *dpi_range = NULL;
_cleanup_(freep) char *quirk = NULL;
_cleanup_(freep) char *str = NULL;
int num;
data->steelseries.device_version = -1;
@@ -294,7 +208,8 @@ init_data_steelseries(struct ratbag *ratbag,
data->steelseries.led_count = -1;
data->steelseries.dpi_list = NULL;
data->steelseries.dpi_range = NULL;
data->steelseries.quirk = STEELSERIES_QURIK_NONE;
data->steelseries.mono_led = 0;
data->steelseries.short_button = 0;
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (num != 0 || !error)
@@ -316,13 +231,13 @@ init_data_steelseries(struct ratbag *ratbag,
if (error)
g_error_free(error);
dpi_range = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
if (dpi_range) {
data->steelseries.dpi_range = dpi_range_from_string(dpi_range);
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
if (str) {
data->steelseries.dpi_range = dpi_range_from_string(str);
} else {
dpi_range = g_key_file_get_string(keyfile, group, "DpiList", NULL);
if (dpi_range)
data->steelseries.dpi_list = dpi_list_from_string(dpi_range);
str = g_key_file_get_string(keyfile, group, "DpiList", NULL);
if (str)
data->steelseries.dpi_list = dpi_list_from_string(str);
}
error = NULL;
@@ -332,86 +247,63 @@ init_data_steelseries(struct ratbag *ratbag,
if (error)
g_error_free(error);
quirk = g_key_file_get_string(keyfile, group, "Quirk", NULL);
if (quirk) {
if (streq(quirk, "Rival100"))
data->steelseries.quirk = STEELSERIES_QUIRK_RIVAL100;
if (streq(quirk, "SenseiRAW"))
data->steelseries.quirk = STEELSERIES_QUIRK_SENSEIRAW;
}
error = NULL;
num = g_key_file_get_integer(keyfile, group, "MonoLed", &error);
if (num > 0 || !error)
data->steelseries.mono_led = num;
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "ShortButton", &error);
if (num > 0 || !error)
data->steelseries.short_button = num;
if (error)
g_error_free(error);
}
static void
init_data_asus(struct ratbag *ratbag,
GKeyFile *keyfile,
struct ratbag_device_data *data)
init_data_sinowealth(struct ratbag *ratbag,
GKeyFile *keyfile,
struct ratbag_device_data *data)
{
const char *group = "Driver/asus";
const char *group = "Driver/sinowealth";
GError *error = NULL;
_cleanup_(freep) char *str = NULL;
int num;
char *led_type;
data->asus.profile_count = -1;
data->asus.button_count = -1;
data->asus.led_count = -1;
data->asus.dpi_count = -1;
data->asus.dpi_range = NULL;
data->asus.is_wireless = -1;
data->asus.quirks = 0;
for (unsigned int i = 0; i < ASUS_MAX_NUM_BUTTON; i++)
data->asus.button_mapping[i] = -1;
data->sinowealth.button_count = -1;
data->sinowealth.led_count = -1;
int profiles = g_key_file_get_integer(keyfile, group, "Profiles", &error);
if (!error && profiles >= 0)
data->asus.profile_count = profiles;
g_clear_error(&error);
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (num != 0 || !error)
data->sinowealth.button_count = num;
if (error)
g_error_free(error);
int buttons = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (!error && buttons >= 0 && buttons <= ASUS_MAX_NUM_BUTTON)
data->asus.button_count = buttons;
g_clear_error(&error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
if (num > 0 || !error)
data->sinowealth.led_count = num;
if (error)
g_error_free(error);
gsize button_mapping_count = 0;
_cleanup_(g_strfreevp) char **button_mapping = g_key_file_get_string_list(keyfile, group, "ButtonMapping", &button_mapping_count, &error);
if (!error && button_mapping) {
for (unsigned int i = 0; i < button_mapping_count; i++) {
data->asus.button_mapping[i] = (int8_t) strtoul(button_mapping[i], NULL, 10);
}
}
g_clear_error(&error);
error = NULL;
int leds = g_key_file_get_integer(keyfile, group, "Leds", &error);
if (!error && leds >= 0 && leds <= ASUS_MAX_NUM_LED)
data->asus.led_count = leds;
g_clear_error(&error);
led_type = g_key_file_get_string(keyfile, group, "LedType", NULL);
if (led_type)
data->sinowealth.led_type = led_type;
if (error)
g_error_free(error);
int dpis = g_key_file_get_integer(keyfile, group, "Dpis", &error);
if (!error && dpis >= 2 && dpis <= ASUS_MAX_NUM_DPI)
data->asus.dpi_count = dpis;
g_clear_error(&error);
error = NULL;
_cleanup_(freep) char *dpi_range = g_key_file_get_string(keyfile, group, "DpiRange", &error);
if (!error && dpi_range)
data->asus.dpi_range = dpi_range_from_string(dpi_range);
g_clear_error(&error);
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
if (str)
data->sinowealth.dpi_range = dpi_range_from_string(str);
error = NULL;
int wireless = g_key_file_get_integer(keyfile, group, "Wireless", &error);
if (!error && (wireless == 0 || wireless == 1))
data->asus.is_wireless = wireless;
g_clear_error(&error);
gsize quirks_count = 0;
_cleanup_(g_strfreevp) char **quirks = g_key_file_get_string_list(keyfile, group, "Quirks", &quirks_count, &error);
if (!error && quirks) {
for (unsigned int i = 0; i < quirks_count; i++) {
if (streq(quirks[i], "DOUBLE_DPI")) {
data->asus.quirks |= ASUS_QUIRK_DOUBLE_DPI;
} else if (streq(quirks[i], "STRIX_PROFILE")) {
data->asus.quirks |= ASUS_QUIRK_STRIX_PROFILE;
} else {
log_debug(ratbag, "%s is invalid quirk. Ignoring...\n", quirks[i]);
}
}
}
g_clear_error(&error);
}
static const struct driver_map {
@@ -424,17 +316,13 @@ static const struct driver_map {
{ HIDPP10, "hidpp10", init_data_hidpp10 },
{ HIDPP20, "hidpp20", init_data_hidpp20 },
{ ROCCAT, "roccat", NULL },
{ ROCCAT_KONE_PURE, "roccat-kone-pure", NULL },
{ ROCCAT_EMP, "roccat-kone-emp", NULL },
{ ETEKCITY, "etekcity", NULL},
{ GSKILL, "gskill", NULL },
{ LOGITECH_G300, "logitech_g300", NULL},
{ LOGITECH_G600, "logitech_g600", NULL},
{ STEELSERIES, "steelseries", init_data_steelseries },
{ ASUS, "asus", init_data_asus },
{ SINOWEALTH, "sinowealth", init_data_sinowealth },
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
{ OPENINPUT, "openinput", NULL },
};
const char *
@@ -470,34 +358,8 @@ ratbag_device_data_destroy(struct ratbag_device_data *data)
{
switch (data->drivertype) {
case HIDPP10:
if (data->hidpp10.dpi_list) {
free(data->hidpp10.dpi_list->entries);
free(data->hidpp10.dpi_list);
}
free(data->hidpp10.dpi_range);
free(data->hidpp10.profile_type);
break;
case SINOWEALTH: {
struct sinowealth_device_data *device_data = NULL;
struct sinowealth_device_data *device_data_next = NULL;
list_for_each_safe(device_data, device_data_next, &data->sinowealth.supported_devices, link) {
free(device_data->device_name);
free(device_data->fw_version);
free(device_data);
}
break;
}
case STEELSERIES:
if (data->steelseries.dpi_list) {
free(data->steelseries.dpi_list->entries);
free(data->steelseries.dpi_list);
}
free(data->steelseries.dpi_range);
break;
default:
break;
}
@@ -707,9 +569,7 @@ ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
goto out;
}
if (id->vendor == USB_VENDOR_ID_LOGITECH && (id->product & 0xff00) == 0xc500)
log_debug(ratbag, "%04x:%04x is a Logitech receiver, not a device. Ignoring...\n", id->vendor, id->product);
else if (!data)
if (!data)
log_debug(ratbag, "No data file found for %04x:%04x\n", id->vendor, id->product);
out:
@@ -781,14 +641,6 @@ ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data)
return data->hidpp20.index;
}
int
ratbag_device_data_hidpp20_get_button_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == HIDPP20);
return data->hidpp20.button_count;
}
int
ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data)
{
@@ -797,14 +649,6 @@ ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data)
return data->hidpp20.led_count;
}
int
ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data)
{
assert(data->drivertype == HIDPP20);
return data->hidpp20.report_rate;
}
enum hidpp20_quirk
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data)
{
@@ -813,16 +657,6 @@ ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data)
return data->hidpp20.quirk;
}
/* SinoWealth */
const struct list *
ratbag_device_data_sinowealth_get_supported_devices(const struct ratbag_device_data *data)
{
assert(data->drivertype == SINOWEALTH);
return &data->sinowealth.supported_devices;
}
/* SteelSeries */
int
@@ -873,68 +707,50 @@ ratbag_device_data_steelseries_get_macro_length(const struct ratbag_device_data
return data->steelseries.macro_length;
}
enum steelseries_quirk
ratbag_device_data_steelseries_get_quirk(const struct ratbag_device_data *data)
int
ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *data)
{
assert(data->drivertype == STEELSERIES);
return data->steelseries.quirk;
}
/* ASUS */
int
ratbag_device_data_asus_get_profile_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.profile_count;
return data->steelseries.mono_led;
}
int
ratbag_device_data_asus_get_button_count(const struct ratbag_device_data *data)
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.button_count;
}
assert(data->drivertype == STEELSERIES);
const int8_t *
ratbag_device_data_asus_get_button_mapping(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.button_mapping;
return data->steelseries.short_button;
}
int
ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data)
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.led_count;
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.button_count;
}
int
ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data)
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.dpi_count;
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.led_count;
}
struct dpi_range *
ratbag_device_data_asus_get_dpi_range(const struct ratbag_device_data *data)
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.dpi_range;
assert(data->drivertype == SINOWEALTH);
return data->sinowealth.dpi_range;
}
int
ratbag_device_data_asus_is_wireless(const struct ratbag_device_data *data)
const char *
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.is_wireless;
}
assert(data->drivertype == SINOWEALTH);
uint32_t
ratbag_device_data_asus_get_quirks(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.quirks;
return data->sinowealth.led_type;
}

View File

@@ -23,8 +23,6 @@
#pragma once
#include "libratbag-private.h"
struct ratbag_device_data;
struct ratbag_device_data *
@@ -82,28 +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_button_count(const struct ratbag_device_data *data);
int
ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data);
int
ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data);
enum hidpp20_quirk
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data);
/* SinoWealth */
/*
* NOTE: Don't forget to check for NULL in fields of each device data entry.
*
* @return List of data for supported devices.
*/
const struct list *
ratbag_device_data_sinowealth_get_supported_devices(const struct ratbag_device_data *data);
/* SteelSeries */
/**
@@ -133,58 +115,27 @@ ratbag_device_data_steelseries_get_dpi_range(const struct ratbag_device_data *da
int
ratbag_device_data_steelseries_get_macro_length(const struct ratbag_device_data *data);
/**
* @return Quirk
*/
enum steelseries_quirk
ratbag_device_data_steelseries_get_quirk(const struct ratbag_device_data *data);
int
ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *data);
/* ASUS */
int
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data);
/**
* @return Number of profiles
* @return The button count or -1 if not set
*/
int
ratbag_device_data_asus_get_profile_count(const struct ratbag_device_data *data);
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data);
/**
* @return Number of buttons
* @return The led count or -1 if not set
*/
int
ratbag_device_data_asus_get_button_count(const struct ratbag_device_data *data);
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data);
/**
* @return Array of button indices, which are used for reading and writing button actions
*/
const int8_t *
ratbag_device_data_asus_get_button_mapping(const struct ratbag_device_data *data);
/**
* @return Number of LEDs
*/
int
ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data);
/**
* @return Number of DPI presets
*/
int
ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data);
/**
* @return NULL if not set
*/
struct dpi_range *
ratbag_device_data_asus_get_dpi_range(const struct ratbag_device_data *data);
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data);
/**
* @return 1 if wireless, 0 otherwise
*/
int
ratbag_device_data_asus_is_wireless(const struct ratbag_device_data *data);
const char *
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data);
/**
* @return Quirks bitmask
*/
uint32_t
ratbag_device_data_asus_get_quirks(const struct ratbag_device_data *data);

View File

@@ -1520,21 +1520,6 @@ ratbag_hidraw_get_usage(struct ratbag_device *device, unsigned int report_id)
return report->usage;
}
unsigned int
ratbag_hidraw_has_vendor_page(struct ratbag_device *device)
{
unsigned i;
if (ratbag_hidraw_get_usage_page(device, 0) >= 0xff00)
return 1;
for (i = 0; i < device->hidraw[0].num_reports; i++) {
if (ratbag_hidraw_get_usage_page(device, device->hidraw[0].reports[i].report_id) >= 0xff00)
return 1;
}
return 0;
}
void
ratbag_close_hidraw(struct ratbag_device *device)
{
@@ -1642,19 +1627,16 @@ ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t l
}
int
ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len,
ratbagd_hidraw_filter_t filter)
ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len)
{
return ratbag_hidraw_read_input_report_index(device, buf, len, 0, filter);
return ratbag_hidraw_read_input_report_index(device, buf, len, 0);
}
int
ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno,
ratbagd_hidraw_filter_t filter)
ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno)
{
int rc, nfds;
int rc;
struct pollfd fds;
int ts, ts_end;
assert(hidrawno >= 0 && hidrawno < MAX_HIDRAW);
@@ -1664,32 +1646,17 @@ ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf
fds.fd = device->hidraw[hidrawno].fd;
fds.events = POLLIN;
/* convert to ms */
ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
ts_end = ts + 1000; /* end in now + 1000ms */
rc = poll(&fds, 1, 1000);
if (rc == -1)
return -errno;
while (ts < ts_end) {
nfds = poll(&fds, 1, ts_end - ts); /* poll for the remainder of timeout */
if (rc == 0)
return -ETIMEDOUT;
if (nfds < 0)
return -errno;
rc = read(device->hidraw[hidrawno].fd, buf, len);
if (nfds > 0) {
rc = read(device->hidraw[hidrawno].fd, buf, len);
if (rc > 0)
log_buf_raw(device->ratbag, "input report: ", buf, rc);
if (rc < 0)
return -errno;
if (rc > 0) {
if(!filter || (filter && filter(buf, rc))) {
log_buf_raw(device->ratbag, "input report: ", buf, rc);
return rc;
}
}
}
ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
}
return -ETIMEDOUT;
return rc >= 0 ? rc : -errno;
}

View File

@@ -47,8 +47,6 @@ struct ratbag_hidraw {
char *sysname;
};
typedef bool (*ratbagd_hidraw_filter_t)(uint8_t *buf, size_t len);
/**
* Open the hidraw device associated with the device.
*
@@ -164,32 +162,27 @@ int ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size
/**
* Read an input report from the device
* Optional filter function can be provided, when the filter returns false the packet is ignored
*
* @param device the ratbag device
* @param[out] buf resulting raw data
* @param len length of buf
* @param filter filter function
*
* @return count of data transfered, or a negative errno on error
*/
int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len,
ratbagd_hidraw_filter_t filter);
int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len);
/**
* Read an input report from the device from a specific hidraw index
* Optional filter function can be provided, when the filter returns false the packet is ignored
*
* @param device the ratbag device
* @param[out] buf resulting raw data
* @param len length of buf
* @param hidrawno index of hidraw array
* @param filter filter function
* @param interal index of hidraw array
*
* @return count of data transfered, or a negative errno on error
*/
int ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno,
ratbagd_hidraw_filter_t filter);
int ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno);
/**
* Tells if a given device has the specified report ID.
@@ -226,16 +219,6 @@ ratbag_hidraw_get_usage_page(struct ratbag_device *device, unsigned int report_i
unsigned int
ratbag_hidraw_get_usage(struct ratbag_device *device, unsigned int report_id);
/**
* Tells if a given device has a vendor usage page
*
* @param device the ratbag device which hidraw node is opened
*
* @return 1 if the device has a vendor usage page, 0 otherwise
*/
unsigned int
ratbag_hidraw_has_vendor_page(struct ratbag_device *device);
/**
* Gives the input key code associated to the keyboard HID usage.
*

View File

@@ -197,6 +197,13 @@ struct ratbag_driver {
*/
int (*commit)(struct ratbag_device *device);
/*
* FIXME: This function is deprecated and should be removed. Once
* we've updated all the device drivers to stop using it we'll remove
* it. Look at commit() instead.
*/
int (*write_profile)(struct ratbag_profile *profile);
/**
* Called to mark a previously writen profile as active.
*
@@ -205,6 +212,31 @@ struct ratbag_driver {
*/
int (*set_active_profile)(struct ratbag_device *device, unsigned int index);
/*
* FIXME: This function is deprecated and should be removed. Once
* we've updated all the device drivers to stop using it we'll remove
* it. Look at commit() instead.
*/
int (*write_button)(struct ratbag_button *button,
const struct ratbag_button_action *action);
/*
* FIXME: This function is deprecated and should be removed. Once
* we've updated all the device drivers to stop using it we'll remove
* it. Look at commit() instead.
*/
int (*write_resolution_dpi)(struct ratbag_resolution *resolution,
int dpi_x, int dpi_y);
/*
* FIXME: This function is deprecated and should be removed. Once
* we've updated all the device drivers to stop using it we'll remove
* it. Look at commit() instead.
*/
int (*write_led)(struct ratbag_led *led, enum ratbag_led_mode mode,
struct ratbag_color color, unsigned int ms,
unsigned int brightness);
/* private */
int (*test_probe)(struct ratbag_device *device, const void *data);
@@ -430,8 +462,6 @@ ratbag_button_action_match(const struct ratbag_button_action *action,
return 0;
switch (action->type) {
case RATBAG_BUTTON_ACTION_TYPE_NONE:
return 1;
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
return match->action.button == action->action.button;
case RATBAG_BUTTON_ACTION_TYPE_KEY:
@@ -439,7 +469,6 @@ ratbag_button_action_match(const struct ratbag_button_action *action,
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
return match->action.special == action->action.special;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
/* TODO: check if events match. */
return 1;
default:
break;
@@ -564,14 +593,10 @@ 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 roccat_kone_pure_driver;
extern struct ratbag_driver roccat_emp_driver;
extern struct ratbag_driver gskill_driver;
extern struct ratbag_driver steelseries_driver;
extern struct ratbag_driver asus_driver;
extern struct ratbag_driver sinowealth_driver;
extern struct ratbag_driver sinowealth_nubwo_driver;
extern struct ratbag_driver openinput_driver;
struct ratbag_device*
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,

View File

@@ -282,6 +282,7 @@ dpi_list_from_string(const char *str)
if (!str || str[0] == '\0')
return NULL;
printf("%s: ", str);
/* first, count how many elements do we have in the table */
count = 1;

View File

@@ -600,14 +600,10 @@ ratbag_create_context(const struct ratbag_interface *interface,
ratbag_register_driver(ratbag, &logitech_g300_driver);
ratbag_register_driver(ratbag, &logitech_g600_driver);
ratbag_register_driver(ratbag, &roccat_driver);
ratbag_register_driver(ratbag, &roccat_kone_pure_driver);
ratbag_register_driver(ratbag, &roccat_emp_driver);
ratbag_register_driver(ratbag, &gskill_driver);
ratbag_register_driver(ratbag, &steelseries_driver);
ratbag_register_driver(ratbag, &asus_driver);
ratbag_register_driver(ratbag, &sinowealth_driver);
ratbag_register_driver(ratbag, &sinowealth_nubwo_driver);
ratbag_register_driver(ratbag, &openinput_driver);
return ratbag;
}
@@ -864,6 +860,75 @@ ratbag_device_get_num_leds(struct ratbag_device *device)
return device->num_leds;
}
static inline enum ratbag_error_code
write_led_helper(struct ratbag_device *device, struct ratbag_led *led)
{
return device->driver->write_led(led, led->mode, led->color, led->ms, led->brightness);
}
/* FIXME: This is a temporary fix for all of the drivers that have yet to be
* converted to the new profile-oriented API. Once all of the drivers have been
* converted, this code should be removed.
*/
static enum ratbag_error_code
ratbag_old_write_profile(struct ratbag_device *device)
{
struct ratbag_profile *profile;
struct ratbag_button *button;
struct ratbag_led *led;
struct ratbag_resolution *resolution;
int rc;
assert(device->driver->write_profile);
list_for_each(profile, &device->profiles, link) {
if (!profile->dirty)
continue;
rc = device->driver->write_profile(profile);
if (rc)
return RATBAG_ERROR_DEVICE;
if (device->driver->write_resolution_dpi) {
ratbag_profile_for_each_resolution(profile, resolution) {
rc = device->driver->write_resolution_dpi(
resolution, resolution->dpi_x,
resolution->dpi_y);
if (rc)
return RATBAG_ERROR_DEVICE;
}
}
if (device->driver->write_button) {
list_for_each(button, &profile->buttons, link) {
struct ratbag_button_action action =
button->action;
if (!button->dirty)
continue;
rc = device->driver->write_button(button,
&action);
if (rc)
return RATBAG_ERROR_DEVICE;
}
}
if (device->driver->write_led) {
list_for_each(led, &profile->leds, link) {
if (!led->dirty)
continue;
rc = write_led_helper(device, led);
if (rc)
return RATBAG_ERROR_DEVICE;
}
}
}
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_device_commit(struct ratbag_device *device)
{
@@ -873,9 +938,15 @@ ratbag_device_commit(struct ratbag_device *device)
struct ratbag_resolution *resolution;
int rc;
rc = device->driver->commit(device);
if (rc)
return RATBAG_ERROR_DEVICE;
if (!device->driver->commit) {
rc = ratbag_old_write_profile(device);
if (rc != RATBAG_SUCCESS)
return rc;
} else {
rc = device->driver->commit(device);
if (rc)
return RATBAG_ERROR_DEVICE;
}
list_for_each(profile, &device->profiles, link) {
profile->dirty = false;

View File

@@ -23,6 +23,7 @@
#include <config.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <hidpp10.h>
@@ -93,10 +94,8 @@ main(int argc, char **argv)
path = argv[argc - 1];
fd = open(path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Failed to open path '%s': %s", path, strerror(errno));
exit(3);
}
if (fd < 0)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
rc = hidpp10_device_new(&base, HIDPP_WIRED_DEVICE_IDX, HIDPP10_PROFILE_UNKNOWN, 5, &dev);

View File

@@ -23,6 +23,7 @@
#include <config.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <hidpp20.h>
@@ -110,17 +111,13 @@ main(int argc, char **argv)
path = argv[argc - 1];
fd = open(path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Failed to open path '%s': %s", path, strerror(errno));
exit(3);
}
if (fd < 0)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp20_device_new(&base, 0xff, NULL, 0);
if (!dev) {
fprintf(stderr, "Failed to open %s as a HID++ 2.0 device", path);
exit(3);
}
if (!dev)
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);
hidpp20_onboard_profiles_get_profiles_desc(dev, &info);

View File

@@ -23,6 +23,7 @@
#include <config.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <hidpp20.h>
@@ -86,17 +87,13 @@ main(int argc, char **argv)
path = argv[argc - 1];
fd = open(path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Failed to open path '%s': %s", path, strerror(errno));
exit(3);
}
if (fd < 0)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp20_device_new(&base, 0xff, NULL, 0);
if (!dev) {
fprintf(stderr, "Failed to open %s as a HID++ 2.0 device", path);
exit(3);
}
if (!dev)
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);
hidpp20_onboard_profiles_get_profiles_desc(dev, &info);

View File

@@ -808,10 +808,7 @@ class RatbagdLed(metaclass=MetaRatbag):
@param color An RGB color, as an integer triplet with values 0-255.
"""
# libratbag.ratbag_led_set_color(self._led, libratbag.ratbag_color(*color))
rc = libratbag.ratbag_color()
rc.red, rc.green, rc.blue = color
libratbag.ratbag_led_set_color(self._led, rc)
libratbag.ratbag_led_set_color(self._led, libratbag.ratbag_color(*color))
@property
def colordepth(self):

View File

@@ -2,13 +2,7 @@
.SH NAME
ratbagctl \- inspect and modify configurable mice
.SH SYNOPSIS
.B ratbagctl
.RI [< options >]
.B list
.br
.B ratbagctl
.RI [< options >]
.RI < device "> <" command "> ..."
.B ratbagctl [OPTIONS] {COMMAND} ... device
.SH DESCRIPTION
.PP
The
@@ -27,8 +21,8 @@ Print debugging output. Multiple -v options increase the verbosity. For example,
will show the protocol output.
.TP 8
.B \-\-nocommit
Do not immediately write the settings to the mouse. This allows
multiple parameters to be set in a script, and the last call to
Do not immediately write the settings to the mouse. This allows to set
multiple parameters in a script, and the last call to
.B ratbagctl
will write them all.
.TP 8