blob: be0f203586bb7c577b9ffd7d3759ed52a1474b3a [file] [log] [blame]
/* prom - prom handling routines via /dev/openprom
Copyright (C) 1996 Jakub Jelinek
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#ifdef __linux__
# include <asm/openpromio.h>
#elif defined (__sun__)
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/openpromio.h>
# include <limits.h>
#else
# error "Unknown system"
#endif
#include <fcntl.h>
static struct openpromio *oi;
static char buffer[2048 + sizeof (oi->oprom_size)];
static int prom_root_node = 0;
static int fd;
static int current_node;
static int previous_node;
static int action;
static int parent_node;
#define SETSIZE oi->oprom_size = 2048;
int prom_init (void)
{
if ((fd = open ("/dev/openprom", O_RDONLY)) < 0 &&
(fd = open ("/dev/misc/openprom", O_RDONLY)) < 0)
return -1;
oi = (struct openpromio *)buffer;
SETSIZE
*(int *)(oi->oprom_array) = 0;
if (ioctl (fd, OPROMNEXT, (void *)oi) >= 0) {
prom_root_node = *(int *)(oi->oprom_array);
current_node = prom_root_node;
previous_node = 0;
parent_node = 0;
action = 0;
return 0;
}
return -1;
}
int prom_set_root_node (void)
{
SETSIZE
*(int *)(oi->oprom_array) = 0;
if (ioctl (fd, OPROMNEXT, (void *)oi) >= 0) {
current_node = prom_root_node;
previous_node = 0;
parent_node = 0;
action = 0;
return 0;
}
return -1;
}
int prom_search_siblings (char *name)
{
int node = current_node;
for (;;) {
SETSIZE
strcpy (oi->oprom_array, "name");
if (ioctl (fd, OPROMGETPROP, (void *)oi) < 0)
return -1;
if (!oi->oprom_size) return -1;
if (!strcmp (oi->oprom_array, name))
return node;
SETSIZE
*(int *)(oi->oprom_array) = node;
if (ioctl (fd, OPROMNEXT, (void *)oi) < 0 || !(*(int *)(oi->oprom_array)))
return -1;
if (!(*(int *)(oi->oprom_array)) || !oi->oprom_size) return -1;
node = *(int *)(oi->oprom_array);
previous_node = current_node;
current_node = node;
action = 0;
}
}
int prom_next_sibling (void)
{
SETSIZE
*(int *)(oi->oprom_array) = current_node;
if (ioctl (fd, OPROMNEXT, (void *)oi) < 0 || !(*(int *)(oi->oprom_array)))
return -1;
if (!(*(int *)(oi->oprom_array)) || !oi->oprom_size) return -1;
previous_node = current_node;
current_node = *(int *)(oi->oprom_array);
action = 0;
return 0;
}
int prom_getchild (void)
{
SETSIZE
*(int *)(oi->oprom_array) = current_node;
if (ioctl (fd, OPROMCHILD, (void *)oi) >= 0) {
if (!(*(int *)(oi->oprom_array)) || !oi->oprom_size) return -1;
parent_node = current_node;
current_node = *(int *)(oi->oprom_array);
action = 1;
previous_node = parent_node;
return 0;
}
return -1;
}
char *prom_getstring (char *name)
{
SETSIZE
strcpy (oi->oprom_array, name);
if (ioctl (fd, OPROMGETPROP, (void *)oi) >= 0) {
if (!oi->oprom_size) return 0;
return oi->oprom_array;
}
return 0;
}
char *prom_getopt (char *name)
{
SETSIZE
strcpy (oi->oprom_array, name);
if (ioctl (fd, OPROMGETOPT, (void *)oi) >= 0) {
if (!oi->oprom_size) return 0;
return oi->oprom_array;
}
return 0;
}
#ifdef __sun__
int prom_getversion()
{
int i;
char arch[10], *p;
SETSIZE
if (ioctl (fd, OPROMGETVERSION, (void *)oi) >= 0) {
p = strchr (oi->oprom_array, '.');
if (p && p > oi->oprom_array && p[-1] >= '0' && p[-1] <= '9' &&
(p == oi->oprom_array + 1 || p[-2] < '0' || p[-2] > '9')) {
switch (p[-1]) {
case '0':
case '1': return 0;
case '2':
case '3': return 2;
}
}
printf ("Please report version string '%s' to jj@sunsite.mff.cuni.cz\n", oi->oprom_array);
}
/* Let's try brute force :)) */
if (prom_set_root_node () < 0) return -1;
*arch = 0;
if ((p = prom_getstring ("compatability")) != 0)
strcpy (arch, p);
else if ((p = prom_getstring ("compatible")) != 0)
strcpy (arch, p);
if (*arch && (!strcmp (arch, "sun4m") || !strcmp (arch, "sun4d") || !strcmp (arch, "sun4e")))
return 2;
else if (!*arch) {
p = prom_getopt ("boot-from");
if (p && (!strncmp (p, "sd(", 3) ||
!strncmp (p, "le(", 3) ||
!strncmp (p, "ie(", 3) ||
!strncmp (p, "fd(", 3) ||
!strncmp (p, "xd(", 3)))
return 0;
} else {
if (prom_getchild () < 0) return -1;
if (prom_search_siblings ("aliases") != -1) {
p = prom_getstring ("disk");
if (!p) p = prom_getstring ("net");
if (!p) p = prom_getstring ("disk0");
if (p && *p == '/') {
if (!strncmp (p + 1, "iommu@", 6) || !strncmp (p + 1, "iommu/", 6) ||
!strncmp (p + 1, "sbus@", 5) || !strncmp (p + 1, "sbus/", 5) ||
!strncmp (p + 1, "espdma@", 7) || !strncmp (p + 1, "espdma/", 7) ||
!strncmp (p + 1, "esp@", 4) || !strncmp (p + 1, "esp/", 4) ||
!strncmp (p + 1, "io-unit@", 8) || !strncmp (p + 1, "io-unit/", 8))
return 2;
}
}
}
return -1;
}
#endif