1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3
4#include "mos/filesystem/vfs_types.h"
5
6#include <mos/lib/structures/list.h>
7
8typedef struct _sysfs_file sysfs_file_t;
9
10typedef enum
11{
12 _SYSFS_INVALID = 0,
13 SYSFS_RO,
14 SYSFS_RW,
15 SYSFS_WO,
16 SYSFS_MEM, ///< memory-backed file
17 SYSFS_DYN, ///< dynamic directory items
18} sysfs_item_type_t;
19
20typedef struct _sysfs_item
21{
22 const char *name;
23 sysfs_item_type_t type;
24 bool (*show)(sysfs_file_t *file);
25 size_t (*store)(sysfs_file_t *file, const char *buf, size_t count, off_t offset);
26 ino_t ino;
27
28 union
29 {
30 struct
31 {
32 bool (*mmap)(sysfs_file_t *file, vmap_t *vmap, off_t offset);
33 bool (*munmap)(sysfs_file_t *file, vmap_t *vmap, bool *unmapped);
34 size_t size;
35 } mem;
36
37 struct
38 {
39 as_linked_list;
40 void (*iterate)(struct _sysfs_item *item, dentry_t *dentry, vfs_listdir_state_t *iterator_state, dentry_iterator_op op);
41 bool (*lookup)(inode_t *parent_dir, dentry_t *dentry);
42 bool (*create)(inode_t *parent_dir, dentry_t *dentry, file_type_t type, file_perm_t perm);
43 } dyn;
44 };
45} sysfs_item_t;
46
47// clang-format off
48#define SYSFS_RO_ITEM(_name, _show_fn) { .name = _name, .type = SYSFS_RO, .show = _show_fn }
49#define SYSFS_RW_ITEM(_name, _show_fn, _store_fn) { .name = _name, .type = SYSFS_RW, .show = _show_fn, .store = _store_fn }
50#define SYSFS_WO_ITEM(_name, _store_fn) { .name = _name, .type = SYSFS_WO, .store = _store_fn }
51#define SYSFS_MEM_ITEM(_name, _mmap_fn, _munmap_fn) { .name = _name, .type = SYSFS_MEM, .mem.mmap = _mmap_fn, .mem.munmap = _munmap_fn }
52#define SYSFS_DYN_ITEMS(_name, _iterate_fn, _lookup_fn) { .type = SYSFS_DYN, .dyn.iterate = _iterate_fn, .dyn.lookup = _lookup_fn }
53#define SYSFS_DYN_DIR(_name, _iterate_fn, _lookup_fn, _create_fn) { .type = SYSFS_DYN, .dyn.iterate = _iterate_fn, .dyn.lookup = _lookup_fn, .dyn.create = _create_fn }
54// clang-format on
55
56#define SYSFS_ITEM_RO_PRINTF(name, fmt, ...) \
57 static bool name(sysfs_file_t *file) \
58 { \
59 sysfs_printf(file, fmt, ##__VA_ARGS__); \
60 return true; \
61 }
62
63#define SYSFS_ITEM_RO_STRING(name, value) SYSFS_ITEM_RO_PRINTF(name, "%s\n", value)
64
65#define SYSFS_DEFINE_DIR(sysfs_name, sysfs_items) \
66 static sysfs_dir_t __sysfs_##sysfs_name = { \
67 .list_node = LIST_NODE_INIT(__sysfs_##sysfs_name), \
68 .name = #sysfs_name, \
69 .items = sysfs_items, \
70 .num_items = MOS_ARRAY_SIZE(sysfs_items), \
71 ._dentry = NULL, \
72 ._dynamic_items = LIST_HEAD_INIT(__sysfs_##sysfs_name._dynamic_items), \
73 }
74
75typedef struct
76{
77 as_linked_list;
78 const char *name;
79 sysfs_item_t *const items;
80 const size_t num_items;
81 dentry_t *_dentry; ///< for internal use only
82 list_head _dynamic_items; ///< for internal use only
83} sysfs_dir_t;
84
85/**
86 * @brief Register a sysfs directory
87 *
88 * @param entry the sysfs directory to register
89 */
90void sysfs_register(sysfs_dir_t *entry);
91
92/**
93 * @brief Register an entry in a sysfs directory
94 *
95 * @param sysfs_dir the sysfs directory to register the item in
96 * @param item the sysfs item to register
97 */
98void sysfs_register_file(sysfs_dir_t *sysfs_dir, sysfs_item_t *item);
99
100/**
101 * @brief Register an entry in the sysfs root directory
102 *
103 * @param item the sysfs item to register
104 */
105should_inline void sysfs_register_root_file(sysfs_item_t *item)
106{
107 sysfs_register_file(NULL, item);
108}
109
110void sysfs_file_set_data(sysfs_file_t *file, void *data);
111void *sysfs_file_get_data(sysfs_file_t *file);
112sysfs_item_t *sysfs_file_get_item(sysfs_file_t *file);
113
114inode_t *sysfs_create_inode(file_type_t type, void *data);
115
116__printf(2, 3) ssize_t sysfs_printf(sysfs_file_t *file, const char *fmt, ...);
117ssize_t sysfs_put_data(sysfs_file_t *file, const void *data, size_t count);
118