--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <json.h>
+
+#include "resource-manager.h"
+#include "resource-type.h"
+
+#define RESOURCE_ATTR_MASK (ULLONG_MAX)
+#define BIT64_INDEX(id) (63 - __builtin_clzll(id))
+#define RESOURCE_ATTR_INDEX(id) BIT64_INDEX(id)
+#define RESOURCE_CTRL_INDEX(id) BIT64_INDEX(id)
+#define RESOURCE_FLAG_VISIBILITY_MASK (SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE \
+ | SYSCOMMON_RESMAN_RESOURCE_FLAG_PUBLIC)
+#define RESOURCE_ATTR_FLAG_VISIBILITY_MASK (SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PRIVATE \
+ | SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC)
+
+
+static GList *g_resource_driver_head;
+
+static gint __compare_resource_type(gconstpointer data, gconstpointer input)
+{
+ struct syscommon_resman_resource_driver *driver;
+ int type = *(int *)input;
+
+ driver = (struct syscommon_resman_resource_driver *)data;
+
+ if (driver && driver->type == type)
+ return 0;
+ return -1;
+}
+
+const struct syscommon_resman_resource_driver *
+syscommon_resman_find_resource_driver(int resource_type)
+{
+ GList *node;
+
+ node = g_list_find_custom(g_resource_driver_head,
+ &resource_type, __compare_resource_type);
+
+ if (!node)
+ return NULL;
+ return (struct syscommon_resman_resource_driver *)node->data;
+}
+
+void
+syscommon_resman_add_resource_driver(const struct syscommon_resman_resource_driver *driver)
+{
+ if (!driver)
+ return;
+
+ g_resource_driver_head =
+ g_list_append(g_resource_driver_head, (gpointer)driver);
+}
+
+void
+syscommon_resman_remove_resource_driver(const struct syscommon_resman_resource_driver *driver)
+{
+ if (!driver)
+ return;
+
+ g_resource_driver_head =
+ g_list_remove(g_resource_driver_head, (gpointer)driver);
+}
+
+static void do_delete_resource(struct syscommon_resman_resource *resource)
+{
+ if (!resource->name)
+ free(resource->name);
+ if (!resource->attrs_value)
+ free(resource->attrs_value);
+ resource->attrs = NULL;
+ resource->num_attrs = 0;
+
+ free(resource);
+}
+
+void
+syscommon_resman_delete_resource(struct syscommon_resman_resource *resource)
+{
+ if (!resource)
+ return;
+
+ if (resource->driver && resource->driver->ops.delete)
+ resource->driver->ops.delete(resource);
+
+ syscommon_resman_unset_resource_attr_interest(resource, RESOURCE_ATTR_MASK);
+
+ do_delete_resource(resource);
+}
+
+int
+syscommon_resman_create_resource(struct syscommon_resman_resource **res,
+ int resource_type)
+{
+ const struct syscommon_resman_resource_driver *driver = NULL;
+ struct syscommon_resman_resource *resource = NULL;
+ int i, ret;
+
+ if (!res)
+ return -EINVAL;
+
+ driver = syscommon_resman_find_resource_driver(resource_type);
+ if (!driver)
+ return -EINVAL;
+
+ resource = calloc(1, sizeof(*resource));
+ if (!resource)
+ return -ENOMEM;
+
+ resource->type = resource_type;
+ resource->name = g_strdup(driver->name);
+ resource->driver = driver;
+ resource->num_attrs = driver->num_attrs;
+ resource->attrs = driver->attrs;
+ resource->attrs_value = calloc(resource->num_attrs,
+ sizeof(*resource->attrs_value));
+ if (!resource->attrs_value) {
+ do_delete_resource(resource);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < resource->num_attrs; i++)
+ resource->attrs_value[i].type = driver->attrs[i].type;
+
+ resource->ctrls = driver->ctrls;
+ resource->num_ctrls = driver->num_ctrls;
+ resource->flag = SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE;
+
+ if (driver->ops.create) {
+ ret = driver->ops.create(resource);
+ if (ret < 0) {
+ do_delete_resource(resource);
+ return ret;
+ }
+ }
+
+ *res = resource;
+
+ return 0;
+}
+
+int
+syscommon_resman_set_resource_flag(struct syscommon_resman_resource *resource,
+ u_int64_t flag_mask)
+{
+ if (!resource)
+ return -EINVAL;
+
+ resource->flag = flag_mask;
+ return 0;
+}
+
+int
+syscommon_resman_set_resource_control(struct syscommon_resman_resource *resource,
+ u_int64_t ctrl_id, const void *data)
+{
+ const struct syscommon_resman_resource_control *ctrl;
+ int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
+ int ret;
+
+ if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
+ return -EINVAL;
+
+ ctrl = &resource->ctrls[ctrl_index];
+ if (!ctrl->ops.set)
+ return -ENOTSUP;
+
+ ret = ctrl->ops.set(resource, ctrl, data);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+const char *
+syscommon_resman_get_resource_control_name(struct syscommon_resman_resource *resource,
+ u_int64_t ctrl_id)
+{
+ const struct syscommon_resman_resource_control *ctrl;
+ int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
+
+ if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
+ return NULL;
+
+ ctrl = &resource->ctrls[ctrl_index];
+
+ return ctrl->name;
+}
+
+static int
+update_resource_attr(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id)
+{
+ int attr_index = RESOURCE_ATTR_INDEX(attr_id);
+ const struct syscommon_resman_resource_attribute *attr = NULL;
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+ int ret;
+
+ if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
+ return -EINVAL;
+
+ attr = &resource->attrs[attr_index];
+
+ if (!attr->ops.get)
+ return -EINVAL;
+
+ attr_value = &resource->attrs_value[attr_index];
+
+ ret = attr->ops.get(resource, attr, attr_value->data);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int
+syscommon_resman_update_resource_attrs(struct syscommon_resman_resource *resource)
+{
+ int i, ret;
+
+ if (!resource || !resource->type)
+ return -EINVAL;
+
+ if (resource->driver && resource->driver->ops.prepare_update) {
+ ret = resource->driver->ops.prepare_update(resource);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < resource->num_attrs; i++) {
+ if (!(resource->attrs[i].id & resource->attr_interest))
+ continue;
+ update_resource_attr(resource, resource->attrs[i].id);
+ }
+
+ return 0;
+}
+
+const struct syscommon_resman_resource_attribute *
+syscommon_resman_get_resource_attr(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id)
+{
+ int attr_index = RESOURCE_ATTR_INDEX(attr_id);
+
+ if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
+ return NULL;
+
+ return &resource->attrs[attr_index];
+}
+
+struct syscommon_resman_resource_attribute_value *
+syscommon_resman_get_resource_attr_value(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id)
+{
+ int attr_index = RESOURCE_ATTR_INDEX(attr_id);
+
+ if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
+ return NULL;
+
+ return &resource->attrs_value[attr_index];
+}
+
+int
+syscommon_resman_is_resource_attr_supported(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, bool *supported)
+{
+ const struct syscommon_resman_resource_attribute *attr = NULL;
+ int attr_index = RESOURCE_ATTR_INDEX(attr_id);
+ int ret;
+ bool is_supported = false;
+
+ if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
+ return -EINVAL;
+
+ attr = &resource->attrs[attr_index];
+
+ if (attr->id & resource->attr_supported) {
+ is_supported = true;
+ } else if (attr->ops.is_supported) {
+ is_supported = attr->ops.is_supported(resource, attr);
+ } else if (attr->ops.get) {
+ /*
+ * Optionally, if .is_supported ops is not implemented,
+ * use .get ops in order to check whether the resource attribute
+ * is supported or not.
+ */
+ char data[SYSCOMMON_RESMAN_BUFF_MAX] = {0, };
+
+ ret = attr->ops.get(resource, attr, (void *)data);
+ is_supported = (ret < 0) ? false : true;
+ }
+
+ if (is_supported)
+ resource->attr_supported |= attr->id;
+
+ *supported = is_supported;
+
+ return 0;
+}
+
+static bool
+check_attr_validate(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, int type)
+{
+ const struct syscommon_resman_resource_attribute *attr;
+
+ attr = syscommon_resman_get_resource_attr(resource, attr_id);
+ if (!attr)
+ return false;
+
+ if (attr->type != type)
+ return false;
+
+ if (!(attr->id & resource->attr_interest))
+ return false;
+
+ return true;
+}
+
+static json_object *
+_get_resource_attr_json(const struct syscommon_resman_resource_attribute *attr,
+ const struct syscommon_resman_resource_attribute_value *attr_value)
+{
+ json_object *jobj_attr, *jobj_attr_name, *jobj_attr_type, *jobj_attr_value, *jobj_temp;
+ struct syscommon_resman_array_value *array;
+ int i;
+
+ switch (attr->type) {
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT:
+ jobj_attr_value = json_object_new_int(*((int32_t *)attr_value->data));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
+ jobj_attr_value = json_object_new_int(*((u_int32_t *)attr_value->data));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
+ jobj_attr_value = json_object_new_int64(*((int64_t *)attr_value->data));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
+ jobj_attr_value = json_object_new_uint64(*((u_int64_t *)attr_value->data));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
+ jobj_attr_value = json_object_new_double(*((double *)attr_value->data));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
+ jobj_attr_value = json_object_new_string((char *)attr_value->data);
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
+ array = attr_value->data;
+
+ jobj_attr_value = json_object_new_array();
+
+ switch (array->type) {
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT:
+ for (i = 0; i < array->length; i++) {
+ int32_t *item = array->data;
+
+ jobj_temp = json_object_new_int(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
+ for (i = 0; i < array->length; i++) {
+ u_int32_t *item = array->data;
+
+ jobj_temp = json_object_new_int(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
+ for (i = 0; i < array->length; i++) {
+ int64_t *item = array->data;
+
+ jobj_temp = json_object_new_int64(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
+ for (i = 0; i < array->length; i++) {
+ u_int64_t *item = array->data;
+
+ jobj_temp = json_object_new_uint64(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
+ for (i = 0; i < array->length; i++) {
+ double *item = array->data;
+
+ jobj_temp = json_object_new_double(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
+ for (i = 0; i < array->length; i++) {
+ char **item = array->data;
+
+ jobj_temp = json_object_new_string(item[i]);
+ json_object_array_add(jobj_attr_value, jobj_temp);
+ }
+ break;
+ default:
+ json_object_put(jobj_attr_value);
+ jobj_attr_value = json_object_new_null();
+ }
+ break;
+ default:
+ jobj_attr_value = json_object_new_null();
+ }
+ jobj_attr = json_object_new_object();
+
+ jobj_attr_name = json_object_new_string(attr->name);
+ /*
+ * Since actually JSON format has no data type limitation itself, in many
+ * cases except converting JSON into json-c, type is not required. So,
+ * for the case of converting JSON generated here to json-c object again
+ * json_type is stored in each attributes.
+ */
+ jobj_attr_type = json_object_new_int(json_object_get_type(jobj_attr_value));
+
+ json_object_object_add(jobj_attr, "name", jobj_attr_name);
+ json_object_object_add(jobj_attr, "json_type", jobj_attr_type);
+ json_object_object_add(jobj_attr, "value", jobj_attr_value);
+
+ return jobj_attr;
+}
+
+static void _put_resource_attr_json(json_object *jobj_attr)
+{
+ json_object *jobj_attr_value;
+
+ json_object_object_del(jobj_attr, "name");
+ json_object_object_del(jobj_attr, "json_type");
+
+ if (json_object_object_get_ex(jobj_attr, "value", &jobj_attr_value) &&
+ json_object_is_type(jobj_attr_value, json_type_array))
+ json_object_array_del_idx(jobj_attr_value, 0,
+ json_object_array_length(jobj_attr_value));
+
+ json_object_object_del(jobj_attr, "value");
+}
+
+int
+syscommon_resman_get_resource_attrs_json(struct syscommon_resman_resource *resource,
+ char **json_string)
+{
+ json_object *jobj_root, *jobj_res_name, *jobj_res_type, *jobj_res_attrs, *jobj_attr;
+ const struct syscommon_resman_resource_attribute *attr;
+ const struct syscommon_resman_resource_attribute_value *attr_value;
+ int i;
+
+ if (!resource || !resource->type)
+ return -EINVAL;
+
+ jobj_root = json_object_new_object();
+
+ jobj_res_name = json_object_new_string(resource->name);
+ jobj_res_type = json_object_new_int(resource->type);
+ jobj_res_attrs = json_object_new_array();
+
+ for (i = 0; i < resource->num_attrs; i++) {
+ if (!(resource->attrs[i].id & resource->attr_interest))
+ continue;
+
+ attr = &resource->attrs[i];
+ attr_value = &resource->attrs_value[i];
+
+ jobj_attr = _get_resource_attr_json(attr, attr_value);
+
+ json_object_array_add(jobj_res_attrs, jobj_attr);
+ }
+
+ json_object_object_add(jobj_root, "res_name", jobj_res_name);
+ json_object_object_add(jobj_root, "res_type", jobj_res_type);
+ json_object_object_add(jobj_root, "res_attrs", jobj_res_attrs);
+
+ *json_string = strdup(json_object_to_json_string(jobj_root));
+
+ for (i = 0; i < json_object_array_length(jobj_res_attrs); i++) {
+ jobj_attr = json_object_array_get_idx(jobj_res_attrs, i);
+ _put_resource_attr_json(jobj_attr);
+ }
+ json_object_array_del_idx(jobj_res_attrs, 0, json_object_array_length(jobj_res_attrs));
+
+ json_object_object_del(jobj_root, "res_attrs");
+ json_object_object_del(jobj_root, "res_type");
+ json_object_object_del(jobj_root, "res_name");
+ json_object_put(jobj_root);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_json(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, char **json_string)
+{
+ const struct syscommon_resman_resource_attribute *attr;
+ const struct syscommon_resman_resource_attribute_value *attr_value;
+ json_object *jobj_attr;
+
+ attr = syscommon_resman_get_resource_attr(resource, attr_id);
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+
+ if (!attr || !attr_value)
+ return -EINVAL;
+
+ jobj_attr = _get_resource_attr_json(attr, attr_value);
+
+ *json_string = strdup(json_object_to_json_string(jobj_attr));
+
+ _put_resource_attr_json(jobj_attr);
+
+ return 0;
+}
+
+static json_object *
+get_resource_driver_json(const struct syscommon_resman_resource_driver *driver)
+{
+ json_object *jobj_drv, *jobj_drv_name, *jobj_drv_type;
+ json_object *jobj_drv_attrs_array, *jobj_drv_attr, *jobj_drv_ctrls_array, *jobj_drv_ctrl;
+ json_object *jobj_drv_attr_name, *jobj_drv_attr_type, *jobj_drv_attr_id;
+ json_object *jobj_drv_ctrl_name, *jobj_drv_ctrl_id;
+ const struct syscommon_resman_resource_attribute *attr;
+ const struct syscommon_resman_resource_control *ctrl;
+ int i;
+
+ jobj_drv = json_object_new_object();
+
+ jobj_drv_name = json_object_new_string(driver->name);
+ jobj_drv_type = json_object_new_int(driver->type);
+
+ jobj_drv_attrs_array = json_object_new_array();
+
+ for (i = 0; i < driver->num_attrs; i++) {
+ attr = &driver->attrs[i];
+
+ jobj_drv_attr = json_object_new_object();
+
+ jobj_drv_attr_name = json_object_new_string(attr->name);
+ jobj_drv_attr_type = json_object_new_int(attr->type);
+ jobj_drv_attr_id = json_object_new_uint64(attr->id);
+
+ json_object_object_add(jobj_drv_attr, "name", jobj_drv_attr_name);
+ json_object_object_add(jobj_drv_attr, "type", jobj_drv_attr_type);
+ json_object_object_add(jobj_drv_attr, "id", jobj_drv_attr_id);
+
+ json_object_array_add(jobj_drv_attrs_array, jobj_drv_attr);
+ }
+
+ jobj_drv_ctrls_array = json_object_new_array();
+
+ for (i = 0; i < driver->num_ctrls; i++) {
+ ctrl = &driver->ctrls[i];
+
+ jobj_drv_ctrl = json_object_new_object();
+
+ jobj_drv_ctrl_name = json_object_new_string(ctrl->name);
+ jobj_drv_ctrl_id = json_object_new_uint64(ctrl->id);
+
+ json_object_object_add(jobj_drv_ctrl, "name", jobj_drv_ctrl_name);
+ json_object_object_add(jobj_drv_ctrl, "id", jobj_drv_ctrl_id);
+
+ json_object_array_add(jobj_drv_ctrls_array, jobj_drv_ctrl);
+ }
+
+ json_object_object_add(jobj_drv, "name", jobj_drv_name);
+ json_object_object_add(jobj_drv, "type", jobj_drv_type);
+ json_object_object_add(jobj_drv, "attrs", jobj_drv_attrs_array);
+ json_object_object_add(jobj_drv, "ctrls", jobj_drv_ctrls_array);
+
+ return jobj_drv;
+}
+
+static void put_resource_driver_json(json_object *jobj_drv)
+{
+ json_object *jobj_array, *jobj_obj;
+ int i;
+
+ if (json_object_object_get_ex(jobj_drv, "ctrls", &jobj_array)) {
+ for (i = 0; i < json_object_array_length(jobj_array); i++) {
+ jobj_obj = json_object_array_get_idx(jobj_array, i);
+
+ json_object_object_del(jobj_obj, "id");
+ json_object_object_del(jobj_obj, "name");
+ }
+ json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
+ }
+
+ if (json_object_object_get_ex(jobj_drv, "attrs", &jobj_array)) {
+ for (i = 0; i < json_object_array_length(jobj_array); i++) {
+ jobj_obj = json_object_array_get_idx(jobj_array, i);
+
+ json_object_object_del(jobj_obj, "id");
+ json_object_object_del(jobj_obj, "type");
+ json_object_object_del(jobj_obj, "name");
+ }
+ json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
+ }
+
+ json_object_object_del(jobj_drv, "ctrls");
+ json_object_object_del(jobj_drv, "attrs");
+ json_object_object_del(jobj_drv, "type");
+ json_object_object_del(jobj_drv, "name");
+}
+
+int syscommon_resman_get_resource_list_json(char **json_string)
+{
+ const struct syscommon_resman_resource_driver *driver;
+ json_object *jobj_root, *jobj_drvs_array, *jobj_drv;
+ int i;
+
+ jobj_root = json_object_new_object();
+ jobj_drvs_array = json_object_new_array();
+
+ for (i = 0; i < g_list_length(g_resource_driver_head); i++) {
+ driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data;
+
+ jobj_drv = get_resource_driver_json(driver);
+ json_object_array_add(jobj_drvs_array, jobj_drv);
+ }
+
+ json_object_object_add(jobj_root, "resources", jobj_drvs_array);
+
+ *json_string = strdup(json_object_to_json_string(jobj_root));
+
+ for (i = 0; i < json_object_array_length(jobj_drvs_array); i++) {
+ jobj_drv = json_object_array_get_idx(jobj_drvs_array, i);
+
+ put_resource_driver_json(jobj_drv);
+ }
+ json_object_array_del_idx(jobj_drvs_array, 0, json_object_array_length(jobj_drvs_array));
+
+ json_object_object_del(jobj_root, "resources");
+ json_object_put(jobj_root);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_int(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, int32_t *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = *((int32_t *)attr_value->data);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_int64(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, int64_t *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT64))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = *((int64_t *)attr_value->data);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_uint(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, u_int32_t *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = *((u_int32_t *)attr_value->data);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_uint64(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, u_int64_t *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT64))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = *((u_int64_t *)attr_value->data);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_double(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, double *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = *((double *)attr_value->data);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_string(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, char *data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_STRING))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ strncpy(data, (char *)attr_value->data, SYSCOMMON_RESMAN_BUFF_MAX);
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_array(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id,
+ struct syscommon_resman_array_value **data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_ARRAY))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = (struct syscommon_resman_array_value *)attr_value->data;
+
+ return 0;
+}
+
+int
+syscommon_resman_get_resource_attr_ptr(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id, void **data)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value = NULL;
+
+ if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_PTR))
+ return -EINVAL;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource, attr_id);
+ if (!attr_value)
+ return -EINVAL;
+
+ *data = attr_value->data;
+
+ return 0;
+}
+
+static inline bool
+is_resource_attr_visible(struct syscommon_resman_resource *resource,
+ const struct syscommon_resman_resource_attribute *attr)
+{
+ u_int64_t res_visibility, attr_visibility;
+
+ res_visibility = resource->flag & RESOURCE_FLAG_VISIBILITY_MASK;
+ attr_visibility = attr->flag & RESOURCE_ATTR_FLAG_VISIBILITY_MASK;
+
+ /* bigger visibility means smaller privilege */
+ if (res_visibility > attr_visibility)
+ return false;
+
+ return true;
+}
+
+int
+syscommon_resman_set_resource_attr_interest(struct syscommon_resman_resource *resource,
+ u_int64_t interest_mask)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value;
+ int i, ret;
+ bool supported;
+
+ if (!resource)
+ return -EINVAL;
+
+ for (i = 0; i < resource->num_attrs; i++) {
+ if (!(resource->attrs[i].id & interest_mask))
+ continue;
+
+ ret = syscommon_resman_is_resource_attr_supported(resource,
+ resource->attrs[i].id,
+ &supported);
+ if (ret < 0) {
+ goto err;
+ } else if (!supported) {
+ ret = -ENOTSUP;
+ goto err;
+ }
+
+ if (!is_resource_attr_visible(resource, &resource->attrs[i])) {
+ ret = -EACCES;
+ goto err;
+ }
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource,
+ resource->attrs[i].id);
+ if (!attr_value) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * In resource monitor, each resource has a lot of attributes, but
+ * only updated attributes are selected by clients on demand. So,
+ * instead of allocating memory at the resource creation, allocate
+ * at the set interest.
+ */
+ if (!attr_value->data) {
+ switch (attr_value->type) {
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT:
+ attr_value->data = calloc(1, sizeof(int32_t));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
+ attr_value->data = calloc(1, sizeof(int64_t));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
+ attr_value->data = calloc(1, sizeof(u_int32_t));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
+ attr_value->data = calloc(1, sizeof(u_int64_t));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
+ attr_value->data = calloc(1, sizeof(double));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
+ attr_value->data = calloc(SYSCOMMON_RESMAN_BUFF_MAX, sizeof(char));
+ break;
+ case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
+ attr_value->data = calloc(1, sizeof(struct syscommon_resman_array_value));
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!attr_value->data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+ }
+
+ resource->attr_interest |= interest_mask;
+
+ return 0;
+
+err:
+ for (; i >= 0; i--) {
+ if (!(resource->attrs[i].id & interest_mask))
+ continue;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource,
+ resource->attrs[i].id);
+ if (!attr_value)
+ continue;
+
+ if (attr_value->data) {
+ free(attr_value->data);
+ attr_value->data = NULL;
+ }
+ }
+
+ return ret;
+}
+
+int
+syscommon_resman_unset_resource_attr_interest(struct syscommon_resman_resource *resource,
+ u_int64_t interest_mask)
+{
+ struct syscommon_resman_resource_attribute_value *attr_value;
+ int i;
+
+ if (!resource)
+ return -EINVAL;
+
+ if (!syscommon_resman_is_resource_attr_interested(resource, interest_mask))
+ return -EINVAL;
+
+ for (i = 0; i < resource->num_attrs; i++) {
+ if (!(resource->attrs[i].id & interest_mask))
+ continue;
+
+ attr_value = syscommon_resman_get_resource_attr_value(resource,
+ resource->attrs[i].id);
+ if (!attr_value)
+ return -EINVAL;
+
+ if (attr_value->data) {
+ switch (attr_value->type) {
+ case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
+ {
+ struct syscommon_resman_array_value *array = attr_value->data;
+
+ if (array->data) {
+ free(array->data);
+ array->data = NULL;
+ }
+ /* fall through */
+ }
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT:
+ case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
+ case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
+ case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
+ case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
+ free(attr_value->data);
+ attr_value->data = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ }
+
+ resource->attr_interest &= ~interest_mask;
+
+ return 0;
+}
+
+bool
+syscommon_resman_is_resource_attr_interested(struct syscommon_resman_resource *resource,
+ u_int64_t interest_mask)
+{
+ if (!resource)
+ return false;
+
+ if (resource->attr_interest != (resource->attr_interest | interest_mask))
+ return false;
+
+ return true;
+}
+
+const char *
+syscommon_resman_get_resource_attr_name(struct syscommon_resman_resource *resource,
+ u_int64_t attr_id)
+{
+ const struct syscommon_resman_resource_attribute *attr;
+
+ attr = syscommon_resman_get_resource_attr(resource, attr_id);
+ if (!attr)
+ return NULL;
+
+ return attr->name;
+}
+
+const char *syscommon_resman_get_resource_name(struct syscommon_resman_resource *resource)
+{
+ return resource ? resource->name : NULL;
+}
+
+void *syscommon_resman_get_resource_privdata(struct syscommon_resman_resource *resource)
+{
+ return resource ? resource->priv : NULL;
+}
+
+int syscommon_resman_get_resource_type(struct syscommon_resman_resource *resource)
+{
+ return resource ? resource->type : -EINVAL;
+}
+
+int
+syscommon_resman_set_resource_privdata(struct syscommon_resman_resource *resource,
+ void *priv)
+{
+ if (!resource)
+ return -EINVAL;
+
+ resource->priv = priv;
+
+ return 0;
+}
+
+void syscommon_resman_init_resource_drivers(void)
+{
+ struct syscommon_resman_resource_driver *driver;
+ int i, ret = 0;
+
+ for (i = 0; i < g_list_length(g_resource_driver_head); i++) {
+ driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data;
+
+ if (driver->ops.init) {
+ ret = driver->ops.init();
+ if (ret < 0)
+ syscommon_resman_remove_resource_driver(driver);
+ }
+ }
+}
+
+void syscommon_resman_exit_resource_drivers(void)
+{
+ const struct syscommon_resman_resource_driver *driver;
+ int i;
+
+ for (i = 0; i < g_list_length(g_resource_driver_head); i++) {
+ driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data;
+
+ if (driver->ops.exit)
+ driver->ops.exit();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RESOURCE_MANAGER_H__
+#define __RESOURCE_MANAGER_H__
+
+// common.h
+
+#include <stdbool.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <glib.h>
+
+#define SYSCOMMON_RESMAN_BUFF_MAX 255
+
+struct syscommon_resman_resource;
+struct syscommon_resman_resource_attribute;
+struct syscommon_resman_resource_control;
+
+struct syscommon_resman_array_value {
+ int type;
+ int length;
+ void *data;
+};
+
+struct syscommon_resman_resource_attribute_value {
+ int type;
+ void *data;
+};
+
+struct syscommon_resman_resource_attribute_ops {
+ int (*set)(struct syscommon_resman_resource *res,
+ const struct syscommon_resman_resource_attribute *attr,
+ const void *data, int count);
+ int (*get)(struct syscommon_resman_resource *res,
+ const struct syscommon_resman_resource_attribute *attr,
+ void *data);
+ /*
+ * If .is_supported ops is not implemented, use .get ops in order to
+ * check whether the resource attribute is supported or not.
+ */
+ bool (*is_supported)(struct syscommon_resman_resource *res,
+ const struct syscommon_resman_resource_attribute *attr);
+};
+
+struct syscommon_resman_resource_attribute {
+ const char name[SYSCOMMON_RESMAN_BUFF_MAX];
+ const u_int64_t id;
+ const int type;
+ const u_int64_t flag;
+ const struct syscommon_resman_resource_attribute_ops ops;
+};
+
+struct syscommon_resman_resource_control_ops {
+ const int (*set)(struct syscommon_resman_resource *res,
+ const struct syscommon_resman_resource_control *ctrl,
+ const void *data);
+ const int (*get)(struct syscommon_resman_resource *res,
+ const struct syscommon_resman_resource_control *ctrl,
+ void **data);
+};
+
+struct syscommon_resman_resource_control {
+ const char name[SYSCOMMON_RESMAN_BUFF_MAX];
+ const u_int64_t id;
+ const struct syscommon_resman_resource_control_ops ops;
+};
+
+struct syscommon_resman_resource_driver_ops {
+ int (*init)(void);
+ void (*exit)(void);
+ int (*create)(struct syscommon_resman_resource *res);
+ void (*delete)(struct syscommon_resman_resource *res);
+ /*
+ * If prepare_update is specified, it will be called
+ * at every update_resource_attrs().
+ */
+ int (*prepare_update)(struct syscommon_resman_resource *res);
+};
+
+struct syscommon_resman_resource_driver {
+ const char *name;
+ const int type;
+ const u_int64_t flag;
+ const int num_attrs;
+ const struct syscommon_resman_resource_attribute *attrs;
+ const int num_ctrls;
+ const struct syscommon_resman_resource_control *ctrls;
+ const struct syscommon_resman_resource_driver_ops ops;
+};
+
+struct syscommon_resman_resource {
+ char *name;
+ const struct syscommon_resman_resource_driver *driver;
+ int type;
+
+ int num_attrs;
+ const struct syscommon_resman_resource_attribute *attrs;
+ struct syscommon_resman_resource_attribute_value *attrs_value;
+ int num_ctrls;
+ const struct syscommon_resman_resource_control *ctrls;
+
+ u_int64_t flag;
+
+ void *priv;
+
+ u_int64_t attr_interest;
+ u_int64_t attr_supported;
+};
+
+#define SYSCOMMON_RESMAN_RESOURCE_DRIVER_REGISTER(resource_driver) \
+static void __attribute__((constructor)) __syscommon_resman_module_init(void) \
+{ \
+ syscommon_resman_add_resource_driver(resource_driver); \
+} \
+static void __attribute__((destructor)) __syscommon_resman_module_exit(void) \
+{ \
+ syscommon_resman_remove_resource_driver(resource_driver); \
+}
+
+/* Add/remove resource driver and device */
+const struct syscommon_resman_resource_driver *
+syscommon_resman_find_resource_driver(int resource_type);
+void syscommon_resman_add_resource_driver(const struct syscommon_resman_resource_driver *resource_driver);
+void syscommon_resman_remove_resource_driver(const struct syscommon_resman_resource_driver *resource_driver);
+
+/* Create/delete resource instance */
+int syscommon_resman_create_resource(struct syscommon_resman_resource **res, int resource_type);
+void syscommon_resman_delete_resource(struct syscommon_resman_resource *resource);
+
+/* Set flag of the resource to given flag mask */
+int syscommon_resman_set_resource_flag(struct syscommon_resman_resource *resource, u_int64_t flag_mask);
+
+/* Handle resource control */
+int syscommon_resman_set_resource_control(struct syscommon_resman_resource *resource, u_int64_t ctrl_id, const void *data);
+const char *syscommon_resman_get_resource_control_name(struct syscommon_resman_resource *resource, u_int64_t ctrl_id);
+
+/* Handle resource attribute */
+int syscommon_resman_update_resource_attrs(struct syscommon_resman_resource *resource);
+const struct syscommon_resman_resource_attribute *
+syscommon_resman_get_resource_attr(struct syscommon_resman_resource *resource, u_int64_t attr_id);
+struct syscommon_resman_resource_attribute_value *
+syscommon_resman_get_resource_attr_value(struct syscommon_resman_resource *resource, u_int64_t attr_id);
+int syscommon_resman_is_resource_attr_supported(struct syscommon_resman_resource *resource, u_int64_t attr_id, bool *supported);
+
+static inline bool
+syscommon_resman_resource_attr_supported_always(struct syscommon_resman_resource *resource,
+ const struct syscommon_resman_resource_attribute *attr)
+{
+ return true;
+}
+
+int syscommon_resman_get_resource_attrs_json(struct syscommon_resman_resource *resource, char **json_string);
+int syscommon_resman_get_resource_attr_json(struct syscommon_resman_resource *resource, u_int64_t attr_id, char **json_string);
+int syscommon_resman_get_resource_list_json(char **json_string);
+
+int syscommon_resman_get_resource_attr_int(struct syscommon_resman_resource *resource, u_int64_t attr_id, int32_t *data);
+int syscommon_resman_get_resource_attr_int64(struct syscommon_resman_resource *resource, u_int64_t attr_id, int64_t *data);
+int syscommon_resman_get_resource_attr_uint(struct syscommon_resman_resource *resource, u_int64_t attr_id, u_int32_t *data);
+int syscommon_resman_get_resource_attr_uint64(struct syscommon_resman_resource *resource, u_int64_t attr_id, u_int64_t *data);
+int syscommon_resman_get_resource_attr_double(struct syscommon_resman_resource *resource, u_int64_t attr_id, double *data);
+int syscommon_resman_get_resource_attr_string(struct syscommon_resman_resource *resource, u_int64_t attr_id, char *data);
+int syscommon_resman_get_resource_attr_array(struct syscommon_resman_resource *resource, u_int64_t attr_id,
+ struct syscommon_resman_array_value **data);
+int syscommon_resman_get_resource_attr_ptr(struct syscommon_resman_resource *resource, u_int64_t attr_id, void **data);
+
+int syscommon_resman_set_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
+int syscommon_resman_unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
+bool syscommon_resman_is_resource_attr_interested(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
+const char *syscommon_resman_get_resource_attr_name(struct syscommon_resman_resource *resource, u_int64_t attr_id);
+
+const char *syscommon_resman_get_resource_name(struct syscommon_resman_resource *resource);
+void *syscommon_resman_get_resource_privdata(struct syscommon_resman_resource *resource);
+int syscommon_resman_get_resource_type(struct syscommon_resman_resource *resource);
+
+int syscommon_resman_set_resource_privdata(struct syscommon_resman_resource *resource, void *priv);
+
+void syscommon_resman_init_resource_drivers(void);
+void syscommon_resman_exit_resource_drivers(void);
+#endif