ratbagd: export the Model property for the device

When the SVGs need to be maintained elsewhere, we need something reliable to
match devices with SVGs. The easiest is to provide a unique model string,
usually composed from the usb/bluetooth information.

A string format was chosen to make it more flexible for the glorious future
where we have something other than usb or bluetooth devices. Meanwhile, the
format is the well-known "usb:1234:56ef:0" string (bus, vid, pid, version).

The version in this string is a future-proof safeguard for libratbag. It will
be used where libratbag supports two devices with the same VID/PID and where
this is not otherwise differentiable. We don't have any such devices yet, so
libratbag just returns a hardcoded 0.

The format is currently defined for usb and bluetooth, in the future we may
have other strings.

The base guarantee is that this is a reliable identifier for the model that
will never change for that model. IOW this is what piper can use to map
devices to their SVGs.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2019-02-21 12:54:12 +10:00
committed by Benjamin Tissoires
parent 367aa29dfe
commit 10a1cc9bbc
6 changed files with 160 additions and 0 deletions

View File

@@ -120,6 +120,48 @@ known to ratbagd.
content of the ID is undefined, the client should treat it as an
opaque string.
.. attribute:: Model
:type: s
:flags: read-only, constant
An ID identifying the physical device model. This string is
guaranteed to be unique for a specific model and always identical
for devices of that model.
This is a string of one of the following formats:
- ``usb:1234:abcd:0``
- ``bluetooth:5678:ef01:0``
- ``unknown``
In the future, other formats may get added. Clients must ignore
unknown string formats.
For a string starting with `usb:`, the format is the bus type (USB)
followed by a 4-digit lowercase hex USB vendor ID, followed by a
4-digit lowercase hex USB product ID, followed by an decimal version
number of unspecified length. These four elements are separated by a
colon (``:``).
For a string starting with `bluetooth:`, the format is the bus type
(Bluetooth) followed by a 4-digit lowercase hex Bluetooth vendor ID,
followed by a 4-digit lowercase hex Bluetooth product ID, followed
by an decimal version number of unspecified length. These four
elements are separated by a colon (``:``).
For the string ``unknown``, the model of the device cannot be
determined. This is usually a bug in libratbag.
For ``DeviceId``s of type ``usb`` and ``bluetooth``, the version
number is reserved for use by libratbag. Device with identical
vendor and product IDs but different versions must be considered
different devices. For example, the version may increase when a
manufacturer re-uses USB Ids.
Vendor or product IDs of 0 are valid IDs (e.g. used used by test
devices).
.. attribute:: Name
:type: s

View File

@@ -232,9 +232,36 @@ static int ratbagd_device_commit(sd_bus_message *m,
return 0;
}
static int
ratbag_device_get_model(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;
struct ratbag_device *lib_device = device->lib_device;
const char *bustype = ratbag_device_get_bustype(lib_device);
uint32_t vid = ratbag_device_get_vendor_id(lib_device),
pid = ratbag_device_get_product_id(lib_device),
version = ratbag_device_get_product_version(lib_device);
char model[64];
if (!bustype)
return sd_bus_message_append(reply, "s", "unknown");
snprintf(model, sizeof(model), "%s:%04x:%04x:%d",
bustype, vid, pid, version);
return sd_bus_message_append(reply, "s", model);
}
const sd_bus_vtable ratbagd_device_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Model", "s", ratbag_device_get_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetSvgFd", "s", "h", ratbagd_device_get_theme_svg_fd, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@@ -517,6 +517,39 @@ ratbag_device_get_svg_name(const struct ratbag_device* device)
return name;
}
LIBRATBAG_EXPORT const char *
ratbag_device_get_bustype(const struct ratbag_device *device)
{
switch (device->ids.bustype) {
case BUS_USB:
return "usb";
case BUS_BLUETOOTH:
return "bluetooth";
default:
return NULL;
}
}
LIBRATBAG_EXPORT uint32_t
ratbag_device_get_vendor_id(const struct ratbag_device *device)
{
return device->ids.vendor;
}
LIBRATBAG_EXPORT uint32_t
ratbag_device_get_product_id(const struct ratbag_device *device)
{
return device->ids.product;
}
LIBRATBAG_EXPORT uint32_t
ratbag_device_get_product_version(const struct ratbag_device *device)
{
/* change this when we have a need for it, i.e. when we start supporting devices
* where the USB ID gets reused */
return 0;
}
void
ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver)
{

View File

@@ -24,6 +24,7 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include <libudev.h>
@@ -439,6 +440,47 @@ ratbag_device_get_name(const struct ratbag_device* device);
const char *
ratbag_device_get_svg_name(const struct ratbag_device* device);
/**
* @ingroup device
*
* Returns the bustype of the device, "usb", "bluetooth" or NULL for
* unknown.
*/
const char *
ratbag_device_get_bustype(const struct ratbag_device *device);
/**
* @ingroup device
*
* Returns the vendor ID of the device.
*/
uint32_t
ratbag_device_get_vendor_id(const struct ratbag_device *device);
/**
* @ingroup device
*
* Returns the product ID of the device.
*/
uint32_t
ratbag_device_get_product_id(const struct ratbag_device *device);
/**
* @ingroup device
*
* Returns the product version of the device. This is a made-up number,
* internal to libratbag. It's purpose is to provide an extra bit of
* differentiation where devices use the same VID/PID for different models.
*
* Devices with identical VID/PID but different versions must be considered
* different devices.
*
* Usually the version will be 0.
*/
uint32_t
ratbag_device_get_product_version(const struct ratbag_device *device);
/**
* @ingroup device
*

View File

@@ -249,6 +249,17 @@ class RatbagdDevice(metaclass=MetaRatbag):
"""The unique identifier of this device."""
return self._path
@property
def model(self):
"""The unique identifier for this device model."""
bus = libratbag.ratbag_device_get_bus(self._device)
if not bus:
return "unknown"
vid = libratbag.ratbag_device_get_vendor_id(self._device)
pid = libratbag.ratbag_device_get_product_id(self._device)
version = libratbag.ratbag_device_get_product_version(self._device)
return "{}:{04x}:{04x}:{d}".format(bus, vid, pid, version)
@property
def name(self):
"""The device name, usually provided by the kernel."""

View File

@@ -347,6 +347,11 @@ class RatbagdDevice(_RatbagdDBus):
"""The unique identifier of this device."""
return self._get_dbus_property("Id")
@GObject.Property
def model(self):
"""The unique identifier for this device model."""
return self._get_dbus_property("Model")
@GObject.Property
def name(self):
"""The device name, usually provided by the kernel."""