You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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 ...
This commit is contained in:
@@ -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
|
||||
When: February 2008
|
||||
Files: include/linux/usb.h, drivers/usb/core/driver.c
|
||||
|
||||
@@ -475,9 +475,6 @@ static struct of_platform_driver of_pci_phb_driver = {
|
||||
.name = "of-pci",
|
||||
.match_table = of_pci_phb_ids,
|
||||
.probe = of_pci_phb_probe,
|
||||
.driver = {
|
||||
.multithread_probe = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static __init int of_pci_phb_init(void)
|
||||
|
||||
+6
-7
@@ -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)
|
||||
{
|
||||
struct amba_device *pcdev = to_amba_device(dev);
|
||||
int retval = 0, i = 0, len = 0;
|
||||
|
||||
if (nr_env < 2)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid);
|
||||
*envp++ = buf;
|
||||
*envp++ = NULL;
|
||||
return 0;
|
||||
retval = add_uevent_var(envp, nr_env, &i,
|
||||
buf, bufsz, &len,
|
||||
"AMBA_ID=%08x", pcdev->periphid);
|
||||
envp[i] = NULL;
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
#define amba_uevent NULL
|
||||
|
||||
@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
|
||||
|
||||
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
|
||||
@@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont)
|
||||
klist_init(&cont->containers,internal_container_klist_get,
|
||||
internal_container_klist_put);
|
||||
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
list_add_tail(&cont->node, &attribute_container_list);
|
||||
up(&attribute_container_mutex);
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ int
|
||||
attribute_container_unregister(struct attribute_container *cont)
|
||||
{
|
||||
int retval = -EBUSY;
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
spin_lock(&cont->containers.k_lock);
|
||||
if (!list_empty(&cont->containers.k_list))
|
||||
goto out;
|
||||
@@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont)
|
||||
list_del(&cont->node);
|
||||
out:
|
||||
spin_unlock(&cont->containers.k_lock);
|
||||
up(&attribute_container_mutex);
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
return retval;
|
||||
|
||||
}
|
||||
@@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev,
|
||||
{
|
||||
struct attribute_container *cont;
|
||||
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
struct internal_container *ic;
|
||||
|
||||
@@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev,
|
||||
attribute_container_add_class_device(&ic->classdev);
|
||||
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
|
||||
@@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev,
|
||||
{
|
||||
struct attribute_container *cont;
|
||||
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
struct internal_container *ic;
|
||||
struct klist_iter iter;
|
||||
@@ -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,
|
||||
{
|
||||
struct attribute_container *cont;
|
||||
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
struct internal_container *ic;
|
||||
struct klist_iter iter;
|
||||
@@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev,
|
||||
fn(cont, dev, &ic->classdev);
|
||||
}
|
||||
}
|
||||
up(&attribute_container_mutex);
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev,
|
||||
{
|
||||
struct attribute_container *cont;
|
||||
|
||||
down(&attribute_container_mutex);
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
if (cont->match(cont, dev))
|
||||
fn(cont, dev);
|
||||
}
|
||||
up(&attribute_container_mutex);
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ extern int cpu_dev_init(void);
|
||||
extern int attribute_container_init(void);
|
||||
|
||||
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 struct bus_type *get_bus(struct bus_type * bus);
|
||||
extern void put_bus(struct bus_type * bus);
|
||||
|
||||
+96
-16
@@ -27,6 +27,9 @@
|
||||
#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
|
||||
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
|
||||
{
|
||||
@@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = {
|
||||
|
||||
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 = {
|
||||
@@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL);
|
||||
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
|
||||
/* Manually detach a device from its associated driver. */
|
||||
static int driver_helper(struct device *dev, void *data)
|
||||
{
|
||||
@@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device_driver *drv,
|
||||
}
|
||||
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
|
||||
|
||||
static struct device * next_device(struct klist_iter * i)
|
||||
@@ -418,21 +458,21 @@ out_put:
|
||||
* - Add device to bus's list of devices.
|
||||
* - 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;
|
||||
int ret = 0;
|
||||
|
||||
if (bus) {
|
||||
dev->is_registered = 1;
|
||||
ret = device_attach(dev);
|
||||
if (ret >= 0) {
|
||||
if (bus->drivers_autoprobe)
|
||||
ret = device_attach(dev);
|
||||
WARN_ON(ret < 0);
|
||||
if (ret >= 0)
|
||||
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
|
||||
ret = 0;
|
||||
} else
|
||||
else
|
||||
dev->is_registered = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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_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
|
||||
static inline int add_bind_files(struct device_driver *drv) { return 0; }
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver *drv)
|
||||
int error = 0;
|
||||
|
||||
if (!bus)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
|
||||
error = kobject_set_name(&drv->kobj, "%s", drv->name);
|
||||
@@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver *drv)
|
||||
if ((error = kobject_register(&drv->kobj)))
|
||||
goto out_put_bus;
|
||||
|
||||
error = driver_attach(drv);
|
||||
if (error)
|
||||
goto out_unregister;
|
||||
if (drv->bus->drivers_autoprobe) {
|
||||
error = driver_attach(drv);
|
||||
if (error)
|
||||
goto out_unregister;
|
||||
}
|
||||
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
|
||||
module_add_driver(drv->owner, drv);
|
||||
|
||||
@@ -605,8 +679,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
|
||||
ret = device_attach(dev);
|
||||
if (dev->parent)
|
||||
up(&dev->parent->sem);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
}
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
@@ -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_drivers, NULL, NULL);
|
||||
|
||||
bus->drivers_autoprobe = 1;
|
||||
retval = add_probe_files(bus);
|
||||
if (retval)
|
||||
goto bus_probe_files_fail;
|
||||
|
||||
retval = bus_add_attrs(bus);
|
||||
if (retval)
|
||||
goto bus_attrs_fail;
|
||||
@@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus)
|
||||
return 0;
|
||||
|
||||
bus_attrs_fail:
|
||||
remove_probe_files(bus);
|
||||
bus_probe_files_fail:
|
||||
kset_unregister(&bus->drivers);
|
||||
bus_drivers_fail:
|
||||
kset_unregister(&bus->devices);
|
||||
@@ -779,7 +859,6 @@ out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bus_unregister - remove a bus from the system
|
||||
* @bus: bus.
|
||||
@@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bus)
|
||||
{
|
||||
pr_debug("bus %s: unregistering\n", bus->name);
|
||||
bus_remove_attrs(bus);
|
||||
remove_probe_files(bus);
|
||||
kset_unregister(&bus->drivers);
|
||||
kset_unregister(&bus->devices);
|
||||
subsystem_unregister(&bus->subsys);
|
||||
|
||||
@@ -145,6 +145,7 @@ int class_register(struct class * cls)
|
||||
INIT_LIST_HEAD(&cls->children);
|
||||
INIT_LIST_HEAD(&cls->devices);
|
||||
INIT_LIST_HEAD(&cls->interfaces);
|
||||
kset_init(&cls->class_dirs);
|
||||
init_MUTEX(&cls->sem);
|
||||
error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
|
||||
if (error)
|
||||
@@ -163,7 +164,6 @@ int class_register(struct class * cls)
|
||||
void class_unregister(struct class * cls)
|
||||
{
|
||||
pr_debug("device class '%s': unregistering\n", cls->name);
|
||||
kobject_unregister(cls->virtual_dir);
|
||||
remove_class_attrs(cls);
|
||||
subsystem_unregister(&cls->subsys);
|
||||
}
|
||||
|
||||
+209
-88
@@ -43,7 +43,8 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
|
||||
const char *dev_driver_string(struct device *dev)
|
||||
{
|
||||
return dev->driver ? dev->driver->name :
|
||||
(dev->bus ? dev->bus->name : "");
|
||||
(dev->bus ? dev->bus->name :
|
||||
(dev->class ? dev->class->name : ""));
|
||||
}
|
||||
EXPORT_SYMBOL(dev_driver_string);
|
||||
|
||||
@@ -119,6 +120,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
|
||||
|
||||
if (ktype == &ktype_device) {
|
||||
struct device *dev = to_dev(kobj);
|
||||
if (dev->uevent_suppress)
|
||||
return 0;
|
||||
if (dev->bus)
|
||||
return 1;
|
||||
if (dev->class)
|
||||
@@ -156,6 +159,11 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
|
||||
"MINOR=%u", MINOR(dev->devt));
|
||||
}
|
||||
|
||||
if (dev->type && dev->type->name)
|
||||
add_uevent_var(envp, num_envp, &i,
|
||||
buffer, buffer_size, &length,
|
||||
"DEVTYPE=%s", dev->type->name);
|
||||
|
||||
if (dev->driver)
|
||||
add_uevent_var(envp, num_envp, &i,
|
||||
buffer, buffer_size, &length,
|
||||
@@ -238,71 +246,152 @@ static struct kset_uevent_ops device_uevent_ops = {
|
||||
.uevent = dev_uevent,
|
||||
};
|
||||
|
||||
static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct kobject *top_kobj;
|
||||
struct kset *kset;
|
||||
char *envp[32];
|
||||
char data[PAGE_SIZE];
|
||||
char *pos;
|
||||
int i;
|
||||
size_t count = 0;
|
||||
int retval;
|
||||
|
||||
/* search the kset, the device belongs to */
|
||||
top_kobj = &dev->kobj;
|
||||
if (!top_kobj->kset && top_kobj->parent) {
|
||||
do {
|
||||
top_kobj = top_kobj->parent;
|
||||
} while (!top_kobj->kset && top_kobj->parent);
|
||||
}
|
||||
if (!top_kobj->kset)
|
||||
goto out;
|
||||
kset = top_kobj->kset;
|
||||
if (!kset->uevent_ops || !kset->uevent_ops->uevent)
|
||||
goto out;
|
||||
|
||||
/* respect filter */
|
||||
if (kset->uevent_ops && kset->uevent_ops->filter)
|
||||
if (!kset->uevent_ops->filter(kset, &dev->kobj))
|
||||
goto out;
|
||||
|
||||
/* let the kset specific function add its keys */
|
||||
pos = data;
|
||||
retval = kset->uevent_ops->uevent(kset, &dev->kobj,
|
||||
envp, ARRAY_SIZE(envp),
|
||||
pos, PAGE_SIZE);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
/* copy keys to file */
|
||||
for (i = 0; envp[i]; i++) {
|
||||
pos = &buf[count];
|
||||
count += sprintf(pos, "%s\n", envp[i]);
|
||||
}
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
if (memcmp(buf, "add", 3) != 0)
|
||||
dev_err(dev, "uevent: unsupported action-string; this will "
|
||||
"be ignored in a future kernel version");
|
||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int device_add_groups(struct device *dev)
|
||||
static int device_add_attributes(struct device *dev,
|
||||
struct device_attribute *attrs)
|
||||
{
|
||||
int i;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (dev->groups) {
|
||||
for (i = 0; dev->groups[i]; i++) {
|
||||
error = sysfs_create_group(&dev->kobj, dev->groups[i]);
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
sysfs_remove_group(&dev->kobj, dev->groups[i]);
|
||||
goto out;
|
||||
}
|
||||
if (attrs) {
|
||||
for (i = 0; attr_name(attrs[i]); i++) {
|
||||
error = device_create_file(dev, &attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &attrs[i]);
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_groups(struct device *dev)
|
||||
static void device_remove_attributes(struct device *dev,
|
||||
struct device_attribute *attrs)
|
||||
{
|
||||
int i;
|
||||
if (dev->groups) {
|
||||
for (i = 0; dev->groups[i]; i++) {
|
||||
sysfs_remove_group(&dev->kobj, dev->groups[i]);
|
||||
|
||||
if (attrs)
|
||||
for (i = 0; attr_name(attrs[i]); i++)
|
||||
device_remove_file(dev, &attrs[i]);
|
||||
}
|
||||
|
||||
static int device_add_groups(struct device *dev,
|
||||
struct attribute_group **groups)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
if (groups) {
|
||||
for (i = 0; groups[i]; i++) {
|
||||
error = sysfs_create_group(&dev->kobj, groups[i]);
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
sysfs_remove_group(&dev->kobj, groups[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_groups(struct device *dev,
|
||||
struct attribute_group **groups)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (groups)
|
||||
for (i = 0; groups[i]; i++)
|
||||
sysfs_remove_group(&dev->kobj, groups[i]);
|
||||
}
|
||||
|
||||
static int device_add_attrs(struct device *dev)
|
||||
{
|
||||
struct class *class = dev->class;
|
||||
struct device_type *type = dev->type;
|
||||
int error = 0;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
if (class && class->dev_attrs) {
|
||||
for (i = 0; attr_name(class->dev_attrs[i]); i++) {
|
||||
error = device_create_file(dev, &class->dev_attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (class) {
|
||||
error = device_add_attributes(dev, class->dev_attrs);
|
||||
if (error)
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &class->dev_attrs[i]);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (type && type->attrs) {
|
||||
for (i = 0; attr_name(type->attrs[i]); i++) {
|
||||
error = device_create_file(dev, &type->attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (type) {
|
||||
error = device_add_groups(dev, type->groups);
|
||||
if (error)
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &type->attrs[i]);
|
||||
goto err_remove_class_attrs;
|
||||
}
|
||||
|
||||
error = device_add_groups(dev, dev->groups);
|
||||
if (error)
|
||||
goto err_remove_type_groups;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_type_groups:
|
||||
if (type)
|
||||
device_remove_groups(dev, type->groups);
|
||||
err_remove_class_attrs:
|
||||
if (class)
|
||||
device_remove_attributes(dev, class->dev_attrs);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -310,17 +399,14 @@ static void device_remove_attrs(struct device *dev)
|
||||
{
|
||||
struct class *class = dev->class;
|
||||
struct device_type *type = dev->type;
|
||||
int i;
|
||||
|
||||
if (class && class->dev_attrs) {
|
||||
for (i = 0; attr_name(class->dev_attrs[i]); i++)
|
||||
device_remove_file(dev, &class->dev_attrs[i]);
|
||||
}
|
||||
device_remove_groups(dev, dev->groups);
|
||||
|
||||
if (type && type->attrs) {
|
||||
for (i = 0; attr_name(type->attrs[i]); i++)
|
||||
device_remove_file(dev, &type->attrs[i]);
|
||||
}
|
||||
if (type)
|
||||
device_remove_groups(dev, type->groups);
|
||||
|
||||
if (class)
|
||||
device_remove_attributes(dev, class->dev_attrs);
|
||||
}
|
||||
|
||||
|
||||
@@ -394,9 +480,10 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
|
||||
EXPORT_SYMBOL_GPL(device_remove_bin_file);
|
||||
|
||||
/**
|
||||
* device_schedule_callback - helper to schedule a callback for a device
|
||||
* device_schedule_callback_owner - helper to schedule a callback for a device
|
||||
* @dev: device.
|
||||
* @func: callback function to invoke later.
|
||||
* @owner: module owning the callback routine
|
||||
*
|
||||
* Attribute methods must not unregister themselves or their parent device
|
||||
* (which would amount to the same thing). Attempts to do so will deadlock,
|
||||
@@ -407,20 +494,23 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file);
|
||||
* argument in the workqueue's process context. @dev will be pinned until
|
||||
* @func returns.
|
||||
*
|
||||
* This routine is usually called via the inline device_schedule_callback(),
|
||||
* which automatically sets @owner to THIS_MODULE.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
|
||||
* underlying sysfs routine (since it is intended for use by attribute
|
||||
* methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
|
||||
*/
|
||||
int device_schedule_callback(struct device *dev,
|
||||
void (*func)(struct device *))
|
||||
int device_schedule_callback_owner(struct device *dev,
|
||||
void (*func)(struct device *), struct module *owner)
|
||||
{
|
||||
return sysfs_schedule_callback(&dev->kobj,
|
||||
(void (*)(void *)) func, dev);
|
||||
(void (*)(void *)) func, dev, owner);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_schedule_callback);
|
||||
EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
|
||||
|
||||
static void klist_children_get(struct klist_node *n)
|
||||
{
|
||||
@@ -477,34 +567,58 @@ static struct kobject * get_device_parent(struct device *dev,
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static struct kobject * virtual_device_parent(struct device *dev)
|
||||
static struct kobject *virtual_device_parent(struct device *dev)
|
||||
{
|
||||
if (!dev->class)
|
||||
return ERR_PTR(-ENODEV);
|
||||
static struct kobject *virtual_dir = NULL;
|
||||
|
||||
if (!dev->class->virtual_dir) {
|
||||
static struct kobject *virtual_dir = NULL;
|
||||
if (!virtual_dir)
|
||||
virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
|
||||
|
||||
if (!virtual_dir)
|
||||
virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
|
||||
dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
|
||||
}
|
||||
|
||||
return dev->class->virtual_dir;
|
||||
return virtual_dir;
|
||||
}
|
||||
|
||||
static struct kobject * get_device_parent(struct device *dev,
|
||||
struct device *parent)
|
||||
{
|
||||
/* if this is a class device, and has no parent, create one */
|
||||
if ((dev->class) && (parent == NULL)) {
|
||||
return virtual_device_parent(dev);
|
||||
} else if (parent)
|
||||
if (dev->class) {
|
||||
struct kobject *kobj = NULL;
|
||||
struct kobject *parent_kobj;
|
||||
struct kobject *k;
|
||||
|
||||
/*
|
||||
* If we have no parent, we live in "virtual".
|
||||
* Class-devices with a bus-device as parent, live
|
||||
* in a class-directory to prevent namespace collisions.
|
||||
*/
|
||||
if (parent == NULL)
|
||||
parent_kobj = virtual_device_parent(dev);
|
||||
else if (parent->class)
|
||||
return &parent->kobj;
|
||||
else
|
||||
parent_kobj = &parent->kobj;
|
||||
|
||||
/* find our class-directory at the parent and reference it */
|
||||
spin_lock(&dev->class->class_dirs.list_lock);
|
||||
list_for_each_entry(k, &dev->class->class_dirs.list, entry)
|
||||
if (k->parent == parent_kobj) {
|
||||
kobj = kobject_get(k);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&dev->class->class_dirs.list_lock);
|
||||
if (kobj)
|
||||
return kobj;
|
||||
|
||||
/* or create a new class-directory at the parent device */
|
||||
return kobject_kset_add_dir(&dev->class->class_dirs,
|
||||
parent_kobj, dev->class->name);
|
||||
}
|
||||
|
||||
if (parent)
|
||||
return &parent->kobj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int setup_parent(struct device *dev, struct device *parent)
|
||||
{
|
||||
struct kobject *kobj;
|
||||
@@ -541,7 +655,6 @@ int device_add(struct device *dev)
|
||||
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
|
||||
|
||||
parent = get_device(dev->parent);
|
||||
|
||||
error = setup_parent(dev, parent);
|
||||
if (error)
|
||||
goto Error;
|
||||
@@ -562,10 +675,11 @@ int device_add(struct device *dev)
|
||||
BUS_NOTIFY_ADD_DEVICE, dev);
|
||||
|
||||
dev->uevent_attr.attr.name = "uevent";
|
||||
dev->uevent_attr.attr.mode = S_IWUSR;
|
||||
dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR;
|
||||
if (dev->driver)
|
||||
dev->uevent_attr.attr.owner = dev->driver->owner;
|
||||
dev->uevent_attr.store = store_uevent;
|
||||
dev->uevent_attr.show = show_uevent;
|
||||
error = device_create_file(dev, &dev->uevent_attr);
|
||||
if (error)
|
||||
goto attrError;
|
||||
@@ -614,16 +728,12 @@ int device_add(struct device *dev)
|
||||
|
||||
if ((error = device_add_attrs(dev)))
|
||||
goto AttrsError;
|
||||
if ((error = device_add_groups(dev)))
|
||||
goto GroupError;
|
||||
if ((error = device_pm_add(dev)))
|
||||
goto PMError;
|
||||
if ((error = bus_add_device(dev)))
|
||||
goto BusError;
|
||||
if (!dev->uevent_suppress)
|
||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||
if ((error = bus_attach_device(dev)))
|
||||
goto AttachError;
|
||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||
bus_attach_device(dev);
|
||||
if (parent)
|
||||
klist_add_tail(&dev->knode_parent, &parent->klist_children);
|
||||
|
||||
@@ -639,19 +749,15 @@ int device_add(struct device *dev)
|
||||
up(&dev->class->sem);
|
||||
}
|
||||
Done:
|
||||
kfree(class_name);
|
||||
kfree(class_name);
|
||||
put_device(dev);
|
||||
return error;
|
||||
AttachError:
|
||||
bus_remove_device(dev);
|
||||
BusError:
|
||||
device_pm_remove(dev);
|
||||
PMError:
|
||||
if (dev->bus)
|
||||
blocking_notifier_call_chain(&dev->bus->bus_notifier,
|
||||
BUS_NOTIFY_DEL_DEVICE, dev);
|
||||
device_remove_groups(dev);
|
||||
GroupError:
|
||||
device_remove_attrs(dev);
|
||||
AttrsError:
|
||||
if (dev->devt_attr) {
|
||||
@@ -677,15 +783,6 @@ int device_add(struct device *dev)
|
||||
#endif
|
||||
sysfs_remove_link(&dev->kobj, "device");
|
||||
}
|
||||
|
||||
down(&dev->class->sem);
|
||||
/* notify any interfaces that the device is now gone */
|
||||
list_for_each_entry(class_intf, &dev->class->interfaces, node)
|
||||
if (class_intf->remove_dev)
|
||||
class_intf->remove_dev(dev, class_intf);
|
||||
/* remove the device from the class list */
|
||||
list_del_init(&dev->node);
|
||||
up(&dev->class->sem);
|
||||
}
|
||||
ueventattrError:
|
||||
device_remove_file(dev, &dev->uevent_attr);
|
||||
@@ -796,9 +893,33 @@ void device_del(struct device * dev)
|
||||
/* remove the device from the class list */
|
||||
list_del_init(&dev->node);
|
||||
up(&dev->class->sem);
|
||||
|
||||
/* If we live in a parent class-directory, unreference it */
|
||||
if (dev->kobj.parent->kset == &dev->class->class_dirs) {
|
||||
struct device *d;
|
||||
int other = 0;
|
||||
|
||||
/*
|
||||
* if we are the last child of our class, delete
|
||||
* our class-directory at this parent
|
||||
*/
|
||||
down(&dev->class->sem);
|
||||
list_for_each_entry(d, &dev->class->devices, node) {
|
||||
if (d == dev)
|
||||
continue;
|
||||
if (d->kobj.parent == dev->kobj.parent) {
|
||||
other = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!other)
|
||||
kobject_del(dev->kobj.parent);
|
||||
|
||||
kobject_put(dev->kobj.parent);
|
||||
up(&dev->class->sem);
|
||||
}
|
||||
}
|
||||
device_remove_file(dev, &dev->uevent_attr);
|
||||
device_remove_groups(dev);
|
||||
device_remove_attrs(dev);
|
||||
bus_remove_device(dev);
|
||||
|
||||
|
||||
+35
-31
@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct stupid_thread_structure {
|
||||
struct device_driver *drv;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static atomic_t probe_count = ATOMIC_INIT(0);
|
||||
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;
|
||||
|
||||
atomic_inc(&probe_count);
|
||||
@@ -154,7 +146,6 @@ probe_failed:
|
||||
*/
|
||||
ret = 0;
|
||||
done:
|
||||
kfree(data);
|
||||
atomic_dec(&probe_count);
|
||||
wake_up(&probe_waitqueue);
|
||||
return ret;
|
||||
@@ -186,16 +177,14 @@ int driver_probe_done(void)
|
||||
* format of the ID structures, nor what is to be considered a match and
|
||||
* what is not.
|
||||
*
|
||||
* This function returns 1 if a match is found, an error if one occurs
|
||||
* (that is not -ENODEV or -ENXIO), and 0 otherwise.
|
||||
* This function returns 1 if a match is found, -ENODEV if the device is
|
||||
* not registered, and 0 otherwise.
|
||||
*
|
||||
* This function must be called with @dev->sem held. When called for a
|
||||
* USB interface, @dev->parent->sem must be held as well.
|
||||
*/
|
||||
int driver_probe_device(struct device_driver * drv, struct device * dev)
|
||||
{
|
||||
struct stupid_thread_structure *data;
|
||||
struct task_struct *probe_task;
|
||||
int ret = 0;
|
||||
|
||||
if (!device_is_registered(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",
|
||||
drv->bus->name, dev->bus_id, drv->name);
|
||||
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
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);
|
||||
ret = really_probe(dev, drv);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
@@ -230,30 +207,57 @@ static int __device_attach(struct device_driver * drv, void * data)
|
||||
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.
|
||||
* @dev: device.
|
||||
*
|
||||
* Walk the list of drivers that the bus has and call
|
||||
* 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;
|
||||
* 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.
|
||||
*/
|
||||
int device_attach(struct device * dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct task_struct *probe_task = ERR_PTR(-ENOMEM);
|
||||
|
||||
down(&dev->sem);
|
||||
if (dev->driver) {
|
||||
ret = device_bind_driver(dev);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
} else
|
||||
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
|
||||
else {
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */
|
||||
|
||||
#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
|
||||
|
||||
static DECLARE_MUTEX (pools_lock);
|
||||
static DEFINE_MUTEX (pools_lock);
|
||||
|
||||
static ssize_t
|
||||
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;
|
||||
next += temp;
|
||||
|
||||
down (&pools_lock);
|
||||
mutex_lock(&pools_lock);
|
||||
list_for_each_entry(pool, &dev->dma_pools, pools) {
|
||||
unsigned pages = 0;
|
||||
unsigned blocks = 0;
|
||||
@@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf)
|
||||
size -= temp;
|
||||
next += temp;
|
||||
}
|
||||
up (&pools_lock);
|
||||
mutex_unlock(&pools_lock);
|
||||
|
||||
return PAGE_SIZE - size;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev,
|
||||
if (dev) {
|
||||
int ret;
|
||||
|
||||
down (&pools_lock);
|
||||
mutex_lock(&pools_lock);
|
||||
if (list_empty (&dev->dma_pools))
|
||||
ret = device_create_file (dev, &dev_attr_pools);
|
||||
else
|
||||
@@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev,
|
||||
kfree(retval);
|
||||
retval = NULL;
|
||||
}
|
||||
up (&pools_lock);
|
||||
mutex_unlock(&pools_lock);
|
||||
} else
|
||||
INIT_LIST_HEAD (&retval->pools);
|
||||
|
||||
@@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page)
|
||||
void
|
||||
dma_pool_destroy (struct dma_pool *pool)
|
||||
{
|
||||
down (&pools_lock);
|
||||
mutex_lock(&pools_lock);
|
||||
list_del (&pool->pools);
|
||||
if (pool->dev && list_empty (&pool->dev->dma_pools))
|
||||
device_remove_file (pool->dev, &dev_attr_pools);
|
||||
up (&pools_lock);
|
||||
mutex_unlock(&pools_lock);
|
||||
|
||||
while (!list_empty (&pool->page_list)) {
|
||||
struct dma_page *page;
|
||||
|
||||
@@ -149,10 +149,6 @@ void put_driver(struct device_driver * drv)
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
klist_init(&drv->klist_devices, NULL, NULL);
|
||||
init_completion(&drv->unloaded);
|
||||
return bus_add_driver(drv);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* driver_unregister - remove driver from system.
|
||||
* @drv: driver.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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 {
|
||||
FW_STATUS_LOADING,
|
||||
FW_STATUS_DONE,
|
||||
FW_STATUS_ABORT,
|
||||
FW_STATUS_READY,
|
||||
FW_STATUS_READY_NOHOTPLUG,
|
||||
};
|
||||
|
||||
static int loading_timeout = 60; /* In seconds */
|
||||
@@ -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);
|
||||
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,
|
||||
"FIRMWARE=%s", fw_priv->fw_id))
|
||||
return -ENOMEM;
|
||||
@@ -333,6 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
|
||||
f_dev->parent = device;
|
||||
f_dev->class = &firmware_class;
|
||||
dev_set_drvdata(f_dev, fw_priv);
|
||||
f_dev->uevent_suppress = 1;
|
||||
retval = device_register(f_dev);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "%s: device_register failed\n",
|
||||
@@ -382,9 +378,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
|
||||
}
|
||||
|
||||
if (uevent)
|
||||
set_bit(FW_STATUS_READY, &fw_priv->status);
|
||||
else
|
||||
set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
|
||||
f_dev->uevent_suppress = 0;
|
||||
*dev_p = f_dev;
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq);
|
||||
DECLARE_MUTEX(dpm_sem);
|
||||
DECLARE_MUTEX(dpm_list_sem);
|
||||
|
||||
int (*platform_enable_wakeup)(struct device *dev, int is_on);
|
||||
|
||||
|
||||
/**
|
||||
* device_pm_set_parent - Specify power dependency.
|
||||
* @dev: Device who needs power.
|
||||
|
||||
@@ -26,7 +26,9 @@ int resume_device(struct device * dev)
|
||||
|
||||
TRACE_DEVICE(dev);
|
||||
TRACE_RESUME(0);
|
||||
|
||||
down(&dev->sem);
|
||||
|
||||
if (dev->power.pm_parent
|
||||
&& dev->power.pm_parent->power.power_state.event) {
|
||||
dev_err(dev, "PM: resume from %d, parent %s still %d\n",
|
||||
@@ -34,15 +36,24 @@ int resume_device(struct device * dev)
|
||||
dev->power.pm_parent->bus_id,
|
||||
dev->power.pm_parent->power.power_state.event);
|
||||
}
|
||||
|
||||
if (dev->bus && dev->bus->resume) {
|
||||
dev_dbg(dev,"resuming\n");
|
||||
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");
|
||||
error = dev->class->resume(dev);
|
||||
}
|
||||
|
||||
up(&dev->sem);
|
||||
|
||||
TRACE_RESUME(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ void device_shutdown(void)
|
||||
{
|
||||
struct device * dev, *devn;
|
||||
|
||||
down_write(&devices_subsys.rwsem);
|
||||
list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
|
||||
kobj.entry) {
|
||||
if (dev->bus && dev->bus->shutdown) {
|
||||
@@ -47,7 +46,6 @@ void device_shutdown(void)
|
||||
dev->driver->shutdown(dev);
|
||||
}
|
||||
}
|
||||
up_write(&devices_subsys.rwsem);
|
||||
|
||||
sysdev_shutdown();
|
||||
}
|
||||
|
||||
@@ -78,6 +78,18 @@ int suspend_device(struct device * dev, pm_message_t state)
|
||||
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) {
|
||||
dev_dbg(dev, "%s%s\n",
|
||||
suspend_verb(state.event),
|
||||
|
||||
@@ -310,14 +310,12 @@ static int proc_ide_read_driver
|
||||
ide_driver_t *ide_drv;
|
||||
int len;
|
||||
|
||||
down_read(&dev->bus->subsys.rwsem);
|
||||
if (dev->driver) {
|
||||
ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
|
||||
len = sprintf(page, "%s version %s\n",
|
||||
dev->driver->name, ide_drv->version);
|
||||
} else
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -327,7 +325,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
|
||||
int ret = 1;
|
||||
int err;
|
||||
|
||||
down_write(&dev->bus->subsys.rwsem);
|
||||
device_release_driver(dev);
|
||||
/* FIXME: device can still be in use by previous driver */
|
||||
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)
|
||||
}
|
||||
if (dev->driver && !strcmp(dev->driver->name, driver))
|
||||
ret = 0;
|
||||
up_write(&dev->bus->subsys.rwsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -370,9 +370,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute
|
||||
|
||||
if (state == 1) {
|
||||
ud->ignore_driver = 1;
|
||||
down_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
device_release_driver(dev);
|
||||
up_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
} else if (state == 0)
|
||||
ud->ignore_driver = 0;
|
||||
|
||||
@@ -1163,6 +1161,7 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
|
||||
struct unit_directory *ud;
|
||||
int i = 0;
|
||||
int length = 0;
|
||||
int retval = 0;
|
||||
/* ieee1394:venNmoNspNverN */
|
||||
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,
|
||||
|
||||
#define PUT_ENVP(fmt,val) \
|
||||
do { \
|
||||
int printed; \
|
||||
envp[i++] = buffer; \
|
||||
printed = snprintf(buffer, buffer_size - length, \
|
||||
fmt, val); \
|
||||
if ((buffer_size - (length+printed) <= 0) || (i >= num_envp)) \
|
||||
return -ENOMEM; \
|
||||
length += printed+1; \
|
||||
buffer += printed+1; \
|
||||
retval = add_uevent_var(envp, num_envp, &i, \
|
||||
buffer, buffer_size, &length, \
|
||||
fmt, val); \
|
||||
if (retval) \
|
||||
return retval; \
|
||||
} while (0)
|
||||
|
||||
PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
|
||||
@@ -1393,12 +1389,10 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
|
||||
if (ud->ne != ne)
|
||||
continue;
|
||||
|
||||
down_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
if (ud->device.driver &&
|
||||
(!ud->device.driver->suspend ||
|
||||
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
|
||||
device_release_driver(&ud->device);
|
||||
up_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
}
|
||||
up(&nodemgr_ud_class.sem);
|
||||
}
|
||||
@@ -1418,10 +1412,8 @@ static void nodemgr_resume_ne(struct node_entry *ne)
|
||||
if (ud->ne != ne)
|
||||
continue;
|
||||
|
||||
down_read(&ieee1394_bus_type.subsys.rwsem);
|
||||
if (ud->device.driver && ud->device.driver->resume)
|
||||
ud->device.driver->resume(&ud->device);
|
||||
up_read(&ieee1394_bus_type.subsys.rwsem);
|
||||
}
|
||||
up(&nodemgr_ud_class.sem);
|
||||
|
||||
@@ -1442,7 +1434,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
|
||||
if (ud->ne != ne)
|
||||
continue;
|
||||
|
||||
down_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
if (ud->device.driver) {
|
||||
pdrv = container_of(ud->device.driver,
|
||||
struct hpsb_protocol_driver,
|
||||
@@ -1450,7 +1441,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
|
||||
if (pdrv->update && pdrv->update(ud))
|
||||
device_release_driver(&ud->device);
|
||||
}
|
||||
up_write(&ieee1394_bus_type.subsys.rwsem);
|
||||
}
|
||||
up(&nodemgr_ud_class.sem);
|
||||
}
|
||||
|
||||
@@ -190,16 +190,14 @@ static void gameport_run_poll_handler(unsigned long d)
|
||||
* 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;
|
||||
|
||||
down_write(&gameport_bus.subsys.rwsem);
|
||||
|
||||
gameport->dev.driver = &drv->driver;
|
||||
if (drv->connect(gameport, drv)) {
|
||||
gameport->dev.driver = NULL;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = device_bind_driver(&gameport->dev);
|
||||
@@ -211,31 +209,21 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv
|
||||
drv->description, error);
|
||||
drv->disconnect(gameport);
|
||||
gameport->dev.driver = NULL;
|
||||
goto out;
|
||||
return error;
|
||||
}
|
||||
|
||||
out:
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gameport_find_driver(struct gameport *gameport)
|
||||
{
|
||||
int error;
|
||||
|
||||
down_write(&gameport_bus.subsys.rwsem);
|
||||
error = device_attach(&gameport->dev);
|
||||
if (error < 0)
|
||||
printk(KERN_WARNING
|
||||
"gameport: device_attach() failed for %s (%s), error: %d\n",
|
||||
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
|
||||
{
|
||||
struct gameport *gameport = to_gameport_port(dev);
|
||||
struct device_driver *drv;
|
||||
int retval;
|
||||
int error;
|
||||
|
||||
retval = mutex_lock_interruptible(&gameport_mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
error = mutex_lock_interruptible(&gameport_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
retval = count;
|
||||
if (!strncmp(buf, "none", count)) {
|
||||
gameport_disconnect_port(gameport);
|
||||
} else if (!strncmp(buf, "reconnect", count)) {
|
||||
@@ -499,15 +486,15 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
|
||||
gameport_find_driver(gameport);
|
||||
} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
|
||||
gameport_disconnect_port(gameport);
|
||||
gameport_bind_driver(gameport, to_gameport_driver(drv));
|
||||
error = gameport_bind_driver(gameport, to_gameport_driver(drv));
|
||||
put_driver(drv);
|
||||
} else {
|
||||
retval = -EINVAL;
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&gameport_mutex);
|
||||
|
||||
return retval;
|
||||
return error ? error : count;
|
||||
}
|
||||
|
||||
static struct device_attribute gameport_device_attrs[] = {
|
||||
@@ -655,7 +642,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
|
||||
do {
|
||||
parent = s->parent;
|
||||
|
||||
gameport_release_driver(s);
|
||||
device_release_driver(&s->dev);
|
||||
gameport_destroy_port(s);
|
||||
} while ((s = parent) != gameport);
|
||||
}
|
||||
@@ -663,7 +650,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
|
||||
/*
|
||||
* Ok, no children left, now disconnect this port
|
||||
*/
|
||||
gameport_release_driver(gameport);
|
||||
device_release_driver(&gameport->dev);
|
||||
}
|
||||
|
||||
void gameport_rescan(struct gameport *gameport)
|
||||
|
||||
+15
-26
@@ -115,18 +115,18 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser
|
||||
* 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;
|
||||
|
||||
down_write(&serio_bus.subsys.rwsem);
|
||||
|
||||
if (serio_match_port(drv->id_table, serio)) {
|
||||
|
||||
serio->dev.driver = &drv->driver;
|
||||
if (serio_connect_driver(serio, drv)) {
|
||||
serio->dev.driver = NULL;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = device_bind_driver(&serio->dev);
|
||||
if (error) {
|
||||
printk(KERN_WARNING
|
||||
@@ -136,31 +136,21 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
|
||||
drv->description, error);
|
||||
serio_disconnect_driver(serio);
|
||||
serio->dev.driver = NULL;
|
||||
goto out;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
out:
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void serio_find_driver(struct serio *serio)
|
||||
{
|
||||
int error;
|
||||
|
||||
down_write(&serio_bus.subsys.rwsem);
|
||||
error = device_attach(&serio->dev);
|
||||
if (error < 0)
|
||||
printk(KERN_WARNING
|
||||
"serio: device_attach() failed for %s (%s), error: %d\n",
|
||||
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 *
|
||||
{
|
||||
struct serio *serio = to_serio_port(dev);
|
||||
struct device_driver *drv;
|
||||
int retval;
|
||||
int error;
|
||||
|
||||
retval = mutex_lock_interruptible(&serio_mutex);
|
||||
if (retval)
|
||||
return retval;
|
||||
error = mutex_lock_interruptible(&serio_mutex);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
retval = count;
|
||||
if (!strncmp(buf, "none", count)) {
|
||||
serio_disconnect_port(serio);
|
||||
} else if (!strncmp(buf, "reconnect", count)) {
|
||||
@@ -486,15 +475,15 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
|
||||
serio_find_driver(serio);
|
||||
} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
|
||||
serio_disconnect_port(serio);
|
||||
serio_bind_driver(serio, to_serio_driver(drv));
|
||||
error = serio_bind_driver(serio, to_serio_driver(drv));
|
||||
put_driver(drv);
|
||||
} else {
|
||||
retval = -EINVAL;
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -665,7 +654,7 @@ static void serio_disconnect_port(struct serio *serio)
|
||||
do {
|
||||
parent = s->parent;
|
||||
|
||||
serio_release_driver(s);
|
||||
device_release_driver(&s->dev);
|
||||
serio_destroy_port(s);
|
||||
} while ((s = parent) != serio);
|
||||
}
|
||||
@@ -673,7 +662,7 @@ static void serio_disconnect_port(struct serio *serio)
|
||||
/*
|
||||
* Ok, no children left, now disconnect this port
|
||||
*/
|
||||
serio_release_driver(serio);
|
||||
device_release_driver(&serio->dev);
|
||||
}
|
||||
|
||||
void serio_rescan(struct serio *serio)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user