Device properties framework updates for 5.5-rc1
Add support for printing fwnode names using a new conversion specifier "%pfw" (Sakari Ailus), clean up the software node and efi/apple-properties code in preparation for improved software node reference properties handling (Dmitry Torokhov) and fix the struct fwnode_operations description (Heikki Krogerus). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAl3dHU0SHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRx1JkP/j/YkE6VsMlXqL+3kMABXfVlAIZtkZ71 YB13wtGHdz0hewvCFJDLZuJ3+axbR5Lk60tqX+lfG6GvWMtudZ+URkZ0KIUBhDXM uwVniqcWvlItMGo+cU7FLW1rKkRDCQ75x4GlKD1MivCG+PZXYqkH/ESQZgi3TdwD 0rYGzUx4nBKzS9yJ6ZnBhSOGRq9sGGHgOr20LjYlAplcOMhE6PP+SQNCfKVk8DE8 ZolavWpmD+nsV97qWGLpJOKWJXplCv+lWX8cQICvONRSWPHq6ehQ4HONnLDtPai3 EcyGQ3LbuVMYKOWUVRYs2X+wvgmAz461Y+Du8FO1QzYuNMYzArRx2naD1LIIUT6Q UE8RRkN2YyqvVmSLlAYAJPH7GCP8mRZV2gHfmS7fF16jUpTOiDHKiZFjOgvSc/lp 31DhBpWr64NgSOSpqi/bX6fSYVv9YGPOd0J8dPNsaGZbHZxJJ2cmZ092u6Rrx6VG x1qO2j2c2xC6Y+pEMCBCqjDUmhFD5P6O7qVky/9kyZv9AWyBlEpni7tdu8J6DqVG RUB0zq5jujfBoTtBFFpVxDiQYvctTs/T9te48DQkdCli0J/bUEEyNw5nX6HKnjZM jyrh93Th512W0JwbPWpJXn1JJMdxkNitwlLRwnhCSSTdcLZiHzDoYdf7taSemvX5 ZJZYhPG5T6i5 =VcCH -----END PGP SIGNATURE----- Merge tag 'devprop-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull device properties framework updates from Rafael Wysocki: "Add support for printing fwnode names using a new conversion specifier "%pfw" (Sakari Ailus), clean up the software node and efi/apple-properties code in preparation for improved software node reference properties handling (Dmitry Torokhov) and fix the struct fwnode_operations description (Heikki Krogerus)" * tag 'devprop-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (22 commits) software node: simplify property_entry_read_string_array() software node: unify PROPERTY_ENTRY_XXX macros software node: remove property_entry_read_uNN_array functions software node: get rid of property_set_pointer() software node: clean up property_copy_string_array() software node: mark internal macros with double underscores efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN software node: introduce PROPERTY_ENTRY_XXX_ARRAY_LEN() software node: remove DEV_PROP_MAX device property: Fix the description of struct fwnode_operations lib/test_printf: Add tests for %pfw printk modifier lib/vsprintf: Add %pfw conversion specifier for printing fwnode names lib/vsprintf: OF nodes are first and foremost, struct device_nodes lib/vsprintf: Make use of fwnode API to obtain node names and separators lib/vsprintf: Add a note on re-using %pf or %pF lib/vsprintf: Remove support for %pF and %pf in favour of %pS and %ps device property: Add a function to obtain a node's prefix device property: Add fwnode_get_name for returning the name of a node device property: Add functions for accessing node's parents device property: Move fwnode_get_parent() up ...
This commit is contained in:
commit
361b0d286a
@ -98,8 +98,6 @@ Symbols/Function Pointers
|
|||||||
|
|
||||||
%pS versatile_init+0x0/0x110
|
%pS versatile_init+0x0/0x110
|
||||||
%ps versatile_init
|
%ps versatile_init
|
||||||
%pF versatile_init+0x0/0x110
|
|
||||||
%pf versatile_init
|
|
||||||
%pSR versatile_init+0x9/0x110
|
%pSR versatile_init+0x9/0x110
|
||||||
(with __builtin_extract_return_addr() translation)
|
(with __builtin_extract_return_addr() translation)
|
||||||
%pB prev_fn_of_versatile_init+0x88/0x88
|
%pB prev_fn_of_versatile_init+0x88/0x88
|
||||||
@ -109,14 +107,6 @@ The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic
|
|||||||
format. They result in the symbol name with (S) or without (s)
|
format. They result in the symbol name with (S) or without (s)
|
||||||
offsets. If KALLSYMS are disabled then the symbol address is printed instead.
|
offsets. If KALLSYMS are disabled then the symbol address is printed instead.
|
||||||
|
|
||||||
Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``)
|
|
||||||
and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and
|
|
||||||
parisc64 function pointers are indirect and, in fact, are function
|
|
||||||
descriptors, which require additional dereferencing before we can lookup
|
|
||||||
the symbol. As of now, ``S`` and ``s`` perform dereferencing on those
|
|
||||||
platforms (when needed), so ``F`` and ``f`` exist for compatibility
|
|
||||||
reasons only.
|
|
||||||
|
|
||||||
The ``B`` specifier results in the symbol name with offsets and should be
|
The ``B`` specifier results in the symbol name with offsets and should be
|
||||||
used when printing stack backtraces. The specifier takes into
|
used when printing stack backtraces. The specifier takes into
|
||||||
consideration the effect of compiler optimisations which may occur
|
consideration the effect of compiler optimisations which may occur
|
||||||
@ -440,6 +430,30 @@ Examples::
|
|||||||
|
|
||||||
Passed by reference.
|
Passed by reference.
|
||||||
|
|
||||||
|
Fwnode handles
|
||||||
|
--------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
%pfw[fP]
|
||||||
|
|
||||||
|
For printing information on fwnode handles. The default is to print the full
|
||||||
|
node name, including the path. The modifiers are functionally equivalent to
|
||||||
|
%pOF above.
|
||||||
|
|
||||||
|
- f - full name of the node, including the path
|
||||||
|
- P - the name of the node including an address (if there is one)
|
||||||
|
|
||||||
|
Examples (ACPI)::
|
||||||
|
|
||||||
|
%pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name
|
||||||
|
%pfwP endpoint@0 - Node name
|
||||||
|
|
||||||
|
Examples (OF)::
|
||||||
|
|
||||||
|
%pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
|
||||||
|
%pfwP endpoint - Node name
|
||||||
|
|
||||||
Time and date (struct rtc_time)
|
Time and date (struct rtc_time)
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
@ -1317,6 +1317,52 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
|
|||||||
args_count, args);
|
args_count, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
const struct acpi_device *adev;
|
||||||
|
struct fwnode_handle *parent;
|
||||||
|
|
||||||
|
/* Is this the root node? */
|
||||||
|
parent = fwnode_get_parent(fwnode);
|
||||||
|
if (!parent)
|
||||||
|
return "\\";
|
||||||
|
|
||||||
|
fwnode_handle_put(parent);
|
||||||
|
|
||||||
|
if (is_acpi_data_node(fwnode)) {
|
||||||
|
const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
|
||||||
|
|
||||||
|
return dn->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
adev = to_acpi_device_node(fwnode);
|
||||||
|
if (WARN_ON(!adev))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return acpi_device_bid(adev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
struct fwnode_handle *parent;
|
||||||
|
|
||||||
|
/* Is this the root node? */
|
||||||
|
parent = fwnode_get_parent(fwnode);
|
||||||
|
if (!parent)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
/* Is this 2nd node from the root? */
|
||||||
|
parent = fwnode_get_next_parent(parent);
|
||||||
|
if (!parent)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
fwnode_handle_put(parent);
|
||||||
|
|
||||||
|
/* ACPI device or data node. */
|
||||||
|
return ".";
|
||||||
|
}
|
||||||
|
|
||||||
static struct fwnode_handle *
|
static struct fwnode_handle *
|
||||||
acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
|
acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
@ -1357,6 +1403,8 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
|||||||
.get_parent = acpi_node_get_parent, \
|
.get_parent = acpi_node_get_parent, \
|
||||||
.get_next_child_node = acpi_get_next_subnode, \
|
.get_next_child_node = acpi_get_next_subnode, \
|
||||||
.get_named_child_node = acpi_fwnode_get_named_child_node, \
|
.get_named_child_node = acpi_fwnode_get_named_child_node, \
|
||||||
|
.get_name = acpi_fwnode_get_name, \
|
||||||
|
.get_name_prefix = acpi_fwnode_get_name_prefix, \
|
||||||
.get_reference_args = acpi_fwnode_get_reference_args, \
|
.get_reference_args = acpi_fwnode_get_reference_args, \
|
||||||
.graph_get_next_endpoint = \
|
.graph_get_next_endpoint = \
|
||||||
acpi_graph_get_next_endpoint, \
|
acpi_graph_get_next_endpoint, \
|
||||||
|
@ -556,6 +556,42 @@ int device_add_properties(struct device *dev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_add_properties);
|
EXPORT_SYMBOL_GPL(device_add_properties);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fwnode_get_name - Return the name of a node
|
||||||
|
* @fwnode: The firmware node
|
||||||
|
*
|
||||||
|
* Returns a pointer to the node name.
|
||||||
|
*/
|
||||||
|
const char *fwnode_get_name(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return fwnode_call_ptr_op(fwnode, get_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fwnode_get_name_prefix - Return the prefix of node for printing purposes
|
||||||
|
* @fwnode: The firmware node
|
||||||
|
*
|
||||||
|
* Returns the prefix of a node, intended to be printed right before the node.
|
||||||
|
* The prefix works also as a separator between the nodes.
|
||||||
|
*/
|
||||||
|
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return fwnode_call_ptr_op(fwnode, get_name_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return fwnode_call_ptr_op(fwnode, get_parent);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fwnode_get_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fwnode_get_next_parent - Iterate to the node's parent
|
* fwnode_get_next_parent - Iterate to the node's parent
|
||||||
* @fwnode: Firmware whose parent is retrieved
|
* @fwnode: Firmware whose parent is retrieved
|
||||||
@ -578,17 +614,50 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
|
|||||||
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fwnode_get_parent - Return parent firwmare node
|
* fwnode_count_parents - Return the number of parents a node has
|
||||||
* @fwnode: Firmware whose parent is retrieved
|
* @fwnode: The node the parents of which are to be counted
|
||||||
*
|
*
|
||||||
* Return parent firmware node of the given node if possible or %NULL if no
|
* Returns the number of parents a node has.
|
||||||
* parent was available.
|
|
||||||
*/
|
*/
|
||||||
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode)
|
unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
return fwnode_call_ptr_op(fwnode, get_parent);
|
struct fwnode_handle *__fwnode;
|
||||||
|
unsigned int count;
|
||||||
|
|
||||||
|
__fwnode = fwnode_get_parent(fwnode);
|
||||||
|
|
||||||
|
for (count = 0; __fwnode; count++)
|
||||||
|
__fwnode = fwnode_get_next_parent(__fwnode);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_get_parent);
|
EXPORT_SYMBOL_GPL(fwnode_count_parents);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fwnode_get_nth_parent - Return an nth parent of a node
|
||||||
|
* @fwnode: The node the parent of which is requested
|
||||||
|
* @depth: Distance of the parent from the node
|
||||||
|
*
|
||||||
|
* Returns the nth parent of a node. If there is no parent at the requested
|
||||||
|
* @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to
|
||||||
|
* fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on.
|
||||||
|
*
|
||||||
|
* The caller is responsible for calling fwnode_handle_put() for the returned
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
|
||||||
|
unsigned int depth)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
fwnode_handle_get(fwnode);
|
||||||
|
|
||||||
|
for (i = 0; i < depth && fwnode; i++)
|
||||||
|
fwnode = fwnode_get_next_parent(fwnode);
|
||||||
|
|
||||||
|
return fwnode;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fwnode_get_next_child_node - Return the next child node handle for a node
|
* fwnode_get_next_child_node - Return the next child node handle for a node
|
||||||
|
@ -71,9 +71,9 @@ software_node_to_swnode(const struct software_node *node)
|
|||||||
return swnode;
|
return swnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct software_node *to_software_node(struct fwnode_handle *fwnode)
|
const struct software_node *to_software_node(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct swnode *swnode = to_swnode(fwnode);
|
const struct swnode *swnode = to_swnode(fwnode);
|
||||||
|
|
||||||
return swnode ? swnode->node : NULL;
|
return swnode ? swnode->node : NULL;
|
||||||
}
|
}
|
||||||
@ -103,71 +103,15 @@ property_entry_get(const struct property_entry *prop, const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
property_set_pointer(struct property_entry *prop, const void *pointer)
|
|
||||||
{
|
|
||||||
switch (prop->type) {
|
|
||||||
case DEV_PROP_U8:
|
|
||||||
if (prop->is_array)
|
|
||||||
prop->pointer.u8_data = pointer;
|
|
||||||
else
|
|
||||||
prop->value.u8_data = *((u8 *)pointer);
|
|
||||||
break;
|
|
||||||
case DEV_PROP_U16:
|
|
||||||
if (prop->is_array)
|
|
||||||
prop->pointer.u16_data = pointer;
|
|
||||||
else
|
|
||||||
prop->value.u16_data = *((u16 *)pointer);
|
|
||||||
break;
|
|
||||||
case DEV_PROP_U32:
|
|
||||||
if (prop->is_array)
|
|
||||||
prop->pointer.u32_data = pointer;
|
|
||||||
else
|
|
||||||
prop->value.u32_data = *((u32 *)pointer);
|
|
||||||
break;
|
|
||||||
case DEV_PROP_U64:
|
|
||||||
if (prop->is_array)
|
|
||||||
prop->pointer.u64_data = pointer;
|
|
||||||
else
|
|
||||||
prop->value.u64_data = *((u64 *)pointer);
|
|
||||||
break;
|
|
||||||
case DEV_PROP_STRING:
|
|
||||||
if (prop->is_array)
|
|
||||||
prop->pointer.str = pointer;
|
|
||||||
else
|
|
||||||
prop->value.str = pointer;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const void *property_get_pointer(const struct property_entry *prop)
|
static const void *property_get_pointer(const struct property_entry *prop)
|
||||||
{
|
{
|
||||||
switch (prop->type) {
|
if (!prop->length)
|
||||||
case DEV_PROP_U8:
|
|
||||||
if (prop->is_array)
|
|
||||||
return prop->pointer.u8_data;
|
|
||||||
return &prop->value.u8_data;
|
|
||||||
case DEV_PROP_U16:
|
|
||||||
if (prop->is_array)
|
|
||||||
return prop->pointer.u16_data;
|
|
||||||
return &prop->value.u16_data;
|
|
||||||
case DEV_PROP_U32:
|
|
||||||
if (prop->is_array)
|
|
||||||
return prop->pointer.u32_data;
|
|
||||||
return &prop->value.u32_data;
|
|
||||||
case DEV_PROP_U64:
|
|
||||||
if (prop->is_array)
|
|
||||||
return prop->pointer.u64_data;
|
|
||||||
return &prop->value.u64_data;
|
|
||||||
case DEV_PROP_STRING:
|
|
||||||
if (prop->is_array)
|
|
||||||
return prop->pointer.str;
|
|
||||||
return &prop->value.str;
|
|
||||||
default:
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
if (prop->is_array)
|
||||||
|
return prop->pointer;
|
||||||
|
|
||||||
|
return &prop->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *property_entry_find(const struct property_entry *props,
|
static const void *property_entry_find(const struct property_entry *props,
|
||||||
@ -187,66 +131,6 @@ static const void *property_entry_find(const struct property_entry *props,
|
|||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_entry_read_u8_array(const struct property_entry *props,
|
|
||||||
const char *propname,
|
|
||||||
u8 *values, size_t nval)
|
|
||||||
{
|
|
||||||
const void *pointer;
|
|
||||||
size_t length = nval * sizeof(*values);
|
|
||||||
|
|
||||||
pointer = property_entry_find(props, propname, length);
|
|
||||||
if (IS_ERR(pointer))
|
|
||||||
return PTR_ERR(pointer);
|
|
||||||
|
|
||||||
memcpy(values, pointer, length);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int property_entry_read_u16_array(const struct property_entry *props,
|
|
||||||
const char *propname,
|
|
||||||
u16 *values, size_t nval)
|
|
||||||
{
|
|
||||||
const void *pointer;
|
|
||||||
size_t length = nval * sizeof(*values);
|
|
||||||
|
|
||||||
pointer = property_entry_find(props, propname, length);
|
|
||||||
if (IS_ERR(pointer))
|
|
||||||
return PTR_ERR(pointer);
|
|
||||||
|
|
||||||
memcpy(values, pointer, length);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int property_entry_read_u32_array(const struct property_entry *props,
|
|
||||||
const char *propname,
|
|
||||||
u32 *values, size_t nval)
|
|
||||||
{
|
|
||||||
const void *pointer;
|
|
||||||
size_t length = nval * sizeof(*values);
|
|
||||||
|
|
||||||
pointer = property_entry_find(props, propname, length);
|
|
||||||
if (IS_ERR(pointer))
|
|
||||||
return PTR_ERR(pointer);
|
|
||||||
|
|
||||||
memcpy(values, pointer, length);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int property_entry_read_u64_array(const struct property_entry *props,
|
|
||||||
const char *propname,
|
|
||||||
u64 *values, size_t nval)
|
|
||||||
{
|
|
||||||
const void *pointer;
|
|
||||||
size_t length = nval * sizeof(*values);
|
|
||||||
|
|
||||||
pointer = property_entry_find(props, propname, length);
|
|
||||||
if (IS_ERR(pointer))
|
|
||||||
return PTR_ERR(pointer);
|
|
||||||
|
|
||||||
memcpy(values, pointer, length);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
property_entry_count_elems_of_size(const struct property_entry *props,
|
property_entry_count_elems_of_size(const struct property_entry *props,
|
||||||
const char *propname, size_t length)
|
const char *propname, size_t length)
|
||||||
@ -265,49 +149,45 @@ static int property_entry_read_int_array(const struct property_entry *props,
|
|||||||
unsigned int elem_size, void *val,
|
unsigned int elem_size, void *val,
|
||||||
size_t nval)
|
size_t nval)
|
||||||
{
|
{
|
||||||
|
const void *pointer;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return property_entry_count_elems_of_size(props, name,
|
return property_entry_count_elems_of_size(props, name,
|
||||||
elem_size);
|
elem_size);
|
||||||
switch (elem_size) {
|
|
||||||
case sizeof(u8):
|
|
||||||
return property_entry_read_u8_array(props, name, val, nval);
|
|
||||||
case sizeof(u16):
|
|
||||||
return property_entry_read_u16_array(props, name, val, nval);
|
|
||||||
case sizeof(u32):
|
|
||||||
return property_entry_read_u32_array(props, name, val, nval);
|
|
||||||
case sizeof(u64):
|
|
||||||
return property_entry_read_u64_array(props, name, val, nval);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENXIO;
|
if (!is_power_of_2(elem_size) || elem_size > sizeof(u64))
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
length = nval * elem_size;
|
||||||
|
|
||||||
|
pointer = property_entry_find(props, name, length);
|
||||||
|
if (IS_ERR(pointer))
|
||||||
|
return PTR_ERR(pointer);
|
||||||
|
|
||||||
|
memcpy(val, pointer, length);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_entry_read_string_array(const struct property_entry *props,
|
static int property_entry_read_string_array(const struct property_entry *props,
|
||||||
const char *propname,
|
const char *propname,
|
||||||
const char **strings, size_t nval)
|
const char **strings, size_t nval)
|
||||||
{
|
{
|
||||||
const struct property_entry *prop;
|
|
||||||
const void *pointer;
|
const void *pointer;
|
||||||
size_t array_len, length;
|
size_t length;
|
||||||
|
int array_len;
|
||||||
|
|
||||||
/* Find out the array length. */
|
/* Find out the array length. */
|
||||||
prop = property_entry_get(props, propname);
|
array_len = property_entry_count_elems_of_size(props, propname,
|
||||||
if (!prop)
|
sizeof(const char *));
|
||||||
return -EINVAL;
|
if (array_len < 0)
|
||||||
|
return array_len;
|
||||||
if (prop->is_array)
|
|
||||||
/* Find the length of an array. */
|
|
||||||
array_len = property_entry_count_elems_of_size(props, propname,
|
|
||||||
sizeof(const char *));
|
|
||||||
else
|
|
||||||
/* The array length for a non-array string property is 1. */
|
|
||||||
array_len = 1;
|
|
||||||
|
|
||||||
/* Return how many there are if strings is NULL. */
|
/* Return how many there are if strings is NULL. */
|
||||||
if (!strings)
|
if (!strings)
|
||||||
return array_len;
|
return array_len;
|
||||||
|
|
||||||
array_len = min(nval, array_len);
|
array_len = min_t(size_t, nval, array_len);
|
||||||
length = array_len * sizeof(*strings);
|
length = array_len * sizeof(*strings);
|
||||||
|
|
||||||
pointer = property_entry_find(props, propname, length);
|
pointer = property_entry_find(props, propname, length);
|
||||||
@ -322,13 +202,15 @@ static int property_entry_read_string_array(const struct property_entry *props,
|
|||||||
static void property_entry_free_data(const struct property_entry *p)
|
static void property_entry_free_data(const struct property_entry *p)
|
||||||
{
|
{
|
||||||
const void *pointer = property_get_pointer(p);
|
const void *pointer = property_get_pointer(p);
|
||||||
|
const char * const *src_str;
|
||||||
size_t i, nval;
|
size_t i, nval;
|
||||||
|
|
||||||
if (p->is_array) {
|
if (p->is_array) {
|
||||||
if (p->type == DEV_PROP_STRING && p->pointer.str) {
|
if (p->type == DEV_PROP_STRING && p->pointer) {
|
||||||
|
src_str = p->pointer;
|
||||||
nval = p->length / sizeof(const char *);
|
nval = p->length / sizeof(const char *);
|
||||||
for (i = 0; i < nval; i++)
|
for (i = 0; i < nval; i++)
|
||||||
kfree(p->pointer.str[i]);
|
kfree(src_str[i]);
|
||||||
}
|
}
|
||||||
kfree(pointer);
|
kfree(pointer);
|
||||||
} else if (p->type == DEV_PROP_STRING) {
|
} else if (p->type == DEV_PROP_STRING) {
|
||||||
@ -337,29 +219,29 @@ static void property_entry_free_data(const struct property_entry *p)
|
|||||||
kfree(p->name);
|
kfree(p->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_copy_string_array(struct property_entry *dst,
|
static const char * const *
|
||||||
const struct property_entry *src)
|
property_copy_string_array(const struct property_entry *src)
|
||||||
{
|
{
|
||||||
const char **d;
|
const char **d;
|
||||||
|
const char * const *src_str = src->pointer;
|
||||||
size_t nval = src->length / sizeof(*d);
|
size_t nval = src->length / sizeof(*d);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
|
d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < nval; i++) {
|
for (i = 0; i < nval; i++) {
|
||||||
d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
|
d[i] = kstrdup(src_str[i], GFP_KERNEL);
|
||||||
if (!d[i] && src->pointer.str[i]) {
|
if (!d[i] && src_str[i]) {
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
kfree(d[i]);
|
kfree(d[i]);
|
||||||
kfree(d);
|
kfree(d);
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->pointer.str = d;
|
return d;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_entry_copy_data(struct property_entry *dst,
|
static int property_entry_copy_data(struct property_entry *dst,
|
||||||
@ -367,36 +249,35 @@ static int property_entry_copy_data(struct property_entry *dst,
|
|||||||
{
|
{
|
||||||
const void *pointer = property_get_pointer(src);
|
const void *pointer = property_get_pointer(src);
|
||||||
const void *new;
|
const void *new;
|
||||||
int error;
|
|
||||||
|
|
||||||
if (src->is_array) {
|
if (src->is_array) {
|
||||||
if (!src->length)
|
if (!src->length)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
if (src->type == DEV_PROP_STRING) {
|
if (src->type == DEV_PROP_STRING) {
|
||||||
error = property_copy_string_array(dst, src);
|
new = property_copy_string_array(src);
|
||||||
if (error)
|
if (!new)
|
||||||
return error;
|
return -ENOMEM;
|
||||||
new = dst->pointer.str;
|
|
||||||
} else {
|
} else {
|
||||||
new = kmemdup(pointer, src->length, GFP_KERNEL);
|
new = kmemdup(pointer, src->length, GFP_KERNEL);
|
||||||
if (!new)
|
if (!new)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dst->is_array = true;
|
||||||
|
dst->pointer = new;
|
||||||
} else if (src->type == DEV_PROP_STRING) {
|
} else if (src->type == DEV_PROP_STRING) {
|
||||||
new = kstrdup(src->value.str, GFP_KERNEL);
|
new = kstrdup(src->value.str, GFP_KERNEL);
|
||||||
if (!new && src->value.str)
|
if (!new && src->value.str)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dst->value.str = new;
|
||||||
} else {
|
} else {
|
||||||
new = pointer;
|
dst->value = src->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->length = src->length;
|
dst->length = src->length;
|
||||||
dst->is_array = src->is_array;
|
|
||||||
dst->type = src->type;
|
dst->type = src->type;
|
||||||
|
|
||||||
property_set_pointer(dst, new);
|
|
||||||
|
|
||||||
dst->name = kstrdup(src->name, GFP_KERNEL);
|
dst->name = kstrdup(src->name, GFP_KERNEL);
|
||||||
if (!dst->name)
|
if (!dst->name)
|
||||||
goto out_free_data;
|
goto out_free_data;
|
||||||
@ -515,12 +396,47 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode,
|
|||||||
propname, val, nval);
|
propname, val, nval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
software_node_get_name(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
const struct swnode *swnode = to_swnode(fwnode);
|
||||||
|
|
||||||
|
if (!swnode)
|
||||||
|
return "(null)";
|
||||||
|
|
||||||
|
return kobject_name(&swnode->kobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
software_node_get_name_prefix(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
struct fwnode_handle *parent;
|
||||||
|
const char *prefix;
|
||||||
|
|
||||||
|
parent = fwnode_get_parent(fwnode);
|
||||||
|
if (!parent)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
/* Figure out the prefix from the parents. */
|
||||||
|
while (is_software_node(parent))
|
||||||
|
parent = fwnode_get_next_parent(parent);
|
||||||
|
|
||||||
|
prefix = fwnode_get_name_prefix(parent);
|
||||||
|
fwnode_handle_put(parent);
|
||||||
|
|
||||||
|
/* Guess something if prefix was NULL. */
|
||||||
|
return prefix ?: "/";
|
||||||
|
}
|
||||||
|
|
||||||
static struct fwnode_handle *
|
static struct fwnode_handle *
|
||||||
software_node_get_parent(const struct fwnode_handle *fwnode)
|
software_node_get_parent(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct swnode *swnode = to_swnode(fwnode);
|
struct swnode *swnode = to_swnode(fwnode);
|
||||||
|
|
||||||
return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : NULL;
|
if (!swnode || !swnode->parent)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return fwnode_handle_get(&swnode->parent->fwnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fwnode_handle *
|
static struct fwnode_handle *
|
||||||
@ -612,6 +528,8 @@ static const struct fwnode_operations software_node_ops = {
|
|||||||
.property_present = software_node_property_present,
|
.property_present = software_node_property_present,
|
||||||
.property_read_int_array = software_node_read_int_array,
|
.property_read_int_array = software_node_read_int_array,
|
||||||
.property_read_string_array = software_node_read_string_array,
|
.property_read_string_array = software_node_read_string_array,
|
||||||
|
.get_name = software_node_get_name,
|
||||||
|
.get_name_prefix = software_node_get_name_prefix,
|
||||||
.get_parent = software_node_get_parent,
|
.get_parent = software_node_get_parent,
|
||||||
.get_next_child_node = software_node_get_next_child,
|
.get_next_child_node = software_node_get_next_child,
|
||||||
.get_named_child_node = software_node_get_named_child_node,
|
.get_named_child_node = software_node_get_named_child_node,
|
||||||
|
@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
|
|||||||
|
|
||||||
for (i = 0; i < dev_header->prop_count; i++) {
|
for (i = 0; i < dev_header->prop_count; i++) {
|
||||||
int remaining = dev_header->len - (ptr - (void *)dev_header);
|
int remaining = dev_header->len - (ptr - (void *)dev_header);
|
||||||
u32 key_len, val_len;
|
u32 key_len, val_len, entry_len;
|
||||||
|
const u8 *entry_data;
|
||||||
char *key;
|
char *key;
|
||||||
|
|
||||||
if (sizeof(key_len) > remaining)
|
if (sizeof(key_len) > remaining)
|
||||||
@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
|
|||||||
ucs2_as_utf8(key, ptr + sizeof(key_len),
|
ucs2_as_utf8(key, ptr + sizeof(key_len),
|
||||||
key_len - sizeof(key_len));
|
key_len - sizeof(key_len));
|
||||||
|
|
||||||
entry[i].name = key;
|
entry_data = ptr + key_len + sizeof(val_len);
|
||||||
entry[i].length = val_len - sizeof(val_len);
|
entry_len = val_len - sizeof(val_len);
|
||||||
entry[i].is_array = !!entry[i].length;
|
entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
|
||||||
entry[i].type = DEV_PROP_U8;
|
entry_len);
|
||||||
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
|
|
||||||
|
|
||||||
if (dump_properties) {
|
if (dump_properties) {
|
||||||
dev_info(dev, "property: %s\n", entry[i].name);
|
dev_info(dev, "property: %s\n", key);
|
||||||
print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
|
print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
|
||||||
16, 1, entry[i].pointer.u8_data,
|
16, 1, entry_data, entry_len, true);
|
||||||
entry[i].length, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += key_len + val_len;
|
ptr += key_len + val_len;
|
||||||
|
@ -872,6 +872,20 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
|
|||||||
of_property_count_strings(node, propname);
|
of_property_count_strings(node, propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *of_fwnode_get_name(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return kbasename(to_of_node(fwnode)->full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *of_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
/* Root needs no prefix here (its name is "/"). */
|
||||||
|
if (!to_of_node(fwnode)->parent)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
static struct fwnode_handle *
|
static struct fwnode_handle *
|
||||||
of_fwnode_get_parent(const struct fwnode_handle *fwnode)
|
of_fwnode_get_parent(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
@ -993,6 +1007,8 @@ const struct fwnode_operations of_fwnode_ops = {
|
|||||||
.property_present = of_fwnode_property_present,
|
.property_present = of_fwnode_property_present,
|
||||||
.property_read_int_array = of_fwnode_property_read_int_array,
|
.property_read_int_array = of_fwnode_property_read_int_array,
|
||||||
.property_read_string_array = of_fwnode_property_read_string_array,
|
.property_read_string_array = of_fwnode_property_read_string_array,
|
||||||
|
.get_name = of_fwnode_get_name,
|
||||||
|
.get_name_prefix = of_fwnode_get_name_prefix,
|
||||||
.get_parent = of_fwnode_get_parent,
|
.get_parent = of_fwnode_get_parent,
|
||||||
.get_next_child_node = of_fwnode_get_next_child_node,
|
.get_next_child_node = of_fwnode_get_next_child_node,
|
||||||
.get_named_child_node = of_fwnode_get_named_child_node,
|
.get_named_child_node = of_fwnode_get_named_child_node,
|
||||||
|
@ -49,13 +49,15 @@ struct fwnode_reference_args {
|
|||||||
* struct fwnode_operations - Operations for fwnode interface
|
* struct fwnode_operations - Operations for fwnode interface
|
||||||
* @get: Get a reference to an fwnode.
|
* @get: Get a reference to an fwnode.
|
||||||
* @put: Put a reference to an fwnode.
|
* @put: Put a reference to an fwnode.
|
||||||
|
* @device_is_available: Return true if the device is available.
|
||||||
* @device_get_match_data: Return the device driver match data.
|
* @device_get_match_data: Return the device driver match data.
|
||||||
* @property_present: Return true if a property is present.
|
* @property_present: Return true if a property is present.
|
||||||
* @property_read_integer_array: Read an array of integer properties. Return
|
* @property_read_int_array: Read an array of integer properties. Return zero on
|
||||||
* zero on success, a negative error code
|
* success, a negative error code otherwise.
|
||||||
* otherwise.
|
|
||||||
* @property_read_string_array: Read an array of string properties. Return zero
|
* @property_read_string_array: Read an array of string properties. Return zero
|
||||||
* on success, a negative error code otherwise.
|
* on success, a negative error code otherwise.
|
||||||
|
* @get_name: Return the name of an fwnode.
|
||||||
|
* @get_name_prefix: Get a prefix for a node (for printing purposes).
|
||||||
* @get_parent: Return the parent of an fwnode.
|
* @get_parent: Return the parent of an fwnode.
|
||||||
* @get_next_child_node: Return the next child node in an iteration.
|
* @get_next_child_node: Return the next child node in an iteration.
|
||||||
* @get_named_child_node: Return a child node with a given name.
|
* @get_named_child_node: Return a child node with a given name.
|
||||||
@ -82,6 +84,8 @@ struct fwnode_operations {
|
|||||||
(*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
|
(*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
|
||||||
const char *propname, const char **val,
|
const char *propname, const char **val,
|
||||||
size_t nval);
|
size_t nval);
|
||||||
|
const char *(*get_name)(const struct fwnode_handle *fwnode);
|
||||||
|
const char *(*get_name_prefix)(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode);
|
struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *
|
struct fwnode_handle *
|
||||||
(*get_next_child_node)(const struct fwnode_handle *fwnode,
|
(*get_next_child_node)(const struct fwnode_handle *fwnode,
|
||||||
|
@ -22,7 +22,6 @@ enum dev_prop_type {
|
|||||||
DEV_PROP_U32,
|
DEV_PROP_U32,
|
||||||
DEV_PROP_U64,
|
DEV_PROP_U64,
|
||||||
DEV_PROP_STRING,
|
DEV_PROP_STRING,
|
||||||
DEV_PROP_MAX,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dev_dma_attr {
|
enum dev_dma_attr {
|
||||||
@ -80,9 +79,14 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
|
|||||||
const char *name,
|
const char *name,
|
||||||
unsigned int index);
|
unsigned int index);
|
||||||
|
|
||||||
|
const char *fwnode_get_name(const struct fwnode_handle *fwnode);
|
||||||
|
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
|
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *fwnode_get_next_parent(
|
struct fwnode_handle *fwnode_get_next_parent(
|
||||||
struct fwnode_handle *fwnode);
|
struct fwnode_handle *fwnode);
|
||||||
|
unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
|
||||||
|
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
|
||||||
|
unsigned int depth);
|
||||||
struct fwnode_handle *fwnode_get_next_child_node(
|
struct fwnode_handle *fwnode_get_next_child_node(
|
||||||
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
|
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
|
||||||
struct fwnode_handle *fwnode_get_next_available_child_node(
|
struct fwnode_handle *fwnode_get_next_available_child_node(
|
||||||
@ -234,13 +238,7 @@ struct property_entry {
|
|||||||
bool is_array;
|
bool is_array;
|
||||||
enum dev_prop_type type;
|
enum dev_prop_type type;
|
||||||
union {
|
union {
|
||||||
union {
|
const void *pointer;
|
||||||
const u8 *u8_data;
|
|
||||||
const u16 *u16_data;
|
|
||||||
const u32 *u32_data;
|
|
||||||
const u64 *u64_data;
|
|
||||||
const char * const *str;
|
|
||||||
} pointer;
|
|
||||||
union {
|
union {
|
||||||
u8 u8_data;
|
u8 u8_data;
|
||||||
u16 u16_data;
|
u16 u16_data;
|
||||||
@ -252,62 +250,63 @@ struct property_entry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: the below four initializers for the anonymous union are carefully
|
* Note: the below initializers for the anonymous union are carefully
|
||||||
* crafted to avoid gcc-4.4.4's problems with initialization of anon unions
|
* crafted to avoid gcc-4.4.4's problems with initialization of anon unions
|
||||||
* and structs.
|
* and structs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_) \
|
#define __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_) \
|
||||||
|
sizeof(((struct property_entry *)NULL)->value._elem_)
|
||||||
|
|
||||||
|
#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _elem_, _Type_, _val_, _len_)\
|
||||||
(struct property_entry) { \
|
(struct property_entry) { \
|
||||||
.name = _name_, \
|
.name = _name_, \
|
||||||
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \
|
.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
|
||||||
.is_array = true, \
|
.is_array = true, \
|
||||||
.type = DEV_PROP_##_Type_, \
|
.type = DEV_PROP_##_Type_, \
|
||||||
{ .pointer = { ._type_##_data = _val_ } }, \
|
{ .pointer = _val_ }, \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
|
#define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_) \
|
||||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
|
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8_data, U8, _val_, _len_)
|
||||||
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
|
#define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_) \
|
||||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
|
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16_data, U16, _val_, _len_)
|
||||||
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
|
#define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_) \
|
||||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
|
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32_data, U32, _val_, _len_)
|
||||||
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
|
#define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_) \
|
||||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
|
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64_data, U64, _val_, _len_)
|
||||||
|
#define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_) \
|
||||||
|
__PROPERTY_ENTRY_ARRAY_LEN(_name_, str, STRING, _val_, _len_)
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
|
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
|
||||||
(struct property_entry) { \
|
PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||||
.name = _name_, \
|
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
|
||||||
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \
|
PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||||
.is_array = true, \
|
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
|
||||||
.type = DEV_PROP_STRING, \
|
PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||||
{ .pointer = { .str = _val_ } }, \
|
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
|
||||||
|
PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||||
|
#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
|
||||||
|
PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||||
|
|
||||||
|
#define __PROPERTY_ENTRY_ELEMENT(_name_, _elem_, _Type_, _val_) \
|
||||||
|
(struct property_entry) { \
|
||||||
|
.name = _name_, \
|
||||||
|
.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
|
||||||
|
.type = DEV_PROP_##_Type_, \
|
||||||
|
{ .value = { ._elem_ = _val_ } }, \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \
|
#define PROPERTY_ENTRY_U8(_name_, _val_) \
|
||||||
(struct property_entry) { \
|
__PROPERTY_ENTRY_ELEMENT(_name_, u8_data, U8, _val_)
|
||||||
.name = _name_, \
|
#define PROPERTY_ENTRY_U16(_name_, _val_) \
|
||||||
.length = sizeof(_type_), \
|
__PROPERTY_ENTRY_ELEMENT(_name_, u16_data, U16, _val_)
|
||||||
.type = DEV_PROP_##_Type_, \
|
#define PROPERTY_ENTRY_U32(_name_, _val_) \
|
||||||
{ .value = { ._type_##_data = _val_ } }, \
|
__PROPERTY_ENTRY_ELEMENT(_name_, u32_data, U32, _val_)
|
||||||
}
|
#define PROPERTY_ENTRY_U64(_name_, _val_) \
|
||||||
|
__PROPERTY_ENTRY_ELEMENT(_name_, u64_data, U64, _val_)
|
||||||
#define PROPERTY_ENTRY_U8(_name_, _val_) \
|
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
|
||||||
PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
|
__PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_)
|
||||||
#define PROPERTY_ENTRY_U16(_name_, _val_) \
|
|
||||||
PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
|
|
||||||
#define PROPERTY_ENTRY_U32(_name_, _val_) \
|
|
||||||
PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
|
|
||||||
#define PROPERTY_ENTRY_U64(_name_, _val_) \
|
|
||||||
PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
|
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
|
|
||||||
(struct property_entry) { \
|
|
||||||
.name = _name_, \
|
|
||||||
.length = sizeof(const char *), \
|
|
||||||
.type = DEV_PROP_STRING, \
|
|
||||||
{ .value = { .str = _val_ } }, \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PROPERTY_ENTRY_BOOL(_name_) \
|
#define PROPERTY_ENTRY_BOOL(_name_) \
|
||||||
(struct property_entry) { \
|
(struct property_entry) { \
|
||||||
@ -418,7 +417,8 @@ struct software_node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool is_software_node(const struct fwnode_handle *fwnode);
|
bool is_software_node(const struct fwnode_handle *fwnode);
|
||||||
const struct software_node *to_software_node(struct fwnode_handle *fwnode);
|
const struct software_node *
|
||||||
|
to_software_node(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *software_node_fwnode(const struct software_node *node);
|
struct fwnode_handle *software_node_fwnode(const struct software_node *node);
|
||||||
|
|
||||||
const struct software_node *
|
const struct software_node *
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
|
||||||
|
#include <linux/property.h>
|
||||||
|
|
||||||
#include "../tools/testing/selftests/kselftest_module.h"
|
#include "../tools/testing/selftests/kselftest_module.h"
|
||||||
|
|
||||||
#define BUF_SIZE 256
|
#define BUF_SIZE 256
|
||||||
@ -593,6 +595,35 @@ flags(void)
|
|||||||
kfree(cmp_buffer);
|
kfree(cmp_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init fwnode_pointer(void)
|
||||||
|
{
|
||||||
|
const struct software_node softnodes[] = {
|
||||||
|
{ .name = "first", },
|
||||||
|
{ .name = "second", .parent = &softnodes[0], },
|
||||||
|
{ .name = "third", .parent = &softnodes[1], },
|
||||||
|
{ NULL /* Guardian */ }
|
||||||
|
};
|
||||||
|
const char * const full_name = "first/second/third";
|
||||||
|
const char * const full_name_second = "first/second";
|
||||||
|
const char * const second_name = "second";
|
||||||
|
const char * const third_name = "third";
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
rval = software_node_register_nodes(softnodes);
|
||||||
|
if (rval) {
|
||||||
|
pr_warn("cannot register softnodes; rval %d\n", rval);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(full_name_second, "%pfw", software_node_fwnode(&softnodes[1]));
|
||||||
|
test(full_name, "%pfw", software_node_fwnode(&softnodes[2]));
|
||||||
|
test(full_name, "%pfwf", software_node_fwnode(&softnodes[2]));
|
||||||
|
test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
|
||||||
|
test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
|
||||||
|
|
||||||
|
software_node_unregister_nodes(softnodes);
|
||||||
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
errptr(void)
|
errptr(void)
|
||||||
{
|
{
|
||||||
@ -636,6 +667,7 @@ test_pointer(void)
|
|||||||
netdev_features();
|
netdev_features();
|
||||||
flags();
|
flags();
|
||||||
errptr();
|
errptr();
|
||||||
|
fwnode_pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init selftest(void)
|
static void __init selftest(void)
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
#include <linux/siphash.h>
|
#include <linux/siphash.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#endif
|
#endif
|
||||||
@ -938,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr,
|
|||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
if (*fmt == 'B')
|
if (*fmt == 'B')
|
||||||
sprint_backtrace(sym, value);
|
sprint_backtrace(sym, value);
|
||||||
else if (*fmt != 'f' && *fmt != 's')
|
else if (*fmt != 's')
|
||||||
sprint_symbol(sym, value);
|
sprint_symbol(sym, value);
|
||||||
else
|
else
|
||||||
sprint_symbol_no_offset(sym, value);
|
sprint_symbol_no_offset(sym, value);
|
||||||
@ -1892,32 +1893,25 @@ char *flags_string(char *buf, char *end, void *flags_ptr,
|
|||||||
return format_flags(buf, end, flags, names);
|
return format_flags(buf, end, flags, names);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *device_node_name_for_depth(const struct device_node *np, int depth)
|
|
||||||
{
|
|
||||||
for ( ; np && depth; depth--)
|
|
||||||
np = np->parent;
|
|
||||||
|
|
||||||
return kbasename(np->full_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static noinline_for_stack
|
static noinline_for_stack
|
||||||
char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
|
char *fwnode_full_name_string(struct fwnode_handle *fwnode, char *buf,
|
||||||
|
char *end)
|
||||||
{
|
{
|
||||||
int depth;
|
int depth;
|
||||||
const struct device_node *parent = np->parent;
|
|
||||||
|
|
||||||
/* special case for root node */
|
/* Loop starting from the root node to the current node. */
|
||||||
if (!parent)
|
for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) {
|
||||||
return string_nocheck(buf, end, "/", default_str_spec);
|
struct fwnode_handle *__fwnode =
|
||||||
|
fwnode_get_nth_parent(fwnode, depth);
|
||||||
|
|
||||||
for (depth = 0; parent->parent; depth++)
|
buf = string(buf, end, fwnode_get_name_prefix(__fwnode),
|
||||||
parent = parent->parent;
|
|
||||||
|
|
||||||
for ( ; depth >= 0; depth--) {
|
|
||||||
buf = string_nocheck(buf, end, "/", default_str_spec);
|
|
||||||
buf = string(buf, end, device_node_name_for_depth(np, depth),
|
|
||||||
default_str_spec);
|
default_str_spec);
|
||||||
|
buf = string(buf, end, fwnode_get_name(__fwnode),
|
||||||
|
default_str_spec);
|
||||||
|
|
||||||
|
fwnode_handle_put(__fwnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1941,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|||||||
struct printf_spec str_spec = spec;
|
struct printf_spec str_spec = spec;
|
||||||
str_spec.field_width = -1;
|
str_spec.field_width = -1;
|
||||||
|
|
||||||
|
if (fmt[0] != 'F')
|
||||||
|
return error_string(buf, end, "(%pO?)", spec);
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_OF))
|
if (!IS_ENABLED(CONFIG_OF))
|
||||||
return error_string(buf, end, "(%pOF?)", spec);
|
return error_string(buf, end, "(%pOF?)", spec);
|
||||||
|
|
||||||
@ -1962,10 +1959,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|||||||
|
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case 'f': /* full_name */
|
case 'f': /* full_name */
|
||||||
buf = device_node_gen_full_name(dn, buf, end);
|
buf = fwnode_full_name_string(of_fwnode_handle(dn), buf,
|
||||||
|
end);
|
||||||
break;
|
break;
|
||||||
case 'n': /* name */
|
case 'n': /* name */
|
||||||
p = kbasename(of_node_full_name(dn));
|
p = fwnode_get_name(of_fwnode_handle(dn));
|
||||||
precision = str_spec.precision;
|
precision = str_spec.precision;
|
||||||
str_spec.precision = strchrnul(p, '@') - p;
|
str_spec.precision = strchrnul(p, '@') - p;
|
||||||
buf = string(buf, end, p, str_spec);
|
buf = string(buf, end, p, str_spec);
|
||||||
@ -1975,7 +1973,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|||||||
buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
|
buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
|
||||||
break;
|
break;
|
||||||
case 'P': /* path-spec */
|
case 'P': /* path-spec */
|
||||||
p = kbasename(of_node_full_name(dn));
|
p = fwnode_get_name(of_fwnode_handle(dn));
|
||||||
if (!p[1])
|
if (!p[1])
|
||||||
p = "/";
|
p = "/";
|
||||||
buf = string(buf, end, p, str_spec);
|
buf = string(buf, end, p, str_spec);
|
||||||
@ -2013,15 +2011,34 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|||||||
return widen_string(buf, buf - buf_start, end, spec);
|
return widen_string(buf, buf - buf_start, end, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *kobject_string(char *buf, char *end, void *ptr,
|
static noinline_for_stack
|
||||||
struct printf_spec spec, const char *fmt)
|
char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
|
||||||
|
struct printf_spec spec, const char *fmt)
|
||||||
{
|
{
|
||||||
switch (fmt[1]) {
|
struct printf_spec str_spec = spec;
|
||||||
case 'F':
|
char *buf_start = buf;
|
||||||
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
|
||||||
|
str_spec.field_width = -1;
|
||||||
|
|
||||||
|
if (*fmt != 'w')
|
||||||
|
return error_string(buf, end, "(%pf?)", spec);
|
||||||
|
|
||||||
|
if (check_pointer(&buf, end, fwnode, spec))
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
fmt++;
|
||||||
|
|
||||||
|
switch (*fmt) {
|
||||||
|
case 'P': /* name */
|
||||||
|
buf = string(buf, end, fwnode_get_name(fwnode), str_spec);
|
||||||
|
break;
|
||||||
|
case 'f': /* full_name */
|
||||||
|
default:
|
||||||
|
buf = fwnode_full_name_string(fwnode, buf, end);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error_string(buf, end, "(%pO?)", spec);
|
return widen_string(buf, buf - buf_start, end, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2036,9 +2053,9 @@ static char *kobject_string(char *buf, char *end, void *ptr,
|
|||||||
*
|
*
|
||||||
* - 'S' For symbolic direct pointers (or function descriptors) with offset
|
* - 'S' For symbolic direct pointers (or function descriptors) with offset
|
||||||
* - 's' For symbolic direct pointers (or function descriptors) without offset
|
* - 's' For symbolic direct pointers (or function descriptors) without offset
|
||||||
* - 'F' Same as 'S'
|
* - '[Ss]R' as above with __builtin_extract_return_addr() translation
|
||||||
* - 'f' Same as 's'
|
* - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
|
||||||
* - '[FfSs]R' as above with __builtin_extract_return_addr() translation
|
* %ps and %pS. Be careful when re-using these specifiers.
|
||||||
* - 'B' For backtraced symbolic direct pointers with offset
|
* - 'B' For backtraced symbolic direct pointers with offset
|
||||||
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
|
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
|
||||||
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
|
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
|
||||||
@ -2128,6 +2145,10 @@ static char *kobject_string(char *buf, char *end, void *ptr,
|
|||||||
* F device node flags
|
* F device node flags
|
||||||
* c major compatible string
|
* c major compatible string
|
||||||
* C full compatible string
|
* C full compatible string
|
||||||
|
* - 'fw[fP]' For a firmware node (struct fwnode_handle) pointer
|
||||||
|
* Without an option prints the full name of the node
|
||||||
|
* f full name
|
||||||
|
* P node name, including a possible unit address
|
||||||
* - 'x' For printing the address. Equivalent to "%lx".
|
* - 'x' For printing the address. Equivalent to "%lx".
|
||||||
*
|
*
|
||||||
* ** When making changes please also update:
|
* ** When making changes please also update:
|
||||||
@ -2141,8 +2162,6 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|||||||
struct printf_spec spec)
|
struct printf_spec spec)
|
||||||
{
|
{
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case 'F':
|
|
||||||
case 'f':
|
|
||||||
case 'S':
|
case 'S':
|
||||||
case 's':
|
case 's':
|
||||||
ptr = dereference_symbol_descriptor(ptr);
|
ptr = dereference_symbol_descriptor(ptr);
|
||||||
@ -2204,7 +2223,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|||||||
case 'G':
|
case 'G':
|
||||||
return flags_string(buf, end, ptr, spec, fmt);
|
return flags_string(buf, end, ptr, spec, fmt);
|
||||||
case 'O':
|
case 'O':
|
||||||
return kobject_string(buf, end, ptr, spec, fmt);
|
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
||||||
|
case 'f':
|
||||||
|
return fwnode_string(buf, end, ptr, spec, fmt + 1);
|
||||||
case 'x':
|
case 'x':
|
||||||
return pointer_string(buf, end, ptr, spec);
|
return pointer_string(buf, end, ptr, spec);
|
||||||
case 'e':
|
case 'e':
|
||||||
@ -2844,8 +2865,6 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
|
|||||||
/* Dereference of functions is still OK */
|
/* Dereference of functions is still OK */
|
||||||
case 'S':
|
case 'S':
|
||||||
case 's':
|
case 's':
|
||||||
case 'F':
|
|
||||||
case 'f':
|
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'K':
|
case 'K':
|
||||||
case 'e':
|
case 'e':
|
||||||
|
@ -6015,14 +6015,18 @@ sub process {
|
|||||||
for (my $count = $linenr; $count <= $lc; $count++) {
|
for (my $count = $linenr; $count <= $lc; $count++) {
|
||||||
my $specifier;
|
my $specifier;
|
||||||
my $extension;
|
my $extension;
|
||||||
|
my $qualifier;
|
||||||
my $bad_specifier = "";
|
my $bad_specifier = "";
|
||||||
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
|
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
|
||||||
$fmt =~ s/%%//g;
|
$fmt =~ s/%%//g;
|
||||||
|
|
||||||
while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
|
while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
|
||||||
$specifier = $1;
|
$specifier = $1;
|
||||||
$extension = $2;
|
$extension = $2;
|
||||||
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxt]/) {
|
$qualifier = $3;
|
||||||
|
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
|
||||||
|
($extension eq "f" &&
|
||||||
|
defined $qualifier && $qualifier !~ /^w/)) {
|
||||||
$bad_specifier = $specifier;
|
$bad_specifier = $specifier;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
@ -6039,7 +6043,6 @@ sub process {
|
|||||||
my $ext_type = "Invalid";
|
my $ext_type = "Invalid";
|
||||||
my $use = "";
|
my $use = "";
|
||||||
if ($bad_specifier =~ /p[Ff]/) {
|
if ($bad_specifier =~ /p[Ff]/) {
|
||||||
$ext_type = "Deprecated";
|
|
||||||
$use = " - use %pS instead";
|
$use = " - use %pS instead";
|
||||||
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
|
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user