drivercore: Output common devicetree information in uevent
When userspace needs to find a specific device, it currently isn't easy to resolve a /sys/devices/ path from a specific device tree node. Nor is it easy to obtain the compatible list for devices. This patch generalizes the code that inserts OF_* values into the uevent device attribute so that any device that is attached to an OF node will have that information exported to userspace. Without this patch only platform devices and some powerpc-specific busses have access to this data. The original function also creates a MODALIAS property for the compatible list, but that code has not been generalized into the common case because it has the potential to break module loading on a lot of bus types. Bus types are still responsible for their own MODALIAS properties. Boot tested on ARM and compile tested on PowerPC and SPARC. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Tobias Klauser <tklauser@distanz.ch> Cc: Frederic Lambert <frdrc66@gmail.com> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Mark Brown <broonie@sirena.org.uk> Cc: "David S. Miller" <davem@davemloft.net> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
7aff0fe330
commit
07d57a32fb
6 changed files with 30 additions and 19 deletions
|
@ -713,7 +713,7 @@ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = {
|
||||||
|
|
||||||
struct bus_type ibmebus_bus_type = {
|
struct bus_type ibmebus_bus_type = {
|
||||||
.name = "ibmebus",
|
.name = "ibmebus",
|
||||||
.uevent = of_device_uevent,
|
.uevent = of_device_uevent_modalias,
|
||||||
.bus_attrs = ibmebus_bus_attrs,
|
.bus_attrs = ibmebus_bus_attrs,
|
||||||
.match = ibmebus_bus_bus_match,
|
.match = ibmebus_bus_bus_match,
|
||||||
.probe = ibmebus_bus_device_probe,
|
.probe = ibmebus_bus_device_probe,
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/genhd.h>
|
#include <linux/genhd.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
@ -267,6 +269,9 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
|
||||||
if (dev->driver)
|
if (dev->driver)
|
||||||
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
|
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
|
||||||
|
|
||||||
|
/* Add common DT information about the device */
|
||||||
|
of_device_uevent(dev, env);
|
||||||
|
|
||||||
/* have the bus specific function add its stuff */
|
/* have the bus specific function add its stuff */
|
||||||
if (dev->bus && dev->bus->uevent) {
|
if (dev->bus && dev->bus->uevent) {
|
||||||
retval = dev->bus->uevent(dev, env);
|
retval = dev->bus->uevent(dev, env);
|
||||||
|
|
|
@ -621,7 +621,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Some devices have extra OF data and an OF-style MODALIAS */
|
/* Some devices have extra OF data and an OF-style MODALIAS */
|
||||||
rc = of_device_uevent(dev,env);
|
rc = of_device_uevent_modalias(dev,env);
|
||||||
if (rc != -ENODEV)
|
if (rc != -ENODEV)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ extern struct device_attribute macio_dev_attrs[];
|
||||||
struct bus_type macio_bus_type = {
|
struct bus_type macio_bus_type = {
|
||||||
.name = "macio",
|
.name = "macio",
|
||||||
.match = macio_bus_match,
|
.match = macio_bus_match,
|
||||||
.uevent = of_device_uevent,
|
.uevent = of_device_uevent_modalias,
|
||||||
.probe = macio_device_probe,
|
.probe = macio_device_probe,
|
||||||
.remove = macio_device_remove,
|
.remove = macio_device_remove,
|
||||||
.shutdown = macio_device_shutdown,
|
.shutdown = macio_device_shutdown,
|
||||||
|
|
|
@ -128,39 +128,41 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
|
||||||
/**
|
/**
|
||||||
* of_device_uevent - Display OF related uevent information
|
* of_device_uevent - Display OF related uevent information
|
||||||
*/
|
*/
|
||||||
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
|
void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||||
{
|
{
|
||||||
const char *compat;
|
const char *compat;
|
||||||
int seen = 0, cplen, sl;
|
int seen = 0, cplen, sl;
|
||||||
|
|
||||||
if ((!dev) || (!dev->of_node))
|
if ((!dev) || (!dev->of_node))
|
||||||
return -ENODEV;
|
return;
|
||||||
|
|
||||||
if (add_uevent_var(env, "OF_NAME=%s", dev->of_node->name))
|
add_uevent_var(env, "OF_NAME=%s", dev->of_node->name);
|
||||||
return -ENOMEM;
|
add_uevent_var(env, "OF_FULLNAME=%s", dev->of_node->full_name);
|
||||||
|
if (dev->of_node->type && strcmp("<NULL>", dev->of_node->type) != 0)
|
||||||
if (add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type))
|
add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Since the compatible field can contain pretty much anything
|
/* Since the compatible field can contain pretty much anything
|
||||||
* it's not really legal to split it out with commas. We split it
|
* it's not really legal to split it out with commas. We split it
|
||||||
* up using a number of environment variables instead. */
|
* up using a number of environment variables instead. */
|
||||||
|
|
||||||
compat = of_get_property(dev->of_node, "compatible", &cplen);
|
compat = of_get_property(dev->of_node, "compatible", &cplen);
|
||||||
while (compat && *compat && cplen > 0) {
|
while (compat && *compat && cplen > 0) {
|
||||||
if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
|
add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
sl = strlen(compat) + 1;
|
sl = strlen(compat) + 1;
|
||||||
compat += sl;
|
compat += sl;
|
||||||
cplen -= sl;
|
cplen -= sl;
|
||||||
seen++;
|
seen++;
|
||||||
}
|
}
|
||||||
|
add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
|
||||||
|
}
|
||||||
|
|
||||||
if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
|
int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
|
||||||
return -ENOMEM;
|
{
|
||||||
|
int sl;
|
||||||
|
|
||||||
/* modalias is trickier, we add it in 2 steps */
|
if ((!dev) || (!dev->of_node))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Devicetree modalias is tricky, we add it in 2 steps */
|
||||||
if (add_uevent_var(env, "MODALIAS="))
|
if (add_uevent_var(env, "MODALIAS="))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ extern void of_device_unregister(struct platform_device *ofdev);
|
||||||
extern ssize_t of_device_get_modalias(struct device *dev,
|
extern ssize_t of_device_get_modalias(struct device *dev,
|
||||||
char *str, ssize_t len);
|
char *str, ssize_t len);
|
||||||
|
|
||||||
extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
|
extern void of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
|
||||||
|
extern int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env);
|
||||||
|
|
||||||
static inline void of_device_node_put(struct device *dev)
|
static inline void of_device_node_put(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +50,10 @@ static inline int of_driver_match_device(struct device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int of_device_uevent(struct device *dev,
|
static inline void of_device_uevent(struct device *dev,
|
||||||
|
struct kobj_uevent_env *env) { }
|
||||||
|
|
||||||
|
static inline int of_device_uevent_modalias(struct device *dev,
|
||||||
struct kobj_uevent_env *env)
|
struct kobj_uevent_env *env)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
Loading…
Reference in a new issue