cf58a9d982f3ea260e733a08eee8d6762f7ba48d
[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         hashtable_hash_in(dev_registry, &devdef->hlist, hash);
29         hashtable_hash_in(
30           dev_byif, &devdef->hlist_if, DEV_IF(devdef->class.meta));
31
32         llist_append(&dev_registry_flat, &devdef->dev_list);
33     }
34 }
35
36 static int
37 devclass_eq(struct devclass* c1, struct devclass* c2)
38 {
39     return c1->meta == c2->meta && c1->variant == c2->variant &&
40            c1->device == c2->device;
41 }
42
43 struct device_def*
44 devdef_byclass(struct devclass* class)
45 {
46     u32_t hash = devclass_hash(*class);
47     int errno;
48
49     struct device_def *pos, *n;
50     hashtable_hash_foreach(dev_registry, hash, pos, n, hlist)
51     {
52         if (pos->class.hash != hash) {
53             continue;
54         }
55         if (devclass_eq(class, &pos->class)) {
56             break;
57         }
58     }
59
60     return pos;
61 }
62
63 struct device*
64 device_create_byclass(struct devclass* class,
65                       u32_t type,
66                       char* name,
67                       int* err_code)
68 {
69     int errno;
70     struct device_def* devdef = devdef_byclass(class);
71
72     if (!devdef) {
73         *err_code = ENOENT;
74         return NULL;
75     }
76
77     if (!devdef->init_for) {
78         if (err_code) {
79             *err_code = ENOTSUP;
80         }
81         return NULL;
82     }
83
84     struct device* dev = device_add(adhoc_devcat, NULL, type, NULL);
85
86     errno = devdef->init_for(devdef, dev);
87     if (err_code && !errno) {
88         *err_code = errno;
89         device_remove(dev);
90         return NULL;
91     }
92
93     device_setname(dev,
94                    "%s_%d:%d:%d_%d",
95                    name,
96                    class->meta,
97                    class->device,
98                    class->device,
99                    dev->dev_id);
100
101     return dev;
102 }
103
104 struct hbucket*
105 device_definitions_byif(int if_type)
106 {
107     return &dev_byif[__hashkey(dev_byif, if_type)];
108 }
109
110 #define device_load_on_stage(stage)                                            \
111     ({                                                                         \
112         int idx = 0;                                                           \
113         struct device_def* devdef;                                             \
114         ldga_foreach(dev_ld_##stage, struct device_def*, idx, devdef)          \
115         {                                                                      \
116             devdef->init(devdef);                                              \
117         }                                                                      \
118     })
119
120 void
121 device_earlystage()
122 {
123     device_load_on_stage(early);
124 }
125
126 void
127 device_timerstage()
128 {
129     device_load_on_stage(aftertimer);
130 }
131
132 void
133 device_poststage()
134 {
135     device_load_on_stage(post);
136 }
137
138 static int
139 __devdb_db_gonext(struct twimap* mapping)
140 {
141     struct device_def* current = twimap_index(mapping, struct device_def*);
142     if (current->dev_list.next == &dev_registry_flat) {
143         return 0;
144     }
145     mapping->index =
146       list_entry(current->dev_list.next, struct device_def, dev_list);
147     return 1;
148 }
149
150 static void
151 __devdb_twifs_lsdb(struct twimap* mapping)
152 {
153     char flags[32];
154     struct device_def* def = twimap_index(mapping, struct device_def*);
155
156     int meta = def->class.meta;
157     ksnprintf(flags, 32, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
158
159     twimap_printf(mapping,
160                   "%d:%d:%d %s (%s)\n",
161                   def->class.meta,
162                   def->class.device,
163                   def->class.variant,
164                   def->name,
165                   flags);
166 }
167
168 static void
169 devdb_twifs_plugin()
170 {
171     struct twimap* map = twifs_mapping(NULL, NULL, "devtab");
172     map->read = __devdb_twifs_lsdb;
173     map->go_next = __devdb_db_gonext;
174 }
175 EXPORT_TWIFS_PLUGIN(devdb, devdb_twifs_plugin);