summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-06-28 16:19:58 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-25 21:08:38 -0700
commit2620efef7029bb040430f50f0fc148f2d5e002ad (patch)
tree433b19e18c40f6972ac0c936b844c997644dc176 /drivers
parent64bb5d2c116478dba7501d2acf078ed74ba30c1f (diff)
Driver core: add ability for classes to handle devices properly
This adds two new callbacks to the class structure: int (*dev_uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); void (*dev_release)(struct device *dev); And one pointer: struct device_attribute * dev_attrs; which all corrispond with the same thing as the "normal" class devices do, yet this is for when a struct device is bound to a class. Someday soon, struct class_device will go away, and then the other fields in this structure can be removed too. But this is necessary in order to get the transition to work properly. Tested out on a network core patch that converted it to use struct device instead of struct class_device. Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/core.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5c91d0d81e78..f1228f25efe0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -94,6 +94,8 @@ static void device_release(struct kobject * kobj)
if (dev->release)
dev->release(dev);
+ else if (dev->class && dev->class->dev_release)
+ dev->class->dev_release(dev);
else {
printk(KERN_ERR "Device '%s' does not have a release() function, "
"it is broken and must be fixed.\n",
@@ -183,6 +185,15 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
}
}
+ if (dev->class && dev->class->dev_uevent) {
+ /* have the class specific function add its stuff */
+ retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+ if (retval) {
+ pr_debug("%s - dev_uevent() returned %d\n",
+ __FUNCTION__, retval);
+ }
+ }
+
return retval;
}
@@ -228,6 +239,43 @@ static void device_remove_groups(struct device *dev)
}
}
+static int device_add_attrs(struct device *dev)
+{
+ struct class *class = dev->class;
+ int error = 0;
+ int i;
+
+ if (!class)
+ return 0;
+
+ if (class->dev_attrs) {
+ for (i = 0; attr_name(class->dev_attrs[i]); i++) {
+ error = device_create_file(dev, &class->dev_attrs[i]);
+ if (error)
+ break;
+ }
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &class->dev_attrs[i]);
+ return error;
+}
+
+static void device_remove_attrs(struct device *dev)
+{
+ struct class *class = dev->class;
+ int i;
+
+ if (!class)
+ return;
+
+ if (class->dev_attrs) {
+ for (i = 0; attr_name(class->dev_attrs[i]); i++)
+ device_remove_file(dev, &class->dev_attrs[i]);
+ }
+}
+
+
static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -382,6 +430,8 @@ int device_add(struct device *dev)
}
}
+ if ((error = device_add_attrs(dev)))
+ goto AttrsError;
if ((error = device_add_groups(dev)))
goto GroupError;
if ((error = device_pm_add(dev)))
@@ -412,6 +462,8 @@ int device_add(struct device *dev)
PMError:
device_remove_groups(dev);
GroupError:
+ device_remove_attrs(dev);
+ AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
@@ -509,6 +561,7 @@ void device_del(struct device * dev)
}
device_remove_file(dev, &dev->uevent_attr);
device_remove_groups(dev);
+ device_remove_attrs(dev);
/* Notify the platform of the removal, in case they
* need to do anything...