forked from Minki/linux
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
|
||||
%pF versatile_init+0x0/0x110
|
||||
%pf versatile_init
|
||||
%pSR versatile_init+0x9/0x110
|
||||
(with __builtin_extract_return_addr() translation)
|
||||
%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)
|
||||
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
|
||||
used when printing stack backtraces. The specifier takes into
|
||||
consideration the effect of compiler optimisations which may occur
|
||||
@ -440,6 +430,30 @@ Examples::
|
||||
|
||||
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)
|
||||
-------------------------------
|
||||
|
||||
|
@ -1317,6 +1317,52 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
|
||||
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 *
|
||||
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_next_child_node = acpi_get_next_subnode, \
|
||||
.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, \
|
||||
.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);
|
||||
|
||||
/**
|
||||
* 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: 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);
|
||||
|
||||
/**
|
||||
* fwnode_get_parent - Return parent firwmare node
|
||||
* @fwnode: Firmware whose parent is retrieved
|
||||
* fwnode_count_parents - Return the number of parents a node has
|
||||
* @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
|
||||
* parent was available.
|
||||
* Returns the number of parents a node has.
|
||||
*/
|
||||
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
|
||||
|
@ -71,9 +71,9 @@ software_node_to_swnode(const struct software_node *node)
|
||||
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;
|
||||
}
|
||||
@ -103,71 +103,15 @@ property_entry_get(const struct property_entry *prop, const char *name)
|
||||
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)
|
||||
{
|
||||
switch (prop->type) {
|
||||
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:
|
||||
if (!prop->length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (prop->is_array)
|
||||
return prop->pointer;
|
||||
|
||||
return &prop->value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
property_entry_count_elems_of_size(const struct property_entry *props,
|
||||
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,
|
||||
size_t nval)
|
||||
{
|
||||
const void *pointer;
|
||||
size_t length;
|
||||
|
||||
if (!val)
|
||||
return property_entry_count_elems_of_size(props, name,
|
||||
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,
|
||||
const char *propname,
|
||||
const char **strings, size_t nval)
|
||||
{
|
||||
const struct property_entry *prop;
|
||||
const void *pointer;
|
||||
size_t array_len, length;
|
||||
size_t length;
|
||||
int array_len;
|
||||
|
||||
/* Find out the array length. */
|
||||
prop = property_entry_get(props, propname);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
array_len = property_entry_count_elems_of_size(props, propname,
|
||||
sizeof(const char *));
|
||||
if (array_len < 0)
|
||||
return array_len;
|
||||
|
||||
/* Return how many there are if strings is NULL. */
|
||||
if (!strings)
|
||||
return array_len;
|
||||
|
||||
array_len = min(nval, array_len);
|
||||
array_len = min_t(size_t, nval, array_len);
|
||||
length = array_len * sizeof(*strings);
|
||||
|
||||
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)
|
||||
{
|
||||
const void *pointer = property_get_pointer(p);
|
||||
const char * const *src_str;
|
||||
size_t i, nval;
|
||||
|
||||
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 *);
|
||||
for (i = 0; i < nval; i++)
|
||||
kfree(p->pointer.str[i]);
|
||||
kfree(src_str[i]);
|
||||
}
|
||||
kfree(pointer);
|
||||
} 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);
|
||||
}
|
||||
|
||||
static int property_copy_string_array(struct property_entry *dst,
|
||||
const struct property_entry *src)
|
||||
static const char * const *
|
||||
property_copy_string_array(const struct property_entry *src)
|
||||
{
|
||||
const char **d;
|
||||
const char * const *src_str = src->pointer;
|
||||
size_t nval = src->length / sizeof(*d);
|
||||
int i;
|
||||
|
||||
d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < nval; i++) {
|
||||
d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
|
||||
if (!d[i] && src->pointer.str[i]) {
|
||||
d[i] = kstrdup(src_str[i], GFP_KERNEL);
|
||||
if (!d[i] && src_str[i]) {
|
||||
while (--i >= 0)
|
||||
kfree(d[i]);
|
||||
kfree(d);
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dst->pointer.str = d;
|
||||
return 0;
|
||||
return d;
|
||||
}
|
||||
|
||||
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 *new;
|
||||
int error;
|
||||
|
||||
if (src->is_array) {
|
||||
if (!src->length)
|
||||
return -ENODATA;
|
||||
|
||||
if (src->type == DEV_PROP_STRING) {
|
||||
error = property_copy_string_array(dst, src);
|
||||
if (error)
|
||||
return error;
|
||||
new = dst->pointer.str;
|
||||
new = property_copy_string_array(src);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
new = kmemdup(pointer, src->length, GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dst->is_array = true;
|
||||
dst->pointer = new;
|
||||
} else if (src->type == DEV_PROP_STRING) {
|
||||
new = kstrdup(src->value.str, GFP_KERNEL);
|
||||
if (!new && src->value.str)
|
||||
return -ENOMEM;
|
||||
|
||||
dst->value.str = new;
|
||||
} else {
|
||||
new = pointer;
|
||||
dst->value = src->value;
|
||||
}
|
||||
|
||||
dst->length = src->length;
|
||||
dst->is_array = src->is_array;
|
||||
dst->type = src->type;
|
||||
|
||||
property_set_pointer(dst, new);
|
||||
|
||||
dst->name = kstrdup(src->name, GFP_KERNEL);
|
||||
if (!dst->name)
|
||||
goto out_free_data;
|
||||
@ -515,12 +396,47 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode,
|
||||
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 *
|
||||
software_node_get_parent(const struct fwnode_handle *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 *
|
||||
@ -612,6 +528,8 @@ static const struct fwnode_operations software_node_ops = {
|
||||
.property_present = software_node_property_present,
|
||||
.property_read_int_array = software_node_read_int_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_next_child_node = software_node_get_next_child,
|
||||
.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++) {
|
||||
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;
|
||||
|
||||
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),
|
||||
key_len - sizeof(key_len));
|
||||
|
||||
entry[i].name = key;
|
||||
entry[i].length = val_len - sizeof(val_len);
|
||||
entry[i].is_array = !!entry[i].length;
|
||||
entry[i].type = DEV_PROP_U8;
|
||||
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
|
||||
|
||||
entry_data = ptr + key_len + sizeof(val_len);
|
||||
entry_len = val_len - sizeof(val_len);
|
||||
entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
|
||||
entry_len);
|
||||
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,
|
||||
16, 1, entry[i].pointer.u8_data,
|
||||
entry[i].length, true);
|
||||
16, 1, entry_data, entry_len, true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 *
|
||||
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_read_int_array = of_fwnode_property_read_int_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_next_child_node = of_fwnode_get_next_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
|
||||
* @get: Get 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.
|
||||
* @property_present: Return true if a property is present.
|
||||
* @property_read_integer_array: Read an array of integer properties. Return
|
||||
* zero on success, a negative error code
|
||||
* otherwise.
|
||||
* @property_read_int_array: Read an array of integer properties. Return zero on
|
||||
* success, a negative error code otherwise.
|
||||
* @property_read_string_array: Read an array of string properties. Return zero
|
||||
* 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_next_child_node: Return the next child node in an iteration.
|
||||
* @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,
|
||||
const char *propname, const char **val,
|
||||
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_next_child_node)(const struct fwnode_handle *fwnode,
|
||||
|
@ -22,7 +22,6 @@ enum dev_prop_type {
|
||||
DEV_PROP_U32,
|
||||
DEV_PROP_U64,
|
||||
DEV_PROP_STRING,
|
||||
DEV_PROP_MAX,
|
||||
};
|
||||
|
||||
enum dev_dma_attr {
|
||||
@ -80,9 +79,14 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
|
||||
const char *name,
|
||||
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_next_parent(
|
||||
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(
|
||||
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
|
||||
struct fwnode_handle *fwnode_get_next_available_child_node(
|
||||
@ -234,13 +238,7 @@ struct property_entry {
|
||||
bool is_array;
|
||||
enum dev_prop_type type;
|
||||
union {
|
||||
union {
|
||||
const u8 *u8_data;
|
||||
const u16 *u16_data;
|
||||
const u32 *u32_data;
|
||||
const u64 *u64_data;
|
||||
const char * const *str;
|
||||
} pointer;
|
||||
const void *pointer;
|
||||
union {
|
||||
u8 u8_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
|
||||
* 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) { \
|
||||
.name = _name_, \
|
||||
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \
|
||||
.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
|
||||
.is_array = true, \
|
||||
.type = DEV_PROP_##_Type_, \
|
||||
{ .pointer = { ._type_##_data = _val_ } }, \
|
||||
{ .pointer = _val_ }, \
|
||||
}
|
||||
|
||||
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
|
||||
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
|
||||
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
|
||||
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
|
||||
#define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_) \
|
||||
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8_data, U8, _val_, _len_)
|
||||
#define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_) \
|
||||
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16_data, U16, _val_, _len_)
|
||||
#define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_) \
|
||||
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32_data, U32, _val_, _len_)
|
||||
#define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_) \
|
||||
__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_) \
|
||||
(struct property_entry) { \
|
||||
.name = _name_, \
|
||||
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \
|
||||
.is_array = true, \
|
||||
.type = DEV_PROP_STRING, \
|
||||
{ .pointer = { .str = _val_ } }, \
|
||||
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
|
||||
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
|
||||
PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_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_) \
|
||||
(struct property_entry) { \
|
||||
.name = _name_, \
|
||||
.length = sizeof(_type_), \
|
||||
.type = DEV_PROP_##_Type_, \
|
||||
{ .value = { ._type_##_data = _val_ } }, \
|
||||
}
|
||||
|
||||
#define PROPERTY_ENTRY_U8(_name_, _val_) \
|
||||
PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _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_U8(_name_, _val_) \
|
||||
__PROPERTY_ENTRY_ELEMENT(_name_, u8_data, U8, _val_)
|
||||
#define PROPERTY_ENTRY_U16(_name_, _val_) \
|
||||
__PROPERTY_ENTRY_ELEMENT(_name_, u16_data, U16, _val_)
|
||||
#define PROPERTY_ENTRY_U32(_name_, _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_STRING(_name_, _val_) \
|
||||
__PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_)
|
||||
|
||||
#define PROPERTY_ENTRY_BOOL(_name_) \
|
||||
(struct property_entry) { \
|
||||
@ -418,7 +417,8 @@ struct software_node {
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
const struct software_node *
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "../tools/testing/selftests/kselftest_module.h"
|
||||
|
||||
#define BUF_SIZE 256
|
||||
@ -593,6 +595,35 @@ flags(void)
|
||||
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
|
||||
errptr(void)
|
||||
{
|
||||
@ -636,6 +667,7 @@ test_pointer(void)
|
||||
netdev_features();
|
||||
flags();
|
||||
errptr();
|
||||
fwnode_pointer();
|
||||
}
|
||||
|
||||
static void __init selftest(void)
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <net/addrconf.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/property.h>
|
||||
#ifdef CONFIG_BLOCK
|
||||
#include <linux/blkdev.h>
|
||||
#endif
|
||||
@ -938,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr,
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
if (*fmt == 'B')
|
||||
sprint_backtrace(sym, value);
|
||||
else if (*fmt != 'f' && *fmt != 's')
|
||||
else if (*fmt != 's')
|
||||
sprint_symbol(sym, value);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
const struct device_node *parent = np->parent;
|
||||
|
||||
/* special case for root node */
|
||||
if (!parent)
|
||||
return string_nocheck(buf, end, "/", default_str_spec);
|
||||
/* Loop starting from the root node to the current node. */
|
||||
for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) {
|
||||
struct fwnode_handle *__fwnode =
|
||||
fwnode_get_nth_parent(fwnode, depth);
|
||||
|
||||
for (depth = 0; parent->parent; depth++)
|
||||
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),
|
||||
buf = string(buf, end, fwnode_get_name_prefix(__fwnode),
|
||||
default_str_spec);
|
||||
buf = string(buf, end, fwnode_get_name(__fwnode),
|
||||
default_str_spec);
|
||||
|
||||
fwnode_handle_put(__fwnode);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -1941,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
||||
struct printf_spec str_spec = spec;
|
||||
str_spec.field_width = -1;
|
||||
|
||||
if (fmt[0] != 'F')
|
||||
return error_string(buf, end, "(%pO?)", spec);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF))
|
||||
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) {
|
||||
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;
|
||||
case 'n': /* name */
|
||||
p = kbasename(of_node_full_name(dn));
|
||||
p = fwnode_get_name(of_fwnode_handle(dn));
|
||||
precision = str_spec.precision;
|
||||
str_spec.precision = strchrnul(p, '@') - p;
|
||||
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);
|
||||
break;
|
||||
case 'P': /* path-spec */
|
||||
p = kbasename(of_node_full_name(dn));
|
||||
p = fwnode_get_name(of_fwnode_handle(dn));
|
||||
if (!p[1])
|
||||
p = "/";
|
||||
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);
|
||||
}
|
||||
|
||||
static char *kobject_string(char *buf, char *end, void *ptr,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
static noinline_for_stack
|
||||
char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
switch (fmt[1]) {
|
||||
case 'F':
|
||||
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
||||
struct printf_spec str_spec = spec;
|
||||
char *buf_start = buf;
|
||||
|
||||
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) without offset
|
||||
* - 'F' Same as 'S'
|
||||
* - 'f' Same as 's'
|
||||
* - '[FfSs]R' as above with __builtin_extract_return_addr() translation
|
||||
* - '[Ss]R' as above with __builtin_extract_return_addr() translation
|
||||
* - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
|
||||
* %ps and %pS. Be careful when re-using these specifiers.
|
||||
* - 'B' For backtraced symbolic direct pointers with offset
|
||||
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
|
||||
* - '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
|
||||
* c major 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".
|
||||
*
|
||||
* ** 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)
|
||||
{
|
||||
switch (*fmt) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
case 'S':
|
||||
case 's':
|
||||
ptr = dereference_symbol_descriptor(ptr);
|
||||
@ -2204,7 +2223,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
case 'G':
|
||||
return flags_string(buf, end, ptr, spec, fmt);
|
||||
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':
|
||||
return pointer_string(buf, end, ptr, spec);
|
||||
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 */
|
||||
case 'S':
|
||||
case 's':
|
||||
case 'F':
|
||||
case 'f':
|
||||
case 'x':
|
||||
case 'K':
|
||||
case 'e':
|
||||
|
@ -6015,14 +6015,18 @@ sub process {
|
||||
for (my $count = $linenr; $count <= $lc; $count++) {
|
||||
my $specifier;
|
||||
my $extension;
|
||||
my $qualifier;
|
||||
my $bad_specifier = "";
|
||||
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
|
||||
$fmt =~ s/%%//g;
|
||||
|
||||
while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
|
||||
while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
|
||||
$specifier = $1;
|
||||
$extension = $2;
|
||||
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxt]/) {
|
||||
$qualifier = $3;
|
||||
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
|
||||
($extension eq "f" &&
|
||||
defined $qualifier && $qualifier !~ /^w/)) {
|
||||
$bad_specifier = $specifier;
|
||||
last;
|
||||
}
|
||||
@ -6039,7 +6043,6 @@ sub process {
|
||||
my $ext_type = "Invalid";
|
||||
my $use = "";
|
||||
if ($bad_specifier =~ /p[Ff]/) {
|
||||
$ext_type = "Deprecated";
|
||||
$use = " - use %pS instead";
|
||||
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user