[SPARC]: Fix serial console device detection.
[pandora-kernel.git] / arch / sparc / kernel / prom.c
index 4b06dcb..e3a5376 100644 (file)
 #include <asm/prom.h>
 #include <asm/oplib.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(struct device_node *device, const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = (char *) of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       np = node->parent;
-
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling) {
-               break;
-       }
-
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -104,79 +41,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcmp(np->name, name) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcmp(np->type, type) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible))
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(struct device_node *np, const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       }
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -190,36 +54,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -239,11 +73,11 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
        while (*prevp) {
                struct property *prop = *prevp;
 
-               if (!strcmp(prop->name, name)) {
+               if (!strcasecmp(prop->name, name)) {
                        void *old_val = prop->value;
                        int ret;
 
-                       ret = prom_setprop(dp->node, name, val, len);
+                       ret = prom_setprop(dp->node, (char *) name, val, len);
                        err = -EINVAL;
                        if (ret >= 0) {
                                prop->value = new_val;
@@ -444,6 +278,7 @@ static struct property * __init build_one_prop(phandle node, char *prev, char *s
        static struct property *tmp = NULL;
        struct property *p;
        int len;
+       const char *name;
 
        if (tmp) {
                p = tmp;
@@ -456,25 +291,30 @@ static struct property * __init build_one_prop(phandle node, char *prev, char *s
 
        p->name = (char *) (p + 1);
        if (special_name) {
+               strcpy(p->name, special_name);
                p->length = special_len;
                p->value = prom_early_alloc(special_len);
                memcpy(p->value, special_val, special_len);
        } else {
                if (prev == NULL) {
-                       prom_firstprop(node, p->name);
+                       name = prom_firstprop(node, NULL);
                } else {
-                       prom_nextprop(node, prev, p->name);
+                       name = prom_nextprop(node, prev, NULL);
                }
-               if (strlen(p->name) == 0) {
+               if (strlen(name) == 0) {
                        tmp = p;
                        return NULL;
                }
+               strcpy(p->name, name);
                p->length = prom_getproplen(node, p->name);
                if (p->length <= 0) {
                        p->length = 0;
                } else {
                        p->value = prom_early_alloc(p->length + 1);
-                       prom_getproperty(node, p->name, p->value, p->length);
+                       len = prom_getproperty(node, p->name, p->value,
+                                              p->length);
+                       if (len <= 0)
+                               p->length = 0;
                        ((unsigned char *)p->value)[p->length] = '\0';
                }
        }
@@ -557,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
        return dp;
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       unsigned long flags;
+       const char *type;
+       phandle node;
+       int skip, fd;
+
+       of_console_path = prom_early_alloc(256);
+
+       switch (prom_vers) {
+       case PROM_V0:
+       case PROM_SUN4:
+               skip = 0;
+               switch (*romvec->pv_stdout) {
+               case PROMDEV_SCREEN:
+                       type = "display";
+                       break;
+
+               case PROMDEV_TTYB:
+                       skip = 1;
+                       /* FALLTHRU */
+
+               case PROMDEV_TTYA:
+                       type = "serial";
+                       break;
+
+               default:
+                       prom_printf("Invalid PROM_V0 stdout value %u\n",
+                                   *romvec->pv_stdout);
+                       prom_halt();
+               }
+
+               for_each_node_by_type(dp, type) {
+                       if (!skip--)
+                               break;
+               }
+               if (!dp) {
+                       prom_printf("Cannot find PROM_V0 console node.\n");
+                       prom_halt();
+               }
+               of_console_device = dp;
+
+               strcpy(of_console_path, dp->full_name);
+               if (!strcmp(type, "serial")) {
+                       strcat(of_console_path,
+                              (skip ? ":b" : ":a"));
+               }
+               break;
+
+       default:
+       case PROM_V2:
+       case PROM_V3:
+               fd = *romvec->pv_v2bootargs.fd_stdout;
+
+               spin_lock_irqsave(&prom_lock, flags);
+               node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+               restore_current();
+               spin_unlock_irqrestore(&prom_lock, flags);
+
+               if (!node) {
+                       prom_printf("Cannot resolve stdout node from "
+                                   "instance %08x.\n", fd);
+                       prom_halt();
+               }
+               dp = of_find_node_by_phandle(node);
+               type = of_get_property(dp, "device_type", NULL);
+
+               if (!type) {
+                       prom_printf("Console stdout lacks "
+                                   "device_type property.\n");
+                       prom_halt();
+               }
+
+               if (strcmp(type, "display") && strcmp(type, "serial")) {
+                       prom_printf("Console device_type is neither display "
+                                   "nor serial.\n");
+                       prom_halt();
+               }
+
+               of_console_device = dp;
+
+               if (prom_vers == PROM_V2) {
+                       strcpy(of_console_path, dp->full_name);
+                       switch (*romvec->pv_stdout) {
+                       case PROMDEV_TTYA:
+                               strcat(of_console_path, ":a");
+                               break;
+                       case PROMDEV_TTYB:
+                               strcat(of_console_path, ":b");
+                               break;
+                       }
+               } else {
+                       const char *path;
+
+                       dp = of_find_node_by_path("/");
+                       path = of_get_property(dp, "stdout-path", NULL);
+                       if (!path) {
+                               prom_printf("No stdout-path in root node.\n");
+                               prom_halt();
+                       }
+                       strcpy(of_console_path, path);
+               }
+               break;
+       }
+
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
@@ -569,6 +538,8 @@ void __init prom_build_devicetree(void)
        allnodes->child = build_tree(allnodes,
                                     prom_getchild(allnodes->node),
                                     &nextp);
+       of_console_init();
+
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
 }