Lynx framebuffers multidomain implementation.
[linux/elbrus.git] / drivers / mcst / prom / sbus_proc_tree.c
blob0dd58a32aa3ecb7d81cdbb9f10b6f28d8b1eca6b
1 #include <linux/kernel.h>
2 #include <linux/mm.h>
3 #include <linux/proc_fs.h>
4 #include <asm-l/tree_entry.h>
5 #include <asm/sbus.h>
7 #include "sbus_proc_tree.h"
9 static struct proc_dir_entry *sbus_ent = NULL;
11 typedef knode_t node_t;
13 node_t *create_node(void)
15 node_t *new_node = kmalloc(sizeof(node_t), GFP_KERNEL);
16 if (new_node == NULL)
17 return NULL;
18 new_node->depth = 0;
19 new_node->child = NULL;
20 new_node->type = NO_TYPE;
21 new_node->next = NULL;
23 return new_node;
26 void add_child(node_t *parent, node_t *node)
28 node->parent = parent;
29 node->depth = parent->depth + 1;
30 node->next = NULL;
31 if (parent->child) {
32 node_t *sibling = parent->child;
33 while (sibling->next)
34 sibling = sibling->next;
35 sibling->next = node;
36 } else {
37 parent->child = node;
41 int build_sub_tree(node_t *parent, int prom_node, int depth, int type)
43 int len;
44 node_t *node;
45 char node_str[128];
47 while (prom_node != 0 && prom_node != -1) {
48 if ((node = create_node()) == NULL) {
49 pr_err("MCT_TREE:build_sub_tree:"
50 " Error memory allocation\n");
51 return -1;
54 len = (int)prom_getproperty(prom_node, "name",
55 node->name, sizeof(node->name));
56 prom_getstring(prom_node, "device_type",
57 node_str, sizeof(node_str));
59 if (!strcmp(node_str, "cpu") ||
60 !strcmp(node->name, "memory") ||
61 !strcmp(node->name, "pcin")) {
62 kfree(node);
63 goto next_dev;
66 if (depth == 0)
67 type = NO_TYPE;
68 node->type = type;
70 if (strcmp(node->name, "sbus") == 0) {
71 node->type = BUS;
72 type = SBUS;
75 len = prom_getproperty(prom_node, "reg",
76 (char *) node->reg_addrs,
77 sizeof(node->reg_addrs));
78 if (len == -1) {
79 node->num_registers = 0;
80 goto no_regs;
83 if (len % sizeof(struct linux_prom_registers)) {
84 pr_err("fill_sbus_device: proplen for regs of %s "
85 " was %d, need multiple of %d\n",
86 node->name, len,
87 (int) sizeof(struct linux_prom_registers));
88 return -1;
90 if (len > (sizeof(struct linux_prom_registers)*PROMREG_MAX)) {
91 pr_err("fill_sbus_device: Too many register properties"
92 " for device %s, len=%d\n",
93 node->name, len);
94 return -1;
96 node->num_registers = len/sizeof(struct linux_prom_registers);
97 node->ranges_applied = 0;
99 /* Compute the slot number. */
100 node->slot = prom_getint(prom_node, "slot");
101 if (node->slot == -1)
102 node->slot = node->reg_addrs[0].which_io;
103 no_regs:
104 len = prom_getproperty(prom_node, "ranges",
105 (char *)node->device_ranges,
106 sizeof(node->device_ranges));
107 if (len == -1) {
108 node->num_device_ranges = 0;
109 goto no_ranges;
111 if (len % sizeof(struct linux_prom_ranges)) {
112 pr_err("fill_sbus_device: proplen for ranges of %s "
113 " was %d, need multiple of %d\n",
114 node->name, len,
115 (int) sizeof(struct linux_prom_ranges));
116 return -1;
118 if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {
119 pr_err("fill_sbus_device: Too many range properties "
120 "for device %s, len=%d\n",
121 node->name, len);
122 return -1;
124 node->num_device_ranges = len/sizeof(struct linux_prom_ranges);
125 no_ranges:
126 add_child(parent, node);
127 next_dev:
128 if (prom_getchild(prom_node)) {
129 build_sub_tree(node, prom_getchild(prom_node),
130 depth+1, type);
133 prom_node = prom_getsibling(prom_node);
135 return 0;
138 int print_nodes(node_t *node, char *buf, int len)
140 do {
141 int i;
143 if (!strcmp(node->name, ".")) {
144 if (node->child) {
145 len = print_nodes(node->child, buf, len);
147 node = node->next;
148 continue;
151 for (i = 0; i < node->depth; i++) {
152 len += sprintf(buf+len, " ");
153 buf[len] = 0;
156 switch (node->type) {
157 case SBUS:
158 len += sprintf(buf+len, "%s@0x%08x Slot %x\n",
159 node->name,
160 node->reg_addrs[0].phys_addr,
161 node->slot);
162 break;
163 default:
164 len += sprintf(buf+len, "%s\n", node->name);
165 break;
168 buf[len] = 0;
169 if (node->child) {
170 len = print_nodes(node->child, buf, len);
172 node = node->next;
173 buf[len] = 0;
174 } while (node);
176 return len;
179 int proc_sbus_entry(char *buf, char **start,
180 off_t off, int count,
181 int *eof, void *data) {
182 int len = 0;
183 node_t *root = (node_t *)data;
185 len = print_nodes(root->child, buf, len);
186 buf[len] = 0;
188 return len;
191 void make_sbus_tree(void)
193 int root_node;
194 node_t *tree_root;
195 char proc_bus_path[128] = "bus/sbus";
197 if ((tree_root = create_node()) == NULL) {
198 pr_err("MCT_TREE:do_build_tree: Error memory allocation\n");
199 return;
201 tree_root->depth = 0;
202 tree_root->slot = -1;
204 root_node = prom_getchild(prom_root_node);
205 build_sub_tree(tree_root, root_node, 0, NO_TYPE);
207 if ((sbus_ent = proc_mkdir(proc_bus_path, NULL)) == NULL)
208 return;
210 create_proc_read_entry("devices",
212 sbus_ent,
213 proc_sbus_entry,
214 tree_root);
217 static int __init tree_init(void)
219 make_sbus_tree();
221 return 0;
224 static void __exit tree_destroy(void)
226 if (!sbus_ent) {
227 remove_proc_entry("devices", sbus_ent);
231 subsys_initcall(tree_init);
232 module_exit(tree_destroy);
233 MODULE_LICENSE("GPL");