mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
ratbagd: expose profiles on the bus
Profiles are static children of devices. Expose them as 2nd-level objects underneath their parent devices on the bus. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
@@ -80,7 +80,8 @@ bin_PROGRAMS += \
|
||||
ratbagd_SOURCES = \
|
||||
src/ratbagd.h \
|
||||
src/ratbagd.c \
|
||||
src/ratbagd-device.c
|
||||
src/ratbagd-device.c \
|
||||
src/ratbagd-profile.c
|
||||
|
||||
ratbagd_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
|
||||
@@ -40,11 +40,83 @@ struct ratbagd_device {
|
||||
RBNode node;
|
||||
char *name;
|
||||
struct ratbag_device *lib_device;
|
||||
|
||||
sd_bus_slot *profile_vtable_slot;
|
||||
sd_bus_slot *profile_enum_slot;
|
||||
unsigned int n_profiles;
|
||||
struct ratbagd_profile **profiles;
|
||||
};
|
||||
|
||||
#define ratbagd_device_from_node(_ptr) \
|
||||
rbnode_of((_ptr), struct ratbagd_device, node)
|
||||
|
||||
static int ratbagd_device_find_profile(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
void *userdata,
|
||||
void **found,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
_cleanup_(freep) char *name = NULL;
|
||||
struct ratbagd_device *device = userdata;
|
||||
unsigned int index;
|
||||
int r;
|
||||
|
||||
r = sd_bus_path_decode_many(path,
|
||||
"/org/freedesktop/ratbag1/device/%/profile/%",
|
||||
NULL,
|
||||
&name);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = safe_atou(name, &index);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (index >= device->n_profiles)
|
||||
return 0;
|
||||
|
||||
*found = device->profiles[index];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ratbagd_device_list_profiles(sd_bus *bus,
|
||||
const char *path,
|
||||
void *userdata,
|
||||
char ***paths,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_device *device = userdata;
|
||||
char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
|
||||
char **profiles;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
profiles = calloc(device->n_profiles + 1, sizeof(char *));
|
||||
if (!profiles)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < device->n_profiles; ++i) {
|
||||
sprintf(index_buffer, "%u", i);
|
||||
r = sd_bus_path_encode_many(&profiles[i],
|
||||
"/org/freedesktop/ratbag1/device/%/profile/%",
|
||||
device->name,
|
||||
index_buffer);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
profiles[i] = NULL;
|
||||
*paths = profiles;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
for (i = 0; profiles[i]; ++i)
|
||||
free(profiles[i]);
|
||||
free(profiles);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ratbagd_device_get_description(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
@@ -76,6 +148,9 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
struct ratbag_device *lib_device)
|
||||
{
|
||||
_cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL;
|
||||
struct ratbag_profile *profile;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
assert(out);
|
||||
assert(ctx);
|
||||
@@ -93,6 +168,25 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
if (!device->name)
|
||||
return -ENOMEM;
|
||||
|
||||
device->n_profiles = ratbag_device_get_num_profiles(device->lib_device);
|
||||
device->profiles = calloc(device->n_profiles, sizeof(*device->profiles));
|
||||
if (!device->profiles)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < device->n_profiles; ++i) {
|
||||
profile = ratbag_device_get_profile(device->lib_device, i);
|
||||
if (!profile)
|
||||
continue;
|
||||
|
||||
r = ratbagd_profile_new(&device->profiles[i], profile, i);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
fprintf(stderr,
|
||||
"Cannot allocate profile for '%s': %m\n",
|
||||
device->name);
|
||||
}
|
||||
}
|
||||
|
||||
*out = device;
|
||||
device = NULL;
|
||||
return 0;
|
||||
@@ -100,11 +194,17 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
|
||||
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
assert(!ratbagd_device_linked(device));
|
||||
|
||||
for (i = 0; i < device->n_profiles; ++i)
|
||||
device->profiles[i] = ratbagd_profile_free(device->profiles[i]);
|
||||
|
||||
device->profiles = mfree(device->profiles);
|
||||
device->lib_device = ratbag_device_unref(device->lib_device);
|
||||
device->name = mfree(device->name);
|
||||
|
||||
@@ -120,7 +220,7 @@ bool ratbagd_device_linked(struct ratbagd_device *device)
|
||||
|
||||
void ratbagd_device_link(struct ratbagd_device *device)
|
||||
{
|
||||
_cleanup_(freep) char *path = NULL;
|
||||
_cleanup_(freep) char *path = NULL, *prefix = NULL;
|
||||
struct ratbagd_device *iter;
|
||||
RBNode **node, *parent;
|
||||
int r, v;
|
||||
@@ -161,6 +261,32 @@ void ratbagd_device_link(struct ratbagd_device *device)
|
||||
"Cannot send device notification for '%s': %m\n",
|
||||
device->name);
|
||||
}
|
||||
|
||||
/* register profile interfaces */
|
||||
r = sd_bus_path_encode_many(&prefix,
|
||||
"/org/freedesktop/ratbag1/device/%/profile",
|
||||
device->name);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_add_fallback_vtable(device->ctx->bus,
|
||||
&device->profile_vtable_slot,
|
||||
prefix,
|
||||
"org.freedesktop.ratbag1.Profile",
|
||||
ratbagd_profile_vtable,
|
||||
ratbagd_device_find_profile,
|
||||
device);
|
||||
if (r >= 0)
|
||||
r = sd_bus_add_node_enumerator(device->ctx->bus,
|
||||
&device->profile_enum_slot,
|
||||
prefix,
|
||||
ratbagd_device_list_profiles,
|
||||
device);
|
||||
}
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
fprintf(stderr,
|
||||
"Cannot register profile interfaces for '%s': %m\n",
|
||||
device->name);
|
||||
}
|
||||
}
|
||||
|
||||
void ratbagd_device_unlink(struct ratbagd_device *device)
|
||||
@@ -171,6 +297,9 @@ void ratbagd_device_unlink(struct ratbagd_device *device)
|
||||
if (!ratbagd_device_linked(device))
|
||||
return;
|
||||
|
||||
device->profile_enum_slot = sd_bus_slot_unref(device->profile_enum_slot);
|
||||
device->profile_vtable_slot = sd_bus_slot_unref(device->profile_vtable_slot);
|
||||
|
||||
/* send out object-manager notification */
|
||||
r = sd_bus_path_encode("/org/freedesktop/ratbag1/device",
|
||||
device->name,
|
||||
|
||||
79
src/ratbagd-profile.c
Normal file
79
src/ratbagd-profile.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/***
|
||||
This file is part of ratbagd.
|
||||
|
||||
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libratbag.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "ratbagd.h"
|
||||
#include "shared-macro.h"
|
||||
|
||||
struct ratbagd_profile {
|
||||
struct ratbag_profile *lib_profile;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
const sd_bus_vtable ratbagd_profile_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_profile, index), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
struct ratbag_profile *lib_profile,
|
||||
unsigned int index)
|
||||
{
|
||||
_cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL;
|
||||
|
||||
assert(out);
|
||||
assert(lib_profile);
|
||||
|
||||
profile = calloc(1, sizeof(*profile));
|
||||
if (!profile)
|
||||
return -ENOMEM;
|
||||
|
||||
profile->lib_profile = lib_profile;
|
||||
profile->index = index;
|
||||
|
||||
*out = profile;
|
||||
profile = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile)
|
||||
{
|
||||
if (!profile)
|
||||
return NULL;
|
||||
|
||||
/* we cannot assume the profile is gone, so set NULL explicitly */
|
||||
ratbag_profile_unref(profile->lib_profile);
|
||||
profile->lib_profile = NULL;
|
||||
|
||||
return mfree(profile);
|
||||
}
|
||||
@@ -38,6 +38,20 @@
|
||||
|
||||
struct ratbagd;
|
||||
struct ratbagd_device;
|
||||
struct ratbagd_profile;
|
||||
|
||||
/*
|
||||
* Profiles
|
||||
*/
|
||||
|
||||
extern const sd_bus_vtable ratbagd_profile_vtable[];
|
||||
|
||||
int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
struct ratbag_profile *lib_profile,
|
||||
unsigned int index);
|
||||
struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free);
|
||||
|
||||
/*
|
||||
* Devices
|
||||
|
||||
@@ -74,6 +74,18 @@
|
||||
#define _weak_ __attribute__((weak))
|
||||
#define _weakref_(_x) __attribute__((weakref(#_x)))
|
||||
|
||||
/*
|
||||
* DECIMAL_TOKEN_MAX() - calculate maximum length of the decimal representation
|
||||
* of an integer
|
||||
* @_type: type of integer
|
||||
*/
|
||||
#define DECIMAL_TOKEN_MAX(_type) \
|
||||
(1 + (sizeof(_type) <= 1 ? 3 : \
|
||||
sizeof(_type) <= 2 ? 5 : \
|
||||
sizeof(_type) <= 4 ? 10 : \
|
||||
sizeof(_type) <= 8 ? 20 : \
|
||||
sizeof(int[-2 * (sizeof(_type) > 8)])))
|
||||
|
||||
/*
|
||||
* PROTECT_ERRNO: make sure a function protects errno
|
||||
*/
|
||||
@@ -204,6 +216,36 @@ static inline char *startswith(const char *s, const char *prefix)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* safe_atou() - safe variant of strtoul()
|
||||
* @s: string to parse
|
||||
* @ret_u: output storage for parsed integer
|
||||
*
|
||||
* This is a sane and safe variant of strtoul(), which rejects any invalid
|
||||
* input, or trailing garbage.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
static inline int safe_atou(const char *s, unsigned int *ret_u)
|
||||
{
|
||||
char *x = NULL;
|
||||
unsigned long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_u);
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(s, &x, 0);
|
||||
if (!x || x == s || *x || errno)
|
||||
return errno > 0 ? -errno : -EINVAL;
|
||||
|
||||
if ((unsigned long)(unsigned int)l != l)
|
||||
return -ERANGE;
|
||||
|
||||
*ret_u = (unsigned int)l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* now() - returns current time in nano-seconds
|
||||
* @clock: clock to use
|
||||
|
||||
Reference in New Issue
Block a user