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: (61 commits)
  sysfs: add parameter "struct bin_attribute *" in .read/.write methods for sysfs binary attributes
  sysfs: make directory dentries and inodes reclaimable
  sysfs: implement sysfs_get_dentry()
  sysfs: move sysfs_drop_dentry() to dir.c and make it static
  sysfs: restructure add/remove paths and fix inode update
  sysfs: use sysfs_mutex to protect the sysfs_dirent tree
  sysfs: consolidate sysfs spinlocks
  sysfs: make kobj point to sysfs_dirent instead of dentry
  sysfs: implement sysfs_find_dirent() and sysfs_get_dirent()
  sysfs: implement SYSFS_FLAG_REMOVED flag
  sysfs: rename sysfs_dirent->s_type to s_flags and make room for flags
  sysfs: make sysfs_drop_dentry() access inodes using ilookup()
  sysfs: Fix oops in sysfs_drop_dentry on x86_64
  sysfs: use singly-linked list for sysfs_dirent tree
  sysfs: slim down sysfs_dirent->s_active
  sysfs: move s_active functions to fs/sysfs/dir.c
  sysfs: fix root sysfs_dirent -> root dentry association
  sysfs: use iget_locked() instead of new_inode()
  sysfs: reorganize sysfs_new_indoe() and sysfs_create()
  sysfs: fix parent refcounting during rename and move
  ...
