#include <sys/types.h>
#include <sys/esunddi.h>
#include <sys/promif_impl.h>
#ifdef _KMDB
static pnode_t chosennode;
static pnode_t optionsnode;
#else
static char *gettoken(char *tp, char *token);
static pnode_t finddevice(char *path);
#endif
#ifdef _KMDB
void
promif_set_nodes(pnode_t chosen, pnode_t options)
{
chosennode = chosen;
optionsnode = options;
}
int
promif_finddevice(void *p)
{
cell_t *ci = (cell_t *)p;
char *path;
ASSERT(ci[1] == 1);
path = p1275_cell2ptr(ci[3]);
if (strcmp("/chosen", path) == 0) {
ci[4] = p1275_dnode2cell(chosennode);
} else if (strcmp("/options", path) == 0) {
ci[4] = p1275_dnode2cell(optionsnode);
} else {
ASSERT(0);
}
return (0);
}
#else
int
promif_finddevice(void *p)
{
cell_t *ci = (cell_t *)p;
pnode_t node;
ASSERT(ci[1] == 1);
thread_affinity_set(curthread, CPU->cpu_id);
node = finddevice(p1275_cell2ptr(ci[3]));
ci[4] = p1275_dnode2cell(node);
thread_affinity_clear(curthread);
return (0);
}
#endif
int
promif_nextnode(void *p)
{
cell_t *ci = (cell_t *)p;
pnode_t next;
ASSERT(ci[1] == 1);
next = promif_stree_nextnode(p1275_cell2dnode(ci[3]));
ci[4] = p1275_dnode2cell(next);
return (0);
}
int
promif_childnode(void *p)
{
cell_t *ci = (cell_t *)p;
pnode_t child;
ASSERT(ci[1] == 1);
child = promif_stree_childnode(p1275_cell2dnode(ci[3]));
ci[4] = p1275_dnode2cell(child);
return (0);
}
int
promif_parentnode(void *p)
{
cell_t *ci = (cell_t *)p;
pnode_t parent;
ASSERT(ci[1] == 1);
parent = promif_stree_parentnode(p1275_cell2dnode(ci[3]));
ci[4] = p1275_dnode2cell(parent);
return (0);
}
#ifndef _KMDB
static char *
gettoken(char *tp, char *token)
{
char *result = token;
for (;;) {
tp = prom_path_gettoken(tp, token);
token += prom_strlen(token);
if ((*tp == ',') || (*tp == ':')) {
*token++ = *tp++;
*token = '\0';
continue;
}
break;
}
prom_strip_options(result, result);
return (tp);
}
static int
get_unit_addr(pnode_t np, char *paddr)
{
dev_info_t *dip;
char *addr;
if ((dip = e_ddi_nodeid_to_dip(np)) == NULL) {
return (-1);
}
if ((addr = ddi_get_name_addr(dip)) == NULL) {
ddi_release_devi(dip);
return (-1);
}
(void) prom_strcpy(paddr, addr);
ddi_release_devi(dip);
return (0);
}
static pnode_t
finddevice(char *path)
{
char name[OBP_MAXPROPNAME];
char addr[OBP_MAXPROPNAME];
char pname[OBP_MAXPROPNAME];
char paddr[OBP_MAXPROPNAME];
char *tp;
pnode_t np;
pnode_t device;
CIF_DBG_NODE("finddevice: %s\n", path);
tp = path;
np = prom_rootnode();
device = OBP_BADNODE;
if (*tp++ != '/')
goto done;
for (;;) {
tp = gettoken(tp, name);
if (*name == '\0')
break;
if (*tp == '@') {
tp++;
tp = gettoken(tp, addr);
} else {
addr[0] = '\0';
}
CIF_DBG_NODE("looking for: %s%s%s\n", name,
(*addr != '\0') ? "@" : "", addr);
if ((np = prom_childnode(np)) == OBP_NONODE)
break;
while (np != OBP_NONODE) {
if (prom_getprop(np, OBP_NAME, pname) < 0)
goto done;
if (get_unit_addr(np, paddr) < 0)
paddr[0] = '\0';
if ((prom_strcmp(name, pname) == 0) &&
(prom_strcmp(addr, paddr) == 0)) {
CIF_DBG_NODE("found dev: %s%s%s (0x%x)\n",
pname, (*paddr != '\0') ? "@" : "",
paddr, np);
break;
} else {
CIF_DBG_NODE(" no match: %s%s%s vs %s%s%s\n",
name, (*addr != '\0') ? "@" : "", addr,
pname, (*paddr != '\0') ? "@" : "", paddr);
}
np = prom_nextnode(np);
}
if (np == OBP_NONODE)
break;
if (*tp == '\0') {
device = np;
break;
}
tp++;
}
done:
if (device == OBP_BADNODE) {
CIF_DBG_NODE("device not found\n\n");
} else {
CIF_DBG_NODE("returning 0x%x\n\n", device);
}
return (device);
}
#endif