halcc: Introduce halcc library
[platform/hal/api/common.git] / halcc / src / halcc-object.c
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
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 <stdio.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <assert.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <glib.h>
26
27 #include "halcc-object.h"
28 #include "halcc-parser.h"
29 #include "halcc-util.h"
30
31 #define HALCC_TRANSPORT_DEFAULT         HALCC_TRANSPORT_PASSTHROUGH
32
33 typedef struct halcc_version {
34         int major;
35         union {
36                 /**
37                  * Can be used interchangeably.
38                  * min_minor might be useful if max_minor is specified.
39                  */
40                 int minor;
41                 int min_minor;
42         };
43         int max_minor;
44 } halcc_version;
45
46 typedef struct halcc_interface {
47         char *name;
48         char *instance_id;
49 } halcc_interface;
50
51 typedef struct halcc_hal {
52         char *name;
53         halcc_version version;
54         halcc_transport_e transport;
55         halcc_dependency_state_e dependency_state;
56         GHashTable *dependencies;
57         GHashTable *interfaces;
58 } halcc_hal;
59
60 typedef struct halcc_manifest {
61         halcc_manifest_type_e manifest_type;
62         halcc_version version;
63         int level;
64         GHashTable *hals;
65 } halcc_manifest;
66
67 typedef enum halcc_hash_compare_type_e {
68         HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION,
69         HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION,
70         HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION,
71 } halcc_hash_compare_type_e;
72
73 typedef struct hash_hal_key {
74         halcc_hal hal;
75         halcc_hash_compare_type_e compare_type;
76 } hash_hal_key;
77
78 #define HASH_HAL_KEY(_name, _major, _minor, _compare_type)      \
79         (hash_hal_key) {                                        \
80             .hal = {                                    \
81                     .name = (char *) _name,             \
82                     .version.major = _major,            \
83                     .version.minor = _minor,            \
84             },                                          \
85             .compare_type = _compare_type,              \
86         }
87
88 #define HASH_HAL_KEY_RAW(_hal, _compare_type)                   \
89         HASH_HAL_KEY((_hal)->name,                              \
90                 (_hal)->version.major,                  \
91                 (_hal)->version.minor,                  \
92                 _compare_type                           \
93         )
94
95 static void hashtable_foreach(GHashTable *table, halcc_iter_cb cb, void *user_data)
96 {
97         GHashTableIter iter;
98         void *data;
99
100         if (!table || !cb)
101                 return;
102
103         g_hash_table_iter_init(&iter, table);
104         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data))
105                 cb(data, user_data);
106 }
107
108 static guint hal_hash(gconstpointer key)
109 {
110         const halcc_hal *hal = (const halcc_hal *) key;
111
112         assert(hal);
113         assert(hal->name);
114
115         return g_str_hash(hal->name);
116 }
117
118 static gboolean hal_hash_equal(gconstpointer a, gconstpointer b)
119 {
120         const halcc_hal *hal = (const halcc_hal *) a;
121         const hash_hal_key *key = (const hash_hal_key *) b;
122         int compare_type;
123
124         assert(hal);
125         assert(key);
126
127         if (strncmp(hal->name, key->hal.name, strlen(hal->name) + 1) != 0)
128                 return false;
129
130         if (hal->version.major != key->hal.version.major)
131                 return false;
132
133         compare_type = key->compare_type;
134
135         switch (compare_type) {
136         case HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION:
137                 return hal->version.minor == key->hal.version.minor;
138         case HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION:
139                 return hal->version.minor <= key->hal.version.minor;
140         case HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION:
141                 return hal->version.minor >= key->hal.version.minor;
142         default:
143                 break;
144         }
145
146         assert(0); // unreachable
147
148         return false;
149 }
150
151 static void hal_hash_value_free(gpointer data)
152 {
153         halcc_hal *hal = (halcc_hal *) data;
154
155         halcc_hal_free(hal);
156 }
157
158 static GHashTable* hashtable_hal_new(void)
159 {
160         return g_hash_table_new_full(hal_hash, hal_hash_equal, NULL, hal_hash_value_free);
161 }
162
163 static int hashtable_hal_insert(GHashTable *hal_table, halcc_hal *hal)
164 {
165         hash_hal_key key;
166
167         if (!hal_table || !hal)
168                 return -EINVAL;
169
170         key = HASH_HAL_KEY_RAW(hal, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
171
172         if (g_hash_table_lookup_extended(hal_table, &key, NULL, NULL))
173                 return -EALREADY;
174
175         g_hash_table_insert(hal_table, hal, hal);
176
177         return 0;
178 }
179
180 static halcc_hal* hashtable_hal_lookup(GHashTable *hal_table,
181         const char *name, int major, int minor, halcc_hash_compare_type_e type)
182 {
183         hash_hal_key key;
184
185         if (!hal_table || !name)
186                 return NULL;
187
188         key = HASH_HAL_KEY(name, major, minor, type);
189
190         return g_hash_table_lookup(hal_table, &key);
191 }
192
193 static halcc_hal* hashtable_hal_steal(GHashTable *hal_table, const char *name, int major, int minor)
194 {
195         hash_hal_key key;
196         halcc_hal *hal = NULL;
197
198         if (!hal_table || !name)
199                 return NULL;
200
201         key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
202
203         if (!g_hash_table_steal_extended(hal_table, &key, NULL, (gpointer*) &hal))
204                 return NULL;
205
206         return hal;
207 }
208
209 static void hashtable_hal_remove(GHashTable *hal_table, const char *name, int major, int minor)
210 {
211         hash_hal_key key;
212
213         if (!hal_table || !name)
214                 return;
215
216         key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
217
218         g_hash_table_remove(hal_table, &key);
219 }
220
221 static guint interface_hash(gconstpointer key)
222 {
223         const halcc_interface *interface = (const halcc_interface *) key;
224         char interface_str[HALCC_NAME_MAX * 2] = { 0 , };
225
226         assert(interface);
227         assert(interface->name);
228
229         if (interface->instance_id)
230                 snprintf(interface_str, sizeof(interface_str), "%s.%s", interface->name, interface->instance_id);
231         else
232                 snprintf(interface_str, sizeof(interface_str), "%s.default", interface->name);
233
234         return g_str_hash(interface_str);
235 }
236
237 static gboolean interface_hash_equal(gconstpointer a, gconstpointer b)
238 {
239         const halcc_interface *interface = (const halcc_interface *) a;
240         const halcc_interface *key = (const halcc_interface *) b;
241
242         assert(interface);
243         assert(key);
244
245         return strncmp(interface->name, key->name, strlen(interface->name) + 1) == 0;
246 }
247
248 static void interface_hash_value_free(gpointer data)
249 {
250         halcc_interface *interface = (halcc_interface *) data;
251
252         halcc_interface_free(interface);
253 }
254
255 static GHashTable* hashtable_interface_new(void)
256 {
257         return g_hash_table_new_full(interface_hash,
258                 interface_hash_equal, NULL, interface_hash_value_free);
259 }
260
261 static int hashtable_interface_insert(GHashTable *interface_table, halcc_interface *interface)
262 {
263         g_hash_table_insert(interface_table, interface, interface);
264
265         return 0;
266 }
267
268 /*
269 static halcc_interface* hashtable_interface_lookup(GHashTable *interface_table,
270         const char *name, const char *instance_id)
271 {
272         halcc_interface key;
273
274         if (!interface_table || !name)
275                 return NULL;
276
277         key = (halcc_interface) {
278                 .name = (char *) name,
279                 .instance_id = (char *) instance_id,
280         };
281
282         return g_hash_table_lookup(interface_table, &key);
283 }
284 */
285
286 static void hashtable_interface_remove(GHashTable *interface_table,
287         const char *name, const char *instance_id)
288 {
289         halcc_interface key;
290
291         if (!interface_table || !name)
292                 return;
293
294         key = (halcc_interface) {
295                 .name = (char *) name,
296                 .instance_id = (char *) instance_id,
297         };
298
299         g_hash_table_remove(interface_table, &key);
300 }
301
302 int halcc_manifest_new(halcc_manifest **manifest)
303 {
304         halcc_manifest *m;
305
306         if (!manifest)
307                 return -EINVAL;
308
309         m = calloc(1, sizeof(halcc_manifest));
310         if (!m)
311                 return -ENOMEM;
312
313         *m = (halcc_manifest) {
314                 .manifest_type = HALCC_UNINITIALIZED_INT,
315                 .version.major = HALCC_UNINITIALIZED_INT,
316                 .version.minor = HALCC_UNINITIALIZED_INT,
317                 .level = HALCC_UNINITIALIZED_INT,
318                 .hals = hashtable_hal_new(),
319         };
320
321         *manifest = g_steal_pointer(&m);
322
323         return 0;
324 }
325
326 void halcc_manifest_free(halcc_manifest *manifest)
327 {
328         if (!manifest)
329                 return;
330
331         g_hash_table_destroy(g_steal_pointer(&manifest->hals));
332
333         free(manifest);
334 }
335
336 int halcc_manifest_set_type(halcc_manifest *manifest, halcc_manifest_type_e type)
337 {
338         if (!manifest)
339                 return -EINVAL;
340
341         if (type < HALCC_MANIFEST_TYPE_HAL_API || type > HALCC_MANIFEST_TYPE_HAL_BACKEND)
342                 return -EINVAL;
343
344
345         return halcc_util_set_int_once(&manifest->manifest_type, type, "manifest.type");
346 }
347
348 int halcc_manifest_get_type(halcc_manifest *manifest, halcc_manifest_type_e *type)
349 {
350         if (!manifest || !type)
351                 return -EINVAL;
352
353         *type = manifest->manifest_type;
354
355         return 0;
356 }
357
358 int halcc_manifest_set_version(halcc_manifest *manifest, int major, int minor)
359 {
360         int ret;
361
362         if (!manifest)
363                 return -EINVAL;
364
365         if (major < 0 || minor < 0)
366                 return -EINVAL;
367
368         ret = halcc_util_set_int_once(&manifest->version.major, major, "manifest.version.major");
369         if (ret != 0)
370                 return ret;
371
372         ret = halcc_util_set_int_once(&manifest->version.minor, minor, "manifest.version.minor");
373         if (ret != 0)
374                 return ret;
375
376         return 0;
377 }
378
379 int halcc_manifest_get_version(halcc_manifest *manifest, int *major, int *minor)
380 {
381         if (!manifest || !major || !minor)
382                 return -EINVAL;
383
384         *major = manifest->version.major;
385         *minor = manifest->version.minor;
386
387         return 0;
388 }
389
390 int halcc_manifest_set_level(halcc_manifest *manifest, int level)
391 {
392         if (!manifest)
393                 return -EINVAL;
394
395         return halcc_util_set_int_once(&manifest->level, level, "manifest.level");
396 }
397
398 int halcc_manifest_get_level(halcc_manifest *manifest, int *level)
399 {
400         if (!manifest || !level)
401                 return -EINVAL;
402
403         *level = manifest->level;
404
405         return 0;
406 }
407
408 int halcc_manifest_add_hal(halcc_manifest *manifest, halcc_hal *hal)
409 {
410         if (!manifest || !hal)
411                 return -EINVAL;
412
413         assert(manifest->hals);
414
415         if (!hal->name)
416                 return -EINVAL;
417
418         return hashtable_hal_insert(manifest->hals, hal);
419 }
420
421 int halcc_manifest_find_hal(halcc_manifest *manifest,
422         const char *hal_name, int major, int minor, halcc_hal **hal)
423 {
424         halcc_hal *h;
425
426         if (!manifest || !hal_name)
427                 return -EINVAL;
428
429         h = hashtable_hal_lookup(manifest->hals,
430                 hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
431         if (!h)
432                 return -ENOTSUP;
433
434         if (hal)
435                 *hal = g_steal_pointer(&h);
436
437         return 0;
438 }
439
440 int halcc_manifest_find_hal_raw(halcc_manifest *manifest,
441         halcc_hal *raw, halcc_hal **hal)
442 {
443         return halcc_manifest_find_hal(manifest,
444                 raw->name, raw->version.major, raw->version.minor, hal);
445 }
446
447 int halcc_manifest_find_hal_backward_compatible(halcc_manifest *manifest,
448         const char *hal_name, int major, int minor, halcc_hal **hal)
449 {
450         halcc_hal *h;
451
452         if (!manifest || !hal_name)
453                 return -EINVAL;
454
455         h = hashtable_hal_lookup(manifest->hals,
456                 hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION);
457         if (!h)
458                 return -ENOTSUP;
459
460         if (hal)
461                 *hal = g_steal_pointer(&h);
462
463         return 0;
464 }
465
466 int halcc_manifest_find_hal_backward_compatible_raw(halcc_manifest *manifest,
467         halcc_hal *raw, halcc_hal **hal)
468 {
469         return halcc_manifest_find_hal_backward_compatible(manifest,
470                 raw->name, raw->version.major, raw->version.minor, hal);
471 }
472
473 int halcc_manifest_find_hal_forward_compatible(halcc_manifest *manifest,
474         const char *hal_name, int major, int minor, halcc_hal **hal)
475 {
476         halcc_hal *h;
477
478         if (!manifest || !hal_name)
479                 return -EINVAL;
480
481         h = hashtable_hal_lookup(manifest->hals,
482                 hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION);
483         if (!h)
484                 return -ENOTSUP;
485
486         if (hal)
487                 *hal = g_steal_pointer(&h);
488
489         return 0;
490 }
491
492 int halcc_manifest_find_hal_forward_compatible_raw(halcc_manifest *manifest,
493         halcc_hal *raw, halcc_hal **hal)
494 {
495         return halcc_manifest_find_hal_forward_compatible(manifest,
496                 raw->name, raw->version.major, raw->version.minor, hal);
497 }
498
499 int halcc_manifest_steal_hal(halcc_manifest *manifest,
500         const char *hal_name, int major, int minor, halcc_hal **hal)
501 {
502         halcc_hal *h = NULL;
503
504         if (!manifest || !hal_name)
505                 return -EINVAL;
506
507         h = hashtable_hal_steal(manifest->hals, hal_name, major, minor);
508         if (!h)
509                 return -ENOTSUP;
510
511         if (hal)
512                 *hal = g_steal_pointer(&h);
513
514         return 0;
515 }
516
517 void halcc_manifest_remove_hal(halcc_manifest *manifest,
518         const char *hal_name, int major, int minor)
519 {
520         if (!manifest || !hal_name)
521                 return;
522
523         hashtable_hal_remove(manifest->hals, hal_name, major, minor);
524 }
525
526 void halcc_manifest_foreach_hal(halcc_manifest *manifest,
527         halcc_iter_cb cb, void *user_data)
528 {
529         if (!manifest || !manifest->hals || !cb)
530                 return;
531
532         hashtable_foreach(manifest->hals, cb, user_data);
533 }
534
535 int halcc_hal_new(halcc_hal **hal)
536 {
537         halcc_hal *h;
538
539         if (!hal)
540                 return -EINVAL;
541
542         h = calloc(1, sizeof(halcc_hal));
543         if (!h)
544                 return -ENOMEM;
545
546         h->transport = HALCC_TRANSPORT_DEFAULT;
547         h->dependency_state = HALCC_DEPENDENCY_STATE_NONE;
548         h->dependencies = hashtable_hal_new();
549         h->interfaces = hashtable_interface_new();
550
551         *hal = g_steal_pointer(&h);
552
553         return 0;
554 }
555
556 void halcc_hal_free(halcc_hal *hal)
557 {
558         if (!hal)
559                 return;
560
561         free(g_steal_pointer(&hal->name));
562         g_hash_table_destroy(g_steal_pointer(&hal->dependencies));
563         g_hash_table_destroy(g_steal_pointer(&hal->interfaces));
564         free(hal);
565 }
566
567 int halcc_hal_set_name(halcc_hal *hal, const char *hal_name)
568 {
569         char *n;
570
571         if (!hal)
572                 return -EINVAL;
573
574         if (hal->name)
575                 free(g_steal_pointer(&hal->name));
576
577         if (!hal_name)
578                 return 0;
579
580         n = strndup(hal_name, HALCC_NAME_MAX);
581         if (!n)
582                 return -ENOMEM;
583
584         hal->name = g_steal_pointer(&n);
585
586         return 0;
587 }
588
589 int halcc_hal_get_name(halcc_hal *hal, const char **hal_name)
590 {
591         if (!hal || !hal_name)
592                 return -EINVAL;
593
594         *hal_name = hal->name;
595
596         return 0;
597 }
598
599 int halcc_hal_set_version(halcc_hal *hal, int major, int min_minor, int max_minor)
600 {
601         if (!hal)
602                 return -EINVAL;
603
604         hal->version.major = major;
605         hal->version.min_minor = min_minor;
606         hal->version.max_minor = max_minor;
607
608         return 0;
609 }
610
611 int halcc_hal_get_version(halcc_hal *hal, int *major, int *min_minor, int *max_minor)
612 {
613         if (!hal || !major || !min_minor)
614                 return -EINVAL;
615
616         *major = hal->version.major;
617         *min_minor = hal->version.min_minor;
618         if (max_minor)
619                 *max_minor = hal->version.max_minor;
620
621         return 0;
622 }
623
624 int halcc_hal_set_transport(halcc_hal *hal, halcc_transport_e transport)
625 {
626         if (!hal)
627                 return -EINVAL;
628
629         hal->transport = transport;
630
631         return 0;
632 }
633
634 int halcc_hal_get_transport(halcc_hal *hal, halcc_transport_e *transport)
635 {
636         if (!hal || !transport)
637                 return -EINVAL;
638
639         assert(hal->transport >= HALCC_TRANSPORT_PASSTHROUGH);
640         assert(hal->transport <= HALCC_TRANSPORT_IPC);
641
642         *transport = hal->transport;
643
644         return 0;
645 }
646
647 int halcc_hal_add_dependency(halcc_hal *hal, halcc_hal *dependency)
648 {
649         if (!hal || !dependency)
650                 return -EINVAL;
651
652         return hashtable_hal_insert(hal->dependencies, dependency);
653 }
654
655 void halcc_hal_remove_dependency(halcc_hal *hal,
656         const char *dependency_hal_name, int major, int minor)
657 {
658         if (!hal || !dependency_hal_name)
659                 return;
660
661         hashtable_hal_remove(hal->dependencies, dependency_hal_name, major, minor);
662 }
663
664 void halcc_hal_foreach_dependency(halcc_hal *hal, halcc_iter_cb cb, void *user_data)
665 {
666         if (!hal || !hal->dependencies || !cb)
667                 return;
668
669         hashtable_foreach(hal->dependencies, cb, user_data);
670 }
671
672 int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface)
673 {
674         if (!hal || !interface)
675                 return -EINVAL;
676
677         return hashtable_interface_insert(hal->interfaces, interface);
678 }
679
680 void halcc_hal_remove_interface(halcc_hal *hal,
681         const char *interface_name, const char *instance_id)
682 {
683         if (!hal || !interface_name)
684                 return;
685
686         hashtable_interface_remove(hal->interfaces, interface_name, instance_id);
687 }
688
689 void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data)
690 {
691         if (!hal || !hal->interfaces || !cb)
692                 return;
693
694         hashtable_foreach(hal->interfaces, cb, user_data);
695 }
696
697 int halcc_interface_new(halcc_interface **interface)
698 {
699         halcc_interface *iface;
700
701         if (!interface)
702                 return -EINVAL;
703
704         iface = calloc(1, sizeof(halcc_interface));
705         if (!iface)
706                 return -ENOMEM;
707
708         *interface = g_steal_pointer(&iface);
709
710         return 0;
711 }
712
713 void halcc_interface_free(halcc_interface *interface)
714 {
715         if (!interface)
716                 return;
717
718         free(g_steal_pointer(&interface->name));
719         free(g_steal_pointer(&interface->instance_id));
720         free(g_steal_pointer(&interface));
721 }
722
723 int halcc_interface_set_name(halcc_interface *interface, const char *interface_name)
724 {
725         char *n;
726
727         if (!interface || !interface_name)
728                 return -EINVAL;
729
730         n = strndup(interface_name, HALCC_NAME_MAX);
731         if (!n)
732                 return -ENOMEM;
733
734         interface->name = g_steal_pointer(&n);
735
736         return 0;
737 }
738
739 int halcc_interface_get_name(halcc_interface *interface, const char **interface_name)
740 {
741         if (!interface || !interface_name)
742                 return -EINVAL;
743
744         *interface_name = interface->name;
745
746         return 0;
747 }
748
749 int halcc_interface_set_instance_id(halcc_interface *interface, const char *instance_id)
750 {
751         char *id = NULL;
752
753         if (!interface || !instance_id)
754                 return -EINVAL;
755
756         id = strndup(instance_id, HALCC_NAME_MAX);
757         if (!id)
758                 return -ENOMEM;
759
760         interface->instance_id = g_steal_pointer(&id);
761
762         return 0;
763 }
764
765 int halcc_interface_get_instance_id(halcc_interface *interface, const char **instance_id)
766 {
767         if (!interface || !instance_id)
768                 return -EINVAL;
769
770         *instance_id = interface->instance_id;
771
772         return 0;
773 }