The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ofw/ofw_fdt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2009-2010 The FreeBSD Foundation
    3  * All rights reserved.
    4  *
    5  * This software was developed by Semihalf under sponsorship from
    6  * the FreeBSD Foundation.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/9.0/sys/dev/ofw/ofw_fdt.c 215120 2010-11-11 13:42:46Z raj $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/systm.h>
   37 
   38 #include <contrib/libfdt/libfdt.h>
   39 
   40 #include <machine/stdarg.h>
   41 
   42 #include <dev/fdt/fdt_common.h>
   43 #include <dev/ofw/ofwvar.h>
   44 #include <dev/ofw/openfirm.h>
   45 
   46 #include "ofw_if.h"
   47 
   48 #ifdef DEBUG
   49 #define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
   50     printf(fmt,##args); } while (0)
   51 #else
   52 #define debugf(fmt, args...)
   53 #endif
   54 
   55 static int ofw_fdt_init(ofw_t, void *);
   56 static phandle_t ofw_fdt_peer(ofw_t, phandle_t);
   57 static phandle_t ofw_fdt_child(ofw_t, phandle_t);
   58 static phandle_t ofw_fdt_parent(ofw_t, phandle_t);
   59 static phandle_t ofw_fdt_instance_to_package(ofw_t, ihandle_t);
   60 static ssize_t ofw_fdt_getproplen(ofw_t, phandle_t, const char *);
   61 static ssize_t ofw_fdt_getprop(ofw_t, phandle_t, const char *, void *, size_t);
   62 static int ofw_fdt_nextprop(ofw_t, phandle_t, const char *, char *, size_t);
   63 static int ofw_fdt_setprop(ofw_t, phandle_t, const char *, const void *,
   64     size_t);
   65 static ssize_t ofw_fdt_canon(ofw_t, const char *, char *, size_t);
   66 static phandle_t ofw_fdt_finddevice(ofw_t, const char *);
   67 static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t);
   68 static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t);
   69 static int ofw_fdt_interpret(ofw_t, const char *, int, cell_t *);
   70 
   71 static ofw_method_t ofw_fdt_methods[] = {
   72         OFWMETHOD(ofw_init,                     ofw_fdt_init),
   73         OFWMETHOD(ofw_peer,                     ofw_fdt_peer),
   74         OFWMETHOD(ofw_child,                    ofw_fdt_child),
   75         OFWMETHOD(ofw_parent,                   ofw_fdt_parent),
   76         OFWMETHOD(ofw_instance_to_package,      ofw_fdt_instance_to_package),
   77         OFWMETHOD(ofw_getproplen,               ofw_fdt_getproplen),
   78         OFWMETHOD(ofw_getprop,                  ofw_fdt_getprop),
   79         OFWMETHOD(ofw_nextprop,                 ofw_fdt_nextprop),
   80         OFWMETHOD(ofw_setprop,                  ofw_fdt_setprop),
   81         OFWMETHOD(ofw_canon,                    ofw_fdt_canon),
   82         OFWMETHOD(ofw_finddevice,               ofw_fdt_finddevice),
   83         OFWMETHOD(ofw_instance_to_path,         ofw_fdt_instance_to_path),
   84         OFWMETHOD(ofw_package_to_path,          ofw_fdt_package_to_path),
   85         OFWMETHOD(ofw_interpret,                ofw_fdt_interpret),
   86         { 0, 0 }
   87 };
   88 
   89 static ofw_def_t ofw_fdt = {
   90         OFW_FDT,
   91         ofw_fdt_methods,
   92         0
   93 };
   94 OFW_DEF(ofw_fdt);
   95 
   96 static void *fdtp = NULL;
   97 
   98 static int
   99 ofw_fdt_init(ofw_t ofw, void *data)
  100 {
  101         int err;
  102 
  103         /* Check FDT blob integrity */
  104         if ((err = fdt_check_header(data)) != 0)
  105                 return (err);
  106 
  107         fdtp = data;
  108         return (0);
  109 }
  110 
  111 /*
  112  * Device tree functions
  113  */
  114 
  115 static int
  116 fdt_phandle_offset(phandle_t p)
  117 {
  118         const char *dt_struct;
  119         int offset;
  120 
  121         dt_struct = (const char *)fdtp + fdt_off_dt_struct(fdtp);
  122 
  123         if (((const char *)p < dt_struct) ||
  124             (const char *)p > (dt_struct + fdt_size_dt_struct(fdtp)))
  125                 return (-1);
  126 
  127         offset = (const char *)p - dt_struct;
  128         if (offset < 0)
  129                 return (-1);
  130 
  131         return (offset);
  132 }
  133 
  134 /* Return the next sibling of this node or 0. */
  135 static phandle_t
  136 ofw_fdt_peer(ofw_t ofw, phandle_t node)
  137 {
  138         phandle_t p;
  139         int depth, offset;
  140 
  141         if (node == 0) {
  142                 /* Find root node */
  143                 offset = fdt_path_offset(fdtp, "/");
  144                 p = (phandle_t)fdt_offset_ptr(fdtp, offset, sizeof(p));
  145 
  146                 return (p);
  147         }
  148 
  149         offset = fdt_phandle_offset(node);
  150         if (offset < 0)
  151                 return (0);
  152 
  153         for (depth = 1, offset = fdt_next_node(fdtp, offset, &depth);
  154             offset >= 0;
  155             offset = fdt_next_node(fdtp, offset, &depth)) {
  156                 if (depth < 0)
  157                         return (0);
  158                 if (depth == 1) {
  159                         p = (phandle_t)fdt_offset_ptr(fdtp, offset, sizeof(p));
  160                         return (p);
  161                 }
  162         }
  163 
  164         return (0);
  165 }
  166 
  167 /* Return the first child of this node or 0. */
  168 static phandle_t
  169 ofw_fdt_child(ofw_t ofw, phandle_t node)
  170 {
  171         phandle_t p;
  172         int depth, offset;
  173 
  174         offset = fdt_phandle_offset(node);
  175         if (offset < 0)
  176                 return (0);
  177 
  178         for (depth = 0, offset = fdt_next_node(fdtp, offset, &depth);
  179             (offset >= 0) && (depth > 0);
  180             offset = fdt_next_node(fdtp, offset, &depth)) {
  181                 if (depth < 0)
  182                         return (0);
  183                 if (depth == 1) {
  184                         p = (phandle_t)fdt_offset_ptr(fdtp, offset, sizeof(p));
  185                         return (p);
  186                 }
  187         }
  188 
  189         return (0);
  190 }
  191 
  192 /* Return the parent of this node or 0. */
  193 static phandle_t
  194 ofw_fdt_parent(ofw_t ofw, phandle_t node)
  195 {
  196         phandle_t p;
  197         int offset, paroffset;
  198 
  199         offset = fdt_phandle_offset(node);
  200         if (offset < 0)
  201                 return (0);
  202 
  203         paroffset = fdt_parent_offset(fdtp, offset);
  204         p = (phandle_t)fdt_offset_ptr(fdtp, paroffset, sizeof(phandle_t));
  205         return (p);
  206 }
  207 
  208 /* Return the package handle that corresponds to an instance handle. */
  209 static phandle_t
  210 ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance)
  211 {
  212         phandle_t p;
  213         int offset;
  214 
  215         /*
  216          * Note: FDT does not have the notion of instances, but we somewhat
  217          * abuse the semantics and let treat as 'instance' the internal
  218          * 'phandle' prop, so that ofw I/F consumers have a uniform way of
  219          * translation between internal representation (which appear in some
  220          * contexts as property values) and effective phandles.
  221          */
  222         offset = fdt_node_offset_by_phandle(fdtp, instance);
  223         if (offset < 0)
  224                 return (-1);
  225 
  226         p = (phandle_t)fdt_offset_ptr(fdtp, offset, sizeof(phandle_t));
  227         return (p);
  228 }
  229 
  230 /* Get the length of a property of a package. */
  231 static ssize_t
  232 ofw_fdt_getproplen(ofw_t ofw, phandle_t package, const char *propname)
  233 {
  234         const struct fdt_property *prop;
  235         int offset, len;
  236 
  237         offset = fdt_phandle_offset(package);
  238         if (offset < 0)
  239                 return (-1);
  240 
  241         if (strcmp(propname, "name") == 0) {
  242                 /* Emulate the 'name' property */
  243                 fdt_get_name(fdtp, offset, &len);
  244                 return (len + 1);
  245         }
  246 
  247         len = -1;
  248         prop = fdt_get_property(fdtp, offset, propname, &len);
  249 
  250         return (len);
  251 }
  252 
  253 /* Get the value of a property of a package. */
  254 static ssize_t
  255 ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
  256     size_t buflen)
  257 {
  258         const void *prop;
  259         const char *name;
  260         int len, offset;
  261 
  262         offset = fdt_phandle_offset(package);
  263         if (offset < 0)
  264                 return (-1);
  265 
  266         if (strcmp(propname, "name") == 0) {
  267                 /* Emulate the 'name' property */
  268                 name = fdt_get_name(fdtp, offset, &len);
  269                 strncpy(buf, name, buflen);
  270                 if (len + 1 > buflen)
  271                         len = buflen;
  272                 return (len + 1);
  273         }
  274 
  275         prop = fdt_getprop(fdtp, offset, propname, &len);
  276         if (prop == NULL)
  277                 return (-1);
  278 
  279         if (len > buflen)
  280                 len = buflen;
  281         bcopy(prop, buf, len);
  282         return (len);
  283 }
  284 
  285 static int
  286 fdt_nextprop(int offset, char *buf, size_t size)
  287 {
  288         const struct fdt_property *prop;
  289         const char *name;
  290         uint32_t tag;
  291         int nextoffset, depth;
  292 
  293         depth = 0;
  294         tag = fdt_next_tag(fdtp, offset, &nextoffset);
  295 
  296         /* Find the next prop */
  297         do {
  298                 offset = nextoffset;
  299                 tag = fdt_next_tag(fdtp, offset, &nextoffset);
  300 
  301                 if (tag == FDT_BEGIN_NODE)
  302                         depth++;
  303                 else if (tag == FDT_END_NODE)
  304                         depth--;
  305                 else if ((tag == FDT_PROP) && (depth == 0)) {
  306                         prop =
  307                             (const struct fdt_property *)fdt_offset_ptr(fdtp,
  308                             offset, sizeof(*prop));
  309                         name = fdt_string(fdtp,
  310                             fdt32_to_cpu(prop->nameoff));
  311                         strncpy(buf, name, size);
  312                         return (strlen(name));
  313                 } else
  314                         depth = -1;
  315         } while (depth >= 0);
  316 
  317         return (-1);
  318 }
  319 
  320 /*
  321  * Get the next property of a package. Return the actual len of retrieved
  322  * prop name.
  323  */
  324 static int
  325 ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf,
  326     size_t size)
  327 {
  328         const struct fdt_property *prop;
  329         int offset, rv;
  330 
  331         offset = fdt_phandle_offset(package);
  332         if (offset < 0)
  333                 return (-1);
  334 
  335         if (previous == NULL)
  336                 /* Find the first prop in the node */
  337                 return (fdt_nextprop(offset, buf, size));
  338 
  339         /*
  340          * Advance to the previous prop
  341          */
  342         prop = fdt_get_property(fdtp, offset, previous, NULL);
  343         if (prop == NULL)
  344                 return (-1);
  345 
  346         offset = fdt_phandle_offset((phandle_t)prop);
  347         rv = fdt_nextprop(offset, buf, size);
  348         return (rv);
  349 }
  350 
  351 /* Set the value of a property of a package. */
  352 static int
  353 ofw_fdt_setprop(ofw_t ofw, phandle_t package, const char *propname,
  354     const void *buf, size_t len)
  355 {
  356         int offset;
  357 
  358         offset = fdt_phandle_offset(package);
  359         if (offset < 0)
  360                 return (-1);
  361 
  362         return (fdt_setprop_inplace(fdtp, offset, propname, buf, len));
  363 }
  364 
  365 /* Convert a device specifier to a fully qualified pathname. */
  366 static ssize_t
  367 ofw_fdt_canon(ofw_t ofw, const char *device, char *buf, size_t len)
  368 {
  369 
  370         return (-1);
  371 }
  372 
  373 /* Return a package handle for the specified device. */
  374 static phandle_t
  375 ofw_fdt_finddevice(ofw_t ofw, const char *device)
  376 {
  377         phandle_t p;
  378         int offset;
  379 
  380         offset = fdt_path_offset(fdtp, device);
  381 
  382         p = (phandle_t)fdt_offset_ptr(fdtp, offset, sizeof(p));
  383 
  384         return (p);
  385 }
  386 
  387 /* Return the fully qualified pathname corresponding to an instance. */
  388 static ssize_t
  389 ofw_fdt_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
  390 {
  391 
  392         return (-1);
  393 }
  394 
  395 /* Return the fully qualified pathname corresponding to a package. */
  396 static ssize_t
  397 ofw_fdt_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
  398 {
  399 
  400         return (-1);
  401 }
  402 
  403 static int
  404 ofw_fdt_fixup(ofw_t ofw)
  405 {
  406 #define FDT_MODEL_LEN   80
  407         char model[FDT_MODEL_LEN];
  408         phandle_t root;
  409         ssize_t len;
  410         int i;
  411 
  412         if ((root = ofw_fdt_finddevice(ofw, "/")) == 0)
  413                 return (ENODEV);
  414 
  415         if ((len = ofw_fdt_getproplen(ofw, root, "model")) <= 0)
  416                 return (0);
  417 
  418         bzero(model, FDT_MODEL_LEN);
  419         if (ofw_fdt_getprop(ofw, root, "model", model, FDT_MODEL_LEN) <= 0)
  420                 return (0);
  421 
  422         /*
  423          * Search fixup table and call handler if appropriate.
  424          */
  425         for (i = 0; fdt_fixup_table[i].model != NULL; i++) {
  426                 if (strncmp(model, fdt_fixup_table[i].model,
  427                     FDT_MODEL_LEN) != 0)
  428                         continue;
  429 
  430                 if (fdt_fixup_table[i].handler != NULL)
  431                         (*fdt_fixup_table[i].handler)(root);
  432         }
  433 
  434         return (0);
  435 }
  436 
  437 static int
  438 ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, cell_t *retvals)
  439 {
  440         int rv;
  441 
  442         /*
  443          * Note: FDT does not have the possibility to 'interpret' commands,
  444          * but we abuse the interface a bit to use it for doing non-standard
  445          * operations on the device tree blob.
  446          *
  447          * Currently the only supported 'command' is to trigger performing
  448          * fixups.
  449          */
  450         if (strncmp("perform-fixup", cmd, 13) != 0)
  451                 return (0);
  452 
  453         rv = ofw_fdt_fixup(ofw);
  454         if (nret > 0)
  455                 retvals[0] = rv;
  456 
  457         return (rv);
  458 }

Cache object: d02ee6de1681d127070b251aea5369d0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.