7167ca27cebb55ec471ac44adcfbc0fd2795cbd1
[platform/core/system/libsyscommon.git] / src / resource-manager / resource-manager.c
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <glib.h>
18 #include <stdio.h>
19 #include <json.h>
20 #include <sys/time.h>
21 #include <pthread.h>
22
23 #include "resource-manager.h"
24 #include "resource-type.h"
25
26 #define BIT64_INDEX(id)                         (63 - __builtin_clzll(id))
27 #define RESOURCE_ATTR_INDEX(id)                 BIT64_INDEX(id)
28 #define RESOURCE_CTRL_INDEX(id)                 BIT64_INDEX(id)
29 #define RESOURCE_FLAG_VISIBILITY_MASK           (SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE \
30                                                 | SYSCOMMON_RESMAN_RESOURCE_FLAG_PUBLIC)
31 #define RESOURCE_ATTR_FLAG_VISIBILITY_MASK      (SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PRIVATE \
32                                                 | SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC)
33
34 struct syscommon_resman_resource {
35         char *name;
36         int id;
37         const struct syscommon_resman_resource_driver *driver;
38         int type;
39
40         int num_attrs;
41         const struct syscommon_resman_resource_attribute *attrs;
42         struct syscommon_resman_resource_attribute_value *attrs_value;
43         int num_ctrls;
44         const struct syscommon_resman_resource_control *ctrls;
45
46         u_int64_t flag;
47
48         void *priv;
49
50         u_int64_t attr_interest;
51         u_int64_t attr_supported;
52 };
53
54 static int unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
55 static bool is_resource_attr_interested(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
56
57 static GList *g_resource_driver_head;
58 static GHashTable *g_resource_hash_table;
59
60 static int clear_sign_bit(unsigned int val)
61 {
62         return (int)((val << 1) >> 1);
63 }
64
65 static int init_resource_id(void)
66 {
67         int val;
68         struct timeval tv;
69
70         gettimeofday(&tv, NULL);
71         val = tv.tv_sec * 1000 + tv.tv_usec / 1000;
72         return clear_sign_bit(val);
73 }
74
75 static int alloc_resource_id(void)
76 {
77         static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
78         static int resource_id = -1;
79         int ret;
80
81         pthread_mutex_lock(&lock);
82
83         if (resource_id < 0)
84                 resource_id = init_resource_id();
85
86         ret = resource_id;
87         resource_id = clear_sign_bit(resource_id + 1);
88
89         pthread_mutex_unlock(&lock);
90
91         return ret;
92 }
93
94 static void free_resource(struct syscommon_resman_resource *resource)
95 {
96         free(resource->name);
97         resource->name = NULL;
98
99         unset_resource_attr_interest(resource, resource->attr_interest);
100         free(resource->attrs_value);
101         resource->attrs_value = NULL;
102
103         resource->attrs = NULL;
104         resource->num_attrs = 0;
105
106         free(resource);
107 }
108
109 static void delete_resource(void *data)
110 {
111         struct syscommon_resman_resource *resource = (struct syscommon_resman_resource *) data;
112
113         if (!resource)
114                 return;
115
116         if (resource->driver && resource->driver->ops.delete)
117                 resource->driver->ops.delete(resource->id);
118
119         free_resource(resource);
120 }
121
122 static int add_resource(struct syscommon_resman_resource *resource)
123 {
124         if (!resource)
125                 return -EINVAL;
126
127         if (!g_resource_hash_table) {
128                 g_resource_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, delete_resource);
129                 if (!g_resource_hash_table)
130                         return -ENOMEM;
131         }
132
133         g_hash_table_insert(g_resource_hash_table, GINT_TO_POINTER(resource->id), resource);
134
135         return 0;
136 }
137
138 static struct syscommon_resman_resource * find_resource(int id)
139 {
140         if (!g_resource_hash_table)
141                 return NULL;
142
143         return g_hash_table_lookup(g_resource_hash_table, GINT_TO_POINTER(id));
144 }
145
146 static gint __compare_resource_type(gconstpointer data, gconstpointer input)
147 {
148         struct syscommon_resman_resource_driver *driver;
149         int type = *(int *)input;
150
151         driver = (struct syscommon_resman_resource_driver *)data;
152
153         if (driver && driver->type == type)
154                 return 0;
155         return -1;
156 }
157
158 const struct syscommon_resman_resource_driver *
159 syscommon_resman_find_resource_driver(int resource_type)
160 {
161         GList *node;
162
163         node = g_list_find_custom(g_resource_driver_head,
164                         &resource_type, __compare_resource_type);
165
166         if (!node)
167                 return NULL;
168         return (struct syscommon_resman_resource_driver *)node->data;
169 }
170
171 void
172 syscommon_resman_add_resource_driver(const struct syscommon_resman_resource_driver *driver)
173 {
174         if (!driver)
175                 return;
176
177         g_resource_driver_head =
178                         g_list_append(g_resource_driver_head, (gpointer)driver);
179 }
180
181 void
182 syscommon_resman_remove_resource_driver(const struct syscommon_resman_resource_driver *driver)
183 {
184         if (!driver)
185                 return;
186
187         g_resource_driver_head =
188                         g_list_remove(g_resource_driver_head, (gpointer)driver);
189 }
190
191 void syscommon_resman_delete_resource(int resource_id)
192 {
193         if (!g_resource_hash_table)
194                 return;
195
196         g_hash_table_remove(g_resource_hash_table, GINT_TO_POINTER(resource_id));
197 }
198
199 int
200 syscommon_resman_create_resource(int *resource_id, int resource_type)
201 {
202         const struct syscommon_resman_resource_driver *driver = NULL;
203         struct syscommon_resman_resource *resource = NULL;
204         int i, ret;
205
206         if (!resource_id)
207                 return -EINVAL;
208
209         driver = syscommon_resman_find_resource_driver(resource_type);
210         if (!driver)
211                 return -EINVAL;
212
213         resource = calloc(1, sizeof(*resource));
214         if (!resource)
215                 return -ENOMEM;
216
217         resource->id = alloc_resource_id();
218         resource->type = resource_type;
219         resource->name = g_strdup(driver->name);
220         resource->driver = driver;
221         resource->num_attrs = driver->num_attrs;
222         resource->attrs = driver->attrs;
223         resource->attrs_value = calloc(resource->num_attrs,
224                                         sizeof(*resource->attrs_value));
225         if (!resource->attrs_value) {
226                 free_resource(resource);
227                 return -ENOMEM;
228         }
229
230         ret = add_resource(resource);
231         if (ret < 0) {
232                 free_resource(resource);
233                 return ret;
234         }
235
236         for (i = 0; i < resource->num_attrs; i++)
237                 resource->attrs_value[i].type = driver->attrs[i].type;
238
239         resource->ctrls = driver->ctrls;
240         resource->num_ctrls = driver->num_ctrls;
241         resource->flag = SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE;
242
243         if (driver->ops.create) {
244                 ret = driver->ops.create(resource->id);
245                 if (ret < 0) {
246                         free_resource(resource);
247                         return ret;
248                 }
249         }
250
251         *resource_id = resource->id;
252
253         return 0;
254 }
255
256 int
257 syscommon_resman_set_resource_flag(int resource_id, u_int64_t flag_mask)
258 {
259         struct syscommon_resman_resource *resource = find_resource(resource_id);
260
261         if (!resource)
262                 return -EINVAL;
263
264         resource->flag = flag_mask;
265         return 0;
266 }
267
268 int
269 syscommon_resman_set_resource_control(int resource_id, u_int64_t ctrl_id, const void *data)
270 {
271         const struct syscommon_resman_resource_control *ctrl;
272         int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
273         int ret;
274         struct syscommon_resman_resource *resource = find_resource(resource_id);
275
276         if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
277                 return -EINVAL;
278
279         ctrl = &resource->ctrls[ctrl_index];
280         if (!ctrl->ops.set)
281                 return -ENOTSUP;
282
283         ret = ctrl->ops.set(resource_id, ctrl, data);
284         if (ret < 0)
285                 return ret;
286
287         return 0;
288 }
289
290 const char *
291 syscommon_resman_get_resource_control_name(int resource_id, u_int64_t ctrl_id)
292 {
293         const struct syscommon_resman_resource_control *ctrl;
294         int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
295         struct syscommon_resman_resource *resource = find_resource(resource_id);
296
297         if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
298                 return NULL;
299
300         ctrl = &resource->ctrls[ctrl_index];
301
302         return ctrl->name;
303 }
304
305 static int
306 update_resource_attr(struct syscommon_resman_resource *resource,
307                      u_int64_t attr_id)
308 {
309         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
310         const struct syscommon_resman_resource_attribute *attr = NULL;
311         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
312         int ret;
313
314         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
315                 return -EINVAL;
316
317         attr = &resource->attrs[attr_index];
318
319         if (!attr->ops.get)
320                 return -EINVAL;
321
322         attr_value = &resource->attrs_value[attr_index];
323
324         ret = attr->ops.get(resource->id, attr, attr_value->data);
325         if (ret < 0)
326                 return ret;
327
328         return 0;
329 }
330
331 int
332 syscommon_resman_update_resource_attrs(int resource_id)
333 {
334         int i, ret;
335         struct syscommon_resman_resource *resource = find_resource(resource_id);
336
337         if (!resource || !resource->type)
338                 return -EINVAL;
339
340         if (resource->driver && resource->driver->ops.prepare_update) {
341                 ret = resource->driver->ops.prepare_update(resource->id);
342                 if (ret < 0)
343                         return ret;
344         }
345
346         for (i = 0; i < resource->num_attrs; i++) {
347                 if (!(resource->attrs[i].id & resource->attr_interest))
348                         continue;
349                 update_resource_attr(resource, resource->attrs[i].id);
350         }
351
352         return 0;
353 }
354
355 static const struct syscommon_resman_resource_attribute *
356 get_resource_attr(struct syscommon_resman_resource *resource, u_int64_t attr_id)
357 {
358         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
359
360         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
361                 return NULL;
362
363         return &resource->attrs[attr_index];
364 }
365
366 const struct syscommon_resman_resource_attribute *
367 syscommon_resman_get_resource_attr(int resource_id, u_int64_t attr_id)
368 {
369         struct syscommon_resman_resource *resource = find_resource(resource_id);
370
371         return get_resource_attr(resource, attr_id);
372 }
373
374
375 static struct syscommon_resman_resource_attribute_value *
376 get_resource_attr_value(struct syscommon_resman_resource *resource, u_int64_t attr_id)
377 {
378         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
379
380         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
381                 return NULL;
382
383         return &resource->attrs_value[attr_index];
384 }
385
386 struct syscommon_resman_resource_attribute_value *
387 syscommon_resman_get_resource_attr_value(int resource_id, u_int64_t attr_id)
388 {
389         struct syscommon_resman_resource *resource = find_resource(resource_id);
390
391         return get_resource_attr_value(resource, attr_id);
392 }
393
394 static int is_resource_attr_supported(struct syscommon_resman_resource *resource, u_int64_t attr_id, bool *supported)
395 {
396         const struct syscommon_resman_resource_attribute *attr = NULL;
397         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
398         int ret;
399         bool is_supported = false;
400
401         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs) {
402                 *supported = false;
403                 return -EINVAL;
404         }
405
406         attr = &resource->attrs[attr_index];
407
408         if (attr->id & resource->attr_supported) {
409                 is_supported = true;
410         } else if (attr->ops.is_supported) {
411                 is_supported = attr->ops.is_supported(resource->id, attr);
412         } else if (attr->ops.get) {
413                 /*
414                  * Optionally, if .is_supported ops is not implemented,
415                  * use .get ops in order to check whether the resource attribute
416                  * is supported or not.
417                  */
418                 char data[SYSCOMMON_RESMAN_BUFF_MAX] = {0, };
419
420                 ret = attr->ops.get(resource->id, attr, (void *)data);
421                 is_supported = (ret < 0) ? false :  true;
422         }
423
424         if (is_supported)
425                 resource->attr_supported |= attr->id;
426
427         *supported = is_supported;
428
429         return 0;
430 }
431
432 int
433 syscommon_resman_is_resource_attr_supported(int resource_id, u_int64_t attr_id, bool *supported)
434 {
435         struct syscommon_resman_resource *resource = find_resource(resource_id);
436
437         return is_resource_attr_supported(resource, attr_id, supported);
438 }
439
440 static bool
441 check_attr_validate(struct syscommon_resman_resource *resource,
442                     u_int64_t attr_id, int type)
443 {
444         const struct syscommon_resman_resource_attribute *attr;
445
446         attr = get_resource_attr(resource, attr_id);
447         if (!attr)
448                 return false;
449
450         if (attr->type != type)
451                 return false;
452
453         if (!(attr->id & resource->attr_interest))
454                 return false;
455
456         return true;
457 }
458
459 static json_object *
460 _get_resource_attr_json(const struct syscommon_resman_resource_attribute *attr,
461                         const struct syscommon_resman_resource_attribute_value *attr_value)
462 {
463         json_object *jobj_attr, *jobj_attr_name, *jobj_attr_type, *jobj_attr_value, *jobj_temp;
464         struct syscommon_resman_array_value *array;
465         int i;
466
467         switch (attr->type) {
468         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
469                 jobj_attr_value = json_object_new_int(*((int32_t *)attr_value->data));
470                 break;
471         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
472                 jobj_attr_value = json_object_new_int(*((u_int32_t *)attr_value->data));
473                 break;
474         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
475                 jobj_attr_value = json_object_new_int64(*((int64_t *)attr_value->data));
476                 break;
477         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
478                 jobj_attr_value = json_object_new_uint64(*((u_int64_t *)attr_value->data));
479                 break;
480         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
481                 jobj_attr_value = json_object_new_double(*((double *)attr_value->data));
482                 break;
483         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
484                 jobj_attr_value = json_object_new_string((char *)attr_value->data);
485                 break;
486         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
487                 array = attr_value->data;
488
489                 jobj_attr_value = json_object_new_array();
490
491                 switch (array->type) {
492                 case SYSCOMMON_RESMAN_DATA_TYPE_INT:
493                         for (i = 0; i < array->length; i++) {
494                                 int32_t *item = array->data;
495
496                                 jobj_temp = json_object_new_int(item[i]);
497                                 json_object_array_add(jobj_attr_value, jobj_temp);
498                         }
499                         break;
500                 case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
501                         for (i = 0; i < array->length; i++) {
502                                 u_int32_t *item = array->data;
503
504                                 jobj_temp = json_object_new_int(item[i]);
505                                 json_object_array_add(jobj_attr_value, jobj_temp);
506                         }
507                         break;
508                 case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
509                         for (i = 0; i < array->length; i++) {
510                                 int64_t *item = array->data;
511
512                                 jobj_temp = json_object_new_int64(item[i]);
513                                 json_object_array_add(jobj_attr_value, jobj_temp);
514                         }
515                         break;
516                 case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
517                         for (i = 0; i < array->length; i++) {
518                                 u_int64_t *item = array->data;
519
520                                 jobj_temp = json_object_new_uint64(item[i]);
521                                 json_object_array_add(jobj_attr_value, jobj_temp);
522                         }
523                         break;
524                 case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
525                         for (i = 0; i < array->length; i++) {
526                                 double *item = array->data;
527
528                                 jobj_temp = json_object_new_double(item[i]);
529                                 json_object_array_add(jobj_attr_value, jobj_temp);
530                         }
531                         break;
532                 case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
533                         for (i = 0; i < array->length; i++) {
534                                 char **item = array->data;
535
536                                 jobj_temp = json_object_new_string(item[i]);
537                                 json_object_array_add(jobj_attr_value, jobj_temp);
538                         }
539                         break;
540                 default:
541                         json_object_put(jobj_attr_value);
542                         jobj_attr_value = json_object_new_null();
543                 }
544                 break;
545         default:
546                 jobj_attr_value = json_object_new_null();
547         }
548         jobj_attr = json_object_new_object();
549
550         jobj_attr_name = json_object_new_string(attr->name);
551         /*
552          * Since actually JSON format has no data type limitation itself, in many
553          * cases except converting JSON into json-c, type is not required. So,
554          * for the case of converting JSON generated here to json-c object again
555          * json_type is stored in each attributes.
556          */
557         jobj_attr_type = json_object_new_int(json_object_get_type(jobj_attr_value));
558
559         json_object_object_add(jobj_attr, "name", jobj_attr_name);
560         json_object_object_add(jobj_attr, "json_type", jobj_attr_type);
561         json_object_object_add(jobj_attr, "value", jobj_attr_value);
562
563         return jobj_attr;
564 }
565
566 static void _put_resource_attr_json(json_object *jobj_attr)
567 {
568         json_object *jobj_attr_value;
569
570         json_object_object_del(jobj_attr, "name");
571         json_object_object_del(jobj_attr, "json_type");
572
573         if (json_object_object_get_ex(jobj_attr, "value", &jobj_attr_value) &&
574                         json_object_is_type(jobj_attr_value, json_type_array))
575                 json_object_array_del_idx(jobj_attr_value, 0,
576                                           json_object_array_length(jobj_attr_value));
577
578         json_object_object_del(jobj_attr, "value");
579 }
580
581 int
582 syscommon_resman_get_resource_attrs_json(int resource_id, char **json_string)
583 {
584         json_object *jobj_root, *jobj_res_name, *jobj_res_type, *jobj_res_attrs, *jobj_attr;
585         const struct syscommon_resman_resource_attribute *attr;
586         const struct syscommon_resman_resource_attribute_value *attr_value;
587         struct syscommon_resman_resource *resource = find_resource(resource_id);
588         int i;
589
590         if (!resource || !resource->type)
591                 return -EINVAL;
592
593         jobj_root = json_object_new_object();
594
595         jobj_res_name = json_object_new_string(resource->name);
596         jobj_res_type = json_object_new_int(resource->type);
597         jobj_res_attrs = json_object_new_array();
598
599         for (i = 0; i < resource->num_attrs; i++) {
600                 if (!(resource->attrs[i].id & resource->attr_interest))
601                         continue;
602
603                 attr = &resource->attrs[i];
604                 attr_value = &resource->attrs_value[i];
605
606                 jobj_attr = _get_resource_attr_json(attr, attr_value);
607
608                 json_object_array_add(jobj_res_attrs, jobj_attr);
609         }
610
611         json_object_object_add(jobj_root, "res_name", jobj_res_name);
612         json_object_object_add(jobj_root, "res_type", jobj_res_type);
613         json_object_object_add(jobj_root, "res_attrs", jobj_res_attrs);
614
615         *json_string = strdup(json_object_to_json_string(jobj_root));
616
617         for (i = 0; i < json_object_array_length(jobj_res_attrs); i++) {
618                 jobj_attr = json_object_array_get_idx(jobj_res_attrs, i);
619                 _put_resource_attr_json(jobj_attr);
620         }
621         json_object_array_del_idx(jobj_res_attrs, 0, json_object_array_length(jobj_res_attrs));
622
623         json_object_object_del(jobj_root, "res_attrs");
624         json_object_object_del(jobj_root, "res_type");
625         json_object_object_del(jobj_root, "res_name");
626         json_object_put(jobj_root);
627
628         return 0;
629 }
630
631 int
632 syscommon_resman_get_resource_attr_json(int resource_id, u_int64_t attr_id, char **json_string)
633 {
634         const struct syscommon_resman_resource_attribute *attr;
635         const struct syscommon_resman_resource_attribute_value *attr_value;
636         json_object *jobj_attr;
637         struct syscommon_resman_resource *resource = find_resource(resource_id);
638
639         attr = get_resource_attr(resource, attr_id);
640         attr_value = get_resource_attr_value(resource, attr_id);
641
642         if (!attr || !attr_value)
643                 return -EINVAL;
644
645         jobj_attr = _get_resource_attr_json(attr, attr_value);
646
647         *json_string = strdup(json_object_to_json_string(jobj_attr));
648
649         _put_resource_attr_json(jobj_attr);
650
651         return 0;
652 }
653
654 static json_object *
655 get_resource_driver_json(const struct syscommon_resman_resource_driver *driver)
656 {
657         json_object *jobj_drv, *jobj_drv_name, *jobj_drv_type;
658         json_object *jobj_drv_attrs_array, *jobj_drv_attr, *jobj_drv_ctrls_array, *jobj_drv_ctrl;
659         json_object *jobj_drv_attr_name, *jobj_drv_attr_type, *jobj_drv_attr_id;
660         json_object *jobj_drv_ctrl_name, *jobj_drv_ctrl_id;
661         const struct syscommon_resman_resource_attribute *attr;
662         const struct syscommon_resman_resource_control *ctrl;
663         int i;
664
665         jobj_drv = json_object_new_object();
666
667         jobj_drv_name = json_object_new_string(driver->name);
668         jobj_drv_type = json_object_new_int(driver->type);
669
670         jobj_drv_attrs_array = json_object_new_array();
671
672         for (i = 0; i < driver->num_attrs; i++) {
673                 attr = &driver->attrs[i];
674
675                 jobj_drv_attr = json_object_new_object();
676
677                 jobj_drv_attr_name = json_object_new_string(attr->name);
678                 jobj_drv_attr_type = json_object_new_int(attr->type);
679                 jobj_drv_attr_id = json_object_new_uint64(attr->id);
680
681                 json_object_object_add(jobj_drv_attr, "name", jobj_drv_attr_name);
682                 json_object_object_add(jobj_drv_attr, "type", jobj_drv_attr_type);
683                 json_object_object_add(jobj_drv_attr, "id", jobj_drv_attr_id);
684
685                 json_object_array_add(jobj_drv_attrs_array, jobj_drv_attr);
686         }
687
688         jobj_drv_ctrls_array = json_object_new_array();
689
690         for (i = 0; i < driver->num_ctrls; i++) {
691                 ctrl = &driver->ctrls[i];
692
693                 jobj_drv_ctrl = json_object_new_object();
694
695                 jobj_drv_ctrl_name = json_object_new_string(ctrl->name);
696                 jobj_drv_ctrl_id = json_object_new_uint64(ctrl->id);
697
698                 json_object_object_add(jobj_drv_ctrl, "name", jobj_drv_ctrl_name);
699                 json_object_object_add(jobj_drv_ctrl, "id", jobj_drv_ctrl_id);
700
701                 json_object_array_add(jobj_drv_ctrls_array, jobj_drv_ctrl);
702         }
703
704         json_object_object_add(jobj_drv, "name", jobj_drv_name);
705         json_object_object_add(jobj_drv, "type", jobj_drv_type);
706         json_object_object_add(jobj_drv, "attrs", jobj_drv_attrs_array);
707         json_object_object_add(jobj_drv, "ctrls", jobj_drv_ctrls_array);
708
709         return jobj_drv;
710 }
711
712 static void put_resource_driver_json(json_object *jobj_drv)
713 {
714         json_object *jobj_array, *jobj_obj;
715         int i;
716
717         if (json_object_object_get_ex(jobj_drv, "ctrls", &jobj_array)) {
718                 for (i = 0; i < json_object_array_length(jobj_array); i++) {
719                         jobj_obj = json_object_array_get_idx(jobj_array, i);
720
721                         json_object_object_del(jobj_obj, "id");
722                         json_object_object_del(jobj_obj, "name");
723                 }
724                 json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
725         }
726
727         if (json_object_object_get_ex(jobj_drv, "attrs", &jobj_array)) {
728                 for (i = 0; i < json_object_array_length(jobj_array); i++) {
729                         jobj_obj = json_object_array_get_idx(jobj_array, i);
730
731                         json_object_object_del(jobj_obj, "id");
732                         json_object_object_del(jobj_obj, "type");
733                         json_object_object_del(jobj_obj, "name");
734                 }
735                 json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
736         }
737
738         json_object_object_del(jobj_drv, "ctrls");
739         json_object_object_del(jobj_drv, "attrs");
740         json_object_object_del(jobj_drv, "type");
741         json_object_object_del(jobj_drv, "name");
742 }
743
744 int syscommon_resman_get_resource_list_json(char **json_string)
745 {
746         const struct syscommon_resman_resource_driver *driver;
747         json_object *jobj_root, *jobj_drvs_array, *jobj_drv;
748         int i;
749
750         jobj_root = json_object_new_object();
751         jobj_drvs_array = json_object_new_array();
752
753         for (i = 0; i < g_list_length(g_resource_driver_head); i++) {
754                 driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data;
755
756                 jobj_drv = get_resource_driver_json(driver);
757                 json_object_array_add(jobj_drvs_array, jobj_drv);
758         }
759
760         json_object_object_add(jobj_root, "resources", jobj_drvs_array);
761
762         *json_string = strdup(json_object_to_json_string(jobj_root));
763
764         for (i = 0; i < json_object_array_length(jobj_drvs_array); i++) {
765                 jobj_drv = json_object_array_get_idx(jobj_drvs_array, i);
766
767                 put_resource_driver_json(jobj_drv);
768         }
769         json_object_array_del_idx(jobj_drvs_array, 0, json_object_array_length(jobj_drvs_array));
770
771         json_object_object_del(jobj_root, "resources");
772         json_object_put(jobj_root);
773
774         return 0;
775 }
776
777 int
778 syscommon_resman_get_resource_attr_int(int resource_id, u_int64_t attr_id, int32_t *data)
779 {
780         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
781         struct syscommon_resman_resource *resource = find_resource(resource_id);
782
783         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT))
784                 return -EINVAL;
785
786         attr_value = get_resource_attr_value(resource, attr_id);
787         if (!attr_value)
788                 return -EINVAL;
789
790         *data = *((int32_t *)attr_value->data);
791
792         return 0;
793 }
794
795 int
796 syscommon_resman_get_resource_attr_int_sync(int resource_id, u_int64_t attr_id, int32_t *data)
797 {
798         int ret;
799
800         ret = update_resource_attr(find_resource(resource_id), attr_id);
801         if (ret != 0)
802                 return ret;
803
804         return syscommon_resman_get_resource_attr_int(resource_id, attr_id, data);
805 }
806
807 int
808 syscommon_resman_get_resource_attr_int64(int resource_id, u_int64_t attr_id, int64_t *data)
809 {
810         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
811         struct syscommon_resman_resource *resource = find_resource(resource_id);
812
813         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT64))
814                 return -EINVAL;
815
816         attr_value = get_resource_attr_value(resource, attr_id);
817         if (!attr_value)
818                 return -EINVAL;
819
820         *data = *((int64_t *)attr_value->data);
821
822         return 0;
823 }
824
825 int
826 syscommon_resman_get_resource_attr_int64_sync(int resource_id, u_int64_t attr_id, int64_t *data)
827 {
828         int ret;
829
830         ret = update_resource_attr(find_resource(resource_id), attr_id);
831         if (ret != 0)
832                 return ret;
833
834         return syscommon_resman_get_resource_attr_int64(resource_id, attr_id, data);
835 }
836
837 int
838 syscommon_resman_get_resource_attr_uint(int resource_id, u_int64_t attr_id, u_int32_t *data)
839 {
840         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
841         struct syscommon_resman_resource *resource = find_resource(resource_id);
842
843         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT))
844                 return -EINVAL;
845
846         attr_value = get_resource_attr_value(resource, attr_id);
847         if (!attr_value)
848                 return -EINVAL;
849
850         *data = *((u_int32_t *)attr_value->data);
851
852         return 0;
853 }
854
855 int
856 syscommon_resman_get_resource_attr_uint_sync(int resource_id, u_int64_t attr_id, u_int32_t *data)
857 {
858         int ret;
859
860         ret = update_resource_attr(find_resource(resource_id), attr_id);
861         if (ret != 0)
862                 return ret;
863
864         return syscommon_resman_get_resource_attr_uint(resource_id, attr_id, data);
865 }
866
867 int
868 syscommon_resman_get_resource_attr_uint64(int resource_id, u_int64_t attr_id, u_int64_t *data)
869 {
870         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
871         struct syscommon_resman_resource *resource = find_resource(resource_id);
872
873         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT64))
874                 return -EINVAL;
875
876         attr_value = get_resource_attr_value(resource, attr_id);
877         if (!attr_value)
878                 return -EINVAL;
879
880         *data = *((u_int64_t *)attr_value->data);
881
882         return 0;
883 }
884
885 int
886 syscommon_resman_get_resource_attr_uint64_sync(int resource_id, u_int64_t attr_id, u_int64_t *data)
887 {
888         int ret;
889
890         ret = update_resource_attr(find_resource(resource_id), attr_id);
891         if (ret != 0)
892                 return ret;
893
894         return syscommon_resman_get_resource_attr_uint64(resource_id, attr_id, data);
895 }
896
897 int
898 syscommon_resman_get_resource_attr_double(int resource_id, u_int64_t attr_id, double *data)
899 {
900         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
901         struct syscommon_resman_resource *resource = find_resource(resource_id);
902
903         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE))
904                 return -EINVAL;
905
906         attr_value = get_resource_attr_value(resource, attr_id);
907         if (!attr_value)
908                 return -EINVAL;
909
910         *data = *((double *)attr_value->data);
911
912         return 0;
913 }
914
915 int
916 syscommon_resman_get_resource_attr_double_sync(int resource_id, u_int64_t attr_id, double *data)
917 {
918         int ret;
919
920         ret = update_resource_attr(find_resource(resource_id), attr_id);
921         if (ret != 0)
922                 return ret;
923
924         return syscommon_resman_get_resource_attr_double(resource_id, attr_id, data);
925 }
926
927 int
928 syscommon_resman_get_resource_attr_string(int resource_id, u_int64_t attr_id, char *data)
929 {
930         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
931         struct syscommon_resman_resource *resource = find_resource(resource_id);
932
933         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_STRING))
934                 return -EINVAL;
935
936         attr_value = get_resource_attr_value(resource, attr_id);
937         if (!attr_value)
938                 return -EINVAL;
939
940         strncpy(data, (char *)attr_value->data, SYSCOMMON_RESMAN_BUFF_MAX);
941
942         return 0;
943 }
944
945 int
946 syscommon_resman_get_resource_attr_string_sync(int resource_id, u_int64_t attr_id, char *data)
947 {
948         int ret;
949
950         ret = update_resource_attr(find_resource(resource_id), attr_id);
951         if (ret != 0)
952                 return ret;
953
954         return syscommon_resman_get_resource_attr_string(resource_id, attr_id, data);
955 }
956
957 int
958 syscommon_resman_get_resource_attr_array(int resource_id, u_int64_t attr_id, struct syscommon_resman_array_value **data)
959 {
960         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
961         struct syscommon_resman_resource *resource = find_resource(resource_id);
962
963         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_ARRAY))
964                 return -EINVAL;
965
966         attr_value = get_resource_attr_value(resource, attr_id);
967         if (!attr_value)
968                 return -EINVAL;
969
970         *data = (struct syscommon_resman_array_value *)attr_value->data;
971
972         return 0;
973 }
974
975 int
976 syscommon_resman_get_resource_attr_array_sync(int resource_id, u_int64_t attr_id, struct syscommon_resman_array_value **data)
977 {
978         int ret;
979
980         ret = update_resource_attr(find_resource(resource_id), attr_id);
981         if (ret != 0)
982                 return ret;
983
984         return syscommon_resman_get_resource_attr_array(resource_id, attr_id, data);
985 }
986
987 int
988 syscommon_resman_get_resource_attr_ptr(int resource_id, u_int64_t attr_id, void **data)
989 {
990         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
991         struct syscommon_resman_resource *resource = find_resource(resource_id);
992
993         if (!check_attr_validate(resource, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_PTR))
994                 return -EINVAL;
995
996         attr_value = get_resource_attr_value(resource, attr_id);
997         if (!attr_value)
998                 return -EINVAL;
999
1000         *data = attr_value->data;
1001
1002         return 0;
1003 }
1004
1005 int
1006 syscommon_resman_get_resource_attr_ptr_sync(int resource_id, u_int64_t attr_id, void **data)
1007 {
1008         int ret;
1009
1010         ret = update_resource_attr(find_resource(resource_id), attr_id);
1011         if (ret != 0)
1012                 return ret;
1013
1014         return syscommon_resman_get_resource_attr_ptr(resource_id, attr_id, data);
1015 }
1016
1017 static inline bool
1018 is_resource_attr_visible(struct syscommon_resman_resource *resource,
1019                          const struct syscommon_resman_resource_attribute *attr)
1020 {
1021         u_int64_t res_visibility, attr_visibility;
1022
1023         res_visibility = resource->flag & RESOURCE_FLAG_VISIBILITY_MASK;
1024         attr_visibility = attr->flag & RESOURCE_ATTR_FLAG_VISIBILITY_MASK;
1025
1026         /* bigger visibility means smaller privilege */
1027         if (res_visibility > attr_visibility)
1028                 return false;
1029
1030         return true;
1031 }
1032
1033 int
1034 syscommon_resman_set_resource_attr_interest(int resource_id, u_int64_t interest_mask)
1035 {
1036         struct syscommon_resman_resource_attribute_value *attr_value;
1037         int i, ret;
1038         bool supported;
1039         struct syscommon_resman_resource *resource = find_resource(resource_id);
1040
1041         if (!resource)
1042                 return -EINVAL;
1043
1044         for (i = 0; i < resource->num_attrs; i++) {
1045                 if (!(resource->attrs[i].id & interest_mask))
1046                         continue;
1047
1048                 ret = is_resource_attr_supported(resource,
1049                                                                   resource->attrs[i].id,
1050                                                                   &supported);
1051                 if (ret < 0) {
1052                         goto err;
1053                 } else if (!supported) {
1054                         ret = -ENOTSUP;
1055                         goto err;
1056                 }
1057
1058                 if (!is_resource_attr_visible(resource, &resource->attrs[i])) {
1059                         ret = -EACCES;
1060                         goto err;
1061                 }
1062
1063                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
1064                 if (!attr_value) {
1065                         ret = -EINVAL;
1066                         goto err;
1067                 }
1068
1069                 /*
1070                  * In resource monitor, each resource has a lot of attributes, but
1071                  * only updated attributes are selected by clients on demand. So,
1072                  * instead of allocating memory at the resource creation, allocate
1073                  * at the set interest.
1074                  */
1075                 if (!attr_value->data) {
1076                         switch (attr_value->type) {
1077                         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
1078                                 attr_value->data = calloc(1, sizeof(int32_t));
1079                                 break;
1080                         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
1081                                 attr_value->data = calloc(1, sizeof(int64_t));
1082                                 break;
1083                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
1084                                 attr_value->data = calloc(1, sizeof(u_int32_t));
1085                                 break;
1086                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
1087                                 attr_value->data = calloc(1, sizeof(u_int64_t));
1088                                 break;
1089                         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
1090                                 attr_value->data = calloc(1, sizeof(double));
1091                                 break;
1092                         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
1093                                 attr_value->data = calloc(SYSCOMMON_RESMAN_BUFF_MAX, sizeof(char));
1094                                 break;
1095                         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
1096                                 attr_value->data = calloc(1, sizeof(struct syscommon_resman_array_value));
1097                                 break;
1098                         default:
1099                                 ret = -EINVAL;
1100                                 goto err;
1101                         }
1102
1103                         if (!attr_value->data) {
1104                                 ret = -ENOMEM;
1105                                 goto err;
1106                         }
1107                 }
1108         }
1109
1110         resource->attr_interest |= interest_mask;
1111
1112         return 0;
1113
1114 err:
1115         for (; i >= 0;  i--) {
1116                 if (!(resource->attrs[i].id & interest_mask))
1117                         continue;
1118
1119                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
1120                 if (!attr_value)
1121                         continue;
1122
1123                 if (attr_value->data) {
1124                         free(attr_value->data);
1125                         attr_value->data = NULL;
1126                 }
1127         }
1128
1129         return ret;
1130 }
1131
1132 static int
1133 unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask)
1134 {
1135         struct syscommon_resman_resource_attribute_value *attr_value;
1136         int i;
1137
1138         if (!resource)
1139                 return -EINVAL;
1140
1141         if (!is_resource_attr_interested(resource, interest_mask))
1142                 return -EINVAL;
1143
1144         for (i = 0; i < resource->num_attrs; i++) {
1145                 if (!(resource->attrs[i].id & interest_mask))
1146                         continue;
1147
1148                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
1149                 if (!attr_value)
1150                         return -EINVAL;
1151
1152                 if (attr_value->data) {
1153                         switch (attr_value->type) {
1154                         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
1155                         {
1156                                 struct syscommon_resman_array_value *array = attr_value->data;
1157
1158                                 if (array->data) {
1159                                         free(array->data);
1160                                         array->data = NULL;
1161                                 }
1162                                 /* fall through */
1163                         }
1164                         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
1165                         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
1166                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
1167                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
1168                         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
1169                         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
1170                                 free(attr_value->data);
1171                                 attr_value->data = NULL;
1172                                 break;
1173                         default:
1174                                 return -EINVAL;
1175                         }
1176                 }
1177         }
1178
1179         resource->attr_interest &= ~interest_mask;
1180
1181         return 0;
1182 }
1183
1184 int
1185 syscommon_resman_unset_resource_attr_interest(int resource_id, u_int64_t interest_mask)
1186 {
1187         struct syscommon_resman_resource *resource = find_resource(resource_id);
1188
1189         return unset_resource_attr_interest(resource, interest_mask);
1190 }
1191
1192 static bool
1193 is_resource_attr_interested(struct syscommon_resman_resource *resource,
1194                                              u_int64_t interest_mask)
1195 {
1196         if (!resource)
1197                 return false;
1198
1199         if (resource->attr_interest != (resource->attr_interest | interest_mask))
1200                 return false;
1201
1202         return true;
1203 }
1204
1205 bool
1206 syscommon_resman_is_resource_attr_interested(int resource_id, u_int64_t interest_mask)
1207 {
1208         struct syscommon_resman_resource *resource = find_resource(resource_id);
1209
1210         return is_resource_attr_interested(resource, interest_mask);
1211 }
1212
1213 const char *
1214 syscommon_resman_get_resource_attr_name(int resource_id, u_int64_t attr_id)
1215 {
1216         const struct syscommon_resman_resource_attribute *attr;
1217         struct syscommon_resman_resource *resource = find_resource(resource_id);
1218
1219         attr = get_resource_attr(resource, attr_id);
1220         if (!attr)
1221                 return NULL;
1222
1223         return attr->name;
1224 }
1225
1226 const char
1227 *syscommon_resman_get_resource_name(int resource_id)
1228 {
1229         struct syscommon_resman_resource *resource = find_resource(resource_id);
1230
1231         return resource ? resource->name : NULL;
1232 }
1233
1234 void *
1235 syscommon_resman_get_resource_privdata(int resource_id)
1236 {
1237         struct syscommon_resman_resource *resource = find_resource(resource_id);
1238
1239         return resource ? resource->priv : NULL;
1240 }
1241
1242 int
1243 syscommon_resman_get_resource_type(int resource_id)
1244 {
1245         struct syscommon_resman_resource *resource = find_resource(resource_id);
1246
1247         return resource ? resource->type : -EINVAL;
1248 }
1249
1250 int
1251 syscommon_resman_set_resource_privdata(int resource_id, void *priv)
1252 {
1253         struct syscommon_resman_resource *resource = find_resource(resource_id);
1254
1255         if (!resource)
1256                 return -EINVAL;
1257
1258         resource->priv = priv;
1259
1260         return 0;
1261 }
1262
1263 static void init_resource_driver(gpointer data, gpointer udata)
1264 {
1265         struct syscommon_resman_resource_driver *driver = (struct syscommon_resman_resource_driver *) data;
1266         int ret = 0;
1267
1268         if (driver && driver->ops.init) {
1269                 ret = driver->ops.init();
1270                 if (ret < 0)
1271                         syscommon_resman_remove_resource_driver(driver);
1272         }
1273 }
1274
1275 static void exit_resource_driver(gpointer data, gpointer udata)
1276 {
1277         struct syscommon_resman_resource_driver *driver = (struct syscommon_resman_resource_driver *) data;
1278
1279         if (driver && driver->ops.exit)
1280                 driver->ops.exit();
1281 }
1282
1283 void syscommon_resman_init_resource_drivers(void)
1284 {
1285         g_list_foreach(g_resource_driver_head, init_resource_driver, NULL);
1286 }
1287
1288 void syscommon_resman_exit_resource_drivers(void)
1289 {
1290         g_list_foreach(g_resource_driver_head, exit_resource_driver, NULL);
1291 }