2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
5 * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions, and the following disclaimer,
13 * without modification, immediately at the beginning of the file.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include "opt_platform.h"
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/errno.h>
40 #include <sys/libkern.h>
43 #include <machine/resource.h>
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47 #include <dev/ofw/openfirm.h>
49 #include "ofw_bus_if.h"
51 #define OFW_COMPAT_LEN 255
52 #define OFW_STATUS_LEN 16
55 ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
60 /* The 'name' property is considered mandatory. */
61 if ((OF_getprop_alloc(node, "name", (void **)&obd->obd_name)) == -1)
63 OF_getprop_alloc(node, "compatible", (void **)&obd->obd_compat);
64 OF_getprop_alloc(node, "device_type", (void **)&obd->obd_type);
65 OF_getprop_alloc(node, "model", (void **)&obd->obd_model);
66 OF_getprop_alloc(node, "status", (void **)&obd->obd_status);
72 ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
77 if (obd->obd_compat != NULL)
78 free(obd->obd_compat, M_OFWPROP);
79 if (obd->obd_model != NULL)
80 free(obd->obd_model, M_OFWPROP);
81 if (obd->obd_name != NULL)
82 free(obd->obd_name, M_OFWPROP);
83 if (obd->obd_type != NULL)
84 free(obd->obd_type, M_OFWPROP);
85 if (obd->obd_status != NULL)
86 free(obd->obd_status, M_OFWPROP);
90 ofw_bus_gen_child_pnpinfo(device_t cbdev, device_t child, struct sbuf *sb)
93 if (!ofw_bus_status_okay(child))
96 if (ofw_bus_get_name(child) != NULL) {
97 sbuf_printf(sb, "name=%s ", ofw_bus_get_name(child));
100 if (ofw_bus_get_compat(child) != NULL) {
101 sbuf_printf(sb, "compat=%s ", ofw_bus_get_compat(child));
108 ofw_bus_gen_get_device_path(device_t cbdev, device_t child, const char *locator,
113 if ( strcmp(locator, BUS_LOCATOR_OFW) == 0){
114 rv = bus_generic_get_device_path(cbdev, child, locator, sb);
116 sbuf_printf(sb, "/%s", ofw_bus_get_name(child));
120 return (bus_generic_get_device_path(cbdev, child, locator, sb));
124 ofw_bus_gen_get_compat(device_t bus, device_t dev)
126 const struct ofw_bus_devinfo *obd;
128 obd = OFW_BUS_GET_DEVINFO(bus, dev);
131 return (obd->obd_compat);
135 ofw_bus_gen_get_model(device_t bus, device_t dev)
137 const struct ofw_bus_devinfo *obd;
139 obd = OFW_BUS_GET_DEVINFO(bus, dev);
142 return (obd->obd_model);
146 ofw_bus_gen_get_name(device_t bus, device_t dev)
148 const struct ofw_bus_devinfo *obd;
150 obd = OFW_BUS_GET_DEVINFO(bus, dev);
153 return (obd->obd_name);
157 ofw_bus_gen_get_node(device_t bus, device_t dev)
159 const struct ofw_bus_devinfo *obd;
161 obd = OFW_BUS_GET_DEVINFO(bus, dev);
163 return ((phandle_t)-1);
164 return (obd->obd_node);
168 ofw_bus_gen_get_type(device_t bus, device_t dev)
170 const struct ofw_bus_devinfo *obd;
172 obd = OFW_BUS_GET_DEVINFO(bus, dev);
175 return (obd->obd_type);
179 ofw_bus_get_status(device_t dev)
181 const struct ofw_bus_devinfo *obd;
183 obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev);
187 return (obd->obd_status);
191 ofw_bus_status_okay(device_t dev)
195 status = ofw_bus_get_status(dev);
196 if (status == NULL || strcmp(status, "okay") == 0 ||
197 strcmp(status, "ok") == 0)
204 ofw_bus_node_status_okay(phandle_t node)
206 char status[OFW_STATUS_LEN];
209 len = OF_getproplen(node, "status");
213 OF_getprop(node, "status", status, OFW_STATUS_LEN);
214 if ((len == 5 && (bcmp(status, "okay", len) == 0)) ||
215 (len == 3 && (bcmp(status, "ok", len))))
222 ofw_bus_node_is_compatible_int(const char *compat, int len,
223 const char *onecompat)
227 onelen = strlen(onecompat);
231 if (strlen(compat) == onelen &&
232 strncasecmp(compat, onecompat, onelen) == 0) {
238 /* Slide to the next sub-string. */
239 l = strlen(compat) + 1;
248 ofw_bus_node_is_compatible(phandle_t node, const char *compatstr)
250 char compat[OFW_COMPAT_LEN];
253 if ((len = OF_getproplen(node, "compatible")) <= 0)
256 bzero(compat, OFW_COMPAT_LEN);
258 if (OF_getprop(node, "compatible", compat, OFW_COMPAT_LEN) < 0)
261 rv = ofw_bus_node_is_compatible_int(compat, len, compatstr);
267 ofw_bus_is_compatible(device_t dev, const char *onecompat)
273 if ((compat = ofw_bus_get_compat(dev)) == NULL)
276 if ((node = ofw_bus_get_node(dev)) == -1)
279 /* Get total 'compatible' prop len */
280 if ((len = OF_getproplen(node, "compatible")) <= 0)
283 return (ofw_bus_node_is_compatible_int(compat, len, onecompat));
287 ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
292 if ((compat = ofw_bus_get_compat(dev)) == NULL)
295 len = strlen(compatible);
296 if (strlen(compat) == len &&
297 strncasecmp(compat, compatible, len) == 0)
303 const struct ofw_compat_data *
304 ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat)
310 for (; compat->ocd_str != NULL; ++compat) {
311 if (ofw_bus_is_compatible(dev, compat->ocd_str))
319 ofw_bus_has_prop(device_t dev, const char *propname)
323 if ((node = ofw_bus_get_node(dev)) == -1)
326 return (OF_hasprop(node, propname));
330 ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
335 if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
337 ii->opi_addrc = addrc * sizeof(pcell_t);
339 ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map",
340 (void **)&ii->opi_imap);
341 if (ii->opi_imapsz > 0) {
342 msksz = OF_getencprop_alloc(node, "interrupt-map-mask",
343 (void **)&ii->opi_imapmsk);
345 * Failure to get the mask is ignored; a full mask is used
346 * then. We barf on bad mask sizes, however.
348 if (msksz != -1 && msksz != ii->opi_addrc + intrsz)
349 panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
355 ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
356 int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
359 uint8_t maskbuf[regsz + pintrsz];
362 if (ii->opi_imapsz <= 0)
364 KASSERT(regsz >= ii->opi_addrc,
365 ("ofw_bus_lookup_imap: register size too small: %d < %d",
366 regsz, ii->opi_addrc));
368 rv = OF_getencprop(node, "reg", reg, regsz);
370 panic("ofw_bus_lookup_imap: cannot get reg property");
372 return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
373 ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
378 * Map an interrupt using the firmware reg, interrupt-map and
379 * interrupt-map-mask properties.
380 * The interrupt property to be mapped must be of size intrsz, and pointed to
381 * by intr. The regs property of the node for which the mapping is done must
382 * be passed as regs. This property is an array of register specifications;
383 * the size of the address part of such a specification must be passed as
384 * physsz. Only the first element of the property is used.
385 * imap and imapsz hold the interrupt mask and it's size.
386 * imapmsk is a pointer to the interrupt-map-mask property, which must have
387 * a size of physsz + intrsz; it may be NULL, in which case a full mask is
389 * maskbuf must point to a buffer of length physsz + intrsz.
390 * The interrupt is returned in result, which must point to a buffer of length
391 * rintrsz (which gives the expected size of the mapped interrupt).
392 * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
395 ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
396 void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
397 int rintrsz, phandle_t *iparent)
400 uint8_t *ref = maskbuf;
401 uint8_t *uiintr = intr;
402 uint8_t *uiregs = regs;
403 uint8_t *uiimapmsk = imapmsk;
409 if (imapmsk != NULL) {
410 for (i = 0; i < physsz; i++)
411 ref[i] = uiregs[i] & uiimapmsk[i];
412 for (i = 0; i < intrsz; i++)
413 ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
415 bcopy(regs, ref, physsz);
416 bcopy(intr, ref + physsz, intrsz);
423 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
424 #ifndef OFW_IMAP_NO_IPARENT_ADDR_CELLS
426 * Find if we need to read the parent address data.
427 * CHRP-derived OF bindings, including ePAPR-compliant FDTs,
428 * use this as an optional part of the specifier.
430 if (OF_getencprop(OF_node_from_xref(parent),
431 "#address-cells", &paddrsz, sizeof(paddrsz)) == -1)
432 paddrsz = 0; /* default */
433 paddrsz *= sizeof(pcell_t);
436 if (OF_searchencprop(OF_node_from_xref(parent),
437 "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
438 pintrsz = 1; /* default */
439 pintrsz *= sizeof(pcell_t);
441 /* Compute the map stride size. */
442 tsz = physsz + intrsz + sizeof(phandle_t) + paddrsz + pintrsz;
443 KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
445 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
446 bcopy(mptr + physsz + intrsz + sizeof(parent) + paddrsz,
447 result, MIN(rintrsz, pintrsz));
451 return (pintrsz/sizeof(pcell_t));
460 ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent,
463 pcell_t *map, mask, msi_base, rid_base, rid_length;
468 /* TODO: This should be OF_searchprop_alloc if we had it */
469 len = OF_getencprop_alloc_multi(node, "msi-map", sizeof(*map),
472 if (msi_parent != NULL) {
474 OF_getencprop(node, "msi-parent", msi_parent,
475 sizeof(*msi_parent));
484 OF_getencprop(node, "msi-map-mask", &mask, sizeof(mask));
486 masked_rid = pci_rid & mask;
487 for (i = 0; i < len; i += 4) {
488 rid_base = map[i + 0];
489 rid_length = map[i + 3];
491 if (masked_rid < rid_base ||
492 masked_rid >= (rid_base + rid_length))
495 msi_base = map[i + 2];
497 if (msi_parent != NULL)
498 *msi_parent = map[i + 1];
500 *msi_rid = masked_rid - rid_base + msi_base;
505 free(map, M_OFWPROP);
511 ofw_bus_iommu_map(phandle_t node, uint16_t pci_rid, phandle_t *iommu_parent,
514 pcell_t *map, mask, iommu_base, rid_base, rid_length;
519 len = OF_getencprop_alloc_multi(node, "iommu-map", sizeof(*map),
526 OF_getencprop(node, "iommu-map-mask", &mask, sizeof(mask));
528 masked_rid = pci_rid & mask;
529 for (i = 0; i < len; i += 4) {
530 rid_base = map[i + 0];
531 rid_length = map[i + 3];
533 if (masked_rid < rid_base ||
534 masked_rid >= (rid_base + rid_length))
537 iommu_base = map[i + 2];
539 if (iommu_parent != NULL)
540 *iommu_parent = map[i + 1];
541 if (iommu_rid != NULL)
542 *iommu_rid = masked_rid - rid_base + iommu_base;
547 free(map, M_OFWPROP);
553 ofw_bus_reg_to_rl_helper(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
554 struct resource_list *rl, const char *reg_source)
557 ssize_t i, j, rid, nreg, ret;
562 * This may be just redundant when having ofw_bus_devinfo
563 * but makes this routine independent of it.
565 ret = OF_getprop_alloc(node, "name", (void **)&name);
569 ret = OF_getencprop_alloc_multi(node, reg_source, sizeof(*reg),
571 nreg = (ret == -1) ? 0 : ret;
573 if (nreg % (acells + scells) != 0) {
575 device_printf(dev, "Malformed reg property on <%s>\n",
576 (name == NULL) ? "unknown" : name);
580 for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) {
582 for (j = 0; j < acells; j++) {
586 for (j = 0; j < scells; j++) {
588 size |= reg[i + acells + j];
590 /* Skip the dummy reg property of glue devices like ssm(4). */
592 resource_list_add(rl, SYS_RES_MEMORY, rid,
593 phys, phys + size - 1, size);
595 free(name, M_OFWPROP);
596 free(reg, M_OFWPROP);
602 ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
603 struct resource_list *rl)
606 return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells, rl, "reg"));
610 ofw_bus_assigned_addresses_to_rl(device_t dev, phandle_t node, pcell_t acells,
611 pcell_t scells, struct resource_list *rl)
614 return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells,
615 rl, "assigned-addresses"));
619 * Get interrupt parent for given node.
620 * Returns 0 if interrupt parent doesn't exist.
623 ofw_bus_find_iparent(phandle_t node)
627 if (OF_searchencprop(node, "interrupt-parent", &iparent,
628 sizeof(iparent)) == -1) {
629 for (iparent = node; iparent != 0;
630 iparent = OF_parent(iparent)) {
631 if (OF_hasprop(iparent, "interrupt-controller"))
634 iparent = OF_xref_from_node(iparent);
640 ofw_bus_intr_to_rl(device_t dev, phandle_t node,
641 struct resource_list *rl, int *rlen)
644 uint32_t icells, *intr;
645 int err, i, irqnum, nintr, rid;
648 nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
651 iparent = ofw_bus_find_iparent(node);
653 device_printf(dev, "No interrupt-parent found, "
654 "assuming direct parent\n");
655 iparent = OF_parent(node);
656 iparent = OF_xref_from_node(iparent);
658 if (OF_searchencprop(OF_node_from_xref(iparent),
659 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
660 device_printf(dev, "Missing #interrupt-cells "
661 "property, assuming <1>\n");
664 if (icells < 1 || icells > nintr) {
665 device_printf(dev, "Invalid #interrupt-cells property "
666 "value <%d>, assuming <1>\n", icells);
671 nintr = OF_getencprop_alloc_multi(node, "interrupts-extended",
672 sizeof(*intr), (void **)&intr);
679 for (i = 0; i < nintr; i += icells) {
682 if (OF_searchencprop(OF_node_from_xref(iparent),
683 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
684 device_printf(dev, "Missing #interrupt-cells "
689 if (icells < 1 || (i + icells) > nintr) {
690 device_printf(dev, "Invalid #interrupt-cells "
691 "property value <%d>\n", icells);
696 irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
697 resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
701 free(intr, M_OFWPROP);
706 ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid,
707 phandle_t *producer, int *ncells, pcell_t **cells)
710 uint32_t icells, *intr;
711 int err, i, nintr, rid;
714 nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
717 iparent = ofw_bus_find_iparent(node);
719 device_printf(dev, "No interrupt-parent found, "
720 "assuming direct parent\n");
721 iparent = OF_parent(node);
722 iparent = OF_xref_from_node(iparent);
724 if (OF_searchencprop(OF_node_from_xref(iparent),
725 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
726 device_printf(dev, "Missing #interrupt-cells "
727 "property, assuming <1>\n");
730 if (icells < 1 || icells > nintr) {
731 device_printf(dev, "Invalid #interrupt-cells property "
732 "value <%d>, assuming <1>\n", icells);
737 nintr = OF_getencprop_alloc_multi(node, "interrupts-extended",
738 sizeof(*intr), (void **)&intr);
745 for (i = 0; i < nintr; i += icells, rid++) {
748 if (OF_searchencprop(OF_node_from_xref(iparent),
749 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
750 device_printf(dev, "Missing #interrupt-cells "
755 if (icells < 1 || (i + icells) > nintr) {
756 device_printf(dev, "Invalid #interrupt-cells "
757 "property value <%d>\n", icells);
762 if (rid == wanted_rid) {
763 *cells = malloc(icells * sizeof(**cells), M_OFWPROP,
767 memcpy(*cells, intr + i, icells * sizeof(**cells));
772 free(intr, M_OFWPROP);
777 ofw_bus_find_child(phandle_t start, const char *child_name)
783 for (child = OF_child(start); child != 0; child = OF_peer(child)) {
784 ret = OF_getprop_alloc(child, "name", (void **)&name);
787 if (strcmp(name, child_name) == 0) {
788 free(name, M_OFWPROP);
792 free(name, M_OFWPROP);
799 ofw_bus_find_compatible(phandle_t node, const char *onecompat)
801 phandle_t child, ret;
804 * Traverse all children of 'start' node, and find first with
805 * matching 'compatible' property.
807 for (child = OF_child(node); child != 0; child = OF_peer(child)) {
808 if (ofw_bus_node_is_compatible(child, onecompat) != 0)
811 ret = ofw_bus_find_compatible(child, onecompat);
819 * @brief Return child of bus whose phandle is node
821 * A direct child of @p will be returned if it its phandle in the
822 * OFW tree is @p node. Otherwise, NULL is returned.
824 * @param bus The bus to examine
825 * @param node The phandle_t to look for.
828 ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node)
830 device_t *children, retval, child;
834 * Nothing can match the flag value for no node.
840 * Search the children for a match. We microoptimize
841 * a bit by not using ofw_bus_get since we already know
842 * the parent. We do not recurse.
844 if (device_get_children(bus, &children, &nkid) != 0)
847 for (i = 0; i < nkid; i++) {
849 if (OFW_BUS_GET_NODE(bus, child) == node) {
854 free(children, M_TEMP);
860 * Parse property that contain list of xrefs and values
861 * (like standard "clocks" and "resets" properties)
863 * node - consumers device node
864 * list_name - name of parsed list - "clocks"
865 * cells_name - name of size property - "#clock-cells"
866 * idx - the index of the requested list entry, or, if -1, an indication
867 * to return the number of entries in the parsed list.
869 * producer - handle of producer
870 * ncells - number of cells in result or the number of items in the list when
872 * cells - array of decoded cells
875 ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name,
876 const char *cells_name, int idx, phandle_t *producer, int *ncells,
882 int rv, i, j, nelems, cnt;
885 nelems = OF_getencprop_alloc_multi(node, list_name, sizeof(*elems),
889 rv = (idx == -1) ? 0 : ENOENT;
890 for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) {
892 if (OF_getencprop(OF_node_from_xref(pnode),
893 cells_name, &pcells, sizeof(pcells)) == -1) {
894 printf("Missing %s property\n", cells_name);
899 if ((i + pcells) > nelems) {
900 printf("Invalid %s property value <%d>\n", cells_name,
906 *cells= malloc(pcells * sizeof(**cells), M_OFWPROP,
910 for (j = 0; j < pcells; j++)
911 (*cells)[j] = elems[i + j];
917 free(elems, M_OFWPROP);
918 if (idx == -1 && rv == 0)
924 * Parse property that contain list of xrefs and values
925 * (like standard "clocks" and "resets" properties)
927 * node - consumers device node
928 * list_name - name of parsed list - "clocks"
929 * cells_name - name of size property - "#clock-cells"
930 * idx - the index of the requested list entry (>= 0)
932 * producer - handle of producer
933 * ncells - number of cells in result
934 * cells - array of decoded cells
937 ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
938 const char *cells_name, int idx, phandle_t *producer, int *ncells,
943 ("ofw_bus_parse_xref_list_alloc: negative index supplied"));
945 return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
946 idx, producer, ncells, cells));
950 * Parse property that contain list of xrefs and values
951 * (like standard "clocks" and "resets" properties)
952 * and determine the number of items in the list
954 * node - consumers device node
955 * list_name - name of parsed list - "clocks"
956 * cells_name - name of size property - "#clock-cells"
958 * count - number of items in list
961 ofw_bus_parse_xref_list_get_length(phandle_t node, const char *list_name,
962 const char *cells_name, int *count)
965 return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
966 -1, NULL, count, NULL));
970 * Find index of string in string list property (case sensitive).
973 ofw_bus_find_string_index(phandle_t node, const char *list_name,
974 const char *name, int *idx)
977 int rv, i, cnt, nelems;
980 nelems = OF_getprop_alloc(node, list_name, (void **)&elems);
985 for (i = 0, cnt = 0; i < nelems; cnt++) {
986 if (strcmp(elems + i, name) == 0) {
991 i += strlen(elems + i) + 1;
995 free(elems, M_OFWPROP);
1000 * Create zero terminated array of strings from string list property.
1003 ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
1004 const char ***out_array)
1008 int i, cnt, nelems, len;
1011 nelems = OF_getprop_alloc(node, list_name, (void **)&elems);
1015 /* Count number of strings. */
1016 for (i = 0, cnt = 0; i < nelems; cnt++)
1017 i += strlen(elems + i) + 1;
1019 /* Allocate space for arrays and all strings. */
1020 array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP,
1023 /* Get address of first string. */
1024 tptr = (char *)(array + cnt + 1);
1027 memcpy(tptr, elems, nelems);
1028 free(elems, M_OFWPROP);
1030 /* Fill string pointers. */
1031 for (i = 0, cnt = 0; i < nelems; cnt++) {
1032 len = strlen(tptr) + 1;