#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/openpromio.h>
#include <libintl.h>
#include "pdevinfo.h"
#include "display.h"
#include "pdevinfo_sun4u.h"
static int prom_fd;
extern char *progname;
extern char *promdev;
extern void getppdata();
extern void printppdata();
#ifdef DPRINT
static char vdebug_flag = 1;
#define dprintf if (vdebug_flag) printf
static void dprint_dev_info(caddr_t, dev_info_t *);
#endif
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
int
_error(char *fmt, ...)
{
int saved_errno;
va_list ap;
extern int errno;
saved_errno = errno;
if (progname)
(void) fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
(void) vfprintf(stderr, fmt, ap);
va_end(ap);
(void) fprintf(stderr, ": ");
errno = saved_errno;
perror("");
return (2);
}
int
is_openprom(void)
{
Oppbuf oppbuf;
register struct openpromio *opp = &(oppbuf.opp);
register unsigned int i;
opp->oprom_size = MAXVALSIZE;
if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
exit(_error("OPROMGETCONS"));
i = (unsigned int)((unsigned char)opp->oprom_array[0]);
return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
}
void
dump_node(Prom_node *node)
{
Oppbuf oppbuf;
register struct openpromio *opp = &oppbuf.opp;
Prop *prop = NULL;
StaticProp *temp;
node->props = NULL;
(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
if ((temp = malloc(sizeof (StaticProp))) == NULL) {
perror("malloc");
exit(1);
}
opp->oprom_size = MAXPROPSIZE;
while (opp->oprom_size != 0) {
Prop *new;
int i;
char *tempp, *newp;
opp->oprom_size = MAXPROPSIZE;
if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0)
exit(_error("OPROMNXTPROP"));
if (opp->oprom_size != 0) {
temp->name.opp.oprom_size = opp->oprom_size;
(void) strcpy(temp->name.opp.oprom_array,
opp->oprom_array);
(void) strcpy(temp->value.opp.oprom_array,
temp->name.opp.oprom_array);
getpropval(&temp->value.opp);
temp->size = temp->value.opp.oprom_size;
if ((new = malloc(sizeof (Prop))) == NULL) {
perror("malloc");
exit(1);
}
new->name.opp.oprom_size = temp->name.opp.oprom_size;
if ((new->name.opp.oprom_array =
malloc(new->name.opp.oprom_size)) == NULL) {
perror("malloc");
exit(1);
}
(void) strcpy(new->name.opp.oprom_array,
temp->name.opp.oprom_array);
new->name.opp.holds_array = 1;
new->value.opp.oprom_size = temp->value.opp.oprom_size;
if (*(temp->value.opp.oprom_array) == '\0') {
for (i = 0; i < OPROM_NODE_SIZE; i++)
new->value.opp.oprom_node[i] =
*(&temp->value.opp.oprom_node+i);
new->value.opp.holds_array = 0;
} else {
if ((new->value.opp.oprom_array =
malloc(new->value.opp.oprom_size))
== NULL) {
perror("malloc");
exit(1);
}
newp = new->value.opp.oprom_array;
tempp = temp->value.opp.oprom_array;
for (i = new->value.opp.oprom_size; i > 0; i--)
*newp++ = *tempp++;
new->value.opp.holds_array = 1;
}
new->size = temp->size;
if (node->props == NULL)
node->props = new;
else if (prop != NULL)
prop->next = new;
prop = new;
prop->next = NULL;
}
}
free(temp);
}
int
promopen(int oflag)
{
while (1) {
if ((prom_fd = open(promdev, oflag)) < 0) {
if (errno == EAGAIN) {
(void) sleep(5);
continue;
}
if (errno == ENXIO)
return (-1);
exit(_error(dgettext(TEXT_DOMAIN, "cannot open %s"),
promdev));
} else
return (0);
}
}
void
promclose(void)
{
if (close(prom_fd) < 0)
exit(_error(dgettext(TEXT_DOMAIN, "close error on %s"),
promdev));
}
void
getpropval(struct openpromio *opp)
{
opp->oprom_size = MAXVALSIZE;
if (ioctl(prom_fd, OPROMGETPROP, opp) < 0)
exit(_error("OPROMGETPROP"));
}
int
next(int id)
{
Oppbuf oppbuf;
register struct openpromio *opp = &(oppbuf.opp);
int *ip = (int *)(opp->oprom_array);
(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
opp->oprom_size = MAXVALSIZE;
*ip = id;
if (ioctl(prom_fd, OPROMNEXT, opp) < 0)
return (_error("OPROMNEXT"));
return (*(int *)opp->oprom_array);
}
int
child(int id)
{
Oppbuf oppbuf;
register struct openpromio *opp = &(oppbuf.opp);
int *ip = (int *)(opp->oprom_array);
(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
opp->oprom_size = MAXVALSIZE;
*ip = id;
if (ioctl(prom_fd, OPROMCHILD, opp) < 0)
return (_error("OPROMCHILD"));
return (*(int *)opp->oprom_array);
}
int
has_board_num(Prom_node *node)
{
Prop *prop = node->props;
while (prop != NULL) {
if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
return (1);
prop = prop->next;
}
return (0);
}
int
get_board_num(Prom_node *node)
{
Prop *prop = node->props;
while (prop != NULL) {
if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
return (prop->value.opp.oprom_node[0]);
prop = prop->next;
}
return (-1);
}
Board_node *
find_board(Sys_tree *root, int board)
{
Board_node *bnode = root->bd_list;
while ((bnode != NULL) && (board != bnode->board_num))
bnode = bnode->next;
return (bnode);
}
Board_node *
insert_board(Sys_tree *root, int board)
{
Board_node *bnode;
Board_node *temp = root->bd_list;
if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
perror("malloc");
exit(1);
}
bnode->nodes = NULL;
bnode->next = NULL;
bnode->board_num = board;
if (temp == NULL)
root->bd_list = bnode;
else if (temp->board_num > board) {
bnode->next = temp;
root->bd_list = bnode;
} else {
while ((temp->next != NULL) && (board > temp->next->board_num))
temp = temp->next;
bnode->next = temp->next;
temp->next = bnode;
}
root->board_cnt++;
return (bnode);
}
char *
get_node_name(Prom_node *pnode)
{
Prop *prop;
if (pnode == NULL) {
return (NULL);
}
prop = pnode->props;
while (prop != NULL) {
if (strcmp("name", prop->name.opp.oprom_array) == 0)
return (prop->value.opp.oprom_array);
prop = prop->next;
}
return (NULL);
}
char *
get_node_type(Prom_node *pnode)
{
Prop *prop;
if (pnode == NULL) {
return (NULL);
}
prop = pnode->props;
while (prop != NULL) {
if (strcmp("device_type", prop->name.opp.oprom_array) == 0)
return (prop->value.opp.oprom_array);
prop = prop->next;
}
return (NULL);
}
Prom_node *
dev_find_node(Prom_node *root, char *name)
{
Prom_node *node;
node = dev_find_node_by_type(root, "name", name);
return (node);
}
Prom_node *
dev_next_node(Prom_node *root, char *name)
{
Prom_node *node;
node = dev_next_node_by_type(root, "name", name);
return (node);
}
Prom_node *
dev_find_type(Prom_node *root, char *type)
{
Prom_node *node;
node = dev_find_node_by_type(root, "device_type", type);
return (node);
}
Prom_node *
dev_next_type(Prom_node *root, char *type)
{
Prom_node *node;
node = dev_next_node_by_type(root, "device_type", type);
return (node);
}
Prom_node *
find_failed_node(Prom_node * root)
{
Prom_node *pnode;
if (root == NULL)
return (NULL);
if (node_failed(root)) {
return (root);
}
if ((pnode = find_failed_node(root->child)) != NULL)
return (pnode);
if ((pnode = find_failed_node(root->sibling)) != NULL)
return (pnode);
return (NULL);
}
Prom_node *
next_failed_node(Prom_node * root)
{
Prom_node *pnode;
Prom_node *parent;
if (root == NULL)
return (NULL);
if ((pnode = find_failed_node(root->child)) != NULL) {
return (pnode);
}
if ((pnode = find_failed_node(root->sibling)) != NULL) {
return (pnode);
}
parent = root->parent;
while (parent != NULL) {
if ((pnode = find_failed_node(parent->sibling)) != NULL)
return (pnode);
else
parent = parent->parent;
}
return (NULL);
}
int
node_failed(Prom_node *node)
{
return (node_status(node, "fail"));
}
int
node_status(Prom_node *node, char *status)
{
void *value;
if (status == NULL)
return (0);
if ((value = get_prop_val(find_prop(node, "status"))) != NULL) {
if ((value != NULL) && strstr((char *)value, status))
return (1);
}
return (0);
}
void *
get_prop_val(Prop *prop)
{
if (prop == NULL)
return (NULL);
if (prop->value.opp.holds_array)
return ((void *)(prop->value.opp.oprom_array));
else
return ((void *)(&prop->value.opp.oprom_node[0]));
}
Prop *
find_prop(Prom_node *pnode, char *name)
{
Prop *prop;
if (pnode == NULL) {
return (NULL);
}
if (pnode->props == NULL) {
(void) printf("%s", dgettext(TEXT_DOMAIN, "Prom node has "
"no properties\n"));
return (NULL);
}
prop = pnode->props;
while ((prop != NULL) && (strcmp(prop->name.opp.oprom_array, name)))
prop = prop->next;
return (prop);
}
void
add_node(Sys_tree *root, Prom_node *pnode)
{
int board;
Board_node *bnode;
Prom_node *p;
if ((board = get_board_num(pnode)) == -1) {
board = 0;
}
if ((bnode = find_board(root, board)) == NULL) {
bnode = insert_board(root, board);
bnode->board_type = UNKNOWN_BOARD;
}
pnode->sibling = NULL;
if (bnode->nodes == NULL)
bnode->nodes = pnode;
else {
p = bnode->nodes;
while (p->sibling != NULL)
p = p->sibling;
p->sibling = pnode;
}
}
Prom_node *
find_device(Board_node *board, int id, char *name)
{
Prom_node *pnode;
int mask;
pnode = dev_find_node(board->nodes, name);
mask = 0x1F;
while (pnode != NULL) {
if ((get_id(pnode) & mask) == id)
return (pnode);
pnode = dev_next_node(pnode, name);
}
return (NULL);
}
Prom_node *
dev_find_node_by_type(Prom_node *root, char *type, char *property)
{
Prom_node *node;
char *type_prop;
if (root == NULL || property == NULL)
return (NULL);
type_prop = (char *)get_prop_val(find_prop(root, type));
if (type_prop != NULL) {
if (strcmp(type_prop, property) == 0) {
return (root);
}
}
if ((node = dev_find_node_by_type(root->child, type,
property)) != NULL)
return (node);
if ((node = dev_find_node_by_type(root->sibling, type,
property)) != NULL)
return (node);
return (NULL);
}
Prom_node *
dev_next_node_by_type(Prom_node *root, char *type, char *property)
{
Prom_node *node;
if (root == NULL || property == NULL)
return (NULL);
if ((node = dev_find_node_by_type(root->child, type,
property)) != NULL)
return (node);
if ((node = dev_find_node_by_type(root->sibling, type,
property)) != NULL)
return (node);
if ((node = dev_find_node_by_type(root->parent->sibling,
type, property)) != NULL)
return (node);
return (NULL);
}
Prom_node *
dev_find_node_by_compatible(Prom_node *root, char *compatible)
{
Prom_node *node;
Prop *prop;
char *compatible_array;
int size, nbytes;
if (root == NULL || compatible == NULL)
return (NULL);
if ((prop = find_prop(root, "compatible")) != NULL &&
(compatible_array = (char *)get_prop_val(prop)) != NULL) {
for (size = prop->size; size >= 0; size -= nbytes) {
if (strcmp(compatible_array, compatible) == 0)
return (root);
nbytes = strlen(compatible_array) + 1;
compatible_array += nbytes;
}
}
node = dev_find_node_by_compatible(root->child, compatible);
if (node != NULL)
return (node);
return (dev_find_node_by_compatible(root->sibling, compatible));
}
Prom_node *
dev_next_node_by_compatible(Prom_node *root, char *compatible)
{
Prom_node *node;
if (root == NULL || compatible == NULL)
return (NULL);
node = dev_find_node_by_compatible(root->child, compatible);
if (node != NULL)
return (node);
node = dev_find_node_by_compatible(root->sibling, compatible);
if (node != NULL)
return (node);
return (dev_find_node_by_compatible(root->parent->sibling, compatible));
}