diff --git a/README.md b/README.md index 74b33813..34ca83e3 100644 --- a/README.md +++ b/README.md @@ -80,33 +80,16 @@ library in the future, if other projects require it. Adding Devices to libratbag --------------------------- -As of commit 3605bede4 libratbag now uses a hwdb entry to match the device -with the drivers. To access a device through libratbag, the udev property -RATBAG_DRIVER must be set for a device's event node. Check with +libratbag relies on a device database to match a device with the drivers. +See the data/devices/ directory for the set of known devices. These files +are usually installed into $prefix/$datadir (e.g. /usr/share/libratbag/). - sudo udevadm info /sys/class/input/eventX | grep RATBAG_DRIVER +To add a new device to libratbag, simply drop a new device file into that +directory and restart ratbagd. See the data/devices/device.example file for +guidance on what information must be set. -If your device is not yet assigned the property, it is not in the hwdb. It -may however be supported by one of our existing drivers. Try enabling it by -adding the device vendor-id/product-id to the hwdb file in -`hwdb/70-libratbag-mouse.hwdb`. For example, for a HID++ 1.0 device, edit -the 70-libratbag-mouse.hwdb file and add an entry with `RATBAG_DRIVER=hidpp10`. -For the other drivers, look for the id of the driver in driver-{drivername}.c -file and do the same. - -Once your device is added to the hwdb, install libratbag and trigger a hwdb -update: - - sudo udevadm hwdb --update - sudo udevadm control --reload - -Then unplug/replug your mouse. `RATBAG_DRIVER` should appear in the udev -properties of your device with the value you previously set. If the property -is not assigned, the hwdb entry does not correctly match your device or the -installed udev rules/hwdb entries are not picked up by udev. - -If the device doesn't work, you'll have to start reverse-engineering the -device-specific protocol. Good luck :) +If the device doesn't work after adding the device file, you'll have to +start reverse-engineering the device-specific protocol. Good luck :) Source ------ diff --git a/circle.yml b/circle.yml index ec802b05..3d6535ec 100644 --- a/circle.yml +++ b/circle.yml @@ -56,7 +56,7 @@ libratbag_references: fedora_install: &fedora_install run: name: Install prerequisites - command: dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel doxygen graphviz valgrind python3-gobject python3-evdev + command: dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel doxygen graphviz valgrind python3-gobject python3-evdev glib2-devel fedora_settings: &fedora_settings @@ -81,7 +81,7 @@ ubuntu_settings: &ubuntu_settings apt-get install -y software-properties-common add-apt-repository universe apt-get update - apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev doxygen graphviz valgrind python3-gi python3-evdev + apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev doxygen graphviz valgrind python3-gi python3-evdev libglib2.0-dev: - checkout - *start_dbus - *build_and_test diff --git a/data/devices/data-parse-test.py b/data/devices/data-parse-test.py new file mode 100755 index 00000000..52fcee89 --- /dev/null +++ b/data/devices/data-parse-test.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +# vim: set expandtab shiftwidth=4 tabstop=4: +# +# Copyright © 2017 Red Hat, Inc. +# +# 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. +# +# Device data verification script +# + +import argparse +import os +import configparser + +# Set on commandline with --svg-dir +svg_dirs = [] + + +def check_svg_str(string): + assert(string.endswith('.svg')) + + svg_file_found = False + for svg_dir in svg_dirs: + files = os.listdir(svg_dir) + if string in files: + svg_file_found = True + break + assert(svg_file_found) + + +def check_match_str(string): + bustypes = ['usb', 'bluetooth'] + + matches = string.split(';') + for match in matches: + if not match: # empty string if trailing ; + continue + + parts = match.split(':') + assert(len(parts) == 3) + assert(parts[0] in bustypes) + vid = parts[1] + assert(vid == '{:04x}'.format(int(vid, 16))) + pid = parts[2] + assert(pid == '{:04x}'.format(int(pid, 16))) + + +def check_section_device(section): + required_keys = ['Name', 'Driver', 'DeviceMatch'] + permitted_keys = required_keys + ['Svg'] + + for key in section.keys(): + assert(key in permitted_keys) + + for r in required_keys: + assert(r in section) + + try: + check_svg_str(section['Svg']) + except KeyError: + pass + + check_match_str(section['DeviceMatch']) + + +def check_dpi_range_str(string): + import re + + m = re.search('^([0-9]+):([0-9]+)@([0-9\.]+)$', string) + assert(m is not None) + min = int(m.group(1)) + max = int(m.group(2)) + steps = float(m.group(3)) + + assert(min >= 0 and min <= 400) + assert(max >= 2000 and max <= 12000) + assert(steps > 0 and steps <= 100) + + if int(steps) == steps: + steps = int(steps) + + assert(string == '{}:{}@{}'.format(min, max, steps)) + + +def check_dpi_list_str(string): + entries = string.split(';') + # Remove possible empty last entry if trailing with a ; + if not entries[len(entries) - 1]: + entries = entries[:-1] + + for idx, entry in enumerate(entries): + dpi = int(entry) + assert(dpi >= 0 and dpi <= 12000) + if idx > 0: + prev = entries[idx - 1] + prev_dpi = int(prev) + assert(dpi > prev_dpi) + + +def check_profile_type_str(string): + types = ['G9', 'G500', 'G700'] + assert(string in types) + + +def check_section_hidpp10(section): + permitted = ['Profiles', 'ProfileType', 'DpiRange', 'DpiList', 'DeviceIndex'] + for key in section.keys(): + assert(key in permitted) + + try: + nprofiles = int(section['Profiles']) + # 10 is arbitrarily chosen + assert(nprofiles > 0 and nprofiles < 10) + except KeyError: + pass + + try: + index = int(section['DeviceIndex']) + # 10 is arbitrarily chosen + assert(index > 0 and index < 10) + except KeyError: + pass + + try: + check_dpi_range_str(section['DpiRange']) + assert('DpiList' not in section.keys()) + except KeyError: + pass + + try: + check_dpi_list_str(section['DpiList']) + assert('DpiRange' not in section.keys()) + except KeyError: + pass + + try: + check_profile_type_str(section['ProfileType']) + except KeyError: + pass + + +def check_section_hidpp20(section): + permitted = ['DeviceIndex'] + for key in section.keys(): + assert(key in permitted) + + try: + index = int(section['DeviceIndex']) + # 10 is arbitrarily chosen + assert(index > 0 and index < 10) + except KeyError: + pass + + +def check_section_driver(driver, section): + if driver == 'hidpp10': + check_section_hidpp10(section) + elif driver == 'hidpp20': + check_section_hidpp20(section) + else: + assert('Unsupported driver section {}'.format(driver)) + + +def parse_data_file(path): + print('Parsing file {}'.format(path)) + data = configparser.ConfigParser(strict=True) + # Don't convert to lowercase + data.optionxform = lambda option: option + data.read(path) + + assert('Device' in data.sections()) + check_section_device(data['Device']) + + driver = data['Device']['Driver'] + driver_section = 'Driver/{}'.format(driver) + + permitted_sections = ['Device', driver_section] + for s in data.sections(): + assert(s in permitted_sections) + + if data.has_section(driver_section): + check_section_driver(driver, data[driver_section]) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Device data-file checker") + parser.add_argument('file', nargs='+') + parser.add_argument('--svg-dir', metavar='dir', action='append', + type=str, + help='Directory to check for SVG files (may be given multiple times)') + args = parser.parse_args() + svg_dirs = args.svg_dir + for path in args.file: + parse_data_file(path) diff --git a/data/devices/device.example b/data/devices/device.example new file mode 100644 index 00000000..3f34e4c9 --- /dev/null +++ b/data/devices/device.example @@ -0,0 +1,49 @@ +# Example description file for a libratbag device +# +# Make sure the file has a recognizable name with a '.device' suffix + +[Device] +# The kernel name of the device. This name is not used by libratbag, it is +# used by debugging tools. +Name=Logitech Example Device + +# DeviceMatch is a triplet of bus:vid:pid, where bus is 'usb' or bluetooth' +# and pid/vid are lowercase 4-digit hexadecimal numbers with preceding +# zeroes. +DeviceMatch=usb:12ab:00f2 + +# The file name of the SVG file representing this device +Svg=logitech-example.svg + +# The libratbag driver backend +Driver=hidpp10 + +# Only one group of driver-specific properties is permitted and it must be +# [Driver/]. It is a bug do have any other [Driver/foo] group in +# a device file, but this example file lists all. + +[Driver/hidpp10] +# The number of profiles, must be greater than 0 +Profiles=1 + +# The type of the profile +ProfileType=G9 + +# The range of available resolutions in the form min:max@step +# Mutually exclusive with DpiList +DpiRange=50:5700@50 + +# The list of available resolutions, separated by semicolons. +# Mutually exclusive with DpiRange +# Where possible, DpiRange should be preferred +DpiList=50;200;400;800 + +# The HID++ 1.0 device index +# Should be unset unless required +# DeviceIndex=1 + + +[Driver/hidpp20] +# The HID++ 2.0 device index +# Should be unset unless required +# DeviceIndex=1 diff --git a/data/devices/etekcity-fixme.device b/data/devices/etekcity-fixme.device new file mode 100644 index 00000000..d36a3948 --- /dev/null +++ b/data/devices/etekcity-fixme.device @@ -0,0 +1,6 @@ +# FIXME: which device is this exactly? +[Device] +Name=Etekcity FIXME +DeviceMatch=usb:1ea7:4011 +Driver=etekcity +Svg=etekcity.svg diff --git a/data/devices/gskill-MX-780.device b/data/devices/gskill-MX-780.device new file mode 100644 index 00000000..d258e33e --- /dev/null +++ b/data/devices/gskill-MX-780.device @@ -0,0 +1,5 @@ +# G.Skill MX-780 +[Device] +Name=G.Skill MX-780 +DeviceMatch=usb:28da:3101 +Driver=gskill diff --git a/data/devices/logitech-M325.device b/data/devices/logitech-M325.device new file mode 100644 index 00000000..1718e6da --- /dev/null +++ b/data/devices/logitech-M325.device @@ -0,0 +1,5 @@ +# Logitech M325 over unifying +[Device] +Name=Logitech M325 +DeviceMatch=usb:046d:400a +Driver=hidpp20 diff --git a/data/devices/logitech-M570.device b/data/devices/logitech-M570.device new file mode 100644 index 00000000..85122536 --- /dev/null +++ b/data/devices/logitech-M570.device @@ -0,0 +1,5 @@ +# Logitech M570 +[Device] +Name=Logitech M570 +DeviceMatch=usb:046d:1028 +Driver=hidpp10 diff --git a/data/devices/logitech-M705.device b/data/devices/logitech-M705.device new file mode 100644 index 00000000..0ffca355 --- /dev/null +++ b/data/devices/logitech-M705.device @@ -0,0 +1,5 @@ +# Logitech M705 +[Device] +Name=Logitech M705 +DeviceMatch=usb:046d:101b +Driver=hidpp10 diff --git a/data/devices/logitech-MX-Master.device b/data/devices/logitech-MX-Master.device new file mode 100644 index 00000000..35914d95 --- /dev/null +++ b/data/devices/logitech-MX-Master.device @@ -0,0 +1,6 @@ +# Logitech MX Master +[Device] +Name=Logitech MX Master +DeviceMatch=usb:046d:4041;bluetooth:046d:b012 +Driver=hidpp20 +Svg=logitech-mx_master.svg diff --git a/data/devices/logitech-T650.device b/data/devices/logitech-T650.device new file mode 100644 index 00000000..a7f45358 --- /dev/null +++ b/data/devices/logitech-T650.device @@ -0,0 +1,5 @@ +# Logitech T650 over unifying +[Device] +Name=Logitech T650 +DeviceMatch=usb:046d:4101 +Driver=hidpp20 diff --git a/data/devices/logitech-Wireless-Touchpad.device b/data/devices/logitech-Wireless-Touchpad.device new file mode 100644 index 00000000..87f6d076 --- /dev/null +++ b/data/devices/logitech-Wireless-Touchpad.device @@ -0,0 +1,5 @@ +# Logitech Wireless Touchpad (Unifying) +[Device] +Name=Logitech Wireless Touchpad +DeviceMatch=usb:046d:4011 +Driver=hidpp20 diff --git a/data/devices/logitech-g300.device b/data/devices/logitech-g300.device new file mode 100644 index 00000000..fd0d86d0 --- /dev/null +++ b/data/devices/logitech-g300.device @@ -0,0 +1,6 @@ +# WARNING: this file was automatically converted and has not yet been vetted +[Device] +Name=Logitech G300 +DeviceMatch=usb:046d:c246 +Driver=logitech_g300 +Svg=logitech-g300.svg diff --git a/data/devices/logitech-g303.device b/data/devices/logitech-g303.device new file mode 100644 index 00000000..7ecac489 --- /dev/null +++ b/data/devices/logitech-g303.device @@ -0,0 +1,6 @@ +# G303 over USB +[Device] +Name=Logitech Gaming Mouse G303 +DeviceMatch=usb:046d:c080 +Svg=logitech-g303.svg +Driver=hidpp20 diff --git a/data/devices/logitech-g403.device b/data/devices/logitech-g403.device new file mode 100644 index 00000000..7257a3da --- /dev/null +++ b/data/devices/logitech-g403.device @@ -0,0 +1,6 @@ +# Logitech G403 over USB +[Device] +Name=Logitech G403 +DeviceMatch=usb:046d:c082 +Driver=hidpp20 +Svg=logitech-g403.svg diff --git a/data/devices/logitech-g5-2007.device b/data/devices/logitech-g5-2007.device new file mode 100644 index 00000000..ec767bcd --- /dev/null +++ b/data/devices/logitech-g5-2007.device @@ -0,0 +1,9 @@ +# Name=Logitech G5 2007 +[Device] +Name=Logitech G5 +DeviceMatch=usb:046d:c049 +Driver=hidpp10 + +[Driver/hidpp10] +DpiList=400;800;1600;2000 +Profiles=1 diff --git a/data/devices/logitech-g5.device b/data/devices/logitech-g5.device new file mode 100644 index 00000000..6c3d8e90 --- /dev/null +++ b/data/devices/logitech-g5.device @@ -0,0 +1,7 @@ +[Device] +Name=G5 +DeviceMatch=usb:046d:c041 +Driver=hidpp10 + +[Driver/hidpp10] +DpiList=400;800;1600;2000 diff --git a/data/devices/logitech-g500.device b/data/devices/logitech-g500.device new file mode 100644 index 00000000..6e3806ac --- /dev/null +++ b/data/devices/logitech-g500.device @@ -0,0 +1,10 @@ +[Device] +Name=Logitech G500 +DeviceMatch=usb:046d:c068 +Driver=hidpp10 +Svg=logitech-g500.svg + +[Driver/hidpp10] +DpiRange=0:5700@23.53 +ProfileType=G500 +Profiles=1 diff --git a/data/devices/logitech-g500s.device b/data/devices/logitech-g500s.device new file mode 100644 index 00000000..c8fbf818 --- /dev/null +++ b/data/devices/logitech-g500s.device @@ -0,0 +1,10 @@ +[Device] +Name=Logitech G500s +DeviceMatch=usb:046d:c24e +Driver=hidpp10 +Svg=logitech-g500s.svg + +[Driver/hidpp10] +DpiRange=0:8200@50 +ProfileType=G500 +Profiles=1 diff --git a/data/devices/logitech-g502-Proteus-Core-over-USB.device b/data/devices/logitech-g502-Proteus-Core-over-USB.device new file mode 100644 index 00000000..04e3f65a --- /dev/null +++ b/data/devices/logitech-g502-Proteus-Core-over-USB.device @@ -0,0 +1,6 @@ +# Logitech G502 Proteus Core over USB +[Device] +Name=Logitech G502 Proteus Core +DeviceMatch=usb:046d:c07d +Driver=hidpp20 +Svg=logitech-g502.svg diff --git a/data/devices/logitech-g502-Proteus-Spectrum-over-USB.device b/data/devices/logitech-g502-Proteus-Spectrum-over-USB.device new file mode 100644 index 00000000..40f19e4b --- /dev/null +++ b/data/devices/logitech-g502-Proteus-Spectrum-over-USB.device @@ -0,0 +1,6 @@ +# Logitech G502 Proteus Spectrum over USB +[Device] +Name=Logitech G502 Proteus Spectrum +DeviceMatch=usb:046d:c332 +Driver=hidpp20 +Svg=logitech-g502.svg diff --git a/data/devices/logitech-g602.device b/data/devices/logitech-g602.device new file mode 100644 index 00000000..20c5a747 --- /dev/null +++ b/data/devices/logitech-g602.device @@ -0,0 +1,8 @@ +# Logitech G602 over wireless USB +[Device] +Name=Logitech G602 +DeviceMatch=usb:046d:c537 +Driver=hidpp20 + +[Driver/hidpp20] +DeviceIndex=1 diff --git a/data/devices/logitech-g7.device b/data/devices/logitech-g7.device new file mode 100644 index 00000000..c3e5d7d2 --- /dev/null +++ b/data/devices/logitech-g7.device @@ -0,0 +1,9 @@ +# Logitech G7 +# http://support.logitech.com/en_us/product/g7-laser-cordless-mouse/specs +[Device] +Name=Logitech G7 +DeviceMatch=usb:046d:c51a +Driver=hidpp10 + +[Driver/hidpp10] +Profiles=1 diff --git a/data/devices/logitech-g700-wireless.device b/data/devices/logitech-g700-wireless.device new file mode 100644 index 00000000..1b41b8be --- /dev/null +++ b/data/devices/logitech-g700-wireless.device @@ -0,0 +1,12 @@ +# Logitech G700 over wireless USB +# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs +[Device] +Name=Logitech G700 +DeviceMatch=usb:046d:c531 +Driver=hidpp10 + +[Driver/hidpp10] +DpiRange=0:5700@23.53 +ProfileType=G700 +DeviceIndex=1 +Profiles=5 diff --git a/data/devices/logitech-g700.device b/data/devices/logitech-g700.device new file mode 100644 index 00000000..893d02cf --- /dev/null +++ b/data/devices/logitech-g700.device @@ -0,0 +1,12 @@ +# Logitech G700 over USB +# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs +[Device] +Name=Logitech G700 +DeviceMatch=usb:046d:c06b +Driver=hidpp10 +Svg=logitech-g700.svg + +[Driver/hidpp10] +DpiRange=0:5700@23.53 +ProfileType=G700 +Profiles=5 diff --git a/data/devices/logitech-g700s-wireless.device b/data/devices/logitech-g700s-wireless.device new file mode 100644 index 00000000..1996c1bd --- /dev/null +++ b/data/devices/logitech-g700s-wireless.device @@ -0,0 +1,13 @@ +# Logitech G700s over wireless USB +# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs +[Device] +Name=Logitech G700s +DeviceMatch=usb:046d:c531 +Driver=hidpp10 +Svg=logitech-g700.svg + +[Driver/hidpp10] +DpiRange=0:8200@50 +ProfileType=G700 +DeviceIndex=1 +Profiles=5 diff --git a/data/devices/logitech-g700s.device b/data/devices/logitech-g700s.device new file mode 100644 index 00000000..a1ff3896 --- /dev/null +++ b/data/devices/logitech-g700s.device @@ -0,0 +1,12 @@ +# Logitech G700s over USB +# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs +[Device] +Name=Logitech G700s +DeviceMatch=usb:046d:c07c +Driver=hidpp10 +Svg=logitech-g700.svg + +[Driver/hidpp10] +DpiRange=0:8200@50 +ProfileType=G700 +Profiles=5 diff --git a/data/devices/logitech-g9.device b/data/devices/logitech-g9.device new file mode 100644 index 00000000..714db7dd --- /dev/null +++ b/data/devices/logitech-g9.device @@ -0,0 +1,11 @@ +# Logitech G9 +# http://support.logitech.com/en_us/product/g9-laser-mouse/specs +[Device] +Name=Logitech G9 +DeviceMatch=usb:046d:c048 +Driver=hidpp10 + +[Driver/hidpp10] +DpiList=0;200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200 +ProfileType=G9 +Profiles=5 diff --git a/data/devices/logitech-g900-wireless.device b/data/devices/logitech-g900-wireless.device new file mode 100644 index 00000000..89f023b2 --- /dev/null +++ b/data/devices/logitech-g900-wireless.device @@ -0,0 +1,9 @@ +# Logitech G900 and G403 over wireless USB +[Device] +Name=Logitech G900, G403 +DeviceMatch=usb:046d:c539 +Driver=hidpp20 +Svg=logitech-g900.svg + +[Driver/hidpp20] +DeviceIndex=1 diff --git a/data/devices/logitech-g900.device b/data/devices/logitech-g900.device new file mode 100644 index 00000000..f25896ca --- /dev/null +++ b/data/devices/logitech-g900.device @@ -0,0 +1,6 @@ +# Logitech G900 over USB +[Device] +Name=Logitech G900 +DeviceMatch=usb:046d:c081 +Driver=hidpp20 +Svg=logitech-g900.svg diff --git a/data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device b/data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device new file mode 100644 index 00000000..87c7f709 --- /dev/null +++ b/data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device @@ -0,0 +1,11 @@ +# Logitech G9x [Call of Duty MW3 Edition] +# http://support.logitech.com/en_us/product/laser-mouse-g9x/specs +[Device] +Name=Logitech G9x [Call of Duty MW3 Edition] +DeviceMatch=usb:046d:c249 +Driver=hidpp10 + +[Driver/hidpp10] +DpiRange=0:5700@23.53 +ProfileType=G500 +Profiles=5 diff --git a/data/devices/logitech-g9x-[Original].device b/data/devices/logitech-g9x-[Original].device new file mode 100644 index 00000000..a1a08de1 --- /dev/null +++ b/data/devices/logitech-g9x-[Original].device @@ -0,0 +1,11 @@ +# Logitech G9x [Original] +# http://support.logitech.com/en_us/product/g9x-laser-mouse/specs +[Device] +Name=G9x [Original] +DeviceMatch=usb:046d:c066 +Driver=hidpp10 + +[Driver/hidpp10] +DpiRange=0:5700@23.53 +ProfileType=G500 +Profiles=5 diff --git a/data/devices/roccat-kone-xtd.device b/data/devices/roccat-kone-xtd.device new file mode 100644 index 00000000..5bab13b0 --- /dev/null +++ b/data/devices/roccat-kone-xtd.device @@ -0,0 +1,5 @@ +[Device] +Name=Roccat Kone XTD +DeviceMatch=usb:1e7d:2e22 +Driver=roccat +Svg=roccat-kone-xtd.svg diff --git a/meson.build b/meson.build index a1b2a6bb..2ed18ea9 100644 --- a/meson.build +++ b/meson.build @@ -48,6 +48,7 @@ dep_udev = dependency('libudev') dep_libevdev = dependency('libevdev') dep_libsystemd = dependency('libsystemd', version : '>=227') dep_systemd = dependency('systemd') +dep_glib = dependency('glib-2.0') dep_lm = cc.find_library('m') #### libutil.a #### @@ -131,6 +132,8 @@ src_libratbag = [ 'src/driver-test.c', 'src/libratbag.c', 'src/libratbag.h', + 'src/libratbag-data.c', + 'src/libratbag-data.h', 'src/libratbag-hidraw.c', 'src/libratbag-hidraw.h', 'src/libratbag-private.h', @@ -142,6 +145,7 @@ src_libratbag = [ deps_libratbag = [ dep_udev, dep_libevdev, + dep_glib, dep_libutil, dep_libhidpp, ] @@ -245,18 +249,46 @@ man_lur_command = configure_file ( install_dir : join_paths(get_option('mandir'), 'man1') ) -#### hwdb #### -udev_dir = get_option('udev-dir') -if udev_dir == '' - udev_dir = '@0@/lib/udev'.format(get_option('prefix')) -endif -udev_rules_dir = '@0@/rules.d'.format(udev_dir) -udev_hwdb_dir = '@0@/hwdb.d'.format(udev_dir) +#### data files #### +data_files = files( + 'data/devices/etekcity-fixme.device', + 'data/devices/gskill-MX-780.device', + 'data/devices/logitech-g300.device', + 'data/devices/logitech-g303.device', + 'data/devices/logitech-g403.device', + 'data/devices/logitech-g500.device', + 'data/devices/logitech-g500s.device', + 'data/devices/logitech-g502-Proteus-Core-over-USB.device', + 'data/devices/logitech-g502-Proteus-Spectrum-over-USB.device', + 'data/devices/logitech-g5-2007.device', + 'data/devices/logitech-g5.device', + 'data/devices/logitech-g602.device', + 'data/devices/logitech-g700.device', + 'data/devices/logitech-g700s.device', + 'data/devices/logitech-g700s-wireless.device', + 'data/devices/logitech-g700-wireless.device', + 'data/devices/logitech-g7.device', + 'data/devices/logitech-g900.device', + 'data/devices/logitech-g900-wireless.device', + 'data/devices/logitech-g9.device', + 'data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device', + 'data/devices/logitech-g9x-[Original].device', + 'data/devices/logitech-M325.device', + 'data/devices/logitech-M570.device', + 'data/devices/logitech-M705.device', + 'data/devices/logitech-MX-Master.device', + 'data/devices/logitech-T650.device', + 'data/devices/logitech-Wireless-Touchpad.device', + 'data/devices/roccat-kone-xtd.device', +) -install_data('hwdb/70-libratbag-mouse.rules', - install_dir : udev_rules_dir) -install_data('hwdb/70-libratbag-mouse.hwdb', - install_dir : udev_hwdb_dir) +install_data(data_files, + install_dir : join_paths(get_option('datadir'), 'libratbag')) + +data_parse_test = find_program(join_paths(meson.source_root(), 'data/devices/data-parse-test.py')) +test('data-parse-test', data_parse_test, + args : [ '--svg-dir', join_paths(meson.source_root(), 'data/default'), + '--svg-dir', join_paths(meson.source_root(), 'data/gnome') ] + data_files) #### svg files #### default_svg_files = [ diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index a05ecbe4..2d003771 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -47,6 +47,7 @@ #include "libratbag-private.h" #include "libratbag-hidraw.h" +#include "libratbag-data.h" struct hidpp10drv_data { struct hidpp10_device *dev; @@ -555,9 +556,8 @@ hidpp10drv_probe(struct ratbag_device *device) struct hidpp10_device *dev = NULL; struct hidpp_device base; enum hidpp10_profile_type type = HIDPP10_PROFILE_UNKNOWN; - const char *prop; + const char *profile; int device_idx = HIDPP_WIRED_DEVICE_IDX; - int nread = 0; unsigned int profile_count = 1; rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw); @@ -568,31 +568,22 @@ hidpp10drv_probe(struct ratbag_device *device) hidpp_device_init(&base, device->hidraw.fd); hidpp_device_set_log_handler(&base, hidpp10_log, HIDPP_LOG_PRIORITY_RAW, device); - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_PROFILE"); - if (prop) { - if (strcasecmp("G500", prop) == 0) + profile = ratbag_device_data_hidpp10_get_profile_type(device->data); + if (profile) { + if (strcasecmp("G500", profile) == 0) type = HIDPP10_PROFILE_G500; - else if (strcasecmp("G700", prop) == 0) + else if (strcasecmp("G700", profile) == 0) type = HIDPP10_PROFILE_G700; - else if (strcasecmp("G9", prop) == 0) + else if (strcasecmp("G9", profile) == 0) type = HIDPP10_PROFILE_G9; - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_PROFILE_COUNT"); - if (prop) - profile_count = atoi(prop); + profile_count = ratbag_device_data_hidpp10_get_profile_count(device->data); } - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_INDEX"); - if (prop) { - sscanf(prop, "%d%n", &device_idx, &nread); - if (!nread || (prop[nread]) != '\0' || device_idx < 0) { - log_error(device->ratbag, - "Error parsing RATBAG_HIDPP10_INDEX: '%s' for %s\n", - prop, - device->name); - device_idx = HIDPP_WIRED_DEVICE_IDX; - } - } + device_idx = ratbag_device_data_hidpp10_get_index(device->data); + if (device_idx == -1) + device_idx = HIDPP_WIRED_DEVICE_IDX; + /* In the general case, we can treat all devices as wired devices * here. If we talk to the correct hidraw device the kernel adjusts * the device index for us, so even for unifying receiver devices @@ -611,23 +602,24 @@ hidpp10drv_probe(struct ratbag_device *device) } if (type != HIDPP10_PROFILE_UNKNOWN) { - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI"); - if (prop) { - rc = hidpp10_build_dpi_table_from_dpi_info(dev, prop); + _cleanup_(dpi_list_freep) struct dpi_list *list = NULL; + _cleanup_(freep) struct dpi_range *range = NULL; + + range = ratbag_device_data_hidpp10_get_dpi_range(device->data); + if (range) { + rc = hidpp10_build_dpi_table_from_dpi_info(dev, range); if (rc) log_error(device->ratbag, - "Error parsing RATBAG_HIDPP10_DPI: '%s' for %s\n", - prop, + "Error parsing DpiRange for %s\n", device->name); } - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI_LIST"); - if (prop) { - rc = hidpp10_build_dpi_table_from_list(dev, prop); + list = ratbag_device_data_hidpp10_get_dpi_list(device->data); + if (list) { + rc = hidpp10_build_dpi_table_from_list(dev, list); if (rc) log_error(device->ratbag, - "Error parsing RATBAG_HIDPP10_DPI_LIST: '%s' for %s\n", - prop, + "Error parsing DpiList for %s\n", device->name); } diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index 08095de3..a25d64d1 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -45,6 +45,7 @@ #include "libratbag-private.h" #include "libratbag-hidraw.h" +#include "libratbag-data.h" #define HIDPP_CAP_RESOLUTION_2200 (1 << 0) #define HIDPP_CAP_SWITCHABLE_RESOLUTION_2201 (1 << 1) @@ -1014,9 +1015,7 @@ hidpp20drv_probe(struct ratbag_device *device) struct hidpp20drv_data *drv_data; struct hidpp_device base; struct hidpp20_device *dev; - const char *prop; int device_idx = HIDPP_RECEIVER_IDX; - int nread = 0; rc = ratbag_find_hidraw(device, hidpp20drv_test_hidraw); if (rc) @@ -1027,25 +1026,17 @@ hidpp20drv_probe(struct ratbag_device *device) hidpp_device_init(&base, device->hidraw.fd); hidpp_device_set_log_handler(&base, hidpp20_log, HIDPP_LOG_PRIORITY_RAW, device); - prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP20_INDEX"); - if (prop) { - sscanf(prop, "%d%n", &device_idx, &nread); - if (!nread || (prop[nread]) != '\0' || device_idx < 0) { - log_error(device->ratbag, - "Error parsing RATBAG_HIDPP20_INDEX: '%s' for %s\n", - prop, - device->name); - device_idx = HIDPP_RECEIVER_IDX; - } - } + device_idx = ratbag_device_data_hidpp20_get_index(device->data); + if (device_idx == -1) + device_idx = HIDPP_RECEIVER_IDX; /* In the general case, we can treat all devices as wired devices * here. If we talk to the correct hidraw device the kernel adjusts * the device index for us, so even for unifying receiver devices * we can just use 0xff as device index. * - * If there is a special need like for G900, we can pass a - * udev prop RATBAG_HIDPP20_INDEX. + * If there is a special need like for G900, we can add this in the + * device data file. */ dev = hidpp20_device_new(&base, device_idx); if (!dev) { diff --git a/src/hidpp10.c b/src/hidpp10.c index 5f8d9857..4f0abf83 100644 --- a/src/hidpp10.c +++ b/src/hidpp10.c @@ -114,20 +114,10 @@ hidpp10_dpi_table_get_min_dpi(struct hidpp10_device *dev) int hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev, - const char *str_list) + const struct dpi_list *list) { - _cleanup_(dpi_list_freep) struct dpi_list *list; size_t i; - /* - * str_list is in the form: - * "0;200;400;600;800;1000;1200" - */ - - list = dpi_list_from_string(str_list); - if (!list) - goto err; - if (list->nentries + 0x80 - 1> 0xff) goto err; @@ -149,19 +139,10 @@ err: int hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev, - const char *str_dpi) + const struct dpi_range *range) { unsigned raw_max, i; - _cleanup_(freep) struct dpi_range *range = NULL; - /* - * str_list is in the form: - * "MIN:MAX@STEP" - */ - - range = dpi_range_from_string(str_dpi); - if (!range) - return -EINVAL; raw_max = (range->max - range->min) / range->step; if (raw_max > 0xff) diff --git a/src/hidpp10.h b/src/hidpp10.h index 8df467e1..2a497ce8 100644 --- a/src/hidpp10.h +++ b/src/hidpp10.h @@ -33,6 +33,9 @@ #include "hidpp-generic.h" +struct dpi_list; +struct dpi_range; + /* FIXME: that's what my G500s supports, but only pages 3-5 are valid. * 0 is zeroed, 1 and 2 are garbage, all above 6 is garbage */ #define HIDPP10_NUM_PROFILES 5 @@ -88,7 +91,7 @@ hidpp10_device_destroy(struct hidpp10_device *dev); */ int hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev, - const char *str_list); + const struct dpi_list *list); /** * Builds the table of dpi for the device from the given dpi description. @@ -103,7 +106,7 @@ hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev, */ int hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev, - const char *str_dpi); + const struct dpi_range *range); /** * Returns the lowest dpi stored in the dpi mapping table generated by diff --git a/src/libratbag-data.c b/src/libratbag-data.c new file mode 100644 index 00000000..b3f8ccba --- /dev/null +++ b/src/libratbag-data.c @@ -0,0 +1,405 @@ +/* + * Copyright © 2017 Red Hat, Inc. + * + * 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 + +#include +#include +#include + +#include "libratbag.h" +#include "libratbag-private.h" +#include "libratbag-data.h" + +#define GROUP_DEVICE "Device" + +DEFINE_TRIVIAL_CLEANUP_FUNC(GKeyFile *, g_key_file_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(GError *, g_error_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(char **, g_strfreev); + +enum driver { + NONE = 0, + HIDPP10, + HIDPP20, + ROCCAT, + ETEKCITY, + GSKILL, + LOGITECH_G300 +}; + +struct data_hidpp20 { + int index; +}; + +struct data_hidpp10 { + int index; + int profile_count; + char *profile_type; + + struct dpi_list *dpi_list; + struct dpi_range *dpi_range; +}; + +struct ratbag_device_data { + int refcount; + char *name; + char *driver; + char *svg; + + enum driver drivertype; + + union { + struct data_hidpp20 hidpp20; + struct data_hidpp10 hidpp10; + }; +}; + +static void +init_data_hidpp10(struct ratbag *ratbag, + GKeyFile *keyfile, + struct ratbag_device_data *data) +{ + const char *group = "Driver/hidpp10"; + char *profile_type; + GError *error = NULL; + _cleanup_(freep) char *str = NULL; + int num; + + data->hidpp10.index = -1; + data->hidpp10.profile_count = -1; + data->hidpp10.profile_type = NULL; + + num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error); + if (num != 0 || !error) + data->hidpp10.index = num; + if (error) + g_error_free(error); + + num = g_key_file_get_integer(keyfile, group, "Profiles", &error); + if (num > 0 || !error) + data->hidpp10.profile_count = num; + if (error) + g_error_free(error); + + profile_type = g_key_file_get_string(keyfile, group, "ProfileType", NULL); + if (profile_type) + data->hidpp10.profile_type = profile_type; + + str = g_key_file_get_string(keyfile, group, "DpiRange", NULL); + if (str) { + data->hidpp10.dpi_range = dpi_range_from_string(str); + } else { + str = g_key_file_get_string(keyfile, group, "DpiList", NULL); + if (str) + data->hidpp10.dpi_list = dpi_list_from_string(str); + } +} + +static void +init_data_hidpp20(struct ratbag *ratbag, + GKeyFile *keyfile, + struct ratbag_device_data *data) +{ + const char *group = "Driver/hidpp20"; + GError *error = NULL; + int num; + + data->hidpp20.index = -1; + + num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error); + if (num != 0 || !error) + data->hidpp20.index = num; + if (error) + g_error_free(error); +} + +static const struct driver_map { + enum driver map; + const char *driver; + void (*init)(struct ratbag *ratbag, + GKeyFile *keyfile, + struct ratbag_device_data *data); +} driver_map[] = { + { HIDPP10, "hidpp10", init_data_hidpp10 }, + { HIDPP20, "hidpp20", init_data_hidpp20 }, + { ROCCAT, "roccat", NULL }, + { ETEKCITY, "etekcity", NULL}, + { GSKILL, "gskill", NULL }, + { LOGITECH_G300, "logitech_g300", NULL}, +}; + +const char * +ratbag_device_data_get_driver(const struct ratbag_device_data *data) +{ + return data->driver; +} + +const char * +ratbag_device_data_get_name(const struct ratbag_device_data *data) +{ + return data->name; +} + +const char * +ratbag_device_data_get_svg(const struct ratbag_device_data *data) +{ + return data->svg; +} + +struct ratbag_device_data * +ratbag_device_data_ref(struct ratbag_device_data *data) +{ + data->refcount++; + return data; +} + +static void +ratbag_device_data_destroy(struct ratbag_device_data *data) +{ + switch (data->drivertype) { + case HIDPP10: + free(data->hidpp10.profile_type); + break; + default: + break; + } + free(data->name); + free(data->driver); + free(data->svg); + free(data); +} + +struct ratbag_device_data * +ratbag_device_data_unref(struct ratbag_device_data *data) +{ + if (data == NULL) + return NULL; + + assert(data->refcount > 0); + data->refcount--; + + if (data->refcount == 0) + ratbag_device_data_destroy(data); + + return NULL; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbag_device_data *, ratbag_device_data_unref); + +static bool +match(const struct input_id *id, char **strv) +{ + const char *bus; + char str[64]; + int i = 0; + + switch (id->bustype) { + case BUS_USB: bus = "usb"; break; + case BUS_BLUETOOTH: bus = "bluetooth"; break; + default: + return false; + } + + snprintf(str, sizeof(str), "%s:%04x:%04x", bus, id->vendor, id->product); + + while (strv[i]) { + if (streq(strv[i], str)) + return true; + i++; + } + + return false; +} + +static bool +file_data_matches(struct ratbag *ratbag, + const char *path, const struct input_id *id, + struct ratbag_device_data **data_out) +{ + _cleanup_(g_key_file_freep) GKeyFile *keyfile = NULL; + _cleanup_(g_error_freep) GError *error = NULL; + _cleanup_(g_strfreevp) char **strv = NULL; + _cleanup_(ratbag_device_data_unrefp) struct ratbag_device_data *data = NULL; + int rc; + + keyfile = g_key_file_new(); + rc = g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, &error); + if (!rc) { + log_error(ratbag, "Failed to parse keyfile %s: %s\n", path, error->message); + return false; + } + + strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "DeviceMatch", NULL, NULL); + if (!strv) { + log_error(ratbag, "Missing DeviceMatch in %s\n", basename(path)); + return false; + } + + if (!match(id, strv)) + return false; + + data = zalloc(sizeof(*data)); + data->refcount = 1; + data->name = g_key_file_get_string(keyfile, GROUP_DEVICE, "Name", NULL); + if (!data->name) { + return false; + } + + data->driver = g_key_file_get_string(keyfile, GROUP_DEVICE, "Driver", NULL); + if (!data->driver) { + log_error(ratbag, "Missing Driver in %s\n", basename(path)); + return false; + } else { + const struct driver_map *map; + + data->drivertype = NONE; + ARRAY_FOR_EACH(driver_map, map) { + if (streq(map->driver, data->driver)) { + data->drivertype = map->map; + if (map->init) + map->init(ratbag, keyfile, data); + break; + } + } + + if (data->drivertype == NONE) { + log_error(ratbag, "Unknown driver %s in %s\n", + data->driver, basename(path)); + return false; + } + } + + data->svg = g_key_file_get_string(keyfile, GROUP_DEVICE, "Svg", NULL); + + *data_out = data; + data = NULL; + + return true; +} + +static int +filter_device_files(const struct dirent *entry) +{ + const char *SUFFIX = ".device"; + const char *name = entry->d_name; + int len, slen; + + if (!name || name[0] == '.') + return 0; + + len = strlen(name); + slen = strlen(SUFFIX); + if (len <= slen) + return 0; + + return streq(&name[len - slen], SUFFIX); +} + +struct ratbag_device_data * +ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id) +{ + struct ratbag_device_data *data = NULL; + struct dirent **files; + int n, nfiles; + + n = scandir(LIBRATBAG_DATA_DIR, &files, filter_device_files, alphasort); + if (n <= 0) { + log_error(ratbag, "Unable to locate device files: %s\n", + n == 0 ? "No files found" : strerror(errno)); + return NULL; + } + + nfiles = n; + while(n--) { + _cleanup_(freep) char *file = NULL; + int rc; + + rc = xasprintf(&file, "%s/%s", LIBRATBAG_DATA_DIR, files[n]->d_name); + if (rc == -1) + goto out; + if (file_data_matches(ratbag, file, id, &data)) + goto out; + } + +out: + while(nfiles--) + free(files[nfiles]); + free(files); + + return data; +} + + +/* HID++ 1.0 */ + +int +ratbag_device_data_hidpp10_get_index(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP10); + + return data->hidpp10.index; +} + +int +ratbag_device_data_hidpp10_get_profile_count(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP10); + + return data->hidpp10.profile_count; +} + +const char * +ratbag_device_data_hidpp10_get_profile_type(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP10); + + return data->hidpp10.profile_type; +} + +struct dpi_list * +ratbag_device_data_hidpp10_get_dpi_list(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP10); + + return data->hidpp10.dpi_list; +} + +struct dpi_range * +ratbag_device_data_hidpp10_get_dpi_range(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP10); + + return data->hidpp10.dpi_range; +} + +/* HID++ 2.0 */ + +int +ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data) +{ + assert(data->drivertype == HIDPP20); + + return data->hidpp20.index; +} diff --git a/src/libratbag-data.h b/src/libratbag-data.h new file mode 100644 index 00000000..b5306952 --- /dev/null +++ b/src/libratbag-data.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2017 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +struct ratbag_device_data; + +struct ratbag_device_data * +ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id); + + +struct ratbag_device_data * +ratbag_device_data_unref(struct ratbag_device_data *data); + +struct ratbag_device_data * +ratbag_device_data_ref(struct ratbag_device_data *data); + + +const char * +ratbag_device_data_get_driver(const struct ratbag_device_data *data); +const char * +ratbag_device_data_get_name(const struct ratbag_device_data *data); +const char * +ratbag_device_data_get_svg(const struct ratbag_device_data *data); + +/* HID++ 1.0 */ +/** + * @return The device index or -1 if not set + */ +int +ratbag_device_data_hidpp10_get_index(const struct ratbag_device_data *data); + +const char * +ratbag_device_data_hidpp10_get_profile_type(const struct ratbag_device_data *data); + +/** + * @return The profile count index or -1 if not set + */ +int +ratbag_device_data_hidpp10_get_profile_count(const struct ratbag_device_data *data); + +struct dpi_list * +ratbag_device_data_hidpp10_get_dpi_list(const struct ratbag_device_data *data); + +struct dpi_range * +ratbag_device_data_hidpp10_get_dpi_range(const struct ratbag_device_data *data); + +/* HID++ 2.0 */ + +/** + * @return The device index or -1 if not set + */ +int +ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data); diff --git a/src/libratbag-private.h b/src/libratbag-private.h index e8b98373..426ddba5 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -90,6 +90,7 @@ struct ratbag_device { struct input_id ids; struct ratbag_driver *driver; struct ratbag *ratbag; + struct ratbag_device_data *data; unsigned long capabilities[NLONGS(MAX_CAP)]; unsigned num_profiles; diff --git a/src/libratbag.c b/src/libratbag.c index 789955c4..b72fd1bf 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -37,6 +37,7 @@ #include "usb-ids.h" #include "libratbag-private.h" #include "libratbag-util.h" +#include "libratbag-data.h" static enum ratbag_error_code error_code(enum ratbag_error_code code) @@ -180,6 +181,7 @@ ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device, device->refcount = 1; device->udev_device = udev_device_ref(udev_device); device->ids = *id; + device->data = ratbag_device_data_new_for_id(ratbag, id); list_init(&device->profiles); list_insert(&ratbag->devices, &device->link); @@ -217,6 +219,7 @@ ratbag_device_destroy(struct ratbag_device *device) list_remove(&device->link); ratbag_unref(device->ratbag); + ratbag_device_data_unref(device->data); free(device->name); free(device); } @@ -358,7 +361,7 @@ ratbag_assign_driver(struct ratbag_device *device, const char *driver_name; if (!test_device) { - driver_name = udev_prop_value(device->udev_device, "RATBAG_DRIVER"); + driver_name = ratbag_device_data_get_driver(device->data); } else { driver_name = "test_driver"; } @@ -433,7 +436,7 @@ ratbag_device_new_from_udev_device(struct ratbag *ratbag, goto out_err; device = ratbag_device_new(ratbag, udev_device, name, &id); - if (!device) + if (!device || !device->data) goto out_err; if (!ratbag_assign_driver(device, &device->ids, NULL)) @@ -483,9 +486,10 @@ ratbag_device_get_name(const struct ratbag_device* device) LIBRATBAG_EXPORT const char * ratbag_device_get_svg_name(const struct ratbag_device* device) { - const char *name; + const char *name = NULL; - name = udev_prop_value(device->udev_device, "RATBAG_SVG"); + if (device->data) + name = ratbag_device_data_get_svg(device->data); if (!name && device->driver->get_svg_name) name = device->driver->get_svg_name(device);