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:
parent
12cb7521c2
commit
0b757c475b
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user