/*
* property.c - Unified device property interface.
*
* Copyright (C) 2014, Intel Corporation
* Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/property.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
static inline bool is_pset_node(struct fwnode_handle *fwnode)
{
return fwnode && fwnode->type == FWNODE_PDATA;
}
static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode)
{
return is_pset_node(fwnode) ?
container_of(fwnode, struct property_set, fwnode) : NULL;
}
static struct property_entry *pset_prop_get(struct property_set *pset,
const char *name)
{
struct property_entry *prop;
if (!pset || !pset->properties)
return NULL;
for (prop = pset->properties; prop->name; prop++)
if (!strcmp(name, prop->name))
return prop;
return NULL;
}
static void *pset_prop_find(struct property_set *pset, const char *propname,
size_t length)
{
struct property_entry *prop;
void *pointer;
prop = pset_prop_get(pset, propname);
if (!prop)
return ERR_PTR(-EINVAL);
if (prop->is_array)
pointer = prop->pointer.raw_data;
else
pointer = &prop->value.raw_data;
if (!pointer)
return ERR_PTR(-ENODATA);
if (length > prop->length)
return ERR_PTR(-EOVERFLOW);
return pointer;
}
static int pset_prop_read_u8_array(struct property_set *pset,
const char *propname,
u8 *values, size_t nval)
{
void *pointer;
size_t length = nval * sizeof(*values);
pointer = pset_prop_find(pset, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(values, pointer, length);
return 0;
}
static int pset_prop_read_u16_array(struct property_set *pset,
const char *propname,
u16 *values, size_t nval)
{
void *pointer;
size_t length = nval * sizeof(*values);
pointer = pset_prop_find(pset, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(values, pointer, length);
return 0;
}
static int pset_prop_read_u32_array(struct property_set *pset,
const char *propname,
u32 *values, size_t nval)
{
void *pointer;
size_t length = nval * sizeof(*values);
pointer = pset_prop_find(pset, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(values, pointer, length);
return 0;
}
static int pset_prop_read_u64_array(struct property_set *pset,
const char *propname,
u64 *values, size_t nval)
{
void *pointer;
size_t length = nval * sizeof(*values);
pointer = pset_prop_find(pset, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(values, pointer, length);
return 0;
}
static int pset_prop_count_elems_of_size(struct property_set *pset,
const char *propname, size_t length)
{
struct property_entry *prop;
prop = pset_prop_get(pset, propname);
if (!prop)
return -EINVAL;
return prop->length / length;
}
static int pset_prop_read_string_array(struct property_set *pset,
const char *propname,
const char **strings, size_t nval)
{
void *pointer;
size_t length = nval * sizeof(*strings);
pointer = pset_prop_find(pset, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(strings, pointer, length);
return 0;
}
static int pset_prop_read_string(struct property_set *pset,
const char *propname, const char **strings)
{
struct property_entry *prop;
const char **pointer;
prop = pset_prop_get(pset, propname);
if (!prop)
return -EINVAL;
if (!prop->is_string)
return -EILSEQ;
if (prop->is_array) {
pointer = prop->pointer.str;
if (!pointer)
return -ENODATA;
} else {
pointer = &prop->value.str;
if (*pointer && strnlen(*pointer, prop->length) >= prop->length)
return -EILSEQ;
}
*strings = *