|
@@ -969,3 +969,141 @@ struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode)
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
|
|
|
+ * @fwnode: Pointer to the parent firmware node
|
|
|
+ * @prev: Previous endpoint node or %NULL to get the first
|
|
|
+ *
|
|
|
+ * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
|
|
|
+ * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case
|
|
|
+ * of success the next endpoint is returned.
|
|
|
+ */
|
|
|
+struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
|
|
|
+ struct fwnode_handle *prev)
|
|
|
+{
|
|
|
+ struct fwnode_handle *port = NULL;
|
|
|
+ struct fwnode_handle *endpoint;
|
|
|
+
|
|
|
+ if (!prev) {
|
|
|
+ do {
|
|
|
+ port = fwnode_get_next_child_node(fwnode, port);
|
|
|
+ /* Ports must have port property */
|
|
|
+ if (fwnode_property_present(port, "port"))
|
|
|
+ break;
|
|
|
+ } while (port);
|
|
|
+ } else {
|
|
|
+ port = fwnode_get_parent(prev);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!port)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ endpoint = fwnode_get_next_child_node(port, prev);
|
|
|
+ while (!endpoint) {
|
|
|
+ port = fwnode_get_next_child_node(fwnode, port);
|
|
|
+ if (!port)
|
|
|
+ break;
|
|
|
+ if (fwnode_property_present(port, "port"))
|
|
|
+ endpoint = fwnode_get_next_child_node(port, NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (endpoint) {
|
|
|
+ /* Endpoints must have "endpoint" property */
|
|
|
+ if (!fwnode_property_present(endpoint, "endpoint"))
|
|
|
+ return ERR_PTR(-EPROTO);
|
|
|
+ }
|
|
|
+
|
|
|
+ return endpoint;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * acpi_graph_get_child_prop_value - Return a child with a given property value
|
|
|
+ * @fwnode: device fwnode
|
|
|
+ * @prop_name: The name of the property to look for
|
|
|
+ * @val: the desired property value
|
|
|
+ *
|
|
|
+ * Return the port node corresponding to a given port number. Returns
|
|
|
+ * the child node on success, NULL otherwise.
|
|
|
+ */
|
|
|
+static struct fwnode_handle *acpi_graph_get_child_prop_value(
|
|
|
+ struct fwnode_handle *fwnode, const char *prop_name, unsigned int val)
|
|
|
+{
|
|
|
+ struct fwnode_handle *child;
|
|
|
+
|
|
|
+ fwnode_for_each_child_node(fwnode, child) {
|
|
|
+ u32 nr;
|
|
|
+
|
|
|
+ if (!fwnode_property_read_u32(fwnode, prop_name, &nr))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (val == nr)
|
|
|
+ return child;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint
|
|
|
+ * @fwnode: Endpoint firmware node pointing to a remote device
|
|
|
+ * @parent: Firmware node of remote port parent is filled here if not %NULL
|
|
|
+ * @port: Firmware node of remote port is filled here if not %NULL
|
|
|
+ * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
|
|
|
+ *
|
|
|
+ * Function parses remote end of ACPI firmware remote endpoint and fills in
|
|
|
+ * fields requested by the caller. Returns %0 in case of success and
|
|
|
+ * negative errno otherwise.
|
|
|
+ */
|
|
|
+int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
|
|
|
+ struct fwnode_handle **parent,
|
|
|
+ struct fwnode_handle **port,
|
|
|
+ struct fwnode_handle **endpoint)
|
|
|
+{
|
|
|
+ unsigned int port_nr, endpoint_nr;
|
|
|
+ struct acpi_reference_args args;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ memset(&args, 0, sizeof(args));
|
|
|
+ ret = acpi_node_get_property_reference(fwnode, "remote-endpoint", 0,
|
|
|
+ &args);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Always require two arguments with the reference: port and
|
|
|
+ * endpoint indices.
|
|
|
+ */
|
|
|
+ if (args.nargs != 2)
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
+ fwnode = acpi_fwnode_handle(args.adev);
|
|
|
+ port_nr = args.args[0];
|
|
|
+ endpoint_nr = args.args[1];
|
|
|
+
|
|
|
+ if (parent)
|
|
|
+ *parent = fwnode;
|
|
|
+
|
|
|
+ if (!port && !endpoint)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
|
|
|
+ if (!fwnode)
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
+ if (port)
|
|
|
+ *port = fwnode;
|
|
|
+
|
|
|
+ if (!endpoint)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint",
|
|
|
+ endpoint_nr);
|
|
|
+ if (!fwnode)
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
+ *endpoint = fwnode;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|