diff options
Diffstat (limited to 'arch/sparc/kernel/prom.c')
-rw-r--r-- | arch/sparc/kernel/prom.c | 106 |
1 files changed, 88 insertions, 18 deletions
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 63b2b9bd778e..946ce6d15819 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c | |||
@@ -27,6 +27,11 @@ | |||
27 | 27 | ||
28 | static struct device_node *allnodes; | 28 | static struct device_node *allnodes; |
29 | 29 | ||
30 | /* use when traversing tree through the allnext, child, sibling, | ||
31 | * or parent members of struct device_node. | ||
32 | */ | ||
33 | static DEFINE_RWLOCK(devtree_lock); | ||
34 | |||
30 | int of_device_is_compatible(struct device_node *device, const char *compat) | 35 | int of_device_is_compatible(struct device_node *device, const char *compat) |
31 | { | 36 | { |
32 | const char* cp; | 37 | const char* cp; |
@@ -185,6 +190,54 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) | |||
185 | } | 190 | } |
186 | EXPORT_SYMBOL(of_getintprop_default); | 191 | EXPORT_SYMBOL(of_getintprop_default); |
187 | 192 | ||
193 | int of_set_property(struct device_node *dp, const char *name, void *val, int len) | ||
194 | { | ||
195 | struct property **prevp; | ||
196 | void *new_val; | ||
197 | int err; | ||
198 | |||
199 | new_val = kmalloc(len, GFP_KERNEL); | ||
200 | if (!new_val) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | memcpy(new_val, val, len); | ||
204 | |||
205 | err = -ENODEV; | ||
206 | |||
207 | write_lock(&devtree_lock); | ||
208 | prevp = &dp->properties; | ||
209 | while (*prevp) { | ||
210 | struct property *prop = *prevp; | ||
211 | |||
212 | if (!strcmp(prop->name, name)) { | ||
213 | void *old_val = prop->value; | ||
214 | int ret; | ||
215 | |||
216 | ret = prom_setprop(dp->node, name, val, len); | ||
217 | err = -EINVAL; | ||
218 | if (ret >= 0) { | ||
219 | prop->value = new_val; | ||
220 | prop->length = len; | ||
221 | |||
222 | if (OF_IS_DYNAMIC(prop)) | ||
223 | kfree(old_val); | ||
224 | |||
225 | OF_MARK_DYNAMIC(prop); | ||
226 | |||
227 | err = 0; | ||
228 | } | ||
229 | break; | ||
230 | } | ||
231 | prevp = &(*prevp)->next; | ||
232 | } | ||
233 | write_unlock(&devtree_lock); | ||
234 | |||
235 | /* XXX Upate procfs if necessary... */ | ||
236 | |||
237 | return err; | ||
238 | } | ||
239 | EXPORT_SYMBOL(of_set_property); | ||
240 | |||
188 | static unsigned int prom_early_allocated; | 241 | static unsigned int prom_early_allocated; |
189 | 242 | ||
190 | static void * __init prom_early_alloc(unsigned long size) | 243 | static void * __init prom_early_alloc(unsigned long size) |
@@ -354,7 +407,9 @@ static char * __init build_full_name(struct device_node *dp) | |||
354 | return n; | 407 | return n; |
355 | } | 408 | } |
356 | 409 | ||
357 | static struct property * __init build_one_prop(phandle node, char *prev) | 410 | static unsigned int unique_id; |
411 | |||
412 | static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) | ||
358 | { | 413 | { |
359 | static struct property *tmp = NULL; | 414 | static struct property *tmp = NULL; |
360 | struct property *p; | 415 | struct property *p; |
@@ -364,25 +419,34 @@ static struct property * __init build_one_prop(phandle node, char *prev) | |||
364 | p = tmp; | 419 | p = tmp; |
365 | memset(p, 0, sizeof(*p) + 32); | 420 | memset(p, 0, sizeof(*p) + 32); |
366 | tmp = NULL; | 421 | tmp = NULL; |
367 | } else | 422 | } else { |
368 | p = prom_early_alloc(sizeof(struct property) + 32); | 423 | p = prom_early_alloc(sizeof(struct property) + 32); |
424 | p->unique_id = unique_id++; | ||
425 | } | ||
369 | 426 | ||
370 | p->name = (char *) (p + 1); | 427 | p->name = (char *) (p + 1); |
371 | if (prev == NULL) { | 428 | if (special_name) { |
372 | prom_firstprop(node, p->name); | 429 | p->length = special_len; |
430 | p->value = prom_early_alloc(special_len); | ||
431 | memcpy(p->value, special_val, special_len); | ||
373 | } else { | 432 | } else { |
374 | prom_nextprop(node, prev, p->name); | 433 | if (prev == NULL) { |
375 | } | 434 | prom_firstprop(node, p->name); |
376 | if (strlen(p->name) == 0) { | 435 | } else { |
377 | tmp = p; | 436 | prom_nextprop(node, prev, p->name); |
378 | return NULL; | 437 | } |
379 | } | 438 | if (strlen(p->name) == 0) { |
380 | p->length = prom_getproplen(node, p->name); | 439 | tmp = p; |
381 | if (p->length <= 0) { | 440 | return NULL; |
382 | p->length = 0; | 441 | } |
383 | } else { | 442 | p->length = prom_getproplen(node, p->name); |
384 | p->value = prom_early_alloc(p->length); | 443 | if (p->length <= 0) { |
385 | len = prom_getproperty(node, p->name, p->value, p->length); | 444 | p->length = 0; |
445 | } else { | ||
446 | p->value = prom_early_alloc(p->length + 1); | ||
447 | prom_getproperty(node, p->name, p->value, p->length); | ||
448 | ((unsigned char *)p->value)[p->length] = '\0'; | ||
449 | } | ||
386 | } | 450 | } |
387 | return p; | 451 | return p; |
388 | } | 452 | } |
@@ -391,9 +455,14 @@ static struct property * __init build_prop_list(phandle node) | |||
391 | { | 455 | { |
392 | struct property *head, *tail; | 456 | struct property *head, *tail; |
393 | 457 | ||
394 | head = tail = build_one_prop(node, NULL); | 458 | head = tail = build_one_prop(node, NULL, |
459 | ".node", &node, sizeof(node)); | ||
460 | |||
461 | tail->next = build_one_prop(node, NULL, NULL, NULL, 0); | ||
462 | tail = tail->next; | ||
395 | while(tail) { | 463 | while(tail) { |
396 | tail->next = build_one_prop(node, tail->name); | 464 | tail->next = build_one_prop(node, tail->name, |
465 | NULL, NULL, 0); | ||
397 | tail = tail->next; | 466 | tail = tail->next; |
398 | } | 467 | } |
399 | 468 | ||
@@ -422,6 +491,7 @@ static struct device_node * __init create_node(phandle node) | |||
422 | return NULL; | 491 | return NULL; |
423 | 492 | ||
424 | dp = prom_early_alloc(sizeof(*dp)); | 493 | dp = prom_early_alloc(sizeof(*dp)); |
494 | dp->unique_id = unique_id++; | ||
425 | 495 | ||
426 | kref_init(&dp->kref); | 496 | kref_init(&dp->kref); |
427 | 497 | ||