Generic device properties framework updates for v4.12-rc1
- Extend the ACPI _DSD properties code and the generic device properties framework to support the concept of remote endponts (Mika Westerberg, Sakari Ailus). - Document the support for ports and endpoints in _DSD properties and extend the generic device properties framework to make it more suitable for the handling of ports and endpoints (Sakari Ailus). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJZB5jZAAoJEILEb/54YlRxPU0P/34yV01FwLCnOGDWACRq62Iv yfW+uSb3x679sk4DBZfmuruE7N96fWtXS+Pbt+a1A62md421r9iQCKSh7o9Q8lcX hUxJt/6NF6hbOygpvDxUXA3XpsV37hKUtVAlqln95JiwgFERBm9TT7GqmTutZaue vbidgp0f2H75eM4pzhLCl7xgjSuwNe7GU60uVtLUSREoaGtylkcjNjdJmLFF518K uMDttQOwX7c0S3/IctAuIax4se6xFXMw0AfiRJA5KoLRFRIkrMVb+YlaqhaITD9t SnjjBQoBQ2z09hLdTQrw0k2qfSkqGx34Qw/JikFLpyUpvJT5tOhtCgR6czLHDkN2 Cz22xWfiHWQS8IH14urxdwhIiLI+VRcrU5GdlP9Rwj9wQCF8W2nWujg6X7gyb2Sg cV82pAbD9wXVPXcZddbXSOhiGExQLlD6EAQ/+Dw73LPU4biV8aBB4GBalrKeHUIq SiYaSvHdwHCv0LxTM3aWoxE2qLh0g+8e1K9vJQnh8BQM6q14qQeWvbq5Gmv+T5LZ FDT/LUCMUx85yiaJ+PU4DFiQ1kutRxzUqtUrFRUCWdHwKd6JnNnEcXM4ouwelJsf 8PuFOLzHLzXXfAbx7EJP7daBbrOmhJs7Y/9UzTnJSquO/1F+k3a26uPfJP2349I+ IfNWjnjjY3QRLYwLKfqF =Ihme -----END PGP SIGNATURE----- Merge tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull generic device properties framework updates from Rafael Wysocki: "These add support for the ports and endpoints concepts, based on the existing DT support for them, to the generic device properties framework and update the ACPI _DSD properties code to recognize ports and endpoints accordingly. Specifics: - Extend the ACPI _DSD properties code and the generic device properties framework to support the concept of remote endponts (Mika Westerberg, Sakari Ailus). - Document the support for ports and endpoints in _DSD properties and extend the generic device properties framework to make it more suitable for the handling of ports and endpoints (Sakari Ailus)" * tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: device property: Read strings using string array reading functions device property: fwnode_property_read_string_array() returns nr of strings device property: Fix reading pset strings using array access functions device property: fwnode_property_read_string_array() may return -EILSEQ ACPI / DSD: Document references, ports and endpoints device property: Add fwnode_get_next_parent() device property: Add support for fwnode endpoints device property: Make dev_fwnode() public of: Add of_fwnode_handle() to convert device nodes to fwnode_handle device property: Add fwnode_handle_get() device property: Add support for remote endpoints ACPI / property: Add support for remote endpoints device property: Add fwnode_get_named_child_node() ACPI / property: Add fwnode_get_next_child_node() device property: Add fwnode_get_parent() ACPI / property: Add possiblity to retrieve parent firmware node
This commit is contained in:
Коммит
5fab10041b
|
@ -0,0 +1,162 @@
|
|||
Graphs
|
||||
|
||||
|
||||
_DSD
|
||||
----
|
||||
|
||||
_DSD (Device Specific Data) [7] is a predefined ACPI device
|
||||
configuration object that can be used to convey information on
|
||||
hardware features which are not specifically covered by the ACPI
|
||||
specification [1][6]. There are two _DSD extensions that are relevant
|
||||
for graphs: property [4] and hierarchical data extensions [5]. The
|
||||
property extension provides generic key-value pairs whereas the
|
||||
hierarchical data extension supports nodes with references to other
|
||||
nodes, forming a tree. The nodes in the tree may contain properties as
|
||||
defined by the property extension. The two extensions together provide
|
||||
a tree-like structure with zero or more properties (key-value pairs)
|
||||
in each node of the tree.
|
||||
|
||||
The data structure may be accessed at runtime by using the device_*
|
||||
and fwnode_* functions defined in include/linux/fwnode.h .
|
||||
|
||||
Fwnode represents a generic firmware node object. It is independent on
|
||||
the firmware type. In ACPI, fwnodes are _DSD hierarchical data
|
||||
extensions objects. A device's _DSD object is represented by an
|
||||
fwnode.
|
||||
|
||||
The data structure may be referenced to elsewhere in the ACPI tables
|
||||
by using a hard reference to the device itself and an index to the
|
||||
hierarchical data extension array on each depth.
|
||||
|
||||
|
||||
Ports and endpoints
|
||||
-------------------
|
||||
|
||||
The port and endpoint concepts are very similar to those in Devicetree
|
||||
[3]. A port represents an interface in a device, and an endpoint
|
||||
represents a connection to that interface.
|
||||
|
||||
All port nodes are located under the device's "_DSD" node in the
|
||||
hierarchical data extension tree. The property extension related to
|
||||
each port node must contain the key "port" and an integer value which
|
||||
is the number of the port. The object it refers to should be called "PRTX",
|
||||
where "X" is the number of the port.
|
||||
|
||||
Further on, endpoints are located under the individual port nodes. The
|
||||
first hierarchical data extension package list entry of the endpoint
|
||||
nodes must begin with "endpoint" and must be followed by the number
|
||||
of the endpoint. The object it refers to should be called "EPXY", where
|
||||
"X" is the number of the port and "Y" is the number of the endpoint.
|
||||
|
||||
Each port node contains a property extension key "port", the value of
|
||||
which is the number of the port node. The each endpoint is similarly numbered
|
||||
with a property extension key "endpoint". Port numbers must be unique within a
|
||||
device and endpoint numbers must be unique within a port.
|
||||
|
||||
The endpoint reference uses property extension with "remote-endpoint" property
|
||||
name followed by a reference in the same package. Such references consist of the
|
||||
the remote device reference, number of the port in the device and finally the
|
||||
number of the endpoint in that port. Individual references thus appear as:
|
||||
|
||||
Package() { device, port_number, endpoint_number }
|
||||
|
||||
The references to endpoints must be always done both ways, to the
|
||||
remote endpoint and back from the referred remote endpoint node.
|
||||
|
||||
A simple example of this is show below:
|
||||
|
||||
Scope (\_SB.PCI0.I2C2)
|
||||
{
|
||||
Device (CAM0)
|
||||
{
|
||||
Name (_DSD, Package () {
|
||||
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||
Package () {
|
||||
Package () { "compatible", Package () { "nokia,smia" } },
|
||||
},
|
||||
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
|
||||
Package () {
|
||||
Package () { "port0", "PRT0" },
|
||||
}
|
||||
})
|
||||
Name (PRT0, Package() {
|
||||
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||
Package () {
|
||||
Package () { "port", 0 },
|
||||
},
|
||||
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
|
||||
Package () {
|
||||
Package () { "endpoint0", "EP00" },
|
||||
}
|
||||
})
|
||||
Name (EP00, Package() {
|
||||
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||
Package () {
|
||||
Package () { "endpoint", 0 },
|
||||
Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } },
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Scope (\_SB.PCI0)
|
||||
{
|
||||
Device (ISP)
|
||||
{
|
||||
Name (_DSD, Package () {
|
||||
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
|
||||
Package () {
|
||||
Package () { "port4", "PRT4" },
|
||||
}
|
||||
})
|
||||
|
||||
Name (PRT4, Package() {
|
||||
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||
Package () {
|
||||
Package () { "port", 4 }, /* CSI-2 port number */
|
||||
},
|
||||
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
|
||||
Package () {
|
||||
Package () { "endpoint0", "EP40" },
|
||||
}
|
||||
})
|
||||
|
||||
Name (EP40, Package() {
|
||||
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||
Package () {
|
||||
Package () { "endpoint", 0 },
|
||||
Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } },
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Here, the port 0 of the "CAM0" device is connected to the port 4 of
|
||||
the "ISP" device and vice versa.
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
[1] _DSD (Device Specific Data) Implementation Guide.
|
||||
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel-1_1.htm>,
|
||||
referenced 2016-10-03.
|
||||
|
||||
[2] Devicetree. <URL:http://www.devicetree.org>, referenced 2016-10-03.
|
||||
|
||||
[3] Documentation/devicetree/bindings/graph.txt
|
||||
|
||||
[4] Device Properties UUID For _DSD.
|
||||
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>,
|
||||
referenced 2016-10-04.
|
||||
|
||||
[5] Hierarchical Data Extension UUID For _DSD.
|
||||
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf>,
|
||||
referenced 2016-10-04.
|
||||
|
||||
[6] Advanced Configuration and Power Interface Specification.
|
||||
<URL:http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf>,
|
||||
referenced 2016-10-04.
|
||||
|
||||
[7] _DSD Device Properties Usage Rules.
|
||||
Documentation/acpi/DSD-properties-rules.txt
|
|
@ -37,14 +37,16 @@ static const u8 ads_uuid[16] = {
|
|||
|
||||
static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
|
||||
const union acpi_object *desc,
|
||||
struct acpi_device_data *data);
|
||||
struct acpi_device_data *data,
|
||||
struct fwnode_handle *parent);
|
||||
static bool acpi_extract_properties(const union acpi_object *desc,
|
||||
struct acpi_device_data *data);
|
||||
|
||||
static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
|
||||
acpi_handle handle,
|
||||
const union acpi_object *link,
|
||||
struct list_head *list)
|
||||
struct list_head *list,
|
||||
struct fwnode_handle *parent)
|
||||
{
|
||||
struct acpi_data_node *dn;
|
||||
bool result;
|
||||
|
@ -55,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
|
|||
|
||||
dn->name = link->package.elements[0].string.pointer;
|
||||
dn->fwnode.type = FWNODE_ACPI_DATA;
|
||||
dn->parent = parent;
|
||||
INIT_LIST_HEAD(&dn->data.subnodes);
|
||||
|
||||
result = acpi_extract_properties(desc, &dn->data);
|
||||
|
@ -71,9 +74,11 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
|
|||
*/
|
||||
status = acpi_get_parent(handle, &scope);
|
||||
if (ACPI_SUCCESS(status)
|
||||
&& acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
|
||||
&& acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
|
||||
&dn->fwnode))
|
||||
result = true;
|
||||
} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
|
||||
} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
|
||||
&dn->fwnode)) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
|
@ -91,7 +96,8 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
|
|||
|
||||
static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
|
||||
const union acpi_object *link,
|
||||
struct list_head *list)
|
||||
struct list_head *list,
|
||||
struct fwnode_handle *parent)
|
||||
{
|
||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||
acpi_status status;
|
||||
|
@ -101,7 +107,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
|
|||
if (ACPI_FAILURE(status))
|
||||
return false;
|
||||
|
||||
if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
|
||||
if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
|
||||
parent))
|
||||
return true;
|
||||
|
||||
ACPI_FREE(buf.pointer);
|
||||
|
@ -110,7 +117,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
|
|||
|
||||
static bool acpi_nondev_subnode_ok(acpi_handle scope,
|
||||
const union acpi_object *link,
|
||||
struct list_head *list)
|
||||
struct list_head *list,
|
||||
struct fwnode_handle *parent)
|
||||
{
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
@ -123,12 +131,13 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
|
|||
if (ACPI_FAILURE(status))
|
||||
return false;
|
||||
|
||||
return acpi_nondev_subnode_data_ok(handle, link, list);
|
||||
return acpi_nondev_subnode_data_ok(handle, link, list, parent);
|
||||
}
|
||||
|
||||
static int acpi_add_nondev_subnodes(acpi_handle scope,
|
||||
const union acpi_object *links,
|
||||
struct list_head *list)
|
||||
struct list_head *list,
|
||||
struct fwnode_handle *parent)
|
||||
{
|
||||
bool ret = false;
|
||||
int i;
|
||||
|
@ -150,15 +159,18 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
|
|||
/* The second one may be a string, a reference or a package. */
|
||||
switch (link->package.elements[1].type) {
|
||||
case ACPI_TYPE_STRING:
|
||||
result = acpi_nondev_subnode_ok(scope, link, list);
|
||||
result = acpi_nondev_subnode_ok(scope, link, list,
|
||||
parent);
|
||||
break;
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
handle = link->package.elements[1].reference.handle;
|
||||
result = acpi_nondev_subnode_data_ok(handle, link, list);
|
||||
result = acpi_nondev_subnode_data_ok(handle, link, list,
|
||||
parent);
|
||||
break;
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
desc = &link->package.elements[1];
|
||||
result = acpi_nondev_subnode_extract(desc, NULL, link, list);
|
||||
result = acpi_nondev_subnode_extract(desc, NULL, link,
|
||||
list, parent);
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
|
@ -172,7 +184,8 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
|
|||
|
||||
static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
|
||||
const union acpi_object *desc,
|
||||
struct acpi_device_data *data)
|
||||
struct acpi_device_data *data,
|
||||
struct fwnode_handle *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -194,7 +207,8 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
|
|||
if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))
|
||||
continue;
|
||||
|
||||
return acpi_add_nondev_subnodes(scope, links, &data->subnodes);
|
||||
return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
|
||||
parent);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -345,7 +359,8 @@ void acpi_init_properties(struct acpi_device *adev)
|
|||
if (acpi_of)
|
||||
acpi_init_of_compatible(adev);
|
||||
}
|
||||
if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))
|
||||
if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer,
|
||||
&adev->data, acpi_fwnode_handle(adev)))
|
||||
adev->data.pointer = buf.pointer;
|
||||
|
||||
if (!adev->data.pointer) {
|
||||
|
@ -699,6 +714,8 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data,
|
|||
return ret;
|
||||
|
||||
*(char **)val = obj->string.pointer;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -708,7 +725,15 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data,
|
|||
int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
|
||||
enum dev_prop_type proptype, void *val)
|
||||
{
|
||||
return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL;
|
||||
int ret;
|
||||
|
||||
if (!adev)
|
||||
return -EINVAL;
|
||||
|
||||
ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
|
||||
if (ret < 0 || proptype != ACPI_TYPE_STRING)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
|
||||
|
@ -784,7 +809,7 @@ static int acpi_copy_property_array_string(const union acpi_object *items,
|
|||
|
||||
val[i] = items[i].string.pointer;
|
||||
}
|
||||
return 0;
|
||||
return nval;
|
||||
}
|
||||
|
||||
static int acpi_data_prop_read(struct acpi_device_data *data,
|
||||
|
@ -798,7 +823,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data,
|
|||
|
||||
if (val && nval == 1) {
|
||||
ret = acpi_data_prop_read_single(data, propname, proptype, val);
|
||||
if (!ret)
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -809,7 +834,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data,
|
|||
if (!val)
|
||||
return obj->package.count;
|
||||
|
||||
if (nval > obj->package.count)
|
||||
if (proptype != DEV_PROP_STRING && nval > obj->package.count)
|
||||
return -EOVERFLOW;
|
||||
else if (nval <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -830,7 +855,9 @@ static int acpi_data_prop_read(struct acpi_device_data *data,
|
|||
ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
|
||||
break;
|
||||
case DEV_PROP_STRING:
|
||||
ret = acpi_copy_property_array_string(items, (char **)val, nval);
|
||||
ret = acpi_copy_property_array_string(
|
||||
items, (char **)val,
|
||||
min_t(u32, nval, obj->package.count));
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -865,21 +892,22 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
|
|||
}
|
||||
|
||||
/**
|
||||
* acpi_get_next_subnode - Return the next child node handle for a device.
|
||||
* @dev: Device to find the next child node for.
|
||||
* acpi_get_next_subnode - Return the next child node handle for a fwnode
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
* @child: Handle to one of the device's child nodes or a null handle.
|
||||
*/
|
||||
struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
||||
struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
struct list_head *head, *next;
|
||||
|
||||
if (!adev)
|
||||
return NULL;
|
||||
|
||||
if (!child || child->type == FWNODE_ACPI) {
|
||||
head = &adev->children;
|
||||
if (adev)
|
||||
head = &adev->children;
|
||||
else
|
||||
goto nondev;
|
||||
|
||||
if (list_empty(head))
|
||||
goto nondev;
|
||||
|
||||
|
@ -888,7 +916,6 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
|||
next = adev->node.next;
|
||||
if (next == head) {
|
||||
child = NULL;
|
||||
adev = ACPI_COMPANION(dev);
|
||||
goto nondev;
|
||||
}
|
||||
adev = list_entry(next, struct acpi_device, node);
|
||||
|
@ -900,9 +927,16 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
|||
|
||||
nondev:
|
||||
if (!child || child->type == FWNODE_ACPI_DATA) {
|
||||
struct acpi_data_node *data = to_acpi_data_node(fwnode);
|
||||
struct acpi_data_node *dn;
|
||||
|
||||
head = &adev->data.subnodes;
|
||||
if (adev)
|
||||
head = &adev->data.subnodes;
|
||||
else if (data)
|
||||
head = &data->data.subnodes;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (list_empty(head))
|
||||
return NULL;
|
||||
|
||||
|
@ -920,3 +954,168 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_node_get_parent - Return parent fwnode of this fwnode
|
||||
* @fwnode: Firmware node whose parent to get
|
||||
*
|
||||
* Returns parent node of an ACPI device or data firmware node or %NULL if
|
||||
* not available.
|
||||
*/
|
||||
struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
if (is_acpi_data_node(fwnode)) {
|
||||
/* All data nodes have parent pointer so just return that */
|
||||
return to_acpi_data_node(fwnode)->parent;
|
||||
} else if (is_acpi_device_node(fwnode)) {
|
||||
acpi_handle handle, parent_handle;
|
||||
|
||||
handle = to_acpi_device_node(fwnode)->handle;
|
||||
if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!acpi_bus_get_device(parent_handle, &adev))
|
||||
return acpi_fwnode_handle(adev);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/phy.h>
|
||||
|
@ -146,47 +147,45 @@ static int pset_prop_read_string_array(struct property_set *pset,
|
|||
const char *propname,
|
||||
const char **strings, size_t nval)
|
||||
{
|
||||
const struct property_entry *prop;
|
||||
const void *pointer;
|
||||
size_t length = nval * sizeof(*strings);
|
||||
size_t array_len, length;
|
||||
|
||||
/* Find out the array length. */
|
||||
prop = pset_prop_get(pset, propname);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
|
||||
if (!prop->is_array)
|
||||
/* The array length for a non-array string property is 1. */
|
||||
array_len = 1;
|
||||
else
|
||||
/* Find the length of an array. */
|
||||
array_len = pset_prop_count_elems_of_size(pset, propname,
|
||||
sizeof(const char *));
|
||||
|
||||
/* Return how many there are if strings is NULL. */
|
||||
if (!strings)
|
||||
return array_len;
|
||||
|
||||
array_len = min(nval, array_len);
|
||||
length = array_len * sizeof(*strings);
|
||||
|
||||
pointer = pset_prop_find(pset, propname, length);
|
||||
if (IS_ERR(pointer))
|
||||
return PTR_ERR(pointer);
|
||||
|
||||
memcpy(strings, pointer, length);
|
||||
return 0;
|
||||
|
||||
return array_len;
|
||||
}
|
||||
|
||||
static int pset_prop_read_string(struct property_set *pset,
|
||||
const char *propname, const char **strings)
|
||||
{
|
||||
const struct property_entry *prop;
|
||||
const char * const *pointer;
|
||||
|
||||
prop = pset_prop_get(pset, propname);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->is_string)
|
||||
return -EILSEQ;
|
||||
if (prop->is_array) {
|
||||
pointer = prop->pointer.str;
|
||||
if (!pointer)
|
||||
return -ENODATA;
|
||||
} else {
|
||||
pointer = &prop->value.str;
|
||||
if (*pointer && strnlen(*pointer, prop->length) >= prop->length)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
*strings = *pointer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *dev_fwnode(struct device *dev)
|
||||
struct fwnode_handle *dev_fwnode(struct device *dev)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
|
||||
&dev->of_node->fwnode : dev->fwnode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_fwnode);
|
||||
|
||||
/**
|
||||
* device_property_present - check if a property of a device is present
|
||||
|
@ -340,8 +339,8 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
|
|||
* Function reads an array of string properties with @propname from the device
|
||||
* firmware description and stores them to @val if found.
|
||||
*
|
||||
* Return: number of values if @val was %NULL,
|
||||
* %0 if the property was found (success),
|
||||
* Return: number of values read on success if @val is non-NULL,
|
||||
* number of values available on success if @val is NULL,
|
||||
* %-EINVAL if given arguments are not valid,
|
||||
* %-ENODATA if the property does not have a value,
|
||||
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
|
||||
|
@ -553,25 +552,8 @@ static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
|
|||
return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
|
||||
val, nval);
|
||||
else if (is_pset_node(fwnode))
|
||||
return val ?
|
||||
pset_prop_read_string_array(to_pset_node(fwnode),
|
||||
propname, val, nval) :
|
||||
pset_prop_count_elems_of_size(to_pset_node(fwnode),
|
||||
propname,
|
||||
sizeof(const char *));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
|
||||
const char *propname, const char **val)
|
||||
{
|
||||
if (is_of_node(fwnode))
|
||||
return of_property_read_string(to_of_node(fwnode), propname, val);
|
||||
else if (is_acpi_node(fwnode))
|
||||
return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
|
||||
val, 1);
|
||||
else if (is_pset_node(fwnode))
|
||||
return pset_prop_read_string(to_pset_node(fwnode), propname, val);
|
||||
return pset_prop_read_string_array(to_pset_node(fwnode),
|
||||
propname, val, nval);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
|
@ -585,11 +567,11 @@ static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
|
|||
* Read an string list property @propname from the given firmware node and store
|
||||
* them to @val if found.
|
||||
*
|
||||
* Return: number of values if @val was %NULL,
|
||||
* %0 if the property was found (success),
|
||||
* Return: number of values read on success if @val is non-NULL,
|
||||
* number of values available on success if @val is NULL,
|
||||
* %-EINVAL if given arguments are not valid,
|
||||
* %-ENODATA if the property does not have a value,
|
||||
* %-EPROTO if the property is not an array of strings,
|
||||
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
|
||||
* %-EOVERFLOW if the size of the property is not as expected,
|
||||
* %-ENXIO if no suitable firmware interface is present.
|
||||
*/
|
||||
|
@ -626,14 +608,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
|
|||
int fwnode_property_read_string(struct fwnode_handle *fwnode,
|
||||
const char *propname, const char **val)
|
||||
{
|
||||
int ret;
|
||||
int ret = fwnode_property_read_string_array(fwnode, propname, val, 1);
|
||||
|
||||
ret = __fwnode_property_read_string(fwnode, propname, val);
|
||||
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
|
||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
||||
ret = __fwnode_property_read_string(fwnode->secondary,
|
||||
propname, val);
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_property_read_string);
|
||||
|
||||
|
@ -931,6 +908,75 @@ int device_add_properties(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(device_add_properties);
|
||||
|
||||
/**
|
||||
* fwnode_get_next_parent - Iterate to the node's parent
|
||||
* @fwnode: Firmware whose parent is retrieved
|
||||
*
|
||||
* This is like fwnode_get_parent() except that it drops the refcount
|
||||
* on the passed node, making it suitable for iterating through a
|
||||
* node's parents.
|
||||
*
|
||||
* Returns a node pointer with refcount incremented, use
|
||||
* fwnode_handle_node() on it when done.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = fwnode_get_parent(fwnode);
|
||||
|
||||
fwnode_handle_put(fwnode);
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
||||
|
||||
/**
|
||||
* fwnode_get_parent - Return parent firwmare node
|
||||
* @fwnode: Firmware whose parent is retrieved
|
||||
*
|
||||
* Return parent firmware node of the given node if possible or %NULL if no
|
||||
* parent was available.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_parent(to_of_node(fwnode));
|
||||
if (node)
|
||||
parent = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
parent = acpi_node_get_parent(fwnode);
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_parent);
|
||||
|
||||
/**
|
||||
* fwnode_get_next_child_node - Return the next child node handle for a node
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
* @child: Handle to one of the node's child nodes or a %NULL handle.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_next_available_child(to_of_node(fwnode),
|
||||
to_of_node(child));
|
||||
if (node)
|
||||
return &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
return acpi_get_next_subnode(fwnode, child);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
|
||||
|
||||
/**
|
||||
* device_get_next_child_node - Return the next child node handle for a device
|
||||
* @dev: Device to find the next child node for.
|
||||
|
@ -939,34 +985,33 @@ EXPORT_SYMBOL_GPL(device_add_properties);
|
|||
struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
struct device_node *node;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct fwnode_handle *fwnode = NULL;
|
||||
|
||||
node = of_get_next_available_child(dev->of_node, to_of_node(child));
|
||||
if (node)
|
||||
return &node->fwnode;
|
||||
} else if (IS_ENABLED(CONFIG_ACPI)) {
|
||||
return acpi_get_next_subnode(dev, child);
|
||||
}
|
||||
return NULL;
|
||||
if (dev->of_node)
|
||||
fwnode = &dev->of_node->fwnode;
|
||||
else if (adev)
|
||||
fwnode = acpi_fwnode_handle(adev);
|
||||
|
||||
return fwnode_get_next_child_node(fwnode, child);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
||||
|
||||
/**
|
||||
* device_get_named_child_node - Return first matching named child node handle
|
||||
* @dev: Device to find the named child node for.
|
||||
* fwnode_get_named_child_node - Return first matching named child node handle
|
||||
* @fwnode: Firmware node to find the named child node for.
|
||||
* @childname: String to match child node name against.
|
||||
*/
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
|
||||
const char *childname)
|
||||
{
|
||||
struct fwnode_handle *child;
|
||||
|
||||
/*
|
||||
* Find first matching named child node of this device.
|
||||
* Find first matching named child node of this fwnode.
|
||||
* For ACPI this will be a data only sub-node.
|
||||
*/
|
||||
device_for_each_child_node(dev, child) {
|
||||
fwnode_for_each_child_node(fwnode, child) {
|
||||
if (is_of_node(child)) {
|
||||
if (!of_node_cmp(to_of_node(child)->name, childname))
|
||||
return child;
|
||||
|
@ -978,8 +1023,31 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
|
||||
|
||||
/**
|
||||
* device_get_named_child_node - Return first matching named child node handle
|
||||
* @dev: Device to find the named child node for.
|
||||
* @childname: String to match child node name against.
|
||||
*/
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
const char *childname)
|
||||
{
|
||||
return fwnode_get_named_child_node(dev_fwnode(dev), childname);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_named_child_node);
|
||||
|
||||
/**
|
||||
* fwnode_handle_get - Obtain a reference to a device node
|
||||
* @fwnode: Pointer to the device node to obtain the reference to.
|
||||
*/
|
||||
void fwnode_handle_get(struct fwnode_handle *fwnode)
|
||||
{
|
||||
if (is_of_node(fwnode))
|
||||
of_node_get(to_of_node(fwnode));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_handle_get);
|
||||
|
||||
/**
|
||||
* fwnode_handle_put - Drop reference to a device node
|
||||
* @fwnode: Pointer to the device node to drop the reference to.
|
||||
|
@ -1117,3 +1185,157 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen)
|
|||
return device_get_mac_addr(dev, "address", addr, alen);
|
||||
}
|
||||
EXPORT_SYMBOL(device_get_mac_address);
|
||||
|
||||
/**
|
||||
* device_graph_get_next_endpoint - Get next endpoint firmware node
|
||||
* @fwnode: Pointer to the parent firmware node
|
||||
* @prev: Previous endpoint node or %NULL to get the first
|
||||
*
|
||||
* Returns an endpoint firmware node pointer or %NULL if no more endpoints
|
||||
* are available.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *prev)
|
||||
{
|
||||
struct fwnode_handle *endpoint = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_next_endpoint(to_of_node(fwnode),
|
||||
to_of_node(prev));
|
||||
|
||||
if (node)
|
||||
endpoint = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
|
||||
if (IS_ERR(endpoint))
|
||||
endpoint = NULL;
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote device the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_remote_port_parent(to_of_node(fwnode));
|
||||
if (node)
|
||||
parent = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL,
|
||||
NULL);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_port - Return fwnode of a remote port
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote port the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *port = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_remote_port(to_of_node(fwnode));
|
||||
if (node)
|
||||
port = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote endpoint the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *endpoint = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint",
|
||||
0);
|
||||
if (node)
|
||||
endpoint = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL,
|
||||
&endpoint);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
|
||||
|
||||
/**
|
||||
* fwnode_graph_parse_endpoint - parse common endpoint node properties
|
||||
* @fwnode: pointer to endpoint fwnode_handle
|
||||
* @endpoint: pointer to the fwnode endpoint data structure
|
||||
*
|
||||
* Parse @fwnode representing a graph endpoint node and store the
|
||||
* information in @endpoint. The caller must hold a reference to
|
||||
* @fwnode.
|
||||
*/
|
||||
int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_endpoint *endpoint)
|
||||
{
|
||||
struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
|
||||
|
||||
memset(endpoint, 0, sizeof(*endpoint));
|
||||
|
||||
endpoint->local_fwnode = fwnode;
|
||||
|
||||
if (is_acpi_node(port_fwnode)) {
|
||||
fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
|
||||
fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
|
||||
} else {
|
||||
fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port);
|
||||
fwnode_property_read_u32(fwnode, "reg", &endpoint->id);
|
||||
}
|
||||
|
||||
fwnode_handle_put(port_fwnode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
|
||||
|
|
|
@ -387,6 +387,7 @@ struct acpi_data_node {
|
|||
const char *name;
|
||||
acpi_handle handle;
|
||||
struct fwnode_handle fwnode;
|
||||
struct fwnode_handle *parent;
|
||||
struct acpi_device_data data;
|
||||
struct list_head sibling;
|
||||
struct kobject kobj;
|
||||
|
|
|
@ -998,8 +998,16 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
|
|||
int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
|
||||
enum dev_prop_type proptype, void *val, size_t nval);
|
||||
|
||||
struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
||||
struct fwnode_handle *subnode);
|
||||
struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child);
|
||||
struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode);
|
||||
|
||||
struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *prev);
|
||||
int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle **remote,
|
||||
struct fwnode_handle **port,
|
||||
struct fwnode_handle **endpoint);
|
||||
|
||||
struct acpi_probe_entry;
|
||||
typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
|
||||
|
@ -1116,12 +1124,34 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev,
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
|
||||
struct fwnode_handle *subnode)
|
||||
static inline struct fwnode_handle *
|
||||
acpi_get_next_subnode(struct fwnode_handle *fwnode, struct fwnode_handle *child)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *
|
||||
acpi_node_get_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *
|
||||
acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *prev)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
|
||||
static inline int
|
||||
acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle **remote,
|
||||
struct fwnode_handle **port,
|
||||
struct fwnode_handle **endpoint)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
|
||||
static const void * __acpi_table_##name[] \
|
||||
__attribute__((unused)) \
|
||||
|
|
|
@ -27,4 +27,16 @@ struct fwnode_handle {
|
|||
struct fwnode_handle *secondary;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fwnode_endpoint - Fwnode graph endpoint
|
||||
* @port: Port number
|
||||
* @id: Endpoint id
|
||||
* @local_fwnode: reference to the related fwnode
|
||||
*/
|
||||
struct fwnode_endpoint {
|
||||
unsigned int port;
|
||||
unsigned int id;
|
||||
const struct fwnode_handle *local_fwnode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -159,6 +159,8 @@ static inline struct device_node *to_of_node(struct fwnode_handle *fwnode)
|
|||
container_of(fwnode, struct device_node, fwnode) : NULL;
|
||||
}
|
||||
|
||||
#define of_fwnode_handle(node) (&(node)->fwnode)
|
||||
|
||||
static inline bool of_have_populated_dt(void)
|
||||
{
|
||||
return of_root != NULL;
|
||||
|
@ -602,6 +604,8 @@ static inline struct device_node *of_find_node_with_property(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define of_fwnode_handle(node) NULL
|
||||
|
||||
static inline bool of_have_populated_dt(void)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -33,6 +33,8 @@ enum dev_dma_attr {
|
|||
DEV_DMA_COHERENT,
|
||||
};
|
||||
|
||||
struct fwnode_handle *dev_fwnode(struct device *dev);
|
||||
|
||||
bool device_property_present(struct device *dev, const char *propname);
|
||||
int device_property_read_u8_array(struct device *dev, const char *propname,
|
||||
u8 *val, size_t nval);
|
||||
|
@ -70,6 +72,15 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
|
|||
int fwnode_property_match_string(struct fwnode_handle *fwnode,
|
||||
const char *propname, const char *string);
|
||||
|
||||
struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode);
|
||||
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
|
||||
struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child);
|
||||
|
||||
#define fwnode_for_each_child_node(fwnode, child) \
|
||||
for (child = fwnode_get_next_child_node(fwnode, NULL); child; \
|
||||
child = fwnode_get_next_child_node(fwnode, child))
|
||||
|
||||
struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
||||
struct fwnode_handle *child);
|
||||
|
||||
|
@ -77,9 +88,12 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
|||
for (child = device_get_next_child_node(dev, NULL); child; \
|
||||
child = device_get_next_child_node(dev, child))
|
||||
|
||||
struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
|
||||
const char *childname);
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
const char *childname);
|
||||
|
||||
void fwnode_handle_get(struct fwnode_handle *fwnode);
|
||||
void fwnode_handle_put(struct fwnode_handle *fwnode);
|
||||
|
||||
unsigned int device_get_child_node_count(struct device *dev);
|
||||
|
@ -258,4 +272,16 @@ int device_get_phy_mode(struct device *dev);
|
|||
|
||||
void *device_get_mac_address(struct device *dev, char *addr, int alen);
|
||||
|
||||
struct fwnode_handle *fwnode_graph_get_next_endpoint(
|
||||
struct fwnode_handle *fwnode, struct fwnode_handle *prev);
|
||||
struct fwnode_handle *fwnode_graph_get_remote_port_parent(
|
||||
struct fwnode_handle *fwnode);
|
||||
struct fwnode_handle *fwnode_graph_get_remote_port(
|
||||
struct fwnode_handle *fwnode);
|
||||
struct fwnode_handle *fwnode_graph_get_remote_endpoint(
|
||||
struct fwnode_handle *fwnode);
|
||||
|
||||
int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_endpoint *endpoint);
|
||||
|
||||
#endif /* _LINUX_PROPERTY_H_ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче