BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / bus_managers / fdt / fdt.cpp
blob5a4fc2a9da46b05a6b282c52f4a3ee54fff1d6c6
1 /*
2 * Copyright 2014, Ithamar R. Adema <ithamar@upgrade-android.com>
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include <drivers/bus/FDT.h>
7 #include <KernelExport.h>
8 #include <util/kernel_cpp.h>
10 #include <ctype.h> // isprint
11 #include <stdio.h> // snprintf
13 extern "C" {
14 #include <fdt.h>
15 #include <libfdt.h>
16 #include <libfdt_env.h>
19 extern void *gFDT;
21 static status_t fdt_setup_devices(struct fdt_device_info *info, int count, void *cookie);
23 static const char *sTabTab = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
24 #define DS "%.*s"
25 #define DA depth - 1, sTabTab
27 static void
28 fdt_dump_value(const char *data, int32 len, int depth)
30 char str[128];
31 char astr[32];
32 char *p;
33 int l;
34 int i;
36 for (i = 0; i < len; ) {
37 p = str;
38 l = sizeof(str);
39 for (; i < len && (p == str || (i % 16 != 0)); i++) {
40 snprintf(p, l - 1, "%02x ", data[i]);
41 l -= strlen(p);
42 p += strlen(p);
43 astr[i % 16] = isprint(data[i]) ? data[i] : '.';
44 astr[i % 16] = isprint(data[i]) ? data[i] : '.';
45 astr[(i % 16) + 1] = '\0';
47 dprintf(DS" %-48.48s %s\n", DA, str, astr);
51 static int
52 fdt_debug_tree(int argc, char **argv)
54 bool dump_props = false, dump_values = false;
56 if (gFDT == NULL) {
57 dprintf("No fdt tree\n");
58 return 0;
61 dprintf("fdt tree:\n");
63 int node = -1;
64 int depth = 0;
65 while ((node = fdt_next_node(gFDT, node, &depth)) >= 0) {
66 dprintf(DS"node at %d: '%s'\n", DA, node,
67 fdt_get_name(gFDT, node, NULL));
69 if (dump_props) {
70 int prop, len;
71 const struct fdt_property *property;
72 prop = fdt_first_property_offset(gFDT, node);
73 while (prop >= 0) {
74 property = fdt_get_property_by_offset(gFDT, prop, &len);
75 if (property == NULL) {
76 dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len));
77 break;
79 dprintf(DS" prop at %d: '%s', len %d\n", DA, prop,
80 fdt_string(gFDT, fdt32_to_cpu(property->nameoff)),
81 fdt32_to_cpu(property->len));
83 if (dump_values)
84 fdt_dump_value(property->data, fdt32_to_cpu(property->len), depth);
86 prop = fdt_next_property_offset(gFDT, prop);
91 return 0;
95 static int32
96 bus_std_ops(int32 op, ...)
98 switch (op) {
99 case B_MODULE_INIT:
100 if (gFDT == NULL || fdt_totalsize(gFDT) <= 0)
101 return B_BAD_DATA;
103 add_debugger_command("fdt", &fdt_debug_tree, "Show Flattened Device Tree");
104 break;
106 case B_MODULE_UNINIT:
107 // Nothing to free, gFDT allocation is managed by kernel
108 break;
110 default:
111 return EINVAL;
114 return B_OK;
117 static int
118 fdt_get_interrupt(fdt_device_node node, int index)
120 const struct fdt_property *prop;
121 int lenp;
123 prop = fdt_get_property(gFDT, node, "interrupts", &lenp);
124 if (prop == NULL)
125 return B_NAME_NOT_FOUND;
127 int numRanges = lenp / sizeof(uint32);
128 if (index > numRanges)
129 return B_BAD_INDEX;
131 return fdt32_to_cpu(((uint32*)prop->data)[index]);
134 static area_id
135 fdt_map_reg_range(fdt_device_node node, int index, void **_address)
137 char name[B_OS_NAME_LENGTH] = "ingo_asked_me_to_name_this";
138 const struct fdt_property *prop;
139 int lenp;
141 prop = fdt_get_property(gFDT, node, "reg", &lenp);
142 if (prop == NULL)
143 return B_NAME_NOT_FOUND;
145 int numRanges = lenp / (sizeof(uint32) * 2);
146 if (index > numRanges)
147 return B_BAD_INDEX;
149 //snprintf(name, sizeof(name), "%s_reg_%d", fdt_get_name(gFDT, node, NULL), index);
151 uint32* regs = (uint32*)prop->data;
152 phys_addr_t rangeStart = (phys_addr_t)fdt32_to_cpu(regs[index*2]);
153 uint32 rangeSize = fdt32_to_cpu(regs[index*2+1]);
154 dprintf("fdt_map_reg_range: found reg range %p/%lu\n", (void*)rangeStart, rangeSize);
156 return map_physical_memory(name, rangeStart, rangeSize,
157 0, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)_address);
160 static struct fdt_module_info sModuleInfo = {
161 // First the bus_manager_info:
164 "bus_managers/fdt/v1",
165 B_KEEP_LOADED, // Keep loaded, even if no driver requires it
166 bus_std_ops
168 NULL // the rescan function
171 fdt_setup_devices,
172 fdt_map_reg_range,
173 fdt_get_interrupt,
177 module_info *modules[] = {
178 (module_info *)&sModuleInfo,
179 NULL
182 static status_t
183 fdt_setup_devices(struct fdt_device_info *info, int count, void *cookie)
185 int numDevs = 0;
187 if (gFDT == NULL)
188 return B_NOT_INITIALIZED;
190 int node = -1;
191 int depth = 0;
192 while ((node = fdt_next_node(gFDT, node, &depth)) >= 0) {
193 for (int i=0; i < count; i++) {
194 if (fdt_node_check_compatible(gFDT, node, info[i].compatible) == 0) {
195 status_t result = info[i].init(&sModuleInfo, node, cookie);
196 if (result != B_OK) {
197 // TODO handle return value from init somehow?
198 dprintf("fdt: device '%s' failed to initialize!\n",
199 fdt_get_name(gFDT, node, NULL));
200 } else {
201 ++numDevs;
207 return (numDevs <= 0) ? B_ENTRY_NOT_FOUND : B_OK;