a2483788069aef3f4ff8b209081df8a696c5b81b
[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 #include <lunaix/syslog.h>
5
6 #include <klibc/hash.h>
7
8 #include <klibc/strfmt.h>
9
10 LOG_MODULE("devdb")
11
12 static DECLARE_HASHTABLE(dev_registry, 32);
13 static DECLARE_HASHTABLE(dev_byif, 8);
14 static DEFINE_LLIST(dev_registry_flat);
15
16 static struct device_cat* adhoc_devcat;
17
18 static inline u32_t
19 hash_dev(u32_t fngrp, u32_t dev)
20 {
21     return (hash_32(fngrp, 16) << 16) | (hash_32(dev, 16));
22 }
23
24 void
25 device_scan_drivers()
26 {
27     adhoc_devcat = device_addcat(NULL, "adhoc");
28
29     hashtable_init(dev_registry);
30     hashtable_init(dev_byif);
31
32     int idx = 0, errno;
33     struct device_def* devdef;
34     ldga_foreach(devdefs, struct device_def*, idx, devdef)
35     {
36         struct devclass* devc = &devdef->class;
37         u32_t hash = hash_dev(devc->fn_grp, devc->device);
38         devdef->class_hash = hash;
39
40         if (!devdef->name) {
41             devdef->name = "<unspecified>";
42         }
43
44         errno = 0;
45         if (devdef->ad_tabulam) {
46             errno = devdef->ad_tabulam(devdef);
47         }
48
49         if (errno) {
50             ERROR("driver unable to register %xh:%xh.%d (err=%d)",
51                     devdef->class.fn_grp, 
52                     devdef->class.device,
53                     devdef->class.variant, errno);
54             continue;
55         }
56
57         hashtable_hash_in(dev_registry, &devdef->hlist, hash);
58         hashtable_hash_in(dev_byif, &devdef->hlist_if, DEV_VN(devc->fn_grp));
59
60         llist_append(&dev_registry_flat, &devdef->dev_list);
61     }
62 }
63
64 static int
65 devclass_eq(struct devclass* c1, struct devclass* c2)
66 {
67     return c1->fn_grp == c2->fn_grp && c1->device == c2->device;
68 }
69
70 struct device_def*
71 devdef_byclass(struct devclass* devc)
72 {
73     u32_t hash = hash_dev(devc->fn_grp, devc->device);
74     int errno;
75
76     struct device_def *pos, *n;
77     hashtable_hash_foreach(dev_registry, hash, pos, n, hlist)
78     {
79         if (pos->class_hash != hash) {
80             continue;
81         }
82         if (devclass_eq(devc, &pos->class)) {
83             break;
84         }
85     }
86
87     return pos;
88 }
89
90 struct device_def*
91 devdef_byident(struct devident* ident)
92 {
93     struct devclass derived = { .device = DEV_KIND_FROM(ident->unique),
94                                 .fn_grp = ident->fn_grp };
95     return devdef_byclass(&derived);
96 }
97
98 struct hbucket*
99 device_definitions_byif(int if_type)
100 {
101     return &dev_byif[__hashkey(dev_byif, if_type)];
102 }
103
104 #define __device_load_on_stage(stage)                                          \
105     ({                                                                         \
106         int idx = 0;                                                           \
107         struct device_def* devdef;                                             \
108         ldga_foreach(dev_##stage, struct device_def*, idx, devdef)             \
109         {                                                                      \
110             device_chain_load_once(devdef);                                    \
111         }                                                                      \
112     })
113 #define device_load_on_stage(stage) __device_load_on_stage(stage)
114
115 void
116 device_onboot_load()
117 {
118     device_load_on_stage(load_onboot);
119 }
120
121 void
122 device_postboot_load()
123 {
124     device_load_on_stage(load_postboot);
125 }
126
127 void
128 device_sysconf_load()
129 {
130     device_load_on_stage(load_sysconf);
131 }
132
133 static int
134 __devdb_db_gonext(struct twimap* mapping)
135 {
136     struct device_def* current = twimap_index(mapping, struct device_def*);
137     if (current->dev_list.next == &dev_registry_flat) {
138         return 0;
139     }
140     mapping->index =
141       list_entry(current->dev_list.next, struct device_def, dev_list);
142     return 1;
143 }
144
145 static void
146 __devdb_twifs_lsdb(struct twimap* mapping)
147 {
148     char flags[64];
149     struct device_def* def = twimap_index(mapping, struct device_def*);
150
151     int meta = def->class.fn_grp;
152     ksnprintf(flags, 64, "vn=%x, fn=%x", DEV_VN(meta), DEV_FN(meta));
153
154     twimap_printf(mapping,
155                   "%08xh:%04d \"%s\" %s\n",
156                   def->class.fn_grp,
157                   def->class.device,
158                   def->name,
159                   flags);
160 }
161
162 void
163 __devdb_reset(struct twimap* map)
164 {
165     map->index =
166       container_of(dev_registry_flat.next, struct device_def, dev_list);
167 }
168
169 static void
170 devdb_twifs_plugin()
171 {
172     struct twimap* map = twifs_mapping(NULL, NULL, "devtab");
173     map->reset = __devdb_reset;
174     map->read = __devdb_twifs_lsdb;
175     map->go_next = __devdb_db_gonext;
176 }
177 EXPORT_TWIFS_PLUGIN(devdb, devdb_twifs_plugin);