Commit d868772f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (46 commits)
  dev_dbg: check dev_dbg() arguments
  drivers/base/attribute_container.c: use mutex instead of binary semaphore
  mod_sysfs_setup() doesn't return errno when kobject_add_dir() failure occurs
  s2ram: add arch irq disable/enable hooks
  define platform wakeup hook, use in pci_enable_wake()
  security: prevent permission checking of file removal via sysfs_remove_group()
  device_schedule_callback() needs a module reference
  s390: cio: Delay uevents for subchannels
  sysfs: bin.c printk fix
  Driver core: use mutex instead of semaphore in DMA pool handler
  driver core: bus_add_driver should return an error if no bus
  debugfs: Add debugfs_create_u64()
  the overdue removal of the mount/umount uevents
  kobject: Comment and warning fixes to kobject.c
  Driver core: warn when userspace writes to the uevent file in a non-supported way
  Driver core: make uevent-environment available in uevent-file
  kobject core: remove rwsem from struct subsystem
  qeth: Remove usage of subsys.rwsem
  PHY: remove rwsem use from phy core
  IEEE1394: remove rwsem use from ieee1394 core
  ...
parents a205752d 404d5b18
...@@ -134,15 +134,6 @@ Who: Arjan van de Ven <arjan@linux.intel.com> ...@@ -134,15 +134,6 @@ Who: Arjan van de Ven <arjan@linux.intel.com>
--------------------------- ---------------------------
What: mount/umount uevents
When: February 2007
Why: These events are not correct, and do not properly let userspace know
when a file system has been mounted or unmounted. Userspace should
poll the /proc/mounts file instead to detect this properly.
Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
What: USB driver API moves to EXPORT_SYMBOL_GPL What: USB driver API moves to EXPORT_SYMBOL_GPL
When: February 2008 When: February 2008
Files: include/linux/usb.h, drivers/usb/core/driver.c Files: include/linux/usb.h, drivers/usb/core/driver.c
......
...@@ -475,9 +475,6 @@ static struct of_platform_driver of_pci_phb_driver = { ...@@ -475,9 +475,6 @@ static struct of_platform_driver of_pci_phb_driver = {
.name = "of-pci", .name = "of-pci",
.match_table = of_pci_phb_ids, .match_table = of_pci_phb_ids,
.probe = of_pci_phb_probe, .probe = of_pci_phb_probe,
.driver = {
.multithread_probe = 1,
},
}; };
static __init int of_pci_phb_init(void) static __init int of_pci_phb_init(void)
......
...@@ -47,14 +47,13 @@ static int amba_match(struct device *dev, struct device_driver *drv) ...@@ -47,14 +47,13 @@ static int amba_match(struct device *dev, struct device_driver *drv)
static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
{ {
struct amba_device *pcdev = to_amba_device(dev); struct amba_device *pcdev = to_amba_device(dev);
int retval = 0, i = 0, len = 0;
if (nr_env < 2) retval = add_uevent_var(envp, nr_env, &i,
return -ENOMEM; buf, bufsz, &len,
"AMBA_ID=%08x", pcdev->periphid);
snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid); envp[i] = NULL;
*envp++ = buf; return retval;
*envp++ = NULL;
return 0;
} }
#else #else
#define amba_uevent NULL #define amba_uevent NULL
......
...@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); ...@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
static struct list_head attribute_container_list; static struct list_head attribute_container_list;
static DECLARE_MUTEX(attribute_container_mutex); static DEFINE_MUTEX(attribute_container_mutex);
/** /**
* attribute_container_register - register an attribute container * attribute_container_register - register an attribute container
...@@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont) ...@@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont)
klist_init(&cont->containers,internal_container_klist_get, klist_init(&cont->containers,internal_container_klist_get,
internal_container_klist_put); internal_container_klist_put);
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
list_add_tail(&cont->node, &attribute_container_list); list_add_tail(&cont->node, &attribute_container_list);
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
return 0; return 0;
} }
...@@ -94,7 +94,7 @@ int ...@@ -94,7 +94,7 @@ int
attribute_container_unregister(struct attribute_container *cont) attribute_container_unregister(struct attribute_container *cont)
{ {
int retval = -EBUSY; int retval = -EBUSY;
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
spin_lock(&cont->containers.k_lock); spin_lock(&cont->containers.k_lock);
if (!list_empty(&cont->containers.k_list)) if (!list_empty(&cont->containers.k_list))
goto out; goto out;
...@@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont) ...@@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont)
list_del(&cont->node); list_del(&cont->node);
out: out:
spin_unlock(&cont->containers.k_lock); spin_unlock(&cont->containers.k_lock);
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
return retval; return retval;
} }
...@@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev, ...@@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev,
{ {
struct attribute_container *cont; struct attribute_container *cont;
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) { list_for_each_entry(cont, &attribute_container_list, node) {
struct internal_container *ic; struct internal_container *ic;
...@@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev, ...@@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev,
attribute_container_add_class_device(&ic->classdev); attribute_container_add_class_device(&ic->classdev);
klist_add_tail(&ic->node, &cont->containers); klist_add_tail(&ic->node, &cont->containers);
} }
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
} }
/* FIXME: can't break out of this unless klist_iter_exit is also /* FIXME: can't break out of this unless klist_iter_exit is also
...@@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev,
{ {
struct attribute_container *cont; struct attribute_container *cont;
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) { list_for_each_entry(cont, &attribute_container_list, node) {
struct internal_container *ic; struct internal_container *ic;
struct klist_iter iter; struct klist_iter iter;
...@@ -234,7 +234,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -234,7 +234,7 @@ attribute_container_remove_device(struct device *dev,
} }
} }
} }
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
} }
/** /**
...@@ -255,7 +255,7 @@ attribute_container_device_trigger(struct device *dev, ...@@ -255,7 +255,7 @@ attribute_container_device_trigger(struct device *dev,
{ {
struct attribute_container *cont; struct attribute_container *cont;
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) { list_for_each_entry(cont, &attribute_container_list, node) {
struct internal_container *ic; struct internal_container *ic;
struct klist_iter iter; struct klist_iter iter;
...@@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev, ...@@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev,
fn(cont, dev, &ic->classdev); fn(cont, dev, &ic->classdev);
} }
} }
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
} }
/** /**
...@@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev, ...@@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev,
{ {
struct attribute_container *cont; struct attribute_container *cont;
down(&attribute_container_mutex); mutex_lock(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) { list_for_each_entry(cont, &attribute_container_list, node) {
if (cont->match(cont, dev)) if (cont->match(cont, dev))
fn(cont, dev); fn(cont, dev);
} }
up(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
} }
/** /**
......
...@@ -16,7 +16,7 @@ extern int cpu_dev_init(void); ...@@ -16,7 +16,7 @@ extern int cpu_dev_init(void);
extern int attribute_container_init(void); extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev); extern int bus_add_device(struct device * dev);
extern int bus_attach_device(struct device * dev); extern void bus_attach_device(struct device * dev);
extern void bus_remove_device(struct device * dev); extern void bus_remove_device(struct device * dev);
extern struct bus_type *get_bus(struct bus_type * bus); extern struct bus_type *get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus); extern void put_bus(struct bus_type * bus);
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#define to_driver(obj) container_of(obj, struct device_driver, kobj) #define to_driver(obj) container_of(obj, struct device_driver, kobj)
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
static ssize_t static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{ {
...@@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = { ...@@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = {
static void driver_release(struct kobject * kobj) static void driver_release(struct kobject * kobj)
{ {
struct device_driver * drv = to_driver(kobj); /*
complete(&drv->unloaded); * Yes this is an empty release function, it is this way because struct
* device is always a static object, not a dynamic one. Yes, this is
* not nice and bad, but remember, drivers are code, reference counted
* by the module count, not a device, which is really data. And yes,
* in the future I do want to have all drivers be created dynamically,
* and am working toward that goal, but it will take a bit longer...
*
* But do not let this example give _anyone_ the idea that they can
* create a release function without any code in it at all, to do that
* is almost always wrong. If you have any questions about this,
* please send an email to <greg@kroah.com>
*/
} }
static struct kobj_type ktype_driver = { static struct kobj_type ktype_driver = {
...@@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL); ...@@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
/* Manually detach a device from its associated driver. */ /* Manually detach a device from its associated driver. */
static int driver_helper(struct device *dev, void *data) static int driver_helper(struct device *dev, void *data)
{ {
...@@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device_driver *drv, ...@@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device_driver *drv,
} }
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
{
return sprintf(buf, "%d\n", bus->drivers_autoprobe);
}
static ssize_t store_drivers_autoprobe(struct bus_type *bus,
const char *buf, size_t count)
{
if (buf[0] == '0')
bus->drivers_autoprobe = 0;
else
bus->drivers_autoprobe = 1;
return count;
}
static ssize_t store_drivers_probe(struct bus_type *bus,
const char *buf, size_t count)
{
struct device *dev;
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
if (!dev)
return -ENODEV;
if (bus_rescan_devices_helper(dev, NULL) != 0)
return -EINVAL;
return count;
}
#endif #endif
static struct device * next_device(struct klist_iter * i) static struct device * next_device(struct klist_iter * i)
...@@ -418,21 +458,21 @@ int bus_add_device(struct device * dev) ...@@ -418,21 +458,21 @@ int bus_add_device(struct device * dev)
* - Add device to bus's list of devices. * - Add device to bus's list of devices.
* - Try to attach to driver. * - Try to attach to driver.
*/ */
int bus_attach_device(struct device * dev) void bus_attach_device(struct device * dev)
{ {
struct bus_type *bus = dev->bus; struct bus_type *bus = dev->bus;
int ret = 0; int ret = 0;
if (bus) { if (bus) {
dev->is_registered = 1; dev->is_registered = 1;
ret = device_attach(dev); if (bus->drivers_autoprobe)
if (ret >= 0) { ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->klist_devices); klist_add_tail(&dev->knode_bus, &bus->klist_devices);
ret = 0; else
} else
dev->is_registered = 0; dev->is_registered = 0;
} }
return ret;
} }
/** /**
...@@ -515,9 +555,41 @@ static void remove_bind_files(struct device_driver *drv) ...@@ -515,9 +555,41 @@ static void remove_bind_files(struct device_driver *drv)
driver_remove_file(drv, &driver_attr_bind); driver_remove_file(drv, &driver_attr_bind);
driver_remove_file(drv, &driver_attr_unbind); driver_remove_file(drv, &driver_attr_unbind);
} }
static int add_probe_files(struct bus_type *bus)
{
int retval;
bus->drivers_probe_attr.attr.name = "drivers_probe";
bus->drivers_probe_attr.attr.mode = S_IWUSR;
bus->drivers_probe_attr.attr.owner = bus->owner;
bus->drivers_probe_attr.store = store_drivers_probe;
retval = bus_create_file(bus, &bus->drivers_probe_attr);
if (retval)
goto out;
bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
bus->drivers_autoprobe_attr.attr.owner = bus->owner;
bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
if (retval)
bus_remove_file(bus, &bus->drivers_probe_attr);
out:
return retval;
}
static void remove_probe_files(struct bus_type *bus)
{
bus_remove_file(bus, &bus->drivers_autoprobe_attr);
bus_remove_file(bus, &bus->drivers_probe_attr);
}
#else #else
static inline int add_bind_files(struct device_driver *drv) { return 0; } static inline int add_bind_files(struct device_driver *drv) { return 0; }
static inline void remove_bind_files(struct device_driver *drv) {} static inline void remove_bind_files(struct device_driver *drv) {}
static inline int add_probe_files(struct bus_type *bus) { return 0; }
static inline void remove_probe_files(struct bus_type *bus) {}
#endif #endif
/** /**
...@@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver *drv) ...@@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver *drv)
int error = 0; int error = 0;
if (!bus) if (!bus)
return 0; return -EINVAL;
pr_debug("bus %s: add driver %s\n", bus->name, drv->name); pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
error = kobject_set_name(&drv->kobj, "%s", drv->name); error = kobject_set_name(&drv->kobj, "%s", drv->name);
...@@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver *drv) ...@@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver *drv)
if ((error = kobject_register(&drv->kobj))) if ((error = kobject_register(&drv->kobj)))
goto out_put_bus; goto out_put_bus;
error = driver_attach(drv); if (drv->bus->drivers_autoprobe) {
if (error) error = driver_attach(drv);
goto out_unregister; if (error)
goto out_unregister;
}
klist_add_tail(&drv->knode_bus, &bus->klist_drivers); klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv); module_add_driver(drv->owner, drv);
...@@ -605,8 +679,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, ...@@ -605,8 +679,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
ret = device_attach(dev); ret = device_attach(dev);
if (dev->parent) if (dev->parent)
up(&dev->parent->sem); up(&dev->parent->sem);
if (ret > 0)
ret = 0;
} }
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
...@@ -762,6 +834,12 @@ int bus_register(struct bus_type * bus) ...@@ -762,6 +834,12 @@ int bus_register(struct bus_type * bus)
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&bus->klist_drivers, NULL, NULL); klist_init(&bus->klist_drivers, NULL, NULL);
bus->drivers_autoprobe = 1;
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus); retval = bus_add_attrs(bus);
if (retval) if (retval)
goto bus_attrs_fail; goto bus_attrs_fail;
...@@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus) ...@@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus)
return 0; return 0;
bus_attrs_fail: bus_attrs_fail:
remove_probe_files(bus);
bus_probe_files_fail:
kset_unregister(&bus->drivers); kset_unregister(&bus->drivers);
bus_drivers_fail: bus_drivers_fail:
kset_unregister(&bus->devices); kset_unregister(&bus->devices);
...@@ -779,7 +859,6 @@ int bus_register(struct bus_type * bus) ...@@ -779,7 +859,6 @@ int bus_register(struct bus_type * bus)
return retval; return retval;
} }
/** /**
* bus_unregister - remove a bus from the system * bus_unregister - remove a bus from the system
* @bus: bus. * @bus: bus.
...@@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bus) ...@@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bus)
{ {
pr_debug("bus %s: unregistering\n", bus->name); pr_debug("bus %s: unregistering\n", bus->name);
bus_remove_attrs(bus); bus_remove_attrs(bus);
remove_probe_files(bus);
kset_unregister(&bus->drivers); kset_unregister(&bus->drivers);
kset_unregister(&bus->devices); kset_unregister(&bus->devices);
subsystem_unregister(&bus->subsys); subsystem_unregister(&bus->subsys);
......
...@@ -145,6 +145,7 @@ int class_register(struct class * cls) ...@@ -145,6 +145,7 @@ int class_register(struct class * cls)
INIT_LIST_HEAD(&cls->children); INIT_LIST_HEAD(&cls->children);
INIT_LIST_HEAD(&cls->devices); INIT_LIST_HEAD(&cls->devices);
INIT_LIST_HEAD(&cls->interfaces); INIT_LIST_HEAD(&cls->interfaces);
kset_init(&cls->class_dirs);
init_MUTEX(&cls->sem); init_MUTEX(&cls->sem);
error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
if (error) if (error)
...@@ -163,7 +164,6 @@ int class_register(struct class * cls) ...@@ -163,7 +164,6 @@ int class_register(struct class * cls)
void class_unregister(struct class * cls) void class_unregister(struct class * cls)
{ {
pr_debug("device class '%s': unregistering\n", cls->name); pr_debug("device class '%s': unregistering\n", cls->name);
kobject_unregister(cls->virtual_dir);
remove_class_attrs(cls); remove_class_attrs(cls);
subsystem_unregister(&cls->subsys); subsystem_unregister(&cls->subsys);
} }
......
This diff is collapsed.
...@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev) ...@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev)
return ret; return ret;
} }
struct stupid_thread_structure {
struct device_driver *drv;
struct device *dev;
};
static atomic_t probe_count = ATOMIC_INIT(0); static atomic_t probe_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
static int really_probe(void *void_data) static int really_probe(struct device *dev, struct device_driver *drv)
{ {
struct stupid_thread_structure *data = void_data;
struct device_driver *drv = data->drv;
struct device *dev = data->dev;
int ret = 0; int ret = 0;
atomic_inc(&probe_count); atomic_inc(&probe_count);
...@@ -154,7 +146,6 @@ static int really_probe(void *void_data) ...@@ -154,7 +146,6 @@ static int really_probe(void *void_data)
*/ */
ret = 0; ret = 0;
done: done:
kfree(data);
atomic_dec(&probe_count); atomic_dec(&probe_count);
wake_up(&probe_waitqueue); wake_up(&probe_waitqueue);
return ret; return ret;
...@@ -186,16 +177,14 @@ int driver_probe_done(void) ...@@ -186,16 +177,14 @@ int driver_probe_done(void)
* format of the ID structures, nor what is to be considered a match and * format of the ID structures, nor what is to be considered a match and
* what is not. * what is not.
* *
* This function returns 1 if a match is found, an error if one occurs * This function returns 1 if a match is found, -ENODEV if the device is
* (that is not -ENODEV or -ENXIO), and 0 otherwise. * not registered, and 0 otherwise.
* *
* This function must be called with @dev->sem held. When called for a * This function must be called with @dev->sem held. When called for a
* USB interface, @dev->parent->sem must be held as well. * USB interface, @dev->parent->sem must be held as well.
*/ */
int driver_probe_device(struct device_driver * drv, struct device * dev) int driver_probe_device(struct device_driver * drv, struct device * dev)
{ {
struct stupid_thread_structure *data;
struct task_struct *probe_task;
int ret = 0; int ret = 0;
if (!device_is_registered(dev)) if (!device_is_registered(dev))
...@@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) ...@@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
pr_debug("%s: Matched Device %s with Driver %s\n", pr_debug("%s: Matched Device %s with Driver %s\n",
drv->bus->name, dev->bus_id, drv->name); drv->bus->name, dev->bus_id, drv->name);
data = kmalloc(sizeof(*data), GFP_KERNEL); ret = really_probe(dev, drv);
if (!data)
return -ENOMEM;
data->drv = drv;
data->dev = dev;
if (drv->multithread_probe) {
probe_task = kthread_run(really_probe, data,
"probe-%s", dev->bus_id);
if (IS_ERR(probe_task))
ret = really_probe(data);
} else
ret = really_probe(data);
done: done:
return ret; return ret;
...@@ -230,30 +207,57 @@ static int __device_attach(struct device_driver * drv, void * data) ...@@ -230,30 +207,57 @@ static int __device_attach(struct device_driver * drv, void * data)
return driver_probe_device(drv, dev); return driver_probe_device(drv, dev);
} }
static int device_probe_drivers(void *data)
{
struct device *dev = data;
int ret = 0;
if (dev->bus) {
down(&dev->sem);
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
up(&dev->sem);
}
return ret;
}
/** /**
* device_attach - try to attach device to a driver. * device_attach - try to attach device to a driver.
* @dev: device. * @dev: device.
* *
* Walk the list of drivers that the bus has and call * Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible * driver_probe_device() for each pair. If a compatible
* pair is found, break out and return. * pair is found, break out and return. If the bus specifies
* multithreaded probing, walking the list of drivers is done
* on a probing thread.
* *
* Returns 1 if the device was bound to a driver; * Returns 1 if the device was bound to a driver;
* 0 if no matching device was found; error code otherwise. * 0 if no matching device was found or multithreaded probing is done;
* -ENODEV if the device is not registered.
* *
* When called for a USB interface, @dev->parent->sem must be held. * When called for a USB interface, @dev->parent->sem must be held.
*/ */
int device_attach(struct device * dev) int device_attach(struct device * dev)
{ {
int ret = 0; int ret = 0;
struct task_struct *probe_task = ERR_PTR(-ENOMEM);
down(&dev->sem); down(&dev->sem);
if (dev->driver) { if (dev->driver) {
ret = device_bind_driver(dev); ret = device_bind_driver(dev);
if (ret == 0) if (ret == 0)
ret = 1; ret = 1;
} else else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); dev->driver = NULL;
ret = 0;
}
} else {
if (dev->bus->multithread_probe)
probe_task = kthread_run(device_probe_drivers, dev,
"probe-%s", dev->bus_id);
if(IS_ERR(probe_task))
ret = bus_for_each_drv(dev->bus, NULL, dev,
__device_attach);
}
up(&dev->sem); up(&dev->sem);
return ret; return ret;
} }
......
...@@ -37,7 +37,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ ...@@ -37,7 +37,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */
#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
static DECLARE_MUTEX (pools_lock); static DEFINE_MUTEX (pools_lock);
static ssize_t static ssize_t
show_pools (struct device *dev, struct device_attribute *attr, char *buf) show_pools (struct device *dev, struct device_attribute *attr, char *buf)
...@@ -55,7 +55,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) ...@@ -55,7 +55,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf)
size -= temp; size -= temp;
next += temp; next += temp;
down (&pools_lock); mutex_lock(&pools_lock);
list_for_each_entry(pool, &dev->dma_pools, pools) { list_for_each_entry(pool, &dev->dma_pools, pools) {
unsigned pages = 0; unsigned pages = 0;
unsigned blocks = 0; unsigned blocks = 0;
...@@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) ...@@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf)
size -= temp; size -= temp;
next += temp; next += temp;
} }
up (&pools_lock); mutex_unlock(&pools_lock);
return PAGE_SIZE - size; return PAGE_SIZE - size;
} }
...@@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev, ...@@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev,
if (dev) { if (dev) {
int ret; int ret;
down (&pools_lock); mutex_lock(&pools_lock);
if (list_empty (&dev->dma_pools)) if (list_empty (&dev->dma_pools))
ret = device_create_file (dev, &dev_attr_pools); ret = device_create_file (dev, &dev_attr_pools);
else else
...@@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev, ...@@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev,
kfree(retval); kfree(retval);
retval = NULL; retval = NULL;
} }
up (&pools_lock); mutex_unlock(&pools_lock);
} else } else
INIT_LIST_HEAD (&retval->pools); INIT_LIST_HEAD (&retval->pools);
...@@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page) ...@@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page)
void void
dma_pool_destroy (struct dma_pool *pool) dma_pool_destroy (struct dma_pool *pool)
{ {
down (&pools_lock); mutex_lock(&pools_lock);
list_del (&pool->pools); list_del (&pool->pools);
if (pool->dev && list_empty (&pool->dev->dma_pools)) if (pool->dev && list_empty (&pool->dev->dma_pools))
device_remove_file (pool->dev, &dev_attr_pools); device_remove_file (pool->dev, &dev_attr_pools);
up (&pools_lock); mutex_unlock(&pools_lock);
while (!list_empty (&pool->page_list)) { while (!list_empty (&pool->page_list)) {
struct dma_page *page; struct dma_page *page;
......
...@@ -149,10 +149,6 @@ void put_driver(struct device_driver * drv) ...@@ -149,10 +149,6 @@ void put_driver(struct device_driver * drv)
* We pass off most of the work to the bus_add_driver() call, * We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus * since most of the things we have to do deal with the bus
* structures. * structures.
*
* The one interesting aspect is that we setup @drv->unloaded
* as a completion that gets complete when the driver reference
* count reaches 0.
*/ */
int driver_register(struct device_driver * drv) int driver_register(struct device_driver * drv)
{ {
...@@ -162,35 +158,19 @@ int driver_register(struct device_driver * drv) ...@@ -162,35 +158,19 @@ int driver_register(struct device_driver * drv)
printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
} }
klist_init(&drv->klist_devices, NULL, NULL); klist_init(&drv->klist_devices, NULL, NULL);
init_completion(&drv->unloaded);
return bus_add_driver(drv); return bus_add_driver(drv);
} }
/** /**
* driver_unregister - remove driver from system. * driver_unregister - remove driver from system.
* @drv: driver. * @drv: driver.
* *
* Again, we pass off most of the work to the bus-level call. * Again, we pass off most of the work to the bus-level call.
*
* Though, once that is done, we wait until @drv->unloaded is completed.
* This will block until the driver refcount reaches 0, and it is
* released. Only modular drivers will call this function, and we
* have to guarantee that it won't complete, letting the driver
* unload until all references are gone.
*/ */
void driver_unregister(struct device_driver * drv) void driver_unregister(struct device_driver * drv)
{ {
bus_remove_driver(drv); bus_remove_driver(drv);
/*
* If the driver is a module, we are probably in
* the module unload path, and we want to wait
* for everything to unload before we can actually
* finish the unload.
*/
if (drv->owner)
wait_for_completion(&drv->unloaded);
} }
/** /**
......
...@@ -31,8 +31,6 @@ enum { ...@@ -31,8 +31,6 @@ enum {
FW_STATUS_LOADING, FW_STATUS_LOADING,
FW_STATUS_DONE, FW_STATUS_DONE,
FW_STATUS_ABORT, FW_STATUS_ABORT,
FW_STATUS_READY,
FW_STATUS_READY_NOHOTPLUG,
}; };
static int loading_timeout = 60; /* In seconds */ static int loading_timeout = 60; /* In seconds */
...@@ -96,9 +94,6 @@ static int firmware_uevent(struct device *dev, char **envp, int num_envp, ...@@ -96,9 +94,6 @@ static int firmware_uevent(struct device *dev, char **envp, int num_envp,
struct firmware_priv *fw_priv = dev_get_drvdata(dev); struct firmware_priv *fw_priv = dev_get_drvdata(dev);
int i = 0, len = 0; int i = 0, len = 0;
if (!test_bit(FW_STATUS_READY, &fw_priv->status))
return -ENODEV;
if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
"FIRMWARE=%s", fw_priv->fw_id)) "FIRMWARE=%s", fw_priv->fw_id))
return -ENOMEM; return -ENOMEM;
...@@ -333,6 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, ...@@ -333,6 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
f_dev->parent = device; f_dev->parent = device;
f_dev->class = &firmware_class; f_dev->class = &firmware_class;
dev_set_drvdata(f_dev, fw_priv); dev_set_drvdata(f_dev, fw_priv);
f_dev->uevent_suppress = 1;
retval = device_register(f_dev); retval = device_register(f_dev);
if (retval) { if (retval) {
printk(KERN_ERR "%s: device_register failed\n", printk(KERN_ERR "%s: device_register failed\n",
...@@ -382,9 +378,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p, ...@@ -382,9 +378,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
} }
if (uevent) if (uevent)
set_bit(FW_STATUS_READY, &fw_priv->status); f_dev->uevent_suppress = 0;
else
set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
*dev_p = f_dev; *dev_p = f_dev;
goto out; goto out;
......
...@@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq); ...@@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq);
DECLARE_MUTEX(dpm_sem); DECLARE_MUTEX(dpm_sem);
DECLARE_MUTEX(dpm_list_sem); DECLARE_MUTEX(dpm_list_sem);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
/** /**
* device_pm_set_parent - Specify power dependency. * device_pm_set_parent - Specify power dependency.
* @dev: Device who needs power. * @dev: Device who needs power.
......
...@@ -26,7 +26,9 @@ int resume_device(struct device * dev) ...@@ -26,7 +26,9 @@ int resume_device(struct device * dev)
TRACE_DEVICE(dev); TRACE_DEVICE(dev);
TRACE_RESUME(0); TRACE_RESUME(0);
down(&dev->sem); down(&dev->sem);
if (dev->power.pm_parent if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) { && dev->power.pm_parent->power.power_state.event) {
dev_err(dev, "PM: resume from %d, parent %s still %d\n", dev_err(dev, "PM: resume from %d, parent %s still %d\n",
...@@ -34,15 +36,24 @@ int resume_device(struct device * dev) ...@@ -34,15 +36,24 @@ int resume_device(struct device * dev)
dev->power.pm_parent->bus_id, dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state.event); dev->power.pm_parent->power.power_state.event);
} }
if (dev->bus && dev->bus->resume) { if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n"); dev_dbg(dev,"resuming\n");
error = dev->bus->resume(dev); error = dev->bus->resume(dev);
} }
if (dev->class && dev->class->resume) {
if (!error && dev->type && dev->type->resume) {
dev_dbg(dev,"resuming\n");
error = dev->type->resume(dev);
}
if (!error && dev->class && dev->class->resume) {
dev_dbg(dev,"class resume\n"); dev_dbg(dev,"class resume\n");
error = dev->class->resume(dev); error = dev->class->resume(dev);
} }
up(&dev->sem); up(&dev->sem);
TRACE_RESUME(error); TRACE_RESUME(error);
return error; return error;
} }
......
...@@ -36,7 +36,6 @@ void device_shutdown(void) ...@@ -36,7 +36,6 @@ void device_shutdown(void)
{ {
struct device * dev, *devn; struct device * dev, *devn;
down_write(&devices_subsys.rwsem);
list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list, list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
kobj.entry) { kobj.entry) {
if (dev->bus && dev->bus->shutdown) { if (dev->bus && dev->bus->shutdown) {
...@@ -47,7 +46,6 @@ void device_shutdown(void) ...@@ -47,7 +46,6 @@ void device_shutdown(void)
dev->driver->shutdown(dev); dev->driver->shutdown(dev);
} }
} }
up_write(&devices_subsys.rwsem);
sysdev_shutdown(); sysdev_shutdown();
} }
......
...@@ -78,6 +78,18 @@ int suspend_device(struct device * dev, pm_message_t state) ...@@ -78,6 +78,18 @@ int suspend_device(struct device * dev, pm_message_t state)
suspend_report_result(dev->class->suspend, error); suspend_report_result(dev->class->suspend, error);
} }
if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "%s%s\n",
suspend_verb(state.event),
((state.event == PM_EVENT_SUSPEND)
&& device_may_wakeup(dev))
? ", may wakeup"
: ""
);
error = dev->type->suspend(dev, state);
suspend_report_result(dev->type->suspend, error);
}
if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) { if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "%s%s\n", dev_dbg(dev, "%s%s\n",
suspend_verb(state.event), suspend_verb(state.event),
......
...@@ -310,14 +310,12 @@ static int proc_ide_read_driver ...@@ -310,14 +310,12 @@ static int proc_ide_read_driver
ide_driver_t *ide_drv; ide_driver_t *ide_drv;
int len; int len;
down_read(&dev->bus->subsys.rwsem);
if (dev->driver) { if (dev->driver) {
ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
len = sprintf(page, "%s version %s\n", len = sprintf(page, "%s version %s\n",
dev->driver->name, ide_drv->version); dev->driver->name, ide_drv->version);
} else } else
len = sprintf(page, "ide-default version 0.9.newide\n"); len = sprintf(page, "ide-default version 0.9.newide\n");
up_read(&dev->bus->subsys.rwsem);
PROC_IDE_READ_RETURN(page,start,off,count,eof,len); PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
} }
...@@ -327,7 +325,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) ...@@ -327,7 +325,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
int ret = 1; int ret = 1;
int err; int err;
down_write(&dev->bus->subsys.rwsem);
device_release_driver(dev); device_release_driver(dev);
/* FIXME: device can still be in use by previous driver */ /* FIXME: device can still be in use by previous driver */
strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
...@@ -345,7 +342,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) ...@@ -345,7 +342,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
} }
if (dev->driver && !strcmp(dev->driver->name, driver)) if (dev->driver && !strcmp(dev->driver->name, driver))
ret = 0; ret = 0;
up_write(&dev->bus->subsys.rwsem);
return ret; return ret;
} }
......
...@@ -370,9 +370,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute ...@@ -370,9 +370,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute
if (state == 1) { if (state == 1) {
ud->ignore_driver = 1; ud->ignore_driver = 1;
down_write(&ieee1394_bus_type.subsys.rwsem);
device_release_driver(dev); device_release_driver(dev);
up_write(&ieee1394_bus_type.subsys.rwsem);
} else if (state == 0) } else if (state == 0)
ud->ignore_driver = 0; ud->ignore_driver = 0;
...@@ -1163,6 +1161,7 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, ...@@ -1163,6 +1161,7 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
struct unit_directory *ud; struct unit_directory *ud;
int i = 0; int i = 0;
int length = 0; int length = 0;
int retval = 0;
/* ieee1394:venNmoNspNverN */ /* ieee1394:venNmoNspNverN */
char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
...@@ -1176,14 +1175,11 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, ...@@ -1176,14 +1175,11 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
#define PUT_ENVP(fmt,val) \ #define PUT_ENVP(fmt,val) \
do { \ do { \
int printed; \ retval = add_uevent_var(envp, num_envp, &i, \
envp[i++] = buffer; \ buffer, buffer_size, &length, \
printed = snprintf(buffer, buffer_size - length, \ fmt, val); \
fmt, val); \ if (retval) \
if ((buffer_size - (length+printed) <= 0) || (i >= num_envp)) \ return retval; \
return -ENOMEM; \
length += printed+1; \
buffer += printed+1; \
} while (0) } while (0)
PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id); PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
...@@ -1393,12 +1389,10 @@ static void nodemgr_suspend_ne(struct node_entry *ne) ...@@ -1393,12 +1389,10 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
down_write(&ieee1394_bus_type.subsys.rwsem);
if (ud->device.driver && if (ud->device.driver &&
(!ud->device.driver->suspend || (!ud->device.driver->suspend ||
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
device_release_driver(&ud->device); device_release_driver(&ud->device);
up_write(&ieee1394_bus_type.subsys.rwsem);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
} }
...@@ -1418,10 +1412,8 @@ static void nodemgr_resume_ne(struct node_entry *ne) ...@@ -1418,10 +1412,8 @@ static void nodemgr_resume_ne(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
down_read(&ieee1394_bus_type.subsys.rwsem);
if (ud->device.driver && ud->device.driver->resume) if (ud->device.driver && ud->device.driver->resume)
ud->device.driver->resume(&ud->device); ud->device.driver->resume(&ud->device);
up_read(&ieee1394_bus_type.subsys.rwsem);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
...@@ -1442,7 +1434,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne) ...@@ -1442,7 +1434,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
down_write(&ieee1394_bus_type.subsys.rwsem);
if (ud->device.driver) { if (ud->device.driver) {
pdrv = container_of(ud->device.driver, pdrv = container_of(ud->device.driver,
struct hpsb_protocol_driver, struct hpsb_protocol_driver,
...@@ -1450,7 +1441,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne) ...@@ -1450,7 +1441,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
if (pdrv->update && pdrv->update(ud)) if (pdrv->update && pdrv->update(ud))
device_release_driver(&ud->device); device_release_driver(&ud->device);
} }
up_write(&ieee1394_bus_type.subsys.rwsem);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
} }
......
...@@ -190,16 +190,14 @@ static void gameport_run_poll_handler(unsigned long d) ...@@ -190,16 +190,14 @@ static void gameport_run_poll_handler(unsigned long d)
* Basic gameport -> driver core mappings * Basic gameport -> driver core mappings
*/ */
static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
{ {
int error; int error;
down_write(&gameport_bus.subsys.rwsem);
gameport->dev.driver = &drv->driver; gameport->dev.driver = &drv->driver;
if (drv->connect(gameport, drv)) { if (drv->connect(gameport, drv)) {
gameport->dev.driver = NULL; gameport->dev.driver = NULL;
goto out; return -ENODEV;
} }
error = device_bind_driver(&gameport->dev); error = device_bind_driver(&gameport->dev);
...@@ -211,31 +209,21 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv ...@@ -211,31 +209,21 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv
drv->description, error); drv->description, error);
drv->disconnect(gameport); drv->disconnect(gameport);
gameport->dev.driver = NULL; gameport->dev.driver = NULL;
goto out; return error;
} }
out: return 0;
up_write(&gameport_bus.subsys.rwsem);
}
static void gameport_release_driver(struct gameport *gameport)
{
down_write(&gameport_bus.subsys.rwsem);
device_release_driver(&gameport->dev);
up_write(&gameport_bus.subsys.rwsem);
} }
static void gameport_find_driver(struct gameport *gameport) static void gameport_find_driver(struct gameport *gameport)
{ {
int error; int error;
down_write(&gameport_bus.subsys.rwsem);
error = device_attach(&gameport->dev); error = device_attach(&gameport->dev);
if (error < 0) if (error < 0)
printk(KERN_WARNING printk(KERN_WARNING
"gameport: device_attach() failed for %s (%s), error: %d\n", "gameport: device_attach() failed for %s (%s), error: %d\n",
gameport->phys, gameport->name, error); gameport->phys, gameport->name, error);
up_write(&gameport_bus.subsys.rwsem);
} }
...@@ -483,13 +471,12 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut ...@@ -483,13 +471,12 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
{ {
struct gameport *gameport = to_gameport_port(dev); struct gameport *gameport = to_gameport_port(dev);
struct device_driver *drv; struct device_driver *drv;
int retval; int error;
retval = mutex_lock_interruptible(&gameport_mutex); error = mutex_lock_interruptible(&gameport_mutex);
if (retval) if (error)
return retval; return error;
retval = count;
if (!strncmp(buf, "none", count)) { if (!strncmp(buf, "none", count)) {
gameport_disconnect_port(gameport); gameport_disconnect_port(gameport);
} else if (!strncmp(buf, "reconnect", count)) { } else if (!strncmp(buf, "reconnect", count)) {
...@@ -499,15 +486,15 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut ...@@ -499,15 +486,15 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
gameport_find_driver(gameport); gameport_find_driver(gameport);
} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) { } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
gameport_disconnect_port(gameport); gameport_disconnect_port(gameport);
gameport_bind_driver(gameport, to_gameport_driver(drv)); error = gameport_bind_driver(gameport, to_gameport_driver(drv));
put_driver(drv); put_driver(drv);
} else { } else {
retval = -EINVAL; error = -EINVAL;
} }
mutex_unlock(&gameport_mutex); mutex_unlock(&gameport_mutex);
return retval; return error ? error : count;
} }
static struct device_attribute gameport_device_attrs[] = { static struct device_attribute gameport_device_attrs[] = {
...@@ -655,7 +642,7 @@ static void gameport_disconnect_port(struct gameport *gameport) ...@@ -655,7 +642,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
do { do {
parent = s->parent; parent = s->parent;
gameport_release_driver(s); device_release_driver(&s->dev);
gameport_destroy_port(s); gameport_destroy_port(s);
} while ((s = parent) != gameport); } while ((s = parent) != gameport);
} }
...@@ -663,7 +650,7 @@ static void gameport_disconnect_port(struct gameport *gameport) ...@@ -663,7 +650,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
/* /*
* Ok, no children left, now disconnect this port * Ok, no children left, now disconnect this port
*/ */
gameport_release_driver(gameport); device_release_driver(&gameport->dev);
} }
void gameport_rescan(struct gameport *gameport) void gameport_rescan(struct gameport *gameport)
......
...@@ -115,18 +115,18 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser ...@@ -115,18 +115,18 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser
* Basic serio -> driver core mappings * Basic serio -> driver core mappings
*/ */
static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
{ {
int error; int error;
down_write(&serio_bus.subsys.rwsem);
if (serio_match_port(drv->id_table, serio)) { if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver; serio->dev.driver = &drv->driver;
if (serio_connect_driver(serio, drv)) { if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL; serio->dev.driver = NULL;
goto out; return -ENODEV;
} }
error = device_bind_driver(&serio->dev); error = device_bind_driver(&serio->dev);
if (error) { if (error) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -136,31 +136,21 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) ...@@ -136,31 +136,21 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
drv->description, error); drv->description, error);
serio_disconnect_driver(serio); serio_disconnect_driver(serio);
serio->dev.driver = NULL; serio->dev.driver = NULL;
goto out; return error;
} }
} }
out: return 0;
up_write(&serio_bus.subsys.rwsem);
}
static void serio_release_driver(struct serio *serio)
{
down_write(&serio_bus.subsys.rwsem);
device_release_driver(&serio->dev);
up_write(&serio_bus.subsys.rwsem);
} }
static void serio_find_driver(struct serio *serio) static void serio_find_driver(struct serio *serio)
{ {
int error; int error;
down_write(&serio_bus.subsys.rwsem);
error = device_attach(&serio->dev); error = device_attach(&serio->dev);
if (error < 0) if (error < 0)
printk(KERN_WARNING printk(KERN_WARNING
"serio: device_attach() failed for %s (%s), error: %d\n", "serio: device_attach() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error); serio->phys, serio->name, error);
up_write(&serio_bus.subsys.rwsem);
} }
...@@ -470,13 +460,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * ...@@ -470,13 +460,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
{ {
struct serio *serio = to_serio_port(dev); struct serio *serio = to_serio_port(dev);
struct device_driver *drv; struct device_driver *drv;
int retval; int error;
retval = mutex_lock_interruptible(&serio_mutex); error = mutex_lock_interruptible(&serio_mutex);
if (retval) if (error)
return retval; return error;
retval = count;
if (!strncmp(buf, "none", count)) { if (!strncmp(buf, "none", count)) {
serio_disconnect_port(serio); serio_disconnect_port(serio);
} else if (!strncmp(buf, "reconnect", count)) { } else if (!strncmp(buf, "reconnect", count)) {
...@@ -486,15 +475,15 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * ...@@ -486,15 +475,15 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
serio_find_driver(serio); serio_find_driver(serio);
} else if ((drv = driver_find(buf, &serio_bus)) != NULL) { } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
serio_disconnect_port(serio); serio_disconnect_port(serio);
serio_bind_driver(serio, to_serio_driver(drv)); error = serio_bind_driver(serio, to_serio_driver(drv));
put_driver(drv); put_driver(drv);
} else { } else {
retval = -EINVAL; error = -EINVAL;
} }
mutex_unlock(&serio_mutex); mutex_unlock(&serio_mutex);
return retval; return error ? error : count;
} }
static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
...@@ -665,7 +654,7 @@ static void serio_disconnect_port(struct serio *serio) ...@@ -665,7 +654,7 @@ static void serio_disconnect_port(struct serio *serio)
do { do {
parent = s->parent; parent = s->parent;
serio_release_driver(s); device_release_driver(&s->dev);
serio_destroy_port(s); serio_destroy_port(s);
} while ((s = parent) != serio); } while ((s = parent) != serio);
} }
...@@ -673,7 +662,7 @@ static void serio_disconnect_port(struct serio *serio) ...@@ -673,7 +662,7 @@ static void serio_disconnect_port(struct serio *serio)
/* /*
* Ok, no children left, now disconnect this port * Ok, no children left, now disconnect this port
*/ */
serio_release_driver(serio); device_release_driver(&serio->dev);
} }
void serio_rescan(struct serio *serio) void serio_rescan(struct serio *serio)
......
...@@ -86,31 +86,26 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, ...@@ -86,31 +86,26 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
{ {
struct mmc_card *card = dev_to_mmc_card(dev); struct mmc_card *card = dev_to_mmc_card(dev);
char ccc[13]; char ccc[13];
int i = 0; int retval = 0, i = 0, length = 0;
#define add_env(fmt,val) \ #define add_env(fmt,val) do { \
({ \ retval = add_uevent_var(envp, num_envp, &i, \
int len, ret = -ENOMEM; \ buf, buf_size, &length, \
if (i < num_envp) { \ fmt, val); \
envp[i++] = buf; \ if (retval) \
len = snprintf(buf, buf_size, fmt, val) + 1; \ return retval; \
buf_size -= len; \ } while (0);
buf += len; \
if (buf_size >= 0) \
ret = 0; \
} \
ret; \
})
for (i = 0; i < 12; i++) for (i = 0; i < 12; i++)
ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
ccc[12] = '\0'; ccc[12] = '\0';
i = 0;
add_env("MMC_CCC=%s", ccc); add_env("MMC_CCC=%s", ccc);
add_env("MMC_MANFID=%06x", card->cid.manfid); add_env("MMC_MANFID=%06x", card->cid.manfid);
add_env("MMC_NAME=%s", mmc_card_name(card)); add_env("MMC_NAME=%s", mmc_card_name(card));
add_env("MMC_OEMID=%04x", card->cid.oemid); add_env("MMC_OEMID=%04x", card->cid.oemid);
#undef add_env
envp[i] = NULL;
return 0; return 0;
} }
......
...@@ -276,21 +276,15 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) ...@@ -276,21 +276,15 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
artificially, we are binding the driver here by hand; artificially, we are binding the driver here by hand;
it will be the same for all the fixed phys anyway. it will be the same for all the fixed phys anyway.
*/ */
down_write(&phydev->dev.bus->subsys.rwsem);
phydev->dev.driver = &fixed_mdio_driver.driver; phydev->dev.driver = &fixed_mdio_driver.driver;
err = phydev->dev.driver->probe(&phydev->dev); err = phydev->dev.driver->probe(&phydev->dev);
if(err < 0) { if(err < 0) {
printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
up_write(&phydev->dev.bus->subsys.rwsem);
goto probe_fail; goto probe_fail;
} }
err = device_bind_driver(&phydev->dev); err = device_bind_driver(&phydev->dev);
up_write(&phydev->dev.bus->subsys.rwsem);
if (err) if (err)
goto probe_fail; goto probe_fail;
......
...@@ -208,16 +208,12 @@ struct phy_device *phy_attach(struct net_device *dev, ...@@ -208,16 +208,12 @@ struct phy_device *phy_attach(struct net_device *dev,
* exist, and we should use the genphy driver. */ * exist, and we should use the genphy driver. */
if (NULL == d->driver) { if (NULL == d->driver) {
int err; int err;
down_write(&d->bus->subsys.rwsem);
d->driver = &genphy_driver.driver; d->driver = &genphy_driver.driver;
err = d->driver->probe(d); err = d->driver->probe(d);
if (err >= 0) if (err >= 0)
err = device_bind_driver(d); err = device_bind_driver(d);
up_write(&d->bus->subsys.rwsem);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -258,11 +254,8 @@ void phy_detach(struct phy_device *phydev) ...@@ -258,11 +254,8 @@ void phy_detach(struct phy_device *phydev)
* was using the generic driver), we unbind the device * was using the generic driver), we unbind the device
* from the generic driver so that there's a chance a * from the generic driver so that there's a chance a
* real driver could be loaded */ * real driver could be loaded */
if (phydev->dev.driver == &genphy_driver.driver) { if (phydev->dev.driver == &genphy_driver.driver)
down_write(&phydev->dev.bus->subsys.rwsem);
device_release_driver(&phydev->dev); device_release_driver(&phydev->dev);
up_write(&phydev->dev.bus->subsys.rwsem);
}
} }
EXPORT_SYMBOL(phy_detach); EXPORT_SYMBOL(phy_detach);
......
...@@ -434,11 +434,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, ...@@ -434,11 +434,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
drv->driver.mod_name = mod_name; drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type; drv->driver.kobj.ktype = &pci_driver_kobj_type;
if (pci_multithread_probe)
drv->driver.multithread_probe = pci_multithread_probe;
else
drv->driver.multithread_probe = drv->multithread_probe;
spin_lock_init(&drv->dynids.lock); spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list); INIT_LIST_HEAD(&drv->dynids.list);
...@@ -574,6 +569,7 @@ struct bus_type pci_bus_type = { ...@@ -574,6 +569,7 @@ struct bus_type pci_bus_type = {
static int __init pci_driver_init(void) static int __init pci_driver_init(void)
{ {
pci_bus_type.multithread_probe = pci_multithread_probe;
return bus_register(&pci_bus_type); return bus_register(&pci_bus_type);
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -891,31 +892,48 @@ pci_disable_device(struct pci_dev *dev) ...@@ -891,31 +892,48 @@ pci_disable_device(struct pci_dev *dev)
} }
/** /**
* pci_enable_wake - enable device to generate PME# when suspended * pci_enable_wake - enable PCI device as wakeup event source
* @dev: - PCI device to operate on * @dev: PCI device affected
* @state: - Current state of device. * @state: PCI state from which device will issue wakeup events
* @enable: - Flag to enable or disable generation * @enable: True to enable event generation; false to disable
*
* Set the bits in the device's PM Capabilities to generate PME# when
* the system is suspended.
* *
* -EIO is returned if device doesn't have PM Capabilities. * This enables the device as a wakeup event source, or disables it.
* -EINVAL is returned if device supports it, but can't generate wake events. * When such events involves platform-specific hooks, those hooks are
* 0 if operation is successful. * called automatically by this routine.
* *
* Devices with legacy power management (no standard PCI PM capabilities)
* always require such platform hooks. Depending on the platform, devices
* supporting the standard PCI PME# signal may require such platform hooks;
* they always update bits in config space to allow PME# generation.
*
* -EIO is returned if the device can't ever be a wakeup event source.
* -EINVAL is returned if the device can't generate wakeup events from
* the specified PCI state. Returns zero if the operation is successful.
*/ */
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
{ {
int pm; int pm;
int status;
u16 value; u16 value;
/* Note that drivers should verify device_may_wakeup(&dev->dev)
* before calling this function. Platform code should report
* errors when drivers try to enable wakeup on devices that
* can't issue wakeups, or on which wakeups were disabled by
* userspace updating the /sys/devices.../power/wakeup file.
*/
status = call_platform_enable_wakeup(&dev->dev, enable);
/* find PCI PM capability in list */ /* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM); pm = pci_find_capability(dev, PCI_CAP_ID_PM);
/* If device doesn't support PM Capabilities, but request is to disable /* If device doesn't support PM Capabilities, but caller wants to
* wake events, it's a nop; otherwise fail */ * disable wake events, it's a NOP. Otherwise fail unless the
if (!pm) * platform hooks handled this legacy device already.
return enable ? -EIO : 0; */
if (!pm)
return enable ? status : 0;
/* Check device's ability to generate PME# */ /* Check device's ability to generate PME# */
pci_read_config_word(dev,pm+PCI_PM_PMC,&value); pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
...@@ -924,8 +942,14 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) ...@@ -924,8 +942,14 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
/* Check if it can generate PME# from requested state. */ /* Check if it can generate PME# from requested state. */
if (!value || !(value & (1 << state))) if (!value || !(value & (1 << state))) {
/* if it can't, revert what the platform hook changed,
* always reporting the base "EINVAL, can't PME#" error
*/
if (enable)
call_platform_enable_wakeup(&dev->dev, 0);
return enable ? -EINVAL : 0; return enable ? -EINVAL : 0;
}
pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
...@@ -936,7 +960,7 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) ...@@ -936,7 +960,7 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
value &= ~PCI_PM_CTRL_PME_ENABLE; value &= ~PCI_PM_CTRL_PME_ENABLE;
pci_write_config_word(dev, pm + PCI_PM_CTRL, value); pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
return 0; return 0;
} }
......
...@@ -311,7 +311,6 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char ...@@ -311,7 +311,6 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char
return NULL; return NULL;
found: found:
down_write(&dev->dev.bus->subsys.rwsem);
dev->card_link = clink; dev->card_link = clink;
dev->dev.driver = &drv->link.driver; dev->dev.driver = &drv->link.driver;
if (pnp_bus_type.probe(&dev->dev)) if (pnp_bus_type.probe(&dev->dev))
...@@ -319,14 +318,11 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char ...@@ -319,14 +318,11 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char
if (device_bind_driver(&dev->dev)) if (device_bind_driver(&dev->dev))
goto err_out; goto err_out;
up_write(&dev->dev.bus->subsys.rwsem);
return dev; return dev;
err_out: err_out:
dev->dev.driver = NULL; dev->dev.driver = NULL;
dev->card_link = NULL; dev->card_link = NULL;
up_write(&dev->dev.bus->subsys.rwsem);
return NULL; return NULL;
} }
...@@ -340,11 +336,9 @@ void pnp_release_card_device(struct pnp_dev * dev) ...@@ -340,11 +336,9 @@ void pnp_release_card_device(struct pnp_dev * dev)
struct pnp_card_driver * drv = dev->card_link->driver; struct pnp_card_driver * drv = dev->card_link->driver;
if (!drv) if (!drv)
return; return;
down_write(&dev->dev.bus->subsys.rwsem);
drv->link.remove = &card_remove; drv->link.remove = &card_remove;
device_release_driver(&dev->dev); device_release_driver(&dev->dev);
drv->link.remove = &card_remove_first; drv->link.remove = &card_remove_first;
up_write(&dev->dev.bus->subsys.rwsem);
} }
/* /*
......
...@@ -871,6 +871,12 @@ io_subchannel_register(struct work_struct *work) ...@@ -871,6 +871,12 @@ io_subchannel_register(struct work_struct *work)
} }
goto out; goto out;
} }
/*
* Now we know this subchannel will stay, we can throw
* our delayed uevent.
*/
sch->dev.uevent_suppress = 0;
kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
/* make it known to the system */ /* make it known to the system */
ret = ccw_device_register(cdev); ret = ccw_device_register(cdev);
if (ret) { if (ret) {
......
...@@ -423,27 +423,25 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp, ...@@ -423,27 +423,25 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size) char *buffer, int buffer_size)
{ {
struct ap_device *ap_dev = to_ap_dev(dev); struct ap_device *ap_dev = to_ap_dev(dev);
int length; int retval = 0, length = 0, i = 0;
if (!ap_dev) if (!ap_dev)
return -ENODEV; return -ENODEV;
/* Set up DEV_TYPE environment variable. */ /* Set up DEV_TYPE environment variable. */
envp[0] = buffer; retval = add_uevent_var(envp, num_envp, &i,
length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X", buffer, buffer_size, &length,
ap_dev->device_type); "DEV_TYPE=%04X", ap_dev->device_type);
if (buffer_size - length <= 0) if (retval)
return -ENOMEM; return retval;
buffer += length;
buffer_size -= length;
/* Add MODALIAS= */ /* Add MODALIAS= */
envp[1] = buffer; retval = add_uevent_var(envp, num_envp, &i,
length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X", buffer, buffer_size, &length,
ap_dev->device_type); "MODALIAS=ap:t%02X", ap_dev->device_type);
if (buffer_size - length <= 0)
return -ENOMEM; envp[i] = NULL;
envp[2] = NULL; return retval;
return 0;
} }
static struct bus_type ap_bus_type = { static struct bus_type ap_bus_type = {
......
...@@ -37,7 +37,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) ...@@ -37,7 +37,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
struct device *dev = NULL; struct device *dev = NULL;
loff_t nr = 0; loff_t nr = 0;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
if (*offset == 0) if (*offset == 0)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
while (1) { while (1) {
...@@ -53,7 +52,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) ...@@ -53,7 +52,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
static void static void
qeth_procfile_seq_stop(struct seq_file *s, void* it) qeth_procfile_seq_stop(struct seq_file *s, void* it)
{ {
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
} }
static void * static void *
......
...@@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) ...@@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
struct class_device *cdev; struct class_device *cdev;
struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p; struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
down_read(&class->subsys.rwsem); down(&class->sem);
list_for_each_entry(cdev, &class->children, node) { list_for_each_entry(cdev, &class->children, node) {
p = class_to_shost(cdev); p = class_to_shost(cdev);
if (p->host_no == hostnum) { if (p->host_no == hostnum) {
...@@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) ...@@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
break; break;
} }
} }
up_read(&class->subsys.rwsem); up(&class->sem);
return shost; return shost;
} }
......
...@@ -246,7 +246,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end, ...@@ -246,7 +246,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
if (start > end) if (start > end)
return start; return start;
down_read(&usb_bus_type.subsys.rwsem);
if (iface) { if (iface) {
driver_name = (iface->dev.driver driver_name = (iface->dev.driver
? iface->dev.driver->name ? iface->dev.driver->name
...@@ -263,7 +262,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end, ...@@ -263,7 +262,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
desc->bInterfaceSubClass, desc->bInterfaceSubClass,
desc->bInterfaceProtocol, desc->bInterfaceProtocol,
driver_name); driver_name);
up_read(&usb_bus_type.subsys.rwsem);
return start; return start;
} }
......
...@@ -421,14 +421,11 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum) ...@@ -421,14 +421,11 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
if (test_bit(ifnum, &ps->ifclaimed)) if (test_bit(ifnum, &ps->ifclaimed))
return 0; return 0;
/* lock against other changes to driver bindings */
down_write(&usb_bus_type.subsys.rwsem);
intf = usb_ifnum_to_if(dev, ifnum); intf = usb_ifnum_to_if(dev, ifnum);
if (!intf) if (!intf)
err = -ENOENT; err = -ENOENT;
else else
err = usb_driver_claim_interface(&usbfs_driver, intf, ps); err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
up_write(&usb_bus_type.subsys.rwsem);
if (err == 0) if (err == 0)
set_bit(ifnum, &ps->ifclaimed); set_bit(ifnum, &ps->ifclaimed);
return err; return err;
...@@ -444,8 +441,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum) ...@@ -444,8 +441,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
if (ifnum >= 8*sizeof(ps->ifclaimed)) if (ifnum >= 8*sizeof(ps->ifclaimed))
return err; return err;
dev = ps->dev; dev = ps->dev;
/* lock against other changes to driver bindings */
down_write(&usb_bus_type.subsys.rwsem);
intf = usb_ifnum_to_if(dev, ifnum); intf = usb_ifnum_to_if(dev, ifnum);
if (!intf) if (!intf)
err = -ENOENT; err = -ENOENT;
...@@ -453,7 +448,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum) ...@@ -453,7 +448,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
usb_driver_release_interface(&usbfs_driver, intf); usb_driver_release_interface(&usbfs_driver, intf);
err = 0; err = 0;
} }
up_write(&usb_bus_type.subsys.rwsem);
return err; return err;
} }
...@@ -813,7 +807,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) ...@@ -813,7 +807,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
if (copy_from_user(&gd, arg, sizeof(gd))) if (copy_from_user(&gd, arg, sizeof(gd)))
return -EFAULT; return -EFAULT;
down_read(&usb_bus_type.subsys.rwsem);
intf = usb_ifnum_to_if(ps->dev, gd.interface); intf = usb_ifnum_to_if(ps->dev, gd.interface);
if (!intf || !intf->dev.driver) if (!intf || !intf->dev.driver)
ret = -ENODATA; ret = -ENODATA;
...@@ -822,7 +815,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) ...@@ -822,7 +815,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
sizeof(gd.driver)); sizeof(gd.driver));
ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
} }
up_read(&usb_bus_type.subsys.rwsem);
return ret; return ret;
} }
...@@ -1351,15 +1343,12 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) ...@@ -1351,15 +1343,12 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* disconnect kernel driver from interface */ /* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT: case USBDEVFS_DISCONNECT:
down_write(&usb_bus_type.subsys.rwsem);
if (intf->dev.driver) { if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver); driver = to_usb_driver(intf->dev.driver);
dev_dbg (&intf->dev, "disconnect by usbfs\n"); dev_dbg (&intf->dev, "disconnect by usbfs\n");
usb_driver_release_interface(driver, intf); usb_driver_release_interface(driver, intf);
} else } else
retval = -ENODATA; retval = -ENODATA;
up_write(&usb_bus_type.subsys.rwsem);
break; break;
/* let kernel drivers try to (re)bind to the interface */ /* let kernel drivers try to (re)bind to the interface */
...@@ -1371,7 +1360,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) ...@@ -1371,7 +1360,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* talk directly to the interface's driver */ /* talk directly to the interface's driver */
default: default:
down_read(&usb_bus_type.subsys.rwsem);
if (intf->dev.driver) if (intf->dev.driver)
driver = to_usb_driver(intf->dev.driver); driver = to_usb_driver(intf->dev.driver);
if (driver == NULL || driver->ioctl == NULL) { if (driver == NULL || driver->ioctl == NULL) {
...@@ -1381,7 +1369,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) ...@@ -1381,7 +1369,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
if (retval == -ENOIOCTLCMD) if (retval == -ENOIOCTLCMD)
retval = -ENOTTY; retval = -ENOTTY;
} }
up_read(&usb_bus_type.subsys.rwsem);
} }
/* cleanup and return */ /* cleanup and return */
......
...@@ -287,9 +287,9 @@ static int usb_unbind_interface(struct device *dev) ...@@ -287,9 +287,9 @@ static int usb_unbind_interface(struct device *dev)
* way to bind to an interface is to return the private data from * way to bind to an interface is to return the private data from
* the driver's probe() method. * the driver's probe() method.
* *
* Callers must own the device lock and the driver model's usb_bus_type.subsys * Callers must own the device lock, so driver probe() entries don't need
* writelock. So driver probe() entries don't need extra locking, * extra locking, but other call contexts may need to explicitly claim that
* but other call contexts may need to explicitly claim those locks. * lock.
*/ */
int usb_driver_claim_interface(struct usb_driver *driver, int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void* priv) struct usb_interface *iface, void* priv)
...@@ -330,9 +330,9 @@ EXPORT_SYMBOL(usb_driver_claim_interface); ...@@ -330,9 +330,9 @@ EXPORT_SYMBOL(usb_driver_claim_interface);
* also causes the driver disconnect() method to be called. * also causes the driver disconnect() method to be called.
* *
* This call is synchronous, and may not be used in an interrupt context. * This call is synchronous, and may not be used in an interrupt context.
* Callers must own the device lock and the driver model's usb_bus_type.subsys * Callers must own the device lock, so driver disconnect() entries don't
* writelock. So driver disconnect() entries don't need extra locking, * need extra locking, but other call contexts may need to explicitly claim
* but other call contexts may need to explicitly claim those locks. * that lock.
*/ */
void usb_driver_release_interface(struct usb_driver *driver, void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface) struct usb_interface *iface)
......
...@@ -119,8 +119,7 @@ MODULE_PARM_DESC(use_both_schemes, ...@@ -119,8 +119,7 @@ MODULE_PARM_DESC(use_both_schemes,
"first one fails"); "first one fails");
#ifdef DEBUG static inline char *portspeed(int portstatus)
static inline char *portspeed (int portstatus)
{ {
if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
return "480 Mb/s"; return "480 Mb/s";
...@@ -129,7 +128,6 @@ static inline char *portspeed (int portstatus) ...@@ -129,7 +128,6 @@ static inline char *portspeed (int portstatus)
else else
return "12 Mb/s"; return "12 Mb/s";
} }
#endif
/* Note that hdev or one of its children must be locked! */ /* Note that hdev or one of its children must be locked! */
static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev) static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev)
......
...@@ -1349,7 +1349,7 @@ static void release_interface(struct device *dev) ...@@ -1349,7 +1349,7 @@ static void release_interface(struct device *dev)
* *
* This call is synchronous. The calling context must be able to sleep, * This call is synchronous. The calling context must be able to sleep,
* must own the device lock, and must not hold the driver model's USB * must own the device lock, and must not hold the driver model's USB
* bus rwsem; usb device driver probe() methods cannot use this routine. * bus mutex; usb device driver probe() methods cannot use this routine.
* *
* Returns zero on success, or else the status code returned by the * Returns zero on success, or else the status code returned by the
* underlying call that failed. On successful completion, each interface * underlying call that failed. On successful completion, each interface
......
...@@ -486,9 +486,6 @@ static int ohci_run (struct ohci_hcd *ohci) ...@@ -486,9 +486,6 @@ static int ohci_run (struct ohci_hcd *ohci)
* or if bus glue did the same (e.g. for PCI add-in cards with * or if bus glue did the same (e.g. for PCI add-in cards with
* PCI PM support). * PCI PM support).
*/ */
ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci_readl (ohci, &ohci->regs->control));
if ((ohci->hc_control & OHCI_CTRL_RWC) != 0 if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
&& !device_may_wakeup(hcd->self.controller)) && !device_may_wakeup(hcd->self.controller))
device_init_wakeup(hcd->self.controller, 1); device_init_wakeup(hcd->self.controller, 1);
...@@ -744,9 +741,6 @@ static void ohci_stop (struct usb_hcd *hcd) ...@@ -744,9 +741,6 @@ static void ohci_stop (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
hcd->state);
ohci_dump (ohci, 1); ohci_dump (ohci, 1);
flush_scheduled_work(); flush_scheduled_work();
......
...@@ -179,6 +179,48 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode, ...@@ -179,6 +179,48 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
} }
EXPORT_SYMBOL_GPL(debugfs_create_u32); EXPORT_SYMBOL_GPL(debugfs_create_u32);
static void debugfs_u64_set(void *data, u64 val)
{
*(u64 *)data = val;
}
static u64 debugfs_u64_get(void *data)
{
return *(u64 *)data;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
/**
* debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
* @value: a pointer to the variable that the file should read to and write
* from.
*
* This function creates a file in debugfs with the given name that
* contains the value of the variable @value. If the @mode variable is so
* set, it can be read from, and written to.
*
* This function will return a pointer to a dentry if it succeeds. This
* pointer must be passed to the debugfs_remove() function when the file is
* to be removed (no automatic cleanup happens if your module is unloaded,
* you are responsible here.) If an error occurs, %NULL will be returned.
*
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
* returned. It is not wise to check for this value, but rather, check for
* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
* code.
*/
struct dentry *debugfs_create_u64(const char *name, mode_t mode,
struct dentry *parent, u64 *value)
{
return debugfs_create_file(name, mode, parent, value, &fops_u64);
}
EXPORT_SYMBOL_GPL(debugfs_create_u64);
static ssize_t read_file_bool(struct file *file, char __user *user_buf, static ssize_t read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
......
...@@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, ...@@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
return err; return err;
} }
/* static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
* Restricted form of lookup. Doesn't follow links, single-component only,
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
{ {
struct dentry * dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
int err; int err;
inode = base->d_inode; inode = base->d_inode;
err = permission(inode, MAY_EXEC, nd);
dentry = ERR_PTR(err);
if (err)
goto out;
/* /*
* See if the low-level filesystem might want * See if the low-level filesystem might want
...@@ -1287,35 +1278,76 @@ static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, st ...@@ -1287,35 +1278,76 @@ static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, st
return dentry; return dentry;
} }
/*
* Restricted form of lookup. Doesn't follow links, single-component only,
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
{
struct dentry *dentry;
struct inode *inode;
int err;
inode = base->d_inode;
err = permission(inode, MAY_EXEC, nd);
dentry = ERR_PTR(err);
if (err)
goto out;
dentry = __lookup_hash_kern(name, base, nd);
out:
return dentry;
}
static struct dentry *lookup_hash(struct nameidata *nd) static struct dentry *lookup_hash(struct nameidata *nd)
{ {
return __lookup_hash(&nd->last, nd->dentry, nd); return __lookup_hash(&nd->last, nd->dentry, nd);
} }
/* SMP-safe */ /* SMP-safe */
struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
{ {
unsigned long hash; unsigned long hash;
struct qstr this;
unsigned int c; unsigned int c;
this.name = name; this->name = name;
this.len = len; this->len = len;
if (!len) if (!len)
goto access; return -EACCES;
hash = init_name_hash(); hash = init_name_hash();
while (len--) { while (len--) {
c = *(const unsigned char *)name++; c = *(const unsigned char *)name++;
if (c == '/' || c == '\0') if (c == '/' || c == '\0')
goto access; return -EACCES;
hash = partial_name_hash(c, hash); hash = partial_name_hash(c, hash);
} }
this.hash = end_name_hash(hash); this->hash = end_name_hash(hash);
return 0;
}
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
{
int err;
struct qstr this;
err = __lookup_one_len(name, &this, base, len);
if (err)
return ERR_PTR(err);
return __lookup_hash(&this, base, NULL); return __lookup_hash(&this, base, NULL);
access: }
return ERR_PTR(-EACCES);
struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len)
{
int err;
struct qstr this;
err = __lookup_one_len(name, &this, base, len);
if (err)
return ERR_PTR(err);
return __lookup_hash_kern(&this, base, NULL);
} }
/* /*
......
...@@ -725,16 +725,6 @@ static int test_bdev_super(struct super_block *s, void *data) ...@@ -725,16 +725,6 @@ static int test_bdev_super(struct super_block *s, void *data)
return (void *)s->s_bdev == data; return (void *)s->s_bdev == data;
} }
static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
{
if (bdev->bd_disk) {
if (bdev->bd_part)
kobject_uevent(&bdev->bd_part->kobj, action);
else
kobject_uevent(&bdev->bd_disk->kobj, action);
}
}
int get_sb_bdev(struct file_system_type *fs_type, int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int), int (*fill_super)(struct super_block *, void *, int),
...@@ -782,7 +772,6 @@ int get_sb_bdev(struct file_system_type *fs_type, ...@@ -782,7 +772,6 @@ int get_sb_bdev(struct file_system_type *fs_type,
} }
s->s_flags |= MS_ACTIVE; s->s_flags |= MS_ACTIVE;
bdev_uevent(bdev, KOBJ_MOUNT);
} }
return simple_set_mnt(mnt, s); return simple_set_mnt(mnt, s);
...@@ -801,7 +790,6 @@ void kill_block_super(struct super_block *sb) ...@@ -801,7 +790,6 @@ void kill_block_super(struct super_block *sb)
{ {
struct block_device *bdev = sb->s_bdev; struct block_device *bdev = sb->s_bdev;
bdev_uevent(bdev, KOBJ_UMOUNT);
generic_shutdown_super(sb); generic_shutdown_super(sb);
sync_blockdev(bdev); sync_blockdev(bdev);
close_bdev_excl(bdev); close_bdev_excl(bdev);
......
...@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) ...@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
if (copy_to_user(userbuf, buffer, count)) if (copy_to_user(userbuf, buffer, count))
return -EFAULT; return -EFAULT;
pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
*off = offs + count; *off = offs + count;
......
...@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct { ...@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct {
struct kobject *kobj; struct kobject *kobj;
void (*func)(void *); void (*func)(void *);
void *data; void *data;
struct module *owner;
struct work_struct work; struct work_struct work;
}; };
...@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) ...@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
(ss->func)(ss->data); (ss->func)(ss->data);
kobject_put(ss->kobj); kobject_put(ss->kobj);
module_put(ss->owner);
kfree(ss); kfree(ss);
} }
...@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) ...@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
* @kobj: object we're acting for. * @kobj: object we're acting for.
* @func: callback function to invoke later. * @func: callback function to invoke later.
* @data: argument to pass to @func. * @data: argument to pass to @func.
* @owner: module owning the callback code
* *
* sysfs attribute methods must not unregister themselves or their parent * sysfs attribute methods must not unregister themselves or their parent
* kobject (which would amount to the same thing). Attempts to do so will * kobject (which would amount to the same thing). Attempts to do so will
...@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work) ...@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
* until @func returns. * until @func returns.
* *
* Returns 0 if the request was submitted, -ENOMEM if storage could not * Returns 0 if the request was submitted, -ENOMEM if storage could not
* be allocated. * be allocated, -ENODEV if a reference to @owner isn't available.
*/ */
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
void *data) void *data, struct module *owner)
{ {
struct sysfs_schedule_callback_struct *ss; struct sysfs_schedule_callback_struct *ss;
if (!try_module_get(owner))
return -ENODEV;
ss = kmalloc(sizeof(*ss), GFP_KERNEL); ss = kmalloc(sizeof(*ss), GFP_KERNEL);
if (!ss) if (!ss) {
module_put(owner);
return -ENOMEM; return -ENOMEM;
}
kobject_get(kobj); kobject_get(kobj);
ss->kobj = kobj; ss->kobj = kobj;
ss->func = func; ss->func = func;
ss->data = data; ss->data = data;
ss->owner = owner;
INIT_WORK(&ss->work, sysfs_schedule_callback_work); INIT_WORK(&ss->work, sysfs_schedule_callback_work);
schedule_work(&ss->work); schedule_work(&ss->work);
return 0; return 0;
......
...@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj, ...@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj,
{ {
struct dentry * dir; struct dentry * dir;
if (grp->name) if (grp->name) {
dir = lookup_one_len(grp->name, kobj->dentry, dir = lookup_one_len_kern(grp->name, kobj->dentry,
strlen(grp->name)); strlen(grp->name));
BUG_ON(IS_ERR(dir));
}
else else
dir = dget(kobj->dentry); dir = dget(kobj->dentry);
......
...@@ -44,6 +44,8 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode, ...@@ -44,6 +44,8 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode,
struct dentry *parent, u16 *value); struct dentry *parent, u16 *value);
struct dentry *debugfs_create_u32(const char *name, mode_t mode, struct dentry *debugfs_create_u32(const char *name, mode_t mode,
struct dentry *parent, u32 *value); struct dentry *parent, u32 *value);
struct dentry *debugfs_create_u64(const char *name, mode_t mode,
struct dentry *parent, u64 *value);
struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *debugfs_create_bool(const char *name, mode_t mode,
struct dentry *parent, u32 *value); struct dentry *parent, u32 *value);
...@@ -104,6 +106,13 @@ static inline struct dentry *debugfs_create_u32(const char *name, mode_t mode, ...@@ -104,6 +106,13 @@ static inline struct dentry *debugfs_create_u32(const char *name, mode_t mode,
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
struct dentry *parent,
u64 *value)
{
return ERR_PTR(-ENODEV);
}
static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode, static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
struct dentry *parent, struct dentry *parent,
u32 *value) u32 *value)
......
...@@ -34,9 +34,24 @@ struct device; ...@@ -34,9 +34,24 @@ struct device;
struct device_driver; struct device_driver;
struct class; struct class;
struct class_device; struct class_device;
struct bus_type;
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
#define BUS_ATTR(_name,_mode,_show,_store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
extern int __must_check bus_create_file(struct bus_type *,
struct bus_attribute *);
extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
struct bus_type { struct bus_type {
const char * name; const char * name;
struct module * owner;
struct subsystem subsys; struct subsystem subsys;
struct kset drivers; struct kset drivers;
...@@ -49,6 +64,8 @@ struct bus_type { ...@@ -49,6 +64,8 @@ struct bus_type {
struct bus_attribute * bus_attrs; struct bus_attribute * bus_attrs;
struct device_attribute * dev_attrs; struct device_attribute * dev_attrs;
struct driver_attribute * drv_attrs; struct driver_attribute * drv_attrs;
struct bus_attribute drivers_autoprobe_attr;
struct bus_attribute drivers_probe_attr;
int (*match)(struct device * dev, struct device_driver * drv); int (*match)(struct device * dev, struct device_driver * drv);
int (*uevent)(struct device *dev, char **envp, int (*uevent)(struct device *dev, char **envp,
...@@ -61,6 +78,9 @@ struct bus_type { ...@@ -61,6 +78,9 @@ struct bus_type {
int (*suspend_late)(struct device * dev, pm_message_t state); int (*suspend_late)(struct device * dev, pm_message_t state);
int (*resume_early)(struct device * dev); int (*resume_early)(struct device * dev);
int (*resume)(struct device * dev); int (*resume)(struct device * dev);
unsigned int drivers_autoprobe:1;
unsigned int multithread_probe:1;
}; };
extern int __must_check bus_register(struct bus_type * bus); extern int __must_check bus_register(struct bus_type * bus);
...@@ -102,26 +122,10 @@ extern int bus_unregister_notifier(struct bus_type *bus, ...@@ -102,26 +122,10 @@ extern int bus_unregister_notifier(struct bus_type *bus,
#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be #define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be
unbound */ unbound */
/* sysfs interface for exporting bus attributes */
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
#define BUS_ATTR(_name,_mode,_show,_store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
extern int __must_check bus_create_file(struct bus_type *,
struct bus_attribute *);
extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
struct device_driver { struct device_driver {
const char * name; const char * name;
struct bus_type * bus; struct bus_type * bus;
struct completion unloaded;
struct kobject kobj; struct kobject kobj;
struct klist klist_devices; struct klist klist_devices;
struct klist_node knode_bus; struct klist_node knode_bus;
...@@ -135,8 +139,6 @@ struct device_driver { ...@@ -135,8 +139,6 @@ struct device_driver {
void (*shutdown) (struct device * dev); void (*shutdown) (struct device * dev);
int (*suspend) (struct device * dev, pm_message_t state); int (*suspend) (struct device * dev, pm_message_t state);
int (*resume) (struct device * dev); int (*resume) (struct device * dev);
unsigned int multithread_probe:1;
}; };
...@@ -181,10 +183,9 @@ struct class { ...@@ -181,10 +183,9 @@ struct class {
struct list_head children; struct list_head children;
struct list_head devices; struct list_head devices;
struct list_head interfaces; struct list_head interfaces;
struct kset class_dirs;
struct semaphore sem; /* locks both the children and interfaces lists */ struct semaphore sem; /* locks both the children and interfaces lists */
struct kobject *virtual_dir;
struct class_attribute * class_attrs; struct class_attribute * class_attrs;
struct class_device_attribute * class_dev_attrs; struct class_device_attribute * class_dev_attrs;
struct device_attribute * dev_attrs; struct device_attribute * dev_attrs;
...@@ -328,11 +329,23 @@ extern struct class_device *class_device_create(struct class *cls, ...@@ -328,11 +329,23 @@ extern struct class_device *class_device_create(struct class *cls,
__attribute__((format(printf,5,6))); __attribute__((format(printf,5,6)));
extern void class_device_destroy(struct class *cls, dev_t devt); extern void class_device_destroy(struct class *cls, dev_t devt);
/*
* The type of device, "struct device" is embedded in. A class
* or bus can contain devices of different types
* like "partitions" and "disks", "mouse" and "event".
* This identifies the device type and carries type-specific
* information, equivalent to the kobj_type of a kobject.
* If "name" is specified, the uevent will contain it in
* the DEVTYPE variable.
*/
struct device_type { struct device_type {
struct device_attribute *attrs; const char *name;
struct attribute_group **groups;
int (*uevent)(struct device *dev, char **envp, int num_envp, int (*uevent)(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size); char *buffer, int buffer_size);
void (*release)(struct device *dev); void (*release)(struct device *dev);
int (*suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
}; };
/* interface for exporting device attributes */ /* interface for exporting device attributes */
...@@ -354,8 +367,12 @@ extern int __must_check device_create_bin_file(struct device *dev, ...@@ -354,8 +367,12 @@ extern int __must_check device_create_bin_file(struct device *dev,
struct bin_attribute *attr); struct bin_attribute *attr);
extern void device_remove_bin_file(struct device *dev, extern void device_remove_bin_file(struct device *dev,
struct bin_attribute *attr); struct bin_attribute *attr);
extern int device_schedule_callback(struct device *dev, extern int device_schedule_callback_owner(struct device *dev,
void (*func)(struct device *)); void (*func)(struct device *), struct module *owner);
/* This is a macro to avoid include problems with THIS_MODULE */
#define device_schedule_callback(dev, func) \
device_schedule_callback_owner(dev, func, THIS_MODULE)
/* device resource management */ /* device resource management */
typedef void (*dr_release_t)(struct device *dev, void *res); typedef void (*dr_release_t)(struct device *dev, void *res);
...@@ -554,7 +571,11 @@ extern const char *dev_driver_string(struct device *dev); ...@@ -554,7 +571,11 @@ extern const char *dev_driver_string(struct device *dev);
#define dev_dbg(dev, format, arg...) \ #define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg) dev_printk(KERN_DEBUG , dev , format , ## arg)
#else #else
#define dev_dbg(dev, format, arg...) do { (void)(dev); } while (0) static inline int __attribute__ ((format (printf, 2, 3)))
dev_dbg(struct device * dev, const char * fmt, ...)
{
return 0;
}
#endif #endif
#define dev_err(dev, format, arg...) \ #define dev_err(dev, format, arg...) \
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/wait.h> #include <linux/wait.h>
...@@ -43,11 +42,9 @@ enum kobject_action { ...@@ -43,11 +42,9 @@ enum kobject_action {
KOBJ_ADD = (__force kobject_action_t) 0x01, /* exclusive to core */ KOBJ_ADD = (__force kobject_action_t) 0x01, /* exclusive to core */
KOBJ_REMOVE = (__force kobject_action_t) 0x02, /* exclusive to core */ KOBJ_REMOVE = (__force kobject_action_t) 0x02, /* exclusive to core */
KOBJ_CHANGE = (__force kobject_action_t) 0x03, /* device state change */ KOBJ_CHANGE = (__force kobject_action_t) 0x03, /* device state change */
KOBJ_MOUNT = (__force kobject_action_t) 0x04, /* mount event for block devices (broken) */ KOBJ_OFFLINE = (__force kobject_action_t) 0x04, /* device offline */
KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for block devices (broken) */ KOBJ_ONLINE = (__force kobject_action_t) 0x05, /* device online */
KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* device offline */ KOBJ_MOVE = (__force kobject_action_t) 0x06, /* device move */
KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* device online */
KOBJ_MOVE = (__force kobject_action_t) 0x08, /* device move */
}; };
struct kobject { struct kobject {
...@@ -89,6 +86,8 @@ extern void kobject_unregister(struct kobject *); ...@@ -89,6 +86,8 @@ extern void kobject_unregister(struct kobject *);
extern struct kobject * kobject_get(struct kobject *); extern struct kobject * kobject_get(struct kobject *);
extern void kobject_put(struct kobject *); extern void kobject_put(struct kobject *);
extern struct kobject *kobject_kset_add_dir(struct kset *kset,
struct kobject *, const char *);
extern struct kobject *kobject_add_dir(struct kobject *, const char *); extern struct kobject *kobject_add_dir(struct kobject *, const char *);
extern char * kobject_get_path(struct kobject *, gfp_t); extern char * kobject_get_path(struct kobject *, gfp_t);
...@@ -175,7 +174,6 @@ extern struct kobject * kset_find_obj(struct kset *, const char *); ...@@ -175,7 +174,6 @@ extern struct kobject * kset_find_obj(struct kset *, const char *);
struct subsystem { struct subsystem {
struct kset kset; struct kset kset;
struct rw_semaphore rwsem;
}; };
#define decl_subsys(_name,_type,_uevent_ops) \ #define decl_subsys(_name,_type,_uevent_ops) \
......
...@@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); ...@@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
extern void release_open_intent(struct nameidata *); extern void release_open_intent(struct nameidata *);
extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int);
extern int follow_down(struct vfsmount **, struct dentry **); extern int follow_down(struct vfsmount **, struct dentry **);
extern int follow_up(struct vfsmount **, struct dentry **); extern int follow_up(struct vfsmount **, struct dentry **);
......
...@@ -361,8 +361,6 @@ struct pci_driver { ...@@ -361,8 +361,6 @@ struct pci_driver {
struct pci_error_handlers *err_handler; struct pci_error_handlers *err_handler;
struct device_driver driver; struct device_driver driver;
struct pci_dynids dynids; struct pci_dynids dynids;
int multithread_probe;
}; };
#define to_pci_driver(drv) container_of(drv,struct pci_driver, driver) #define to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
......
...@@ -166,6 +166,24 @@ extern struct pm_ops *pm_ops; ...@@ -166,6 +166,24 @@ extern struct pm_ops *pm_ops;
extern int pm_suspend(suspend_state_t state); extern int pm_suspend(suspend_state_t state);
/**
* arch_suspend_disable_irqs - disable IRQs for suspend
*
* Disables IRQs (in the default case). This is a weak symbol in the common
* code and thus allows architectures to override it if more needs to be
* done. Not called for suspend to disk.
*/
extern void arch_suspend_disable_irqs(void);
/**
* arch_suspend_enable_irqs - enable IRQs after suspend
*
* Enables IRQs (in the default case). This is a weak symbol in the common
* code and thus allows architectures to override it if more needs to be
* done. Not called for suspend to disk.
*/
extern void arch_suspend_enable_irqs(void);
/* /*
* Device power management * Device power management
*/ */
...@@ -273,6 +291,20 @@ extern void __suspend_report_result(const char *function, void *fn, int ret); ...@@ -273,6 +291,20 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
__suspend_report_result(__FUNCTION__, fn, ret); \ __suspend_report_result(__FUNCTION__, fn, ret); \
} while (0) } while (0)
/*
* Platform hook to activate device wakeup capability, if that's not already
* handled by enable_irq_wake() etc.
* Returns zero on success, else negative errno
*/
extern int (*platform_enable_wakeup)(struct device *dev, int is_on);
static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
{
if (platform_enable_wakeup)
return (*platform_enable_wakeup)(dev, is_on);
return 0;
}
#else /* !CONFIG_PM */ #else /* !CONFIG_PM */
static inline int device_suspend(pm_message_t state) static inline int device_suspend(pm_message_t state)
...@@ -294,6 +326,11 @@ static inline void dpm_runtime_resume(struct device * dev) ...@@ -294,6 +326,11 @@ static inline void dpm_runtime_resume(struct device * dev)
#define suspend_report_result(fn, ret) do { } while (0) #define suspend_report_result(fn, ret) do { } while (0)
static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
{
return -EIO;
}
#endif #endif
/* changes to device_may_wakeup take effect on the next pm state change. /* changes to device_may_wakeup take effect on the next pm state change.
......
...@@ -80,7 +80,7 @@ struct sysfs_ops { ...@@ -80,7 +80,7 @@ struct sysfs_ops {
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
extern int sysfs_schedule_callback(struct kobject *kobj, extern int sysfs_schedule_callback(struct kobject *kobj,
void (*func)(void *), void *data); void (*func)(void *), void *data, struct module *owner);
extern int __must_check extern int __must_check
sysfs_create_dir(struct kobject *, struct dentry *); sysfs_create_dir(struct kobject *, struct dentry *);
...@@ -137,7 +137,7 @@ extern int __must_check sysfs_init(void); ...@@ -137,7 +137,7 @@ extern int __must_check sysfs_init(void);
#else /* CONFIG_SYSFS */ #else /* CONFIG_SYSFS */
static inline int sysfs_schedule_callback(struct kobject *kobj, static inline int sysfs_schedule_callback(struct kobject *kobj,
void (*func)(void *), void *data) void (*func)(void *), void *data, struct module *owner)
{ {
return -ENOSYS; return -ENOSYS;
} }
......
...@@ -1148,8 +1148,10 @@ int mod_sysfs_setup(struct module *mod, ...@@ -1148,8 +1148,10 @@ int mod_sysfs_setup(struct module *mod,
goto out; goto out;
mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
if (!mod->holders_dir) if (!mod->holders_dir) {
err = -ENOMEM;
goto out_unreg; goto out_unreg;
}
err = module_param_sysfs_setup(mod, kparam, num_params); err = module_param_sysfs_setup(mod, kparam, num_params);
if (err) if (err)
......
...@@ -111,13 +111,24 @@ static int suspend_prepare(suspend_state_t state) ...@@ -111,13 +111,24 @@ static int suspend_prepare(suspend_state_t state)
return error; return error;
} }
/* default implementation */
void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
{
local_irq_disable();
}
/* default implementation */
void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
{
local_irq_enable();
}
int suspend_enter(suspend_state_t state) int suspend_enter(suspend_state_t state)
{ {
int error = 0; int error = 0;
unsigned long flags;
local_irq_save(flags); arch_suspend_disable_irqs();
BUG_ON(!irqs_disabled());
if ((error = device_power_down(PMSG_SUSPEND))) { if ((error = device_power_down(PMSG_SUSPEND))) {
printk(KERN_ERR "Some devices failed to power down\n"); printk(KERN_ERR "Some devices failed to power down\n");
...@@ -126,7 +137,8 @@ int suspend_enter(suspend_state_t state) ...@@ -126,7 +137,8 @@ int suspend_enter(suspend_state_t state)
error = pm_ops->enter(state); error = pm_ops->enter(state);
device_power_up(); device_power_up();
Done: Done:
local_irq_restore(flags); arch_suspend_enable_irqs();
BUG_ON(irqs_disabled());
return error; return error;
} }
......
...@@ -157,7 +157,7 @@ static void unlink(struct kobject * kobj) ...@@ -157,7 +157,7 @@ static void unlink(struct kobject * kobj)
} }
/** /**
* kobject_add - add an object to the hierarchy. * kobject_shadow_add - add an object to the hierarchy.
* @kobj: object. * @kobj: object.
* @shadow_parent: sysfs directory to add to. * @shadow_parent: sysfs directory to add to.
*/ */
...@@ -174,6 +174,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) ...@@ -174,6 +174,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
if (!*kobj->k_name) { if (!*kobj->k_name) {
pr_debug("kobject attempted to be registered with no name!\n"); pr_debug("kobject attempted to be registered with no name!\n");
WARN_ON(1); WARN_ON(1);
kobject_put(kobj);
return -EINVAL; return -EINVAL;
} }
parent = kobject_get(kobj->parent); parent = kobject_get(kobj->parent);
...@@ -190,8 +191,8 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) ...@@ -190,8 +191,8 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
list_add_tail(&kobj->entry,&kobj->kset->list); list_add_tail(&kobj->entry,&kobj->kset->list);
spin_unlock(&kobj->kset->list_lock); spin_unlock(&kobj->kset->list_lock);
kobj->parent = parent;
} }
kobj->parent = parent;
error = create_dir(kobj, shadow_parent); error = create_dir(kobj, shadow_parent);
if (error) { if (error) {
...@@ -311,13 +312,43 @@ EXPORT_SYMBOL(kobject_set_name); ...@@ -311,13 +312,43 @@ EXPORT_SYMBOL(kobject_set_name);
int kobject_rename(struct kobject * kobj, const char *new_name) int kobject_rename(struct kobject * kobj, const char *new_name)
{ {
int error = 0; int error = 0;
const char *devpath = NULL;
char *devpath_string = NULL;
char *envp[2];
kobj = kobject_get(kobj); kobj = kobject_get(kobj);
if (!kobj) if (!kobj)
return -EINVAL; return -EINVAL;
if (!kobj->parent) if (!kobj->parent)
return -EINVAL; return -EINVAL;
devpath = kobject_get_path(kobj, GFP_KERNEL);
if (!devpath) {
error = -ENOMEM;
goto out;
}
devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
if (!devpath_string) {
error = -ENOMEM;
goto out;
}
sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
envp[0] = devpath_string;
envp[1] = NULL;
/* Note : if we want to send the new name alone, not the full path,
* we could probably use kobject_name(kobj); */
error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name); error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
/* This function is mostly/only used for network interface.
* Some hotplug package track interfaces by their name and
* therefore want to know when the name is changed by the user. */
if (!error)
kobject_uevent_env(kobj, KOBJ_MOVE, envp);
out:
kfree(devpath_string);
kfree(devpath);
kobject_put(kobj); kobject_put(kobj);
return error; return error;
...@@ -488,13 +519,15 @@ static struct kobj_type dir_ktype = { ...@@ -488,13 +519,15 @@ static struct kobj_type dir_ktype = {
}; };
/** /**
* kobject_add_dir - add sub directory of object. * kobject_kset_add_dir - add sub directory of object.
* @kset: kset the directory is belongs to.
* @parent: object in which a directory is created. * @parent: object in which a directory is created.
* @name: directory name. * @name: directory name.
* *
* Add a plain directory object as child of given object. * Add a plain directory object as child of given object.
*/ */
struct kobject *kobject_add_dir(struct kobject *parent, const char *name) struct kobject *kobject_kset_add_dir(struct kset *kset,
struct kobject *parent, const char *name)
{ {
struct kobject *k; struct kobject *k;
int ret; int ret;
...@@ -506,13 +539,14 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name) ...@@ -506,13 +539,14 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
if (!k) if (!k)
return NULL; return NULL;
k->kset = kset;
k->parent = parent; k->parent = parent;
k->ktype = &dir_ktype; k->ktype = &dir_ktype;
kobject_set_name(k, name); kobject_set_name(k, name);
ret = kobject_register(k); ret = kobject_register(k);
if (ret < 0) { if (ret < 0) {
printk(KERN_WARNING "kobject_add_dir: " printk(KERN_WARNING "%s: kobject_register error: %d\n",
"kobject_register error: %d\n", ret); __func__, ret);
kobject_del(k); kobject_del(k);
return NULL; return NULL;
} }
...@@ -520,6 +554,18 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name) ...@@ -520,6 +554,18 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
return k; return k;
} }
/**
* kobject_add_dir - add sub directory of object.
* @parent: object in which a directory is created.
* @name: directory name.
*
* Add a plain directory object as child of given object.
*/
struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
{
return kobject_kset_add_dir(NULL, parent, name);
}
/** /**
* kset_init - initialize a kset for use * kset_init - initialize a kset for use
* @k: kset * @k: kset
...@@ -613,7 +659,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) ...@@ -613,7 +659,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
void subsystem_init(struct subsystem * s) void subsystem_init(struct subsystem * s)
{ {
init_rwsem(&s->rwsem);
kset_init(&s->kset); kset_init(&s->kset);
} }
...@@ -622,8 +667,7 @@ void subsystem_init(struct subsystem * s) ...@@ -622,8 +667,7 @@ void subsystem_init(struct subsystem * s)
* @s: the subsystem we're registering. * @s: the subsystem we're registering.
* *
* Once we register the subsystem, we want to make sure that * Once we register the subsystem, we want to make sure that
* the kset points back to this subsystem for correct usage of * the kset points back to this subsystem.
* the rwsem.
*/ */
int subsystem_register(struct subsystem * s) int subsystem_register(struct subsystem * s)
......
...@@ -42,10 +42,6 @@ static char *action_to_string(enum kobject_action action) ...@@ -42,10 +42,6 @@ static char *action_to_string(enum kobject_action action)
return "remove"; return "remove";
case KOBJ_CHANGE: case KOBJ_CHANGE:
return "change"; return "change";
case KOBJ_MOUNT:
return "mount";
case KOBJ_UMOUNT:
return "umount";
case KOBJ_OFFLINE: case KOBJ_OFFLINE:
return "offline"; return "offline";
case KOBJ_ONLINE: case KOBJ_ONLINE:
...@@ -95,10 +91,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, ...@@ -95,10 +91,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
/* search the kset we belong to */ /* search the kset we belong to */
top_kobj = kobj; top_kobj = kobj;
if (!top_kobj->kset && top_kobj->parent) { while (!top_kobj->kset && top_kobj->parent) {
do { top_kobj = top_kobj->parent;
top_kobj = top_kobj->parent;
} while (!top_kobj->kset && top_kobj->parent);
} }
if (!top_kobj->kset) { if (!top_kobj->kset) {
pr_debug("kobject attempted to send uevent without kset!\n"); pr_debug("kobject attempted to send uevent without kset!\n");
...@@ -115,6 +109,16 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, ...@@ -115,6 +109,16 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
return 0; return 0;
} }
/* originating subsystem */
if (uevent_ops && uevent_ops->name)
subsystem = uevent_ops->name(kset, kobj);
else
subsystem = kobject_name(&kset->kobj);
if (!subsystem) {
pr_debug("unset subsytem caused the event to drop!\n");
return 0;
}
/* environment index */ /* environment index */
envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
if (!envp) if (!envp)
...@@ -134,12 +138,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, ...@@ -134,12 +138,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
goto exit; goto exit;
} }
/* originating subsystem */
if (uevent_ops && uevent_ops->name)
subsystem = uevent_ops->name(kset, kobj);
else
subsystem = kobject_name(&kset->kobj);
/* event environemnt for helper process only */ /* event environemnt for helper process only */
envp[i++] = "HOME=/"; envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
void kref_init(struct kref *kref) void kref_init(struct kref *kref)
{ {
atomic_set(&kref->refcount,1); atomic_set(&kref->refcount,1);
smp_mb();
} }
/** /**
...@@ -31,6 +32,7 @@ void kref_get(struct kref *kref) ...@@ -31,6 +32,7 @@ void kref_get(struct kref *kref)
{ {
WARN_ON(!atomic_read(&kref->refcount)); WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount); atomic_inc(&kref->refcount);
smp_mb__after_atomic_inc();
} }
/** /**
......
...@@ -412,20 +412,25 @@ static int netdev_uevent(struct device *d, char **envp, ...@@ -412,20 +412,25 @@ static int netdev_uevent(struct device *d, char **envp,
int num_envp, char *buf, int size) int num_envp, char *buf, int size)
{ {
struct net_device *dev = to_net_dev(d); struct net_device *dev = to_net_dev(d);
int i = 0; int retval, len = 0, i = 0;
int n;
/* pass interface to uevent. */ /* pass interface to uevent. */
envp[i++] = buf; retval = add_uevent_var(envp, num_envp, &i,
n = snprintf(buf, size, "INTERFACE=%s", dev->name) + 1; buf, size, &len,
buf += n; "INTERFACE=%s", dev->name);
size -= n; if (retval)
goto exit;
if ((size <= 0) || (i >= num_envp))
return -ENOMEM; /* pass ifindex to uevent.
* ifindex is useful as it won't change (interface name may change)
* and is what RtNetlink uses natively. */
retval = add_uevent_var(envp, num_envp, &i,
buf, size, &len,
"IFINDEX=%d", dev->ifindex);
exit:
envp[i] = NULL; envp[i] = NULL;
return 0; return retval;
} }
#endif #endif
......
...@@ -61,9 +61,9 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, ...@@ -61,9 +61,9 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
{ {
struct soundbus_dev * soundbus_dev; struct soundbus_dev * soundbus_dev;
struct of_device * of; struct of_device * of;
char *scratch, *compat, *compat2; char *compat;
int i = 0; int retval = 0, i = 0, length = 0;
int length, cplen, cplen2, seen = 0; int cplen, seen = 0;
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
...@@ -75,63 +75,47 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, ...@@ -75,63 +75,47 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
of = &soundbus_dev->ofdev; of = &soundbus_dev->ofdev;
/* stuff we want to pass to /sbin/hotplug */ /* stuff we want to pass to /sbin/hotplug */
envp[i++] = scratch = buffer; retval = add_uevent_var(envp, num_envp, &i,
length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name); buffer, buffer_size, &length,
++length; "OF_NAME=%s", of->node->name);
buffer_size -= length; if (retval)
if ((buffer_size <= 0) || (i >= num_envp)) return retval;
return -ENOMEM;
scratch += length; retval = add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
envp[i++] = scratch; "OF_TYPE=%s", of->node->type);
length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type); if (retval)
++length; return retval;
buffer_size -= length;
if ((buffer_size <= 0) || (i >= num_envp))
return -ENOMEM;
scratch += length;
/* Since the compatible field can contain pretty much anything /* Since the compatible field can contain pretty much anything
* it's not really legal to split it out with commas. We split it * it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */ * up using a number of environment variables instead. */
compat = (char *) get_property(of->node, "compatible", &cplen); compat = (char *) get_property(of->node, "compatible", &cplen);
compat2 = compat;
cplen2= cplen;
while (compat && cplen > 0) { while (compat && cplen > 0) {
envp[i++] = scratch; int tmp = length;
length = scnprintf (scratch, buffer_size, retval = add_uevent_var(envp, num_envp, &i,
"OF_COMPATIBLE_%d=%s", seen, compat); buffer, buffer_size, &length,
++length; "OF_COMPATIBLE_%d=%s", seen, compat);
buffer_size -= length; if (retval)
if ((buffer_size <= 0) || (i >= num_envp)) return retval;
return -ENOMEM; compat += length - tmp;
scratch += length; cplen -= length - tmp;
length = strlen (compat) + 1; seen += 1;
compat += length;
cplen -= length;
seen++;
} }
envp[i++] = scratch; retval = add_uevent_var(envp, num_envp, &i,
length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen); buffer, buffer_size, &length,
++length; "OF_COMPATIBLE_N=%d", seen);
buffer_size -= length; if (retval)
if ((buffer_size <= 0) || (i >= num_envp)) return retval;
return -ENOMEM; retval = add_uevent_var(envp, num_envp, &i,
scratch += length; buffer, buffer_size, &length,
"MODALIAS=%s", soundbus_dev->modalias);
envp[i++] = scratch;
length = scnprintf (scratch, buffer_size, "MODALIAS=%s",
soundbus_dev->modalias);
buffer_size -= length;
if ((buffer_size <= 0) || (i >= num_envp))
return -ENOMEM;
envp[i] = NULL; envp[i] = NULL;
return 0; return retval;
} }
static int soundbus_device_remove(struct device *dev) static int soundbus_device_remove(struct device *dev)
......
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