|
@@ -468,10 +468,11 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * acpi_data_get_property_reference - returns handle to the referenced object
|
|
|
- * @data: ACPI device data object containing the property
|
|
|
+ * __acpi_node_get_property_reference - returns handle to the referenced object
|
|
|
+ * @fwnode: Firmware node to get the property from
|
|
|
* @propname: Name of the property
|
|
|
* @index: Index of the reference to return
|
|
|
+ * @num_args: Maximum number of arguments after each reference
|
|
|
* @args: Location to store the returned reference with optional arguments
|
|
|
*
|
|
|
* Find property with @name, verifify that it is a package containing at least
|
|
@@ -482,17 +483,40 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
|
|
|
* If there's more than one reference in the property value package, @index is
|
|
|
* used to select the one to return.
|
|
|
*
|
|
|
+ * It is possible to leave holes in the property value set like in the
|
|
|
+ * example below:
|
|
|
+ *
|
|
|
+ * Package () {
|
|
|
+ * "cs-gpios",
|
|
|
+ * Package () {
|
|
|
+ * ^GPIO, 19, 0, 0,
|
|
|
+ * ^GPIO, 20, 0, 0,
|
|
|
+ * 0,
|
|
|
+ * ^GPIO, 21, 0, 0,
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * Calling this function with index %2 return %-ENOENT and with index %3
|
|
|
+ * returns the last entry. If the property does not contain any more values
|
|
|
+ * %-ENODATA is returned. The NULL entry must be single integer and
|
|
|
+ * preferably contain value %0.
|
|
|
+ *
|
|
|
* Return: %0 on success, negative error code on failure.
|
|
|
*/
|
|
|
-static int acpi_data_get_property_reference(struct acpi_device_data *data,
|
|
|
- const char *propname, size_t index,
|
|
|
- struct acpi_reference_args *args)
|
|
|
+int __acpi_node_get_property_reference(struct fwnode_handle *fwnode,
|
|
|
+ const char *propname, size_t index, size_t num_args,
|
|
|
+ struct acpi_reference_args *args)
|
|
|
{
|
|
|
const union acpi_object *element, *end;
|
|
|
const union acpi_object *obj;
|
|
|
+ struct acpi_device_data *data;
|
|
|
struct acpi_device *device;
|
|
|
int ret, idx = 0;
|
|
|
|
|
|
+ data = acpi_device_data_of_node(fwnode);
|
|
|
+ if (!data)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
|
|
|
if (ret)
|
|
|
return ret;
|
|
@@ -532,59 +556,54 @@ static int acpi_data_get_property_reference(struct acpi_device_data *data,
|
|
|
while (element < end) {
|
|
|
u32 nargs, i;
|
|
|
|
|
|
- if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
|
|
|
- return -EPROTO;
|
|
|
-
|
|
|
- ret = acpi_bus_get_device(element->reference.handle, &device);
|
|
|
- if (ret)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- element++;
|
|
|
- nargs = 0;
|
|
|
-
|
|
|
- /* assume following integer elements are all args */
|
|
|
- for (i = 0; element + i < end; i++) {
|
|
|
- int type = element[i].type;
|
|
|
+ if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
|
|
|
+ ret = acpi_bus_get_device(element->reference.handle,
|
|
|
+ &device);
|
|
|
+ if (ret)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ nargs = 0;
|
|
|
+ element++;
|
|
|
+
|
|
|
+ /* assume following integer elements are all args */
|
|
|
+ for (i = 0; element + i < end && i < num_args; i++) {
|
|
|
+ int type = element[i].type;
|
|
|
+
|
|
|
+ if (type == ACPI_TYPE_INTEGER)
|
|
|
+ nargs++;
|
|
|
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
|
|
|
+ break;
|
|
|
+ else
|
|
|
+ return -EPROTO;
|
|
|
+ }
|
|
|
|
|
|
- if (type == ACPI_TYPE_INTEGER)
|
|
|
- nargs++;
|
|
|
- else if (type == ACPI_TYPE_LOCAL_REFERENCE)
|
|
|
- break;
|
|
|
- else
|
|
|
+ if (nargs > MAX_ACPI_REFERENCE_ARGS)
|
|
|
return -EPROTO;
|
|
|
- }
|
|
|
|
|
|
- if (idx++ == index) {
|
|
|
- args->adev = device;
|
|
|
- args->nargs = nargs;
|
|
|
- for (i = 0; i < nargs; i++)
|
|
|
- args->args[i] = element[i].integer.value;
|
|
|
+ if (idx == index) {
|
|
|
+ args->adev = device;
|
|
|
+ args->nargs = nargs;
|
|
|
+ for (i = 0; i < nargs; i++)
|
|
|
+ args->args[i] = element[i].integer.value;
|
|
|
|
|
|
- return 0;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ element += nargs;
|
|
|
+ } else if (element->type == ACPI_TYPE_INTEGER) {
|
|
|
+ if (idx == index)
|
|
|
+ return -ENOENT;
|
|
|
+ element++;
|
|
|
+ } else {
|
|
|
+ return -EPROTO;
|
|
|
}
|
|
|
|
|
|
- element += nargs;
|
|
|
+ idx++;
|
|
|
}
|
|
|
|
|
|
- return -EPROTO;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * acpi_node_get_property_reference - get a handle to the referenced object.
|
|
|
- * @fwnode: Firmware node to get the property from.
|
|
|
- * @propname: Name of the property.
|
|
|
- * @index: Index of the reference to return.
|
|
|
- * @args: Location to store the returned reference with optional arguments.
|
|
|
- */
|
|
|
-int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
|
|
|
- const char *name, size_t index,
|
|
|
- struct acpi_reference_args *args)
|
|
|
-{
|
|
|
- struct acpi_device_data *data = acpi_device_data_of_node(fwnode);
|
|
|
-
|
|
|
- return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL;
|
|
|
+ return -ENODATA;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(acpi_node_get_property_reference);
|
|
|
+EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
|
|
|
|
|
|
static int acpi_data_prop_read_single(struct acpi_device_data *data,
|
|
|
const char *propname,
|