mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
ratbagd: pick the ID from a list of preselected names
We don't want anyone to rely on a specific content of the ID, e.g. by hardcoding hidraw/event node numbers. So let's make this an opaque list with no meaning other than "this is a rodent". This is solely for the benefit of ratbagctl which uses these IDs as access identifier. This doesn't affect ratbag-command which still uses device paths. It also does not affect the object path. And piper shows the device name anyway. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
@@ -44,6 +44,7 @@ struct ratbagd_device {
|
||||
struct ratbagd *ctx;
|
||||
RBNode node;
|
||||
char *sysname;
|
||||
char *id;
|
||||
char *path;
|
||||
struct ratbag_device *lib_device;
|
||||
|
||||
@@ -274,7 +275,7 @@ ratbagd_device_get_capabilities(sd_bus *bus,
|
||||
|
||||
const sd_bus_vtable ratbagd_device_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, sysname), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, id), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 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),
|
||||
@@ -287,6 +288,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = {
|
||||
int ratbagd_device_new(struct ratbagd_device **out,
|
||||
struct ratbagd *ctx,
|
||||
const char *sysname,
|
||||
const char *id,
|
||||
struct ratbag_device *lib_device)
|
||||
{
|
||||
_cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL;
|
||||
@@ -297,6 +299,7 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
assert(out);
|
||||
assert(ctx);
|
||||
assert(sysname);
|
||||
assert(id);
|
||||
|
||||
device = zalloc(sizeof(*device));
|
||||
device->ctx = ctx;
|
||||
@@ -304,6 +307,7 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
device->lib_device = ratbag_device_ref(lib_device);
|
||||
|
||||
device->sysname = strdup_safe(sysname);
|
||||
device->id = strdup_safe(id);
|
||||
|
||||
r = sd_bus_path_encode(RATBAGD_OBJ_ROOT "/device",
|
||||
device->sysname,
|
||||
@@ -357,12 +361,19 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
|
||||
device->lib_device = ratbag_device_unref(device->lib_device);
|
||||
device->path = mfree(device->path);
|
||||
device->sysname = mfree(device->sysname);
|
||||
device->id = mfree(device->id);
|
||||
|
||||
assert(!device->lib_device); /* ratbag yields !NULL if still pinned */
|
||||
|
||||
return mfree(device);
|
||||
}
|
||||
|
||||
const char *ratbagd_device_get_id(struct ratbagd_device *device)
|
||||
{
|
||||
assert(device);
|
||||
return device->sysname;
|
||||
}
|
||||
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device)
|
||||
{
|
||||
assert(device);
|
||||
|
||||
@@ -190,7 +190,7 @@ int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
|
||||
device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr);
|
||||
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device);
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", "test_device", device);
|
||||
|
||||
/* the ratbagd_device takes its own reference, drop ours */
|
||||
ratbag_device_unref(device);
|
||||
|
||||
@@ -204,6 +204,67 @@ static const sd_bus_vtable ratbagd_vtable[] = {
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
/* 32 pre-picked names. If you have more than 32 devices connected and need
|
||||
* ratbag to control them all, congratulations, you are official a niche
|
||||
* use-case.
|
||||
*/
|
||||
static const char *device_ids[] = {
|
||||
"mara", "capybara", "porcupine", "paca",
|
||||
"vole", "woodrat", "gerbil", "shrew",
|
||||
"hare", "beaver", "gopher", "chinchilla",
|
||||
"mouse", "rat", "rabbit", "guineapig",
|
||||
"hutia", "degu", "gundi", "acouchy",
|
||||
"nutria", "tuco-tuco", "paca", "hamster",
|
||||
"zokor", "chipmunk", "squirrel", "marmot",
|
||||
"groundhog", "suslik", "agouti", "blesmol",
|
||||
};
|
||||
|
||||
/* bitmask telling us which ones of the above are free. */
|
||||
static uint32_t device_ids_free = (1UL << ARRAY_LENGTH(device_ids)) - 1;
|
||||
|
||||
static inline const char *
|
||||
pick_device_id(const char *sysname)
|
||||
{
|
||||
int index;
|
||||
|
||||
/* search for the first number in the sysname and where we find it,
|
||||
* use that as lookup index. This way we get some sort of
|
||||
* consistency, hidraw2 is always "rat", etc.
|
||||
* Totally not necessary but we might as well have some fun here.
|
||||
* Where this fails or picks an id already chosen, we fall back to
|
||||
* "choose the first one free".
|
||||
*/
|
||||
if (sscanf(sysname, "%*[^0-9]%d", &index) == 1 &&
|
||||
index >= 0 && (unsigned)index < sizeof(device_ids_free) * 8 &&
|
||||
!!(device_ids_free & (1 << index)))
|
||||
goto assign;
|
||||
|
||||
index = ffs(device_ids_free);
|
||||
|
||||
/* This can only happen if you have >32 devices, so let's not worry
|
||||
* about this too much */
|
||||
if (index == 0)
|
||||
return sysname;
|
||||
|
||||
index -= 1; /* ffs is 1-based */
|
||||
|
||||
assign:
|
||||
device_ids_free &= ~(1 << index);
|
||||
|
||||
return device_ids[index];
|
||||
}
|
||||
|
||||
static inline void
|
||||
release_device_id(const char *id)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(device_ids); i++) {
|
||||
if (streq(id, device_ids[i])) {
|
||||
device_ids_free |= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
struct udev_device *udevice)
|
||||
{
|
||||
@@ -230,9 +291,11 @@ static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
if (streq_ptr("remove", udev_device_get_action(udevice))) {
|
||||
/* device was removed, unlink it and destroy our context */
|
||||
if (device) {
|
||||
release_device_id(ratbagd_device_get_id(device));
|
||||
ratbagd_device_unlink(device);
|
||||
ratbagd_device_free(device);
|
||||
|
||||
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
RATBAGD_NAME_ROOT ".Manager",
|
||||
@@ -242,6 +305,7 @@ static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
} else if (device) {
|
||||
/* device already known, refresh our view of the device */
|
||||
} else {
|
||||
const char *id;
|
||||
enum ratbag_error_code error;
|
||||
|
||||
/* device unknown, create new one and link it */
|
||||
@@ -251,7 +315,8 @@ static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
if (error != RATBAG_SUCCESS)
|
||||
return; /* unsupported device */
|
||||
|
||||
r = ratbagd_device_new(&device, ctx, sysname, lib_device);
|
||||
id = pick_device_id(sysname);
|
||||
r = ratbagd_device_new(&device, ctx, sysname, id, lib_device);
|
||||
|
||||
/* the ratbagd_device takes its own reference, drop ours */
|
||||
ratbag_device_unref(lib_device);
|
||||
|
||||
@@ -169,8 +169,10 @@ extern const sd_bus_vtable ratbagd_device_vtable[];
|
||||
int ratbagd_device_new(struct ratbagd_device **out,
|
||||
struct ratbagd *ctx,
|
||||
const char *sysname,
|
||||
const char *id,
|
||||
struct ratbag_device *lib_device);
|
||||
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_id(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_path(struct ratbagd_device *device);
|
||||
unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device);
|
||||
|
||||
Reference in New Issue
Block a user