mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
Compare commits
32 Commits
v0.14
...
firmware-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84b1519ebd | ||
|
|
99b8c80aee | ||
|
|
f7c22ed88c | ||
|
|
aeda65cbfa | ||
|
|
ed2439e5e2 | ||
|
|
f407521e8f | ||
|
|
3c4fe23f70 | ||
|
|
9e2ac55dbc | ||
|
|
1e72ebaa7b | ||
|
|
920bc2b993 | ||
|
|
20b573668e | ||
|
|
49acc11db3 | ||
|
|
364e3fd965 | ||
|
|
bb230d390d | ||
|
|
93a076bed9 | ||
|
|
e7b50c9061 | ||
|
|
9d533bdc3e | ||
|
|
d7906b54b4 | ||
|
|
f1eba370ed | ||
|
|
7b5ab2ed99 | ||
|
|
d2d5471836 | ||
|
|
9cfc1e98e3 | ||
|
|
691661276f | ||
|
|
25ed99db84 | ||
|
|
02226d0428 | ||
|
|
f822fb0fa7 | ||
|
|
b88be0add0 | ||
|
|
9fc6d12486 | ||
|
|
0c64dad9e1 | ||
|
|
f61485c603 | ||
|
|
8c295479d8 | ||
|
|
e55b04ec7d |
@@ -156,10 +156,7 @@ ubuntu_settings: &ubuntu_settings
|
|||||||
- run:
|
- run:
|
||||||
name: Install prerequisites
|
name: Install prerequisites
|
||||||
command: |
|
command: |
|
||||||
apt-get update
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt-get install -y software-properties-common
|
|
||||||
apt-get remove -y libnss-systemd
|
|
||||||
add-apt-repository universe
|
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y git ${UBUNTU_DEP_BUILD} ${UBUNTU_DEP_TEST}
|
apt-get install -y git ${UBUNTU_DEP_BUILD} ${UBUNTU_DEP_TEST}
|
||||||
- checkout
|
- checkout
|
||||||
@@ -242,10 +239,10 @@ jobs:
|
|||||||
<<: *arch_settings
|
<<: *arch_settings
|
||||||
docker:
|
docker:
|
||||||
- image: archlinux
|
- image: archlinux
|
||||||
ubuntu_19_10:
|
ubuntu_20_04:
|
||||||
<<: *ubuntu_settings
|
<<: *ubuntu_settings
|
||||||
docker:
|
docker:
|
||||||
- image: ubuntu:19.10
|
- image: ubuntu:20.04
|
||||||
doc_build:
|
doc_build:
|
||||||
<<: *doc_build
|
<<: *doc_build
|
||||||
docker:
|
docker:
|
||||||
@@ -260,7 +257,7 @@ workflows:
|
|||||||
version: 2
|
version: 2
|
||||||
compile_and_test:
|
compile_and_test:
|
||||||
jobs:
|
jobs:
|
||||||
- ubuntu_19_10
|
- ubuntu_20_04
|
||||||
- arch
|
- arch
|
||||||
- fedora_31
|
- fedora_31
|
||||||
- doc_build
|
- doc_build
|
||||||
|
|||||||
5
data/devices/glorious-model-d.device
Normal file
5
data/devices/glorious-model-d.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Glorious Model D
|
||||||
|
DeviceMatch=usb:258a:0033
|
||||||
|
Driver=sinowealth
|
||||||
|
|
||||||
5
data/devices/glorious-model-o.device
Normal file
5
data/devices/glorious-model-o.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Glorious Model O
|
||||||
|
DeviceMatch=usb:258a:0036
|
||||||
|
Driver=sinowealth
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech M720
|
Name=Logitech M720
|
||||||
DeviceMatch=usb:046d:405e
|
DeviceMatch=usb:046d:405e;bluetooth:046d:b015
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Logitech MX Vertical
|
Name=Logitech MX Vertical
|
||||||
DeviceMatch=usb:046d:407b
|
DeviceMatch=bluetooth:046d:b020;usb:046d:407b
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# G102 and G203 (USB)
|
# G102, G103 and G203 (USB)
|
||||||
[Device]
|
[Device]
|
||||||
Name=Logitech Gaming Mouse G102/G103
|
Name=Logitech Gaming Mouse G102/G103/G203
|
||||||
DeviceMatch=usb:046d:c084
|
DeviceMatch=usb:046d:c084;usb:046d:c092
|
||||||
Driver=hidpp20
|
Driver=hidpp20
|
||||||
LedTypes=logo;side;
|
LedTypes=logo;side;
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ Driver=hidpp10
|
|||||||
[Driver/hidpp10]
|
[Driver/hidpp10]
|
||||||
DpiList=400;800;1600;2000
|
DpiList=400;800;1600;2000
|
||||||
Profiles=1
|
Profiles=1
|
||||||
|
ProfileType=G500
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
Name=G9x [Original]
|
Name=G9x [Original]
|
||||||
DeviceMatch=usb:046d:c066
|
DeviceMatch=usb:046d:c066
|
||||||
Driver=hidpp10
|
Driver=hidpp10
|
||||||
|
LedTypes=dpi
|
||||||
|
|
||||||
[Driver/hidpp10]
|
[Driver/hidpp10]
|
||||||
DpiRange=0:5700@23.53
|
DpiRange=200:5700@50
|
||||||
ProfileType=G500
|
ProfileType=G500
|
||||||
Profiles=5
|
Profiles=5
|
||||||
|
Leds=1
|
||||||
|
|||||||
5
data/devices/nubwo-x7-spectrum.device
Normal file
5
data/devices/nubwo-x7-spectrum.device
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[Device]
|
||||||
|
Name=Nubwo x7 spectrum
|
||||||
|
DeviceMatch=usb:258a:0012
|
||||||
|
Driver=sinowealth_nubwo
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[Device]
|
[Device]
|
||||||
Name=Roccat Kone Pure
|
Name=Roccat Kone Pure
|
||||||
DeviceMatch=usb:1e7d:2dc2
|
DeviceMatch=usb:1e7d:2dc2;usb:1e7d:2dbe
|
||||||
Driver=roccat-kone-pure
|
Driver=roccat-kone-pure
|
||||||
|
|||||||
14
doc/dbus.rst
14
doc/dbus.rst
@@ -151,6 +151,20 @@ known to ratbagd.
|
|||||||
Vendor or product IDs of 0 are valid IDs (e.g. used used by test
|
Vendor or product IDs of 0 are valid IDs (e.g. used used by test
|
||||||
devices).
|
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
|
.. attribute:: Name
|
||||||
|
|
||||||
:type: s
|
:type: s
|
||||||
|
|||||||
10
meson.build
10
meson.build
@@ -1,5 +1,5 @@
|
|||||||
project('libratbag', 'c',
|
project('libratbag', 'c',
|
||||||
version : '0.14',
|
version : '0.15',
|
||||||
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.40.0')
|
meson_version : '>= 0.40.0')
|
||||||
@@ -175,6 +175,8 @@ src_libratbag = [
|
|||||||
'src/driver-roccat-kone-pure.c',
|
'src/driver-roccat-kone-pure.c',
|
||||||
'src/driver-gskill.c',
|
'src/driver-gskill.c',
|
||||||
'src/driver-steelseries.c',
|
'src/driver-steelseries.c',
|
||||||
|
'src/driver-sinowealth.c',
|
||||||
|
'src/driver-sinowealth-nubwo.c',
|
||||||
'src/driver-test.c',
|
'src/driver-test.c',
|
||||||
'src/libratbag.c',
|
'src/libratbag.c',
|
||||||
'src/libratbag.h',
|
'src/libratbag.h',
|
||||||
@@ -346,6 +348,9 @@ data_files = files(
|
|||||||
'data/devices/steelseries-rival.device',
|
'data/devices/steelseries-rival.device',
|
||||||
'data/devices/steelseries-sensei-310.device',
|
'data/devices/steelseries-sensei-310.device',
|
||||||
'data/devices/steelseries-sensei-raw.device',
|
'data/devices/steelseries-sensei-raw.device',
|
||||||
|
'data/devices/glorious-model-d.device',
|
||||||
|
'data/devices/glorious-model-o.device',
|
||||||
|
'data/devices/nubwo-x7-spectrum.device',
|
||||||
)
|
)
|
||||||
|
|
||||||
install_data(data_files,
|
install_data(data_files,
|
||||||
@@ -545,16 +550,17 @@ dep_python3 = dependency('', required : false)
|
|||||||
if meson.version().version_compare('<0.48.0')
|
if meson.version().version_compare('<0.48.0')
|
||||||
python = import('python3')
|
python = import('python3')
|
||||||
py3 = python.find_python()
|
py3 = python.find_python()
|
||||||
|
py_version = python.language_version()
|
||||||
else
|
else
|
||||||
pymod = import('python')
|
pymod = import('python')
|
||||||
py3 = pymod.find_installation()
|
py3 = pymod.find_installation()
|
||||||
if meson.version().version_compare('>= 0.53.0')
|
if meson.version().version_compare('>= 0.53.0')
|
||||||
dep_python3 = py3.dependency(embed : true)
|
dep_python3 = py3.dependency(embed : true)
|
||||||
endif
|
endif
|
||||||
|
py_version = py3.language_version()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# From python 3.8 we neeed python3-embed
|
# From python 3.8 we neeed python3-embed
|
||||||
py_version = py3.language_version()
|
|
||||||
embed = py_version.version_compare('>= 3.8') ? '-embed' : ''
|
embed = py_version.version_compare('>= 3.8') ? '-embed' : ''
|
||||||
if not dep_python3.found()
|
if not dep_python3.found()
|
||||||
dep_python3 = dependency('python-@0@@1@'.format(py_version, embed), required : false)
|
dep_python3 = dependency('python-@0@@1@'.format(py_version, embed), required : false)
|
||||||
|
|||||||
@@ -220,9 +220,45 @@ ratbag_device_get_model(sd_bus *bus,
|
|||||||
return sd_bus_message_append(reply, "s", model);
|
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[] = {
|
const sd_bus_vtable ratbagd_device_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Model", "s", ratbag_device_get_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
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("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_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),
|
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
|||||||
@@ -573,7 +573,8 @@ hidpp10drv_commit(struct ratbag_device *device)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
p.enabled = profile->is_enabled;
|
p.enabled = profile->is_enabled;
|
||||||
strncpy_safe((char*)p.name, profile->name, 24);
|
if (profile->name != NULL)
|
||||||
|
strncpy_safe((char*)p.name, profile->name, 24);
|
||||||
|
|
||||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
p.dpi_modes[resolution->index].xres = resolution->dpi_x;
|
p.dpi_modes[resolution->index].xres = resolution->dpi_x;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#define LOGITECH_G300_BUTTON_MAX 8
|
#define LOGITECH_G300_BUTTON_MAX 8
|
||||||
#define LOGITECH_G300_NUM_DPI 4
|
#define LOGITECH_G300_NUM_DPI 4
|
||||||
#define LOGITECH_G300_NUM_LED 1
|
#define LOGITECH_G300_NUM_LED 1
|
||||||
#define LOGITECH_G300_DPI_MIN 250
|
#define LOGITECH_G300_DPI_MIN 100
|
||||||
#define LOGITECH_G300_DPI_MAX 2500
|
#define LOGITECH_G300_DPI_MAX 2500
|
||||||
|
|
||||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE 0xF0
|
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE 0xF0
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
|
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
|
||||||
|
|
||||||
struct logitech_g300_resolution {
|
struct logitech_g300_resolution {
|
||||||
uint8_t dpi :7; /* Range 1-10. dpi = 250*value */
|
uint8_t dpi :7; /* Range 1-10. dpi = 100*value */
|
||||||
uint8_t is_default :1;
|
uint8_t is_default :1;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
@@ -449,11 +449,10 @@ logitech_g300_read_profile(struct ratbag_profile *profile)
|
|||||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
struct logitech_g300_resolution *res =
|
struct logitech_g300_resolution *res =
|
||||||
&report->dpi_levels[resolution->index];
|
&report->dpi_levels[resolution->index];
|
||||||
unsigned int dpis[10] = { 250, 500, 750, 1000, 1250, 1500, 1750,
|
unsigned int dpis[49] = { 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950, 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350, 2400, 2450, 2500, };
|
||||||
2000, 2250, 2500 };
|
|
||||||
|
|
||||||
resolution->dpi_x = res->dpi * 250;
|
resolution->dpi_x = res->dpi * 50;
|
||||||
resolution->dpi_y = res->dpi * 250;
|
resolution->dpi_y = res->dpi * 50;
|
||||||
resolution->is_default = res->is_default;
|
resolution->is_default = res->is_default;
|
||||||
resolution->is_active = res->is_default;
|
resolution->is_active = res->is_default;
|
||||||
|
|
||||||
@@ -546,7 +545,7 @@ logitech_g300_write_profile(struct ratbag_profile *profile)
|
|||||||
struct logitech_g300_resolution *res =
|
struct logitech_g300_resolution *res =
|
||||||
&report->dpi_levels[resolution->index];
|
&report->dpi_levels[resolution->index];
|
||||||
|
|
||||||
res->dpi = resolution->dpi_x / 250;
|
res->dpi = resolution->dpi_x / 50;
|
||||||
res->is_default = resolution->is_default;
|
res->is_default = resolution->is_default;
|
||||||
|
|
||||||
if (profile->is_active && resolution->is_active)
|
if (profile->is_active && resolution->is_active)
|
||||||
|
|||||||
@@ -835,7 +835,7 @@ roccat_remove(struct ratbag_device *device)
|
|||||||
|
|
||||||
struct ratbag_driver roccat_driver = {
|
struct ratbag_driver roccat_driver = {
|
||||||
.name = "Roccat Kone Pure",
|
.name = "Roccat Kone Pure",
|
||||||
.id = "roccat",
|
.id = "roccat-kone-pure",
|
||||||
.probe = roccat_probe,
|
.probe = roccat_probe,
|
||||||
.remove = roccat_remove,
|
.remove = roccat_remove,
|
||||||
.write_profile = roccat_write_profile,
|
.write_profile = roccat_write_profile,
|
||||||
|
|||||||
319
src/driver-sinowealth-nubwo.c
Normal file
319
src/driver-sinowealth-nubwo.c
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 Pipat Saengow
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libratbag-enums.h"
|
||||||
|
#include "libratbag-hidraw.h"
|
||||||
|
#include "libratbag-private.h"
|
||||||
|
#include "libratbag-util.h"
|
||||||
|
#include "shared-macro.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SINOWEALTHNUBWO_PERF_CMD_REPORTID 0x02
|
||||||
|
#define SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID 0x03
|
||||||
|
#define SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID 0x04
|
||||||
|
|
||||||
|
#define SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE 256
|
||||||
|
#define SINOWEALTHNUBWO_GET_FIRMWARE_MSGOFFSET 48
|
||||||
|
|
||||||
|
#define SINOWEALTHNUBWO_PERF_CMD_MSGSIZE 16
|
||||||
|
|
||||||
|
// Actually more but I only implemented one
|
||||||
|
#define SINOWEALTHNUBWO_NUM_PROFILES 1
|
||||||
|
#define SINOWEALTHNUBWO_NUM_RESOLUTIONS 1
|
||||||
|
// Actually 8 but I am not going to implement macros.
|
||||||
|
#define SINOWEALTHNUBWO_NUM_BUTTONS 0
|
||||||
|
#define SINOWEALTHNUBWO_NUM_LEDS 1
|
||||||
|
|
||||||
|
//Magic set_feature that must be called before requesting firmware string
|
||||||
|
static uint8_t PREFIRMWARE_QUERY_MSG[] = {0x02, 0x01, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
static unsigned int REPORT_RATES[] = { 125, 250, 333, 500, 1000 };
|
||||||
|
static uint8_t REPORT_RATES_ENCODED[] = {0x08, 0x04, 0x03, 0x02, 0x01};
|
||||||
|
static uint8_t REPORT_RATES_CMD[] = {0x02, 0x06, 0xbb, 0xaa, 0x28, 0x00, 0x01, 0x00};
|
||||||
|
|
||||||
|
static unsigned int DPILIST[] = { 1000, 2000, 3000, 5000, 15000};
|
||||||
|
static uint8_t DPI_ENCODED[] = {0x04, 0x03, 0x02, 0x01, 0x00};
|
||||||
|
static uint8_t DPI_CMD[] = { 0x02, 0x06, 0xbb, 0xaa, 0x32, 0x00, 0x01, 0x00 };
|
||||||
|
|
||||||
|
enum
|
||||||
|
sinowealthnubwo_color_mode {
|
||||||
|
SINOWEALTHNUBWO_COLOR_OFF = 0x00,
|
||||||
|
SINOWEALTHNUBWO_COLOR_ON = 0x01,
|
||||||
|
SINOWEALTHNUBWO_COLOR_BREATHING = 0x02,
|
||||||
|
SINOWEALTHNUBWO_COLOR_COLOR_SHIFT = 0x03,
|
||||||
|
SINOWEALTHNUBWO_COLOR_SPECTRUM = 0x04,
|
||||||
|
SINOWEALTHNUBWO_COLOR_MARQUEE = 0x05,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct
|
||||||
|
sinowealthnubwo_aesthetic_report {
|
||||||
|
uint8_t report_id; //0x03
|
||||||
|
uint8_t cmd[7];
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t color_mode;
|
||||||
|
uint8_t padzero; // 0x00
|
||||||
|
uint8_t brightness; // 0x01 to 0x03
|
||||||
|
uint8_t tempo; // 0x05 0x03 0x01
|
||||||
|
uint8_t padzero2[16*3+1];
|
||||||
|
} __packed__;
|
||||||
|
|
||||||
|
static uint8_t AESTHETIC_CMD[] = {0x06, 0xbb, 0xaa, 0x2a, 0x00, 0x0a, 0x00};
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_test_hidraw(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID)
|
||||||
|
&& ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID)
|
||||||
|
&& ratbag_hidraw_has_report(device, SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_get_firmware_string(struct ratbag_device *device, char **output)
|
||||||
|
{
|
||||||
|
uint8_t buff[SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE + 1] = {0}; //Purposefully overalloacate to prevent buffer overrun
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, PREFIRMWARE_QUERY_MSG, ARRAY_LENGTH(PREFIRMWARE_QUERY_MSG));
|
||||||
|
if (size < 0) {
|
||||||
|
log_error(device->ratbag, "Error while sending pre-firmware request message: %d\n", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = ratbag_hidraw_get_feature_report(device, SINOWEALTHNUBWO_GET_FIRMWARE_CMD_REPORTID, buff, SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE);
|
||||||
|
if (size != SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE) {
|
||||||
|
log_error(device->ratbag ,"Firmware report reply size mismatch expected %d got %d\n", SINOWEALTHNUBWO_GET_FIRMWARE_MSGSIZE, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = strdup_ascii_only((char *) buff + SINOWEALTHNUBWO_GET_FIRMWARE_MSGOFFSET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_probe(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct ratbag_profile *profile;
|
||||||
|
struct ratbag_resolution *resolution;
|
||||||
|
struct ratbag_led *led;
|
||||||
|
|
||||||
|
error = ratbag_find_hidraw(device, sinowealthnubwo_test_hidraw);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
char *fwstr;
|
||||||
|
error = sinowealth_get_firmware_string(device, &fwstr);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
log_info(device->ratbag, "Firmware: %s\n", fwstr);
|
||||||
|
free(fwstr);
|
||||||
|
|
||||||
|
ratbag_device_init_profiles(device,
|
||||||
|
SINOWEALTHNUBWO_NUM_PROFILES,
|
||||||
|
SINOWEALTHNUBWO_NUM_RESOLUTIONS,
|
||||||
|
SINOWEALTHNUBWO_NUM_BUTTONS,
|
||||||
|
SINOWEALTHNUBWO_NUM_LEDS);
|
||||||
|
|
||||||
|
ratbag_device_for_each_profile(device, profile) {
|
||||||
|
profile->is_active = true;
|
||||||
|
|
||||||
|
ratbag_profile_set_cap(profile, RATBAG_PROFILE_CAP_WRITE_ONLY);
|
||||||
|
ratbag_profile_set_report_rate_list(profile, REPORT_RATES, ARRAY_LENGTH(REPORT_RATES));
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
ratbag_resolution_set_dpi_list(resolution, DPILIST, ARRAY_LENGTH(DPILIST));
|
||||||
|
resolution->dpi_x = resolution->dpi_y = DPILIST[ARRAY_LENGTH(DPILIST)-1];
|
||||||
|
resolution->is_active = true;
|
||||||
|
resolution->is_default = true;
|
||||||
|
}
|
||||||
|
ratbag_profile_for_each_led(profile, led) {
|
||||||
|
led->mode = RATBAG_LED_OFF;
|
||||||
|
led->color.red = led->color.green = led->color.blue = 0xFF;
|
||||||
|
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||||
|
led->type = RATBAG_LED_TYPE_SIDE;
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||||
|
//Actually more
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
encode_dpi(unsigned int dpi)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAY_LENGTH(DPILIST); i++)
|
||||||
|
if (DPILIST[i] == dpi)
|
||||||
|
return DPI_ENCODED[i];
|
||||||
|
return DPI_ENCODED[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
encode_report_rate(unsigned int reportrate)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAY_LENGTH(REPORT_RATES); i++)
|
||||||
|
if (REPORT_RATES[i] == reportrate)
|
||||||
|
return REPORT_RATES_ENCODED[i];
|
||||||
|
return REPORT_RATES_ENCODED[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_set_dpi(struct ratbag_device *device, int dpi)
|
||||||
|
{
|
||||||
|
uint8_t buf[SINOWEALTHNUBWO_PERF_CMD_MSGSIZE] = {0};
|
||||||
|
memcpy(buf, DPI_CMD, ARRAY_LENGTH(DPI_CMD));
|
||||||
|
buf[ARRAY_LENGTH(DPI_CMD)] = encode_dpi(dpi);
|
||||||
|
int error = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, buf, SINOWEALTHNUBWO_PERF_CMD_MSGSIZE);
|
||||||
|
if (error < 0)
|
||||||
|
return error;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_set_report_rate(struct ratbag_device *device, int reportrate)
|
||||||
|
{
|
||||||
|
uint8_t buf[SINOWEALTHNUBWO_PERF_CMD_MSGSIZE] = {0};
|
||||||
|
memcpy(buf, REPORT_RATES_CMD, ARRAY_LENGTH(REPORT_RATES_CMD));
|
||||||
|
buf[ARRAY_LENGTH(REPORT_RATES_CMD)] = encode_report_rate(reportrate);
|
||||||
|
int error = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_PERF_CMD_REPORTID, buf, SINOWEALTHNUBWO_PERF_CMD_MSGSIZE);
|
||||||
|
if (error < 0)
|
||||||
|
return error;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum sinowealthnubwo_color_mode encode_color(enum ratbag_led_mode mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case RATBAG_LED_OFF:
|
||||||
|
return SINOWEALTHNUBWO_COLOR_OFF;
|
||||||
|
case RATBAG_LED_ON:
|
||||||
|
return SINOWEALTHNUBWO_COLOR_ON;
|
||||||
|
case RATBAG_LED_CYCLE:
|
||||||
|
return SINOWEALTHNUBWO_COLOR_MARQUEE;
|
||||||
|
case RATBAG_LED_BREATHING:
|
||||||
|
return SINOWEALTHNUBWO_COLOR_BREATHING;
|
||||||
|
default:
|
||||||
|
return SINOWEALTHNUBWO_COLOR_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t normalize_duration(int duration)
|
||||||
|
{
|
||||||
|
const int MAX_DURATION = 10000;
|
||||||
|
const uint8_t avail_dura[] = {0x01, 0x03, 0x05};
|
||||||
|
const int selected = (duration * ((int) ARRAY_LENGTH(avail_dura)) - 1) / MAX_DURATION;
|
||||||
|
return avail_dura[selected];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t normalize_brightness(int brightness)
|
||||||
|
{
|
||||||
|
const int MAX_BRIGHTNESS = 255;
|
||||||
|
return 1 + (brightness * 3 - 1) / MAX_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_set_aesthetic(struct ratbag_device *device, struct ratbag_led *led) {
|
||||||
|
struct sinowealthnubwo_aesthetic_report report;
|
||||||
|
memset(&report, 0, sizeof(struct sinowealthnubwo_aesthetic_report));
|
||||||
|
report.report_id = SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID;
|
||||||
|
memcpy(report.cmd, AESTHETIC_CMD, ARRAY_LENGTH(AESTHETIC_CMD));
|
||||||
|
report.r = led->color.red;
|
||||||
|
report.g = led->color.green;
|
||||||
|
report.b = led->color.blue;
|
||||||
|
report.color_mode = encode_color(led->mode);
|
||||||
|
report.tempo = normalize_duration(led->ms);
|
||||||
|
report.brightness = normalize_brightness(led->brightness);
|
||||||
|
|
||||||
|
int size = ratbag_hidraw_set_feature_report(device, SINOWEALTHNUBWO_AESTHETIC_CMD_REPORTID, (uint8_t *) &report, sizeof(report));
|
||||||
|
if (size < 0)
|
||||||
|
return size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_write_profile(struct ratbag_device *device, struct ratbag_profile *profile)
|
||||||
|
{
|
||||||
|
struct ratbag_resolution *resolution;
|
||||||
|
struct ratbag_led *led;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
log_debug(device->ratbag, "Writing updates\n");
|
||||||
|
|
||||||
|
log_debug(device->ratbag, "Setting report rate\n");
|
||||||
|
error = sinowealthnubwo_set_report_rate(device, profile->hz);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
if (!resolution->dirty)
|
||||||
|
continue;
|
||||||
|
log_debug(device->ratbag, "Setting DPI\n");
|
||||||
|
error = sinowealthnubwo_set_dpi(device, resolution->dpi_x);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ratbag_profile_for_each_led(profile, led) {
|
||||||
|
if (!led->dirty)
|
||||||
|
continue;
|
||||||
|
log_debug(device->ratbag, "Setting aesthetic\n");
|
||||||
|
error = sinowealthnubwo_set_aesthetic(device, led);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealthnubwo_commit(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
struct ratbag_profile *profile;
|
||||||
|
list_for_each(profile, &device->profiles, link) {
|
||||||
|
if (!profile->dirty) continue;
|
||||||
|
|
||||||
|
int error = sinowealthnubwo_write_profile(device, profile);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sinowealthnubwo_remove(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
ratbag_close_hidraw(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ratbag_driver sinowealth_nubwo_driver = {
|
||||||
|
.name = "Sinowealth Nubwo",
|
||||||
|
.id = "sinowealth_nubwo",
|
||||||
|
.probe = sinowealthnubwo_probe,
|
||||||
|
.remove = sinowealthnubwo_remove,
|
||||||
|
.commit = sinowealthnubwo_commit,
|
||||||
|
};
|
||||||
480
src/driver-sinowealth.c
Normal file
480
src/driver-sinowealth.c
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 Marian Beermann
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libratbag-private.h"
|
||||||
|
#include "libratbag-hidraw.h"
|
||||||
|
|
||||||
|
#define SINOWEALTH_REPORT_ID_CONFIG 0x4
|
||||||
|
#define SINOWEALTH_REPORT_ID_CMD 0x5
|
||||||
|
#define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1
|
||||||
|
#define SINOWEALTH_CMD_GET_CONFIG 0x11
|
||||||
|
#define SINOWEALTH_CONFIG_SIZE 520
|
||||||
|
#define SINOWEALTH_CONFIG_SIZE_USED 131
|
||||||
|
|
||||||
|
#define SINOWEALTH_XY_INDEPENDENT 0x80
|
||||||
|
|
||||||
|
/* The PC software only goes down to 400, but the PMW3360 doesn't care */
|
||||||
|
#define SINOWEALTH_DPI_MIN 100
|
||||||
|
#define SINOWEALTH_DPI_MAX 12000
|
||||||
|
#define SINOWEALTH_DPI_STEP 100
|
||||||
|
|
||||||
|
/* other models might have up to eight */
|
||||||
|
#define SINOWEALTH_NUM_DPIS 6
|
||||||
|
|
||||||
|
#define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0
|
||||||
|
#define SINOWEALTH_RGB_SPEED_BITS 0x0F
|
||||||
|
|
||||||
|
struct sinowealth_rgb8 {
|
||||||
|
uint8_t r, g, b;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
_Static_assert(sizeof(struct sinowealth_rgb8) == 3, "Invalid size");
|
||||||
|
|
||||||
|
struct sinowealth_rbg8 {
|
||||||
|
uint8_t r, b, g;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
_Static_assert(sizeof(struct sinowealth_rbg8) == 3, "Invalid size");
|
||||||
|
|
||||||
|
enum rgb_effect {
|
||||||
|
RGB_OFF = 0,
|
||||||
|
RGB_GLORIOUS = 0x1, /* unicorn mode */
|
||||||
|
RGB_SINGLE = 0x2, /* single constant color */
|
||||||
|
RGB_BREATHING = 0x5, /* Full RGB breathing */
|
||||||
|
RGB_BREATHING7 = 0x3, /* breathing with seven user-defined colors */
|
||||||
|
RGB_BREATHING1 = 0xa, /* single color breathing */
|
||||||
|
RGB_TAIL = 0x4,
|
||||||
|
RGB_RAVE = 0x7,
|
||||||
|
RGB_WAVE = 0x9
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sinowealth_config_report {
|
||||||
|
uint8_t report_id; /* SINOWEALTH_REPORT_ID_CONFIG */
|
||||||
|
uint8_t command_id;
|
||||||
|
uint8_t unknown1;
|
||||||
|
/* always 0 when config is read from device,
|
||||||
|
* has to be 0x7b when writing config to device
|
||||||
|
*/
|
||||||
|
uint8_t config_write;
|
||||||
|
uint8_t unknown2[6];
|
||||||
|
/* 0x80 - SINOWEALTH_XY_INDEPENDENT */
|
||||||
|
uint8_t config;
|
||||||
|
uint8_t dpi_count:4;
|
||||||
|
uint8_t active_dpi:4;
|
||||||
|
/* bit set: disabled, unset: enabled
|
||||||
|
* this structure has support for eight DPI slots,
|
||||||
|
* but the glorious software only exposes six
|
||||||
|
*/
|
||||||
|
uint8_t dpi_enabled;
|
||||||
|
/* DPI/CPI is encoded in the way the PMW3360 sensor accepts it
|
||||||
|
* value = (DPI - 100) / 100
|
||||||
|
* If XY are identical, dpi[0-6] contain the sensitivities,
|
||||||
|
* while in XY independent mode each entry takes two chars for X and Y.
|
||||||
|
*/
|
||||||
|
uint8_t dpi[16];
|
||||||
|
struct sinowealth_rgb8 dpi_color[8];
|
||||||
|
uint8_t rgb_effect; /* see enum rgb_effect */
|
||||||
|
/* 0x40 - brightness (constant)
|
||||||
|
* 0x1/2/3 - speed
|
||||||
|
*/
|
||||||
|
uint8_t glorious_mode;
|
||||||
|
uint8_t glorious_direction;
|
||||||
|
uint8_t single_mode;
|
||||||
|
struct sinowealth_rbg8 single_color;
|
||||||
|
/* 0x40 - brightness (constant)
|
||||||
|
* 0x1/2/3 - speed
|
||||||
|
*/
|
||||||
|
uint8_t breathing7_mode;
|
||||||
|
uint8_t breathing7_colorcount; /* 7, constant */
|
||||||
|
struct sinowealth_rbg8 breathing7_colors[7];
|
||||||
|
/* 0x10/20/30/40 - brightness
|
||||||
|
* 0x1/2/3 - speed
|
||||||
|
*/
|
||||||
|
uint8_t tail_mode;
|
||||||
|
uint8_t unknown3[33];
|
||||||
|
/* 0x10/20/30/40 - brightness
|
||||||
|
* 0x1/2/3 - speed
|
||||||
|
*/
|
||||||
|
uint8_t rave_mode;
|
||||||
|
struct sinowealth_rbg8 rave_colors[2];
|
||||||
|
/* 0x10/20/30/40 - brightness
|
||||||
|
* 0x1/2/3 - speed
|
||||||
|
*/
|
||||||
|
uint8_t wave_mode;
|
||||||
|
/* 0x1/2/3 - speed */
|
||||||
|
uint8_t breathing1_mode;
|
||||||
|
struct sinowealth_rbg8 breathing1_color;
|
||||||
|
uint8_t unknown4;
|
||||||
|
/* 0x1 - 2 mm
|
||||||
|
* 0x2 - 3 mm
|
||||||
|
*/
|
||||||
|
uint8_t lift_off_distance;
|
||||||
|
uint8_t padding[SINOWEALTH_CONFIG_SIZE - SINOWEALTH_CONFIG_SIZE_USED];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
_Static_assert(sizeof(struct sinowealth_config_report) == SINOWEALTH_CONFIG_SIZE, "Invalid size");
|
||||||
|
|
||||||
|
struct sinowealth_data {
|
||||||
|
/* this is kinda unnecessary at this time, but all the other drivers do it too ;) */
|
||||||
|
struct sinowealth_config_report config;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_raw_to_dpi(int raw)
|
||||||
|
{
|
||||||
|
return (raw + 1) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_dpi_to_raw(int dpi)
|
||||||
|
{
|
||||||
|
assert(dpi >= SINOWEALTH_DPI_MIN && dpi <= SINOWEALTH_DPI_MAX);
|
||||||
|
return dpi / 100 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ratbag_color
|
||||||
|
sinowealth_raw_to_color(struct sinowealth_rgb8 raw)
|
||||||
|
{
|
||||||
|
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sinowealth_rgb8
|
||||||
|
sinowealth_color_to_raw(struct ratbag_color color)
|
||||||
|
{
|
||||||
|
return (struct sinowealth_rgb8) {.r = color.red, .g = color.green, .b = color.blue};
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ratbag_color
|
||||||
|
sinowealth_rbg_to_color(struct sinowealth_rbg8 raw)
|
||||||
|
{
|
||||||
|
return (struct ratbag_color) {.red = raw.r, .green = raw.g, .blue = raw.b};
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sinowealth_rbg8
|
||||||
|
sinowealth_color_to_rbg(struct ratbag_color color)
|
||||||
|
{
|
||||||
|
return (struct sinowealth_rbg8) {.r = color.red, .g = color.green, .b = color.blue};
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_rgb_mode_to_brightness(uint8_t mode)
|
||||||
|
{
|
||||||
|
/* brightness is 0-4 in the upper nibble of mode,
|
||||||
|
* while libratbag uses 0-255.
|
||||||
|
*/
|
||||||
|
return min((mode >> 4) * 64, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
sinowealth_brightness_to_rgb_mode(int brightness)
|
||||||
|
{
|
||||||
|
/* convert 0-255 to 0-4 in the upper nibble of mode */
|
||||||
|
return ((brightness + 1) / 64) << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_rgb_mode_to_duration(uint8_t mode)
|
||||||
|
{
|
||||||
|
switch (mode & SINOWEALTH_RGB_SPEED_BITS) {
|
||||||
|
case 0: return 10000; /* static: does not translate to duration */
|
||||||
|
case 1: return 1500;
|
||||||
|
case 2: return 1000;
|
||||||
|
case 3: return 500;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
sinowealth_duration_to_rgb_mode(int duration_ms)
|
||||||
|
{
|
||||||
|
uint8_t mode = 0;
|
||||||
|
if (duration_ms <= 500) {
|
||||||
|
mode |= 3;
|
||||||
|
} else if (duration_ms <= 1000) {
|
||||||
|
mode |= 2;
|
||||||
|
} else {
|
||||||
|
mode |= 1;
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sinowealth_set_led_from_rgb_mode(struct ratbag_led *led, uint8_t mode)
|
||||||
|
{
|
||||||
|
led->brightness = sinowealth_rgb_mode_to_brightness(mode);
|
||||||
|
led->ms = sinowealth_rgb_mode_to_duration(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
sinowealth_led_to_rgb_mode(const struct ratbag_led *led)
|
||||||
|
{
|
||||||
|
uint8_t mode;
|
||||||
|
mode = sinowealth_brightness_to_rgb_mode(led->brightness);
|
||||||
|
mode |= sinowealth_duration_to_rgb_mode(led->ms);
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_read_profile(struct ratbag_profile *profile)
|
||||||
|
{
|
||||||
|
struct ratbag_device *device = profile->device;
|
||||||
|
struct sinowealth_data *drv_data = device->drv_data;
|
||||||
|
struct sinowealth_config_report *config = &drv_data->config;
|
||||||
|
struct ratbag_resolution *resolution;
|
||||||
|
struct ratbag_led *led;
|
||||||
|
unsigned int hz = 1000; /* TODO */
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_CONFIG};
|
||||||
|
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd));
|
||||||
|
if (rc != sizeof(cmd)) {
|
||||||
|
log_error(device->ratbag, "Error while sending read config command: %d\n", rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
|
||||||
|
(uint8_t*) config, SINOWEALTH_CONFIG_SIZE);
|
||||||
|
/* The GET_FEATURE report length has to be 520, but the actual data returned is less */
|
||||||
|
if (rc != SINOWEALTH_CONFIG_SIZE_USED) {
|
||||||
|
log_error(device->ratbag, "Could not read device configuration: %d\n", rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
ratbag_profile_set_report_rate_list(profile, &hz, 1);
|
||||||
|
ratbag_profile_set_report_rate(profile, hz);
|
||||||
|
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
||||||
|
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2]);
|
||||||
|
resolution->dpi_y = sinowealth_raw_to_dpi(config->dpi[resolution->index * 2 + 1]);
|
||||||
|
} else {
|
||||||
|
resolution->dpi_x = sinowealth_raw_to_dpi(config->dpi[resolution->index]);
|
||||||
|
resolution->dpi_y = resolution->dpi_x;
|
||||||
|
}
|
||||||
|
if (config->dpi_enabled & (1<<resolution->index)) {
|
||||||
|
/* DPI step is disabled, fake it by setting DPI to 0 */
|
||||||
|
resolution->dpi_x = 0;
|
||||||
|
resolution->dpi_y = 0;
|
||||||
|
}
|
||||||
|
resolution->is_active = resolution->index == config->active_dpi - 1;
|
||||||
|
resolution->is_default = resolution->is_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Body lighting */
|
||||||
|
led = ratbag_profile_get_led(profile, 0);
|
||||||
|
switch (config->rgb_effect) {
|
||||||
|
case RGB_OFF:
|
||||||
|
led->mode = RATBAG_LED_OFF;
|
||||||
|
break;
|
||||||
|
case RGB_SINGLE:
|
||||||
|
led->mode = RATBAG_LED_ON;
|
||||||
|
led->color = sinowealth_rbg_to_color(config->single_color);
|
||||||
|
led->brightness = sinowealth_rgb_mode_to_brightness(config->single_mode);
|
||||||
|
break;
|
||||||
|
case RGB_GLORIOUS:
|
||||||
|
case RGB_BREATHING:
|
||||||
|
case RGB_BREATHING7:
|
||||||
|
case RGB_TAIL:
|
||||||
|
case RGB_RAVE:
|
||||||
|
case RGB_WAVE:
|
||||||
|
led->mode = RATBAG_LED_CYCLE;
|
||||||
|
sinowealth_set_led_from_rgb_mode(led, config->glorious_mode);
|
||||||
|
break;
|
||||||
|
case RGB_BREATHING1:
|
||||||
|
led->mode = RATBAG_LED_BREATHING;
|
||||||
|
led->color = sinowealth_rbg_to_color(config->breathing1_color);
|
||||||
|
sinowealth_set_led_from_rgb_mode(led, config->breathing1_mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ratbag_led_unref(led);
|
||||||
|
|
||||||
|
profile->is_active = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sinowealth_init_profile(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
struct ratbag_profile *profile;
|
||||||
|
struct ratbag_resolution *resolution;
|
||||||
|
struct ratbag_led *led;
|
||||||
|
/* number of DPIs = all DPIs from min to max (inclusive) and "0 DPI" as a special value
|
||||||
|
* to signal a disabled DPI step.
|
||||||
|
*/
|
||||||
|
int num_dpis = (SINOWEALTH_DPI_MAX - SINOWEALTH_DPI_MIN) / SINOWEALTH_DPI_STEP + 2;
|
||||||
|
unsigned int dpis[num_dpis];
|
||||||
|
|
||||||
|
/* TODO: Button remapping */
|
||||||
|
ratbag_device_init_profiles(device, 1, SINOWEALTH_NUM_DPIS, 0, 1);
|
||||||
|
|
||||||
|
profile = ratbag_device_get_profile(device, 0);
|
||||||
|
|
||||||
|
/* Generate DPI list */
|
||||||
|
dpis[0] = 0; /* 0 DPI = disabled */
|
||||||
|
for (int i = 1; i < num_dpis; i++) {
|
||||||
|
dpis[i] = SINOWEALTH_DPI_MIN + (i - 1) * SINOWEALTH_DPI_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
ratbag_resolution_set_dpi_list(resolution, dpis, num_dpis);
|
||||||
|
ratbag_resolution_set_cap(resolution, RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up LED capabilities */
|
||||||
|
led = ratbag_profile_get_led(profile, 0);
|
||||||
|
led->type = RATBAG_LED_TYPE_SIDE;
|
||||||
|
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||||
|
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||||
|
ratbag_led_unref(led);
|
||||||
|
|
||||||
|
ratbag_profile_unref(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_test_hidraw(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
/* Only the keyboard interface has this report */
|
||||||
|
return ratbag_hidraw_has_report(device, SINOWEALTH_REPORT_ID_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_probe(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct sinowealth_data *drv_data = 0;
|
||||||
|
struct ratbag_profile *profile = 0;
|
||||||
|
|
||||||
|
rc = ratbag_find_hidraw(device, sinowealth_test_hidraw);
|
||||||
|
if (rc)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
drv_data = zalloc(sizeof(*drv_data));
|
||||||
|
ratbag_set_drv_data(device, drv_data);
|
||||||
|
|
||||||
|
sinowealth_init_profile(device);
|
||||||
|
|
||||||
|
profile = ratbag_device_get_profile(device, 0);
|
||||||
|
rc = sinowealth_read_profile(profile);
|
||||||
|
if (rc) {
|
||||||
|
rc = -ENODEV;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(drv_data);
|
||||||
|
ratbag_set_drv_data(device, 0);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sinowealth_commit(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
struct ratbag_profile *profile = ratbag_device_get_profile(device, 0);
|
||||||
|
struct sinowealth_data *drv_data = device->drv_data;
|
||||||
|
struct sinowealth_config_report *config = &drv_data->config;
|
||||||
|
struct ratbag_resolution *resolution;
|
||||||
|
struct ratbag_led *led;
|
||||||
|
int rc;
|
||||||
|
uint8_t dpi_enabled = 0;
|
||||||
|
|
||||||
|
/* Check if any resolution requires independent XY DPIs */
|
||||||
|
config->config &= ~SINOWEALTH_XY_INDEPENDENT;
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
if (resolution->dpi_x != resolution->dpi_y && resolution->dpi_x && resolution->dpi_y) {
|
||||||
|
config->config |= SINOWEALTH_XY_INDEPENDENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config->dpi_count = 0;
|
||||||
|
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||||
|
if (!resolution->dpi_x || !resolution->dpi_y)
|
||||||
|
continue;
|
||||||
|
if (config->config & SINOWEALTH_XY_INDEPENDENT) {
|
||||||
|
config->dpi[resolution->index * 2] = sinowealth_dpi_to_raw(resolution->dpi_x);
|
||||||
|
config->dpi[resolution->index * 2 + 1] = sinowealth_dpi_to_raw(resolution->dpi_y);
|
||||||
|
} else {
|
||||||
|
config->dpi[resolution->index] = sinowealth_dpi_to_raw(resolution->dpi_x);
|
||||||
|
}
|
||||||
|
dpi_enabled |= 1<<resolution->index;
|
||||||
|
config->dpi_count++;
|
||||||
|
}
|
||||||
|
config->dpi_enabled = ~dpi_enabled; /* config->dpi_enabled is inverted */
|
||||||
|
|
||||||
|
/* Body lighting */
|
||||||
|
led = ratbag_profile_get_led(profile, 0);
|
||||||
|
switch(led->mode) {
|
||||||
|
case RATBAG_LED_OFF:
|
||||||
|
config->rgb_effect = RGB_OFF;
|
||||||
|
break;
|
||||||
|
case RATBAG_LED_ON:
|
||||||
|
config->rgb_effect = RGB_SINGLE;
|
||||||
|
config->single_color = sinowealth_color_to_rbg(led->color);
|
||||||
|
break;
|
||||||
|
case RATBAG_LED_CYCLE:
|
||||||
|
config->rgb_effect = RGB_GLORIOUS;
|
||||||
|
config->glorious_mode = sinowealth_led_to_rgb_mode(led);
|
||||||
|
break;
|
||||||
|
case RATBAG_LED_BREATHING:
|
||||||
|
config->rgb_effect = RGB_BREATHING1;
|
||||||
|
config->breathing1_color = sinowealth_color_to_rbg(led->color);
|
||||||
|
config->breathing1_mode = sinowealth_led_to_rgb_mode(led);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ratbag_led_unref(led);
|
||||||
|
|
||||||
|
config->config_write = 0x7b; /* magic */
|
||||||
|
|
||||||
|
rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG,
|
||||||
|
(uint8_t*) config, SINOWEALTH_CONFIG_SIZE);
|
||||||
|
if (rc != SINOWEALTH_CONFIG_SIZE) {
|
||||||
|
log_error(device->ratbag, "Error while writing config: %d\n", rc);
|
||||||
|
ratbag_profile_unref(profile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ratbag_profile_unref(profile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sinowealth_remove(struct ratbag_device *device)
|
||||||
|
{
|
||||||
|
ratbag_close_hidraw(device);
|
||||||
|
free(ratbag_get_drv_data(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ratbag_driver sinowealth_driver = {
|
||||||
|
.name = "Sinowealth",
|
||||||
|
.id = "sinowealth",
|
||||||
|
.probe = sinowealth_probe,
|
||||||
|
.remove = sinowealth_remove,
|
||||||
|
.commit = sinowealth_commit
|
||||||
|
};
|
||||||
@@ -78,11 +78,6 @@
|
|||||||
#define STEELSERIES_BUTTON_KBD 0x51
|
#define STEELSERIES_BUTTON_KBD 0x51
|
||||||
#define STEELSERIES_BUTTON_CONSUMER 0x61
|
#define STEELSERIES_BUTTON_CONSUMER 0x61
|
||||||
|
|
||||||
struct steelseries_data {
|
|
||||||
int firmware_major;
|
|
||||||
int firmware_minor;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct steelseries_point {
|
struct steelseries_point {
|
||||||
struct list link;
|
struct list link;
|
||||||
|
|
||||||
@@ -177,7 +172,6 @@ button_defaults_for_layout(struct ratbag_button *button, int button_count)
|
|||||||
static int
|
static int
|
||||||
steelseries_get_firmware_version(struct ratbag_device *device)
|
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);
|
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||||
size_t buf_len = STEELSERIES_REPORT_SIZE;
|
size_t buf_len = STEELSERIES_REPORT_SIZE;
|
||||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||||
@@ -199,8 +193,8 @@ steelseries_get_firmware_version(struct ratbag_device *device)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
drv_data->firmware_major = buf[1];
|
device->firmware_major = buf[1];
|
||||||
drv_data->firmware_minor = buf[0];
|
device->firmware_minor = buf[0];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -265,7 +259,6 @@ steelseries_read_settings(struct ratbag_device *device)
|
|||||||
static int
|
static int
|
||||||
steelseries_probe(struct ratbag_device *device)
|
steelseries_probe(struct ratbag_device *device)
|
||||||
{
|
{
|
||||||
struct steelseries_data *drv_data = NULL;
|
|
||||||
struct ratbag_profile *profile = NULL;
|
struct ratbag_profile *profile = NULL;
|
||||||
struct ratbag_resolution *resolution;
|
struct ratbag_resolution *resolution;
|
||||||
struct ratbag_button *button;
|
struct ratbag_button *button;
|
||||||
@@ -363,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);
|
rc = steelseries_get_firmware_version(device);
|
||||||
if(rc == 0)
|
if(rc == 0)
|
||||||
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
|
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
|
||||||
drv_data->firmware_major,
|
device->firmware_major,
|
||||||
drv_data->firmware_minor);
|
device->firmware_minor);
|
||||||
|
|
||||||
steelseries_read_settings(device);
|
steelseries_read_settings(device);
|
||||||
|
|
||||||
@@ -960,7 +950,6 @@ steelseries_remove(struct ratbag_device *device)
|
|||||||
{
|
{
|
||||||
ratbag_close_hidraw_index(device, 0);
|
ratbag_close_hidraw_index(device, 0);
|
||||||
ratbag_close_hidraw_index(device, 1);
|
ratbag_close_hidraw_index(device, 1);
|
||||||
free(ratbag_get_drv_data(device));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ratbag_driver steelseries_driver = {
|
struct ratbag_driver steelseries_driver = {
|
||||||
|
|||||||
@@ -807,8 +807,12 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile
|
|||||||
__CMD_PROFILE);
|
__CMD_PROFILE);
|
||||||
|
|
||||||
res = hidpp10_request_command(dev, &profile);
|
res = hidpp10_request_command(dev, &profile);
|
||||||
if (res)
|
if (res) {
|
||||||
return res;
|
/* Profiles not supported */
|
||||||
|
hidpp_log_debug(&dev->base, "Profiles not supported\n");
|
||||||
|
*current_profile = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
type = profile.msg.parameters[0];
|
type = profile.msg.parameters[0];
|
||||||
page = profile.msg.parameters[1];
|
page = profile.msg.parameters[1];
|
||||||
|
|||||||
@@ -2592,6 +2592,7 @@ hidpp20_buttons_to_cpu(struct hidpp20_device *device,
|
|||||||
case HIDPP20_BUTTON_DISABLED:
|
case HIDPP20_BUTTON_DISABLED:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
memcpy(b, button, sizeof(*b));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2642,6 +2643,7 @@ hidpp20_buttons_from_cpu(struct hidpp20_profile *profile,
|
|||||||
button->macro.zero = 0;
|
button->macro.zero = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
memcpy(b, button, sizeof(*b));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ enum driver {
|
|||||||
LOGITECH_G300,
|
LOGITECH_G300,
|
||||||
LOGITECH_G600,
|
LOGITECH_G600,
|
||||||
STEELSERIES,
|
STEELSERIES,
|
||||||
|
SINOWEALTH,
|
||||||
|
SINOWEALTH_NUBWO,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data_hidpp20 {
|
struct data_hidpp20 {
|
||||||
@@ -267,6 +269,8 @@ 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", NULL },
|
||||||
|
{ SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -146,6 +147,9 @@ struct ratbag_device {
|
|||||||
unsigned num_buttons;
|
unsigned num_buttons;
|
||||||
unsigned num_leds;
|
unsigned num_leds;
|
||||||
|
|
||||||
|
int firmware_major;
|
||||||
|
int firmware_minor;
|
||||||
|
|
||||||
void *drv_data;
|
void *drv_data;
|
||||||
|
|
||||||
struct list link;
|
struct list link;
|
||||||
@@ -594,6 +598,8 @@ extern struct ratbag_driver logitech_g600_driver;
|
|||||||
extern struct ratbag_driver roccat_driver;
|
extern struct ratbag_driver roccat_driver;
|
||||||
extern struct ratbag_driver gskill_driver;
|
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_nubwo_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,
|
||||||
|
|||||||
@@ -545,6 +545,18 @@ ratbag_device_get_product_id(const struct ratbag_device *device)
|
|||||||
return device->ids.product;
|
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
|
LIBRATBAG_EXPORT uint32_t
|
||||||
ratbag_device_get_product_version(const struct ratbag_device *device)
|
ratbag_device_get_product_version(const struct ratbag_device *device)
|
||||||
{
|
{
|
||||||
@@ -602,6 +614,8 @@ ratbag_create_context(const struct ratbag_interface *interface,
|
|||||||
ratbag_register_driver(ratbag, &roccat_driver);
|
ratbag_register_driver(ratbag, &roccat_driver);
|
||||||
ratbag_register_driver(ratbag, &gskill_driver);
|
ratbag_register_driver(ratbag, &gskill_driver);
|
||||||
ratbag_register_driver(ratbag, &steelseries_driver);
|
ratbag_register_driver(ratbag, &steelseries_driver);
|
||||||
|
ratbag_register_driver(ratbag, &sinowealth_driver);
|
||||||
|
ratbag_register_driver(ratbag, &sinowealth_nubwo_driver);
|
||||||
|
|
||||||
return ratbag;
|
return ratbag;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -421,6 +421,24 @@ ratbag_device_set_user_data(struct ratbag_device *device, void *userdata);
|
|||||||
void*
|
void*
|
||||||
ratbag_device_get_user_data(const struct ratbag_device *device);
|
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
|
* @ingroup device
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -212,6 +212,8 @@ def print_device(d, level):
|
|||||||
|
|
||||||
print(" " * level + "{} - {}".format(d.id, d.name))
|
print(" " * level + "{} - {}".format(d.id, d.name))
|
||||||
print(" " * level + " Model: {}".format(d.model))
|
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 Buttons: {}".format(len(p.buttons)))
|
||||||
print(" " * level + " Number of Leds: {}".format(len(p.leds)))
|
print(" " * level + " Number of Leds: {}".format(len(p.leds)))
|
||||||
print(" " * level + "Number of Profiles: {}".format(len(d.profiles)))
|
print(" " * level + "Number of Profiles: {}".format(len(d.profiles)))
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ class _RatbagdDBus(GObject.GObject):
|
|||||||
# args to .Set are "interface name", "function name", value-variant
|
# args to .Set are "interface name", "function name", value-variant
|
||||||
val = GLib.Variant("{}".format(type), value)
|
val = GLib.Variant("{}".format(type), value)
|
||||||
if readwrite:
|
if readwrite:
|
||||||
pval = GLib.Variant("(ssv)".format(type), (self._interface, property, val))
|
pval = GLib.Variant("(ssv)", (self._interface, property, val))
|
||||||
self._proxy.call_sync("org.freedesktop.DBus.Properties.Set",
|
self._proxy.call_sync("org.freedesktop.DBus.Properties.Set",
|
||||||
pval, Gio.DBusCallFlags.NO_AUTO_START,
|
pval, Gio.DBusCallFlags.NO_AUTO_START,
|
||||||
2000, None)
|
2000, None)
|
||||||
@@ -342,6 +342,16 @@ class RatbagdDevice(_RatbagdDBus):
|
|||||||
"""The unique identifier for this device model."""
|
"""The unique identifier for this device model."""
|
||||||
return self._get_dbus_property("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
|
@GObject.Property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""The device name, usually provided by the kernel."""
|
"""The device name, usually provided by the kernel."""
|
||||||
|
|||||||
Reference in New Issue
Block a user