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/contrib/libfdt/fdt_ro.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  * libfdt - Flat Device Tree manipulation
    3  * Copyright (C) 2006 David Gibson, IBM Corporation.
    4  *
    5  * libfdt is dual licensed: you can use it either under the terms of
    6  * the GPL, or the BSD license, at your option.
    7  *
    8  *  a) This library is free software; you can redistribute it and/or
    9  *     modify it under the terms of the GNU General Public License as
   10  *     published by the Free Software Foundation; either version 2 of the
   11  *     License, or (at your option) any later version.
   12  *
   13  *     This library is distributed in the hope that it will be useful,
   14  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *     GNU General Public License for more details.
   17  *
   18  *     You should have received a copy of the GNU General Public
   19  *     License along with this library; if not, write to the Free
   20  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   21  *     MA 02110-1301 USA
   22  *
   23  * Alternatively,
   24  *
   25  *  b) Redistribution and use in source and binary forms, with or
   26  *     without modification, are permitted provided that the following
   27  *     conditions are met:
   28  *
   29  *     1. Redistributions of source code must retain the above
   30  *        copyright notice, this list of conditions and the following
   31  *        disclaimer.
   32  *     2. Redistributions in binary form must reproduce the above
   33  *        copyright notice, this list of conditions and the following
   34  *        disclaimer in the documentation and/or other materials
   35  *        provided with the distribution.
   36  *
   37  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
   38  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
   39  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   40  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   41  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   42  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   43  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   44  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   45  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   46  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   47  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   48  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   49  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   50  */
   51 #include "libfdt_env.h"
   52 
   53 #include <fdt.h>
   54 #include <libfdt.h>
   55 
   56 #include "libfdt_internal.h"
   57 
   58 static int fdt_nodename_eq_(const void *fdt, int offset,
   59                             const char *s, int len)
   60 {
   61         int olen;
   62         const char *p = fdt_get_name(fdt, offset, &olen);
   63 
   64         if (!p || olen < len)
   65                 /* short match */
   66                 return 0;
   67 
   68         if (memcmp(p, s, len) != 0)
   69                 return 0;
   70 
   71         if (p[len] == '\0')
   72                 return 1;
   73         else if (!memchr(s, '@', len) && (p[len] == '@'))
   74                 return 1;
   75         else
   76                 return 0;
   77 }
   78 
   79 const char *fdt_string(const void *fdt, int stroffset)
   80 {
   81         return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
   82 }
   83 
   84 static int fdt_string_eq_(const void *fdt, int stroffset,
   85                           const char *s, int len)
   86 {
   87         const char *p = fdt_string(fdt, stroffset);
   88 
   89         return (strlen(p) == len) && (memcmp(p, s, len) == 0);
   90 }
   91 
   92 uint32_t fdt_get_max_phandle(const void *fdt)
   93 {
   94         uint32_t max_phandle = 0;
   95         int offset;
   96 
   97         for (offset = fdt_next_node(fdt, -1, NULL);;
   98              offset = fdt_next_node(fdt, offset, NULL)) {
   99                 uint32_t phandle;
  100 
  101                 if (offset == -FDT_ERR_NOTFOUND)
  102                         return max_phandle;
  103 
  104                 if (offset < 0)
  105                         return (uint32_t)-1;
  106 
  107                 phandle = fdt_get_phandle(fdt, offset);
  108                 if (phandle == (uint32_t)-1)
  109                         continue;
  110 
  111                 if (phandle > max_phandle)
  112                         max_phandle = phandle;
  113         }
  114 
  115         return 0;
  116 }
  117 
  118 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
  119 {
  120         FDT_CHECK_HEADER(fdt);
  121         *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
  122         *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
  123         return 0;
  124 }
  125 
  126 int fdt_num_mem_rsv(const void *fdt)
  127 {
  128         int i = 0;
  129 
  130         while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
  131                 i++;
  132         return i;
  133 }
  134 
  135 static int nextprop_(const void *fdt, int offset)
  136 {
  137         uint32_t tag;
  138         int nextoffset;
  139 
  140         do {
  141                 tag = fdt_next_tag(fdt, offset, &nextoffset);
  142 
  143                 switch (tag) {
  144                 case FDT_END:
  145                         if (nextoffset >= 0)
  146                                 return -FDT_ERR_BADSTRUCTURE;
  147                         else
  148                                 return nextoffset;
  149 
  150                 case FDT_PROP:
  151                         return offset;
  152                 }
  153                 offset = nextoffset;
  154         } while (tag == FDT_NOP);
  155 
  156         return -FDT_ERR_NOTFOUND;
  157 }
  158 
  159 int fdt_subnode_offset_namelen(const void *fdt, int offset,
  160                                const char *name, int namelen)
  161 {
  162         int depth;
  163 
  164         FDT_CHECK_HEADER(fdt);
  165 
  166         for (depth = 0;
  167              (offset >= 0) && (depth >= 0);
  168              offset = fdt_next_node(fdt, offset, &depth))
  169                 if ((depth == 1)
  170                     && fdt_nodename_eq_(fdt, offset, name, namelen))
  171                         return offset;
  172 
  173         if (depth < 0)
  174                 return -FDT_ERR_NOTFOUND;
  175         return offset; /* error */
  176 }
  177 
  178 int fdt_subnode_offset(const void *fdt, int parentoffset,
  179                        const char *name)
  180 {
  181         return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
  182 }
  183 
  184 int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
  185 {
  186         const char *end = path + namelen;
  187         const char *p = path;
  188         int offset = 0;
  189 
  190         FDT_CHECK_HEADER(fdt);
  191 
  192         /* see if we have an alias */
  193         if (*path != '/') {
  194                 const char *q = memchr(path, '/', end - p);
  195 
  196                 if (!q)
  197                         q = end;
  198 
  199                 p = fdt_get_alias_namelen(fdt, p, q - p);
  200                 if (!p)
  201                         return -FDT_ERR_BADPATH;
  202                 offset = fdt_path_offset(fdt, p);
  203 
  204                 p = q;
  205         }
  206 
  207         while (p < end) {
  208                 const char *q;
  209 
  210                 while (*p == '/') {
  211                         p++;
  212                         if (p == end)
  213                                 return offset;
  214                 }
  215                 q = memchr(p, '/', end - p);
  216                 if (! q)
  217                         q = end;
  218 
  219                 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
  220                 if (offset < 0)
  221                         return offset;
  222 
  223                 p = q;
  224         }
  225 
  226         return offset;
  227 }
  228 
  229 int fdt_path_offset(const void *fdt, const char *path)
  230 {
  231         return fdt_path_offset_namelen(fdt, path, strlen(path));
  232 }
  233 
  234 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
  235 {
  236         const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
  237         const char *nameptr;
  238         int err;
  239 
  240         if (((err = fdt_check_header(fdt)) != 0)
  241             || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
  242                         goto fail;
  243 
  244         nameptr = nh->name;
  245 
  246         if (fdt_version(fdt) < 0x10) {
  247                 /*
  248                  * For old FDT versions, match the naming conventions of V16:
  249                  * give only the leaf name (after all /). The actual tree
  250                  * contents are loosely checked.
  251                  */
  252                 const char *leaf;
  253                 leaf = strrchr(nameptr, '/');
  254                 if (leaf == NULL) {
  255                         err = -FDT_ERR_BADSTRUCTURE;
  256                         goto fail;
  257                 }
  258                 nameptr = leaf+1;
  259         }
  260 
  261         if (len)
  262                 *len = strlen(nameptr);
  263 
  264         return nameptr;
  265 
  266  fail:
  267         if (len)
  268                 *len = err;
  269         return NULL;
  270 }
  271 
  272 int fdt_first_property_offset(const void *fdt, int nodeoffset)
  273 {
  274         int offset;
  275 
  276         if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
  277                 return offset;
  278 
  279         return nextprop_(fdt, offset);
  280 }
  281 
  282 int fdt_next_property_offset(const void *fdt, int offset)
  283 {
  284         if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
  285                 return offset;
  286 
  287         return nextprop_(fdt, offset);
  288 }
  289 
  290 static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
  291                                                               int offset,
  292                                                               int *lenp)
  293 {
  294         int err;
  295         const struct fdt_property *prop;
  296 
  297         if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
  298                 if (lenp)
  299                         *lenp = err;
  300                 return NULL;
  301         }
  302 
  303         prop = fdt_offset_ptr_(fdt, offset);
  304 
  305         if (lenp)
  306                 *lenp = fdt32_to_cpu(prop->len);
  307 
  308         return prop;
  309 }
  310 
  311 const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
  312                                                       int offset,
  313                                                       int *lenp)
  314 {
  315         /* Prior to version 16, properties may need realignment
  316          * and this API does not work. fdt_getprop_*() will, however. */
  317 
  318         if (fdt_version(fdt) < 0x10) {
  319                 if (lenp)
  320                         *lenp = -FDT_ERR_BADVERSION;
  321                 return NULL;
  322         }
  323 
  324         return fdt_get_property_by_offset_(fdt, offset, lenp);
  325 }
  326 
  327 static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
  328                                                             int offset,
  329                                                             const char *name,
  330                                                             int namelen,
  331                                                             int *lenp,
  332                                                             int *poffset)
  333 {
  334         for (offset = fdt_first_property_offset(fdt, offset);
  335              (offset >= 0);
  336              (offset = fdt_next_property_offset(fdt, offset))) {
  337                 const struct fdt_property *prop;
  338 
  339                 if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
  340                         offset = -FDT_ERR_INTERNAL;
  341                         break;
  342                 }
  343                 if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
  344                                    name, namelen)) {
  345                         if (poffset)
  346                                 *poffset = offset;
  347                         return prop;
  348                 }
  349         }
  350 
  351         if (lenp)
  352                 *lenp = offset;
  353         return NULL;
  354 }
  355 
  356 
  357 const struct fdt_property *fdt_get_property_namelen(const void *fdt,
  358                                                     int offset,
  359                                                     const char *name,
  360                                                     int namelen, int *lenp)
  361 {
  362         /* Prior to version 16, properties may need realignment
  363          * and this API does not work. fdt_getprop_*() will, however. */
  364         if (fdt_version(fdt) < 0x10) {
  365                 if (lenp)
  366                         *lenp = -FDT_ERR_BADVERSION;
  367                 return NULL;
  368         }
  369 
  370         return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
  371                                          NULL);
  372 }
  373 
  374 
  375 const struct fdt_property *fdt_get_property(const void *fdt,
  376                                             int nodeoffset,
  377                                             const char *name, int *lenp)
  378 {
  379         return fdt_get_property_namelen(fdt, nodeoffset, name,
  380                                         strlen(name), lenp);
  381 }
  382 
  383 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
  384                                 const char *name, int namelen, int *lenp)
  385 {
  386         int poffset;
  387         const struct fdt_property *prop;
  388 
  389         prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
  390                                          &poffset);
  391         if (!prop)
  392                 return NULL;
  393 
  394         /* Handle realignment */
  395         if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
  396             fdt32_to_cpu(prop->len) >= 8)
  397                 return prop->data + 4;
  398         return prop->data;
  399 }
  400 
  401 const void *fdt_getprop_by_offset(const void *fdt, int offset,
  402                                   const char **namep, int *lenp)
  403 {
  404         const struct fdt_property *prop;
  405 
  406         prop = fdt_get_property_by_offset_(fdt, offset, lenp);
  407         if (!prop)
  408                 return NULL;
  409         if (namep)
  410                 *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
  411 
  412         /* Handle realignment */
  413         if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
  414             fdt32_to_cpu(prop->len) >= 8)
  415                 return prop->data + 4;
  416         return prop->data;
  417 }
  418 
  419 const void *fdt_getprop(const void *fdt, int nodeoffset,
  420                         const char *name, int *lenp)
  421 {
  422         return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
  423 }
  424 
  425 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
  426 {
  427         const fdt32_t *php;
  428         int len;
  429 
  430         /* FIXME: This is a bit sub-optimal, since we potentially scan
  431          * over all the properties twice. */
  432         php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
  433         if (!php || (len != sizeof(*php))) {
  434                 php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
  435                 if (!php || (len != sizeof(*php)))
  436                         return 0;
  437         }
  438 
  439         return fdt32_to_cpu(*php);
  440 }
  441 
  442 const char *fdt_get_alias_namelen(const void *fdt,
  443                                   const char *name, int namelen)
  444 {
  445         int aliasoffset;
  446 
  447         aliasoffset = fdt_path_offset(fdt, "/aliases");
  448         if (aliasoffset < 0)
  449                 return NULL;
  450 
  451         return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
  452 }
  453 
  454 const char *fdt_get_alias(const void *fdt, const char *name)
  455 {
  456         return fdt_get_alias_namelen(fdt, name, strlen(name));
  457 }
  458 
  459 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
  460 {
  461         int pdepth = 0, p = 0;
  462         int offset, depth, namelen;
  463         const char *name;
  464 
  465         FDT_CHECK_HEADER(fdt);
  466 
  467         if (buflen < 2)
  468                 return -FDT_ERR_NOSPACE;
  469 
  470         for (offset = 0, depth = 0;
  471              (offset >= 0) && (offset <= nodeoffset);
  472              offset = fdt_next_node(fdt, offset, &depth)) {
  473                 while (pdepth > depth) {
  474                         do {
  475                                 p--;
  476                         } while (buf[p-1] != '/');
  477                         pdepth--;
  478                 }
  479 
  480                 if (pdepth >= depth) {
  481                         name = fdt_get_name(fdt, offset, &namelen);
  482                         if (!name)
  483                                 return namelen;
  484                         if ((p + namelen + 1) <= buflen) {
  485                                 memcpy(buf + p, name, namelen);
  486                                 p += namelen;
  487                                 buf[p++] = '/';
  488                                 pdepth++;
  489                         }
  490                 }
  491 
  492                 if (offset == nodeoffset) {
  493                         if (pdepth < (depth + 1))
  494                                 return -FDT_ERR_NOSPACE;
  495 
  496                         if (p > 1) /* special case so that root path is "/", not "" */
  497                                 p--;
  498                         buf[p] = '\0';
  499                         return 0;
  500                 }
  501         }
  502 
  503         if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
  504                 return -FDT_ERR_BADOFFSET;
  505         else if (offset == -FDT_ERR_BADOFFSET)
  506                 return -FDT_ERR_BADSTRUCTURE;
  507 
  508         return offset; /* error from fdt_next_node() */
  509 }
  510 
  511 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
  512                                  int supernodedepth, int *nodedepth)
  513 {
  514         int offset, depth;
  515         int supernodeoffset = -FDT_ERR_INTERNAL;
  516 
  517         FDT_CHECK_HEADER(fdt);
  518 
  519         if (supernodedepth < 0)
  520                 return -FDT_ERR_NOTFOUND;
  521 
  522         for (offset = 0, depth = 0;
  523              (offset >= 0) && (offset <= nodeoffset);
  524              offset = fdt_next_node(fdt, offset, &depth)) {
  525                 if (depth == supernodedepth)
  526                         supernodeoffset = offset;
  527 
  528                 if (offset == nodeoffset) {
  529                         if (nodedepth)
  530                                 *nodedepth = depth;
  531 
  532                         if (supernodedepth > depth)
  533                                 return -FDT_ERR_NOTFOUND;
  534                         else
  535                                 return supernodeoffset;
  536                 }
  537         }
  538 
  539         if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
  540                 return -FDT_ERR_BADOFFSET;
  541         else if (offset == -FDT_ERR_BADOFFSET)
  542                 return -FDT_ERR_BADSTRUCTURE;
  543 
  544         return offset; /* error from fdt_next_node() */
  545 }
  546 
  547 int fdt_node_depth(const void *fdt, int nodeoffset)
  548 {
  549         int nodedepth;
  550         int err;
  551 
  552         err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
  553         if (err)
  554                 return (err < 0) ? err : -FDT_ERR_INTERNAL;
  555         return nodedepth;
  556 }
  557 
  558 int fdt_parent_offset(const void *fdt, int nodeoffset)
  559 {
  560         int nodedepth = fdt_node_depth(fdt, nodeoffset);
  561 
  562         if (nodedepth < 0)
  563                 return nodedepth;
  564         return fdt_supernode_atdepth_offset(fdt, nodeoffset,
  565                                             nodedepth - 1, NULL);
  566 }
  567 
  568 int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
  569                                   const char *propname,
  570                                   const void *propval, int proplen)
  571 {
  572         int offset;
  573         const void *val;
  574         int len;
  575 
  576         FDT_CHECK_HEADER(fdt);
  577 
  578         /* FIXME: The algorithm here is pretty horrible: we scan each
  579          * property of a node in fdt_getprop(), then if that didn't
  580          * find what we want, we scan over them again making our way
  581          * to the next node.  Still it's the easiest to implement
  582          * approach; performance can come later. */
  583         for (offset = fdt_next_node(fdt, startoffset, NULL);
  584              offset >= 0;
  585              offset = fdt_next_node(fdt, offset, NULL)) {
  586                 val = fdt_getprop(fdt, offset, propname, &len);
  587                 if (val && (len == proplen)
  588                     && (memcmp(val, propval, len) == 0))
  589                         return offset;
  590         }
  591 
  592         return offset; /* error from fdt_next_node() */
  593 }
  594 
  595 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
  596 {
  597         int offset;
  598 
  599         if ((phandle == 0) || (phandle == -1))
  600                 return -FDT_ERR_BADPHANDLE;
  601 
  602         FDT_CHECK_HEADER(fdt);
  603 
  604         /* FIXME: The algorithm here is pretty horrible: we
  605          * potentially scan each property of a node in
  606          * fdt_get_phandle(), then if that didn't find what
  607          * we want, we scan over them again making our way to the next
  608          * node.  Still it's the easiest to implement approach;
  609          * performance can come later. */
  610         for (offset = fdt_next_node(fdt, -1, NULL);
  611              offset >= 0;
  612              offset = fdt_next_node(fdt, offset, NULL)) {
  613                 if (fdt_get_phandle(fdt, offset) == phandle)
  614                         return offset;
  615         }
  616 
  617         return offset; /* error from fdt_next_node() */
  618 }
  619 
  620 int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
  621 {
  622         int len = strlen(str);
  623         const char *p;
  624 
  625         while (listlen >= len) {
  626                 if (memcmp(str, strlist, len+1) == 0)
  627                         return 1;
  628                 p = memchr(strlist, '\0', listlen);
  629                 if (!p)
  630                         return 0; /* malformed strlist.. */
  631                 listlen -= (p-strlist) + 1;
  632                 strlist = p + 1;
  633         }
  634         return 0;
  635 }
  636 
  637 int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
  638 {
  639         const char *list, *end;
  640         int length, count = 0;
  641 
  642         list = fdt_getprop(fdt, nodeoffset, property, &length);
  643         if (!list)
  644                 return length;
  645 
  646         end = list + length;
  647 
  648         while (list < end) {
  649                 length = strnlen(list, end - list) + 1;
  650 
  651                 /* Abort if the last string isn't properly NUL-terminated. */
  652                 if (list + length > end)
  653                         return -FDT_ERR_BADVALUE;
  654 
  655                 list += length;
  656                 count++;
  657         }
  658 
  659         return count;
  660 }
  661 
  662 int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
  663                           const char *string)
  664 {
  665         int length, len, idx = 0;
  666         const char *list, *end;
  667 
  668         list = fdt_getprop(fdt, nodeoffset, property, &length);
  669         if (!list)
  670                 return length;
  671 
  672         len = strlen(string) + 1;
  673         end = list + length;
  674 
  675         while (list < end) {
  676                 length = strnlen(list, end - list) + 1;
  677 
  678                 /* Abort if the last string isn't properly NUL-terminated. */
  679                 if (list + length > end)
  680                         return -FDT_ERR_BADVALUE;
  681 
  682                 if (length == len && memcmp(list, string, length) == 0)
  683                         return idx;
  684 
  685                 list += length;
  686                 idx++;
  687         }
  688 
  689         return -FDT_ERR_NOTFOUND;
  690 }
  691 
  692 const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
  693                                const char *property, int idx,
  694                                int *lenp)
  695 {
  696         const char *list, *end;
  697         int length;
  698 
  699         list = fdt_getprop(fdt, nodeoffset, property, &length);
  700         if (!list) {
  701                 if (lenp)
  702                         *lenp = length;
  703 
  704                 return NULL;
  705         }
  706 
  707         end = list + length;
  708 
  709         while (list < end) {
  710                 length = strnlen(list, end - list) + 1;
  711 
  712                 /* Abort if the last string isn't properly NUL-terminated. */
  713                 if (list + length > end) {
  714                         if (lenp)
  715                                 *lenp = -FDT_ERR_BADVALUE;
  716 
  717                         return NULL;
  718                 }
  719 
  720                 if (idx == 0) {
  721                         if (lenp)
  722                                 *lenp = length - 1;
  723 
  724                         return list;
  725                 }
  726 
  727                 list += length;
  728                 idx--;
  729         }
  730 
  731         if (lenp)
  732                 *lenp = -FDT_ERR_NOTFOUND;
  733 
  734         return NULL;
  735 }
  736 
  737 int fdt_node_check_compatible(const void *fdt, int nodeoffset,
  738                               const char *compatible)
  739 {
  740         const void *prop;
  741         int len;
  742 
  743         prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
  744         if (!prop)
  745                 return len;
  746 
  747         return !fdt_stringlist_contains(prop, len, compatible);
  748 }
  749 
  750 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
  751                                   const char *compatible)
  752 {
  753         int offset, err;
  754 
  755         FDT_CHECK_HEADER(fdt);
  756 
  757         /* FIXME: The algorithm here is pretty horrible: we scan each
  758          * property of a node in fdt_node_check_compatible(), then if
  759          * that didn't find what we want, we scan over them again
  760          * making our way to the next node.  Still it's the easiest to
  761          * implement approach; performance can come later. */
  762         for (offset = fdt_next_node(fdt, startoffset, NULL);
  763              offset >= 0;
  764              offset = fdt_next_node(fdt, offset, NULL)) {
  765                 err = fdt_node_check_compatible(fdt, offset, compatible);
  766                 if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
  767                         return err;
  768                 else if (err == 0)
  769                         return offset;
  770         }
  771 
  772         return offset; /* error from fdt_next_node() */
  773 }

Cache object: 9b50f724684ff6e1ccd497ab973725a2


[ 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.