From 6fcf53acccf85b4b0d0260e66c692a341760f464 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 30 Apr 2009 15:23:42 +0200 Subject: 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 Signed-off-by: Jan Blunck Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/device.h | 3 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 4d59975c24a..7ecb1938e59 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) @@ -1128,6 +1136,47 @@ static struct device *next_device(struct klist_iter *i) return dev; } +/** + * 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. diff --git a/include/linux/device.h b/include/linux/device.h index 4410464b134..ed4e39f2c42 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -194,6 +194,7 @@ struct class { struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); + char *(*nodename)(struct device *dev); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev); @@ -289,6 +290,7 @@ struct device_type { const char *name; struct attribute_group **groups; int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + char *(*nodename)(struct device *dev); void (*release)(struct device *dev); struct dev_pm_ops *pm; @@ -488,6 +490,7 @@ extern struct device *device_find_child(struct device *dev, void *data, extern int device_rename(struct device *dev, char *new_name); extern int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order); +extern const char *device_get_nodename(struct device *dev, const char **tmp); /* * Root device objects for grouping under /sys/devices -- cgit v1.2.3-70-g09d2