#include <sys/promif.h>
#include <sys/promimpl.h>
#include <sys/prom_emul.h>
#include <sys/obpdefs.h>
#include <sys/sunddi.h>
#include <sys/sysmacros.h>
static prom_node_t *promif_top;
static prom_node_t *promif_find_node(pnode_t nodeid);
static int getproplen(prom_node_t *pnp, char *name);
static void *getprop(prom_node_t *pnp, char *name);
static void
promif_create_prop(prom_node_t *pnp, char *name, void *val, int len, int flags)
{
struct prom_prop *p, *q;
q = kmem_zalloc(sizeof (*q), KM_SLEEP);
q->pp_name = kmem_zalloc(strlen(name) + 1, KM_SLEEP);
(void) strcpy(q->pp_name, name);
q->pp_val = len > 0 ? kmem_alloc(len, KM_SLEEP) : NULL;
q->pp_len = len;
switch (flags) {
case DDI_PROP_TYPE_INT:
case DDI_PROP_TYPE_INT64:
default:
(void) bcopy(val, q->pp_val, len);
break;
}
if (pnp->pn_propp == NULL) {
pnp->pn_propp = q;
return;
}
for (p = pnp->pn_propp; p->pp_next != NULL; p = p->pp_next)
;
p->pp_next = q;
}
static prom_node_t *
promif_create_node(dev_info_t *dip)
{
prom_node_t *pnp;
ddi_prop_t *hwprop;
char *nodename;
pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP);
pnp->pn_nodeid = DEVI(dip)->devi_nodeid;
hwprop = DEVI(dip)->devi_hw_prop_ptr;
while (hwprop != NULL) {
promif_create_prop(pnp, hwprop->prop_name, hwprop->prop_val,
hwprop->prop_len, hwprop->prop_flags & DDI_PROP_TYPE_MASK);
hwprop = hwprop->prop_next;
}
nodename = ddi_node_name(dip);
promif_create_prop(pnp, "name", nodename, strlen(nodename) + 1,
DDI_PROP_TYPE_STRING);
return (pnp);
}
static void promif_create_children(prom_node_t *, dev_info_t *);
static void
promif_create_peers(prom_node_t *pnp, dev_info_t *dip)
{
dev_info_t *ndip = ddi_get_next_sibling(dip);
while (ndip) {
pnp->pn_sibling = promif_create_node(ndip);
promif_create_children(pnp->pn_sibling, ndip);
pnp = pnp->pn_sibling;
ndip = ddi_get_next_sibling(ndip);
}
}
static void
promif_create_children(prom_node_t *pnp, dev_info_t *dip)
{
dev_info_t *cdip = ddi_get_child(dip);
while (cdip) {
pnp->pn_child = promif_create_node(cdip);
promif_create_peers(pnp->pn_child, cdip);
pnp = pnp->pn_child;
cdip = ddi_get_child(cdip);
}
}
void
promif_create_device_tree(void)
{
promif_top = promif_create_node(ddi_root_node());
promif_create_children(promif_top, ddi_root_node());
}
static prom_node_t *
promif_find_node(pnode_t nodeid)
{
prom_node_t *stack[64];
uint_t top = 0;
if (nodeid == OBP_NONODE)
return (promif_top);
if (promif_top == NULL)
return (NULL);
stack[top++] = promif_top;
while (top > 0) {
prom_node_t *cur = stack[--top];
if (cur->pn_nodeid == nodeid)
return (cur);
if (cur->pn_sibling != NULL)
stack[top++] = cur->pn_sibling;
VERIFY3U(top, <, ARRAY_SIZE(stack));
if (cur->pn_child != NULL)
stack[top++] = cur->pn_child;
VERIFY3U(top, <, ARRAY_SIZE(stack));
}
return (NULL);
}
pnode_t
promif_nextnode(pnode_t nodeid)
{
prom_node_t *pnp;
pnp = promif_find_node(nodeid);
if (pnp && (nodeid == OBP_NONODE))
return (pnp->pn_nodeid);
if (pnp && pnp->pn_sibling)
return (pnp->pn_sibling->pn_nodeid);
return (OBP_NONODE);
}
pnode_t
promif_childnode(pnode_t nodeid)
{
prom_node_t *pnp;
pnp = promif_find_node(nodeid);
if (pnp && pnp->pn_child)
return (pnp->pn_child->pn_nodeid);
return (OBP_NONODE);
}
static int
getproplen(prom_node_t *pnp, char *name)
{
struct prom_prop *propp;
for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
if (strcmp(propp->pp_name, name) == 0)
return (propp->pp_len);
return (-1);
}
int
promif_getproplen(pnode_t nodeid, char *name)
{
prom_node_t *pnp;
pnp = promif_find_node(nodeid);
if (pnp == NULL)
return (-1);
return (getproplen(pnp, name));
}
static void *
getprop(prom_node_t *pnp, char *name)
{
struct prom_prop *propp;
for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
if (strcmp(propp->pp_name, name) == 0)
return (propp->pp_val);
return (NULL);
}
int
promif_getprop(pnode_t nodeid, char *name, void *value)
{
prom_node_t *pnp;
void *v;
int len;
pnp = promif_find_node(nodeid);
if (pnp == NULL)
return (-1);
len = getproplen(pnp, name);
if (len > 0) {
v = getprop(pnp, name);
bcopy(v, value, len);
}
return (len);
}
static char *
nextprop(prom_node_t *pnp, char *name)
{
struct prom_prop *propp;
if (name == NULL || *name == '\0')
if (pnp->pn_propp)
return (pnp->pn_propp->pp_name);
for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
if (strcmp(propp->pp_name, name) == 0)
if (propp->pp_next)
return (propp->pp_next->pp_name);
return (NULL);
}
char *
promif_nextprop(pnode_t nodeid, char *name, char *next)
{
prom_node_t *pnp;
char *s;
next[0] = '\0';
pnp = promif_find_node(nodeid);
if (pnp == NULL)
return (NULL);
s = nextprop(pnp, name);
if (s == NULL)
return (next);
(void) strcpy(next, s);
return (next);
}