Commit cfe15b8a authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/driver-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 2ed3d4f0 b168474c
......@@ -1247,6 +1247,12 @@ W: http://nfs.sourceforge.net/
W: http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
S: Maintained
KERNEL EVENT LAYER (KOBJECT_UEVENT)
P: Robert Love
M: rml@novell.com
L: linux-kernel@vger.kernel.org
S: Maintained
LANMEDIA WAN CARD DRIVER
P: Andrew Stanley-Jones
M: asj@lanmedia.com
......
......@@ -135,6 +135,52 @@ static struct kobj_type ktype_bus = {
decl_subsys(bus, &ktype_bus, NULL);
static int __bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct list_head *head;
struct device *dev;
int error = 0;
if (!(bus = get_bus(bus)))
return -EINVAL;
head = &bus->devices.list;
dev = list_prepare_entry(start, head, bus_list);
list_for_each_entry_continue(dev, head, bus_list) {
get_device(dev);
error = fn(dev, data);
put_device(dev);
if (error)
break;
}
put_bus(bus);
return error;
}
static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void * data, int (*fn)(struct device_driver *, void *))
{
struct list_head *head;
struct device_driver *drv;
int error = 0;
if (!(bus = get_bus(bus)))
return -EINVAL;
head = &bus->drivers.list;
drv = list_prepare_entry(start, head, kobj.entry);
list_for_each_entry_continue(drv, head, kobj.entry) {
get_driver(drv);
error = fn(drv, data);
put_driver(drv);
if (error)
break;
}
put_bus(bus);
return error;
}
/**
* bus_for_each_dev - device iterator.
* @bus: bus type.
......@@ -154,30 +200,16 @@ decl_subsys(bus, &ktype_bus, NULL);
* to retain this data, it should do, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type * bus, struct device * start,
void * data, int (*fn)(struct device *, void *))
{
struct device *dev;
struct list_head * head;
int error = 0;
if (!(bus = get_bus(bus)))
return -EINVAL;
head = &bus->devices.list;
dev = list_prepare_entry(start, head, bus_list);
int ret;
down_read(&bus->subsys.rwsem);
list_for_each_entry_continue(dev, head, bus_list) {
get_device(dev);
error = fn(dev, data);
put_device(dev);
if (error)
break;
}
ret = __bus_for_each_dev(bus, start, data, fn);
up_read(&bus->subsys.rwsem);
put_bus(bus);
return error;
return ret;
}
/**
......@@ -203,27 +235,12 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *))
{
struct list_head * head;
struct device_driver *drv;
int error = 0;
if(!(bus = get_bus(bus)))
return -EINVAL;
head = &bus->drivers.list;
drv = list_prepare_entry(start, head, kobj.entry);
int ret;
down_read(&bus->subsys.rwsem);
list_for_each_entry_continue(drv, head, kobj.entry) {
get_driver(drv);
error = fn(drv, data);
put_driver(drv);
if(error)
break;
}
ret = __bus_for_each_drv(bus, start, data, fn);
up_read(&bus->subsys.rwsem);
put_bus(bus);
return error;
return ret;
}
/**
......@@ -325,10 +342,10 @@ int device_attach(struct device * dev)
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to match
* the driver with each one.
* If bus_match() returns 0 and the @dev->driver is set, we've found
* a compatible pair.
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*
* Note that we ignore the -ENODEV error from driver_probe_device(),
* since it's perfectly valid for a driver not to bind to any devices.
......@@ -590,7 +607,9 @@ int bus_rescan_devices(struct bus_type * bus)
{
int count = 0;
bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
down_write(&bus->subsys.rwsem);
__bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
up_write(&bus->subsys.rwsem);
return count;
}
......
......@@ -283,8 +283,34 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
{
struct class_device *class_dev = to_class_dev(kobj);
int retval = 0;
int i = 0;
int length = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (class_dev->dev) {
/* add physical device, backing this device */
struct device *dev = class_dev->dev;
char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path);
kfree(path);
/* add bus name of physical device */
if (dev->bus)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;
}
if (class_dev->class->hotplug) {
/* have the bus specific function add its stuff */
retval = class_dev->class->hotplug (class_dev, envp, num_envp,
......
......@@ -209,12 +209,12 @@ void device_initialize(struct device *dev)
*/
int device_add(struct device *dev)
{
struct device * parent;
int error;
struct device *parent = NULL;
int error = -EINVAL;
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id))
return -EINVAL;
goto Error;
parent = get_device(dev->parent);
......
......@@ -438,8 +438,46 @@ static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)
return ((ktype == &ktype_block) || (ktype == &ktype_part));
}
static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct device *dev = NULL;
struct kobj_type *ktype = get_ktype(kobj);
int length = 0;
int i = 0;
/* get physical device backing disk or partition */
if (ktype == &ktype_block) {
struct gendisk *disk = container_of(kobj, struct gendisk, kobj);
dev = disk->driverfs_dev;
} else if (ktype == &ktype_part) {
struct gendisk *disk = container_of(kobj->parent, struct gendisk, kobj);
dev = disk->driverfs_dev;
}
if (dev) {
/* add physical device, backing this device */
char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path);
kfree(path);
/* add bus name of physical device */
if (dev->bus)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
envp[i] = NULL;
}
return 0;
}
static struct kset_hotplug_ops block_hotplug_ops = {
.filter = block_hotplug_filter,
.filter = block_hotplug_filter,
.hotplug = block_hotplug,
};
/* declare block_subsys. */
......
......@@ -56,7 +56,7 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
sd = sysfs_new_dirent(parent_sd, element);
if (!sd)
return -ENOMEM;
return 0;
sd->s_mode = mode;
sd->s_type = type;
......@@ -201,7 +201,7 @@ static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry)
return err;
}
struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
......@@ -277,7 +277,7 @@ void sysfs_remove_dir(struct kobject * kobj)
pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
down(&dentry->d_inode->i_sem);
list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
if (!sd->s_element)
if (!sd->s_element || !(sd->s_type & SYSFS_NOT_PINNED))
continue;
list_del_init(&sd->s_sibling);
sysfs_drop_dentry(sd, dentry);
......
......@@ -330,11 +330,13 @@ static int sysfs_release(struct inode * inode, struct file * filp)
{
struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
struct attribute * attr = to_attr(filp->f_dentry);
struct module * owner = attr->owner;
struct sysfs_buffer * buffer = filp->private_data;
if (kobj)
kobject_put(kobj);
module_put(attr->owner);
/* After this point, attr should not be accessed. */
module_put(owner);
if (buffer) {
if (buffer->page)
......
......@@ -76,11 +76,6 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
return error;
}
int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
return sysfs_create(dentry, mode, NULL);
}
struct dentry * sysfs_get_dentry(struct dentry * parent, const char * name)
{
struct qstr qstr;
......
......@@ -22,7 +22,7 @@ static struct super_operations sysfs_ops = {
.drop_inode = generic_delete_inode,
};
struct sysfs_dirent sysfs_root = {
static struct sysfs_dirent sysfs_root = {
.s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling),
.s_children = LIST_HEAD_INIT(sysfs_root.s_children),
.s_element = NULL,
......
......@@ -9,12 +9,6 @@
#include "sysfs.h"
struct inode_operations sysfs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = sysfs_follow_link,
.put_link = sysfs_put_link,
};
static int object_depth(struct kobject * kobj)
{
struct kobject * p = kobj;
......@@ -157,7 +151,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path)
}
int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int error = -ENOMEM;
unsigned long page = get_zeroed_page(GFP_KERNEL);
......@@ -167,13 +161,20 @@ int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
return 0;
}
void sysfs_put_link(struct dentry *dentry, struct nameidata *nd)
static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd)
{
char *page = nd_get_link(nd);
if (!IS_ERR(page))
free_page((unsigned long)page);
}
struct inode_operations sysfs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = sysfs_follow_link,
.put_link = sysfs_put_link,
};
EXPORT_SYMBOL_GPL(sysfs_create_link);
EXPORT_SYMBOL_GPL(sysfs_remove_link);
......@@ -17,8 +17,6 @@ extern void sysfs_remove_subdir(struct dentry *);
extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);
extern int sysfs_follow_link(struct dentry *, struct nameidata *);
extern void sysfs_put_link(struct dentry *, struct nameidata *);
extern struct rw_semaphore sysfs_rename_sem;
extern struct super_block * sysfs_sb;
extern struct file_operations sysfs_dir_operations;
......
......@@ -183,6 +183,7 @@ int kobject_add(struct kobject * kobj)
unlink(kobj);
if (parent)
kobject_put(parent);
kobject_put(kobj);
} else {
kobject_hotplug(kobj, KOBJ_ADD);
}
......
......@@ -120,9 +120,8 @@ static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action,
sprintf(attrpath, "%s/%s", path, attr->name);
rc = send_uevent(signal, attrpath, NULL, gfp_mask);
kfree(attrpath);
} else {
} else
rc = send_uevent(signal, path, NULL, gfp_mask);
}
exit:
kfree(path);
......@@ -148,7 +147,6 @@ int kobject_uevent_atomic(struct kobject *kobj, enum kobject_action action,
{
return do_kobject_uevent(kobj, action, attr, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
static int __init kobject_uevent_init(void)
......@@ -164,11 +162,11 @@ static int __init kobject_uevent_init(void)
return 0;
}
core_initcall(kobject_uevent_init);
postcore_initcall(kobject_uevent_init);
#else
static inline int send_uevent(const char *signal, const char *obj,
const void *buf, int buflen, int gfp_mask)
char **envp, int gfp_mask)
{
return 0;
}
......
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