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_bus_subr.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) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
    3  * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions, and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in
   14  *    the documentation and/or other materials provided with the
   15  *    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 FOR
   21  * 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_bus_subr.c 209298 2010-06-18 14:06:27Z nwhitehorn $");
   32 
   33 #include "opt_platform.h"
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/errno.h>
   38 #include <sys/libkern.h>
   39 
   40 #include <dev/ofw/ofw_bus.h>
   41 #include <dev/ofw/ofw_bus_subr.h>
   42 #include <dev/ofw/openfirm.h>
   43 
   44 #include "ofw_bus_if.h"
   45 
   46 int
   47 ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
   48 {
   49 
   50         if (obd == NULL)
   51                 return (ENOMEM);
   52         /* The 'name' property is considered mandatory. */
   53         if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1)
   54                 return (EINVAL);
   55         OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat);
   56         OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type);
   57         OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model);
   58         obd->obd_node = node;
   59         return (0);
   60 }
   61 
   62 void
   63 ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
   64 {
   65 
   66         if (obd == NULL)
   67                 return;
   68         if (obd->obd_compat != NULL)
   69                 free(obd->obd_compat, M_OFWPROP);
   70         if (obd->obd_model != NULL)
   71                 free(obd->obd_model, M_OFWPROP);
   72         if (obd->obd_name != NULL)
   73                 free(obd->obd_name, M_OFWPROP);
   74         if (obd->obd_type != NULL)
   75                 free(obd->obd_type, M_OFWPROP);
   76 }
   77 
   78 int
   79 ofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf,
   80     size_t buflen)
   81 {
   82 
   83         if (ofw_bus_get_name(child) != NULL) {
   84                 strlcat(buf, "name=", buflen);
   85                 strlcat(buf, ofw_bus_get_name(child), buflen);
   86         }
   87 
   88         if (ofw_bus_get_compat(child) != NULL) {
   89                 strlcat(buf, " compat=", buflen);
   90                 strlcat(buf, ofw_bus_get_compat(child), buflen);
   91         }
   92         return (0);
   93 };
   94 
   95 const char *
   96 ofw_bus_gen_get_compat(device_t bus, device_t dev)
   97 {
   98         const struct ofw_bus_devinfo *obd;
   99 
  100         obd = OFW_BUS_GET_DEVINFO(bus, dev);
  101         if (obd == NULL)
  102                 return (NULL);
  103         return (obd->obd_compat);
  104 }
  105 
  106 const char *
  107 ofw_bus_gen_get_model(device_t bus, device_t dev)
  108 {
  109         const struct ofw_bus_devinfo *obd;
  110 
  111         obd = OFW_BUS_GET_DEVINFO(bus, dev);
  112         if (obd == NULL)
  113                 return (NULL);
  114         return (obd->obd_model);
  115 }
  116 
  117 const char *
  118 ofw_bus_gen_get_name(device_t bus, device_t dev)
  119 {
  120         const struct ofw_bus_devinfo *obd;
  121 
  122         obd = OFW_BUS_GET_DEVINFO(bus, dev);
  123         if (obd == NULL)
  124                 return (NULL);
  125         return (obd->obd_name);
  126 }
  127 
  128 phandle_t
  129 ofw_bus_gen_get_node(device_t bus, device_t dev)
  130 {
  131         const struct ofw_bus_devinfo *obd;
  132 
  133         obd = OFW_BUS_GET_DEVINFO(bus, dev);
  134         if (obd == NULL)
  135                 return (0);
  136         return (obd->obd_node);
  137 }
  138 
  139 const char *
  140 ofw_bus_gen_get_type(device_t bus, device_t dev)
  141 {
  142         const struct ofw_bus_devinfo *obd;
  143 
  144         obd = OFW_BUS_GET_DEVINFO(bus, dev);
  145         if (obd == NULL)
  146                 return (NULL);
  147         return (obd->obd_type);
  148 }
  149 
  150 int
  151 ofw_bus_is_compatible(device_t dev, const char *onecompat)
  152 {
  153         phandle_t node;
  154         const char *compat;
  155         int len, onelen, l;
  156 
  157         if ((compat = ofw_bus_get_compat(dev)) == NULL)
  158                 return (0);
  159 
  160         if ((node = ofw_bus_get_node(dev)) == 0)
  161                 return (0);
  162 
  163         /* Get total 'compatible' prop len */
  164         if ((len = OF_getproplen(node, "compatible")) <= 0)
  165                 return (0);
  166 
  167         onelen = strlen(onecompat);
  168 
  169         while (len > 0) {
  170                 if (strncasecmp(compat, onecompat, onelen) == 0)
  171                         /* Found it. */
  172                         return (1);
  173 
  174                 /* Slide to the next sub-string. */
  175                 l = strlen(compat) + 1;
  176                 compat += l;
  177                 len -= l;
  178         }
  179         return (0);
  180 }
  181 
  182 int
  183 ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
  184 {
  185         const char *compat;
  186 
  187         if ((compat = ofw_bus_get_compat(dev)) == NULL)
  188                 return (0);
  189 
  190         if (strncasecmp(compat, compatible, strlen(compatible)) == 0)
  191                 return (1);
  192 
  193         return (0);
  194 }
  195 
  196 #ifndef FDT
  197 void
  198 ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
  199 {
  200         pcell_t addrc;
  201         int msksz;
  202 
  203         if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
  204                 addrc = 2;
  205         ii->opi_addrc = addrc * sizeof(pcell_t);
  206 
  207         ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1,
  208             (void **)&ii->opi_imap);
  209         if (ii->opi_imapsz > 0) {
  210                 msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1,
  211                     (void **)&ii->opi_imapmsk);
  212                 /*
  213                  * Failure to get the mask is ignored; a full mask is used
  214                  * then.  We barf on bad mask sizes, however.
  215                  */
  216                 if (msksz != -1 && msksz != ii->opi_addrc + intrsz)
  217                         panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
  218                             "property!");
  219         }
  220 }
  221 
  222 int
  223 ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
  224     int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
  225     phandle_t *iparent, void *maskbuf)
  226 {
  227         int rv;
  228 
  229         if (ii->opi_imapsz <= 0)
  230                 return (0);
  231         KASSERT(regsz >= ii->opi_addrc,
  232             ("ofw_bus_lookup_imap: register size too small: %d < %d",
  233                 regsz, ii->opi_addrc));
  234         rv = OF_getprop(node, "reg", reg, regsz);
  235         if (rv < regsz)
  236                 panic("ofw_bus_lookup_imap: could not get reg property");
  237         return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
  238             ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
  239             mintrsz, iparent));
  240 }
  241 
  242 /*
  243  * Map an interrupt using the firmware reg, interrupt-map and
  244  * interrupt-map-mask properties.
  245  * The interrupt property to be mapped must be of size intrsz, and pointed to
  246  * by intr.  The regs property of the node for which the mapping is done must
  247  * be passed as regs. This property is an array of register specifications;
  248  * the size of the address part of such a specification must be passed as
  249  * physsz.  Only the first element of the property is used.
  250  * imap and imapsz hold the interrupt mask and it's size.
  251  * imapmsk is a pointer to the interrupt-map-mask property, which must have
  252  * a size of physsz + intrsz; it may be NULL, in which case a full mask is
  253  * assumed.
  254  * maskbuf must point to a buffer of length physsz + intrsz.
  255  * The interrupt is returned in result, which must point to a buffer of length
  256  * rintrsz (which gives the expected size of the mapped interrupt).
  257  * Returns 1 if a mapping was found, 0 otherwise.
  258  */
  259 int
  260 ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
  261     void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
  262     int rintrsz, phandle_t *iparent)
  263 {
  264         phandle_t parent;
  265         uint8_t *ref = maskbuf;
  266         uint8_t *uiintr = intr;
  267         uint8_t *uiregs = regs;
  268         uint8_t *uiimapmsk = imapmsk;
  269         uint8_t *mptr;
  270         pcell_t pintrsz;
  271         int i, rsz, tsz;
  272 
  273         rsz = -1;
  274         if (imapmsk != NULL) {
  275                 for (i = 0; i < physsz; i++)
  276                         ref[i] = uiregs[i] & uiimapmsk[i];
  277                 for (i = 0; i < intrsz; i++)
  278                         ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
  279         } else {
  280                 bcopy(regs, ref, physsz);
  281                 bcopy(intr, ref + physsz, intrsz);
  282         }
  283 
  284         mptr = imap;
  285         i = imapsz;
  286         while (i > 0) {
  287                 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
  288                 if (OF_searchprop(parent, "#interrupt-cells",
  289                     &pintrsz, sizeof(pintrsz)) == -1)
  290                         pintrsz = 1;    /* default */
  291                 pintrsz *= sizeof(pcell_t);
  292 
  293                 /* Compute the map stride size. */
  294                 tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz;
  295                 KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
  296 
  297                 /*
  298                  * XXX: Apple hardware uses a second cell to set information
  299                  * on the interrupt trigger type.  This information should
  300                  * be used somewhere to program the PIC.
  301                  */
  302 
  303                 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
  304                         bcopy(mptr + physsz + intrsz + sizeof(parent),
  305                             result, rintrsz);
  306 
  307                         if (iparent != NULL)
  308                                 *iparent = parent;
  309                         return (1);
  310                 }
  311                 mptr += tsz;
  312                 i -= tsz;
  313         }
  314         return (0);
  315 }
  316 #endif /* !FDT */

Cache object: 440408b295f76c3a468339a7bb3007a8


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