Commit df0cca21 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

driver core: add support for calling /sbin/hotplug when classes are found and...

driver core: add support for calling /sbin/hotplug when classes are found and removed from the system.
parent be75e771
...@@ -54,10 +54,15 @@ extern void interface_remove(struct device_class *, struct device *); ...@@ -54,10 +54,15 @@ extern void interface_remove(struct device_class *, struct device *);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
extern int dev_hotplug(struct device *dev, const char *action); extern int dev_hotplug(struct device *dev, const char *action);
extern int class_hotplug(struct device *dev, const char *action);
#else #else
static inline int dev_hotplug(struct device *dev, const char *action) static inline int dev_hotplug(struct device *dev, const char *action)
{ {
return 0; return 0;
} }
static int class_hotplug(struct device *dev, const char *action)
{
return 0;
}
#endif #endif
...@@ -84,7 +84,8 @@ int devclass_add_device(struct device * dev) ...@@ -84,7 +84,8 @@ int devclass_add_device(struct device * dev)
interface_add(cls,dev); interface_add(cls,dev);
} }
/* notify userspace (call /sbin/hotplug) here */ /* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "add");
up_write(&cls->rwsem); up_write(&cls->rwsem);
if (error) if (error)
...@@ -106,6 +107,10 @@ void devclass_remove_device(struct device * dev) ...@@ -106,6 +107,10 @@ void devclass_remove_device(struct device * dev)
cls->name,dev->name); cls->name,dev->name);
interface_remove(cls,dev); interface_remove(cls,dev);
unenum_device(cls,dev); unenum_device(cls,dev);
/* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "remove");
if (cls->remove_device) if (cls->remove_device)
cls->remove_device(dev); cls->remove_device(dev);
up_write(&cls->rwsem); up_write(&cls->rwsem);
......
...@@ -22,15 +22,21 @@ ...@@ -22,15 +22,21 @@
/* /*
* hotplugging invokes what /proc/sys/kernel/hotplug says (normally * hotplugging invokes what /proc/sys/kernel/hotplug says (normally
* /sbin/hotplug) when devices get added or removed. * /sbin/hotplug) when devices or classes get added or removed.
* *
* This invokes a user mode policy agent, typically helping to load driver * This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide * or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks. * a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* See the documentation at http://linux-hotplug.sf.net for more info.
*
*/ */
#define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */ #define NUM_ENVP 32 /* number of env pointers */
int dev_hotplug (struct device *dev, const char *action)
static int do_hotplug (struct device *dev, char *argv1, const char *action,
int (* hotplug) (struct device *, char **, int, char *, int))
{ {
char *argv [3], **envp, *buffer, *scratch; char *argv [3], **envp, *buffer, *scratch;
char *dev_path; char *dev_path;
...@@ -39,11 +45,6 @@ int dev_hotplug (struct device *dev, const char *action) ...@@ -39,11 +45,6 @@ int dev_hotplug (struct device *dev, const char *action)
int dev_length; int dev_length;
pr_debug ("%s\n", __FUNCTION__); pr_debug ("%s\n", __FUNCTION__);
if (!dev)
return -ENODEV;
if (!dev->bus)
return -ENODEV;
if (!hotplug_path [0]) if (!hotplug_path [0])
return -ENODEV; return -ENODEV;
...@@ -82,9 +83,8 @@ int dev_hotplug (struct device *dev, const char *action) ...@@ -82,9 +83,8 @@ int dev_hotplug (struct device *dev, const char *action)
strcpy (dev_path, "root"); strcpy (dev_path, "root");
fill_devpath (dev, dev_path, dev_length); fill_devpath (dev, dev_path, dev_length);
/* only one standardized param to hotplug command: the bus name */
argv [0] = hotplug_path; argv [0] = hotplug_path;
argv [1] = dev->bus->name; argv [1] = argv1;
argv [2] = 0; argv [2] = 0;
/* minimal command environment */ /* minimal command environment */
...@@ -99,11 +99,10 @@ int dev_hotplug (struct device *dev, const char *action) ...@@ -99,11 +99,10 @@ int dev_hotplug (struct device *dev, const char *action)
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "DEVPATH=%s", dev_path) + 1; scratch += sprintf (scratch, "DEVPATH=%s", dev_path) + 1;
if (dev->bus->hotplug) { if (hotplug) {
/* have the bus specific function add its stuff */ /* have the bus specific function add its stuff */
retval = dev->bus->hotplug (dev, &envp[i], NUM_ENVP - i, retval = hotplug (dev, &envp[i], NUM_ENVP - i, scratch,
scratch, BUFFER_SIZE - (scratch - buffer));
BUFFER_SIZE - (scratch - buffer));
if (retval) { if (retval) {
pr_debug ("%s - hotplug() returned %d\n", pr_debug ("%s - hotplug() returned %d\n",
__FUNCTION__, retval); __FUNCTION__, retval);
...@@ -124,3 +123,42 @@ int dev_hotplug (struct device *dev, const char *action) ...@@ -124,3 +123,42 @@ int dev_hotplug (struct device *dev, const char *action)
kfree (envp); kfree (envp);
return retval; return retval;
} }
/*
* dev_hotplug - called when any device is added or removed from a bus
*/
int dev_hotplug (struct device *dev, const char *action)
{
pr_debug ("%s\n", __FUNCTION__);
if (!dev)
return -ENODEV;
if (!dev->bus)
return -ENODEV;
return do_hotplug (dev, dev->bus->name, action, dev->bus->hotplug);
}
/*
* class_hotplug - called when a class is added or removed from a device
*/
int class_hotplug (struct device *dev, const char *action)
{
struct device_class * cls;
pr_debug ("%s\n", __FUNCTION__);
if (!dev)
return -ENODEV;
if (!dev->bus)
return -ENODEV;
cls = get_devclass(dev->driver->devclass);
if (!cls)
return -ENODEV;
return do_hotplug (dev, cls->name, action, cls->hotplug);
}
...@@ -187,6 +187,8 @@ struct device_class { ...@@ -187,6 +187,8 @@ struct device_class {
int (*add_device)(struct device *); int (*add_device)(struct device *);
void (*remove_device)(struct device *); void (*remove_device)(struct device *);
int (*hotplug)(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
}; };
extern int devclass_register(struct device_class *); extern int devclass_register(struct device_class *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment