Compare commits

..

2 Commits

Author SHA1 Message Date
Thomas H.P. Andersen
84b1519ebd steelseries: port to using the firmware field in device 2020-09-29 00:54:01 +02:00
Thomas H.P. Andersen
99b8c80aee device: add firmware major/minor
This adds fields to the device struct to store the
firmware version on the device. It is also exposed
over dbus to the clients.

The firmware of a device can define the protocol
or memory layout that should be used to talk to
the device. Several devices can query the firmware
version via separate commands and we can use this
information in the drivers to change behavior of the
driver based on the device firmware.

The firmware version is also exposed over dbus so that
it is easily available for users via e.g. ratbagctl. It
can also be used in piper to warn users that a known bug
in a firmware version can cause problems when trying to
configure with libratbag.
2020-09-29 00:53:52 +02:00
86 changed files with 1140 additions and 5998 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_31:
<<: *fedora_settings
docker:
- image: fedora:31
arch:
<<: *arch_settings
docker:
- image: archlinux
ubuntu_20_04:
<<: *ubuntu_settings
docker:
- image: ubuntu:20.04
doc_build:
<<: *doc_build
docker:
- image: fedora:31
doc_deploy:
<<: *docs_deploy
docker:
- image: fedora:31
workflows:
version: 2
compile_and_test:
jobs:
- ubuntu_20_04
- arch
- fedora_31
- 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

@@ -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,3 @@ 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

View File

@@ -1,11 +1,5 @@
[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
LedType=RBG
SensorType=PMW3360

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

@@ -151,6 +151,20 @@ known to ratbagd.
Vendor or product IDs of 0 are valid IDs (e.g. used used by test
devices).
.. attribute:: FirmwareMajor
:type: i
:flags: read-only, constant
The device's firmware major version.
.. attribute:: FirmwareMinor
:type: i
:flags: read-only, constant
The device's firmware minor version.
.. attribute:: Name
:type: s

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.40.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,92 @@ 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_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 +399,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 ####
@@ -404,9 +456,10 @@ install_man('ratbagd/ratbagd.8')
# (org.freedesktop.ratbag_devel1). This server is used by ratbagdctl.devel.
#
config_ratbagd_devel = configuration_data()
dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
output : 'org.freedesktop.ratbag_devel1.conf',
copy: true)
configuration : config_ratbagd_devel)
# This is a hack. We always install the devel policy file into
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise.
@@ -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

