Move to more hookless approach in IEEE1275 devices handling.

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-03-02 23:51:19 +01:00
parent 99fcda8a7b
commit 6e4146c41e
9 changed files with 390 additions and 353 deletions

View file

@ -32,184 +32,227 @@ enum grub_ieee1275_parse_type
GRUB_PARSE_DEVICE_TYPE
};
/* Walk children of 'devpath', calling hook for each. */
int
grub_children_iterate (const char *devpath,
int (*hook) (struct grub_ieee1275_devalias *alias))
static int
fill_alias (struct grub_ieee1275_devalias *alias)
{
grub_ssize_t actual;
if (grub_ieee1275_get_property (alias->phandle, "device_type", alias->type,
IEEE1275_MAX_PROP_LEN, &actual))
alias->type[0] = 0;
if (alias->parent_dev == alias->phandle)
return 0;
if (grub_ieee1275_package_to_path (alias->phandle, alias->path,
IEEE1275_MAX_PATH_LEN, &actual))
return 0;
if (grub_strcmp (alias->parent_path, alias->path) == 0)
return 0;
if (grub_ieee1275_get_property (alias->phandle, "name", alias->name,
IEEE1275_MAX_PROP_LEN, &actual))
return 0;
grub_dprintf ("devalias", "device path=%s\n", alias->path);
return 1;
}
void
grub_ieee1275_devalias_free (struct grub_ieee1275_devalias *alias)
{
grub_free (alias->name);
grub_free (alias->type);
grub_free (alias->path);
grub_free (alias->parent_path);
alias->name = 0;
alias->type = 0;
alias->path = 0;
alias->parent_path = 0;
alias->phandle = GRUB_IEEE1275_PHANDLE_INVALID;
}
void
grub_ieee1275_children_peer (struct grub_ieee1275_devalias *alias)
{
while (grub_ieee1275_peer (alias->phandle, &alias->phandle) != -1)
if (fill_alias (alias))
return;
grub_ieee1275_devalias_free (alias);
}
void
grub_ieee1275_children_first (const char *devpath,
struct grub_ieee1275_devalias *alias)
{
grub_ieee1275_phandle_t dev;
grub_ieee1275_phandle_t child;
char *childtype, *childpath;
char *childname;
int ret = 0;
grub_dprintf ("devalias", "iterating children of %s\n",
devpath);
alias->name = 0;
alias->path = 0;
alias->parent_path = 0;
alias->type = 0;
if (grub_ieee1275_finddevice (devpath, &dev))
return 0;
return;
if (grub_ieee1275_child (dev, &child))
return 0;
if (grub_ieee1275_child (dev, &alias->phandle))
return;
childtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!childtype)
return 0;
childpath = grub_malloc (IEEE1275_MAX_PATH_LEN);
if (!childpath)
alias->type = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!alias->type)
return;
alias->path = grub_malloc (IEEE1275_MAX_PATH_LEN);
if (!alias->path)
{
grub_free (childtype);
return 0;
grub_free (alias->type);
return;
}
childname = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!childname)
alias->parent_path = grub_strdup (devpath);
if (!alias->parent_path)
{
grub_free (childpath);
grub_free (childtype);
return 0;
grub_free (alias->path);
grub_free (alias->type);
return;
}
do
alias->name = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!alias->name)
{
struct grub_ieee1275_devalias alias;
grub_ssize_t actual;
grub_free (alias->path);
grub_free (alias->type);
grub_free (alias->parent_path);
return;
}
if (!fill_alias (alias))
grub_ieee1275_children_peer (alias);
}
if (grub_ieee1275_get_property (child, "device_type", childtype,
IEEE1275_MAX_PROP_LEN, &actual))
childtype[0] = 0;
static int
iterate_recursively (const char *path,
int (*hook) (struct grub_ieee1275_devalias *alias))
{
struct grub_ieee1275_devalias alias;
int ret = 0;
if (dev == child)
continue;
if (grub_ieee1275_package_to_path (child, childpath,
IEEE1275_MAX_PATH_LEN, &actual))
continue;
if (grub_strcmp (devpath, childpath) == 0)
continue;
if (grub_ieee1275_get_property (child, "name", childname,
IEEE1275_MAX_PROP_LEN, &actual))
continue;
alias.type = childtype;
alias.path = childpath;
alias.name = childname;
FOR_IEEE1275_DEVCHILDREN(path, alias)
{
ret = hook (&alias);
if (ret)
break;
ret = iterate_recursively (alias.path, hook);
if (ret)
break;
}
while (grub_ieee1275_peer (child, &child) != -1);
grub_free (childname);
grub_free (childpath);
grub_free (childtype);
grub_ieee1275_devalias_free (&alias);
return ret;
}
int
grub_ieee1275_devices_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
{
auto int it_through (struct grub_ieee1275_devalias *alias);
int it_through (struct grub_ieee1275_devalias *alias)
{
if (hook (alias))
return 1;
return grub_children_iterate (alias->path, it_through);
}
return grub_children_iterate ("/", it_through);
return iterate_recursively ("/", hook);
}
/* Iterate through all device aliases. This function can be used to
find a device of a specific type. */
int
grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
void
grub_ieee1275_devalias_init_iterator (struct grub_ieee1275_devalias *alias)
{
grub_ieee1275_phandle_t aliases;
char *aliasname, *devtype;
grub_ssize_t actual;
struct grub_ieee1275_devalias alias;
int ret = 0;
alias->name = 0;
alias->path = 0;
alias->parent_path = 0;
alias->type = 0;
if (grub_ieee1275_finddevice ("/aliases", &aliases))
return 0;
grub_dprintf ("devalias", "iterating aliases\n");
aliasname = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!aliasname)
return 0;
devtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!devtype)
if (grub_ieee1275_finddevice ("/aliases", &alias->parent_dev))
return;
alias->name = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!alias->name)
return;
alias->type = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!alias->type)
{
grub_free (aliasname);
return 0;
grub_free (alias->name);
alias->name = 0;
return;
}
/* Find the first property. */
aliasname[0] = '\0';
alias->name[0] = '\0';
}
while (grub_ieee1275_next_property (aliases, aliasname, aliasname) > 0)
int
grub_ieee1275_devalias_next (struct grub_ieee1275_devalias *alias)
{
if (!alias->name)
return 0;
while (1)
{
grub_ieee1275_phandle_t dev;
grub_ssize_t pathlen;
char *devpath;
grub_ssize_t actual;
grub_dprintf ("devalias", "devalias name = %s\n", aliasname);
if (alias->path)
{
grub_free (alias->path);
alias->path = 0;
}
if (grub_ieee1275_next_property (alias->parent_dev, alias->name,
alias->name) <= 0)
{
grub_ieee1275_devalias_free (alias);
return 0;
}
grub_ieee1275_get_property_length (aliases, aliasname, &pathlen);
grub_dprintf ("devalias", "devalias name = %s\n", alias->name);
grub_ieee1275_get_property_length (alias->parent_dev, alias->name, &pathlen);
/* The property `name' is a special case we should skip. */
if (!grub_strcmp (aliasname, "name"))
if (grub_strcmp (alias->name, "name") == 0)
continue;
/* Sun's OpenBoot often doesn't zero terminate the device alias
strings, so we will add a NULL byte at the end explicitly. */
pathlen += 1;
devpath = grub_malloc (pathlen + 1);
if (! devpath)
alias->path = grub_malloc (pathlen + 1);
if (! alias->path)
{
grub_free (devtype);
grub_free (aliasname);
grub_ieee1275_devalias_free (alias);
return 0;
}
if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen,
&actual) || actual < 0)
if (grub_ieee1275_get_property (alias->parent_dev, alias->name, alias->path,
pathlen, &actual) || actual < 0)
{
grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
goto nextprop;
grub_dprintf ("devalias", "get_property (%s) failed\n", alias->name);
grub_free (alias->path);
continue;
}
if (actual > pathlen)
actual = pathlen;
devpath[actual] = '\0';
devpath[pathlen] = '\0';
alias->path[actual] = '\0';
alias->path[pathlen] = '\0';
if (grub_ieee1275_finddevice (devpath, &dev))
if (grub_ieee1275_finddevice (alias->path, &alias->phandle))
{
grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath);
goto nextprop;
grub_dprintf ("devalias", "finddevice (%s) failed\n", alias->path);
grub_free (alias->path);
alias->path = 0;
continue;
}
if (grub_ieee1275_get_property (dev, "device_type", devtype,
if (grub_ieee1275_get_property (alias->phandle, "device_type", alias->type,
IEEE1275_MAX_PROP_LEN, &actual))
{
/* NAND device don't have device_type property. */
devtype[0] = 0;
alias->type[0] = 0;
}
alias.name = aliasname;
alias.path = devpath;
alias.type = devtype;
ret = hook (&alias);
nextprop:
grub_free (devpath);
if (ret)
break;
return 1;
}
grub_free (devtype);
grub_free (aliasname);
return ret;
}
/* Call the "map" method of /chosen/mmu. */
@ -286,37 +329,28 @@ grub_ieee1275_get_devargs (const char *path)
}
/* Get the device path of the Open Firmware node name `path'. */
static char *
char *
grub_ieee1275_get_devname (const char *path)
{
char *colon = grub_strchr (path, ':');
char *newpath = 0;
int pathlen = grub_strlen (path);
auto int match_alias (struct grub_ieee1275_devalias *alias);
int match_alias (struct grub_ieee1275_devalias *curalias)
{
/* briQ firmware can change capitalization in /chosen/bootpath. */
if (grub_strncasecmp (curalias->path, path, pathlen) == 0
&& curalias->path[pathlen] == 0)
{
newpath = grub_strdup (curalias->name);
return 1;
}
return 0;
}
struct grub_ieee1275_devalias curalias;
if (colon)
pathlen = (int)(colon - path);
/* Try to find an alias for this device. */
grub_devalias_iterate (match_alias);
FOR_IEEE1275_DEVALIASES (curalias)
/* briQ firmware can change capitalization in /chosen/bootpath. */
if (grub_strncasecmp (curalias.path, path, pathlen) == 0
&& curalias.path[pathlen] == 0)
{
char *newpath;
newpath = grub_strdup (curalias.name);
grub_ieee1275_devalias_free (&curalias);
return newpath;
}
if (! newpath)
newpath = grub_strndup (path, pathlen);
return newpath;
return grub_strndup (path, pathlen);
}
static char *