feat: fstat now handle symbolic link
[lunaix-os.git] / lunaix-os / kernel / device / devdb.c
1 #include <lunaix/device.h>
2 #include <lunaix/fs/twifs.h>
3 #include <lunaix/status.h>
4
5 #include <klibc/stdio.h>
6
7 static DECLARE_HASHTABLE(dev_registry, 32);
8 static DECLARE_HASHTABLE(dev_byif, 8);
9 static DEFINE_LLIST(dev_registry_flat);
10
11 static struct device* adhoc_devcat;
12
13 void
14 device_register_all()
15 {
16     adhoc_devcat = device_addcat(NULL, "adhoc");
17
18     hashtable_init(dev_registry);
19     hashtable_init(dev_byif);
20
21     int idx = 0;
22     struct device_def* devdef;
23     ldga_foreach(devdefs, struct device_def*, idx, devdef)
24     {
25         u32_t hash = devclass_hash(devdef->class);
26         devdef->class.hash = hash;
27
28         if (!devdef->name) {
29             devdef->name = "<unspecified>";
30         }
31
32         hashtable_hash_in(dev_registry, &devdef->hlist, hash);
33         hashtable_hash_in(
34           dev_byif, &devdef->hlist_if, DEV_IF(devdef->class.meta));
35
36         llist_append(&dev_registry_flat, &devdef->dev_list);
37     }
38 }
39
40 static int
41 devclass_eq(struct devclass* c1, struct devclass* c2)
42 {
43     return c1->meta == c2->meta && c1->variant == c2->variant &&
44            c1->device == c2->device;
45 }
46
47 struct device_def*
48 devdef_byclass(struct devclass* class)
49 {
50     u32_t hash = devclass_hash(*class);
51     int errno;
52
53     struct device_def *pos, *n;
54     hashtable_hash_foreach(dev_registry, hash, pos, n, hlist)
55     {
56         if (pos->class.hash != hash) {
57             continue;
58         }
59         if (devclass_eq(class, &pos->class)) {
60             break;
61         }
62     }
63
64     return pos;
65 }
66
67 struct device*
68 device_create_byclass(struct devclass* class,
69                       u32_t type,
70                       char* name,
71                       int* err_code)
72 {
73     int errno;
74     struct device_def* devdef = devdef_byclass(class);
75
76     if (!devdef) {
77         *err_code = ENOENT;
78         return NULL;
79     }
80
81     if (!devdef->init_for) {
82         if (err_code) {
83             *err_code = ENOTSUP;
84         }
85         return NULL;
86     }
87
88     struct device* dev = device_add(adhoc_devcat, class, NULL, type, NULL);
89
90     errno = devdef->init_for(devdef, dev);
91     if (err_code && !errno) {
92         *err_code = errno;
93         device_remove(dev);
94         return NULL;
95     }
96
97     device_setname(dev,
98                    "%s_%d:%d:%d_%d",
99                    name,
100                    class->meta,
101                    class->device,
102                    class->device,
103                    dev->dev_uid);
104
105     return dev;
106 }
107
108 struct hbucket*
109 device_definitions_byif(int if_type)
110 {
111     return &dev_byif[__hashkey(dev_byif, if_type)];
112 }
113
114 #define device_load_on_stage(stage)                                            \
115     ({                                                                         \
116         int idx = 0;                                                           \
117         struct device_def* devdef;                                             \
118         ldga_foreach(dev_ld_##stage, struct device_def*, idx, devdef)          \
119         {                                                                      \
120             devdef->init(devdef);                                              \
121         }                                                                      \
122     })
123
124 void
125 device_earlystage()
126 {
127     device_load_on_stage(early);
128 }
129
130 void
131 device_timerstage()
132 {
133     device_load_on_stage(aftertimer);
134 }
135
136 void
137 device_poststage()
138 {
139     device_load_on_stage(post);
140 }
141
142 static int
143 __devdb_db_gonext(struct twimap* mapping)
144 {
145     struct device_def* current = twimap_index(mapping, struct device_def*);
146     if (current->dev_list.next == &dev_registry_flat) {
147         return 0;
148     }
149     mapping->index =
150       list_entry(current->dev_list.next, struct device_def, dev_list);
151     return 1;
152 }
153
154 static void
155 __devdb_twifs_lsdb(struct twimap* mapping)
156 {
157     char flags[64];
158     struct device_def* def = twimap_index(mapping, struct device_def*);
159
160     int meta = def->class.meta;
161     ksnprintf(flags, 64, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
162
163     twimap_printf(mapping,
164                   "%xh:%d:%d \"%s\" %s\n",
165                   def->class.meta,
166                   def->class.device,
167                   def->class.variant,
168                   def->name,
169                   flags);
170 }
171
172 void
173 __devdb_reset(struct twimap* map)
174 {
175     map->index =
176       container_of(dev_registry_flat.next, struct device_def, dev_list);
177 }
178
179 static void
180 devdb_twifs_plugin()
181 {
182     struct twimap* map = twifs_mapping(NULL, NULL, "devtab");
183     map->reset = __devdb_reset;
184     map->read = __devdb_twifs_lsdb;
185     map->go_next = __devdb_db_gonext;
186 }
187 EXPORT_TWIFS_PLUGIN(devdb, devdb_twifs_plugin);