@@ -220,9 +220,45 @@ ratbag_device_get_model(sd_bus *bus,
return sd_bus_message_append(reply, "s", model);
}
static int
ratbag_device_get_firmware_major(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
int version = ratbag_device_get_firmware_major_version(device->lib_device);
CHECK_CALL(sd_bus_message_append(reply, "i", version));
return 0;
}
static int
ratbag_device_get_firmware_minor(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
int version = ratbag_device_get_firmware_minor_version(device->lib_device);
CHECK_CALL(sd_bus_message_append(reply, "i", version));
return 0;
}
const sd_bus_vtable ratbagd_device_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Model", "s", ratbag_device_get_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareMajor", "i", ratbag_device_get_firmware_major, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareMinor", "i", ratbag_device_get_firmware_minor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),

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

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
@@ -82,11 +78,6 @@
#define STEELSERIES_BUTTON_KBD 0x51
#define STEELSERIES_BUTTON_CONSUMER 0x61
struct steelseries_data {
int firmware_major;
int firmware_minor;
};
struct steelseries_point {
struct list link;
@@ -116,31 +107,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
@@ -201,45 +172,29 @@ button_defaults_for_layout(struct ratbag_button *button, int button_count)
static int
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;
drv_data->firmware_major = buf[1];
drv_data->firmware_minor = buf[0];
device->firmware_major = buf[1];
device->firmware_minor = buf[0];
return 0;
}
@@ -252,33 +207,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;
@@ -313,12 +259,11 @@ steelseries_read_settings(struct ratbag_device *device)
static int
steelseries_probe(struct ratbag_device *device)
{
struct steelseries_data *drv_data = NULL;
struct ratbag_profile *profile = NULL;
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 +280,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 +329,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 +339,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 {
@@ -421,14 +356,11 @@ steelseries_probe(struct ratbag_device *device)
}
}
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
rc = steelseries_get_firmware_version(device);
if(rc == 0)
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
drv_data->firmware_major,
drv_data->firmware_minor);
device->firmware_major,
device->firmware_minor);
steelseries_read_settings(device);
@@ -443,19 +375,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 +396,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 +430,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 +467,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 +488,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 +505,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 +556,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 +564,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 +578,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 +599,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 +699,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 +771,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 +845,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 +877,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)
@@ -1082,7 +950,6 @@ steelseries_remove(struct ratbag_device *device)
{
ratbag_close_hidraw_index(device, 0);
ratbag_close_hidraw_index(device, 1);
free(ratbag_get_drv_data(device));
}
struct ratbag_driver steelseries_driver = {

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,8 @@ struct data_steelseries {
struct dpi_list *dpi_list;
struct dpi_range *dpi_range;
int macro_length;
enum steelseries_quirk quirk;
};
struct data_asus {
int profile_count;
int button_count;
int8_t button_mapping[ASUS_MAX_NUM_BUTTON];
int led_count;
int dpi_count;
int is_wireless;
struct dpi_range *dpi_range;
uint32_t quirks;
int mono_led;
int short_button;
};
struct ratbag_device_data {
@@ -117,9 +92,7 @@ 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;
};
enum ratbag_led_type led_types[20];
@@ -186,18 +159,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 +175,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 +185,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 +192,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 +200,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 +223,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 +239,19 @@ 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);
static void
init_data_asus(struct ratbag *ratbag,
GKeyFile *keyfile,
struct ratbag_device_data *data)
{
const char *group = "Driver/asus";
GError *error = NULL;
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;
int profiles = g_key_file_get_integer(keyfile, group, "Profiles", &error);
if (!error && profiles >= 0)
data->asus.profile_count = profiles;
g_clear_error(&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);
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);
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);
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);
_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);
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);
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 const struct driver_map {
@@ -424,17 +264,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, "sinowealth", NULL },
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
{ OPENINPUT, "openinput", NULL },
};
const char *
@@ -470,34 +306,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 +517,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 +589,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 +597,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 +605,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 +655,18 @@ 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;
}
int
ratbag_device_data_asus_get_led_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.led_count;
}
int
ratbag_device_data_asus_get_dpi_count(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.dpi_count;
}
struct dpi_range *
ratbag_device_data_asus_get_dpi_range(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.dpi_range;
}
int
ratbag_device_data_asus_is_wireless(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.is_wireless;
}
uint32_t
ratbag_device_data_asus_get_quirks(const struct ratbag_device_data *data)
{
assert(data->drivertype == ASUS);
return data->asus.quirks;
return data->steelseries.short_button;
}

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,8 @@ 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);
/* ASUS */
/**
* @return Number of profiles
*/
int
ratbag_device_data_asus_get_profile_count(const struct ratbag_device_data *data);
ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *data);
/**
* @return Number of buttons
*/
int
ratbag_device_data_asus_get_button_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);
/**
* @return 1 if wireless, 0 otherwise
*/
int
ratbag_device_data_asus_is_wireless(const struct ratbag_device_data *data);
/**
* @return Quirks bitmask
*/
uint32_t
ratbag_device_data_asus_get_quirks(const struct ratbag_device_data *data);
ratbag_device_data_steelseries_get_short_button(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

@@ -147,6 +147,9 @@ struct ratbag_device {
unsigned num_buttons;
unsigned num_leds;
int firmware_major;
int firmware_minor;
void *drv_data;
struct list link;
@@ -197,6 +200,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 +215,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 +465,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 +472,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 +596,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

@@ -545,6 +545,18 @@ ratbag_device_get_product_id(const struct ratbag_device *device)
return device->ids.product;
}
LIBRATBAG_EXPORT int32_t
ratbag_device_get_firmware_major_version(const struct ratbag_device *device)
{
return device->firmware_major;
}
LIBRATBAG_EXPORT int32_t
ratbag_device_get_firmware_minor_version(const struct ratbag_device *device)
{
return device->firmware_minor;
}
LIBRATBAG_EXPORT uint32_t
ratbag_device_get_product_version(const struct ratbag_device *device)
{
@@ -600,14 +612,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 +872,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 +950,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

@@ -421,6 +421,24 @@ ratbag_device_set_user_data(struct ratbag_device *device, void *userdata);
void*
ratbag_device_get_user_data(const struct ratbag_device *device);
/**
* @ingroup device
*
* @param device A previously initialized ratbag device
* @return The firmware major version of the device.
*/
int32_t
ratbag_device_get_firmware_major_version(const struct ratbag_device *device);
/**
* @ingroup device
*
* @param device A previously initialized ratbag device
* @return The firmware minor version of the device.
*/
int32_t
ratbag_device_get_firmware_minor_version(const struct ratbag_device *device);
/**
* @ingroup device
*

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

View File

@@ -212,6 +212,8 @@ def print_device(d, level):
print(" " * level + "{} - {}".format(d.id, d.name))
print(" " * level + " Model: {}".format(d.model))
if d.firmware_major > 0 or d.firmware_minor > 0:
print(" " * level + " Firmware version: {}.{}".format(d.firmware_major, d.firmware_minor))
print(" " * level + " Number of Buttons: {}".format(len(p.buttons)))
print(" " * level + " Number of Leds: {}".format(len(p.leds)))
print(" " * level + "Number of Profiles: {}".format(len(d.profiles)))

View File

@@ -342,6 +342,16 @@ class RatbagdDevice(_RatbagdDBus):
"""The unique identifier for this device model."""
return self._get_dbus_property("Model")
@GObject.Property
def firmware_major(self):
"""The firmware major version."""
return self._get_dbus_property("FirmwareMajor")
@GObject.Property
def firmware_minor(self):
"""The firmware minor version."""
return self._get_dbus_property("FirmwareMinor")
@GObject.Property
def name(self):
"""The device name, usually provided by the kernel."""