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:
Коммит
dc690d8ef8
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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);
|
||||
|
||||
|
@ -606,7 +609,7 @@ static int locomo_resume(struct platform_device *dev)
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
|
@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister);
|
|||
|
||||
|
||||
static LIST_HEAD(sysdev_drivers);
|
||||
static DECLARE_MUTEX(sysdev_drivers_lock);
|
||||
static DEFINE_MUTEX(sysdev_drivers_lock);
|
||||
|
||||
/**
|
||||
* sysdev_driver_register - Register auxillary driver
|
||||
|
@ -172,7 +172,7 @@ static DECLARE_MUTEX(sysdev_drivers_lock);
|
|||
int sysdev_driver_register(struct sysdev_class * cls,
|
||||
struct sysdev_driver * drv)
|
||||
{
|
||||
down(&sysdev_drivers_lock);
|
||||
mutex_lock(&sysdev_drivers_lock);
|
||||
if (cls && kset_get(&cls->kset)) {
|
||||
list_add_tail(&drv->entry, &cls->drivers);
|
||||
|
||||
|
@ -184,7 +184,7 @@ int sysdev_driver_register(struct sysdev_class * cls,
|
|||
}
|
||||
} else
|
||||
list_add_tail(&drv->entry, &sysdev_drivers);
|
||||
up(&sysdev_drivers_lock);
|
||||
mutex_unlock(&sysdev_drivers_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ int sysdev_driver_register(struct sysdev_class * cls,
|
|||
void sysdev_driver_unregister(struct sysdev_class * cls,
|
||||
struct sysdev_driver * drv)
|
||||
{
|
||||
down(&sysdev_drivers_lock);
|
||||
mutex_lock(&sysdev_drivers_lock);
|
||||
list_del_init(&drv->entry);
|
||||
if (cls) {
|
||||
if (drv->remove) {
|
||||
|
@ -207,7 +207,7 @@ void sysdev_driver_unregister(struct sysdev_class * cls,
|
|||
}
|
||||
kset_put(&cls->kset);
|
||||
}
|
||||
up(&sysdev_drivers_lock);
|
||||
mutex_unlock(&sysdev_drivers_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysdev_driver_register);
|
||||
|
@ -246,7 +246,7 @@ int sysdev_register(struct sys_device * sysdev)
|
|||
if (!error) {
|
||||
struct sysdev_driver * drv;
|
||||
|
||||
down(&sysdev_drivers_lock);
|
||||
mutex_lock(&sysdev_drivers_lock);
|
||||
/* Generic notification is implicit, because it's that
|
||||
* code that should have called us.
|
||||
*/
|
||||
|
@ -262,7 +262,7 @@ int sysdev_register(struct sys_device * sysdev)
|
|||
if (drv->add)
|
||||
drv->add(sysdev);
|
||||
}
|
||||
up(&sysdev_drivers_lock);
|
||||
mutex_unlock(&sysdev_drivers_lock);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ void sysdev_unregister(struct sys_device * sysdev)
|
|||
{
|
||||
struct sysdev_driver * drv;
|
||||
|
||||
down(&sysdev_drivers_lock);
|
||||
mutex_lock(&sysdev_drivers_lock);
|
||||
list_for_each_entry(drv, &sysdev_drivers, entry) {
|
||||
if (drv->remove)
|
||||
drv->remove(sysdev);
|
||||
|
@ -281,7 +281,7 @@ void sysdev_unregister(struct sys_device * sysdev)
|
|||
if (drv->remove)
|
||||
drv->remove(sysdev);
|
||||
}
|
||||
up(&sysdev_drivers_lock);
|
||||
mutex_unlock(&sysdev_drivers_lock);
|
||||
|
||||
kobject_unregister(&sysdev->kobj);
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ void sysdev_shutdown(void)
|
|||
|
||||
pr_debug("Shutting Down System Devices\n");
|
||||
|
||||
down(&sysdev_drivers_lock);
|
||||
mutex_lock(&sysdev_drivers_lock);
|
||||
list_for_each_entry_reverse(cls, &system_subsys.list,
|
||||
kset.kobj.entry) {
|
||||
struct sys_device * sysdev;
|
||||
|
@ -337,7 +337,7 @@ void sysdev_shutdown(void)
|
|||
cls->shutdown(sysdev);
|
||||
}
|
||||
}
|
||||
up(&sysdev_drivers_lock);
|
||||
mutex_unlock(&sysdev_drivers_lock);
|
||||
}
|
||||
|
||||
static void __sysdev_resume(struct sys_device *dev)
|
||||
|
|
|
@ -146,8 +146,7 @@ static void pkt_kobj_release(struct kobject *kobj)
|
|||
**********************************************************/
|
||||
|
||||
#define DEF_ATTR(_obj,_name,_mode) \
|
||||
static struct attribute _obj = { \
|
||||
.name = _name, .owner = THIS_MODULE, .mode = _mode }
|
||||
static struct attribute _obj = { .name = _name, .mode = _mode }
|
||||
|
||||
/**********************************************************
|
||||
/sys/class/pktcdvd/pktcdvd[0-7]/
|
||||
|
|
|
@ -2171,52 +2171,42 @@ static int create_files(struct bmc_device *bmc)
|
|||
int err;
|
||||
|
||||
bmc->device_id_attr.attr.name = "device_id";
|
||||
bmc->device_id_attr.attr.owner = THIS_MODULE;
|
||||
bmc->device_id_attr.attr.mode = S_IRUGO;
|
||||
bmc->device_id_attr.show = device_id_show;
|
||||
|
||||
bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
|
||||
bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
|
||||
bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
|
||||
bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
|
||||
|
||||
bmc->revision_attr.attr.name = "revision";
|
||||
bmc->revision_attr.attr.owner = THIS_MODULE;
|
||||
bmc->revision_attr.attr.mode = S_IRUGO;
|
||||
bmc->revision_attr.show = revision_show;
|
||||
|
||||
bmc->firmware_rev_attr.attr.name = "firmware_revision";
|
||||
bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
|
||||
bmc->firmware_rev_attr.attr.mode = S_IRUGO;
|
||||
bmc->firmware_rev_attr.show = firmware_rev_show;
|
||||
|
||||
bmc->version_attr.attr.name = "ipmi_version";
|
||||
bmc->version_attr.attr.owner = THIS_MODULE;
|
||||
bmc->version_attr.attr.mode = S_IRUGO;
|
||||
bmc->version_attr.show = ipmi_version_show;
|
||||
|
||||
bmc->add_dev_support_attr.attr.name = "additional_device_support";
|
||||
bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
|
||||
bmc->add_dev_support_attr.attr.mode = S_IRUGO;
|
||||
bmc->add_dev_support_attr.show = add_dev_support_show;
|
||||
|
||||
bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
|
||||
bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
|
||||
bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
|
||||
bmc->manufacturer_id_attr.show = manufacturer_id_show;
|
||||
|
||||
bmc->product_id_attr.attr.name = "product_id";
|
||||
bmc->product_id_attr.attr.owner = THIS_MODULE;
|
||||
bmc->product_id_attr.attr.mode = S_IRUGO;
|
||||
bmc->product_id_attr.show = product_id_show;
|
||||
|
||||
bmc->guid_attr.attr.name = "guid";
|
||||
bmc->guid_attr.attr.owner = THIS_MODULE;
|
||||
bmc->guid_attr.attr.mode = S_IRUGO;
|
||||
bmc->guid_attr.show = guid_show;
|
||||
|
||||
bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
|
||||
bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
|
||||
bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
|
||||
bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ static spinlock_t cpufreq_stats_lock;
|
|||
|
||||
#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
|
||||
static struct freq_attr _attr_##_name = {\
|
||||
.attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
|
||||
.mode = _mode, }, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, }, \
|
||||
.show = _show,\
|
||||
};
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
|
|||
|
||||
static struct freq_attr freq_attr_scaling_setspeed =
|
||||
{
|
||||
.attr = { .name = "scaling_setspeed", .mode = 0644, .owner = THIS_MODULE },
|
||||
.attr = { .name = "scaling_setspeed", .mode = 0644 },
|
||||
.show = show_speed,
|
||||
.store = store_speed,
|
||||
};
|
||||
|
|
|
@ -199,7 +199,6 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
|
|||
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
|
||||
.attr = { .name = "scaling_available_frequencies",
|
||||
.mode = 0444,
|
||||
.owner=THIS_MODULE
|
||||
},
|
||||
.show = show_available_freqs,
|
||||
};
|
||||
|
|
|
@ -84,4 +84,13 @@ config DCDBAS
|
|||
Say Y or M here to enable the driver for use by Dell systems
|
||||
management software such as Dell OpenManage.
|
||||
|
||||
config DMIID
|
||||
bool "Export DMI identification via sysfs to userspace"
|
||||
depends on DMI
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to query SMBIOS/DMI system identification
|
||||
information from userspace through /sys/class/dmi/id/ or if you want
|
||||
DMI-based module auto-loading.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -7,3 +7,4 @@ obj-$(CONFIG_EFI_VARS) += efivars.o
|
|||
obj-$(CONFIG_EFI_PCDP) += pcdp.o
|
||||
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
|
||||
obj-$(CONFIG_DCDBAS) += dcdbas.o
|
||||
obj-$(CONFIG_DMIID) += dmi-id.o
|
||||
|
|
|
@ -149,8 +149,9 @@ static ssize_t smi_data_buf_size_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
|
||||
size_t count)
|
||||
static ssize_t smi_data_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
size_t max_read;
|
||||
ssize_t ret;
|
||||
|
@ -170,8 +171,9 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
|
||||
size_t count)
|
||||
static ssize_t smi_data_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
|
|
|
@ -67,8 +67,7 @@
|
|||
#define DCDBAS_BIN_ATTR_RW(_name) \
|
||||
struct bin_attribute bin_attr_##_name = { \
|
||||
.attr = { .name = __stringify(_name), \
|
||||
.mode = 0600, \
|
||||
.owner = THIS_MODULE }, \
|
||||
.mode = 0600 }, \
|
||||
.read = _name##_read, \
|
||||
.write = _name##_write, \
|
||||
}
|
||||
|
|
|
@ -543,8 +543,9 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
|
|||
return ret_count;
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_data(struct kobject *kobj, char *buffer,
|
||||
loff_t pos, size_t count)
|
||||
static ssize_t read_rbu_data(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
ssize_t ret_count = 0;
|
||||
|
||||
|
@ -591,8 +592,9 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
|
|||
spin_unlock(&rbu_data.lock);
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
|
||||
loff_t pos, size_t count)
|
||||
static ssize_t read_rbu_image_type(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
int size = 0;
|
||||
if (!pos)
|
||||
|
@ -600,8 +602,9 @@ static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
|
||||
loff_t pos, size_t count)
|
||||
static ssize_t write_rbu_image_type(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
int rc = count;
|
||||
int req_firm_rc = 0;
|
||||
|
@ -660,8 +663,9 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
|
||||
loff_t pos, size_t count)
|
||||
static ssize_t read_rbu_packet_size(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
int size = 0;
|
||||
if (!pos) {
|
||||
|
@ -672,8 +676,9 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
|
||||
loff_t pos, size_t count)
|
||||
static ssize_t write_rbu_packet_size(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
unsigned long temp;
|
||||
spin_lock(&rbu_data.lock);
|
||||
|
@ -687,18 +692,18 @@ static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
|
|||
}
|
||||
|
||||
static struct bin_attribute rbu_data_attr = {
|
||||
.attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
|
||||
.attr = {.name = "data", .mode = 0444},
|
||||
.read = read_rbu_data,
|
||||
};
|
||||
|
||||
static struct bin_attribute rbu_image_type_attr = {
|
||||
.attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
|
||||
.attr = {.name = "image_type", .mode = 0644},
|
||||
.read = read_rbu_image_type,
|
||||
.write = write_rbu_image_type,
|
||||
};
|
||||
|
||||
static struct bin_attribute rbu_packet_size_attr = {
|
||||
.attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644},
|
||||
.attr = {.name = "packet_size", .mode = 0644},
|
||||
.read = read_rbu_packet_size,
|
||||
.write = write_rbu_packet_size,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Export SMBIOS/DMI info via sysfs to userspace
|
||||
*
|
||||
* Copyright 2007, Lennart Poettering
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/autoconf.h>
|
||||
|
||||
#define DEFINE_DMI_ATTR(_name, _mode, _show) \
|
||||
static struct device_attribute sys_dmi_##_name##_attr = \
|
||||
__ATTR(_name, _mode, _show, NULL);
|
||||
|
||||
#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
|
||||
static ssize_t sys_dmi_##_name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *page) \
|
||||
{ \
|
||||
ssize_t len; \
|
||||
len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
|
||||
page[len-1] = '\n'; \
|
||||
return len; \
|
||||
} \
|
||||
DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
|
||||
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(bios_date, 0444, DMI_BIOS_DATE);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor, 0444, DMI_SYS_VENDOR);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_serial, 0400, DMI_BOARD_SERIAL);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag, 0444, DMI_BOARD_ASSET_TAG);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor, 0444, DMI_CHASSIS_VENDOR);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(chassis_type, 0444, DMI_CHASSIS_TYPE);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(chassis_version, 0444, DMI_CHASSIS_VERSION);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial, 0400, DMI_CHASSIS_SERIAL);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);
|
||||
|
||||
static void ascii_filter(char *d, const char *s)
|
||||
{
|
||||
/* Filter out characters we don't want to see in the modalias string */
|
||||
for (; *s; s++)
|
||||
if (*s > ' ' && *s < 127 && *s != ':')
|
||||
*(d++) = *s;
|
||||
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
static ssize_t get_modalias(char *buffer, size_t buffer_size)
|
||||
{
|
||||
static const struct mafield {
|
||||
const char *prefix;
|
||||
int field;
|
||||
} fields[] = {
|
||||
{ "bvn", DMI_BIOS_VENDOR },
|
||||
{ "bvr", DMI_BIOS_VERSION },
|
||||
{ "bd", DMI_BIOS_DATE },
|
||||
{ "svn", DMI_SYS_VENDOR },
|
||||
{ "pn", DMI_PRODUCT_NAME },
|
||||
{ "pvr", DMI_PRODUCT_VERSION },
|
||||
{ "rvn", DMI_BOARD_VENDOR },
|
||||
{ "rn", DMI_BOARD_NAME },
|
||||
{ "rvr", DMI_BOARD_VERSION },
|
||||
{ "cvn", DMI_CHASSIS_VENDOR },
|
||||
{ "ct", DMI_CHASSIS_TYPE },
|
||||
{ "cvr", DMI_CHASSIS_VERSION },
|
||||
{ NULL, DMI_NONE }
|
||||
};
|
||||
|
||||
ssize_t l, left;
|
||||
char *p;
|
||||
const struct mafield *f;
|
||||
|
||||
strcpy(buffer, "dmi");
|
||||
p = buffer + 3; left = buffer_size - 4;
|
||||
|
||||
for (f = fields; f->prefix && left > 0; f++) {
|
||||
const char *c;
|
||||
char *t;
|
||||
|
||||
c = dmi_get_system_info(f->field);
|
||||
if (!c)
|
||||
continue;
|
||||
|
||||
t = kmalloc(strlen(c) + 1, GFP_KERNEL);
|
||||
if (!t)
|
||||
break;
|
||||
ascii_filter(t, c);
|
||||
l = scnprintf(p, left, ":%s%s", f->prefix, t);
|
||||
kfree(t);
|
||||
|
||||
p += l;
|
||||
left -= l;
|
||||
}
|
||||
|
||||
p[0] = ':';
|
||||
p[1] = 0;
|
||||
|
||||
return p - buffer + 1;
|
||||
}
|
||||
|
||||
static ssize_t sys_dmi_modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
ssize_t r;
|
||||
r = get_modalias(page, PAGE_SIZE-1);
|
||||
page[r] = '\n';
|
||||
page[r+1] = 0;
|
||||
return r+1;
|
||||
}
|
||||
|
||||
DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
|
||||
|
||||
static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
|
||||
|
||||
static struct attribute_group sys_dmi_attribute_group = {
|
||||
.attrs = sys_dmi_attributes,
|
||||
};
|
||||
|
||||
static struct attribute_group* sys_dmi_attribute_groups[] = {
|
||||
&sys_dmi_attribute_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int dmi_dev_uevent(struct device *dev, char **envp,
|
||||
int num_envp, char *buffer, int buffer_size)
|
||||
{
|
||||
strcpy(buffer, "MODALIAS=");
|
||||
get_modalias(buffer+9, buffer_size-9);
|
||||
envp[0] = buffer;
|
||||
envp[1] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct class dmi_class = {
|
||||
.name = "dmi",
|
||||
.dev_release = (void(*)(struct device *)) kfree,
|
||||
.dev_uevent = dmi_dev_uevent,
|
||||
};
|
||||
|
||||
static struct device *dmi_dev;
|
||||
|
||||
/* Initialization */
|
||||
|
||||
#define ADD_DMI_ATTR(_name, _field) \
|
||||
if (dmi_get_system_info(_field)) \
|
||||
sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
|
||||
|
||||
extern int dmi_available;
|
||||
|
||||
static int __init dmi_id_init(void)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if (!dmi_available)
|
||||
return -ENODEV;
|
||||
|
||||
/* Not necessarily all DMI fields are available on all
|
||||
* systems, hence let's built an attribute table of just
|
||||
* what's available */
|
||||
i = 0;
|
||||
ADD_DMI_ATTR(bios_vendor, DMI_BIOS_VENDOR);
|
||||
ADD_DMI_ATTR(bios_version, DMI_BIOS_VERSION);
|
||||
ADD_DMI_ATTR(bios_date, DMI_BIOS_DATE);
|
||||
ADD_DMI_ATTR(sys_vendor, DMI_SYS_VENDOR);
|
||||
ADD_DMI_ATTR(product_name, DMI_PRODUCT_NAME);
|
||||
ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
|
||||
ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
|
||||
ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
|
||||
ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
|
||||
ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
|
||||
ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
|
||||
ADD_DMI_ATTR(board_serial, DMI_BOARD_SERIAL);
|
||||
ADD_DMI_ATTR(board_asset_tag, DMI_BOARD_ASSET_TAG);
|
||||
ADD_DMI_ATTR(chassis_vendor, DMI_CHASSIS_VENDOR);
|
||||
ADD_DMI_ATTR(chassis_type, DMI_CHASSIS_TYPE);
|
||||
ADD_DMI_ATTR(chassis_version, DMI_CHASSIS_VERSION);
|
||||
ADD_DMI_ATTR(chassis_serial, DMI_CHASSIS_SERIAL);
|
||||
ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
|
||||
sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
|
||||
|
||||
ret = class_register(&dmi_class);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
|
||||
if (!dmi_dev) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_class_unregister;
|
||||
}
|
||||
|
||||
dmi_dev->class = &dmi_class;
|
||||
strcpy(dmi_dev->bus_id, "id");
|
||||
dmi_dev->groups = sys_dmi_attribute_groups;
|
||||
|
||||
ret = device_register(dmi_dev);
|
||||
if (ret)
|
||||
goto fail_class_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_class_unregister:
|
||||
|
||||
class_unregister(&dmi_class);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_initcall(dmi_id_init);
|
|
@ -84,6 +84,7 @@ static int __init dmi_checksum(u8 *buf)
|
|||
|
||||
static char *dmi_ident[DMI_STRING_MAX];
|
||||
static LIST_HEAD(dmi_devices);
|
||||
int dmi_available;
|
||||
|
||||
/*
|
||||
* Save a DMI string
|
||||
|
@ -102,6 +103,51 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
|
|||
dmi_ident[slot] = p;
|
||||
}
|
||||
|
||||
static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
|
||||
{
|
||||
u8 *d = (u8*) dm + index;
|
||||
char *s;
|
||||
int is_ff = 1, is_00 = 1, i;
|
||||
|
||||
if (dmi_ident[slot])
|
||||
return;
|
||||
|
||||
for (i = 0; i < 16 && (is_ff || is_00); i++) {
|
||||
if(d[i] != 0x00) is_ff = 0;
|
||||
if(d[i] != 0xFF) is_00 = 0;
|
||||
}
|
||||
|
||||
if (is_ff || is_00)
|
||||
return;
|
||||
|
||||
s = dmi_alloc(16*2+4+1);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
sprintf(s,
|
||||
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
|
||||
dmi_ident[slot] = s;
|
||||
}
|
||||
|
||||
static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
|
||||
{
|
||||
u8 *d = (u8*) dm + index;
|
||||
char *s;
|
||||
|
||||
if (dmi_ident[slot])
|
||||
return;
|
||||
|
||||
s = dmi_alloc(4);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
sprintf(s, "%u", *d & 0x7F);
|
||||
dmi_ident[slot] = s;
|
||||
}
|
||||
|
||||
static void __init dmi_save_devices(struct dmi_header *dm)
|
||||
{
|
||||
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
|
||||
|
@ -192,11 +238,21 @@ static void __init dmi_decode(struct dmi_header *dm)
|
|||
dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
|
||||
dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
|
||||
break;
|
||||
case 2: /* Base Board Information */
|
||||
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
|
||||
dmi_save_ident(dm, DMI_BOARD_NAME, 5);
|
||||
dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
|
||||
dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
|
||||
dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
|
||||
break;
|
||||
case 3: /* Chassis Information */
|
||||
dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
|
||||
dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
|
||||
dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
|
||||
dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
|
||||
dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
|
||||
break;
|
||||
case 10: /* Onboard Devices Information */
|
||||
dmi_save_devices(dm);
|
||||
|
@ -243,18 +299,20 @@ void __init dmi_scan_machine(void)
|
|||
if (efi.smbios == EFI_INVALID_TABLE_ADDR)
|
||||
goto out;
|
||||
|
||||
/* This is called as a core_initcall() because it isn't
|
||||
* needed during early boot. This also means we can
|
||||
* iounmap the space when we're done with it.
|
||||
*/
|
||||
/* This is called as a core_initcall() because it isn't
|
||||
* needed during early boot. This also means we can
|
||||
* iounmap the space when we're done with it.
|
||||
*/
|
||||
p = dmi_ioremap(efi.smbios, 32);
|
||||
if (p == NULL)
|
||||
goto out;
|
||||
|
||||
rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
|
||||
dmi_iounmap(p, 32);
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
dmi_available = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
@ -268,8 +326,10 @@ void __init dmi_scan_machine(void)
|
|||
|
||||
for (q = p; q < p + 0x10000; q += 16) {
|
||||
rc = dmi_present(q);
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
dmi_available = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
out: printk(KERN_INFO "DMI not present or invalid.\n");
|
||||
|
@ -404,3 +464,4 @@ int dmi_get_year(int field)
|
|||
|
||||
return year;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
|
|||
|
||||
#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
|
||||
struct edd_attribute edd_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.test = _test, \
|
||||
};
|
||||
|
|
|
@ -131,21 +131,21 @@ struct efivar_attribute {
|
|||
|
||||
#define EFI_ATTR(_name, _mode, _show, _store) \
|
||||
struct subsys_attribute efi_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define EFIVAR_ATTR(_name, _mode, _show, _store) \
|
||||
struct efivar_attribute efivar_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
|
||||
struct subsys_attribute var_subsys_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
|
|
@ -112,7 +112,8 @@ exit:
|
|||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||
|
@ -145,7 +146,6 @@ static struct bin_attribute eeprom_attr = {
|
|||
.attr = {
|
||||
.name = "eeprom",
|
||||
.mode = S_IRUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = EEPROM_SIZE,
|
||||
.read = eeprom_read,
|
||||
|
|
|
@ -126,8 +126,9 @@ exit_up:
|
|||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
static ssize_t max6875_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client = kobj_to_i2c_client(kobj);
|
||||
struct max6875_data *data = i2c_get_clientdata(client);
|
||||
|
@ -153,7 +154,6 @@ static struct bin_attribute user_eeprom_attr = {
|
|||
.attr = {
|
||||
.name = "eeprom",
|
||||
.mode = S_IRUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = USER_EEPROM_SIZE,
|
||||
.read = max6875_read,
|
||||
|
|
|
@ -479,7 +479,6 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
|
|||
|
||||
element->attr.attr.name = element->name;
|
||||
element->attr.attr.mode = S_IRUGO;
|
||||
element->attr.attr.owner = THIS_MODULE;
|
||||
element->attr.show = show;
|
||||
element->index = i;
|
||||
|
||||
|
|
|
@ -119,7 +119,6 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
|
|||
.attr = { \
|
||||
.name = __stringify(_name), \
|
||||
.mode = _mode, \
|
||||
.owner = THIS_MODULE, \
|
||||
}, \
|
||||
.show = psmouse_attr_show_helper, \
|
||||
.store = psmouse_attr_set_helper, \
|
||||
|
|
|
@ -212,7 +212,6 @@ int wf_register_control(struct wf_control *new_ct)
|
|||
list_add(&new_ct->link, &wf_controls);
|
||||
|
||||
new_ct->attr.attr.name = new_ct->name;
|
||||
new_ct->attr.attr.owner = THIS_MODULE;
|
||||
new_ct->attr.attr.mode = 0644;
|
||||
new_ct->attr.show = wf_show_control;
|
||||
new_ct->attr.store = wf_store_control;
|
||||
|
@ -325,7 +324,6 @@ int wf_register_sensor(struct wf_sensor *new_sr)
|
|||
list_add(&new_sr->link, &wf_sensors);
|
||||
|
||||
new_sr->attr.attr.name = new_sr->name;
|
||||
new_sr->attr.attr.owner = THIS_MODULE;
|
||||
new_sr->attr.attr.mode = 0444;
|
||||
new_sr->attr.show = wf_show_sensor;
|
||||
new_sr->attr.store = NULL;
|
||||
|
|
|
@ -737,8 +737,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
|
|||
struct device_attribute dev_attr_##_name = { \
|
||||
.attr = { \
|
||||
.name = __stringify(_name), \
|
||||
.mode = 0, \
|
||||
.owner = THIS_MODULE }, \
|
||||
.mode = 0 }, \
|
||||
.show = NULL, \
|
||||
.store = NULL, \
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
* msi-laptop.c - MSI S270 laptop support. This laptop is sold under
|
||||
* various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
|
||||
*
|
||||
* Driver also supports S271, S420 models.
|
||||
*
|
||||
* This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
|
||||
*
|
||||
* lcd_level - Screen brightness: contains a single integer in the
|
||||
|
@ -281,25 +283,56 @@ static struct platform_device *msipf_device;
|
|||
|
||||
/* Initialization */
|
||||
|
||||
static int dmi_check_cb(struct dmi_system_id *id)
|
||||
{
|
||||
printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dmi_system_id __initdata msi_dmi_table[] = {
|
||||
{
|
||||
.ident = "MSI S270",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
|
||||
}
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
|
||||
DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "MSI S271",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "MSI S420",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Medion MD96100",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
|
||||
}
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
|
||||
DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
static int __init msi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -394,3 +427,8 @@ MODULE_AUTHOR("Lennart Poettering");
|
|||
MODULE_DESCRIPTION("MSI Laptop Support");
|
||||
MODULE_VERSION(MSI_DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
|
||||
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
|
||||
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
|
||||
MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
|
||||
|
|
|
@ -1337,7 +1337,7 @@ const char * buf, size_t count)
|
|||
|
||||
#define ATTR(_name, _mode) \
|
||||
struct attribute veth_##_name##_attr = { \
|
||||
.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \
|
||||
.name = __stringify(_name), .mode = _mode, \
|
||||
};
|
||||
|
||||
static ATTR(active, 0644);
|
||||
|
|
|
@ -121,14 +121,14 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
|
|||
|
||||
#define PDCS_ATTR(_name, _mode, _show, _store) \
|
||||
struct subsys_attribute pdcs_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define PATHS_ATTR(_name, _mode, _show, _store) \
|
||||
struct pdcspath_attribute paths_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
|
|
@ -106,7 +106,8 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
|
|||
static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
|
||||
static int ibm_get_table_from_acpi(char **bufp);
|
||||
static ssize_t ibm_read_apci_table(struct kobject *kobj,
|
||||
char *buffer, loff_t pos, size_t size);
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t size);
|
||||
static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
|
||||
u32 lvl, void *context, void **rv);
|
||||
static int __init ibm_acpiphp_init(void);
|
||||
|
@ -117,7 +118,6 @@ static struct notification ibm_note;
|
|||
static struct bin_attribute ibm_apci_table_attr = {
|
||||
.attr = {
|
||||
.name = "apci_table",
|
||||
.owner = THIS_MODULE,
|
||||
.mode = S_IRUGO,
|
||||
},
|
||||
.read = ibm_read_apci_table,
|
||||
|
@ -358,7 +358,8 @@ read_table_done:
|
|||
* our solution is to only allow reading the table in all at once
|
||||
**/
|
||||
static ssize_t ibm_read_apci_table(struct kobject *kobj,
|
||||
char *buffer, loff_t pos, size_t size)
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t size)
|
||||
{
|
||||
int bytes_read = -EINVAL;
|
||||
char *table = NULL;
|
||||
|
|
|
@ -213,7 +213,8 @@ struct device_attribute pci_dev_attrs[] = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
|
||||
unsigned int size = 64;
|
||||
|
@ -285,7 +286,8 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
|
||||
unsigned int size = count;
|
||||
|
@ -352,7 +354,8 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
* callback routine (pci_legacy_read).
|
||||
*/
|
||||
ssize_t
|
||||
pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
struct class_device,
|
||||
|
@ -376,7 +379,8 @@ pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
* callback routine (pci_legacy_write).
|
||||
*/
|
||||
ssize_t
|
||||
pci_write_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
struct class_device,
|
||||
|
@ -499,7 +503,6 @@ static int pci_create_resource_files(struct pci_dev *pdev)
|
|||
sprintf(res_attr_name, "resource%d", i);
|
||||
res_attr->attr.name = res_attr_name;
|
||||
res_attr->attr.mode = S_IRUSR | S_IWUSR;
|
||||
res_attr->attr.owner = THIS_MODULE;
|
||||
res_attr->size = pci_resource_len(pdev, i);
|
||||
res_attr->mmap = pci_mmap_resource;
|
||||
res_attr->private = &pdev->resource[i];
|
||||
|
@ -529,7 +532,8 @@ static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
|
|||
* writing anything except 0 enables it
|
||||
*/
|
||||
static ssize_t
|
||||
pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
|
||||
|
||||
|
@ -552,7 +556,8 @@ pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
* device corresponding to @kobj.
|
||||
*/
|
||||
static ssize_t
|
||||
pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
|
||||
void __iomem *rom;
|
||||
|
@ -582,7 +587,6 @@ static struct bin_attribute pci_config_attr = {
|
|||
.attr = {
|
||||
.name = "config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 256,
|
||||
.read = pci_read_config,
|
||||
|
@ -593,7 +597,6 @@ static struct bin_attribute pcie_config_attr = {
|
|||
.attr = {
|
||||
.name = "config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 4096,
|
||||
.read = pci_read_config,
|
||||
|
@ -628,7 +631,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
|
|||
rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
|
||||
rom_attr->attr.name = "rom";
|
||||
rom_attr->attr.mode = S_IRUSR;
|
||||
rom_attr->attr.owner = THIS_MODULE;
|
||||
rom_attr->read = pci_read_rom;
|
||||
rom_attr->write = pci_write_rom;
|
||||
retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
|
||||
|
|
|
@ -39,7 +39,6 @@ static void pci_create_legacy_files(struct pci_bus *b)
|
|||
b->legacy_io->attr.name = "legacy_io";
|
||||
b->legacy_io->size = 0xffff;
|
||||
b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
|
||||
b->legacy_io->attr.owner = THIS_MODULE;
|
||||
b->legacy_io->read = pci_read_legacy_io;
|
||||
b->legacy_io->write = pci_write_legacy_io;
|
||||
class_device_create_bin_file(&b->class_dev, b->legacy_io);
|
||||
|
@ -49,7 +48,6 @@ static void pci_create_legacy_files(struct pci_bus *b)
|
|||
b->legacy_mem->attr.name = "legacy_mem";
|
||||
b->legacy_mem->size = 1024*1024;
|
||||
b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
|
||||
b->legacy_mem->attr.owner = THIS_MODULE;
|
||||
b->legacy_mem->mmap = pci_mmap_legacy_mem;
|
||||
class_device_create_bin_file(&b->class_dev, b->legacy_mem);
|
||||
}
|
||||
|
|
|
@ -283,7 +283,9 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off
|
|||
return (ret);
|
||||
}
|
||||
|
||||
static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t pccard_show_cis(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
unsigned int size = 0x200;
|
||||
|
||||
|
@ -311,7 +313,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
|
|||
return (count);
|
||||
}
|
||||
|
||||
static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t pccard_store_cis(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
|
||||
cisdump_t *cis;
|
||||
|
@ -366,7 +370,7 @@ static struct device_attribute *pccard_socket_attributes[] = {
|
|||
};
|
||||
|
||||
static struct bin_attribute pccard_cis_attr = {
|
||||
.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE},
|
||||
.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
|
||||
.size = 0x200,
|
||||
.read = pccard_show_cis,
|
||||
.write = pccard_store_cis,
|
||||
|
|
|
@ -67,7 +67,8 @@ struct device_attribute rio_dev_attrs[] = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
rio_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct rio_dev *dev =
|
||||
to_rio_dev(container_of(kobj, struct device, kobj));
|
||||
|
@ -137,7 +138,8 @@ rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
rio_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
rio_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct rio_dev *dev =
|
||||
to_rio_dev(container_of(kobj, struct device, kobj));
|
||||
|
@ -197,7 +199,6 @@ static struct bin_attribute rio_config_attr = {
|
|||
.attr = {
|
||||
.name = "config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 0x200000,
|
||||
.read = rio_read_config,
|
||||
|
|
|
@ -258,8 +258,9 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
|
|||
.ioctl = ds1553_rtc_ioctl,
|
||||
};
|
||||
|
||||
static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static ssize_t ds1553_nvram_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
|
@ -272,8 +273,9 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static ssize_t ds1553_nvram_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
|
@ -290,7 +292,6 @@ static struct bin_attribute ds1553_nvram_attr = {
|
|||
.attr = {
|
||||
.name = "nvram",
|
||||
.mode = S_IRUGO | S_IWUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = RTC_OFFSET,
|
||||
.read = ds1553_nvram_read,
|
||||
|
|
|
@ -127,8 +127,9 @@ static const struct rtc_class_ops ds1742_rtc_ops = {
|
|||
.set_time = ds1742_rtc_set_time,
|
||||
};
|
||||
|
||||
static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static ssize_t ds1742_nvram_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
|
@ -141,8 +142,9 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static ssize_t ds1742_nvram_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
|
@ -159,7 +161,6 @@ static struct bin_attribute ds1742_nvram_attr = {
|
|||
.attr = {
|
||||
.name = "nvram",
|
||||
.mode = S_IRUGO | S_IWUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.read = ds1742_nvram_read,
|
||||
.write = ds1742_nvram_write,
|
||||
|
|
|
@ -141,8 +141,9 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
|
|||
/*
|
||||
* Channel measurement related functions
|
||||
*/
|
||||
static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t chp_measurement_chars_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct channel_path *chp;
|
||||
unsigned int size;
|
||||
|
@ -165,7 +166,6 @@ static struct bin_attribute chp_measurement_chars_attr = {
|
|||
.attr = {
|
||||
.name = "measurement_chars",
|
||||
.mode = S_IRUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = sizeof(struct cmg_chars),
|
||||
.read = chp_measurement_chars_read,
|
||||
|
@ -193,8 +193,9 @@ static void chp_measurement_copy_block(struct cmg_entry *buf,
|
|||
} while (reference_buf.values[0] != buf->values[0]);
|
||||
}
|
||||
|
||||
static ssize_t chp_measurement_read(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t chp_measurement_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct channel_path *chp;
|
||||
struct channel_subsystem *css;
|
||||
|
@ -217,7 +218,6 @@ static struct bin_attribute chp_measurement_attr = {
|
|||
.attr = {
|
||||
.name = "measurement",
|
||||
.mode = S_IRUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = sizeof(struct cmg_entry),
|
||||
.read = chp_measurement_read,
|
||||
|
|
|
@ -991,7 +991,7 @@ static struct attribute_group qeth_osn_device_attr_group = {
|
|||
|
||||
#define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \
|
||||
struct device_attribute dev_attr_##_id = { \
|
||||
.attr = {.name=__stringify(_name), .mode=_mode, .owner=THIS_MODULE },\
|
||||
.attr = {.name=__stringify(_name), .mode=_mode, },\
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
|
|
@ -59,8 +59,9 @@
|
|||
struct class_device_attribute *arcmsr_host_attrs[];
|
||||
|
||||
static ssize_t
|
||||
arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
arcmsr_sysfs_iop_message_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *host = class_to_shost(cdev);
|
||||
|
@ -105,8 +106,9 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
arcmsr_sysfs_iop_message_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *host = class_to_shost(cdev);
|
||||
|
@ -152,8 +154,9 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *host = class_to_shost(cdev);
|
||||
|
@ -188,7 +191,6 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
|
|||
.attr = {
|
||||
.name = "mu_read",
|
||||
.mode = S_IRUSR ,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 1032,
|
||||
.read = arcmsr_sysfs_iop_message_read,
|
||||
|
@ -198,7 +200,6 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
|
|||
.attr = {
|
||||
.name = "mu_write",
|
||||
.mode = S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 1032,
|
||||
.write = arcmsr_sysfs_iop_message_write,
|
||||
|
@ -208,7 +209,6 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
|
|||
.attr = {
|
||||
.name = "mu_clear",
|
||||
.mode = S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 1,
|
||||
.write = arcmsr_sysfs_iop_message_clear,
|
||||
|
|
|
@ -2465,6 +2465,7 @@ restart:
|
|||
/**
|
||||
* ipr_read_trace - Dump the adapter trace
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
* @off: offset
|
||||
* @count: buffer size
|
||||
|
@ -2472,8 +2473,9 @@ restart:
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_read_trace(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t ipr_read_trace(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
|
@ -3166,6 +3168,7 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {
|
|||
/**
|
||||
* ipr_read_dump - Dump the adapter
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
* @off: offset
|
||||
* @count: buffer size
|
||||
|
@ -3173,8 +3176,9 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_read_dump(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t ipr_read_dump(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
|
@ -3327,6 +3331,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
|
|||
/**
|
||||
* ipr_write_dump - Setup dump state of adapter
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
* @off: offset
|
||||
* @count: buffer size
|
||||
|
@ -3334,8 +3339,9 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_write_dump(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t ipr_write_dump(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
|
||||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
|
|
|
@ -38,8 +38,10 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
|
|||
|
||||
#if 0
|
||||
/* FIXME: smp needs to migrate into the sas class */
|
||||
static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
|
||||
static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
|
||||
static ssize_t smp_portal_read(struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
static ssize_t smp_portal_write(struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
#endif
|
||||
|
||||
/* ---------- SMP task management ---------- */
|
||||
|
@ -1368,7 +1370,6 @@ static void sas_ex_smp_hook(struct domain_device *dev)
|
|||
memset(bin_attr, 0, sizeof(*bin_attr));
|
||||
|
||||
bin_attr->attr.name = SMP_BIN_ATTR_NAME;
|
||||
bin_attr->attr.owner = THIS_MODULE;
|
||||
bin_attr->attr.mode = 0600;
|
||||
|
||||
bin_attr->size = 0;
|
||||
|
@ -1846,8 +1847,9 @@ out:
|
|||
#if 0
|
||||
/* ---------- SMP portal ---------- */
|
||||
|
||||
static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
|
||||
size_t size)
|
||||
static ssize_t smp_portal_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t offs, size_t size)
|
||||
{
|
||||
struct domain_device *dev = to_dom_device(kobj);
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
|
@ -1873,8 +1875,9 @@ static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
|
||||
size_t size)
|
||||
static ssize_t smp_portal_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t offs, size_t size)
|
||||
{
|
||||
struct domain_device *dev = to_dom_device(kobj);
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
|
|
|
@ -1133,7 +1133,8 @@ struct class_device_attribute *lpfc_host_attrs[] = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t buf_off;
|
||||
struct Scsi_Host *host = class_to_shost(container_of(kobj,
|
||||
|
@ -1165,7 +1166,8 @@ sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t buf_off;
|
||||
uint32_t * tmp_ptr;
|
||||
|
@ -1200,7 +1202,6 @@ static struct bin_attribute sysfs_ctlreg_attr = {
|
|||
.attr = {
|
||||
.name = "ctlreg",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 256,
|
||||
.read = sysfs_ctlreg_read,
|
||||
|
@ -1222,7 +1223,8 @@ sysfs_mbox_idle (struct lpfc_hba * phba)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct Scsi_Host * host =
|
||||
class_to_shost(container_of(kobj, struct class_device, kobj));
|
||||
|
@ -1274,7 +1276,8 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct Scsi_Host *host =
|
||||
class_to_shost(container_of(kobj, struct class_device,
|
||||
|
@ -1422,7 +1425,6 @@ static struct bin_attribute sysfs_mbox_attr = {
|
|||
.attr = {
|
||||
.name = "mbox",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = MAILBOX_CMD_SIZE,
|
||||
.read = sysfs_mbox_read,
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
/* SYSFS attributes --------------------------------------------------------- */
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -31,8 +32,9 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -73,7 +75,6 @@ static struct bin_attribute sysfs_fw_dump_attr = {
|
|||
.attr = {
|
||||
.name = "fw_dump",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 0,
|
||||
.read = qla2x00_sysfs_read_fw_dump,
|
||||
|
@ -81,8 +82,9 @@ static struct bin_attribute sysfs_fw_dump_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_read_nvram(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -101,8 +103,9 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_write_nvram(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -149,7 +152,6 @@ static struct bin_attribute sysfs_nvram_attr = {
|
|||
.attr = {
|
||||
.name = "nvram",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 512,
|
||||
.read = qla2x00_sysfs_read_nvram,
|
||||
|
@ -157,8 +159,9 @@ static struct bin_attribute sysfs_nvram_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_read_optrom(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -176,8 +179,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_optrom(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_write_optrom(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -198,7 +202,6 @@ static struct bin_attribute sysfs_optrom_attr = {
|
|||
.attr = {
|
||||
.name = "optrom",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = OPTROM_SIZE_24XX,
|
||||
.read = qla2x00_sysfs_read_optrom,
|
||||
|
@ -206,8 +209,9 @@ static struct bin_attribute sysfs_optrom_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -279,15 +283,15 @@ static struct bin_attribute sysfs_optrom_ctl_attr = {
|
|||
.attr = {
|
||||
.name = "optrom_ctl",
|
||||
.mode = S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 0,
|
||||
.write = qla2x00_sysfs_write_optrom_ctl,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_read_vpd(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -305,8 +309,9 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_write_vpd(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -327,7 +332,6 @@ static struct bin_attribute sysfs_vpd_attr = {
|
|||
.attr = {
|
||||
.name = "vpd",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 0,
|
||||
.read = qla2x00_sysfs_read_vpd,
|
||||
|
@ -335,8 +339,9 @@ static struct bin_attribute sysfs_vpd_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
qla2x00_sysfs_read_sfp(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
|
@ -375,7 +380,6 @@ static struct bin_attribute sysfs_sfp_attr = {
|
|||
.attr = {
|
||||
.name = "sfp",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = SFP_DEV_SIZE * 2,
|
||||
.read = qla2x00_sysfs_read_sfp,
|
||||
|
|
|
@ -111,7 +111,8 @@ at25_ee_read(
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
at25_bin_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev;
|
||||
struct at25_data *at25;
|
||||
|
@ -236,7 +237,8 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
at25_bin_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev;
|
||||
struct at25_data *at25;
|
||||
|
@ -314,7 +316,6 @@ static int at25_probe(struct spi_device *spi)
|
|||
*/
|
||||
at25->bin.attr.name = "eeprom";
|
||||
at25->bin.attr.mode = S_IRUSR;
|
||||
at25->bin.attr.owner = THIS_MODULE;
|
||||
at25->bin.read = at25_bin_read;
|
||||
|
||||
at25->bin.size = at25->chip.byte_len;
|
||||
|
|
|
@ -1109,11 +1109,6 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
|
|||
|
||||
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
|
||||
|
||||
/* Make sure no potential wakeup events get lost,
|
||||
* by forcing the root hub to be resumed.
|
||||
*/
|
||||
rhdev->dev.power.prev_state.event = PM_EVENT_ON;
|
||||
|
||||
spin_lock_irqsave(&device_state_lock, flags);
|
||||
hub = hdev_to_hub(rhdev);
|
||||
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
|
||||
|
|
|
@ -2102,7 +2102,9 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u
|
|||
}
|
||||
|
||||
|
||||
static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t radeon_show_edid1(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
@ -2113,7 +2115,9 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, si
|
|||
}
|
||||
|
||||
|
||||
static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t radeon_show_edid2(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
@ -2126,7 +2130,6 @@ static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, si
|
|||
static struct bin_attribute edid1_attr = {
|
||||
.attr = {
|
||||
.name = "edid1",
|
||||
.owner = THIS_MODULE,
|
||||
.mode = 0444,
|
||||
},
|
||||
.size = EDID_LENGTH,
|
||||
|
@ -2136,7 +2139,6 @@ static struct bin_attribute edid1_attr = {
|
|||
static struct bin_attribute edid2_attr = {
|
||||
.attr = {
|
||||
.name = "edid2",
|
||||
.owner = THIS_MODULE,
|
||||
.mode = 0444,
|
||||
},
|
||||
.size = EDID_LENGTH,
|
||||
|
|
|
@ -172,7 +172,7 @@ static struct class backlight_class = {
|
|||
|
||||
#define DECLARE_ATTR(_name,_mode,_show,_store) \
|
||||
{ \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ static struct class lcd_class = {
|
|||
|
||||
#define DECLARE_ATTR(_name,_mode,_show,_store) \
|
||||
{ \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
}
|
||||
|
|
|
@ -91,8 +91,9 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
|
|||
}
|
||||
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
|
||||
|
||||
static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
static ssize_t w1_f23_read_bin(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
|
||||
|
@ -199,8 +200,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
static ssize_t w1_f23_write_bin(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
int addr, len, idx;
|
||||
|
@ -252,7 +254,6 @@ static struct bin_attribute w1_f23_bin_attr = {
|
|||
.attr = {
|
||||
.name = "eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = W1_EEPROM_SIZE,
|
||||
.read = w1_f23_read_bin,
|
||||
|
|
|
@ -42,13 +42,13 @@ static u8 bad_roms[][9] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
|
||||
static ssize_t w1_therm_read_bin(struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
|
||||
static struct bin_attribute w1_therm_bin_attr = {
|
||||
.attr = {
|
||||
.name = "w1_slave",
|
||||
.mode = S_IRUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = W1_SLAVE_DATA_SIZE,
|
||||
.read = w1_therm_read_bin,
|
||||
|
@ -159,7 +159,9 @@ static int w1_therm_check_rom(u8 rom[9])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t w1_therm_read_bin(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
struct w1_master *dev = sl->master;
|
||||
|
|
|
@ -105,7 +105,9 @@ static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *a
|
|||
return sprintf(buf, "%s\n", sl->name);
|
||||
}
|
||||
|
||||
static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t w1_slave_read_id(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
|
||||
|
@ -128,7 +130,6 @@ static struct bin_attribute w1_slave_attr_bin_id = {
|
|||
.attr = {
|
||||
.name = "id",
|
||||
.mode = S_IRUGO,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = 8,
|
||||
.read = w1_slave_read_id,
|
||||
|
@ -136,7 +137,9 @@ static struct bin_attribute w1_slave_attr_bin_id = {
|
|||
|
||||
/* Default family */
|
||||
|
||||
static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t w1_default_write(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
|
||||
|
@ -153,7 +156,9 @@ out_up:
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
static ssize_t w1_default_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
|
||||
|
@ -167,7 +172,6 @@ static struct bin_attribute w1_default_attr = {
|
|||
.attr = {
|
||||
.name = "rw",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = PAGE_SIZE,
|
||||
.read = w1_default_read,
|
||||
|
|
|
@ -49,8 +49,9 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *
|
|||
|
||||
static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL);
|
||||
|
||||
static ssize_t zorro_read_config(struct kobject *kobj, char *buf, loff_t off,
|
||||
size_t count)
|
||||
static ssize_t zorro_read_config(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device,
|
||||
kobj));
|
||||
|
@ -78,7 +79,6 @@ static struct bin_attribute zorro_config_attr = {
|
|||
.attr = {
|
||||
.name = "config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE
|
||||
},
|
||||
.size = sizeof(struct ConfigDev),
|
||||
.read = zorro_read_config,
|
||||
|
|
|
@ -368,6 +368,69 @@ void debugfs_remove(struct dentry *dentry)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_remove);
|
||||
|
||||
/**
|
||||
* debugfs_rename - rename a file/directory in the debugfs filesystem
|
||||
* @old_dir: a pointer to the parent dentry for the renamed object. This
|
||||
* should be a directory dentry.
|
||||
* @old_dentry: dentry of an object to be renamed.
|
||||
* @new_dir: a pointer to the parent dentry where the object should be
|
||||
* moved. This should be a directory dentry.
|
||||
* @new_name: a pointer to a string containing the target name.
|
||||
*
|
||||
* This function renames a file/directory in debugfs. The target must not
|
||||
* exist for rename to succeed.
|
||||
*
|
||||
* This function will return a pointer to old_dentry (which is updated to
|
||||
* reflect renaming) if it succeeds. If an error occurs, %NULL will be
|
||||
* returned.
|
||||
*
|
||||
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
|
||||
* returned.
|
||||
*/
|
||||
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *new_dir, const char *new_name)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry = NULL, *trap;
|
||||
const char *old_name;
|
||||
|
||||
trap = lock_rename(new_dir, old_dir);
|
||||
/* Source or destination directories don't exist? */
|
||||
if (!old_dir->d_inode || !new_dir->d_inode)
|
||||
goto exit;
|
||||
/* Source does not exist, cyclic rename, or mountpoint? */
|
||||
if (!old_dentry->d_inode || old_dentry == trap ||
|
||||
d_mountpoint(old_dentry))
|
||||
goto exit;
|
||||
dentry = lookup_one_len(new_name, new_dir, strlen(new_name));
|
||||
/* Lookup failed, cyclic rename or target exists? */
|
||||
if (IS_ERR(dentry) || dentry == trap || dentry->d_inode)
|
||||
goto exit;
|
||||
|
||||
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
||||
|
||||
error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode,
|
||||
dentry);
|
||||
if (error) {
|
||||
fsnotify_oldname_free(old_name);
|
||||
goto exit;
|
||||
}
|
||||
d_move(old_dentry, dentry);
|
||||
fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,
|
||||
old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode),
|
||||
NULL, old_dentry->d_inode);
|
||||
fsnotify_oldname_free(old_name);
|
||||
unlock_rename(new_dir, old_dir);
|
||||
dput(dentry);
|
||||
return old_dentry;
|
||||
exit:
|
||||
if (dentry && !IS_ERR(dentry))
|
||||
dput(dentry);
|
||||
unlock_rename(new_dir, old_dir);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_rename);
|
||||
|
||||
static decl_subsys(debug, NULL, NULL);
|
||||
|
||||
static int __init debugfs_init(void)
|
||||
|
|
|
@ -840,8 +840,6 @@ static int __init ecryptfs_init(void)
|
|||
goto out;
|
||||
}
|
||||
kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
|
||||
sysfs_attr_version.attr.owner = THIS_MODULE;
|
||||
sysfs_attr_version_str.attr.owner = THIS_MODULE;
|
||||
rc = do_sysfs_registration();
|
||||
if (rc) {
|
||||
printk(KERN_ERR "sysfs registration failed\n");
|
||||
|
|
|
@ -74,7 +74,6 @@ struct mlog_attribute {
|
|||
#define define_mask(_name) { \
|
||||
.attr = { \
|
||||
.name = #_name, \
|
||||
.owner = THIS_MODULE, \
|
||||
.mode = S_IRUGO | S_IWUSR, \
|
||||
}, \
|
||||
.mask = ML_##_name, \
|
||||
|
|
|
@ -397,7 +397,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
|
|||
static struct attribute addpartattr = {
|
||||
.name = "whole_disk",
|
||||
.mode = S_IRUSR | S_IRGRP | S_IROTH,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
sysfs_create_file(&p->kobj, &addpartattr);
|
||||
|
|
189
fs/sysfs/bin.c
189
fs/sysfs/bin.c
|
@ -20,29 +20,41 @@
|
|||
|
||||
#include "sysfs.h"
|
||||
|
||||
struct bin_buffer {
|
||||
struct mutex mutex;
|
||||
void *buffer;
|
||||
int mmapped;
|
||||
};
|
||||
|
||||
static int
|
||||
fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
|
||||
{
|
||||
struct bin_attribute * attr = to_bin_attr(dentry);
|
||||
struct kobject * kobj = to_kobj(dentry->d_parent);
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
int rc;
|
||||
|
||||
if (!attr->read)
|
||||
return -EIO;
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
return attr->read(kobj, buffer, off, count);
|
||||
rc = -EIO;
|
||||
if (attr->read)
|
||||
rc = attr->read(kobj, attr, buffer, off, count);
|
||||
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
||||
read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
|
||||
{
|
||||
char *buffer = file->private_data;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int size = dentry->d_inode->i_size;
|
||||
loff_t offs = *off;
|
||||
int ret;
|
||||
|
||||
if (count > PAGE_SIZE)
|
||||
count = PAGE_SIZE;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
|
||||
if (size) {
|
||||
if (offs > size)
|
||||
|
@ -51,43 +63,56 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
|||
count = size - offs;
|
||||
}
|
||||
|
||||
ret = fill_read(dentry, buffer, offs, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
count = ret;
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
if (copy_to_user(userbuf, buffer, count))
|
||||
return -EFAULT;
|
||||
count = fill_read(dentry, bb->buffer, offs, count);
|
||||
if (count < 0)
|
||||
goto out_unlock;
|
||||
|
||||
pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
|
||||
if (copy_to_user(userbuf, bb->buffer, count)) {
|
||||
count = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
|
||||
|
||||
*off = offs + count;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&bb->mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
struct bin_attribute *attr = to_bin_attr(dentry);
|
||||
struct kobject *kobj = to_kobj(dentry->d_parent);
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
int rc;
|
||||
|
||||
if (!attr->write)
|
||||
return -EIO;
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
return attr->write(kobj, buffer, offset, count);
|
||||
rc = -EIO;
|
||||
if (attr->write)
|
||||
rc = attr->write(kobj, attr, buffer, offset, count);
|
||||
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t write(struct file * file, const char __user * userbuf,
|
||||
size_t count, loff_t * off)
|
||||
static ssize_t write(struct file *file, const char __user *userbuf,
|
||||
size_t bytes, loff_t *off)
|
||||
{
|
||||
char *buffer = file->private_data;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int size = dentry->d_inode->i_size;
|
||||
loff_t offs = *off;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
|
||||
if (count > PAGE_SIZE)
|
||||
count = PAGE_SIZE;
|
||||
if (size) {
|
||||
if (offs > size)
|
||||
return 0;
|
||||
|
@ -95,72 +120,100 @@ static ssize_t write(struct file * file, const char __user * userbuf,
|
|||
count = size - offs;
|
||||
}
|
||||
|
||||
if (copy_from_user(buffer, userbuf, count))
|
||||
return -EFAULT;
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
count = flush_write(dentry, buffer, offs, count);
|
||||
if (copy_from_user(bb->buffer, userbuf, count)) {
|
||||
count = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
count = flush_write(dentry, bb->buffer, offs, count);
|
||||
if (count > 0)
|
||||
*off = offs + count;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&bb->mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct bin_attribute *attr = to_bin_attr(dentry);
|
||||
struct kobject *kobj = to_kobj(dentry->d_parent);
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
int rc;
|
||||
|
||||
if (!attr->mmap)
|
||||
return -EINVAL;
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
return attr->mmap(kobj, attr, vma);
|
||||
/* need attr_sd for attr, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
rc = -EINVAL;
|
||||
if (attr->mmap)
|
||||
rc = attr->mmap(kobj, attr, vma);
|
||||
|
||||
if (rc == 0 && !bb->mmapped)
|
||||
bb->mmapped = 1;
|
||||
else
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
mutex_unlock(&bb->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int open(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
|
||||
struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
|
||||
int error = -EINVAL;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
|
||||
struct bin_buffer *bb = NULL;
|
||||
int error;
|
||||
|
||||
if (!kobj || !attr)
|
||||
goto Done;
|
||||
|
||||
/* Grab the module reference for this attribute if we have one */
|
||||
error = -ENODEV;
|
||||
if (!try_module_get(attr->attr.owner))
|
||||
goto Done;
|
||||
/* need attr_sd for attr */
|
||||
if (!sysfs_get_active(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
error = -EACCES;
|
||||
if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
|
||||
goto Error;
|
||||
goto err_out;
|
||||
if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
|
||||
goto Error;
|
||||
goto err_out;
|
||||
|
||||
error = -ENOMEM;
|
||||
file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!file->private_data)
|
||||
goto Error;
|
||||
bb = kzalloc(sizeof(*bb), GFP_KERNEL);
|
||||
if (!bb)
|
||||
goto err_out;
|
||||
|
||||
error = 0;
|
||||
goto Done;
|
||||
bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!bb->buffer)
|
||||
goto err_out;
|
||||
|
||||
Error:
|
||||
module_put(attr->attr.owner);
|
||||
Done:
|
||||
if (error)
|
||||
kobject_put(kobj);
|
||||
mutex_init(&bb->mutex);
|
||||
file->private_data = bb;
|
||||
|
||||
/* open succeeded, put active reference and pin attr_sd */
|
||||
sysfs_put_active(attr_sd);
|
||||
sysfs_get(attr_sd);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
sysfs_put_active(attr_sd);
|
||||
kfree(bb);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int release(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
|
||||
struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
|
||||
u8 * buffer = file->private_data;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
|
||||
kobject_put(kobj);
|
||||
module_put(attr->attr.owner);
|
||||
kfree(buffer);
|
||||
if (bb->mmapped)
|
||||
sysfs_put_active_two(attr_sd);
|
||||
sysfs_put(attr_sd);
|
||||
kfree(bb->buffer);
|
||||
kfree(bb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -181,9 +234,9 @@ const struct file_operations bin_fops = {
|
|||
|
||||
int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
|
||||
{
|
||||
BUG_ON(!kobj || !kobj->dentry || !attr);
|
||||
BUG_ON(!kobj || !kobj->sd || !attr);
|
||||
|
||||
return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
|
||||
return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,7 +248,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
|
|||
|
||||
void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
|
||||
{
|
||||
if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
|
||||
if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) {
|
||||
printk(KERN_ERR "%s: "
|
||||
"bad dentry or inode or no such file: \"%s\"\n",
|
||||
__FUNCTION__, attr->attr.name);
|
||||
|
|
1357
fs/sysfs/dir.c
1357
fs/sysfs/dir.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
369
fs/sysfs/file.c
369
fs/sysfs/file.c
|
@ -50,29 +50,15 @@ static struct sysfs_ops subsys_sysfs_ops = {
|
|||
.store = subsys_attr_store,
|
||||
};
|
||||
|
||||
/**
|
||||
* add_to_collection - add buffer to a collection
|
||||
* @buffer: buffer to be added
|
||||
* @node: inode of set to add to
|
||||
*/
|
||||
|
||||
static inline void
|
||||
add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
|
||||
{
|
||||
struct sysfs_buffer_collection *set = node->i_private;
|
||||
|
||||
mutex_lock(&node->i_mutex);
|
||||
list_add(&buffer->associates, &set->associates);
|
||||
mutex_unlock(&node->i_mutex);
|
||||
}
|
||||
|
||||
static inline void
|
||||
remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
|
||||
{
|
||||
mutex_lock(&node->i_mutex);
|
||||
list_del(&buffer->associates);
|
||||
mutex_unlock(&node->i_mutex);
|
||||
}
|
||||
struct sysfs_buffer {
|
||||
size_t count;
|
||||
loff_t pos;
|
||||
char * page;
|
||||
struct sysfs_ops * ops;
|
||||
struct semaphore sem;
|
||||
int needs_read_fill;
|
||||
int event;
|
||||
};
|
||||
|
||||
/**
|
||||
* fill_read_buffer - allocate and fill buffer from object.
|
||||
|
@ -87,9 +73,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
|
|||
*/
|
||||
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
|
||||
{
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
struct attribute * attr = to_attr(dentry);
|
||||
struct kobject * kobj = to_kobj(dentry->d_parent);
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
struct sysfs_ops * ops = buffer->ops;
|
||||
int ret = 0;
|
||||
ssize_t count;
|
||||
|
@ -99,8 +84,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
|
|||
if (!buffer->page)
|
||||
return -ENOMEM;
|
||||
|
||||
buffer->event = atomic_read(&sd->s_event);
|
||||
count = ops->show(kobj,attr,buffer->page);
|
||||
/* need attr_sd for attr and ops, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
buffer->event = atomic_read(&attr_sd->s_event);
|
||||
count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
|
||||
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
BUG_ON(count > (ssize_t)PAGE_SIZE);
|
||||
if (count >= 0) {
|
||||
buffer->needs_read_fill = 0;
|
||||
|
@ -138,10 +130,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
|
||||
down(&buffer->sem);
|
||||
if (buffer->needs_read_fill) {
|
||||
if (buffer->orphaned)
|
||||
retval = -ENODEV;
|
||||
else
|
||||
retval = fill_read_buffer(file->f_path.dentry,buffer);
|
||||
retval = fill_read_buffer(file->f_path.dentry,buffer);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
|
@ -199,11 +188,20 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
|
|||
static int
|
||||
flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
|
||||
{
|
||||
struct attribute * attr = to_attr(dentry);
|
||||
struct kobject * kobj = to_kobj(dentry->d_parent);
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
struct sysfs_ops * ops = buffer->ops;
|
||||
int rc;
|
||||
|
||||
return ops->store(kobj,attr,buffer->page,count);
|
||||
/* need attr_sd for attr and ops, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
|
||||
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,37 +229,26 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
|
|||
ssize_t len;
|
||||
|
||||
down(&buffer->sem);
|
||||
if (buffer->orphaned) {
|
||||
len = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
len = fill_write_buffer(buffer, buf, count);
|
||||
if (len > 0)
|
||||
len = flush_write_buffer(file->f_path.dentry, buffer, len);
|
||||
if (len > 0)
|
||||
*ppos += len;
|
||||
out:
|
||||
up(&buffer->sem);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int sysfs_open_file(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
|
||||
struct attribute * attr = to_attr(file->f_path.dentry);
|
||||
struct sysfs_buffer_collection *set;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
struct sysfs_buffer * buffer;
|
||||
struct sysfs_ops * ops = NULL;
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
if (!kobj || !attr)
|
||||
goto Einval;
|
||||
|
||||
/* Grab the module reference for this attribute if we have one */
|
||||
if (!try_module_get(attr->owner)) {
|
||||
error = -ENODEV;
|
||||
goto Done;
|
||||
}
|
||||
/* need attr_sd for attr and ops, its parent for kobj */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
return -ENODEV;
|
||||
|
||||
/* if the kobject has no ktype, then we assume that it is a subsystem
|
||||
* itself, and use ops for it.
|
||||
|
@ -273,33 +260,21 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
|
|||
else
|
||||
ops = &subsys_sysfs_ops;
|
||||
|
||||
error = -EACCES;
|
||||
|
||||
/* No sysfs operations, either from having no subsystem,
|
||||
* or the subsystem have no operations.
|
||||
*/
|
||||
if (!ops)
|
||||
goto Eaccess;
|
||||
|
||||
/* make sure we have a collection to add our buffers to */
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (!(set = inode->i_private)) {
|
||||
if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
|
||||
error = -ENOMEM;
|
||||
goto Done;
|
||||
} else {
|
||||
INIT_LIST_HEAD(&set->associates);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
goto err_out;
|
||||
|
||||
/* File needs write support.
|
||||
* The inode's perms must say it's ok,
|
||||
* and we must have a store method.
|
||||
*/
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
|
||||
if (!(inode->i_mode & S_IWUGO) || !ops->store)
|
||||
goto Eaccess;
|
||||
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* File needs read support.
|
||||
|
@ -308,48 +283,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
|
|||
*/
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
if (!(inode->i_mode & S_IRUGO) || !ops->show)
|
||||
goto Eaccess;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* No error? Great, allocate a buffer for the file, and store it
|
||||
* it in file->private_data for easy access.
|
||||
*/
|
||||
error = -ENOMEM;
|
||||
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
|
||||
if (buffer) {
|
||||
INIT_LIST_HEAD(&buffer->associates);
|
||||
init_MUTEX(&buffer->sem);
|
||||
buffer->needs_read_fill = 1;
|
||||
buffer->ops = ops;
|
||||
add_to_collection(buffer, inode);
|
||||
file->private_data = buffer;
|
||||
} else
|
||||
error = -ENOMEM;
|
||||
goto Done;
|
||||
if (!buffer)
|
||||
goto err_out;
|
||||
|
||||
Einval:
|
||||
error = -EINVAL;
|
||||
goto Done;
|
||||
Eaccess:
|
||||
error = -EACCES;
|
||||
module_put(attr->owner);
|
||||
Done:
|
||||
if (error)
|
||||
kobject_put(kobj);
|
||||
init_MUTEX(&buffer->sem);
|
||||
buffer->needs_read_fill = 1;
|
||||
buffer->ops = ops;
|
||||
file->private_data = buffer;
|
||||
|
||||
/* open succeeded, put active references and pin attr_sd */
|
||||
sysfs_put_active_two(attr_sd);
|
||||
sysfs_get(attr_sd);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
sysfs_put_active_two(attr_sd);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int sysfs_release(struct inode * inode, struct file * filp)
|
||||
{
|
||||
struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
|
||||
struct attribute * attr = to_attr(filp->f_path.dentry);
|
||||
struct module * owner = attr->owner;
|
||||
struct sysfs_buffer * buffer = filp->private_data;
|
||||
struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
|
||||
struct sysfs_buffer *buffer = filp->private_data;
|
||||
|
||||
if (buffer)
|
||||
remove_from_collection(buffer, inode);
|
||||
kobject_put(kobj);
|
||||
/* After this point, attr should not be accessed. */
|
||||
module_put(owner);
|
||||
sysfs_put(attr_sd);
|
||||
|
||||
if (buffer) {
|
||||
if (buffer->page)
|
||||
|
@ -376,57 +341,43 @@ static int sysfs_release(struct inode * inode, struct file * filp)
|
|||
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct sysfs_buffer * buffer = filp->private_data;
|
||||
struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
|
||||
struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata;
|
||||
int res = 0;
|
||||
struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
|
||||
|
||||
/* need parent for the kobj, grab both */
|
||||
if (!sysfs_get_active_two(attr_sd))
|
||||
goto trigger;
|
||||
|
||||
poll_wait(filp, &kobj->poll, wait);
|
||||
|
||||
if (buffer->event != atomic_read(&sd->s_event)) {
|
||||
res = POLLERR|POLLPRI;
|
||||
buffer->needs_read_fill = 1;
|
||||
}
|
||||
sysfs_put_active_two(attr_sd);
|
||||
|
||||
return res;
|
||||
if (buffer->event != atomic_read(&attr_sd->s_event))
|
||||
goto trigger;
|
||||
|
||||
return 0;
|
||||
|
||||
trigger:
|
||||
buffer->needs_read_fill = 1;
|
||||
return POLLERR|POLLPRI;
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *step_down(struct dentry *dir, const char * name)
|
||||
void sysfs_notify(struct kobject *k, char *dir, char *attr)
|
||||
{
|
||||
struct dentry * de;
|
||||
struct sysfs_dirent *sd = k->sd;
|
||||
|
||||
if (dir == NULL || dir->d_inode == NULL)
|
||||
return NULL;
|
||||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
de = lookup_one_len(name, dir, strlen(name));
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
dput(dir);
|
||||
if (IS_ERR(de))
|
||||
return NULL;
|
||||
if (de->d_inode == NULL) {
|
||||
dput(de);
|
||||
return NULL;
|
||||
}
|
||||
return de;
|
||||
}
|
||||
|
||||
void sysfs_notify(struct kobject * k, char *dir, char *attr)
|
||||
{
|
||||
struct dentry *de = k->dentry;
|
||||
if (de)
|
||||
dget(de);
|
||||
if (de && dir)
|
||||
de = step_down(de, dir);
|
||||
if (de && attr)
|
||||
de = step_down(de, attr);
|
||||
if (de) {
|
||||
struct sysfs_dirent * sd = de->d_fsdata;
|
||||
if (sd)
|
||||
atomic_inc(&sd->s_event);
|
||||
if (sd && dir)
|
||||
sd = sysfs_find_dirent(sd, dir);
|
||||
if (sd && attr)
|
||||
sd = sysfs_find_dirent(sd, attr);
|
||||
if (sd) {
|
||||
atomic_inc(&sd->s_event);
|
||||
wake_up_interruptible(&k->poll);
|
||||
dput(de);
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_notify);
|
||||
|
||||
|
@ -440,19 +391,30 @@ const struct file_operations sysfs_file_operations = {
|
|||
};
|
||||
|
||||
|
||||
int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
|
||||
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
|
||||
int type)
|
||||
{
|
||||
struct sysfs_dirent * parent_sd = dir->d_fsdata;
|
||||
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
|
||||
int error = -EEXIST;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
if (!sysfs_dirent_exist(parent_sd, attr->name))
|
||||
error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
|
||||
mode, type);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
sd = sysfs_new_dirent(attr->name, mode, type);
|
||||
if (!sd)
|
||||
return -ENOMEM;
|
||||
sd->s_elem.attr.attr = (void *)attr;
|
||||
|
||||
return error;
|
||||
sysfs_addrm_start(&acxt, dir_sd);
|
||||
|
||||
if (!sysfs_find_dirent(dir_sd, attr->name)) {
|
||||
sysfs_add_one(&acxt, sd);
|
||||
sysfs_link_sibling(sd);
|
||||
}
|
||||
|
||||
if (sysfs_addrm_finish(&acxt))
|
||||
return 0;
|
||||
|
||||
sysfs_put(sd);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
|
||||
|
@ -464,9 +426,9 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
|
|||
|
||||
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
|
||||
{
|
||||
BUG_ON(!kobj || !kobj->dentry || !attr);
|
||||
BUG_ON(!kobj || !kobj->sd || !attr);
|
||||
|
||||
return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR);
|
||||
return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
|
||||
|
||||
}
|
||||
|
||||
|
@ -480,16 +442,16 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
|
|||
int sysfs_add_file_to_group(struct kobject *kobj,
|
||||
const struct attribute *attr, const char *group)
|
||||
{
|
||||
struct dentry *dir;
|
||||
struct sysfs_dirent *dir_sd;
|
||||
int error;
|
||||
|
||||
dir = lookup_one_len(group, kobj->dentry, strlen(group));
|
||||
if (IS_ERR(dir))
|
||||
error = PTR_ERR(dir);
|
||||
else {
|
||||
error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR);
|
||||
dput(dir);
|
||||
}
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group);
|
||||
if (!dir_sd)
|
||||
return -ENOENT;
|
||||
|
||||
error = sysfs_add_file(dir_sd, attr, SYSFS_KOBJ_ATTR);
|
||||
sysfs_put(dir_sd);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
|
||||
|
@ -502,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
|
|||
*/
|
||||
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
|
||||
{
|
||||
struct dentry * dir = kobj->dentry;
|
||||
struct dentry * victim;
|
||||
int res = -ENOENT;
|
||||
struct sysfs_dirent *victim_sd = NULL;
|
||||
struct dentry *victim = NULL;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
victim = lookup_one_len(attr->name, dir, strlen(attr->name));
|
||||
if (!IS_ERR(victim)) {
|
||||
/* make sure dentry is really there */
|
||||
if (victim->d_inode &&
|
||||
(victim->d_parent->d_inode == dir->d_inode)) {
|
||||
victim->d_inode->i_mtime = CURRENT_TIME;
|
||||
fsnotify_modify(victim);
|
||||
res = 0;
|
||||
} else
|
||||
d_drop(victim);
|
||||
rc = -ENOENT;
|
||||
victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
|
||||
if (!victim_sd)
|
||||
goto out;
|
||||
|
||||
/**
|
||||
* Drop the reference acquired from lookup_one_len() above.
|
||||
*/
|
||||
dput(victim);
|
||||
victim = sysfs_get_dentry(victim_sd);
|
||||
if (IS_ERR(victim)) {
|
||||
rc = PTR_ERR(victim);
|
||||
victim = NULL;
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
|
||||
return res;
|
||||
mutex_lock(&victim->d_inode->i_mutex);
|
||||
victim->d_inode->i_mtime = CURRENT_TIME;
|
||||
fsnotify_modify(victim);
|
||||
mutex_unlock(&victim->d_inode->i_mutex);
|
||||
rc = 0;
|
||||
out:
|
||||
dput(victim);
|
||||
sysfs_put(victim_sd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -538,30 +501,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
|
|||
*/
|
||||
int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
|
||||
{
|
||||
struct dentry *dir = kobj->dentry;
|
||||
struct dentry *victim;
|
||||
struct sysfs_dirent *victim_sd = NULL;
|
||||
struct dentry *victim = NULL;
|
||||
struct inode * inode;
|
||||
struct iattr newattrs;
|
||||
int res = -ENOENT;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
victim = lookup_one_len(attr->name, dir, strlen(attr->name));
|
||||
if (!IS_ERR(victim)) {
|
||||
if (victim->d_inode &&
|
||||
(victim->d_parent->d_inode == dir->d_inode)) {
|
||||
inode = victim->d_inode;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) |
|
||||
(inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
res = notify_change(victim, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
}
|
||||
dput(victim);
|
||||
rc = -ENOENT;
|
||||
victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
|
||||
if (!victim_sd)
|
||||
goto out;
|
||||
|
||||
victim = sysfs_get_dentry(victim_sd);
|
||||
if (IS_ERR(victim)) {
|
||||
rc = PTR_ERR(victim);
|
||||
victim = NULL;
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
|
||||
return res;
|
||||
inode = victim->d_inode;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
rc = notify_change(victim, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
out:
|
||||
dput(victim);
|
||||
sysfs_put(victim_sd);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_chmod_file);
|
||||
|
||||
|
@ -576,7 +543,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
|
|||
|
||||
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
|
||||
{
|
||||
sysfs_hash_and_remove(kobj->dentry, attr->name);
|
||||
sysfs_hash_and_remove(kobj->sd, attr->name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -589,12 +556,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
|
|||
void sysfs_remove_file_from_group(struct kobject *kobj,
|
||||
const struct attribute *attr, const char *group)
|
||||
{
|
||||
struct dentry *dir;
|
||||
struct sysfs_dirent *dir_sd;
|
||||
|
||||
dir = lookup_one_len(group, kobj->dentry, strlen(group));
|
||||
if (!IS_ERR(dir)) {
|
||||
sysfs_hash_and_remove(dir, attr->name);
|
||||
dput(dir);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group);
|
||||
if (dir_sd) {
|
||||
sysfs_hash_and_remove(dir_sd, attr->name);
|
||||
sysfs_put(dir_sd);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
|
||||
|
|
|
@ -18,26 +18,25 @@
|
|||
#include "sysfs.h"
|
||||
|
||||
|
||||
static void remove_files(struct dentry * dir,
|
||||
const struct attribute_group * grp)
|
||||
static void remove_files(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
struct attribute *const* attr;
|
||||
|
||||
for (attr = grp->attrs; *attr; attr++)
|
||||
sysfs_hash_and_remove(dir,(*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
}
|
||||
|
||||
static int create_files(struct dentry * dir,
|
||||
const struct attribute_group * grp)
|
||||
static int create_files(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
struct attribute *const* attr;
|
||||
int error = 0;
|
||||
|
||||
for (attr = grp->attrs; *attr && !error; attr++) {
|
||||
error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
|
||||
}
|
||||
for (attr = grp->attrs; *attr && !error; attr++)
|
||||
error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
|
||||
if (error)
|
||||
remove_files(dir,grp);
|
||||
remove_files(dir_sd, grp);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -45,44 +44,44 @@ static int create_files(struct dentry * dir,
|
|||
int sysfs_create_group(struct kobject * kobj,
|
||||
const struct attribute_group * grp)
|
||||
{
|
||||
struct dentry * dir;
|
||||
struct sysfs_dirent *sd;
|
||||
int error;
|
||||
|
||||
BUG_ON(!kobj || !kobj->dentry);
|
||||
BUG_ON(!kobj || !kobj->sd);
|
||||
|
||||
if (grp->name) {
|
||||
error = sysfs_create_subdir(kobj,grp->name,&dir);
|
||||
error = sysfs_create_subdir(kobj, grp->name, &sd);
|
||||
if (error)
|
||||
return error;
|
||||
} else
|
||||
dir = kobj->dentry;
|
||||
dir = dget(dir);
|
||||
if ((error = create_files(dir,grp))) {
|
||||
sd = kobj->sd;
|
||||
sysfs_get(sd);
|
||||
error = create_files(sd, grp);
|
||||
if (error) {
|
||||
if (grp->name)
|
||||
sysfs_remove_subdir(dir);
|
||||
sysfs_remove_subdir(sd);
|
||||
}
|
||||
dput(dir);
|
||||
sysfs_put(sd);
|
||||
return error;
|
||||
}
|
||||
|
||||
void sysfs_remove_group(struct kobject * kobj,
|
||||
const struct attribute_group * grp)
|
||||
{
|
||||
struct dentry * dir;
|
||||
struct sysfs_dirent *dir_sd = kobj->sd;
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (grp->name) {
|
||||
dir = lookup_one_len_kern(grp->name, kobj->dentry,
|
||||
strlen(grp->name));
|
||||
BUG_ON(IS_ERR(dir));
|
||||
}
|
||||
else
|
||||
dir = dget(kobj->dentry);
|
||||
sd = sysfs_get_dirent(dir_sd, grp->name);
|
||||
BUG_ON(!sd);
|
||||
} else
|
||||
sd = sysfs_get(dir_sd);
|
||||
|
||||
remove_files(dir,grp);
|
||||
remove_files(sd, grp);
|
||||
if (grp->name)
|
||||
sysfs_remove_subdir(dir);
|
||||
/* release the ref. taken in this routine */
|
||||
dput(dir);
|
||||
sysfs_remove_subdir(sd);
|
||||
|
||||
sysfs_put(sd);
|
||||
}
|
||||
|
||||
|
||||
|
|
231
fs/sysfs/inode.c
231
fs/sysfs/inode.c
|
@ -133,187 +133,94 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
|
|||
*/
|
||||
static struct lock_class_key sysfs_inode_imutex_key;
|
||||
|
||||
struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
|
||||
void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
|
||||
{
|
||||
struct inode * inode = new_inode(sysfs_sb);
|
||||
if (inode) {
|
||||
inode->i_blocks = 0;
|
||||
inode->i_mapping->a_ops = &sysfs_aops;
|
||||
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
|
||||
inode->i_op = &sysfs_inode_operations;
|
||||
inode->i_ino = sd->s_ino;
|
||||
lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
|
||||
inode->i_blocks = 0;
|
||||
inode->i_mapping->a_ops = &sysfs_aops;
|
||||
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
|
||||
inode->i_op = &sysfs_inode_operations;
|
||||
inode->i_ino = sd->s_ino;
|
||||
lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
|
||||
|
||||
if (sd->s_iattr) {
|
||||
/* sysfs_dirent has non-default attributes
|
||||
* get them for the new inode from persistent copy
|
||||
* in sysfs_dirent
|
||||
*/
|
||||
set_inode_attr(inode, sd->s_iattr);
|
||||
} else
|
||||
set_default_inode_attr(inode, sd->s_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_inode - get inode for sysfs_dirent
|
||||
* @sd: sysfs_dirent to allocate inode for
|
||||
*
|
||||
* Get inode for @sd. If such inode doesn't exist, a new inode
|
||||
* is allocated and basics are initialized. New inode is
|
||||
* returned locked.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* Pointer to allocated inode on success, NULL on failure.
|
||||
*/
|
||||
struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = iget_locked(sysfs_sb, sd->s_ino);
|
||||
if (inode && (inode->i_state & I_NEW))
|
||||
sysfs_init_inode(sd, inode);
|
||||
|
||||
if (sd->s_iattr) {
|
||||
/* sysfs_dirent has non-default attributes
|
||||
* get them for the new inode from persistent copy
|
||||
* in sysfs_dirent
|
||||
*/
|
||||
set_inode_attr(inode, sd->s_iattr);
|
||||
} else
|
||||
set_default_inode_attr(inode, mode);
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
|
||||
{
|
||||
int error = 0;
|
||||
struct inode * inode = NULL;
|
||||
if (dentry) {
|
||||
if (!dentry->d_inode) {
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
if ((inode = sysfs_new_inode(mode, sd))) {
|
||||
if (dentry->d_parent && dentry->d_parent->d_inode) {
|
||||
struct inode *p_inode = dentry->d_parent->d_inode;
|
||||
p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
|
||||
}
|
||||
goto Proceed;
|
||||
}
|
||||
else
|
||||
error = -ENOMEM;
|
||||
} else
|
||||
error = -EEXIST;
|
||||
} else
|
||||
error = -ENOENT;
|
||||
goto Done;
|
||||
|
||||
Proceed:
|
||||
if (init)
|
||||
error = init(inode);
|
||||
if (!error) {
|
||||
d_instantiate(dentry, inode);
|
||||
if (S_ISDIR(mode))
|
||||
dget(dentry); /* pin only directory dentry in core */
|
||||
} else
|
||||
iput(inode);
|
||||
Done:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name for corresponding element represented by the given sysfs_dirent
|
||||
/**
|
||||
* sysfs_instantiate - instantiate dentry
|
||||
* @dentry: dentry to be instantiated
|
||||
* @inode: inode associated with @sd
|
||||
*
|
||||
* Unlock @inode if locked and instantiate @dentry with @inode.
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*/
|
||||
const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
|
||||
void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
struct attribute * attr;
|
||||
struct bin_attribute * bin_attr;
|
||||
struct sysfs_symlink * sl;
|
||||
BUG_ON(!dentry || dentry->d_inode);
|
||||
|
||||
BUG_ON(!sd || !sd->s_element);
|
||||
if (inode->i_state & I_NEW)
|
||||
unlock_new_inode(inode);
|
||||
|
||||
switch (sd->s_type) {
|
||||
case SYSFS_DIR:
|
||||
/* Always have a dentry so use that */
|
||||
return sd->s_dentry->d_name.name;
|
||||
|
||||
case SYSFS_KOBJ_ATTR:
|
||||
attr = sd->s_element;
|
||||
return attr->name;
|
||||
|
||||
case SYSFS_KOBJ_BIN_ATTR:
|
||||
bin_attr = sd->s_element;
|
||||
return bin_attr->attr.name;
|
||||
|
||||
case SYSFS_KOBJ_LINK:
|
||||
sl = sd->s_element;
|
||||
return sl->link_name;
|
||||
}
|
||||
return NULL;
|
||||
d_instantiate(dentry, inode);
|
||||
}
|
||||
|
||||
static inline void orphan_all_buffers(struct inode *node)
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
|
||||
{
|
||||
struct sysfs_buffer_collection *set;
|
||||
struct sysfs_buffer *buf;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent **pos, *sd;
|
||||
|
||||
mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
|
||||
set = node->i_private;
|
||||
if (set) {
|
||||
list_for_each_entry(buf, &set->associates, associates) {
|
||||
down(&buf->sem);
|
||||
buf->orphaned = 1;
|
||||
up(&buf->sem);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&node->i_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unhashes the dentry corresponding to given sysfs_dirent
|
||||
* Called with parent inode's i_mutex held.
|
||||
*/
|
||||
void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
|
||||
{
|
||||
struct dentry *dentry = NULL;
|
||||
struct inode *inode;
|
||||
|
||||
/* We're not holding a reference to ->s_dentry dentry but the
|
||||
* field will stay valid as long as sysfs_lock is held.
|
||||
*/
|
||||
spin_lock(&sysfs_lock);
|
||||
spin_lock(&dcache_lock);
|
||||
|
||||
/* dget dentry if it's still alive */
|
||||
if (sd->s_dentry && sd->s_dentry->d_inode)
|
||||
dentry = dget_locked(sd->s_dentry);
|
||||
|
||||
spin_unlock(&dcache_lock);
|
||||
spin_unlock(&sysfs_lock);
|
||||
|
||||
/* drop dentry */
|
||||
if (dentry) {
|
||||
spin_lock(&dcache_lock);
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!d_unhashed(dentry) && dentry->d_inode) {
|
||||
inode = dentry->d_inode;
|
||||
spin_lock(&inode->i_lock);
|
||||
__iget(inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
dget_locked(dentry);
|
||||
__d_drop(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
simple_unlink(parent->d_inode, dentry);
|
||||
orphan_all_buffers(inode);
|
||||
iput(inode);
|
||||
} else {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
dput(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
int sysfs_hash_and_remove(struct dentry * dir, const char * name)
|
||||
{
|
||||
struct sysfs_dirent * sd;
|
||||
struct sysfs_dirent * parent_sd;
|
||||
int found = 0;
|
||||
|
||||
if (!dir)
|
||||
if (!dir_sd)
|
||||
return -ENOENT;
|
||||
|
||||
if (dir->d_inode == NULL)
|
||||
/* no inode means this hasn't been made visible yet */
|
||||
return -ENOENT;
|
||||
sysfs_addrm_start(&acxt, dir_sd);
|
||||
|
||||
parent_sd = dir->d_fsdata;
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
|
||||
if (!sd->s_element)
|
||||
for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
|
||||
sd = *pos;
|
||||
|
||||
if (!sysfs_type(sd))
|
||||
continue;
|
||||
if (!strcmp(sysfs_get_name(sd), name)) {
|
||||
list_del_init(&sd->s_sibling);
|
||||
sysfs_drop_dentry(sd, dir);
|
||||
sysfs_put(sd);
|
||||
found = 1;
|
||||
if (!strcmp(sd->s_name, name)) {
|
||||
*pos = sd->s_sibling;
|
||||
sd->s_sibling = NULL;
|
||||
sysfs_remove_one(&acxt, sd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
|
||||
return found ? 0 : -ENOENT;
|
||||
if (sysfs_addrm_finish(&acxt))
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
|
|
@ -19,28 +19,18 @@ struct vfsmount *sysfs_mount;
|
|||
struct super_block * sysfs_sb = NULL;
|
||||
struct kmem_cache *sysfs_dir_cachep;
|
||||
|
||||
static void sysfs_clear_inode(struct inode *inode);
|
||||
|
||||
static const struct super_operations sysfs_ops = {
|
||||
.statfs = simple_statfs,
|
||||
.drop_inode = sysfs_delete_inode,
|
||||
.clear_inode = sysfs_clear_inode,
|
||||
};
|
||||
|
||||
static struct sysfs_dirent sysfs_root = {
|
||||
.s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling),
|
||||
.s_children = LIST_HEAD_INIT(sysfs_root.s_children),
|
||||
.s_element = NULL,
|
||||
.s_type = SYSFS_ROOT,
|
||||
.s_iattr = NULL,
|
||||
struct sysfs_dirent sysfs_root = {
|
||||
.s_count = ATOMIC_INIT(1),
|
||||
.s_flags = SYSFS_ROOT,
|
||||
.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
.s_ino = 1,
|
||||
};
|
||||
|
||||
static void sysfs_clear_inode(struct inode *inode)
|
||||
{
|
||||
kfree(inode->i_private);
|
||||
}
|
||||
|
||||
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
@ -53,24 +43,26 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sb->s_time_gran = 1;
|
||||
sysfs_sb = sb;
|
||||
|
||||
inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
&sysfs_root);
|
||||
if (inode) {
|
||||
inode->i_op = &sysfs_dir_inode_operations;
|
||||
inode->i_fop = &sysfs_dir_operations;
|
||||
/* directory inodes start off with i_nlink == 2 (for "." entry) */
|
||||
inc_nlink(inode);
|
||||
} else {
|
||||
inode = new_inode(sysfs_sb);
|
||||
if (!inode) {
|
||||
pr_debug("sysfs: could not get root inode\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sysfs_init_inode(&sysfs_root, inode);
|
||||
|
||||
inode->i_op = &sysfs_dir_inode_operations;
|
||||
inode->i_fop = &sysfs_dir_operations;
|
||||
/* directory inodes start off with i_nlink == 2 (for "." entry) */
|
||||
inc_nlink(inode);
|
||||
|
||||
root = d_alloc_root(inode);
|
||||
if (!root) {
|
||||
pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
|
||||
iput(inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sysfs_root.s_dentry = root;
|
||||
root->d_fsdata = &sysfs_root;
|
||||
sb->s_root = root;
|
||||
return 0;
|
||||
|
|
|
@ -11,71 +11,39 @@
|
|||
|
||||
#include "sysfs.h"
|
||||
|
||||
static int object_depth(struct kobject * kobj)
|
||||
static int object_depth(struct sysfs_dirent *sd)
|
||||
{
|
||||
struct kobject * p = kobj;
|
||||
int depth = 0;
|
||||
do { depth++; } while ((p = p->parent));
|
||||
|
||||
for (; sd->s_parent; sd = sd->s_parent)
|
||||
depth++;
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
static int object_path_length(struct kobject * kobj)
|
||||
static int object_path_length(struct sysfs_dirent * sd)
|
||||
{
|
||||
struct kobject * p = kobj;
|
||||
int length = 1;
|
||||
do {
|
||||
length += strlen(kobject_name(p)) + 1;
|
||||
p = p->parent;
|
||||
} while (p);
|
||||
|
||||
for (; sd->s_parent; sd = sd->s_parent)
|
||||
length += strlen(sd->s_name) + 1;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void fill_object_path(struct kobject * kobj, char * buffer, int length)
|
||||
static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
|
||||
{
|
||||
struct kobject * p;
|
||||
|
||||
--length;
|
||||
for (p = kobj; p; p = p->parent) {
|
||||
int cur = strlen(kobject_name(p));
|
||||
for (; sd->s_parent; sd = sd->s_parent) {
|
||||
int cur = strlen(sd->s_name);
|
||||
|
||||
/* back up enough to print this bus id with '/' */
|
||||
length -= cur;
|
||||
strncpy(buffer + length,kobject_name(p),cur);
|
||||
strncpy(buffer + length, sd->s_name, cur);
|
||||
*(buffer + --length) = '/';
|
||||
}
|
||||
}
|
||||
|
||||
static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target)
|
||||
{
|
||||
struct sysfs_dirent * parent_sd = parent->d_fsdata;
|
||||
struct sysfs_symlink * sl;
|
||||
int error = 0;
|
||||
|
||||
error = -ENOMEM;
|
||||
sl = kmalloc(sizeof(*sl), GFP_KERNEL);
|
||||
if (!sl)
|
||||
goto exit1;
|
||||
|
||||
sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
|
||||
if (!sl->link_name)
|
||||
goto exit2;
|
||||
|
||||
strcpy(sl->link_name, name);
|
||||
sl->target_kobj = kobject_get(target);
|
||||
|
||||
error = sysfs_make_dirent(parent_sd, NULL, sl, S_IFLNK|S_IRWXUGO,
|
||||
SYSFS_KOBJ_LINK);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
kobject_put(target);
|
||||
kfree(sl->link_name);
|
||||
exit2:
|
||||
kfree(sl);
|
||||
exit1:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_create_link - create symlink between two objects.
|
||||
* @kobj: object whose directory we're creating the link in.
|
||||
|
@ -84,24 +52,57 @@ exit1:
|
|||
*/
|
||||
int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
|
||||
{
|
||||
struct dentry *dentry = NULL;
|
||||
int error = -EEXIST;
|
||||
struct sysfs_dirent *parent_sd = NULL;
|
||||
struct sysfs_dirent *target_sd = NULL;
|
||||
struct sysfs_dirent *sd = NULL;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
int error;
|
||||
|
||||
BUG_ON(!name);
|
||||
|
||||
if (!kobj) {
|
||||
if (sysfs_mount && sysfs_mount->mnt_sb)
|
||||
dentry = sysfs_mount->mnt_sb->s_root;
|
||||
parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
|
||||
} else
|
||||
dentry = kobj->dentry;
|
||||
parent_sd = kobj->sd;
|
||||
|
||||
if (!dentry)
|
||||
return -EFAULT;
|
||||
error = -EFAULT;
|
||||
if (!parent_sd)
|
||||
goto out_put;
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
if (!sysfs_dirent_exist(dentry->d_fsdata, name))
|
||||
error = sysfs_add_link(dentry, name, target);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
/* target->sd can go away beneath us but is protected with
|
||||
* sysfs_assoc_lock. Fetch target_sd from it.
|
||||
*/
|
||||
spin_lock(&sysfs_assoc_lock);
|
||||
if (target->sd)
|
||||
target_sd = sysfs_get(target->sd);
|
||||
spin_unlock(&sysfs_assoc_lock);
|
||||
|
||||
error = -ENOENT;
|
||||
if (!target_sd)
|
||||
goto out_put;
|
||||
|
||||
error = -ENOMEM;
|
||||
sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
|
||||
if (!sd)
|
||||
goto out_put;
|
||||
sd->s_elem.symlink.target_sd = target_sd;
|
||||
|
||||
sysfs_addrm_start(&acxt, parent_sd);
|
||||
|
||||
if (!sysfs_find_dirent(parent_sd, name)) {
|
||||
sysfs_add_one(&acxt, sd);
|
||||
sysfs_link_sibling(sd);
|
||||
}
|
||||
|
||||
if (sysfs_addrm_finish(&acxt))
|
||||
return 0;
|
||||
|
||||
error = -EEXIST;
|
||||
/* fall through */
|
||||
out_put:
|
||||
sysfs_put(target_sd);
|
||||
sysfs_put(sd);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -114,17 +115,17 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
|
|||
|
||||
void sysfs_remove_link(struct kobject * kobj, const char * name)
|
||||
{
|
||||
sysfs_hash_and_remove(kobj->dentry,name);
|
||||
sysfs_hash_and_remove(kobj->sd, name);
|
||||
}
|
||||
|
||||
static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
|
||||
char *path)
|
||||
static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
|
||||
struct sysfs_dirent * target_sd, char *path)
|
||||
{
|
||||
char * s;
|
||||
int depth, size;
|
||||
|
||||
depth = object_depth(kobj);
|
||||
size = object_path_length(target) + depth * 3 - 1;
|
||||
depth = object_depth(parent_sd);
|
||||
size = object_path_length(target_sd) + depth * 3 - 1;
|
||||
if (size > PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
|
@ -133,7 +134,7 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
|
|||
for (s = path; depth--; s += 3)
|
||||
strcpy(s,"../");
|
||||
|
||||
fill_object_path(target, path, size);
|
||||
fill_object_path(target_sd, path, size);
|
||||
pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
|
||||
|
||||
return 0;
|
||||
|
@ -141,27 +142,16 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
|
|||
|
||||
static int sysfs_getlink(struct dentry *dentry, char * path)
|
||||
{
|
||||
struct kobject *kobj, *target_kobj;
|
||||
int error = 0;
|
||||
struct sysfs_dirent *sd = dentry->d_fsdata;
|
||||
struct sysfs_dirent *parent_sd = sd->s_parent;
|
||||
struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
|
||||
int error;
|
||||
|
||||
kobj = sysfs_get_kobject(dentry->d_parent);
|
||||
if (!kobj)
|
||||
return -EINVAL;
|
||||
mutex_lock(&sysfs_mutex);
|
||||
error = sysfs_get_target_path(parent_sd, target_sd, path);
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
|
||||
target_kobj = sysfs_get_kobject(dentry);
|
||||
if (!target_kobj) {
|
||||
kobject_put(kobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
down_read(&sysfs_rename_sem);
|
||||
error = sysfs_get_target_path(kobj, target_kobj, path);
|
||||
up_read(&sysfs_rename_sem);
|
||||
|
||||
kobject_put(kobj);
|
||||
kobject_put(target_kobj);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
|
|
165
fs/sysfs/sysfs.h
165
fs/sysfs/sysfs.h
|
@ -1,9 +1,40 @@
|
|||
struct sysfs_elem_dir {
|
||||
struct kobject * kobj;
|
||||
};
|
||||
|
||||
struct sysfs_elem_symlink {
|
||||
struct sysfs_dirent * target_sd;
|
||||
};
|
||||
|
||||
struct sysfs_elem_attr {
|
||||
struct attribute * attr;
|
||||
};
|
||||
|
||||
struct sysfs_elem_bin_attr {
|
||||
struct bin_attribute * bin_attr;
|
||||
};
|
||||
|
||||
/*
|
||||
* As long as s_count reference is held, the sysfs_dirent itself is
|
||||
* accessible. Dereferencing s_elem or any other outer entity
|
||||
* requires s_active reference.
|
||||
*/
|
||||
struct sysfs_dirent {
|
||||
atomic_t s_count;
|
||||
struct list_head s_sibling;
|
||||
struct list_head s_children;
|
||||
void * s_element;
|
||||
int s_type;
|
||||
atomic_t s_active;
|
||||
struct sysfs_dirent * s_parent;
|
||||
struct sysfs_dirent * s_sibling;
|
||||
struct sysfs_dirent * s_children;
|
||||
const char * s_name;
|
||||
|
||||
union {
|
||||
struct sysfs_elem_dir dir;
|
||||
struct sysfs_elem_symlink symlink;
|
||||
struct sysfs_elem_attr attr;
|
||||
struct sysfs_elem_bin_attr bin_attr;
|
||||
} s_elem;
|
||||
|
||||
unsigned int s_flags;
|
||||
umode_t s_mode;
|
||||
ino_t s_ino;
|
||||
struct dentry * s_dentry;
|
||||
|
@ -11,30 +42,60 @@ struct sysfs_dirent {
|
|||
atomic_t s_event;
|
||||
};
|
||||
|
||||
#define SD_DEACTIVATED_BIAS INT_MIN
|
||||
|
||||
struct sysfs_addrm_cxt {
|
||||
struct sysfs_dirent *parent_sd;
|
||||
struct inode *parent_inode;
|
||||
struct sysfs_dirent *removed;
|
||||
int cnt;
|
||||
};
|
||||
|
||||
extern struct vfsmount * sysfs_mount;
|
||||
extern struct sysfs_dirent sysfs_root;
|
||||
extern struct kmem_cache *sysfs_dir_cachep;
|
||||
|
||||
extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
|
||||
extern void sysfs_link_sibling(struct sysfs_dirent *sd);
|
||||
extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
|
||||
extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
|
||||
extern void sysfs_put_active(struct sysfs_dirent *sd);
|
||||
extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
|
||||
extern void sysfs_put_active_two(struct sysfs_dirent *sd);
|
||||
extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *parent_sd);
|
||||
extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *sd);
|
||||
extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
|
||||
struct sysfs_dirent *sd);
|
||||
extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
|
||||
|
||||
extern void sysfs_delete_inode(struct inode *inode);
|
||||
extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
|
||||
extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
|
||||
extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode);
|
||||
extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
|
||||
extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
|
||||
|
||||
extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
|
||||
extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
|
||||
umode_t, int);
|
||||
extern void release_sysfs_dirent(struct sysfs_dirent * sd);
|
||||
extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
const unsigned char *name);
|
||||
extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const unsigned char *name);
|
||||
extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
|
||||
int type);
|
||||
|
||||
extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
|
||||
extern int sysfs_hash_and_remove(struct dentry * dir, const char * name);
|
||||
extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type);
|
||||
extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
|
||||
extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
|
||||
|
||||
extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
|
||||
extern void sysfs_remove_subdir(struct dentry *);
|
||||
extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
||||
struct sysfs_dirent **p_sd);
|
||||
extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
|
||||
|
||||
extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
|
||||
extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);
|
||||
extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
|
||||
|
||||
extern spinlock_t sysfs_lock;
|
||||
extern struct rw_semaphore sysfs_rename_sem;
|
||||
extern spinlock_t sysfs_assoc_lock;
|
||||
extern struct mutex sysfs_mutex;
|
||||
extern struct super_block * sysfs_sb;
|
||||
extern const struct file_operations sysfs_dir_operations;
|
||||
extern const struct file_operations sysfs_file_operations;
|
||||
|
@ -42,73 +103,9 @@ extern const struct file_operations bin_fops;
|
|||
extern const struct inode_operations sysfs_dir_inode_operations;
|
||||
extern const struct inode_operations sysfs_symlink_inode_operations;
|
||||
|
||||
struct sysfs_symlink {
|
||||
char * link_name;
|
||||
struct kobject * target_kobj;
|
||||
};
|
||||
|
||||
struct sysfs_buffer {
|
||||
struct list_head associates;
|
||||
size_t count;
|
||||
loff_t pos;
|
||||
char * page;
|
||||
struct sysfs_ops * ops;
|
||||
struct semaphore sem;
|
||||
int orphaned;
|
||||
int needs_read_fill;
|
||||
int event;
|
||||
};
|
||||
|
||||
struct sysfs_buffer_collection {
|
||||
struct list_head associates;
|
||||
};
|
||||
|
||||
static inline struct kobject * to_kobj(struct dentry * dentry)
|
||||
static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
|
||||
{
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
return ((struct kobject *) sd->s_element);
|
||||
}
|
||||
|
||||
static inline struct attribute * to_attr(struct dentry * dentry)
|
||||
{
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
return ((struct attribute *) sd->s_element);
|
||||
}
|
||||
|
||||
static inline struct bin_attribute * to_bin_attr(struct dentry * dentry)
|
||||
{
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
return ((struct bin_attribute *) sd->s_element);
|
||||
}
|
||||
|
||||
static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
|
||||
{
|
||||
struct kobject * kobj = NULL;
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
if (!d_unhashed(dentry)) {
|
||||
struct sysfs_dirent * sd = dentry->d_fsdata;
|
||||
if (sd->s_type & SYSFS_KOBJ_LINK) {
|
||||
struct sysfs_symlink * sl = sd->s_element;
|
||||
kobj = kobject_get(sl->target_kobj);
|
||||
} else
|
||||
kobj = kobject_get(sd->s_element);
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
return kobj;
|
||||
}
|
||||
|
||||
static inline void release_sysfs_dirent(struct sysfs_dirent * sd)
|
||||
{
|
||||
if (sd->s_type & SYSFS_KOBJ_LINK) {
|
||||
struct sysfs_symlink * sl = sd->s_element;
|
||||
kfree(sl->link_name);
|
||||
kobject_put(sl->target_kobj);
|
||||
kfree(sl);
|
||||
}
|
||||
kfree(sd->s_iattr);
|
||||
kmem_cache_free(sysfs_dir_cachep, sd);
|
||||
return sd->s_flags & SYSFS_TYPE_MASK;
|
||||
}
|
||||
|
||||
static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
|
||||
|
@ -122,7 +119,7 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
|
|||
|
||||
static inline void sysfs_put(struct sysfs_dirent * sd)
|
||||
{
|
||||
if (atomic_dec_and_test(&sd->s_count))
|
||||
if (sd && atomic_dec_and_test(&sd->s_count))
|
||||
release_sysfs_dirent(sd);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
|||
|
||||
void debugfs_remove(struct dentry *dentry);
|
||||
|
||||
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *new_dir, const char *new_name);
|
||||
|
||||
struct dentry *debugfs_create_u8(const char *name, mode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
struct dentry *debugfs_create_u16(const char *name, mode_t mode,
|
||||
|
@ -85,6 +88,12 @@ static inline struct dentry *debugfs_create_symlink(const char *name,
|
|||
static inline void debugfs_remove(struct dentry *dentry)
|
||||
{ }
|
||||
|
||||
static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *new_dir, char *new_name)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_u8(const char *name, mode_t mode,
|
||||
struct dentry *parent,
|
||||
u8 *value)
|
||||
|
|
|
@ -238,7 +238,6 @@ extern int __must_check class_device_create_file(struct class_device *,
|
|||
* @devt: for internal use by the driver core only.
|
||||
* @node: for internal use by the driver core only.
|
||||
* @kobj: for internal use by the driver core only.
|
||||
* @devt_attr: for internal use by the driver core only.
|
||||
* @groups: optional additional groups to be created
|
||||
* @dev: if set, a symlink to the struct device is created in the sysfs
|
||||
* directory for this struct class device.
|
||||
|
@ -263,8 +262,6 @@ struct class_device {
|
|||
struct kobject kobj;
|
||||
struct class * class; /* required */
|
||||
dev_t devt; /* dev_t, creates the sysfs "dev" */
|
||||
struct class_device_attribute *devt_attr;
|
||||
struct class_device_attribute uevent_attr;
|
||||
struct device * dev; /* not necessary, but nice to have */
|
||||
void * class_data; /* class-specific data */
|
||||
struct class_device *parent; /* parent of this child device, if there is one */
|
||||
|
@ -419,8 +416,6 @@ struct device {
|
|||
struct device_type *type;
|
||||
unsigned is_registered:1;
|
||||
unsigned uevent_suppress:1;
|
||||
struct device_attribute uevent_attr;
|
||||
struct device_attribute *devt_attr;
|
||||
|
||||
struct semaphore sem; /* semaphore to synchronize calls to
|
||||
* its driver.
|
||||
|
|
|
@ -12,9 +12,17 @@ enum dmi_field {
|
|||
DMI_PRODUCT_NAME,
|
||||
DMI_PRODUCT_VERSION,
|
||||
DMI_PRODUCT_SERIAL,
|
||||
DMI_PRODUCT_UUID,
|
||||
DMI_BOARD_VENDOR,
|
||||
DMI_BOARD_NAME,
|
||||
DMI_BOARD_VERSION,
|
||||
DMI_BOARD_SERIAL,
|
||||
DMI_BOARD_ASSET_TAG,
|
||||
DMI_CHASSIS_VENDOR,
|
||||
DMI_CHASSIS_TYPE,
|
||||
DMI_CHASSIS_VERSION,
|
||||
DMI_CHASSIS_SERIAL,
|
||||
DMI_CHASSIS_ASSET_TAG,
|
||||
DMI_STRING_MAX,
|
||||
};
|
||||
|
||||
|
|
|
@ -83,4 +83,33 @@ void idr_remove(struct idr *idp, int id);
|
|||
void idr_destroy(struct idr *idp);
|
||||
void idr_init(struct idr *idp);
|
||||
|
||||
|
||||
/*
|
||||
* IDA - IDR based id allocator, use when translation from id to
|
||||
* pointer isn't necessary.
|
||||
*/
|
||||
#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
|
||||
#define IDA_BITMAP_LONGS (128 / sizeof(long) - 1)
|
||||
#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
|
||||
|
||||
struct ida_bitmap {
|
||||
long nr_busy;
|
||||
unsigned long bitmap[IDA_BITMAP_LONGS];
|
||||
};
|
||||
|
||||
struct ida {
|
||||
struct idr idr;
|
||||
struct ida_bitmap *free_bitmap;
|
||||
};
|
||||
|
||||
#define IDA_INIT(name) { .idr = IDR_INIT(name), .free_bitmap = NULL, }
|
||||
#define DEFINE_IDA(name) struct ida name = IDA_INIT(name)
|
||||
|
||||
int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
|
||||
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
|
||||
int ida_get_new(struct ida *ida, int *p_id);
|
||||
void ida_remove(struct ida *ida, int id);
|
||||
void ida_destroy(struct ida *ida);
|
||||
void ida_init(struct ida *ida);
|
||||
|
||||
#endif /* __IDR_H__ */
|
||||
|
|
|
@ -55,7 +55,7 @@ struct kobject {
|
|||
struct kobject * parent;
|
||||
struct kset * kset;
|
||||
struct kobj_type * ktype;
|
||||
struct dentry * dentry;
|
||||
struct sysfs_dirent * sd;
|
||||
wait_queue_head_t poll;
|
||||
};
|
||||
|
||||
|
@ -71,13 +71,14 @@ extern void kobject_init(struct kobject *);
|
|||
extern void kobject_cleanup(struct kobject *);
|
||||
|
||||
extern int __must_check kobject_add(struct kobject *);
|
||||
extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
|
||||
extern int __must_check kobject_shadow_add(struct kobject *kobj,
|
||||
struct sysfs_dirent *shadow_parent);
|
||||
extern void kobject_del(struct kobject *);
|
||||
|
||||
extern int __must_check kobject_rename(struct kobject *, const char *new_name);
|
||||
extern int __must_check kobject_shadow_rename(struct kobject *kobj,
|
||||
struct dentry *new_parent,
|
||||
const char *new_name);
|
||||
struct sysfs_dirent *new_parent,
|
||||
const char *new_name);
|
||||
extern int __must_check kobject_move(struct kobject *, struct kobject *);
|
||||
|
||||
extern int __must_check kobject_register(struct kobject *);
|
||||
|
|
|
@ -267,15 +267,10 @@ struct dev_pm_info {
|
|||
unsigned can_wakeup:1;
|
||||
#ifdef CONFIG_PM
|
||||
unsigned should_wakeup:1;
|
||||
pm_message_t prev_state;
|
||||
void * saved_state;
|
||||
struct device * pm_parent;
|
||||
struct list_head entry;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern void device_pm_set_parent(struct device * dev, struct device * parent);
|
||||
|
||||
extern int device_power_down(pm_message_t state);
|
||||
extern void device_power_up(void);
|
||||
extern void device_resume(void);
|
||||
|
|
|
@ -101,8 +101,7 @@ struct sysdev_attribute {
|
|||
|
||||
#define _SYSDEV_ATTR(_name,_mode,_show,_store) \
|
||||
{ \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode, \
|
||||
.owner = THIS_MODULE }, \
|
||||
.attr = { .name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
}
|
||||
|
|
|
@ -19,10 +19,15 @@ struct kobject;
|
|||
struct module;
|
||||
struct nameidata;
|
||||
struct dentry;
|
||||
struct sysfs_dirent;
|
||||
|
||||
/* FIXME
|
||||
* The *owner field is no longer used, but leave around
|
||||
* until the tree gets cleaned up fully.
|
||||
*/
|
||||
struct attribute {
|
||||
const char * name;
|
||||
struct module * owner;
|
||||
struct module * owner;
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
|
@ -39,14 +44,14 @@ struct attribute_group {
|
|||
*/
|
||||
|
||||
#define __ATTR(_name,_mode,_show,_store) { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
}
|
||||
|
||||
#define __ATTR_RO(_name) { \
|
||||
.attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
|
||||
.show = _name##_show, \
|
||||
.attr = { .name = __stringify(_name), .mode = 0444 }, \
|
||||
.show = _name##_show, \
|
||||
}
|
||||
|
||||
#define __ATTR_NULL { .attr = { .name = NULL } }
|
||||
|
@ -59,8 +64,10 @@ struct bin_attribute {
|
|||
struct attribute attr;
|
||||
size_t size;
|
||||
void *private;
|
||||
ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
|
||||
ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
|
||||
ssize_t (*read)(struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
ssize_t (*write)(struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
int (*mmap)(struct kobject *, struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma);
|
||||
};
|
||||
|
@ -70,12 +77,16 @@ struct sysfs_ops {
|
|||
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
|
||||
};
|
||||
|
||||
#define SYSFS_TYPE_MASK 0x00ff
|
||||
#define SYSFS_ROOT 0x0001
|
||||
#define SYSFS_DIR 0x0002
|
||||
#define SYSFS_KOBJ_ATTR 0x0004
|
||||
#define SYSFS_KOBJ_BIN_ATTR 0x0008
|
||||
#define SYSFS_KOBJ_LINK 0x0020
|
||||
#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
|
||||
#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
|
||||
|
||||
#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
|
||||
#define SYSFS_FLAG_REMOVED 0x0100
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
||||
|
@ -83,13 +94,14 @@ extern int sysfs_schedule_callback(struct kobject *kobj,
|
|||
void (*func)(void *), void *data, struct module *owner);
|
||||
|
||||
extern int __must_check
|
||||
sysfs_create_dir(struct kobject *, struct dentry *);
|
||||
sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
|
||||
|
||||
extern void
|
||||
sysfs_remove_dir(struct kobject *);
|
||||
|
||||
extern int __must_check
|
||||
sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
|
||||
sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
|
||||
const char *new_name);
|
||||
|
||||
extern int __must_check
|
||||
sysfs_move_dir(struct kobject *, struct kobject *);
|
||||
|
@ -129,8 +141,8 @@ void sysfs_notify(struct kobject * k, char *dir, char *attr);
|
|||
|
||||
extern int sysfs_make_shadowed_dir(struct kobject *kobj,
|
||||
void * (*follow_link)(struct dentry *, struct nameidata *));
|
||||
extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
|
||||
extern void sysfs_remove_shadow_dir(struct dentry *dir);
|
||||
extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
|
||||
extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
|
||||
|
||||
extern int __must_check sysfs_init(void);
|
||||
|
||||
|
@ -142,7 +154,8 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
|
||||
static inline int sysfs_create_dir(struct kobject *kobj,
|
||||
struct sysfs_dirent *shadow_parent_sd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -152,9 +165,9 @@ static inline void sysfs_remove_dir(struct kobject * k)
|
|||
;
|
||||
}
|
||||
|
||||
static inline int sysfs_rename_dir(struct kobject * k,
|
||||
struct dentry *new_parent,
|
||||
const char *new_name)
|
||||
static inline int sysfs_rename_dir(struct kobject *kobj,
|
||||
struct sysfs_dirent *new_parent_sd,
|
||||
const char *new_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -488,8 +488,7 @@ static void free_modinfo_##field(struct module *mod) \
|
|||
mod->field = NULL; \
|
||||
} \
|
||||
static struct module_attribute modinfo_##field = { \
|
||||
.attr = { .name = __stringify(field), .mode = 0444, \
|
||||
.owner = THIS_MODULE }, \
|
||||
.attr = { .name = __stringify(field), .mode = 0444 }, \
|
||||
.show = show_modinfo_##field, \
|
||||
.setup = setup_modinfo_##field, \
|
||||
.test = modinfo_##field##_exists, \
|
||||
|
@ -793,7 +792,7 @@ static ssize_t show_refcnt(struct module_attribute *mattr,
|
|||
}
|
||||
|
||||
static struct module_attribute refcnt = {
|
||||
.attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE },
|
||||
.attr = { .name = "refcnt", .mode = 0444 },
|
||||
.show = show_refcnt,
|
||||
};
|
||||
|
||||
|
@ -851,7 +850,7 @@ static ssize_t show_initstate(struct module_attribute *mattr,
|
|||
}
|
||||
|
||||
static struct module_attribute initstate = {
|
||||
.attr = { .name = "initstate", .mode = 0444, .owner = THIS_MODULE },
|
||||
.attr = { .name = "initstate", .mode = 0444 },
|
||||
.show = show_initstate,
|
||||
};
|
||||
|
||||
|
@ -1032,7 +1031,6 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
|
|||
sattr->mattr.show = module_sect_show;
|
||||
sattr->mattr.store = NULL;
|
||||
sattr->mattr.attr.name = sattr->name;
|
||||
sattr->mattr.attr.owner = mod;
|
||||
sattr->mattr.attr.mode = S_IRUGO;
|
||||
*(gattr++) = &(sattr++)->mattr.attr;
|
||||
}
|
||||
|
@ -1090,7 +1088,6 @@ int module_add_modinfo_attrs(struct module *mod)
|
|||
if (!attr->test ||
|
||||
(attr->test && attr->test(mod))) {
|
||||
memcpy(temp_attr, attr, sizeof(*temp_attr));
|
||||
temp_attr->attr.owner = mod;
|
||||
error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
|
||||
++temp_attr;
|
||||
}
|
||||
|
|
|
@ -491,7 +491,6 @@ param_sysfs_setup(struct module_kobject *mk,
|
|||
pattr->mattr.show = param_attr_show;
|
||||
pattr->mattr.store = param_attr_store;
|
||||
pattr->mattr.attr.name = (char *)&kp->name[name_skip];
|
||||
pattr->mattr.attr.owner = mk->mod;
|
||||
pattr->mattr.attr.mode = kp->perm;
|
||||
*(gattr++) = &(pattr++)->mattr.attr;
|
||||
}
|
||||
|
|
332
lib/idr.c
332
lib/idr.c
|
@ -70,6 +70,26 @@ static void free_layer(struct idr *idp, struct idr_layer *p)
|
|||
spin_unlock_irqrestore(&idp->lock, flags);
|
||||
}
|
||||
|
||||
static void idr_mark_full(struct idr_layer **pa, int id)
|
||||
{
|
||||
struct idr_layer *p = pa[0];
|
||||
int l = 0;
|
||||
|
||||
__set_bit(id & IDR_MASK, &p->bitmap);
|
||||
/*
|
||||
* If this layer is full mark the bit in the layer above to
|
||||
* show that this part of the radix tree is full. This may
|
||||
* complete the layer above and require walking up the radix
|
||||
* tree.
|
||||
*/
|
||||
while (p->bitmap == IDR_FULL) {
|
||||
if (!(p = pa[++l]))
|
||||
break;
|
||||
id = id >> IDR_BITS;
|
||||
__set_bit((id & IDR_MASK), &p->bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* idr_pre_get - reserver resources for idr allocation
|
||||
* @idp: idr handle
|
||||
|
@ -95,15 +115,15 @@ int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
|
|||
}
|
||||
EXPORT_SYMBOL(idr_pre_get);
|
||||
|
||||
static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
|
||||
static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
|
||||
{
|
||||
int n, m, sh;
|
||||
struct idr_layer *p, *new;
|
||||
struct idr_layer *pa[MAX_LEVEL];
|
||||
int l, id;
|
||||
int l, id, oid;
|
||||
long bm;
|
||||
|
||||
id = *starting_id;
|
||||
restart:
|
||||
p = idp->top;
|
||||
l = idp->layers;
|
||||
pa[l--] = NULL;
|
||||
|
@ -117,12 +137,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
|
|||
if (m == IDR_SIZE) {
|
||||
/* no space available go back to previous layer. */
|
||||
l++;
|
||||
oid = id;
|
||||
id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
|
||||
|
||||
/* if already at the top layer, we need to grow */
|
||||
if (!(p = pa[l])) {
|
||||
*starting_id = id;
|
||||
return -2;
|
||||
}
|
||||
continue;
|
||||
|
||||
/* If we need to go up one layer, continue the
|
||||
* loop; otherwise, restart from the top.
|
||||
*/
|
||||
sh = IDR_BITS * (l + 1);
|
||||
if (oid >> sh == id >> sh)
|
||||
continue;
|
||||
else
|
||||
goto restart;
|
||||
}
|
||||
if (m != n) {
|
||||
sh = IDR_BITS*l;
|
||||
|
@ -144,30 +175,13 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
|
|||
pa[l--] = p;
|
||||
p = p->ary[m];
|
||||
}
|
||||
/*
|
||||
* We have reached the leaf node, plant the
|
||||
* users pointer and return the raw id.
|
||||
*/
|
||||
p->ary[m] = (struct idr_layer *)ptr;
|
||||
__set_bit(m, &p->bitmap);
|
||||
p->count++;
|
||||
/*
|
||||
* If this layer is full mark the bit in the layer above
|
||||
* to show that this part of the radix tree is full.
|
||||
* This may complete the layer above and require walking
|
||||
* up the radix tree.
|
||||
*/
|
||||
n = id;
|
||||
while (p->bitmap == IDR_FULL) {
|
||||
if (!(p = pa[++l]))
|
||||
break;
|
||||
n = n >> IDR_BITS;
|
||||
__set_bit((n & IDR_MASK), &p->bitmap);
|
||||
}
|
||||
return(id);
|
||||
|
||||
pa[l] = p;
|
||||
return id;
|
||||
}
|
||||
|
||||
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
|
||||
static int idr_get_empty_slot(struct idr *idp, int starting_id,
|
||||
struct idr_layer **pa)
|
||||
{
|
||||
struct idr_layer *p, *new;
|
||||
int layers, v, id;
|
||||
|
@ -213,12 +227,31 @@ build_up:
|
|||
}
|
||||
idp->top = p;
|
||||
idp->layers = layers;
|
||||
v = sub_alloc(idp, ptr, &id);
|
||||
v = sub_alloc(idp, &id, pa);
|
||||
if (v == -2)
|
||||
goto build_up;
|
||||
return(v);
|
||||
}
|
||||
|
||||
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
|
||||
{
|
||||
struct idr_layer *pa[MAX_LEVEL];
|
||||
int id;
|
||||
|
||||
id = idr_get_empty_slot(idp, starting_id, pa);
|
||||
if (id >= 0) {
|
||||
/*
|
||||
* Successfully found an empty slot. Install the user
|
||||
* pointer and mark the slot full.
|
||||
*/
|
||||
pa[0]->ary[id & IDR_MASK] = (struct idr_layer *)ptr;
|
||||
pa[0]->count++;
|
||||
idr_mark_full(pa, id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* idr_get_new_above - allocate new idr entry above or equal to a start id
|
||||
* @idp: idr handle
|
||||
|
@ -473,3 +506,248 @@ void idr_init(struct idr *idp)
|
|||
spin_lock_init(&idp->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(idr_init);
|
||||
|
||||
|
||||
/*
|
||||
* IDA - IDR based ID allocator
|
||||
*
|
||||
* this is id allocator without id -> pointer translation. Memory
|
||||
* usage is much lower than full blown idr because each id only
|
||||
* occupies a bit. ida uses a custom leaf node which contains
|
||||
* IDA_BITMAP_BITS slots.
|
||||
*
|
||||
* 2007-04-25 written by Tejun Heo <htejun@gmail.com>
|
||||
*/
|
||||
|
||||
static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!ida->free_bitmap) {
|
||||
spin_lock_irqsave(&ida->idr.lock, flags);
|
||||
if (!ida->free_bitmap) {
|
||||
ida->free_bitmap = bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&ida->idr.lock, flags);
|
||||
}
|
||||
|
||||
kfree(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* ida_pre_get - reserve resources for ida allocation
|
||||
* @ida: ida handle
|
||||
* @gfp_mask: memory allocation flag
|
||||
*
|
||||
* This function should be called prior to locking and calling the
|
||||
* following function. It preallocates enough memory to satisfy the
|
||||
* worst possible allocation.
|
||||
*
|
||||
* If the system is REALLY out of memory this function returns 0,
|
||||
* otherwise 1.
|
||||
*/
|
||||
int ida_pre_get(struct ida *ida, gfp_t gfp_mask)
|
||||
{
|
||||
/* allocate idr_layers */
|
||||
if (!idr_pre_get(&ida->idr, gfp_mask))
|
||||
return 0;
|
||||
|
||||
/* allocate free_bitmap */
|
||||
if (!ida->free_bitmap) {
|
||||
struct ida_bitmap *bitmap;
|
||||
|
||||
bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask);
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
free_bitmap(ida, bitmap);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(ida_pre_get);
|
||||
|
||||
/**
|
||||
* ida_get_new_above - allocate new ID above or equal to a start id
|
||||
* @ida: ida handle
|
||||
* @staring_id: id to start search at
|
||||
* @p_id: pointer to the allocated handle
|
||||
*
|
||||
* Allocate new ID above or equal to @ida. It should be called with
|
||||
* any required locks.
|
||||
*
|
||||
* If memory is required, it will return -EAGAIN, you should unlock
|
||||
* and go back to the ida_pre_get() call. If the ida is full, it will
|
||||
* return -ENOSPC.
|
||||
*
|
||||
* @p_id returns a value in the range 0 ... 0x7fffffff.
|
||||
*/
|
||||
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
|
||||
{
|
||||
struct idr_layer *pa[MAX_LEVEL];
|
||||
struct ida_bitmap *bitmap;
|
||||
unsigned long flags;
|
||||
int idr_id = starting_id / IDA_BITMAP_BITS;
|
||||
int offset = starting_id % IDA_BITMAP_BITS;
|
||||
int t, id;
|
||||
|
||||
restart:
|
||||
/* get vacant slot */
|
||||
t = idr_get_empty_slot(&ida->idr, idr_id, pa);
|
||||
if (t < 0) {
|
||||
if (t == -1)
|
||||
return -EAGAIN;
|
||||
else /* will be -3 */
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (t * IDA_BITMAP_BITS >= MAX_ID_BIT)
|
||||
return -ENOSPC;
|
||||
|
||||
if (t != idr_id)
|
||||
offset = 0;
|
||||
idr_id = t;
|
||||
|
||||
/* if bitmap isn't there, create a new one */
|
||||
bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK];
|
||||
if (!bitmap) {
|
||||
spin_lock_irqsave(&ida->idr.lock, flags);
|
||||
bitmap = ida->free_bitmap;
|
||||
ida->free_bitmap = NULL;
|
||||
spin_unlock_irqrestore(&ida->idr.lock, flags);
|
||||
|
||||
if (!bitmap)
|
||||
return -EAGAIN;
|
||||
|
||||
memset(bitmap, 0, sizeof(struct ida_bitmap));
|
||||
pa[0]->ary[idr_id & IDR_MASK] = (void *)bitmap;
|
||||
pa[0]->count++;
|
||||
}
|
||||
|
||||
/* lookup for empty slot */
|
||||
t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset);
|
||||
if (t == IDA_BITMAP_BITS) {
|
||||
/* no empty slot after offset, continue to the next chunk */
|
||||
idr_id++;
|
||||
offset = 0;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
id = idr_id * IDA_BITMAP_BITS + t;
|
||||
if (id >= MAX_ID_BIT)
|
||||
return -ENOSPC;
|
||||
|
||||
__set_bit(t, bitmap->bitmap);
|
||||
if (++bitmap->nr_busy == IDA_BITMAP_BITS)
|
||||
idr_mark_full(pa, idr_id);
|
||||
|
||||
*p_id = id;
|
||||
|
||||
/* Each leaf node can handle nearly a thousand slots and the
|
||||
* whole idea of ida is to have small memory foot print.
|
||||
* Throw away extra resources one by one after each successful
|
||||
* allocation.
|
||||
*/
|
||||
if (ida->idr.id_free_cnt || ida->free_bitmap) {
|
||||
struct idr_layer *p = alloc_layer(&ida->idr);
|
||||
if (p)
|
||||
kmem_cache_free(idr_layer_cache, p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ida_get_new_above);
|
||||
|
||||
/**
|
||||
* ida_get_new - allocate new ID
|
||||
* @ida: idr handle
|
||||
* @p_id: pointer to the allocated handle
|
||||
*
|
||||
* Allocate new ID. It should be called with any required locks.
|
||||
*
|
||||
* If memory is required, it will return -EAGAIN, you should unlock
|
||||
* and go back to the idr_pre_get() call. If the idr is full, it will
|
||||
* return -ENOSPC.
|
||||
*
|
||||
* @id returns a value in the range 0 ... 0x7fffffff.
|
||||
*/
|
||||
int ida_get_new(struct ida *ida, int *p_id)
|
||||
{
|
||||
return ida_get_new_above(ida, 0, p_id);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_get_new);
|
||||
|
||||
/**
|
||||
* ida_remove - remove the given ID
|
||||
* @ida: ida handle
|
||||
* @id: ID to free
|
||||
*/
|
||||
void ida_remove(struct ida *ida, int id)
|
||||
{
|
||||
struct idr_layer *p = ida->idr.top;
|
||||
int shift = (ida->idr.layers - 1) * IDR_BITS;
|
||||
int idr_id = id / IDA_BITMAP_BITS;
|
||||
int offset = id % IDA_BITMAP_BITS;
|
||||
int n;
|
||||
struct ida_bitmap *bitmap;
|
||||
|
||||
/* clear full bits while looking up the leaf idr_layer */
|
||||
while ((shift > 0) && p) {
|
||||
n = (idr_id >> shift) & IDR_MASK;
|
||||
__clear_bit(n, &p->bitmap);
|
||||
p = p->ary[n];
|
||||
shift -= IDR_BITS;
|
||||
}
|
||||
|
||||
if (p == NULL)
|
||||
goto err;
|
||||
|
||||
n = idr_id & IDR_MASK;
|
||||
__clear_bit(n, &p->bitmap);
|
||||
|
||||
bitmap = (void *)p->ary[n];
|
||||
if (!test_bit(offset, bitmap->bitmap))
|
||||
goto err;
|
||||
|
||||
/* update bitmap and remove it if empty */
|
||||
__clear_bit(offset, bitmap->bitmap);
|
||||
if (--bitmap->nr_busy == 0) {
|
||||
__set_bit(n, &p->bitmap); /* to please idr_remove() */
|
||||
idr_remove(&ida->idr, idr_id);
|
||||
free_bitmap(ida, bitmap);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
printk(KERN_WARNING
|
||||
"ida_remove called for id=%d which is not allocated.\n", id);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_remove);
|
||||
|
||||
/**
|
||||
* ida_destroy - release all cached layers within an ida tree
|
||||
* ida: ida handle
|
||||
*/
|
||||
void ida_destroy(struct ida *ida)
|
||||
{
|
||||
idr_destroy(&ida->idr);
|
||||
kfree(ida->free_bitmap);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_destroy);
|
||||
|
||||
/**
|
||||
* ida_init - initialize ida handle
|
||||
* @ida: ida handle
|
||||
*
|
||||
* This function is use to set up the handle (@ida) that you will pass
|
||||
* to the rest of the functions.
|
||||
*/
|
||||
void ida_init(struct ida *ida)
|
||||
{
|
||||
memset(ida, 0, sizeof(struct ida));
|
||||
idr_init(&ida->idr);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(ida_init);
|
||||
|
|
|
@ -44,7 +44,7 @@ static int populate_dir(struct kobject * kobj)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
|
||||
static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
|
||||
{
|
||||
int error = 0;
|
||||
if (kobject_name(kobj)) {
|
||||
|
@ -162,7 +162,7 @@ static void unlink(struct kobject * kobj)
|
|||
* @shadow_parent: sysfs directory to add to.
|
||||
*/
|
||||
|
||||
int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
|
||||
int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
|
||||
{
|
||||
int error = 0;
|
||||
struct kobject * parent;
|
||||
|
@ -338,7 +338,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
|
|||
/* 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->sd, new_name);
|
||||
|
||||
/* This function is mostly/only used for network interface.
|
||||
* Some hotplug package track interfaces by their name and
|
||||
|
@ -361,8 +361,8 @@ out:
|
|||
* @new_name: object's new name
|
||||
*/
|
||||
|
||||
int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
|
||||
const char *new_name)
|
||||
int kobject_shadow_rename(struct kobject *kobj,
|
||||
struct sysfs_dirent *new_parent, const char *new_name)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
|
@ -597,10 +597,17 @@ int kset_add(struct kset * k)
|
|||
|
||||
int kset_register(struct kset * k)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!k)
|
||||
return -EINVAL;
|
||||
|
||||
kset_init(k);
|
||||
return kset_add(k);
|
||||
err = kset_add(k);
|
||||
if (err)
|
||||
return err;
|
||||
kobject_uevent(&k->kobj, KOBJ_ADD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -360,8 +360,9 @@ static struct attribute_group bridge_group = {
|
|||
*
|
||||
* Returns the number of bytes read.
|
||||
*/
|
||||
static ssize_t brforward_read(struct kobject *kobj, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t brforward_read(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct net_bridge *br = to_bridge(dev);
|
||||
|
@ -383,8 +384,7 @@ static ssize_t brforward_read(struct kobject *kobj, char *buf,
|
|||
|
||||
static struct bin_attribute bridge_forward = {
|
||||
.attr = { .name = SYSFS_BRIDGE_FDB,
|
||||
.mode = S_IRUGO,
|
||||
.owner = THIS_MODULE, },
|
||||
.mode = S_IRUGO, },
|
||||
.read = brforward_read,
|
||||
};
|
||||
|
||||
|
|
|
@ -29,8 +29,7 @@ struct brport_attribute {
|
|||
#define BRPORT_ATTR(_name,_mode,_show,_store) \
|
||||
struct brport_attribute brport_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), \
|
||||
.mode = _mode, \
|
||||
.owner = THIS_MODULE, }, \
|
||||
.mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче