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