forked from drath/libratbag
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
952bd9dc07 | ||
|
|
6b97d94a2f | ||
|
|
ccaa8d1b6c | ||
|
|
abe451df33 | ||
|
|
a3fa876c3d | ||
|
|
230647c7f3 | ||
|
|
3f99446a1b | ||
|
|
a766f8e909 | ||
|
|
9ae975f9a9 | ||
|
|
780934b1a1 | ||
|
|
337fb935c4 | ||
|
|
c9cf5fe90c | ||
|
|
18af0f97d2 | ||
|
|
286f13c654 | ||
|
|
c6b9cc0c2a | ||
|
|
7d82bb51a6 | ||
|
|
8976033da7 | ||
|
|
c9c6a1675f | ||
|
|
f1e2a4ccff | ||
|
|
104543fdf1 | ||
|
|
b3275e10d7 | ||
|
|
120908bda8 | ||
|
|
32d6443553 | ||
|
|
ae943eaee7 | ||
|
|
4a9503f2da | ||
|
|
e268100d31 | ||
|
|
8ec0e8bbc5 | ||
|
|
e6a9fba498 |
@@ -258,7 +258,7 @@ workflows:
|
|||||||
compile_and_test:
|
compile_and_test:
|
||||||
jobs:
|
jobs:
|
||||||
- ubuntu_20_04
|
- ubuntu_20_04
|
||||||
- arch
|
# - arch
|
||||||
- fedora_32
|
- fedora_32
|
||||||
- doc_build
|
- doc_build
|
||||||
- doc_deploy:
|
- doc_deploy:
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
[Device]
|
|
||||||
Name=Dream Machines DM5 Blink
|
|
||||||
DeviceMatch=usb:258a:0027
|
|
||||||
Driver=sinowealth
|
|
||||||
|
|
||||||
[Driver/sinowealth]
|
|
||||||
Buttons=8
|
|
||||||
Leds=1
|
|
||||||
LedType=RGB
|
|
||||||
DpiRange=100:16000@100
|
|
||||||
@@ -3,7 +3,3 @@ Name=Glorious Model D
|
|||||||
DeviceMatch=usb:258a:0033
|
DeviceMatch=usb:258a:0033
|
||||||
Driver=sinowealth
|
Driver=sinowealth
|
||||||
|
|
||||||
[Driver/sinowealth]
|
|
||||||
Buttons=6
|
|
||||||
Leds=2
|
|
||||||
DpiRange=100:12000@100
|
|
||||||
@@ -3,8 +3,3 @@ Name=Glorious Model O
|
|||||||
DeviceMatch=usb:258a:0036
|
DeviceMatch=usb:258a:0036
|
||||||
Driver=sinowealth
|
Driver=sinowealth
|
||||||
|
|
||||||
[Driver/sinowealth]
|
|
||||||
Buttons=6
|
|
||||||
Leds=2
|
|
||||||
LedType=RBG
|
|
||||||
DpiRange=100:12000@100
|
|
||||||
5
data/devices/logitech-M500s.device
Normal file
5
data/devices/logitech-M500s.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Logitech M500s
|
||||||
|
[Device]
|
||||||
|
Name=Logitech M500s
|
||||||
|
DeviceMatch=usb:046d:c093
|
||||||
|
Driver=hidpp20
|
||||||
5
data/devices/logitech-M545.device
Normal file
5
data/devices/logitech-M545.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Logitech M545
|
||||||
|
[Device]
|
||||||
|
Name=Logitech M545
|
||||||
|
DeviceMatch=usb:046d:4052
|
||||||
|
Driver=hidpp20
|
||||||
5
data/devices/logitech-MX-Anywhere-3.device
Normal file
5
data/devices/logitech-MX-Anywhere-3.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Logitech MX Anywhere 3
|
||||||
|
[Device]
|
||||||
|
Name=Logitech MX Anywhere 3
|
||||||
|
DeviceMatch=bluetooth:046d:b025;usb:046d:4090
|
||||||
|
Driver=hidpp20
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech MX Anywhere 2
|
Name=Logitech MX Anywhere 2
|
||||||
DeviceMatch=usb:046d:404a;bluetooth:046d:b013;bluetooth:046d:b018;bluetooth:046d:b01f
|
DeviceMatch=usb:046d:404a;usb:046d:4072;usb:046d:4063;bluetooth:046d:b013;bluetooth:046d:b018;bluetooth:046d:b01f
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech MX Vertical
|
Name=Logitech MX Vertical
|
||||||
DeviceMatch=bluetooth:046d:b020;usb:046d:407b
|
DeviceMatch=bluetooth:046d:b020;usb:046d:407b;usb:046d:c08a
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|||||||
5
data/devices/logitech-g-pro-x-wireless-superlight.device
Normal file
5
data/devices/logitech-g-pro-x-wireless-superlight.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Logitech G Pro X Wireless Superlight
|
||||||
|
DeviceMatch=usb:046d:4093;usb:046d:c094
|
||||||
|
LedTypes=logo;battery;dpi;
|
||||||
|
Driver=hidpp20
|
||||||
8
data/devices/logitech-g915-tkl.device
Normal file
8
data/devices/logitech-g915-tkl.device
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Logitech G915 TKL
|
||||||
|
DeviceMatch=usb:046d:c343;bluetooth:046d:b35f
|
||||||
|
LedTypes=logo;switches
|
||||||
|
Driver=hidpp20
|
||||||
|
|
||||||
|
[Driver/hidpp20]
|
||||||
|
DeviceIndex=1
|
||||||
4
data/devices/openinput.device
Normal file
4
data/devices/openinput.device
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[Device]
|
||||||
|
Name=openinput
|
||||||
|
DeviceMatch=usb:1d50:616a
|
||||||
|
Driver=openinput
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Roccat Kone Pure
|
Name=Roccat Kone Pure
|
||||||
DeviceMatch=usb:1e7d:2dc2;usb:1e7d:2dbe
|
DeviceMatch=usb:1e7d:2dc2;usb:1e7d:2dbe;usb:1e7d:2dcb
|
||||||
Driver=roccat-kone-pure
|
Driver=roccat-kone-pure
|
||||||
|
|||||||
11
data/devices/steelseries-kinzu-v2-pro.device
Normal file
11
data/devices/steelseries-kinzu-v2-pro.device
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Device]
|
||||||
|
Name=SteelSeries Kinzu V2 Pro Edition
|
||||||
|
DeviceMatch=usb:1038:1366
|
||||||
|
Driver=steelseries
|
||||||
|
|
||||||
|
[Driver/steelseries]
|
||||||
|
DeviceVersion=1
|
||||||
|
Buttons=3
|
||||||
|
Leds=0
|
||||||
|
DpiList=400;800;1600;3200
|
||||||
|
MacroLength=0
|
||||||
16
meson.build
16
meson.build
@@ -1,8 +1,8 @@
|
|||||||
project('libratbag', 'c',
|
project('libratbag', 'c',
|
||||||
version : '0.15',
|
version : '0.16',
|
||||||
license : 'MIT/Expat',
|
license : 'MIT/Expat',
|
||||||
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
|
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
|
||||||
meson_version : '>= 0.53.0')
|
meson_version : '>= 0.40.0')
|
||||||
|
|
||||||
# The DBus API version. Increase this every time the DBus API changes.
|
# The DBus API version. Increase this every time the DBus API changes.
|
||||||
# No backwards/forwards guarantee, clients are expected to understand
|
# No backwards/forwards guarantee, clients are expected to understand
|
||||||
@@ -174,6 +174,7 @@ src_libratbag = [
|
|||||||
'src/driver-roccat.c',
|
'src/driver-roccat.c',
|
||||||
'src/driver-roccat-kone-pure.c',
|
'src/driver-roccat-kone-pure.c',
|
||||||
'src/driver-gskill.c',
|
'src/driver-gskill.c',
|
||||||
|
'src/driver-openinput.c',
|
||||||
'src/driver-steelseries.c',
|
'src/driver-steelseries.c',
|
||||||
'src/driver-sinowealth.c',
|
'src/driver-sinowealth.c',
|
||||||
'src/driver-sinowealth-nubwo.c',
|
'src/driver-sinowealth-nubwo.c',
|
||||||
@@ -283,6 +284,8 @@ data_files = files(
|
|||||||
'data/devices/etekcity-scroll-alpha.device',
|
'data/devices/etekcity-scroll-alpha.device',
|
||||||
'data/devices/gskill-MX-780.device',
|
'data/devices/gskill-MX-780.device',
|
||||||
'data/devices/logitech-M325.device',
|
'data/devices/logitech-M325.device',
|
||||||
|
'data/devices/logitech-M500s.device',
|
||||||
|
'data/devices/logitech-M545.device',
|
||||||
'data/devices/logitech-M570.device',
|
'data/devices/logitech-M570.device',
|
||||||
'data/devices/logitech-M585-M590.device',
|
'data/devices/logitech-M585-M590.device',
|
||||||
'data/devices/logitech-M705.device',
|
'data/devices/logitech-M705.device',
|
||||||
@@ -296,6 +299,7 @@ data_files = files(
|
|||||||
'data/devices/logitech-Wireless-Touchpad.device',
|
'data/devices/logitech-Wireless-Touchpad.device',
|
||||||
'data/devices/logitech-g-powerplay.device',
|
'data/devices/logitech-g-powerplay.device',
|
||||||
'data/devices/logitech-g-pro-wireless.device',
|
'data/devices/logitech-g-pro-wireless.device',
|
||||||
|
'data/devices/logitech-g-pro-x-wireless-superlight.device',
|
||||||
'data/devices/logitech-g-pro.device',
|
'data/devices/logitech-g-pro.device',
|
||||||
'data/devices/logitech-g102-g203.device',
|
'data/devices/logitech-g102-g203.device',
|
||||||
'data/devices/logitech-g300.device',
|
'data/devices/logitech-g300.device',
|
||||||
@@ -332,16 +336,20 @@ data_files = files(
|
|||||||
'data/devices/logitech-g815.device',
|
'data/devices/logitech-g815.device',
|
||||||
'data/devices/logitech-g910.device',
|
'data/devices/logitech-g910.device',
|
||||||
'data/devices/logitech-g915.device',
|
'data/devices/logitech-g915.device',
|
||||||
|
'data/devices/logitech-g915-tkl.device',
|
||||||
'data/devices/logitech-g935.device',
|
'data/devices/logitech-g935.device',
|
||||||
'data/devices/logitech-g9x-Call-of-Duty-MW3-Edition.device',
|
'data/devices/logitech-g9x-Call-of-Duty-MW3-Edition.device',
|
||||||
'data/devices/logitech-g9x-Original.device',
|
'data/devices/logitech-g9x-Original.device',
|
||||||
'data/devices/logitech-Marathon-M705.device',
|
'data/devices/logitech-Marathon-M705.device',
|
||||||
'data/devices/logitech-MX-Anywhere2.device',
|
'data/devices/logitech-MX-Anywhere2.device',
|
||||||
'data/devices/logitech-MX-Anywhere2S.device',
|
'data/devices/logitech-MX-Anywhere2S.device',
|
||||||
|
'data/devices/logitech-MX-Anywhere-3.device',
|
||||||
'data/devices/logitech-MX-Vertical.device',
|
'data/devices/logitech-MX-Vertical.device',
|
||||||
|
'data/devices/openinput.device',
|
||||||
'data/devices/roccat-kone-pure.device',
|
'data/devices/roccat-kone-pure.device',
|
||||||
'data/devices/roccat-kone-xtd.device',
|
'data/devices/roccat-kone-xtd.device',
|
||||||
'data/devices/steelseries-kinzu-v2.device',
|
'data/devices/steelseries-kinzu-v2.device',
|
||||||
|
'data/devices/steelseries-kinzu-v2-pro.device',
|
||||||
'data/devices/steelseries-kinzu-v3.device',
|
'data/devices/steelseries-kinzu-v3.device',
|
||||||
'data/devices/steelseries-rival-310.device',
|
'data/devices/steelseries-rival-310.device',
|
||||||
'data/devices/steelseries-rival-600.device',
|
'data/devices/steelseries-rival-600.device',
|
||||||
@@ -351,7 +359,6 @@ data_files = files(
|
|||||||
'data/devices/glorious-model-d.device',
|
'data/devices/glorious-model-d.device',
|
||||||
'data/devices/glorious-model-o.device',
|
'data/devices/glorious-model-o.device',
|
||||||
'data/devices/nubwo-x7-spectrum.device',
|
'data/devices/nubwo-x7-spectrum.device',
|
||||||
'data/devices/dream-machines-dm5-blink.device',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
install_data(data_files,
|
install_data(data_files,
|
||||||
@@ -457,9 +464,10 @@ install_man('ratbagd/ratbagd.8')
|
|||||||
# (org.freedesktop.ratbag_devel1). This server is used by ratbagdctl.devel.
|
# (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',
|
dbus_devel_policy = configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
|
||||||
output : 'org.freedesktop.ratbag_devel1.conf',
|
output : 'org.freedesktop.ratbag_devel1.conf',
|
||||||
copy : true)
|
configuration : config_ratbagd_devel)
|
||||||
|
|
||||||
# This is a hack. We always install the devel policy file into
|
# This is a hack. We always install the devel policy file into
|
||||||
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise.
|
# /etc/dbus-1/system.d, independent of any prefixes we use otherwise.
|
||||||
|
|||||||
@@ -697,5 +697,5 @@ void ratbagd_schedule_task(struct ratbagd *ctx,
|
|||||||
cb->callback = callback;
|
cb->callback = callback;
|
||||||
cb->userdata = userdata;
|
cb->userdata = userdata;
|
||||||
|
|
||||||
sd_event_add_post(ctx->event, &source, ratbagd_callback_handler, cb);
|
sd_event_add_defer(ctx->event, &source, ratbagd_callback_handler, cb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include "libratbag-hidraw.h"
|
#include "libratbag-hidraw.h"
|
||||||
|
|
||||||
#define LOGITECH_G600_NUM_PROFILES 3
|
#define LOGITECH_G600_NUM_PROFILES 3
|
||||||
#define LOGITECH_G600_NUM_BUTTONS 20
|
#define LOGITECH_G600_NUM_BUTTONS 41 // 20 buttons + 1 color buffer + 20 G-shift
|
||||||
#define LOGITECH_G600_NUM_DPI 4
|
#define LOGITECH_G600_NUM_DPI 4
|
||||||
#define LOGITECH_G600_NUM_LED 1
|
#define LOGITECH_G600_NUM_LED 1
|
||||||
#define LOGITECH_G600_DPI_MIN 200
|
#define LOGITECH_G600_DPI_MIN 200
|
||||||
@@ -109,20 +109,41 @@ static const struct logitech_g600_button_type_mapping logitech_g600_button_type_
|
|||||||
{ 3, RATBAG_BUTTON_TYPE_WHEEL_LEFT },
|
{ 3, RATBAG_BUTTON_TYPE_WHEEL_LEFT },
|
||||||
{ 4, RATBAG_BUTTON_TYPE_WHEEL_RIGHT },
|
{ 4, RATBAG_BUTTON_TYPE_WHEEL_RIGHT },
|
||||||
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
|
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
|
||||||
{ 6, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP },
|
{ 6, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP }, // G07
|
||||||
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP },
|
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP }, // G08
|
||||||
{ 8, RATBAG_BUTTON_TYPE_SIDE }, // 8 = G9 ... 19 = G20
|
{ 8, RATBAG_BUTTON_TYPE_SIDE }, // G09
|
||||||
{ 9, RATBAG_BUTTON_TYPE_SIDE },
|
{ 9, RATBAG_BUTTON_TYPE_SIDE }, // G10
|
||||||
{ 10, RATBAG_BUTTON_TYPE_SIDE },
|
{ 10, RATBAG_BUTTON_TYPE_SIDE }, // G11
|
||||||
{ 11, RATBAG_BUTTON_TYPE_SIDE },
|
{ 11, RATBAG_BUTTON_TYPE_SIDE }, // G12
|
||||||
{ 12, RATBAG_BUTTON_TYPE_SIDE },
|
{ 12, RATBAG_BUTTON_TYPE_SIDE }, // G13
|
||||||
{ 13, RATBAG_BUTTON_TYPE_SIDE },
|
{ 13, RATBAG_BUTTON_TYPE_SIDE }, // G14
|
||||||
{ 14, RATBAG_BUTTON_TYPE_SIDE },
|
{ 14, RATBAG_BUTTON_TYPE_SIDE }, // G15
|
||||||
{ 15, RATBAG_BUTTON_TYPE_SIDE },
|
{ 15, RATBAG_BUTTON_TYPE_SIDE }, // G16
|
||||||
{ 16, RATBAG_BUTTON_TYPE_SIDE },
|
{ 16, RATBAG_BUTTON_TYPE_SIDE }, // G17
|
||||||
{ 17, RATBAG_BUTTON_TYPE_SIDE },
|
{ 17, RATBAG_BUTTON_TYPE_SIDE }, // G18
|
||||||
{ 18, RATBAG_BUTTON_TYPE_SIDE },
|
{ 18, RATBAG_BUTTON_TYPE_SIDE }, // G19
|
||||||
{ 19, RATBAG_BUTTON_TYPE_SIDE },
|
{ 19, RATBAG_BUTTON_TYPE_SIDE }, // G20
|
||||||
|
{ 20, RATBAG_BUTTON_TYPE_UNKNOWN }, //HACK is where the G-shift color information is located
|
||||||
|
{ 21, RATBAG_BUTTON_TYPE_LEFT }, // G-shift + left
|
||||||
|
{ 22, RATBAG_BUTTON_TYPE_RIGHT }, // G-shift + right click
|
||||||
|
{ 23, RATBAG_BUTTON_TYPE_MIDDLE }, // G-shift + middle
|
||||||
|
{ 24, RATBAG_BUTTON_TYPE_WHEEL_LEFT}, // G-shift + scroll left
|
||||||
|
{ 25, RATBAG_BUTTON_TYPE_WHEEL_RIGHT}, // G-shift + scroll right
|
||||||
|
{ 26, RATBAG_BUTTON_TYPE_PINKIE }, // G-shift + Pinky(shift modifer)
|
||||||
|
{ 27, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP }, // G-shift + 07
|
||||||
|
{ 28, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP }, // G-shift + G08
|
||||||
|
{ 29, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G09
|
||||||
|
{ 30, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G10
|
||||||
|
{ 31, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G11
|
||||||
|
{ 32, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G12
|
||||||
|
{ 33, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G13
|
||||||
|
{ 34, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G14
|
||||||
|
{ 35, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G15
|
||||||
|
{ 36, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G16
|
||||||
|
{ 37, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G17
|
||||||
|
{ 38, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G18
|
||||||
|
{ 39, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G19
|
||||||
|
{ 40, RATBAG_BUTTON_TYPE_SIDE }, // G-shift + G20
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum ratbag_button_type
|
static enum ratbag_button_type
|
||||||
@@ -144,7 +165,7 @@ struct logitech_g600_button_mapping {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct logitech_g600_button_mapping logitech_g600_button_mapping[] = {
|
static struct logitech_g600_button_mapping logitech_g600_button_mapping[] = {
|
||||||
/* 0x00 is either key or unassigned. Must be handled separatly */
|
/* 0x00 is either key or unassigned. Must be handled separately */
|
||||||
{ 0x01, BUTTON_ACTION_BUTTON(1) },
|
{ 0x01, BUTTON_ACTION_BUTTON(1) },
|
||||||
{ 0x02, BUTTON_ACTION_BUTTON(2) },
|
{ 0x02, BUTTON_ACTION_BUTTON(2) },
|
||||||
{ 0x03, BUTTON_ACTION_BUTTON(3) },
|
{ 0x03, BUTTON_ACTION_BUTTON(3) },
|
||||||
@@ -600,6 +621,12 @@ logitech_g600_write_profile(struct ratbag_profile *profile)
|
|||||||
report->led_duration = 0x0f;
|
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;
|
buf = (uint8_t*)report;
|
||||||
|
|
||||||
rc = ratbag_hidraw_raw_request(device, report->id,
|
rc = ratbag_hidraw_raw_request(device, report->id,
|
||||||
|
|||||||
482
src/driver-openinput.c
Normal file
482
src/driver-openinput.c
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2021 Filipe Laíns
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "libratbag-private.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* reports */
|
||||||
|
#define OI_REPORT_SHORT 0x20
|
||||||
|
#define OI_REPORT_LONG 0x21
|
||||||
|
#define OI_REPORT_SHORT_SIZE 8
|
||||||
|
#define OI_REPORT_LONG_SIZE 32
|
||||||
|
|
||||||
|
#define OI_REPORT_MAX_SIZE OI_REPORT_LONG_SIZE
|
||||||
|
#define OI_REPORT_DATA_INDEX 3
|
||||||
|
#define OI_REPORT_DATA_MAX_SIZE OI_REPORT_LONG_SIZE - OI_REPORT_DATA_INDEX
|
||||||
|
|
||||||
|
/* protocol function pages */
|
||||||
|
#define OI_PAGE_INFO 0x00
|
||||||
|
#define OI_PAGE_GIMMICKS 0xFD
|
||||||
|
#define OI_PAGE_DEBUG 0xFE
|
||||||
|
#define OI_PAGE_ERROR 0xFF
|
||||||
|
|
||||||
|
/* info page (0x00) functions */
|
||||||
|
#define OI_FUNCTION_VERSION 0x00
|
||||||
|
#define OI_FUNCTION_FW_INFO 0x01
|
||||||
|
#define OI_FUNCTION_SUPPORTED_FUNCTION_PAGES 0x02
|
||||||
|
#define OI_FUNCTION_SUPPORTED_FUNCTIONS 0x03
|
||||||
|
|
||||||
|
/* error page (0xFF) */
|
||||||
|
#define OI_ERROR_INVALID_VALUE 0x01
|
||||||
|
#define OI_ERROR_UNSUPPORTED_FUNCTION 0x02
|
||||||
|
#define OI_ERROR_CUSTOM 0xFE
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int report_rates[] = { 125, 250, 500, 750, 1000 };
|
||||||
|
|
||||||
|
struct openinput_drv_data {
|
||||||
|
unsigned int num_profiles;
|
||||||
|
unsigned int num_resolutions;
|
||||||
|
unsigned int num_buttons;
|
||||||
|
unsigned int num_leds;
|
||||||
|
unsigned int fw_major;
|
||||||
|
unsigned int fw_minor;
|
||||||
|
unsigned int fw_patch;
|
||||||
|
uint64_t supported;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct oi_report_t {
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t function_page;
|
||||||
|
uint8_t function;
|
||||||
|
uint8_t data[29];
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
|
||||||
|
#define CASE_RETURN_STRING(a) case a: return #a; break
|
||||||
|
static const char*
|
||||||
|
openinput_function_page_get_name(uint8_t page)
|
||||||
|
{
|
||||||
|
static char numeric[16];
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
switch(page) {
|
||||||
|
CASE_RETURN_STRING(OI_PAGE_INFO);
|
||||||
|
CASE_RETURN_STRING(OI_PAGE_GIMMICKS);
|
||||||
|
CASE_RETURN_STRING(OI_PAGE_DEBUG);
|
||||||
|
CASE_RETURN_STRING(OI_PAGE_ERROR);
|
||||||
|
default:
|
||||||
|
sprintf_safe(numeric, "0x%02x", page);
|
||||||
|
str = numeric;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
openinput_function_get_name(uint8_t page, uint8_t function)
|
||||||
|
{
|
||||||
|
static char numeric[32];
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
switch(page) {
|
||||||
|
case OI_PAGE_INFO:
|
||||||
|
switch (function) {
|
||||||
|
CASE_RETURN_STRING(OI_FUNCTION_VERSION);
|
||||||
|
CASE_RETURN_STRING(OI_FUNCTION_FW_INFO);
|
||||||
|
CASE_RETURN_STRING(OI_FUNCTION_SUPPORTED_FUNCTION_PAGES);
|
||||||
|
CASE_RETURN_STRING(OI_FUNCTION_SUPPORTED_FUNCTIONS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
sprintf_safe(numeric, "0x%02x 0x%02x", page, function);
|
||||||
|
str = numeric;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
#undef CASE_RETURN_STRING
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
openinput_get_error_string(struct oi_report_t *report)
|
||||||
|
{
|
||||||
|
char help_str[OI_REPORT_LONG_SIZE - OI_REPORT_DATA_INDEX + 1] = {0};
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
switch (report->function) {
|
||||||
|
case OI_ERROR_INVALID_VALUE:
|
||||||
|
xasprintf(&str, "Invalid value (in position %u)", report->data[2]);
|
||||||
|
break;
|
||||||
|
case OI_ERROR_CUSTOM:
|
||||||
|
memcpy(help_str, report->data, sizeof(help_str)-1); /* copy error string */
|
||||||
|
xasprintf(&str, "Custom error (%s)", help_str);
|
||||||
|
break;
|
||||||
|
case OI_ERROR_UNSUPPORTED_FUNCTION:
|
||||||
|
xasprintf(&str, "Unsupported function (0x%02x, 0x%02x)", report->data[0], report->data[1]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xasprintf(&str, "Unkown error (%u)", report->function);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
openinput_get_report_size(unsigned int report)
|
||||||
|
{
|
||||||
|
switch (report) {
|
||||||
|
case OI_REPORT_SHORT:
|
||||||
|
return OI_REPORT_SHORT_SIZE;
|
||||||
|
case OI_REPORT_LONG:
|
||||||
|
return OI_REPORT_LONG_SIZE;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_send_report(struct ratbag_device *device, struct oi_report_t *report)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t buffer[OI_REPORT_MAX_SIZE];
|
||||||
|
size_t size = openinput_get_report_size(report->id);
|
||||||
|
|
||||||
|
memcpy(buffer, report, size);
|
||||||
|
|
||||||
|
ret = ratbag_hidraw_output_report(device, buffer, size);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_error(device->ratbag, "openinput: failed to send data to device (%s)\n",
|
||||||
|
strerror(-ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ratbag_hidraw_read_input_report(device, buffer, OI_REPORT_MAX_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_error(device->ratbag, "openinput: failed to read data from device (%s)\n",
|
||||||
|
strerror(-ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(report, buffer, openinput_get_report_size(buffer[0]));
|
||||||
|
|
||||||
|
/* check for error */
|
||||||
|
if (report->function_page == OI_PAGE_ERROR) {
|
||||||
|
log_error(device->ratbag, "openinput: %s\n", openinput_get_error_string(report));
|
||||||
|
return report->function;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_info_version(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct openinput_drv_data *drv_data = ratbag_get_drv_data(device);
|
||||||
|
struct oi_report_t report = {
|
||||||
|
.id = OI_REPORT_SHORT,
|
||||||
|
.function_page = OI_PAGE_INFO,
|
||||||
|
.function = OI_FUNCTION_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = openinput_send_report(device, &report);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drv_data->fw_major = report.data[0];
|
||||||
|
drv_data->fw_minor = report.data[1];
|
||||||
|
drv_data->fw_patch = report.data[2];
|
||||||
|
|
||||||
|
log_info(device->ratbag, "openinput: protocol version %u.%u.%u\n",
|
||||||
|
drv_data->fw_major, drv_data->fw_minor, drv_data->fw_patch);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OI_FUNCTION_FW_INFO_VENDOR 0x00
|
||||||
|
#define OI_FUNCTION_FW_INFO_VERSION 0x01
|
||||||
|
#define OI_FUNCTION_FW_INFO_DEVICE_NAME 0x02
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_info_fw_info(struct ratbag_device *device,
|
||||||
|
uint8_t field_id,
|
||||||
|
unsigned char *description,
|
||||||
|
size_t description_size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct oi_report_t report = {
|
||||||
|
.id = OI_REPORT_SHORT,
|
||||||
|
.function_page = OI_PAGE_INFO,
|
||||||
|
.function = OI_FUNCTION_FW_INFO,
|
||||||
|
.data = {field_id}
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = openinput_send_report(device, &report);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
memcpy(description, report.data, min(sizeof(report.data), description_size));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_info_supported_function_pages(struct ratbag_device *device,
|
||||||
|
uint8_t start_index,
|
||||||
|
uint8_t *pages_count,
|
||||||
|
uint8_t *pages_left,
|
||||||
|
uint8_t *pages,
|
||||||
|
size_t pages_size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct oi_report_t report = {
|
||||||
|
.id = OI_REPORT_SHORT,
|
||||||
|
.function_page = OI_PAGE_INFO,
|
||||||
|
.function = OI_FUNCTION_SUPPORTED_FUNCTION_PAGES,
|
||||||
|
.data = {start_index}
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = openinput_send_report(device, &report);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*pages_count = report.data[0];
|
||||||
|
*pages_left = report.data[1];
|
||||||
|
memcpy(pages, report.data + 2, min(sizeof(report.data), pages_size));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_info_supported_functions(struct ratbag_device *device,
|
||||||
|
uint8_t function_page,
|
||||||
|
uint8_t start_index,
|
||||||
|
uint8_t *functions_count,
|
||||||
|
uint8_t *functions_left,
|
||||||
|
uint8_t *functions,
|
||||||
|
size_t functions_size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct oi_report_t report = {
|
||||||
|
.id = OI_REPORT_SHORT,
|
||||||
|
.function_page = OI_PAGE_INFO,
|
||||||
|
.function = OI_FUNCTION_SUPPORTED_FUNCTIONS,
|
||||||
|
.data = {function_page, start_index}
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = openinput_send_report(device, &report);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*functions_count = report.data[0];
|
||||||
|
*functions_left = report.data[1];
|
||||||
|
memcpy(functions, report.data + 2, min(sizeof(report.data), functions_size));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_read_supported_functions(struct ratbag_device *device, uint8_t page)
|
||||||
|
{
|
||||||
|
struct ratbag *ratbag = device->ratbag;
|
||||||
|
int ret;
|
||||||
|
uint8_t i, total, read = 0, count = 0, left = 0;
|
||||||
|
uint8_t buffer[OI_REPORT_DATA_MAX_SIZE];
|
||||||
|
|
||||||
|
ret = openinput_info_supported_functions(device,
|
||||||
|
page,
|
||||||
|
read,
|
||||||
|
&count, &left,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
total = count + left;
|
||||||
|
uint8_t functions[total];
|
||||||
|
|
||||||
|
memcpy(functions, buffer, count);
|
||||||
|
|
||||||
|
/* there are still functions left to read! */
|
||||||
|
while (left) {
|
||||||
|
ret = openinput_info_supported_functions(device,
|
||||||
|
page,
|
||||||
|
read,
|
||||||
|
&count, &left,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* make sure the new size values make sense, to avoid deadlocks */
|
||||||
|
if (total != (read + count + left)) {
|
||||||
|
log_error(ratbag, "openinput: invalid number of functions left to read (%u)\n", left);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
log_debug(ratbag, "openinput: read %u functions, %u left\n", count, left);
|
||||||
|
|
||||||
|
memcpy(functions + read, buffer, count);
|
||||||
|
read += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate over read functions */
|
||||||
|
for (i = 0; i < total; i++) {
|
||||||
|
log_debug(ratbag, "openinput: found function %s\n", openinput_function_get_name(page, functions[i]));
|
||||||
|
/* TODO: set bits in drv_data->supported when we implement support for certain capabilities */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_read_supported_function_pages(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
struct ratbag *ratbag = device->ratbag;
|
||||||
|
int ret;
|
||||||
|
uint8_t i, total, read = 0, count = 0, left = 0;
|
||||||
|
uint8_t buffer[OI_REPORT_DATA_MAX_SIZE];
|
||||||
|
|
||||||
|
log_debug(ratbag, "openinput: starting reading device functions...\n");
|
||||||
|
|
||||||
|
ret = openinput_info_supported_function_pages(device,
|
||||||
|
read,
|
||||||
|
&count, &left,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
total = count + left;
|
||||||
|
uint8_t pages[total];
|
||||||
|
|
||||||
|
memcpy(pages, buffer, count);
|
||||||
|
|
||||||
|
/* there are still function pages left to read! */
|
||||||
|
while (left) {
|
||||||
|
ret = openinput_info_supported_function_pages(device,
|
||||||
|
read,
|
||||||
|
&count, &left,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* make sure the new size values make sense, to avoid deadlocks */
|
||||||
|
if (total != (read + count + left)) {
|
||||||
|
log_error(ratbag, "openinput: invalid number of function pages left to read (%u)\n", left);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
log_debug(ratbag, "openinput: read %u pages, %u left\n", count, left);
|
||||||
|
|
||||||
|
memcpy(pages + read, buffer, count);
|
||||||
|
read += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate over read function pages, and read their functions */
|
||||||
|
for (i = 0; i < total; i++) {
|
||||||
|
log_debug(ratbag, "openinput: found function page %s\n", openinput_function_page_get_name(pages[i]));
|
||||||
|
openinput_read_supported_functions(device, pages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
openinput_read_profile(struct ratbag_profile *profile)
|
||||||
|
{
|
||||||
|
ratbag_profile_set_report_rate_list(profile, report_rates, sizeof(*report_rates));
|
||||||
|
profile->is_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_test_hidraw(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
return ratbag_hidraw_has_report(device, OI_REPORT_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openinput_probe(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct openinput_drv_data *drv_data;
|
||||||
|
struct ratbag_profile *profile;
|
||||||
|
unsigned char str[OI_REPORT_DATA_MAX_SIZE];
|
||||||
|
|
||||||
|
ret = ratbag_find_hidraw(device, openinput_test_hidraw);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drv_data = zalloc(sizeof(*drv_data));
|
||||||
|
|
||||||
|
drv_data->num_profiles = 1;
|
||||||
|
|
||||||
|
ratbag_set_drv_data(device, drv_data);
|
||||||
|
|
||||||
|
openinput_info_version(device);
|
||||||
|
|
||||||
|
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_VENDOR, str, sizeof(str));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
log_info(device->ratbag, "openinput: firmware vendor: %s\n", str);
|
||||||
|
|
||||||
|
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_VERSION, str, sizeof(str));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
log_info(device->ratbag, "openinput: firmware version: %s\n", str);
|
||||||
|
|
||||||
|
ret = openinput_info_fw_info(device, OI_FUNCTION_FW_INFO_DEVICE_NAME, str, sizeof(str));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
log_info(device->ratbag, "openinput: device: %s\n", str);
|
||||||
|
|
||||||
|
ret = openinput_read_supported_function_pages(device);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ratbag_device_init_profiles(device,
|
||||||
|
drv_data->num_profiles,
|
||||||
|
drv_data->num_resolutions,
|
||||||
|
drv_data->num_buttons,
|
||||||
|
drv_data->num_leds);
|
||||||
|
|
||||||
|
ratbag_device_for_each_profile(device, profile)
|
||||||
|
openinput_read_profile(profile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
openinput_remove(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
ratbag_close_hidraw(device);
|
||||||
|
free(ratbag_get_drv_data(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ratbag_driver openinput_driver = {
|
||||||
|
.name = "openinput",
|
||||||
|
.id = "openinput",
|
||||||
|
.probe = openinput_probe,
|
||||||
|
.remove = openinput_remove,
|
||||||
|
};
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
* DEALINGS IN THE SOFTWARE.
|
* DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "libratbag-enums.h"
|
#include "libratbag-enums.h"
|
||||||
#include "libratbag-hidraw.h"
|
#include "libratbag-hidraw.h"
|
||||||
#include "libratbag-private.h"
|
#include "libratbag-private.h"
|
||||||
|
|||||||
@@ -23,36 +23,38 @@
|
|||||||
|
|
||||||
#include "libratbag-private.h"
|
#include "libratbag-private.h"
|
||||||
#include "libratbag-hidraw.h"
|
#include "libratbag-hidraw.h"
|
||||||
#include "libratbag-data.h"
|
|
||||||
|
|
||||||
#define SINOWEALTH_REPORT_ID_CONFIG 0x4
|
#define SINOWEALTH_REPORT_ID_CONFIG 0x4
|
||||||
#define SINOWEALTH_REPORT_ID_CMD 0x5
|
#define SINOWEALTH_REPORT_ID_CMD 0x5
|
||||||
#define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1
|
#define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1
|
||||||
#define SINOWEALTH_CMD_GET_CONFIG 0x11
|
#define SINOWEALTH_CMD_GET_CONFIG 0x11
|
||||||
#define SINOWEALTH_CMD_GET_BUTTONS 0x12
|
|
||||||
#define SINOWEALTH_CONFIG_SIZE 520
|
#define SINOWEALTH_CONFIG_SIZE 520
|
||||||
#define SINOWEALTH_CONFIG_SIZE_USED 131
|
#define SINOWEALTH_CONFIG_SIZE_USED 131
|
||||||
#define SINOWEALTH_BUTTON_SIZE 88
|
|
||||||
|
|
||||||
#define SINOWEALTH_XY_INDEPENDENT 0x80
|
#define SINOWEALTH_XY_INDEPENDENT 0x80
|
||||||
|
|
||||||
|
/* The PC software only goes down to 400, but the PMW3360 doesn't care */
|
||||||
|
#define SINOWEALTH_DPI_MIN 100
|
||||||
|
#define SINOWEALTH_DPI_MAX 12000
|
||||||
|
#define SINOWEALTH_DPI_STEP 100
|
||||||
|
|
||||||
/* other models might have up to eight */
|
/* other models might have up to eight */
|
||||||
#define SINOWEALTH_NUM_DPIS 6
|
#define SINOWEALTH_NUM_DPIS 6
|
||||||
|
|
||||||
#define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0
|
#define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0
|
||||||
#define SINOWEALTH_RGB_SPEED_BITS 0x0F
|
#define SINOWEALTH_RGB_SPEED_BITS 0x0F
|
||||||
|
|
||||||
#define SINOWEALTH_BUTTON_TYPE_BUTTON 0x11
|
struct sinowealth_rgb8 {
|
||||||
#define SINOWEALTH_BUTTON_TYPE_KEY 0x21
|
uint8_t r, g, b;
|
||||||
#define SINOWEALTH_BUTTON_TYPE_REPEATED 0x31
|
|
||||||
#define SINOWEALTH_BUTTON_TYPE_SWITCH_DPI 0x41
|
|
||||||
#define SINOWEALTH_BUTTON_TYPE_DISABLED 0x50
|
|
||||||
|
|
||||||
struct sinowealth_color {
|
|
||||||
uint8_t data[3];
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
_Static_assert(sizeof(struct sinowealth_color) == 3, "Invalid size");
|
_Static_assert(sizeof(struct sinowealth_rgb8) == 3, "Invalid size");
|
||||||
|
|
||||||
|
struct sinowealth_rbg8 {
|
||||||
|
uint8_t r, b, g;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
_Static_assert(sizeof(struct sinowealth_rbg8) == 3, "Invalid size");
|
||||||
|
|
||||||
enum rgb_effect {
|
enum rgb_effect {
|
||||||
RGB_OFF = 0,
|
RGB_OFF = 0,
|
||||||
@@ -86,13 +88,11 @@ struct sinowealth_config_report {
|
|||||||
uint8_t dpi_enabled;
|
uint8_t dpi_enabled;
|
||||||
/* DPI/CPI is encoded in the way the PMW3360 sensor accepts it
|
/* DPI/CPI is encoded in the way the PMW3360 sensor accepts it
|
||||||
* value = (DPI - 100) / 100
|
* value = (DPI - 100) / 100
|
||||||
* or the way the PMW3389 sensor accepts it
|
|
||||||
* value = DPI / 100
|
|
||||||
* If XY are identical, dpi[0-6] contain the sensitivities,
|
* If XY are identical, dpi[0-6] contain the sensitivities,
|
||||||
* while in XY independent mode each entry takes two chars for X and Y.
|
* while in XY independent mode each entry takes two chars for X and Y.
|
||||||
*/
|
*/
|
||||||
uint8_t dpi[16];
|
uint8_t dpi[16];
|
||||||
struct sinowealth_color dpi_color[8];
|
struct sinowealth_rgb8 dpi_color[8];
|
||||||
uint8_t rgb_effect; /* see enum rgb_effect */
|
uint8_t rgb_effect; /* see enum rgb_effect */
|
||||||
/* 0x40 - brightness (constant)
|
/* 0x40 - brightness (constant)
|
||||||
* 0x1/2/3 - speed
|
* 0x1/2/3 - speed
|
||||||
@@ -100,13 +100,13 @@ struct sinowealth_config_report {
|
|||||||
uint8_t glorious_mode;
|
uint8_t glorious_mode;
|
||||||
uint8_t glorious_direction;
|
uint8_t glorious_direction;
|
||||||
uint8_t single_mode;
|
uint8_t single_mode;
|
||||||
struct sinowealth_color single_color;
|
struct sinowealth_rbg8 single_color;
|
||||||
/* 0x40 - brightness (constant)
|
/* 0x40 - brightness (constant)
|
||||||
* 0x1/2/3 - speed
|
* 0x1/2/3 - speed
|
||||||
*/
|
*/
|
||||||
uint8_t breathing7_mode;
|
uint8_t breathing7_mode;
|
||||||
uint8_t breathing7_colorcount; /* 7, constant */
|
uint8_t breathing7_colorcount; /* 7, constant */
|
||||||
struct sinowealth_color breathing7_colors[7];
|
struct sinowealth_rbg8 breathing7_colors[7];
|
||||||
/* 0x10/20/30/40 - brightness
|
/* 0x10/20/30/40 - brightness
|
||||||
* 0x1/2/3 - speed
|
* 0x1/2/3 - speed
|
||||||
*/
|
*/
|
||||||
@@ -116,14 +116,14 @@ struct sinowealth_config_report {
|
|||||||
* 0x1/2/3 - speed
|
* 0x1/2/3 - speed
|
||||||
*/
|
*/
|
||||||
uint8_t rave_mode;
|
uint8_t rave_mode;
|
||||||
struct sinowealth_color rave_colors[2];
|
struct sinowealth_rbg8 rave_colors[2];
|
||||||
/* 0x10/20/30/40 - brightness
|
/* 0x10/20/30/40 - brightness
|
||||||
* 0x1/2/3 - speed
|
* 0x1/2/3 - speed
|
||||||
*/
|
*/
|
||||||
uint8_t wave_mode;
|
uint8_t wave_mode;
|
||||||
/* 0x1/2/3 - speed */
|
/* 0x1/2/3 - speed */
|
||||||
uint8_t breathing1_mode;
|
uint8_t breathing1_mode;
|
||||||
struct sinowealth_color breathing1_color;
|
struct sinowealth_rbg8 breathing1_color;
|
||||||
uint8_t unknown4;
|
uint8_t unknown4;
|
||||||
/* 0x1 - 2 mm
|
/* 0x1 - 2 mm
|
||||||
* 0x2 - 3 mm
|
* 0x2 - 3 mm
|
||||||
@@ -134,96 +134,46 @@ struct sinowealth_config_report {
|
|||||||
|
|
||||||
_Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
|
_Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
|
||||||
|
|
||||||
struct sinowealth_button_data {
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t data[3];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct sinowealth_button_report {
|
|
||||||
uint8_t report_id;
|
|
||||||
uint8_t command_id;
|
|
||||||
uint8_t unknown1[6];
|
|
||||||
struct sinowealth_button_data buttons[20];
|
|
||||||
uint8_t padding[SINOWEALTH_CONFIG_SIZE - SINOWEALTH_BUTTON_SIZE];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
_Static_assert(sizeof(struct sinowealth_button_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
|
|
||||||
|
|
||||||
enum sinowealth_sensor {
|
|
||||||
PWM3360,
|
|
||||||
PWM3389,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum sinowealth_led_format {
|
|
||||||
LED_RGB,
|
|
||||||
LED_RBG,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sinowealth_data {
|
struct sinowealth_data {
|
||||||
/* this is kinda unnecessary at this time, but all the other drivers do it too ;) */
|
/* this is kinda unnecessary at this time, but all the other drivers do it too ;) */
|
||||||
struct sinowealth_config_report config;
|
struct sinowealth_config_report config;
|
||||||
/* holds button data so we can send back unchanged values for the buttons we do not parse yet */
|
|
||||||
struct sinowealth_button_report buttons;
|
|
||||||
/* Specifies sensor used in the device */
|
|
||||||
enum sinowealth_sensor sensor;
|
|
||||||
/* whether the devices stores the main LED in RGB or RBG format */
|
|
||||||
enum sinowealth_led_format led_type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sinowealth_raw_to_dpi(struct ratbag_device *device, int raw)
|
sinowealth_raw_to_dpi(int raw)
|
||||||
{
|
{
|
||||||
struct sinowealth_data *drv_data = device->drv_data;
|
return (raw + 1) * 100;
|
||||||
int dpi;
|
|
||||||
|
|
||||||
if (drv_data->sensor == PWM3360)
|
|
||||||
dpi = (raw + 1) * 100;
|
|
||||||
else
|
|
||||||
dpi = raw * 100;
|
|
||||||
|
|
||||||
return dpi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sinowealth_dpi_to_raw(struct ratbag_device *device, unsigned int dpi)
|
sinowealth_dpi_to_raw(int dpi)
|
||||||
{
|
{
|
||||||
struct sinowealth_data *drv_data = device->drv_data;
|
assert(dpi >= SINOWEALTH_DPI_MIN && dpi <= SINOWEALTH_DPI_MAX);
|
||||||
struct dpi_range *dpirange = NULL;
|
return dpi / 100 - 1;
|
||||||
int raw;
|
|
||||||
|
|
||||||
dpirange = ratbag_device_data_sinowealth_get_dpi_range(device->data);
|
|
||||||
assert(dpi >= dpirange->min && dpi <= dpirange->max);
|
|
||||||
|
|
||||||
if (drv_data->sensor == PWM3360)
|
|
||||||
raw = dpi / 100 - 1;
|
|
||||||
else
|
|
||||||
raw = dpi / 100;
|
|
||||||
|
|
||||||
return raw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ratbag_color
|
static struct ratbag_color
|
||||||
sinowealth_raw_to_color(struct sinowealth_color raw)
|
sinowealth_raw_to_color(struct sinowealth_rgb8 raw)
|
||||||
{
|
{
|
||||||
return (struct ratbag_color) {.red = raw.data[0], .green = raw.data[1], .blue = raw.data[2]};
|
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sinowealth_color
|
static struct sinowealth_rgb8
|
||||||
sinowealth_color_to_raw(struct ratbag_color color)
|
sinowealth_color_to_raw(struct ratbag_color color)
|
||||||
{
|
{
|
||||||
return (struct sinowealth_color) {.data[0] = color.red, .data[1] = color.green, .data[2] = color.blue};
|
return (struct sinowealth_rgb8) {.r = color.red, .g = color.green, .b = color.blue};
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ratbag_color
|
static struct ratbag_color
|
||||||
sinowealth_rbg_to_color(struct sinowealth_color raw)
|
sinowealth_rbg_to_color(struct sinowealth_rbg8 raw)
|
||||||
{
|
{
|
||||||
return (struct ratbag_color) {.red = raw.data[0], .green = raw.data[2], .blue = raw.data[1]};
|
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sinowealth_color
|
static struct sinowealth_rbg8
|
||||||
sinowealth_color_to_rbg(struct ratbag_color color)
|
sinowealth_color_to_rbg(struct ratbag_color color)
|
||||||
{
|
{
|
||||||
return (struct sinowealth_color) {.data[0] = color.red, .data[2] = color.green, .data[1] = color.blue};
|
return (struct sinowealth_rbg8) {.r = color.red, .g = color.green, .b = color.blue};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -295,6 +245,20 @@ sinowealth_read_profile(struct ratbag_profile *profile)
|
|||||||
unsigned int hz = 1000; /* TODO */
|
unsigned int hz = 1000; /* TODO */
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Print firmware version */
|
||||||
|
uint8_t version[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_FIRMWARE_VERSION};
|
||||||
|
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, version, sizeof(version));
|
||||||
|
if (rc != sizeof(version)) {
|
||||||
|
log_error(device->ratbag, "Error while sending read firmware version command: %d\n", rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CMD, version, sizeof(version));
|
||||||
|
if (rc != sizeof(version)) {
|
||||||
|
log_error(device->ratbag, "Could not read firmware version: %d\n", rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
log_debug(device->ratbag, "firmware version: %.4s\n", version + 2);
|
||||||
|
|
||||||
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_CONFIG};
|
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_CONFIG};
|
||||||
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
|
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
|
||||||
if (rc != sizeof(cmd)) {
|
if (rc != sizeof(cmd)) {
|
||||||
@@ -316,10 +280,10 @@ sinowealth_read_profile(struct ratbag_profile *profile)
|
|||||||
|
|
||||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
||||||
resolution->dpi_x = sinowealth_raw_to_dpi(device, config->dpi[resolution->index * 2]);
|
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2]);
|
||||||
resolution->dpi_y = sinowealth_raw_to_dpi(device, config->dpi[resolution->index * 2 + 1]);
|
resolution->dpi_y = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2 + 1]);
|
||||||
} else {
|
} else {
|
||||||
resolution->dpi_x = sinowealth_raw_to_dpi(device, config->dpi[resolution->index]);
|
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index]);
|
||||||
resolution->dpi_y = resolution->dpi_x;
|
resolution->dpi_y = resolution->dpi_x;
|
||||||
}
|
}
|
||||||
if (config->dpi_enabled & (1<<resolution->index)) {
|
if (config->dpi_enabled & (1<<resolution->index)) {
|
||||||
@@ -339,10 +303,7 @@ sinowealth_read_profile(struct ratbag_profile *profile)
|
|||||||
break;
|
break;
|
||||||
case RGB_SINGLE:
|
case RGB_SINGLE:
|
||||||
led->mode = RATBAG_LED_ON;
|
led->mode = RATBAG_LED_ON;
|
||||||
if (drv_data->led_type == LED_RGB)
|
led->color = sinowealth_rbg_to_color(config->single_color);
|
||||||
led->color = sinowealth_raw_to_color(config->single_color);
|
|
||||||
else
|
|
||||||
led->color = sinowealth_rbg_to_color(config->single_color);
|
|
||||||
led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode);
|
led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode);
|
||||||
break;
|
break;
|
||||||
case RGB_GLORIOUS:
|
case RGB_GLORIOUS:
|
||||||
@@ -367,243 +328,43 @@ sinowealth_read_profile(struct ratbag_profile *profile)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sinowealth_button_mapping {
|
|
||||||
uint8_t raw;
|
|
||||||
struct ratbag_button_action action;
|
|
||||||
};
|
|
||||||
static struct sinowealth_button_mapping sinowealth_button_mapping[] = {
|
|
||||||
{ 0x01, BUTTON_ACTION_BUTTON(1) },
|
|
||||||
{ 0x02, BUTTON_ACTION_BUTTON(2) },
|
|
||||||
{ 0x04, BUTTON_ACTION_BUTTON(3) },
|
|
||||||
{ 0x08, BUTTON_ACTION_BUTTON(5) },
|
|
||||||
{ 0x10, BUTTON_ACTION_BUTTON(4) },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct ratbag_button_action*
|
|
||||||
sinowealth_raw_to_button_action(uint8_t data)
|
|
||||||
{
|
|
||||||
struct sinowealth_button_mapping *mapping;
|
|
||||||
|
|
||||||
ARRAY_FOR_EACH(sinowealth_button_mapping, mapping) {
|
|
||||||
if (mapping->raw == data)
|
|
||||||
return &mapping->action;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
sinowealth_button_action_to_raw(const struct ratbag_button_action *action)
|
|
||||||
{
|
|
||||||
struct sinowealth_button_mapping *mapping;
|
|
||||||
|
|
||||||
ARRAY_FOR_EACH(sinowealth_button_mapping, mapping) {
|
|
||||||
if (ratbag_button_action_match(&mapping->action, action))
|
|
||||||
return mapping->raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
sinowealth_read_buttons(struct ratbag_profile *profile)
|
|
||||||
{
|
|
||||||
struct ratbag_device *device = profile->device;
|
|
||||||
struct sinowealth_data *drv_data = device->drv_data;
|
|
||||||
struct sinowealth_button_report *buf = &drv_data->buttons;
|
|
||||||
struct ratbag_button *button;
|
|
||||||
struct sinowealth_button_data button_data;
|
|
||||||
enum ratbag_button_type button_types[8] = {RATBAG_BUTTON_TYPE_UNKNOWN};
|
|
||||||
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_BUTTONS};
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
|
|
||||||
if (rc != sizeof(cmd)) {
|
|
||||||
log_error(device->ratbag, "Error while sending read config command: %d\n", rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG, (uint8_t*) buf, SINOWEALTH_CONFIG_SIZE);
|
|
||||||
if (rc != SINOWEALTH_BUTTON_SIZE) {
|
|
||||||
log_error(device->ratbag, "Could not read device button configuration: %d\n", rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_types[0] = RATBAG_BUTTON_TYPE_LEFT;
|
|
||||||
button_types[1] = RATBAG_BUTTON_TYPE_RIGHT;
|
|
||||||
button_types[2] = RATBAG_BUTTON_TYPE_MIDDLE;
|
|
||||||
button_types[3] = RATBAG_BUTTON_TYPE_THUMB;
|
|
||||||
button_types[4] = RATBAG_BUTTON_TYPE_THUMB2;
|
|
||||||
button_types[5] = RATBAG_BUTTON_TYPE_RESOLUTION_UP;
|
|
||||||
button_types[6] = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN;
|
|
||||||
button_types[7] = RATBAG_BUTTON_TYPE_THUMB3;
|
|
||||||
|
|
||||||
ratbag_profile_for_each_button(profile, 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);
|
|
||||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
|
|
||||||
|
|
||||||
button->type = button_types[button->index];
|
|
||||||
|
|
||||||
button_data = buf->buttons[button->index];
|
|
||||||
|
|
||||||
if (button_data.type == SINOWEALTH_BUTTON_TYPE_BUTTON) {
|
|
||||||
const struct ratbag_button_action *action;
|
|
||||||
action = sinowealth_raw_to_button_action(button_data.data[0]);
|
|
||||||
if (action)
|
|
||||||
ratbag_button_set_action(button, action);
|
|
||||||
} else if (button_data.type == SINOWEALTH_BUTTON_TYPE_KEY) {
|
|
||||||
unsigned int key, modifiers;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
key = ratbag_hidraw_get_keycode_from_keyboard_usage(device, button_data.data[1]);
|
|
||||||
|
|
||||||
modifiers = 0;
|
|
||||||
if (button_data.data[0] & 0x01)
|
|
||||||
modifiers |= MODIFIER_LEFTCTRL;
|
|
||||||
if (button_data.data[0] & 0x02)
|
|
||||||
modifiers |= MODIFIER_LEFTSHIFT;
|
|
||||||
if (button_data.data[0] & 0x04)
|
|
||||||
modifiers |= MODIFIER_LEFTALT;
|
|
||||||
if (button_data.data[0] & 0x08)
|
|
||||||
modifiers |= MODIFIER_LEFTMETA;
|
|
||||||
|
|
||||||
rc = ratbag_button_macro_new_from_keycode(button, key, modifiers);
|
|
||||||
if (rc < 0) {
|
|
||||||
log_error(device->ratbag,
|
|
||||||
"Error while reading button %d\n",
|
|
||||||
button->index);
|
|
||||||
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
sinowealth_write_buttons(struct ratbag_profile *profile)
|
|
||||||
{
|
|
||||||
struct ratbag_device *device = profile->device;
|
|
||||||
struct sinowealth_data *drv_data = device->drv_data;
|
|
||||||
struct sinowealth_button_report *buf = &drv_data->buttons;
|
|
||||||
struct ratbag_button *button;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
buf->report_id = 0x04;
|
|
||||||
buf->command_id = 0x12;
|
|
||||||
buf->unknown1[1] = 0x50;
|
|
||||||
|
|
||||||
ratbag_profile_for_each_button(profile, button) {
|
|
||||||
struct sinowealth_button_data *button_data;
|
|
||||||
struct ratbag_button_action *action = &button->action;
|
|
||||||
|
|
||||||
button_data = &buf->buttons[button->index];
|
|
||||||
|
|
||||||
if (action->type == RATBAG_BUTTON_ACTION_TYPE_BUTTON) {
|
|
||||||
button_data->type = SINOWEALTH_BUTTON_TYPE_BUTTON;
|
|
||||||
button_data->data[0] = sinowealth_button_action_to_raw(action);
|
|
||||||
} else if (action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) {
|
|
||||||
unsigned int key, modifiers;
|
|
||||||
|
|
||||||
rc = ratbag_action_keycode_from_macro(action,
|
|
||||||
&key,
|
|
||||||
&modifiers);
|
|
||||||
if (rc < 0) {
|
|
||||||
log_error(device->ratbag,
|
|
||||||
"Error while writing macro for button %d\n",
|
|
||||||
button->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
button_data->type = SINOWEALTH_BUTTON_TYPE_KEY;
|
|
||||||
button_data->data[0] = modifiers;
|
|
||||||
button_data->data[1] = ratbag_hidraw_get_keyboard_usage_from_keycode(device, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
|
|
||||||
(uint8_t*) buf, SINOWEALTH_CONFIG_SIZE);
|
|
||||||
if (rc != SINOWEALTH_CONFIG_SIZE) {
|
|
||||||
log_error(device->ratbag, "Error while writing buttons: %d\n", rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sinowealth_init_profile(struct ratbag_device *device)
|
sinowealth_init_profile(struct ratbag_device *device)
|
||||||
{
|
{
|
||||||
struct ratbag_profile *profile;
|
struct ratbag_profile *profile;
|
||||||
struct ratbag_resolution *resolution;
|
struct ratbag_resolution *resolution;
|
||||||
struct ratbag_led *led;
|
struct ratbag_led *led;
|
||||||
struct sinowealth_data *drv_data = device->drv_data;
|
/* number of DPIs = all DPIs from min to max (inclusive) and "0 DPI" as a special value
|
||||||
struct dpi_range *dpirange = NULL;
|
* to signal a disabled DPI step.
|
||||||
int button_count, led_count;
|
*/
|
||||||
const char *led_type;
|
int num_dpis = (SINOWEALTH_DPI_MAX - SINOWEALTH_DPI_MIN) / SINOWEALTH_DPI_STEP + 2;
|
||||||
|
unsigned int dpis[num_dpis];
|
||||||
|
|
||||||
dpirange = ratbag_device_data_sinowealth_get_dpi_range(device->data);
|
/* TODO: Button remapping */
|
||||||
button_count = ratbag_device_data_sinowealth_get_button_count(device->data);
|
ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, 0, 1);
|
||||||
led_count = ratbag_device_data_sinowealth_get_led_count(device->data);
|
|
||||||
led_type = ratbag_device_data_sinowealth_get_led_type(device->data);
|
|
||||||
|
|
||||||
if (!dpirange)
|
|
||||||
{
|
|
||||||
log_error(device->ratbag, "DpiRange must be defined in .device file\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_count < 0)
|
|
||||||
{
|
|
||||||
log_error(device->ratbag, "Button count must be defined in .device file\n");
|
|
||||||
button_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (led_count < 0)
|
|
||||||
{
|
|
||||||
log_error(device->ratbag, "Led count must be defined in .device file\n");
|
|
||||||
led_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!led_type)
|
|
||||||
log_error(device->ratbag, "Led type must be defined in .device file. Defaulting to RGB.\n");
|
|
||||||
|
|
||||||
if (dpirange->max == 12000)
|
|
||||||
drv_data->sensor = PWM3360;
|
|
||||||
else
|
|
||||||
drv_data->sensor = PWM3389;
|
|
||||||
|
|
||||||
if (led_type && streq(led_type, "RBG"))
|
|
||||||
drv_data->led_type = LED_RBG;
|
|
||||||
else
|
|
||||||
drv_data->led_type = LED_RGB;
|
|
||||||
|
|
||||||
ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, button_count, led_count);
|
|
||||||
|
|
||||||
profile = ratbag_device_get_profile(device, 0);
|
profile = ratbag_device_get_profile(device, 0);
|
||||||
|
|
||||||
|
/* Generate DPI list */
|
||||||
|
dpis[0] = 0; /* 0 DPI = disabled */
|
||||||
|
for (int i = 1; i < num_dpis; i++) {
|
||||||
|
dpis[i] = SINOWEALTH_DPI_MIN + (i - 1) * SINOWEALTH_DPI_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
ratbag_resolution_set_dpi_list_from_range(resolution,
|
ratbag_resolution_set_dpi_list(resolution, dpis, num_dpis);
|
||||||
dpirange->min,
|
|
||||||
dpirange->max);
|
|
||||||
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up LED capabilities */
|
/* Set up LED capabilities */
|
||||||
ratbag_profile_for_each_led(profile, led) {
|
led = ratbag_profile_get_led(profile, 0);
|
||||||
if (led->index == 0) {
|
led->type = RATBAG_LED_TYPE_SIDE;
|
||||||
led->type = RATBAG_LED_TYPE_SIDE;
|
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||||
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||||
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||||
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
ratbag_led_unref(led);
|
||||||
} else {
|
|
||||||
led->type = RATBAG_LED_TYPE_DPI;
|
|
||||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ratbag_profile_unref(profile);
|
ratbag_profile_unref(profile);
|
||||||
}
|
}
|
||||||
@@ -638,12 +399,6 @@ sinowealth_probe(struct ratbag_device *device)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sinowealth_read_buttons(profile);
|
|
||||||
if (rc) {
|
|
||||||
rc = -ENODEV;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -677,10 +432,10 @@ sinowealth_commit(struct ratbag_device *device)
|
|||||||
if (!resolution->dpi_x || !resolution->dpi_y)
|
if (!resolution->dpi_x || !resolution->dpi_y)
|
||||||
continue;
|
continue;
|
||||||
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
||||||
config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(device, resolution->dpi_x);
|
config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(resolution->dpi_x);
|
||||||
config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(device, resolution->dpi_y);
|
config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(resolution->dpi_y);
|
||||||
} else {
|
} else {
|
||||||
config->dpi[resolution->index] = sinowealth_dpi_to_raw(device, resolution->dpi_x);
|
config->dpi[resolution->index] = sinowealth_dpi_to_raw(resolution->dpi_x);
|
||||||
}
|
}
|
||||||
dpi_enabled |= 1<<resolution->index;
|
dpi_enabled |= 1<<resolution->index;
|
||||||
config->dpi_count++;
|
config->dpi_count++;
|
||||||
@@ -695,17 +450,14 @@ sinowealth_commit(struct ratbag_device *device)
|
|||||||
break;
|
break;
|
||||||
case RATBAG_LED_ON:
|
case RATBAG_LED_ON:
|
||||||
config->rgb_effect = RGB_SINGLE;
|
config->rgb_effect = RGB_SINGLE;
|
||||||
if (drv_data->led_type == LED_RGB)
|
config->single_color = sinowealth_color_to_rbg(led->color);
|
||||||
config->single_color = sinowealth_color_to_raw(led->color);
|
|
||||||
else
|
|
||||||
config->single_color = sinowealth_color_to_rbg(led->color);
|
|
||||||
break;
|
break;
|
||||||
case RATBAG_LED_CYCLE:
|
case RATBAG_LED_CYCLE:
|
||||||
config->rgb_effect = RGB_GLORIOUS;
|
config->rgb_effect = RGB_GLORIOUS;
|
||||||
config->glorious_mode = sinowealth_led_to_rgb_mode(led);
|
config->glorious_mode = sinowealth_led_to_rgb_mode(led);
|
||||||
break;
|
break;
|
||||||
case RATBAG_LED_BREATHING:
|
case RATBAG_LED_BREATHING:
|
||||||
config->rgb_effect = RGB_BREATHING7;
|
config->rgb_effect = RGB_BREATHING1;
|
||||||
config->breathing1_color = sinowealth_color_to_rbg(led->color);
|
config->breathing1_color = sinowealth_color_to_rbg(led->color);
|
||||||
config->breathing1_mode = sinowealth_led_to_rgb_mode(led);
|
config->breathing1_mode = sinowealth_led_to_rgb_mode(led);
|
||||||
break;
|
break;
|
||||||
@@ -722,10 +474,8 @@ sinowealth_commit(struct ratbag_device *device)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sinowealth_write_buttons(profile);
|
|
||||||
|
|
||||||
ratbag_profile_unref(profile);
|
ratbag_profile_unref(profile);
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "libratbag-private.h"
|
#include "libratbag-private.h"
|
||||||
#include "libratbag-data.h"
|
#include "libratbag-data.h"
|
||||||
#include "hidpp20.h"
|
#include "hidpp20.h"
|
||||||
|
#include "usb-ids.h"
|
||||||
|
|
||||||
#define GROUP_DEVICE "Device"
|
#define GROUP_DEVICE "Device"
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ enum driver {
|
|||||||
STEELSERIES,
|
STEELSERIES,
|
||||||
SINOWEALTH,
|
SINOWEALTH,
|
||||||
SINOWEALTH_NUBWO,
|
SINOWEALTH_NUBWO,
|
||||||
|
OPENINPUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data_hidpp20 {
|
struct data_hidpp20 {
|
||||||
@@ -82,13 +84,6 @@ struct data_steelseries {
|
|||||||
int short_button;
|
int short_button;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data_sinowealth {
|
|
||||||
int button_count;
|
|
||||||
int led_count;
|
|
||||||
char *led_type;
|
|
||||||
struct dpi_range *dpi_range;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ratbag_device_data {
|
struct ratbag_device_data {
|
||||||
int refcount;
|
int refcount;
|
||||||
char *name;
|
char *name;
|
||||||
@@ -100,7 +95,6 @@ struct ratbag_device_data {
|
|||||||
struct data_hidpp20 hidpp20;
|
struct data_hidpp20 hidpp20;
|
||||||
struct data_hidpp10 hidpp10;
|
struct data_hidpp10 hidpp10;
|
||||||
struct data_steelseries steelseries;
|
struct data_steelseries steelseries;
|
||||||
struct data_sinowealth sinowealth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ratbag_led_type led_types[20];
|
enum ratbag_led_type led_types[20];
|
||||||
@@ -262,50 +256,6 @@ init_data_steelseries(struct ratbag *ratbag,
|
|||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
init_data_sinowealth(struct ratbag *ratbag,
|
|
||||||
GKeyFile *keyfile,
|
|
||||||
struct ratbag_device_data *data)
|
|
||||||
{
|
|
||||||
const char *group = "Driver/sinowealth";
|
|
||||||
GError *error = NULL;
|
|
||||||
_cleanup_(freep) char *str = NULL;
|
|
||||||
int num;
|
|
||||||
char *led_type;
|
|
||||||
|
|
||||||
data->sinowealth.button_count = -1;
|
|
||||||
data->sinowealth.led_count = -1;
|
|
||||||
|
|
||||||
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
|
|
||||||
if (num != 0 || !error)
|
|
||||||
data->sinowealth.button_count = num;
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
|
|
||||||
if (num > 0 || !error)
|
|
||||||
data->sinowealth.led_count = num;
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
|
|
||||||
led_type = g_key_file_get_string(keyfile, group, "LedType", NULL);
|
|
||||||
if (led_type)
|
|
||||||
data->sinowealth.led_type = led_type;
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
|
|
||||||
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
|
|
||||||
if (str)
|
|
||||||
data->sinowealth.dpi_range = dpi_range_from_string(str);
|
|
||||||
error = NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct driver_map {
|
static const struct driver_map {
|
||||||
enum driver map;
|
enum driver map;
|
||||||
const char *driver;
|
const char *driver;
|
||||||
@@ -321,8 +271,9 @@ static const struct driver_map {
|
|||||||
{ LOGITECH_G300, "logitech_g300", NULL},
|
{ LOGITECH_G300, "logitech_g300", NULL},
|
||||||
{ LOGITECH_G600, "logitech_g600", NULL},
|
{ LOGITECH_G600, "logitech_g600", NULL},
|
||||||
{ STEELSERIES, "steelseries", init_data_steelseries },
|
{ STEELSERIES, "steelseries", init_data_steelseries },
|
||||||
{ SINOWEALTH, "sinowealth", init_data_sinowealth },
|
{ SINOWEALTH, "sinowealth", NULL },
|
||||||
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
|
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
|
||||||
|
{ OPENINPUT, "openinput", NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@@ -569,7 +520,9 @@ ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data)
|
if (id->vendor == USB_VENDOR_ID_LOGITECH && (id->product & 0xff00) == 0xc500)
|
||||||
|
log_debug(ratbag, "%04x:%04x is a Logitech receiver, not a device. Ignoring...\n", id->vendor, id->product);
|
||||||
|
else if (!data)
|
||||||
log_debug(ratbag, "No data file found for %04x:%04x\n", id->vendor, id->product);
|
log_debug(ratbag, "No data file found for %04x:%04x\n", id->vendor, id->product);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -722,35 +675,3 @@ ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data
|
|||||||
|
|
||||||
return data->steelseries.short_button;
|
return data->steelseries.short_button;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data)
|
|
||||||
{
|
|
||||||
assert(data->drivertype == SINOWEALTH);
|
|
||||||
|
|
||||||
return data->sinowealth.button_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data)
|
|
||||||
{
|
|
||||||
assert(data->drivertype == SINOWEALTH);
|
|
||||||
|
|
||||||
return data->sinowealth.led_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dpi_range *
|
|
||||||
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data)
|
|
||||||
{
|
|
||||||
assert(data->drivertype == SINOWEALTH);
|
|
||||||
|
|
||||||
return data->sinowealth.dpi_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data)
|
|
||||||
{
|
|
||||||
assert(data->drivertype == SINOWEALTH);
|
|
||||||
|
|
||||||
return data->sinowealth.led_type;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -120,22 +120,3 @@ ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *dat
|
|||||||
|
|
||||||
int
|
int
|
||||||
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data);
|
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data);
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The button count or -1 if not set
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ratbag_device_data_sinowealth_get_button_count(const struct ratbag_device_data *data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The led count or -1 if not set
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ratbag_device_data_sinowealth_get_led_count(const struct ratbag_device_data *data);
|
|
||||||
|
|
||||||
struct dpi_range *
|
|
||||||
ratbag_device_data_sinowealth_get_dpi_range(const struct ratbag_device_data *data);
|
|
||||||
|
|
||||||
const char *
|
|
||||||
ratbag_device_data_sinowealth_get_led_type(const struct ratbag_device_data *data);
|
|
||||||
|
|
||||||
|
|||||||
@@ -597,6 +597,7 @@ extern struct ratbag_driver gskill_driver;
|
|||||||
extern struct ratbag_driver steelseries_driver;
|
extern struct ratbag_driver steelseries_driver;
|
||||||
extern struct ratbag_driver sinowealth_driver;
|
extern struct ratbag_driver sinowealth_driver;
|
||||||
extern struct ratbag_driver sinowealth_nubwo_driver;
|
extern struct ratbag_driver sinowealth_nubwo_driver;
|
||||||
|
extern struct ratbag_driver openinput_driver;
|
||||||
|
|
||||||
struct ratbag_device*
|
struct ratbag_device*
|
||||||
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
||||||
|
|||||||
@@ -604,6 +604,7 @@ ratbag_create_context(const struct ratbag_interface *interface,
|
|||||||
ratbag_register_driver(ratbag, &steelseries_driver);
|
ratbag_register_driver(ratbag, &steelseries_driver);
|
||||||
ratbag_register_driver(ratbag, &sinowealth_driver);
|
ratbag_register_driver(ratbag, &sinowealth_driver);
|
||||||
ratbag_register_driver(ratbag, &sinowealth_nubwo_driver);
|
ratbag_register_driver(ratbag, &sinowealth_nubwo_driver);
|
||||||
|
ratbag_register_driver(ratbag, &openinput_driver);
|
||||||
|
|
||||||
return ratbag;
|
return ratbag;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user