mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-08 07:33:53 +01:00
Add driver for the Logitech G300/G300s
Supports the common functionality exposed by libratbag: - selecting profile 1-3 (profiles cannot be disabled) - selecting resolution 1-4 (can also not be disabled) - report frequency - default resolution per profile - button actions: mouse button numbers or key+modifier (modifiers are just a bit field and can easly be set in the driver, but not included as libratbag does not support it yet) - LEDs are not yet hooked up but are just a table of 7 different predifined colors. - Seting active profile and resolution are both implemented but only profile activation is in use. The resolution activation code is commented until supported from libratbag itself. The G300 has an unusual way of numbering buttons: Left:1, Right:2, Middle: 3 The purpose of report type 0xF2 is not known.
This commit is contained in:
committed by
bentiss
parent
7d241642f9
commit
25294d9a63
@@ -95,6 +95,10 @@ mouse:usb:v046dpc249:name:*:
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
|
||||
# G300
|
||||
mouse:usb:v046dpc246:name:*:
|
||||
RATBAG_DRIVER=logitech_g300
|
||||
|
||||
# G500
|
||||
mouse:usb:v046dpc068:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
|
||||
@@ -11,6 +11,7 @@ libratbag_la_SOURCES = \
|
||||
driver-etekcity.c \
|
||||
driver-hidpp20.c \
|
||||
driver-hidpp10.c \
|
||||
driver-logitech-g300.c \
|
||||
driver-roccat.c \
|
||||
driver-gskill.c \
|
||||
driver-test.c \
|
||||
|
||||
494
src/driver-logitech-g300.c
Normal file
494
src/driver-logitech-g300.c
Normal file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright © 2016 Thomas Hindoe Paaboel Andersen.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
|
||||
#define LOGITECH_G300_PROFILE_MAX 2
|
||||
#define LOGITECH_G300_BUTTON_MAX 8
|
||||
#define LOGITECH_G300_NUM_DPI 4
|
||||
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE 0xF1
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_RESOLUTION 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_0 0xF3
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_1 0xF4
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_2 0xF5
|
||||
|
||||
#define LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE 2
|
||||
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
|
||||
|
||||
struct logitech_g300_resolution {
|
||||
uint8_t dpi :7; /* Range 1-10. dpi = 250*value */
|
||||
uint8_t is_default :1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_button {
|
||||
uint8_t code;
|
||||
uint8_t modifier;
|
||||
uint8_t key;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_profile_report {
|
||||
uint8_t id; /* F3, F4, F5 */
|
||||
uint8_t led; /* 00=off, 01=red, 02=green, 03=yellow, 04=blue, 05=pink, 06=turquoise, 07=white */
|
||||
uint8_t frequency; /* 00=1000, 01=125, 02=250, 03=500 */
|
||||
struct logitech_g300_resolution dpi_levels[LOGITECH_G300_NUM_DPI];
|
||||
uint8_t unknown; /* dpi index for shift, but something else too */
|
||||
struct logitech_g300_button buttons[LOGITECH_G300_BUTTON_MAX + 1];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_profile_data {
|
||||
struct logitech_g300_profile_report report;
|
||||
};
|
||||
|
||||
struct logitech_g300_data {
|
||||
struct logitech_g300_profile_data profile_data[LOGITECH_G300_PROFILE_MAX + 1];
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct logitech_g300_profile_report) == LOGITECH_G300_REPORT_SIZE_PROFILE,
|
||||
"Size of logitech_g300_profile_report is wrong");
|
||||
|
||||
struct logitech_g300_button_type_mapping {
|
||||
uint8_t raw;
|
||||
enum ratbag_button_type type;
|
||||
};
|
||||
|
||||
static const struct logitech_g300_button_type_mapping logitech_g300_button_type_mapping[] = {
|
||||
{ 0, RATBAG_BUTTON_TYPE_LEFT },
|
||||
{ 1, RATBAG_BUTTON_TYPE_RIGHT },
|
||||
{ 2, RATBAG_BUTTON_TYPE_MIDDLE },
|
||||
{ 3, RATBAG_BUTTON_TYPE_THUMB },
|
||||
{ 4, RATBAG_BUTTON_TYPE_THUMB2 },
|
||||
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
|
||||
{ 6, RATBAG_BUTTON_TYPE_PINKIE2 },
|
||||
{ 7, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP },
|
||||
{ 8, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP },
|
||||
};
|
||||
|
||||
static enum ratbag_button_type
|
||||
logitech_g300_raw_to_button_type(uint8_t data)
|
||||
{
|
||||
const struct logitech_g300_button_type_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_type_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return mapping->type;
|
||||
}
|
||||
|
||||
return RATBAG_BUTTON_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
struct logitech_g300_button_mapping {
|
||||
uint8_t raw;
|
||||
struct ratbag_button_action action;
|
||||
};
|
||||
|
||||
static struct logitech_g300_button_mapping logitech_g300_button_mapping[] = {
|
||||
/* 0x00 is either key or unassigned. Must be handled separatly */
|
||||
{ 0x01, BUTTON_ACTION_BUTTON(1) },
|
||||
{ 0x02, BUTTON_ACTION_BUTTON(2) },
|
||||
{ 0x03, BUTTON_ACTION_BUTTON(3) },
|
||||
{ 0x04, BUTTON_ACTION_BUTTON(4) },
|
||||
{ 0x05, BUTTON_ACTION_BUTTON(5) },
|
||||
{ 0x0A, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP) },
|
||||
{ 0x0B, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN) },
|
||||
{ 0x0C, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP) },
|
||||
{ 0x0D, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP) },
|
||||
{ 0x0E, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE) },
|
||||
{ 0x0F, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT) },
|
||||
};
|
||||
|
||||
static const struct ratbag_button_action*
|
||||
logitech_g300_raw_to_button_action(uint8_t data)
|
||||
{
|
||||
struct logitech_g300_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return &mapping->action;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
logitech_g300_button_action_to_raw(const struct ratbag_button_action *action)
|
||||
{
|
||||
struct logitech_g300_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_mapping, mapping) {
|
||||
if (ratbag_button_action_match(&mapping->action, action))
|
||||
return mapping->raw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct logitech_g300_frequency_mapping {
|
||||
uint8_t raw;
|
||||
unsigned int frequency;
|
||||
};
|
||||
|
||||
static struct logitech_g300_frequency_mapping logitech_g300_frequency_mapping[] = {
|
||||
{ 0, 1000 },
|
||||
{ 1, 125 },
|
||||
{ 2, 250 },
|
||||
{ 3, 500 },
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
logitech_g300_raw_to_frequency(uint8_t data)
|
||||
{
|
||||
struct logitech_g300_frequency_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_frequency_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return mapping->frequency;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
logitech_g300_frequency_to_raw(unsigned int frequency)
|
||||
{
|
||||
struct logitech_g300_frequency_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_frequency_mapping, mapping) {
|
||||
if (mapping->frequency == frequency)
|
||||
return mapping->raw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
uint8_t buf[LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE];
|
||||
int i, ret;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE, buf,
|
||||
sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
/* The current profile is identifed by its LED color code. */
|
||||
for (i = 0; i <= LOGITECH_G300_PROFILE_MAX; i++) {
|
||||
struct logitech_g300_profile_report report;
|
||||
|
||||
report = drv_data->profile_data[i].report;
|
||||
if (report.led == buf[1])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x80 + index, 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index > LOGITECH_G300_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
logitech_g300_set_current_resolution(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x40 + index*2, 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index >= LOGITECH_G300_NUM_DPI)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
logitech_g300_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_resolution *resolution;
|
||||
unsigned int i, hz;
|
||||
uint8_t report_id;
|
||||
int rc;
|
||||
|
||||
assert(index <= LOGITECH_G300_PROFILE_MAX);
|
||||
|
||||
pdata = &drv_data->profile_data[index];
|
||||
report = &pdata->report;
|
||||
|
||||
switch (index) {
|
||||
case 0: report_id = LOGITECH_G300_REPORT_ID_PROFILE_0; break;
|
||||
case 1: report_id = LOGITECH_G300_REPORT_ID_PROFILE_1; break;
|
||||
case 2: report_id = LOGITECH_G300_REPORT_ID_PROFILE_2; break;
|
||||
}
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report_id,
|
||||
(uint8_t*)report,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < (signed)sizeof(*report)) {
|
||||
log_error(device->ratbag,
|
||||
"Error while requesting profile: %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
hz = logitech_g300_raw_to_frequency(report->frequency);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct logitech_g300_resolution *res =
|
||||
&report->dpi_levels[i];
|
||||
|
||||
resolution = &profile->resolution.modes[i];
|
||||
resolution->dpi_x = res->dpi * 250;
|
||||
resolution->dpi_y = res->dpi * 250;
|
||||
resolution->hz = hz;
|
||||
resolution->is_default = res->is_default;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_read_button(struct ratbag_button *button)
|
||||
{
|
||||
const struct ratbag_button_action *action;
|
||||
struct ratbag_profile *profile = button->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *profile_report;
|
||||
struct logitech_g300_button *button_report;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
profile_report = &pdata->report;
|
||||
button_report = &profile_report->buttons[button->index];
|
||||
|
||||
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);
|
||||
|
||||
button->type = logitech_g300_raw_to_button_type(button->index);
|
||||
|
||||
action = logitech_g300_raw_to_button_action(button_report->code);
|
||||
if (action) {
|
||||
button->action = *action;
|
||||
}
|
||||
else if (button_report->code == 0x00 && (button_report->modifier > 0x00 || button_report->key > 0x00))
|
||||
{
|
||||
struct ratbag_button_action *key_action = &button->action;
|
||||
|
||||
key_action->type = RATBAG_BUTTON_ACTION_TYPE_KEY;
|
||||
key_action->action.key.key = ratbag_hidraw_get_keycode_from_keyboard_usage(
|
||||
device, button_report->key);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_test_hidraw(struct ratbag_device *device)
|
||||
{
|
||||
return ratbag_hidraw_has_report(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE);
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_probe(struct ratbag_device *device)
|
||||
{
|
||||
int rc;
|
||||
struct ratbag_profile *profile;
|
||||
struct logitech_g300_data *drv_data = NULL;
|
||||
int active_idx;
|
||||
|
||||
rc = ratbag_find_hidraw(device, logitech_g300_test_hidraw);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
/* profiles are 0-indexed */
|
||||
ratbag_device_init_profiles(device,
|
||||
LOGITECH_G300_PROFILE_MAX + 1,
|
||||
LOGITECH_G300_NUM_DPI,
|
||||
LOGITECH_G300_BUTTON_MAX + 1);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
|
||||
active_idx = logitech_g300_current_profile(device);
|
||||
|
||||
if (active_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
"Can't talk to the mouse: '%s' (%d)\n",
|
||||
strerror(-active_idx),
|
||||
active_idx);
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->index == (unsigned int)active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_raw(device->ratbag,
|
||||
"'%s' is in profile %d\n",
|
||||
ratbag_device_get_name(device),
|
||||
profile->index);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(drv_data);
|
||||
ratbag_set_drv_data(device, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_button *button;
|
||||
uint8_t *buf;
|
||||
unsigned int hz, i;
|
||||
int rc;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
report = &pdata->report;
|
||||
|
||||
/* The same hz is used for all resolutions */
|
||||
hz = profile->resolution.modes[0].hz;
|
||||
report->frequency = logitech_g300_frequency_to_raw(hz);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *resolution = &profile->resolution.modes[i];
|
||||
struct logitech_g300_resolution *res = &report->dpi_levels[i];
|
||||
|
||||
res->dpi = resolution->dpi_x / 250;
|
||||
res->is_default = resolution->is_default;
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
struct ratbag_button_action *action = &button->action;
|
||||
struct logitech_g300_button *raw_button;
|
||||
|
||||
if (!button->dirty)
|
||||
continue;
|
||||
|
||||
raw_button = &report->buttons[button->index];
|
||||
|
||||
raw_button->code = logitech_g300_button_action_to_raw(action);
|
||||
raw_button->modifier = 0x00;
|
||||
raw_button->key = 0x00;
|
||||
if (action->type == RATBAG_BUTTON_ACTION_TYPE_KEY) {
|
||||
raw_button->key = ratbag_hidraw_get_keyboard_usage_from_keycode(
|
||||
device, action->action.key.key);
|
||||
}
|
||||
}
|
||||
|
||||
buf = (uint8_t*)report;
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report->id,
|
||||
buf,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_commit(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
int rc = 0;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
continue;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Profile %d changed, rewriting\n", profile->index);
|
||||
|
||||
rc = logitech_g300_write_profile(profile);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_remove(struct ratbag_device *device)
|
||||
{
|
||||
ratbag_close_hidraw(device);
|
||||
free(ratbag_get_drv_data(device));
|
||||
}
|
||||
|
||||
struct ratbag_driver logitech_g300_driver = {
|
||||
.name = "Logitech G300",
|
||||
.id = "logitech_g300",
|
||||
.probe = logitech_g300_probe,
|
||||
.remove = logitech_g300_remove,
|
||||
.read_profile = logitech_g300_read_profile,
|
||||
.commit = logitech_g300_commit,
|
||||
.set_active_profile = logitech_g300_set_current_profile,
|
||||
.read_button = logitech_g300_read_button,
|
||||
};
|
||||
@@ -433,6 +433,7 @@ log_buffer(struct ratbag *ratbag,
|
||||
struct ratbag_driver etekcity_driver;
|
||||
struct ratbag_driver hidpp20_driver;
|
||||
struct ratbag_driver hidpp10_driver;
|
||||
struct ratbag_driver logitech_g300_driver;
|
||||
struct ratbag_driver roccat_driver;
|
||||
struct ratbag_driver gskill_driver;
|
||||
|
||||
|
||||
@@ -533,6 +533,7 @@ ratbag_create_context(const struct ratbag_interface *interface,
|
||||
ratbag_register_driver(ratbag, &etekcity_driver);
|
||||
ratbag_register_driver(ratbag, &hidpp20_driver);
|
||||
ratbag_register_driver(ratbag, &hidpp10_driver);
|
||||
ratbag_register_driver(ratbag, &logitech_g300_driver);
|
||||
ratbag_register_driver(ratbag, &roccat_driver);
|
||||
ratbag_register_driver(ratbag, &gskill_driver);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user