OFW: Add helper functions for parsing xref based lists.

By using this functions, we can parse a list of tuples, each of them holds
xref and variable number of values.
This kind of list is used in DT for clocks, gpios, resets ...

Discussed with:	ian, nwhitehorn
Approved by:	kib (mentor)
Differential Revision: https://reviews.freebsd.org/D4316
This commit is contained in:
Michal Meloun 2015-12-13 08:17:49 +00:00
parent 12cb7521c2
commit 0b757c475b
2 changed files with 140 additions and 0 deletions

View File

@ -607,3 +607,134 @@ ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node)
return (retval);
}
/*
* Parse property that contain list of xrefs and values
* (like standard "clocks" and "resets" properties)
* Input arguments:
* node - consumers device node
* list_name - name of parsed list - "clocks"
* cells_name - name of size property - "#clock-cells"
* Output arguments:
* producer - handle of producer
* ncells - number of cells in result
* cells - array of decoded cells
*/
int
ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
const char *cells_name, int idx, phandle_t *producer, int *ncells,
pcell_t **cells)
{
phandle_t pnode;
phandle_t *elems;
uint32_t pcells;
int rv, i, j, nelems, cnt;
elems = NULL;
nelems = OF_getencprop_alloc(node, list_name, sizeof(*elems),
(void **)&elems);
if (nelems <= 0)
return (ENOENT);
rv = ENOENT;
for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) {
pnode = elems[i++];
if (OF_getencprop(OF_node_from_xref(pnode),
cells_name, &pcells, sizeof(pcells)) == -1) {
printf("Missing %s property\n", cells_name);
rv = ENOENT;
break;
}
if ((i + pcells) > nelems) {
printf("Invalid %s property value <%d>\n", cells_name,
pcells);
rv = ERANGE;
break;
}
if (cnt == idx) {
*cells= malloc(pcells * sizeof(**cells), M_OFWPROP,
M_WAITOK);
*producer = pnode;
*ncells = pcells;
for (j = 0; j < pcells; j++)
(*cells)[j] = elems[i + j];
rv = 0;
break;
}
}
if (elems != NULL)
free(elems, M_OFWPROP);
return (rv);
}
/*
* Find index of string in string list property (case sensitive).
*/
int
ofw_bus_find_string_index(phandle_t node, const char *list_name,
const char *name, int *idx)
{
char *elems;
int rv, i, cnt, nelems;
elems = NULL;
nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems);
if (nelems <= 0)
return (ENOENT);
rv = ENOENT;
for (i = 0, cnt = 0; i < nelems; cnt++) {
if (strcmp(elems + i, name) == 0) {
*idx = cnt;
rv = 0;
break;
}
i += strlen(elems + i) + 1;
}
if (elems != NULL)
free(elems, M_OFWPROP);
return (rv);
}
/*
* Create zero terminated array of strings from string list property.
*/
int
ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
const char ***array)
{
char *elems, *tptr;
int i, cnt, nelems, len;
elems = NULL;
nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems);
if (nelems <= 0)
return (nelems);
/* Count number of strings. */
for (i = 0, cnt = 0; i < nelems; cnt++)
i += strlen(elems + i) + 1;
/* Allocate space for arrays and all strings. */
*array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP,
M_WAITOK);
/* Get address of first string. */
tptr = (char *)(*array + cnt);
/* Copy strings. */
memcpy(tptr, elems, nelems);
free(elems, M_OFWPROP);
/* Fill string pointers. */
for (i = 0, cnt = 0; i < nelems; cnt++) {
len = strlen(tptr + i) + 1;
*array[cnt] = tptr;
i += len;
tptr += len;
}
*array[cnt] = 0;
return (cnt);
}

View File

@ -110,4 +110,13 @@ phandle_t ofw_bus_find_child(phandle_t, const char *);
/* Helper routine to find a device_t child matchig a given phandle_t */
device_t ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node);
/* Helper routines for parsing lists */
int ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
const char *cells_name, int idx, phandle_t *producer, int *ncells,
pcell_t **cells);
int ofw_bus_find_string_index(phandle_t node, const char *list_name,
const char *name, int *idx);
int ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
const char ***array);
#endif /* !_DEV_OFW_OFW_BUS_SUBR_H_ */