diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2009-04-30 15:23:42 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-15 21:30:25 -0700 |
commit | 6fcf53acccf85b4b0d0260e66c692a341760f464 (patch) | |
tree | 445f725558bde27492095f8d05cc645315f8c1c1 /drivers/base | |
parent | acc0e90fbccbc6e4d48184cba0983ea044e131af (diff) |
Driver Core: add nodename callbacks
This adds the nodename callback for struct class, struct device_type and
struct device, to allow drivers to send userspace hints on the device
name and subdirectory that should be used for it.
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/core.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 4d59975c24a8..7ecb1938e590 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -162,10 +162,18 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, struct device *dev = to_dev(kobj); int retval = 0; - /* add the major/minor if present */ + /* add device node properties if present */ if (MAJOR(dev->devt)) { + const char *tmp; + const char *name; + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); + name = device_get_nodename(dev, &tmp); + if (name) { + add_uevent_var(env, "DEVNAME=%s", name); + kfree(tmp); + } } if (dev->type && dev->type->name) @@ -1129,6 +1137,47 @@ static struct device *next_device(struct klist_iter *i) } /** + * device_get_nodename - path of device node file + * @dev: device + * @tmp: possibly allocated string + * + * Return the relative path of a possible device node. + * Non-default names may need to allocate a memory to compose + * a name. This memory is returned in tmp and needs to be + * freed by the caller. + */ +const char *device_get_nodename(struct device *dev, const char **tmp) +{ + char *s; + + *tmp = NULL; + + /* the device type may provide a specific name */ + if (dev->type && dev->type->nodename) + *tmp = dev->type->nodename(dev); + if (*tmp) + return *tmp; + + /* the class may provide a specific name */ + if (dev->class && dev->class->nodename) + *tmp = dev->class->nodename(dev); + if (*tmp) + return *tmp; + + /* return name without allocation, tmp == NULL */ + if (strchr(dev_name(dev), '!') == NULL) + return dev_name(dev); + + /* replace '!' in the name with '/' */ + *tmp = kstrdup(dev_name(dev), GFP_KERNEL); + if (!*tmp) + return NULL; + while ((s = strchr(*tmp, '!'))) + s[0] = '/'; + return *tmp; +} + +/** * device_for_each_child - device child iterator. * @parent: parent struct device. * @data: data for the callback. |