This commit is contained in:
Linus Torvalds
2007-07-12 13:40:20 -07:00
93 changed files with 2850 additions and 1522 deletions
@@ -78,6 +78,7 @@ static CLASS_DEVICE_ATTR(loading, 0644,
firmware_loading_show, firmware_loading_store);
static ssize_t firmware_data_read(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
@@ -88,6 +89,7 @@ static ssize_t firmware_data_read(struct kobject *kobj,
return count;
}
static ssize_t firmware_data_write(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
+166
View File
@@ -0,0 +1,166 @@
Rules on how to access information in the Linux kernel sysfs
The kernel exported sysfs exports internal kernel implementation-details
and depends on internal kernel structures and layout. It is agreed upon
by the kernel developers that the Linux kernel does not provide a stable
internal API. As sysfs is a direct export of kernel internal
structures, the sysfs interface can not provide a stable interface eighter,
it may always change along with internal kernel changes.
To minimize the risk of breaking users of sysfs, which are in most cases
low-level userspace applications, with a new kernel release, the users
of sysfs must follow some rules to use an as abstract-as-possible way to
access this filesystem. The current udev and HAL programs already
implement this and users are encouraged to plug, if possible, into the
abstractions these programs provide instead of accessing sysfs
directly.
But if you really do want or need to access sysfs directly, please follow
the following rules and then your programs should work with future
versions of the sysfs interface.
- Do not use libsysfs
It makes assumptions about sysfs which are not true. Its API does not
offer any abstraction, it exposes all the kernel driver-core
implementation details in its own API. Therefore it is not better than
reading directories and opening the files yourself.
Also, it is not actively maintained, in the sense of reflecting the
current kernel-development. The goal of providing a stable interface
to sysfs has failed, it causes more problems, than it solves. It
violates many of the rules in this document.
- sysfs is always at /sys
Parsing /proc/mounts is a waste of time. Other mount points are a
system configuration bug you should not try to solve. For test cases,
possibly support a SYSFS_PATH environment variable to overwrite the
applications behavior, but never try to search for sysfs. Never try
to mount it, if you are not an early boot script.
- devices are only "devices"
There is no such thing like class-, bus-, physical devices,
interfaces, and such that you can rely on in userspace. Everything is
just simply a "device". Class-, bus-, physical, ... types are just
kernel implementation details, which should not be expected by
applications that look for devices in sysfs.
The properties of a device are:
o devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0)
- identical to the DEVPATH value in the event sent from the kernel
at device creation and removal
- the unique key to the device at that point in time
- the kernels path to the device-directory without the leading
/sys, and always starting with with a slash
- all elements of a devpath must be real directories. Symlinks
pointing to /sys/devices must always be resolved to their real
target, and the target path must be used to access the device.
That way the devpath to the device matches the devpath of the
kernel used at event time.
- using or exposing symlink values as elements in a devpath string
is a bug in the application
o kernel name (sda, tty, 0000:00:1f.2, ...)
- a directory name, identical to the last element of the devpath
- applications need to handle spaces and characters like '!' in
the name
o subsystem (block, tty, pci, ...)
- simple string, never a path or a link
- retrieved by reading the "subsystem"-link and using only the
last element of the target path
o driver (tg3, ata_piix, uhci_hcd)
- a simple string, which may contain spaces, never a path or a
link
- it is retrieved by reading the "driver"-link and using only the
last element of the target path
- devices which do not have "driver"-link, just do not have a
driver; copying the driver value in a child device context, is a
bug in the application
o attributes
- the files in the device directory or files below a subdirectories
of the same device directory
- accessing attributes reached by a symlink pointing to another device,
like the "device"-link, is a bug in the application
Everything else is just a kernel driver-core implementation detail,
that should not be assumed to be stable across kernel releases.
- Properties of parent devices never belong into a child device.
Always look at the parent devices themselves for determining device
context properties. If the device 'eth0' or 'sda' does not have a
"driver"-link, then this device does not have a driver. Its value is empty.
Never copy any property of the parent-device into a child-device. Parent
device-properties may change dynamically without any notice to the
child device.
- Hierarchy in a single device-tree
There is only one valid place in sysfs where hierarchy can be examined
and this is below: /sys/devices.
It is planned, that all device directories will end up in the tree
below this directory.
- Classification by subsystem
There are currently three places for classification of devices:
/sys/block, /sys/class and /sys/bus. It is planned that these will
not contain any device-directories themselves, but only flat lists of
symlinks pointing to the unified /sys/devices tree.
All three places have completely different rules on how to access
device information. It is planned to merge all three
classification-directories into one place at /sys/subsystem,
following the layout of the bus-directories. All buses and
classes, including the converted block-subsystem, will show up
there.
The devices belonging to a subsystem will create a symlink in the
"devices" directory at /sys/subsystem/<name>/devices.
If /sys/subsystem exists, /sys/bus, /sys/class and /sys/block can be
ignored. If it does not exist, you have always to scan all three
places, as the kernel is free to move a subsystem from one place to
the other, as long as the devices are still reachable by the same
subsystem name.
Assuming /sys/class/<subsystem> and /sys/bus/<subsystem>, or
/sys/block and /sys/class/block are not interchangeable, is a bug in
the application.
- Block
The converted block-subsystem at /sys/class/block, or
/sys/subsystem/block will contain the links for disks and partitions
at the same level, never in a hierarchy. Assuming the block-subsytem to
contain only disks and not partition-devices in the same flat list is
a bug in the application.
- "device"-link and <subsystem>:<kernel name>-links
Never depend on the "device"-link. The "device"-link is a workaround
for the old layout, where class-devices are not created in
/sys/devices/ like the bus-devices. If the link-resolving of a
device-directory does not end in /sys/devices/, you can use the
"device"-link to find the parent devices in /sys/devices/. That is the
single valid use of the "device"-link, it must never appear in any
path as an element. Assuming the existence of the "device"-link for
a device in /sys/devices/ is a bug in the application.
Accessing /sys/class/net/eth0/device is a bug in the application.
Never depend on the class-specific links back to the /sys/class
directory. These links are also a workaround for the design mistake
that class-devices are not created in /sys/devices. If a device
directory does not contain directories for child devices, these links
may be used to find the child devices in /sys/class. That is the single
valid use of these links, they must never appear in any path as an
element. Assuming the existence of these links for devices which are
real child device directories in the /sys/devices tree, is a bug in
the application.
It is planned to remove all these links when when all class-device
directories live in /sys/devices.
- Position of devices along device chain can change.
Never depend on a specific parent device position in the devpath,
or the chain of parent devices. The kernel is free to insert devices into
the chain. You must always request the parent device you are looking for
by its subsystem value. You need to walk up the chain until you find
the device that matches the expected subsystem. Depending on a specific
position of a parent device, or exposing relative paths, using "../" to
access the chain of parents, is a bug in the application.
+8 -3
View File
@@ -60,6 +60,9 @@ struct locomo {
unsigned int irq;
spinlock_t lock;
void __iomem *base;
#ifdef CONFIG_PM
void *saved_state;
#endif
};
struct locomo_dev_info {
@@ -565,7 +568,7 @@ static int locomo_suspend(struct platform_device *dev, pm_message_t state)
if (!save)
return -ENOMEM;
dev->dev.power.saved_state = (void *) save;
lchip->saved_state = save;
spin_lock_irqsave(&lchip->lock, flags);
@@ -605,8 +608,8 @@ static int locomo_resume(struct platform_device *dev)
struct locomo_save_data *save;
unsigned long r;
unsigned long flags;
save = (struct locomo_save_data *) dev->dev.power.saved_state;
save = lchip->saved_state;
if (!save)
return 0;
@@ -628,6 +631,8 @@ static int locomo_resume(struct platform_device *dev)
locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
spin_unlock_irqrestore(&lchip->lock, flags);
lchip->saved_state = NULL;
kfree(save);
return 0;
+8 -5
View File
@@ -51,6 +51,9 @@ struct sa1111 {
int irq;
spinlock_t lock;
void __iomem *base;
#ifdef CONFIG_PM
void *saved_state;
#endif
};
/*
@@ -822,7 +825,7 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!save)
return -ENOMEM;
dev->dev.power.saved_state = save;
sachip->saved_state = save;
spin_lock_irqsave(&sachip->lock, flags);
@@ -878,7 +881,7 @@ static int sa1111_resume(struct platform_device *dev)
unsigned long flags, id;
void __iomem *base;
save = (struct sa1111_save_data *)dev->dev.power.saved_state;
save = sachip->saved_state;
if (!save)
return 0;
@@ -923,7 +926,7 @@ static int sa1111_resume(struct platform_device *dev)
spin_unlock_irqrestore(&sachip->lock, flags);
dev->dev.power.saved_state = NULL;
sachip->saved_state = NULL;
kfree(save);
return 0;
@@ -958,8 +961,8 @@ static int sa1111_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
#ifdef CONFIG_PM
kfree(pdev->dev.power.saved_state);
pdev->dev.power.saved_state = NULL;
kfree(sachip->saved_state);
sachip->saved_state = NULL;
#endif
}
+4 -11
View File
@@ -185,28 +185,21 @@ static int __devinit neponset_probe(struct platform_device *dev)
/*
* LDM power management.
*/
static unsigned int neponset_saved_state;
static int neponset_suspend(struct platform_device *dev, pm_message_t state)
{
/*
* Save state.
*/
if (!dev->dev.power.saved_state)
dev->dev.power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
if (!dev->dev.power.saved_state)
return -ENOMEM;
*(unsigned int *)dev->dev.power.saved_state = NCR_0;
neponset_saved_state = NCR_0;
return 0;
}
static int neponset_resume(struct platform_device *dev)
{
if (dev->dev.power.saved_state) {
NCR_0 = *(unsigned int *)dev->dev.power.saved_state;
kfree(dev->dev.power.saved_state);
dev->dev.power.saved_state = NULL;
}
NCR_0 = neponset_saved_state;
return 0;
}
-1
View File
@@ -2415,7 +2415,6 @@ static struct bin_attribute mv64xxx_hs_reg_attr = { /* Hotswap register */
.attr = {
.name = "hs_reg",
.mode = S_IRUGO | S_IWUSR,
.owner = THIS_MODULE,
},
.size = VAL_LEN_MAX,
.read = mv64xxx_hs_reg_read,
-2
View File
@@ -312,7 +312,6 @@ static struct bin_attribute ipl_parameter_attr = {
.attr = {
.name = "binary_parameter",
.mode = S_IRUGO,
.owner = THIS_MODULE,
},
.size = PAGE_SIZE,
.read = &ipl_parameter_read,
@@ -336,7 +335,6 @@ static struct bin_attribute ipl_scp_data_attr = {
.attr = {
.name = "scp_data",
.mode = S_IRUGO,
.owner = THIS_MODULE,
},
.size = PAGE_SIZE,
.read = &ipl_scp_data_read,
+1
View File
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include "base.h"
+1 -1
View File
@@ -44,6 +44,6 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
extern char *make_class_name(const char *name, struct kobject *kobj);
extern void devres_release_all(struct device *dev);
extern int devres_release_all(struct device *dev);
extern struct kset devices_subsys;
+19 -7
View File
@@ -138,12 +138,24 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
}
}
static struct kobj_type ktype_bus = {
static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
};
static decl_subsys(bus, &ktype_bus, NULL);
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
if (ktype == &bus_ktype)
return 1;
return 0;
}
static struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
#ifdef CONFIG_HOTPLUG
@@ -562,7 +574,6 @@ static int add_probe_files(struct bus_type *bus)
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)
@@ -570,7 +581,6 @@ static int add_probe_files(struct bus_type *bus)
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);
@@ -610,7 +620,8 @@ int bus_add_driver(struct device_driver *drv)
if (error)
goto out_put_bus;
drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj)))
error = kobject_register(&drv->kobj);
if (error)
goto out_put_bus;
if (drv->bus->drivers_autoprobe) {
@@ -760,7 +771,8 @@ static int bus_add_attrs(struct bus_type * bus)
if (bus->bus_attrs) {
for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
error = bus_create_file(bus,&bus->bus_attrs[i]);
if (error)
goto Err;
}
}
+16 -30
View File
@@ -312,9 +312,6 @@ static void class_dev_release(struct kobject * kobj)
pr_debug("device class '%s': release.\n", cd->class_id);
kfree(cd->devt_attr);
cd->devt_attr = NULL;
if (cd->release)
cd->release(cd);
else if (cls->release)
@@ -547,6 +544,9 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
return print_dev_t(buf, class_dev->devt);
}
static struct class_device_attribute class_devt_attr =
__ATTR(dev, S_IRUGO, show_dev, NULL);
static ssize_t store_uevent(struct class_device *class_dev,
const char *buf, size_t count)
{
@@ -554,6 +554,9 @@ static ssize_t store_uevent(struct class_device *class_dev,
return count;
}
static struct class_device_attribute class_uevent_attr =
__ATTR(uevent, S_IWUSR, NULL, store_uevent);
void class_device_initialize(struct class_device *class_dev)
{
kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -603,32 +606,15 @@ int class_device_add(struct class_device *class_dev)
&parent_class->subsys.kobj, "subsystem");
if (error)
goto out3;
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent_class->owner;
class_dev->uevent_attr.store = store_uevent;
error = class_device_create_file(class_dev, &class_dev->uevent_attr);
error = class_device_create_file(class_dev, &class_uevent_attr);
if (error)
goto out3;
if (MAJOR(class_dev->devt)) {
struct class_device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
error = class_device_create_file(class_dev, &class_devt_attr);
if (error)
goto out4;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
attr->attr.owner = parent_class->owner;
attr->show = show_dev;
error = class_device_create_file(class_dev, attr);
if (error) {
kfree(attr);
goto out4;
}
class_dev->devt_attr = attr;
}
error = class_device_add_attrs(class_dev);
@@ -671,10 +657,10 @@ int class_device_add(struct class_device *class_dev)
out6:
class_device_remove_attrs(class_dev);
out5:
if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr);
if (MAJOR(class_dev->devt))
class_device_remove_file(class_dev, &class_devt_attr);
out4:
class_device_remove_file(class_dev, &class_dev->uevent_attr);
class_device_remove_file(class_dev, &class_uevent_attr);
out3:
kobject_del(&class_dev->kobj);
out2:
@@ -774,9 +760,9 @@ void class_device_del(struct class_device *class_dev)
sysfs_remove_link(&class_dev->kobj, "device");
}
sysfs_remove_link(&class_dev->kobj, "subsystem");
class_device_remove_file(class_dev, &class_dev->uevent_attr);
if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr);
class_device_remove_file(class_dev, &class_uevent_attr);
if (MAJOR(class_dev->devt))
class_device_remove_file(class_dev, &class_devt_attr);
class_device_remove_attrs(class_dev);
class_device_remove_groups(class_dev);
+21 -37
View File
@@ -310,6 +310,9 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
return count;
}
static struct device_attribute uevent_attr =
__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
static int device_add_attributes(struct device *dev,
struct device_attribute *attrs)
{
@@ -423,6 +426,9 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
return print_dev_t(buf, dev->devt);
}
static struct device_attribute devt_attr =
__ATTR(dev, S_IRUGO, show_dev, NULL);
/*
* devices_subsys - structure to be registered with kobject core.
*/
@@ -681,35 +687,14 @@ int device_add(struct device *dev)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
dev->uevent_attr.attr.name = "uevent";
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);
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
struct device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
if (dev->driver)
attr->attr.owner = dev->driver->owner;
attr->show = show_dev;
error = device_create_file(dev, attr);
if (error) {
kfree(attr);
goto ueventattrError;
}
dev->devt_attr = attr;
}
if (dev->class) {
@@ -733,11 +718,14 @@ int device_add(struct device *dev)
}
}
if ((error = device_add_attrs(dev)))
error = device_add_attrs(dev);
if (error)
goto AttrsError;
if ((error = device_pm_add(dev)))
error = device_pm_add(dev);
if (error)
goto PMError;
if ((error = bus_add_device(dev)))
error = bus_add_device(dev);
if (error)
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
@@ -767,10 +755,8 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
@@ -792,7 +778,7 @@ int device_add(struct device *dev)
}
}
ueventattrError:
device_remove_file(dev, &dev->uevent_attr);
device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
@@ -869,10 +855,8 @@ void device_del(struct device * dev)
if (parent)
klist_del(&dev->knode_parent);
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
@@ -926,7 +910,7 @@ void device_del(struct device * dev)
up(&dev->class->sem);
}
}
device_remove_file(dev, &dev->uevent_attr);
device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
bus_remove_device(dev);
+10 -11
View File
@@ -281,24 +281,16 @@ int driver_attach(struct device_driver * drv)
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
/**
* device_release_driver - manually detach device from driver.
* @dev: device.
*
* Manually detach device from driver.
*
/*
* __device_release_driver() must be called with @dev->sem held.
* When called for a USB interface, @dev->parent->sem must be held
* as well.
* When called for a USB interface, @dev->parent->sem must be held as well.
*/
static void __device_release_driver(struct device * dev)
{
struct device_driver * drv;
drv = dev->driver;
drv = get_driver(dev->driver);
if (drv) {
get_driver(drv);
driver_sysfs_remove(dev);
sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver);
@@ -318,6 +310,13 @@ static void __device_release_driver(struct device * dev)
}
}
/**
* device_release_driver - manually detach device from driver.
* @dev: device.
*
* Manually detach device from driver.
* When called for a USB interface, @dev->parent->sem must be held.
*/
void device_release_driver(struct device * dev)
{
/*
+2
View File
@@ -10,6 +10,8 @@
#include <linux/device.h>
#include <linux/module.h>
#include "base.h"
struct devres_node {
struct list_head entry;
dr_release_t release;
+3 -3
View File
@@ -175,7 +175,7 @@ static ssize_t firmware_loading_store(struct device *dev,
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
static ssize_t
firmware_data_read(struct kobject *kobj,
firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
@@ -240,7 +240,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
* the driver as a firmware image.
**/
static ssize_t
firmware_data_write(struct kobject *kobj,
firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
@@ -271,7 +271,7 @@ out:
}
static struct bin_attribute firmware_attr_data_tmpl = {
.attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE},
.attr = {.name = "data", .mode = 0644},
.size = 0,
.read = firmware_data_read,
.write = firmware_data_write,
+12 -32
View File
@@ -20,64 +20,44 @@
*/
#include <linux/device.h>
#include <linux/mutex.h>
#include "power.h"
LIST_HEAD(dpm_active);
LIST_HEAD(dpm_off);
LIST_HEAD(dpm_off_irq);
DECLARE_MUTEX(dpm_sem);
DECLARE_MUTEX(dpm_list_sem);
DEFINE_MUTEX(dpm_mtx);
DEFINE_MUTEX(dpm_list_mtx);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
/**
* device_pm_set_parent - Specify power dependency.
* @dev: Device who needs power.
* @parent: Device that supplies power.
*
* This function is used to manually describe a power-dependency
* relationship. It may be used to specify a transversal relationship
* (where the power supplier is not the physical (or electrical)
* ancestor of a specific device.
* The effect of this is that the supplier will not be powered down
* before the power dependent.
*/
void device_pm_set_parent(struct device * dev, struct device * parent)
{
put_device(dev->power.pm_parent);
dev->power.pm_parent = get_device(parent);
}
EXPORT_SYMBOL_GPL(device_pm_set_parent);
int device_pm_add(struct device * dev)
int device_pm_add(struct device *dev)
{
int error;
pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
down(&dpm_list_sem);
mutex_lock(&dpm_list_mtx);
list_add_tail(&dev->power.entry, &dpm_active);
device_pm_set_parent(dev, dev->parent);
if ((error = dpm_sysfs_add(dev)))
error = dpm_sysfs_add(dev);
if (error)
list_del(&dev->power.entry);
up(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
return error;
}
void device_pm_remove(struct device * dev)
void device_pm_remove(struct device *dev)
{
pr_debug("PM: Removing info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
down(&dpm_list_sem);
mutex_lock(&dpm_list_mtx);
dpm_sysfs_remove(dev);
put_device(dev->power.pm_parent);
list_del_init(&dev->power.entry);
up(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
}
+2 -2
View File
@@ -14,12 +14,12 @@ extern void device_shutdown(void);
/*
* Used to synchronize global power management operations.
*/
extern struct semaphore dpm_sem;
extern struct mutex dpm_mtx;
/*
* Used to serialize changes to the dpm_* lists.
*/
extern struct semaphore dpm_list_sem;
extern struct mutex dpm_list_mtx;
/*
* The PM lists.
+7 -16
View File
@@ -29,14 +29,6 @@ int resume_device(struct device * dev)
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",
dev->power.power_state.event,
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);
@@ -80,7 +72,7 @@ static int resume_device_early(struct device * dev)
*/
void dpm_resume(void)
{
down(&dpm_list_sem);
mutex_lock(&dpm_list_mtx);
while(!list_empty(&dpm_off)) {
struct list_head * entry = dpm_off.next;
struct device * dev = to_device(entry);
@@ -88,13 +80,12 @@ void dpm_resume(void)
get_device(dev);
list_move_tail(entry, &dpm_active);
up(&dpm_list_sem);
if (!dev->power.prev_state.event)
resume_device(dev);
down(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
resume_device(dev);
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
up(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
}
@@ -108,9 +99,9 @@ void dpm_resume(void)
void device_resume(void)
{
might_sleep();
down(&dpm_sem);
mutex_lock(&dpm_mtx);
dpm_resume();
up(&dpm_sem);
mutex_unlock(&dpm_mtx);
}
EXPORT_SYMBOL_GPL(device_resume);
+6 -6
View File
@@ -32,9 +32,9 @@ static void runtime_resume(struct device * dev)
void dpm_runtime_resume(struct device * dev)
{
down(&dpm_sem);
mutex_lock(&dpm_mtx);
runtime_resume(dev);
up(&dpm_sem);
mutex_unlock(&dpm_mtx);
}
EXPORT_SYMBOL(dpm_runtime_resume);
@@ -49,7 +49,7 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state)
{
int error = 0;
down(&dpm_sem);
mutex_lock(&dpm_mtx);
if (dev->power.power_state.event == state.event)
goto Done;
@@ -59,7 +59,7 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state)
if (!(error = suspend_device(dev, state)))
dev->power.power_state = state;
Done:
up(&dpm_sem);
mutex_unlock(&dpm_mtx);
return error;
}
EXPORT_SYMBOL(dpm_runtime_suspend);
@@ -78,8 +78,8 @@ EXPORT_SYMBOL(dpm_runtime_suspend);
*/
void dpm_set_power_state(struct device * dev, pm_message_t state)
{
down(&dpm_sem);
mutex_lock(&dpm_mtx);
dev->power.power_state = state;
up(&dpm_sem);
mutex_unlock(&dpm_mtx);
}
#endif /* 0 */
+23 -49
View File
@@ -40,6 +40,14 @@ static inline char *suspend_verb(u32 event)
}
static void
suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
{
dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
", may wakeup" : "");
}
/**
* suspend_device - Save state of one device.
* @dev: Device.
@@ -55,49 +63,21 @@ int suspend_device(struct device * dev, pm_message_t state)
dev_dbg(dev, "PM: suspend %d-->%d\n",
dev->power.power_state.event, state.event);
}
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) {
dev_err(dev,
"PM: suspend %d->%d, parent %s already %d\n",
dev->power.power_state.event, state.event,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state.event);
}
dev->power.prev_state = dev->power.power_state;
if (dev->class && dev->class->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "class %s%s\n",
suspend_verb(state.event),
((state.event == PM_EVENT_SUSPEND)
&& device_may_wakeup(dev))
? ", may wakeup"
: ""
);
if (dev->class && dev->class->suspend) {
suspend_device_dbg(dev, state, "class ");
error = dev->class->suspend(dev, 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"
: ""
);
if (!error && dev->type && dev->type->suspend) {
suspend_device_dbg(dev, state, "type ");
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),
((state.event == PM_EVENT_SUSPEND)
&& device_may_wakeup(dev))
? ", may wakeup"
: ""
);
if (!error && dev->bus && dev->bus->suspend) {
suspend_device_dbg(dev, state, "");
error = dev->bus->suspend(dev, state);
suspend_report_result(dev->bus->suspend, error);
}
@@ -108,21 +88,15 @@ int suspend_device(struct device * dev, pm_message_t state)
/*
* This is called with interrupts off, only a single CPU
* running. We can't do down() on a semaphore (and we don't
* running. We can't acquire a mutex or semaphore (and we don't
* need the protection)
*/
static int suspend_device_late(struct device *dev, pm_message_t state)
{
int error = 0;
if (dev->bus && dev->bus->suspend_late && !dev->power.power_state.event) {
dev_dbg(dev, "LATE %s%s\n",
suspend_verb(state.event),
((state.event == PM_EVENT_SUSPEND)
&& device_may_wakeup(dev))
? ", may wakeup"
: ""
);
if (dev->bus && dev->bus->suspend_late) {
suspend_device_dbg(dev, state, "LATE ");
error = dev->bus->suspend_late(dev, state);
suspend_report_result(dev->bus->suspend_late, error);
}
@@ -153,18 +127,18 @@ int device_suspend(pm_message_t state)
int error = 0;
might_sleep();
down(&dpm_sem);
down(&dpm_list_sem);
mutex_lock(&dpm_mtx);
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_active) && error == 0) {
struct list_head * entry = dpm_active.prev;
struct device * dev = to_device(entry);
get_device(dev);
up(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
error = suspend_device(dev, state);
down(&dpm_list_sem);
mutex_lock(&dpm_list_mtx);
/* Check if the device got removed */
if (!list_empty(&dev->power.entry)) {
@@ -179,11 +153,11 @@ int device_suspend(pm_message_t state)
error == -EAGAIN ? " (please convert to suspend_late)" : "");
put_device(dev);
}
up(&dpm_list_sem);
mutex_unlock(&dpm_list_mtx);
if (error)
dpm_resume();
up(&dpm_sem);
mutex_unlock(&dpm_mtx);
return error;
}

Some files were not shown because too many files have changed in this diff Show More