of: create of_phandle_args to simplify return of phandle parsing data

of_parse_phandle_with_args() needs to return quite a bit of data.  Rather
than making each datum a separate **out_ argument, this patch creates
struct of_phandle_args to contain all the returned data and reworks the
user of the function.  This patch also enables of_parse_phandle_with_args()
to return the device node pointer for the phandle node.

This patch also ends up being fairly major surgery to
of_parse_handle_with_args().  The existing structure didn't work well
when extending to use of_phandle_args, and I discovered bugs during testing.
I also took the opportunity to rename the function to be like the
existing of_parse_phandle().

v2: - moved declaration of of_phandle_args to fix compile on non-DT builds
    - fixed incorrect index in example usage
    - fixed incorrect return code handling for empty entries

Reviewed-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
Grant Likely
2011-12-12 09:25:57 -07:00
parent 1a2d397a6e
commit 15c9a0acc3
5 changed files with 111 additions and 102 deletions

View File

@@ -824,17 +824,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
EXPORT_SYMBOL(of_parse_phandle);
/**
* of_parse_phandles_with_args - Find a node pointed by phandle in a list
* of_parse_phandle_with_args() - Find a node pointed by phandle in a list
* @np: pointer to a device tree node containing a list
* @list_name: property name that contains a list
* @cells_name: property name that specifies phandles' arguments count
* @index: index of a phandle to parse out
* @out_node: optional pointer to device_node struct pointer (will be filled)
* @out_args: optional pointer to arguments pointer (will be filled)
* @out_args: optional pointer to output arguments structure (will be filled)
*
* This function is useful to parse lists of phandles and their arguments.
* Returns 0 on success and fills out_node and out_args, on error returns
* appropriate errno value.
* Returns 0 on success and fills out_args, on error returns appropriate
* errno value.
*
* Caller is responsible to call of_node_put() on the returned out_args->node
* pointer.
*
* Example:
*
@@ -851,94 +853,96 @@ EXPORT_SYMBOL(of_parse_phandle);
* }
*
* To get a device_node of the `node2' node you may call this:
* of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
*/
int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
const char *cells_name, int index,
struct device_node **out_node,
const void **out_args)
struct of_phandle_args *out_args)
{
int ret = -EINVAL;
const __be32 *list;
const __be32 *list_end;
int size;
int cur_index = 0;
const __be32 *list, *list_end;
int size, cur_index = 0;
uint32_t count = 0;
struct device_node *node = NULL;
const void *args = NULL;
phandle phandle;
/* Retrieve the phandle list property */
list = of_get_property(np, list_name, &size);
if (!list) {
ret = -ENOENT;
goto err0;
}
if (!list)
return -EINVAL;
list_end = list + size / sizeof(*list);
/* Loop over the phandles until all the requested entry is found */
while (list < list_end) {
const __be32 *cells;
phandle phandle;
count = 0;
/*
* If phandle is 0, then it is an empty entry with no
* arguments. Skip forward to the next entry.
*/
phandle = be32_to_cpup(list++);
args = list;
if (phandle) {
/*
* Find the provider node and parse the #*-cells
* property to determine the argument length
*/
node = of_find_node_by_phandle(phandle);
if (!node) {
pr_err("%s: could not find phandle\n",
np->full_name);
break;
}
if (of_property_read_u32(node, cells_name, &count)) {
pr_err("%s: could not get %s for %s\n",
np->full_name, cells_name,
node->full_name);
break;
}
/* one cell hole in the list = <>; */
if (!phandle)
goto next;
node = of_find_node_by_phandle(phandle);
if (!node) {
pr_debug("%s: could not find phandle\n",
np->full_name);
goto err0;
/*
* Make sure that the arguments actually fit in the
* remaining property data length
*/
if (list + count > list_end) {
pr_err("%s: arguments longer than property\n",
np->full_name);
break;
}
}
cells = of_get_property(node, cells_name, &size);
if (!cells || size != sizeof(*cells)) {
pr_debug("%s: could not get %s for %s\n",
np->full_name, cells_name, node->full_name);
goto err1;
}
/*
* All of the error cases above bail out of the loop, so at
* this point, the parsing is successful. If the requested
* index matches, then fill the out_args structure and return,
* or return -ENOENT for an empty entry.
*/
if (cur_index == index) {
if (!phandle)
return -ENOENT;
list += be32_to_cpup(cells);
if (list > list_end) {
pr_debug("%s: insufficient arguments length\n",
np->full_name);
goto err1;
if (out_args) {
int i;
if (WARN_ON(count > MAX_PHANDLE_ARGS))
count = MAX_PHANDLE_ARGS;
out_args->np = node;
out_args->args_count = count;
for (i = 0; i < count; i++)
out_args->args[i] = be32_to_cpup(list++);
}
return 0;
}
next:
if (cur_index == index)
break;
of_node_put(node);
node = NULL;
args = NULL;
list += count;
cur_index++;
}
if (!node) {
/*
* args w/o node indicates that the loop above has stopped at
* the 'hole' cell. Report this differently.
*/
if (args)
ret = -EEXIST;
else
ret = -ENOENT;
goto err0;
}
if (out_node)
*out_node = node;
if (out_args)
*out_args = args;
return 0;
err1:
of_node_put(node);
err0:
pr_debug("%s failed with status %d\n", __func__, ret);
return ret;
/* Loop exited without finding a valid entry; return an error */
if (node)
of_node_put(node);
return -EINVAL;
}
EXPORT_SYMBOL(of_parse_phandles_with_args);
EXPORT_SYMBOL(of_parse_phandle_with_args);
/**
* prom_add_property - Add a property to a node