Commit 6dc1ec37 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://ldm.bkbits.net/linux-2.5-kobject

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 6e6e099b 808897cf
This diff is collapsed.
......@@ -44,7 +44,7 @@
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/limits.h>
#include <linux/driverfs_fs.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <asm/edd.h>
#include <linux/device.h>
......@@ -63,20 +63,9 @@ MODULE_LICENSE("GPL");
#define left (count - (p - buf) - 1)
/*
* bios_dir may go away completely,
* and it definitely won't be at the root
* of driverfs forever.
*/
static struct driver_dir_entry bios_dir = {
.name = "bios",
.mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO),
};
struct edd_device {
char name[EDD_DEVICE_NAME_SIZE];
struct edd_info *info;
struct driver_dir_entry dir;
struct kobject kobj;
};
struct edd_attribute {
......@@ -112,13 +101,13 @@ edd_dev_set_info(struct edd_device *edev, struct edd_info *info)
}
#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
#define to_edd_device(_dir) container_of(_dir,struct edd_device,dir)
#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
static ssize_t
edd_attr_show(struct driver_dir_entry *dir, struct attribute *attr,
edd_attr_show(struct kobject * kobj, struct attribute *attr,
char *buf, size_t count, loff_t off)
{
struct edd_device *dev = to_edd_device(dir);
struct edd_device *dev = to_edd_device(kobj);
struct edd_attribute *edd_attr = to_edd_attr(attr);
ssize_t ret = 0;
......@@ -127,7 +116,7 @@ edd_attr_show(struct driver_dir_entry *dir, struct attribute *attr,
return ret;
}
static struct driverfs_ops edd_attr_ops = {
static struct sysfs_ops edd_attr_ops = {
.show = edd_attr_show,
};
......@@ -586,89 +575,26 @@ static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
static struct edd_attribute * def_attrs[] = {
&edd_attr_raw_data,
&edd_attr_version,
&edd_attr_extensions,
&edd_attr_info_flags,
&edd_attr_sectors,
&edd_attr_default_cylinders,
&edd_attr_default_heads,
&edd_attr_default_sectors_per_track,
&edd_attr_interface,
&edd_attr_host_bus,
static struct attribute * def_attrs[] = {
&edd_attr_raw_data.attr,
&edd_attr_version.attr,
&edd_attr_extensions.attr,
&edd_attr_info_flags.attr,
&edd_attr_sectors.attr,
&edd_attr_default_cylinders.attr,
&edd_attr_default_heads.attr,
&edd_attr_default_sectors_per_track.attr,
&edd_attr_interface.attr,
&edd_attr_host_bus.attr,
NULL,
};
/* edd_get_devpath_length(), edd_fill_devpath(), and edd_device_link()
were taken from linux/drivers/base/fs/device.c. When these
or similar are exported to generic code, remove these.
*/
static int
edd_get_devpath_length(struct device *dev)
{
int length = 1;
struct device *parent = dev;
/* walk up the ancestors until we hit the root.
* Add 1 to strlen for leading '/' of each level.
*/
do {
length += strlen(parent->bus_id) + 1;
parent = parent->parent;
} while (parent);
return length;
}
static void
edd_fill_devpath(struct device *dev, char *path, int length)
{
struct device *parent;
--length;
for (parent = dev; parent; parent = parent->parent) {
int cur = strlen(parent->bus_id);
/* back up enough to print this bus id with '/' */
length -= cur;
strncpy(path + length, parent->bus_id, cur);
*(path + --length) = '/';
}
}
static int
edd_device_symlink(struct edd_device *edev, struct device *dev, char *name)
{
char *path;
int length;
int error = 0;
if (!dev->bus || !name)
return 0;
length = edd_get_devpath_length(dev);
/* now add the path from the edd_device directory
* It should be '../..' (one to get to the 'bios' directory,
* and one to get to the root of the fs.)
*/
length += strlen("../../root");
if (length > PATH_MAX)
return -ENAMETOOLONG;
if (!(path = kmalloc(length, GFP_KERNEL)))
return -ENOMEM;
memset(path, 0, length);
static struct subsystem edd_subsys = {
.kobj = { .name = "edd" },
.sysfs_ops = &edd_attr_ops,
.default_attrs = def_attrs,
};
/* our relative position */
strcpy(path, "../../root");
edd_fill_devpath(dev, path, length);
error = driverfs_create_symlink(&edev->dir, name, path);
kfree(path);
return error;
}
/**
* edd_dev_is_type() - is this EDD device a 'type' device?
......@@ -721,7 +647,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
struct pci_dev *pci_dev = edd_get_pci_dev(edev);
if (!pci_dev)
return 1;
return edd_device_symlink(edev, &pci_dev->dev, "pci_dev");
return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
}
/**
......@@ -833,61 +759,16 @@ edd_create_symlink_to_scsidev(struct edd_device *edev)
return 1;
get_device(&sdev->sdev_driverfs_dev);
rc = edd_device_symlink(edev, &sdev->sdev_driverfs_dev, "disc");
rc = sysfs_create_link(&edev->kobj,&sdev->sdev_driverfs_dev.kobj, "disc");
put_device(&sdev->sdev_driverfs_dev);
return rc;
}
static inline int
edd_create_file(struct edd_device *edev, struct edd_attribute *attr)
{
return driverfs_create_file(&attr->attr, &edev->dir);
}
static inline void
edd_device_unregister(struct edd_device *edev)
{
driverfs_remove_dir(&edev->dir);
}
static int
edd_populate_dir(struct edd_device *edev)
{
struct edd_attribute *attr;
int i;
int error = 0;
for (i = 0; (attr=def_attrs[i]); i++) {
if (!attr->test || (attr->test && !attr->test(edev))) {
if ((error = edd_create_file(edev, attr))) {
break;
}
}
}
if (error)
return error;
edd_create_symlink_to_pcidev(edev);
edd_create_symlink_to_scsidev(edev);
return 0;
}
static int
edd_make_dir(struct edd_device *edev)
{
int error;
edev->dir.name = edev->name;
edev->dir.mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
edev->dir.ops = &edd_attr_ops;
error = driverfs_create_dir(&edev->dir, &bios_dir);
if (!error)
error = edd_populate_dir(edev);
return error;
kobject_unregister(&edev->kobj);
}
static int
......@@ -899,9 +780,15 @@ edd_device_register(struct edd_device *edev, int i)
return 1;
memset(edev, 0, sizeof (*edev));
edd_dev_set_info(edev, &edd[i]);
snprintf(edev->name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
kobject_init(&edev->kobj);
snprintf(edev->kobj.name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
edd[i].device);
error = edd_make_dir(edev);
edev->kobj.subsys = &edd_subsys;
error = kobject_register(&edev->kobj);
if (!error) {
edd_create_symlink_to_pcidev(edev);
edd_create_symlink_to_scsidev(edev);
}
return error;
}
......@@ -926,7 +813,7 @@ edd_init(void)
return 1;
}
rc = driverfs_create_dir(&bios_dir, NULL);
rc = firmware_register(&edd_subsys);
if (rc)
return rc;
......@@ -943,12 +830,9 @@ edd_init(void)
edd_devices[i] = edev;
}
if (rc) {
driverfs_remove_dir(&bios_dir);
return rc;
}
return 0;
if (rc)
firmware_unregister(&edd_subsys);
return rc;
}
static void __exit
......@@ -963,8 +847,7 @@ edd_exit(void)
kfree(edev);
}
}
driverfs_remove_dir(&bios_dir);
firmware_unregister(&edd_subsys);
}
late_initcall(edd_init);
......
......@@ -32,7 +32,7 @@ obj-$(CONFIG_ACPI_INTERPRETER) += osl.o utils.o \
#
# ACPI Bus and Device Drivers
#
obj-$(CONFIG_ACPI_BUS) += bus.o driverfs.o
obj-$(CONFIG_ACPI_BUS) += bus.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
......
......@@ -27,7 +27,7 @@
#define __ACPI_BUS_H__
#include <linux/version.h>
#include <linux/driverfs_fs.h>
#include <linux/kobject.h>
#include "include/acpi.h"
......@@ -255,7 +255,7 @@ struct acpi_device {
struct acpi_device_ops ops;
struct acpi_driver *driver;
void *driver_data;
struct driver_dir_entry driverfs_dir;
struct kobject kobj;
};
#define acpi_driver_data(d) ((d)->driver_data)
......@@ -274,6 +274,7 @@ struct acpi_bus_event {
u32 data;
};
extern struct subsystem acpi_subsys;
/*
* External Functions
......
......@@ -675,6 +675,9 @@ acpi_bus_init (void)
return_VALUE(-ENODEV);
}
struct subsystem acpi_subsys = {
.kobj = { .name = "acpi" },
};
static int __init acpi_init (void)
{
......@@ -693,6 +696,8 @@ static int __init acpi_init (void)
return -ENODEV;
}
firmware_register(&acpi_subsys);
result = acpi_bus_init();
if (!result) {
......
/*
* driverfs.c - ACPI bindings for driverfs.
*
* Copyright (c) 2002 Patrick Mochel
* Copyright (c) 2002 The Open Source Development Lab
*
*/
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/driverfs_fs.h>
#include "acpi_bus.h"
static struct driver_dir_entry acpi_dir = {
.name = "acpi",
.mode = (S_IRWXU | S_IRUGO | S_IXUGO),
};
/* driverfs ops for ACPI attribute files go here, when/if
* there are ACPI attribute files.
* For now, we just have directory creation and removal.
*/
void acpi_remove_dir(struct acpi_device * dev)
{
if (dev)
driverfs_remove_dir(&dev->driverfs_dir);
}
int acpi_create_dir(struct acpi_device * dev)
{
struct driver_dir_entry * parent;
parent = dev->parent ? &dev->parent->driverfs_dir : &acpi_dir;
dev->driverfs_dir.name = dev->pnp.bus_id;
dev->driverfs_dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
return driverfs_create_dir(&dev->driverfs_dir,parent);
}
static int __init acpi_driverfs_init(void)
{
return driverfs_create_dir(&acpi_dir,NULL);
}
subsys_initcall(acpi_driverfs_init);
......@@ -25,20 +25,52 @@ extern struct acpi_device *acpi_root;
static LIST_HEAD(acpi_device_list);
static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;
static int
acpi_device_register (
struct acpi_device *device,
struct acpi_device *parent)
static void acpi_device_release(struct kobject * kobj)
{
return acpi_create_dir(device);
struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);
kfree(dev);
}
static struct subsystem acpi_namespace_subsys = {
.kobj = { .name = "namespace" },
.parent = &acpi_subsys,
.release = acpi_device_release,
};
static void acpi_device_register(struct acpi_device * device, struct acpi_device * parent)
{
/*
* Linkage
* -------
* Link this device to its parent and siblings.
*/
INIT_LIST_HEAD(&device->children);
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&device->g_list);
spin_lock(&acpi_device_lock);
if (device->parent) {
list_add_tail(&device->node, &device->parent->children);
list_add_tail(&device->g_list,&device->parent->g_list);
} else
list_add_tail(&device->g_list,&acpi_device_list);
spin_unlock(&acpi_device_lock);
kobject_init(&device->kobj);
strncpy(device->kobj.name,device->pnp.bus_id,KOBJ_NAME_LEN);
if (parent)
device->kobj.parent = &parent->kobj;
device->kobj.subsys = &acpi_namespace_subsys;
kobject_register(&device->kobj);
}
static int
acpi_device_unregister (
struct acpi_device *device)
struct acpi_device *device,
int type)
{
acpi_remove_dir(device);
kobject_unregister(&device->kobj);
return 0;
}
......@@ -443,16 +475,6 @@ acpi_bus_get_flags (
return_VALUE(0);
}
static int
acpi_bus_remove (
struct acpi_device *device,
int type)
{
acpi_device_unregister(device);
kfree(device);
return 0;
}
static void acpi_device_get_busid(struct acpi_device * device, acpi_handle handle, int type)
{
char bus_id[5] = {'?',0};
......@@ -621,28 +643,6 @@ void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle,
#endif /*CONFIG_ACPI_DEBUG*/
}
static void acpi_device_attach(struct acpi_device * device, struct acpi_device * parent)
{
/*
* Linkage
* -------
* Link this device to its parent and siblings.
*/
INIT_LIST_HEAD(&device->children);
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&device->g_list);
spin_lock(&acpi_device_lock);
if (device->parent) {
list_add_tail(&device->node, &device->parent->children);
list_add_tail(&device->g_list,&device->parent->g_list);
} else
list_add_tail(&device->g_list,&acpi_device_list);
spin_unlock(&acpi_device_lock);
acpi_device_register(device, parent);
}
static int
acpi_bus_add (
struct acpi_device **child,
......@@ -741,7 +741,7 @@ acpi_bus_add (
acpi_device_get_debug_info(device,handle,type);
acpi_device_attach(device,parent);
acpi_device_register(device,parent);
/*
* Bind _ADR-Based Devices
......@@ -919,6 +919,8 @@ static int __init acpi_scan_init(void)
if (acpi_disabled)
return_VALUE(0);
subsystem_register(&acpi_namespace_subsys);
/*
* Create the root device in the bus's device tree
*/
......@@ -935,7 +937,7 @@ static int __init acpi_scan_init(void)
result = acpi_bus_scan(acpi_root);
if (result)
acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
Done:
return_VALUE(result);
......
......@@ -2,13 +2,14 @@
obj-y := core.o sys.o interface.o power.o bus.o \
driver.o class.o intf.o platform.o \
cpu.o
cpu.o firmware.o
obj-y += fs/
obj-$(CONFIG_HOTPLUG) += hotplug.o
export-objs := core.o power.o sys.o bus.o driver.o \
class.o intf.o platform.o cpu.o
class.o intf.o platform.o cpu.o \
firmware.o
include $(TOPDIR)/Rules.make
......@@ -10,44 +10,15 @@ extern struct list_head global_device_list;
extern spinlock_t device_lock;
extern struct semaphore device_sem;
extern struct device * get_device_locked(struct device *);
extern int bus_add_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
extern int device_make_dir(struct device * dev);
extern void device_remove_dir(struct device * dev);
extern int bus_make_dir(struct bus_type * bus);
extern void bus_remove_dir(struct bus_type * bus);
extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
extern int driver_make_dir(struct device_driver * drv);
extern void driver_remove_dir(struct device_driver * drv);
extern int device_bus_link(struct device * dev);
extern void device_remove_symlink(struct driver_dir_entry * dir, const char * name);
extern int devclass_make_dir(struct device_class *);
extern void devclass_remove_dir(struct device_class *);
extern int devclass_drv_link(struct device_driver *);
extern void devclass_drv_unlink(struct device_driver *);
extern int devclass_dev_link(struct device_class *, struct device *);
extern void devclass_dev_unlink(struct device_class *, struct device *);
extern int devclass_add_device(struct device *);
extern void devclass_remove_device(struct device *);
extern int intf_make_dir(struct device_interface *);
extern void intf_remove_dir(struct device_interface *);
extern int intf_dev_link(struct intf_data *);
extern void intf_dev_unlink(struct intf_data *);
extern int interface_add(struct device_class *, struct device *);
extern void interface_remove(struct device_class *, struct device *);
......
......@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include "base.h"
static LIST_HEAD(bus_driver_list);
......@@ -19,6 +20,109 @@ static LIST_HEAD(bus_driver_list);
#define to_dev(node) container_of(node,struct device,bus_list)
#define to_drv(node) container_of(node,struct device_driver,bus_list)
#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr)
#define to_bus(obj) container_of(obj,struct bus_type,subsys.kobj)
/*
* sysfs bindings for drivers
*/
#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr)
#define to_driver(obj) container_of(obj, struct device_driver, kobj)
static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_driver(kobj);
ssize_t ret = 0;
if (drv_attr->show)
ret = drv_attr->show(drv,buf,count,off);
return ret;
}
static ssize_t
drv_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_driver(kobj);
ssize_t ret = 0;
if (drv_attr->store)
ret = drv_attr->store(drv,buf,count,off);
return ret;
}
static struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
/*
* sysfs bindings for drivers
*/
static ssize_t
bus_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->show)
ret = bus_attr->show(bus,buf,count,off);
return ret;
}
static ssize_t
bus_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->store)
ret = bus_attr->store(bus,buf,count,off);
return ret;
}
static struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
if (get_bus(bus)) {
error = sysfs_create_file(&bus->subsys.kobj,&attr->attr);
put_bus(bus);
} else
error = -EINVAL;
return error;
}
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
if (get_bus(bus)) {
sysfs_remove_file(&bus->subsys.kobj,&attr->attr);
put_bus(bus);
}
}
struct subsystem bus_subsys = {
.kobj = { .name = "bus" },
.sysfs_ops = &bus_sysfs_ops,
};
/**
* bus_for_each_dev - walk list of devices and do something to each
* @bus: bus in question
......@@ -92,6 +196,7 @@ static void attach(struct device * dev)
pr_debug("bound device '%s' to driver '%s'\n",
dev->bus_id,dev->driver->name);
list_add_tail(&dev->driver_list,&dev->driver->devices);
sysfs_create_link(&dev->driver->kobj,&dev->kobj,dev->kobj.name);
}
static int bus_match(struct device * dev, struct device_driver * drv)
......@@ -162,6 +267,7 @@ static int driver_attach(struct device_driver * drv)
static void detach(struct device * dev, struct device_driver * drv)
{
if (drv) {
sysfs_remove_link(&drv->kobj,dev->kobj.name);
list_del_init(&dev->driver_list);
devclass_remove_device(dev);
if (drv->remove)
......@@ -206,7 +312,7 @@ int bus_add_device(struct device * dev)
list_add_tail(&dev->bus_list,&dev->bus->devices);
device_attach(dev);
up_write(&dev->bus->rwsem);
device_bus_link(dev);
sysfs_create_link(&bus->devsubsys.kobj,&dev->kobj,dev->bus_id);
}
return 0;
}
......@@ -221,9 +327,9 @@ int bus_add_device(struct device * dev)
void bus_remove_device(struct device * dev)
{
if (dev->bus) {
sysfs_remove_link(&dev->bus->devsubsys.kobj,dev->bus_id);
down_write(&dev->bus->rwsem);
pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id);
device_remove_symlink(&dev->bus->device_dir,dev->bus_id);
device_detach(dev);
list_del_init(&dev->bus_list);
up_write(&dev->bus->rwsem);
......@@ -240,7 +346,6 @@ int bus_add_driver(struct device_driver * drv)
list_add_tail(&drv->bus_list,&bus->drivers);
driver_attach(drv);
up_write(&bus->rwsem);
driver_make_dir(drv);
}
return 0;
}
......@@ -275,7 +380,6 @@ void put_bus(struct bus_type * bus)
list_del_init(&bus->node);
spin_unlock(&device_lock);
WARN_ON(bus->present);
bus_remove_dir(bus);
}
int bus_register(struct bus_type * bus)
......@@ -286,16 +390,25 @@ int bus_register(struct bus_type * bus)
atomic_set(&bus->refcount,2);
bus->present = 1;
strncpy(bus->subsys.kobj.name,bus->name,KOBJ_NAME_LEN);
bus->subsys.parent = &bus_subsys;
subsystem_register(&bus->subsys);
snprintf(bus->devsubsys.kobj.name,KOBJ_NAME_LEN,"devices");
bus->devsubsys.parent = &bus->subsys;
subsystem_register(&bus->devsubsys);
snprintf(bus->drvsubsys.kobj.name,KOBJ_NAME_LEN,"drivers");
bus->drvsubsys.parent = &bus->subsys;
bus->drvsubsys.sysfs_ops = &driver_sysfs_ops;
subsystem_register(&bus->drvsubsys);
spin_lock(&device_lock);
list_add_tail(&bus->node,&bus_driver_list);
spin_unlock(&device_lock);
pr_debug("bus type '%s' registered\n",bus->name);
/* give it some driverfs entities */
bus_make_dir(bus);
put_bus(bus);
return 0;
}
......@@ -306,9 +419,19 @@ void bus_unregister(struct bus_type * bus)
spin_unlock(&device_lock);
pr_debug("bus %s: unregistering\n",bus->name);
subsystem_unregister(&bus->drvsubsys);
subsystem_unregister(&bus->devsubsys);
subsystem_unregister(&bus->subsys);
put_bus(bus);
}
static int __init bus_subsys_init(void)
{
return subsystem_register(&bus_subsys);
}
core_initcall(bus_subsys_init);
EXPORT_SYMBOL(bus_for_each_dev);
EXPORT_SYMBOL(bus_for_each_drv);
EXPORT_SYMBOL(bus_add_device);
......@@ -317,3 +440,6 @@ EXPORT_SYMBOL(bus_register);
EXPORT_SYMBOL(bus_unregister);
EXPORT_SYMBOL(get_bus);
EXPORT_SYMBOL(put_bus);
EXPORT_SYMBOL(bus_create_file);
EXPORT_SYMBOL(bus_remove_file);
......@@ -4,10 +4,98 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include "base.h"
static LIST_HEAD(class_list);
#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
#define to_class(obj) container_of(obj,struct device_class,subsys.kobj)
static ssize_t
devclass_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(kobj);
ssize_t ret = 0;
if (class_attr->show)
ret = class_attr->show(dc,buf,count,off);
return ret;
}
static ssize_t
devclass_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(kobj);
ssize_t ret = 0;
if (class_attr->store)
ret = class_attr->store(dc,buf,count,off);
return ret;
}
static struct sysfs_ops class_sysfs_ops = {
show: devclass_attr_show,
store: devclass_attr_store,
};
static struct subsystem class_subsys = {
.kobj = { .name = "class", },
.sysfs_ops = &class_sysfs_ops,
};
static int devclass_dev_link(struct device_class * cls, struct device * dev)
{
char linkname[16];
snprintf(linkname,16,"%u",dev->class_num);
return sysfs_create_link(&cls->devsubsys.kobj,&dev->kobj,linkname);
}
static void devclass_dev_unlink(struct device_class * cls, struct device * dev)
{
char linkname[16];
snprintf(linkname,16,"%u",dev->class_num);
sysfs_remove_link(&cls->devsubsys.kobj,linkname);
}
static int devclass_drv_link(struct device_driver * drv)
{
char name[KOBJ_NAME_LEN * 3];
snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
return sysfs_create_link(&drv->devclass->drvsubsys.kobj,&drv->kobj,name);
}
static void devclass_drv_unlink(struct device_driver * drv)
{
char name[KOBJ_NAME_LEN * 3];
snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
return sysfs_remove_link(&drv->devclass->drvsubsys.kobj,name);
}
int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr)
{
int error;
if (cls) {
error = sysfs_create_file(&cls->subsys.kobj,&attr->attr);
} else
error = -EINVAL;
return error;
}
void devclass_remove_file(struct device_class * cls, struct devclass_attribute * attr)
{
if (cls)
sysfs_remove_file(&cls->subsys.kobj,&attr->attr);
}
int devclass_add_driver(struct device_driver * drv)
{
struct device_class * cls = get_devclass(drv->devclass);
......@@ -136,7 +224,6 @@ void put_devclass(struct device_class * cls)
if (atomic_dec_and_lock(&cls->refcount,&device_lock)) {
list_del_init(&cls->node);
spin_unlock(&device_lock);
devclass_remove_dir(cls);
}
}
......@@ -150,10 +237,21 @@ int devclass_register(struct device_class * cls)
cls->present = 1;
pr_debug("device class '%s': registering\n",cls->name);
strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN);
cls->subsys.parent = &class_subsys;
subsystem_register(&cls->subsys);
snprintf(cls->devsubsys.kobj.name,KOBJ_NAME_LEN,"devices");
cls->devsubsys.parent = &cls->subsys;
subsystem_register(&cls->devsubsys);
snprintf(cls->drvsubsys.kobj.name,KOBJ_NAME_LEN,"drivers");
cls->drvsubsys.parent = &cls->subsys;
subsystem_register(&cls->drvsubsys);
spin_lock(&device_lock);
list_add_tail(&cls->node,&class_list);
spin_unlock(&device_lock);
devclass_make_dir(cls);
put_devclass(cls);
return 0;
}
......@@ -164,9 +262,19 @@ void devclass_unregister(struct device_class * cls)
cls->present = 0;
spin_unlock(&device_lock);
pr_debug("device class '%s': unregistering\n",cls->name);
subsystem_unregister(&cls->drvsubsys);
subsystem_unregister(&cls->devsubsys);
subsystem_unregister(&cls->subsys);
put_devclass(cls);
}
static int __init class_subsys_init(void)
{
return subsystem_register(&class_subsys);
}
core_initcall(class_subsys_init);
EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister);
EXPORT_SYMBOL(get_devclass);
......
......@@ -23,7 +23,74 @@ DECLARE_MUTEX(device_sem);
spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
#define to_dev(node) container_of(node,struct device,driver_list)
#define to_dev(obj) container_of(obj,struct device,kobj)
/*
* sysfs bindings for devices.
*/
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
extern struct attribute * dev_default_attrs[];
static ssize_t
dev_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct device_attribute * dev_attr = to_dev_attr(attr);
struct device * dev = to_dev(kobj);
ssize_t ret = 0;
if (dev_attr->show)
ret = dev_attr->show(dev,buf,count,off);
return ret;
}
static ssize_t
dev_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct device_attribute * dev_attr = to_dev_attr(attr);
struct device * dev = to_dev(kobj);
ssize_t ret = 0;
if (dev_attr->store)
ret = dev_attr->store(dev,buf,count,off);
return ret;
}
static struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
struct subsystem device_subsys = {
.kobj = {
.name = "devices",
},
.sysfs_ops = &dev_sysfs_ops,
.default_attrs = dev_default_attrs,
};
int device_create_file(struct device * dev, struct device_attribute * attr)
{
int error = 0;
if (get_device(dev)) {
error = sysfs_create_file(&dev->kobj,&attr->attr);
put_device(dev);
}
return error;
}
void device_remove_file(struct device * dev, struct device_attribute * attr)
{
if (get_device(dev)) {
sysfs_remove_file(&dev->kobj,&attr->attr);
put_device(dev);
}
}
int device_add(struct device *dev)
{
......@@ -44,7 +111,11 @@ int device_add(struct device *dev)
pr_debug("DEV: registering device: ID = '%s', name = %s\n",
dev->bus_id, dev->name);
if ((error = device_make_dir(dev)))
strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN);
if (dev->parent)
dev->kobj.parent = &dev->parent->kobj;
dev->kobj.subsys = &device_subsys;
if ((error = kobject_register(&dev->kobj)))
goto register_done;
bus_add_device(dev);
......@@ -69,6 +140,7 @@ int device_add(struct device *dev)
void device_initialize(struct device *dev)
{
kobject_init(&dev->kobj);
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list);
......@@ -157,9 +229,6 @@ void device_del(struct device * dev)
bus_remove_device(dev);
/* remove the driverfs directory */
device_remove_dir(dev);
if (dev->release)
dev->release(dev);
......@@ -184,10 +253,21 @@ void device_unregister(struct device * dev)
pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
dev->bus_id,dev->name);
kobject_unregister(&dev->kobj);
put_device(dev);
}
static int __init device_subsys_init(void)
{
return subsystem_register(&device_subsys);
}
core_initcall(device_subsys_init);
EXPORT_SYMBOL(device_register);
EXPORT_SYMBOL(device_unregister);
EXPORT_SYMBOL(get_device);
EXPORT_SYMBOL(put_device);
EXPORT_SYMBOL(device_create_file);
EXPORT_SYMBOL(device_remove_file);
......@@ -12,6 +12,29 @@
#define to_dev(node) container_of(node,struct device,driver_list)
/*
* helpers for creating driver attributes in sysfs
*/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
{
int error;
if (get_driver(drv)) {
error = sysfs_create_file(&drv->kobj,&attr->attr);
put_driver(drv);
} else
error = -EINVAL;
return error;
}
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
{
if (get_driver(drv)) {
sysfs_remove_file(&drv->kobj,&attr->attr);
put_driver(drv);
}
}
int driver_for_each_dev(struct device_driver * drv, void * data,
int (*callback)(struct device *, void * ))
{
......@@ -65,7 +88,6 @@ void put_driver(struct device_driver * drv)
return;
spin_unlock(&device_lock);
BUG_ON(drv->present);
bus_remove_driver(drv);
if (drv->release)
drv->release(drv);
put_bus(bus);
......@@ -84,6 +106,11 @@ int driver_register(struct device_driver * drv)
pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name);
kobject_init(&drv->kobj);
strncpy(drv->kobj.name,drv->name,KOBJ_NAME_LEN);
drv->kobj.subsys = &drv->bus->drvsubsys;
kobject_register(&drv->kobj);
get_bus(drv->bus);
atomic_set(&drv->refcount,2);
rwlock_init(&drv->lock);
......@@ -108,3 +135,6 @@ EXPORT_SYMBOL(driver_register);
EXPORT_SYMBOL(driver_unregister);
EXPORT_SYMBOL(get_driver);
EXPORT_SYMBOL(put_driver);
EXPORT_SYMBOL(driver_create_file);
EXPORT_SYMBOL(driver_remove_file);
/*
* firmware.c - firmware subsystem hoohaw.
*/
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/init.h>
static struct subsystem firmware_subsys = {
.kobj = { .name = "firmware" },
};
int firmware_register(struct subsystem * s)
{
s->parent = &firmware_subsys;
return subsystem_register(s);
}
void firmware_unregister(struct subsystem * s)
{
subsystem_unregister(s);
}
static int __init firmware_init(void)
{
return subsystem_register(&firmware_subsys);
}
core_initcall(firmware_init);
EXPORT_SYMBOL(firmware_register);
EXPORT_SYMBOL(firmware_unregister);
obj-y := device.o bus.o driver.o class.o intf.o
obj-y := device.o
export-objs := device.o bus.o driver.o class.o
export-objs := device.o
include $(TOPDIR)/Rules.make
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/stat.h>
#include "fs.h"
static struct driver_dir_entry bus_dir;
#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr)
#define to_bus(dir) container_of(dir,struct bus_type,dir)
/* driverfs ops for device attribute files */
static int
bus_attr_open(struct driver_dir_entry * dir)
{
struct bus_type * bus = to_bus(dir);
get_bus(bus);
return 0;
}
static int
bus_attr_close(struct driver_dir_entry * dir)
{
struct bus_type * bus = to_bus(dir);
put_bus(bus);
return 0;
}
static ssize_t
bus_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(dir);
ssize_t ret = 0;
if (bus_attr->show)
ret = bus_attr->show(bus,buf,count,off);
return ret;
}
static ssize_t
bus_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(dir);
ssize_t ret = 0;
if (bus_attr->store)
ret = bus_attr->store(bus,buf,count,off);
return ret;
}
static struct driverfs_ops bus_attr_ops = {
.open = bus_attr_open,
.close = bus_attr_close,
.show = bus_attr_show,
.store = bus_attr_store,
};
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
if (get_bus(bus)) {
error = driverfs_create_file(&attr->attr,&bus->dir);
put_bus(bus);
} else
error = -EINVAL;
return error;
}
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
if (get_bus(bus)) {
driverfs_remove_file(&bus->dir,attr->attr.name);
put_bus(bus);
}
}
int bus_make_dir(struct bus_type * bus)
{
int error;
bus->dir.name = bus->name;
bus->dir.ops = &bus_attr_ops;
error = device_create_dir(&bus->dir,&bus_dir);
if (!error) {
bus->device_dir.name = "devices";
device_create_dir(&bus->device_dir,&bus->dir);
bus->driver_dir.name = "drivers";
device_create_dir(&bus->driver_dir,&bus->dir);
}
return error;
}
void bus_remove_dir(struct bus_type * bus)
{
/* remove driverfs entries */
driverfs_remove_dir(&bus->driver_dir);
driverfs_remove_dir(&bus->device_dir);
driverfs_remove_dir(&bus->dir);
}
static struct driver_dir_entry bus_dir = {
.name = "bus",
.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
};
static int __init bus_init(void)
{
/* make 'bus' driverfs directory */
return driverfs_create_dir(&bus_dir,NULL);
}
core_initcall(bus_init);
EXPORT_SYMBOL(bus_create_file);
EXPORT_SYMBOL(bus_remove_file);
/*
* class.c - driverfs bindings for device classes.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include "fs.h"
static struct driver_dir_entry class_dir;
#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
#define to_class(d) container_of(d,struct device_class,dir)
static ssize_t
devclass_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(dir);
ssize_t ret = 0;
if (class_attr->show)
ret = class_attr->show(dc,buf,count,off);
return ret;
}
static ssize_t
devclass_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(dir);
ssize_t ret = 0;
if (class_attr->store)
ret = class_attr->store(dc,buf,count,off);
return ret;
}
static struct driverfs_ops devclass_attr_ops = {
show: devclass_attr_show,
store: devclass_attr_store,
};
int devclass_create_file(struct device_class * dc, struct devclass_attribute * attr)
{
int error;
if (dc) {
error = driverfs_create_file(&attr->attr,&dc->dir);
} else
error = -EINVAL;
return error;
}
void devclass_remove_file(struct device_class * dc, struct devclass_attribute * attr)
{
if (dc)
driverfs_remove_file(&dc->dir,attr->attr.name);
}
/**
* devclass_dev_link - create symlink to device's directory
* @cls - device class we're a part of
* @dev - device we're linking to
*
* Create a symlink in the class's devices/ directory to @dev's
* directory in the physical hierarchy. The name is the device's
* class-enumerated value (struct device::class_num). We're
* creating:
* class/<class name>/devices/<link name> ->
* root/<path to device>/<device's dir>
* So, the link looks like:
* ../../../root/<path to device>/
*/
int devclass_dev_link(struct device_class * cls, struct device * dev)
{
char linkname[16];
char * path;
int length;
int error;
length = get_devpath_length(dev);
length += strlen("../../../root");
if (length > PATH_MAX)
return -ENAMETOOLONG;
if (!(path = kmalloc(length,GFP_KERNEL)))
return -ENOMEM;
memset(path,0,length);
strcpy(path,"../../../root");
fill_devpath(dev,path,length);
snprintf(linkname,16,"%u",dev->class_num);
error = driverfs_create_symlink(&cls->device_dir,linkname,path);
kfree(path);
return error;
}
void devclass_dev_unlink(struct device_class * cls, struct device * dev)
{
char linkname[16];
snprintf(linkname,16,"%u",dev->class_num);
driverfs_remove_file(&cls->device_dir,linkname);
}
/**
* devclass_drv_link - create symlink to driver's directory
* @drv: driver we're linking up
*
* Create a symlink in the class's drivers/ directory to @drv's
* directory (in the bus's directory). It's name is <bus>:<driver>
* to prevent naming conflicts.
*
* We're creating
* class/<class name>/drivers/<link name> ->
* bus/<bus name>/drivers/<driver name>/
* So, the link looks like:
* ../../../bus/<bus name>/drivers/<driver name>
*/
int devclass_drv_link(struct device_driver * drv)
{
char * name;
char * path;
int namelen;
int pathlen;
int error = 0;
namelen = strlen(drv->name) + strlen(drv->bus->name) + 2;
name = kmalloc(namelen,GFP_KERNEL);
if (!name)
return -ENOMEM;
snprintf(name,namelen,"%s:%s",drv->bus->name,drv->name);
pathlen = strlen("../../../bus/") +
strlen(drv->bus->name) +
strlen("/drivers/") +
strlen(drv->name) + 1;
if (!(path = kmalloc(pathlen,GFP_KERNEL))) {
error = -ENOMEM;
goto Done;
}
snprintf(path,pathlen,"%s%s%s%s",
"../../../bus/",
drv->bus->name,
"/drivers/",
drv->name);
error = driverfs_create_symlink(&drv->devclass->driver_dir,name,path);
Done:
kfree(name);
kfree(path);
return error;
}
void devclass_drv_unlink(struct device_driver * drv)
{
char * name;
int length;
length = strlen(drv->name) + strlen(drv->bus->name) + 2;
if ((name = kmalloc(length,GFP_KERNEL))) {
driverfs_remove_file(&drv->devclass->driver_dir,name);
kfree(name);
}
}
void devclass_remove_dir(struct device_class * dc)
{
driverfs_remove_dir(&dc->device_dir);
driverfs_remove_dir(&dc->driver_dir);
driverfs_remove_dir(&dc->dir);
}
int devclass_make_dir(struct device_class * dc)
{
int error;
dc->dir.name = dc->name;
dc->dir.ops = &devclass_attr_ops;
error = device_create_dir(&dc->dir,&class_dir);
if (!error) {
dc->driver_dir.name = "drivers";
error = device_create_dir(&dc->driver_dir,&dc->dir);
if (!error) {
dc->device_dir.name = "devices";
error = device_create_dir(&dc->device_dir,&dc->dir);
}
if (error)
driverfs_remove_dir(&dc->dir);
}
return error;
}
static struct driver_dir_entry class_dir = {
name: "class",
mode: (S_IRWXU | S_IRUGO | S_IXUGO),
};
static int __init devclass_driverfs_init(void)
{
return driverfs_create_dir(&class_dir,NULL);
}
core_initcall(devclass_driverfs_init);
EXPORT_SYMBOL(devclass_create_file);
EXPORT_SYMBOL(devclass_remove_file);
......@@ -16,112 +16,6 @@
#include <linux/stat.h>
#include <linux/limits.h>
static struct driver_dir_entry device_root_dir = {
.name = "root",
.mode = (S_IRWXU | S_IRUGO | S_IXUGO),
};
extern struct device_attribute * device_default_files[];
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
#define to_device(d) container_of(d, struct device, dir)
/* driverfs ops for device attribute files */
static int
dev_attr_open(struct driver_dir_entry * dir)
{
struct device * dev = to_device(dir);
get_device(dev);
return 0;
}
static int
dev_attr_close(struct driver_dir_entry * dir)
{
struct device * dev = to_device(dir);
put_device(dev);
return 0;
}
static ssize_t
dev_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct device_attribute * dev_attr = to_dev_attr(attr);
struct device * dev = to_device(dir);
ssize_t ret = 0;
if (dev_attr->show)
ret = dev_attr->show(dev,buf,count,off);
return ret;
}
static ssize_t
dev_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct device_attribute * dev_attr = to_dev_attr(attr);
struct device * dev = to_device(dir);
ssize_t ret = 0;
if (dev_attr->store)
ret = dev_attr->store(dev,buf,count,off);
return ret;
}
static struct driverfs_ops dev_attr_ops = {
.open = dev_attr_open,
.close = dev_attr_close,
.show = dev_attr_show,
.store = dev_attr_store,
};
/**
* device_create_file - create a driverfs file for a device
* @dev: device requesting file
* @entry: entry describing file
*
* Allocate space for file entry, copy descriptor, and create.
*/
int device_create_file(struct device * dev, struct device_attribute * entry)
{
int error = -EINVAL;
if (get_device(dev)) {
error = driverfs_create_file(&entry->attr,&dev->dir);
put_device(dev);
}
return error;
}
/**
* device_remove_file - remove a device's file by name
* @dev: device requesting removal
* @name: name of the file
*
*/
void device_remove_file(struct device * dev, struct device_attribute * attr)
{
if (dev) {
get_device(dev);
driverfs_remove_file(&dev->dir,attr->attr.name);
put_device(dev);
}
}
/**
* device_remove_dir - remove a device's directory
* @dev: device in question
*/
void device_remove_dir(struct device * dev)
{
if (dev)
driverfs_remove_dir(&dev->dir);
}
int get_devpath_length(struct device * dev)
{
int length = 1;
......@@ -153,92 +47,3 @@ void fill_devpath(struct device * dev, char * path, int length)
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
}
int device_bus_link(struct device * dev)
{
char * path;
int length;
int error = 0;
if (!dev->bus)
return 0;
length = get_devpath_length(dev);
/* now add the path from the bus directory
* It should be '../../..' (one to get to the bus's directory,
* one to get to the 'bus' directory, and one to get to the root
* of the fs.)
*/
length += strlen("../../../root");
if (length > PATH_MAX)
return -ENAMETOOLONG;
if (!(path = kmalloc(length,GFP_KERNEL)))
return -ENOMEM;
memset(path,0,length);
/* our relative position */
strcpy(path,"../../../root");
fill_devpath(dev,path,length);
error = driverfs_create_symlink(&dev->bus->device_dir,dev->bus_id,path);
kfree(path);
return error;
}
void device_remove_symlink(struct driver_dir_entry * dir, const char * name)
{
driverfs_remove_file(dir,name);
}
int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent)
{
dir->mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
return driverfs_create_dir(dir,parent);
}
/**
* device_make_dir - create a driverfs directory
* @name: name of directory
* @parent: dentry for the parent directory
*
* Do the initial creation of the device's driverfs directory
* and populate it with the one default file.
*
* This is just a helper for device_register(), as we
* don't export this function. (Yes, that means we don't allow
* devices to create subdirectories).
*/
int device_make_dir(struct device * dev)
{
struct driver_dir_entry * parent;
struct device_attribute * entry;
int error;
int i;
parent = dev->parent ? &dev->parent->dir : &device_root_dir;
dev->dir.name = dev->bus_id;
dev->dir.ops = &dev_attr_ops;
if ((error = device_create_dir(&dev->dir,parent)))
return error;
for (i = 0; (entry = *(device_default_files + i)); i++) {
if ((error = device_create_file(dev,entry))) {
device_remove_dir(dev);
break;
}
}
return error;
}
static int device_driverfs_init(void)
{
return driverfs_create_dir(&device_root_dir,NULL);
}
core_initcall(device_driverfs_init);
EXPORT_SYMBOL(device_create_file);
EXPORT_SYMBOL(device_remove_file);
#include <linux/device.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/err.h>
#include "fs.h"
#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr)
#define to_drv(d) container_of(d, struct device_driver, dir)
/* driverfs ops for device attribute files */
static int
drv_attr_open(struct driver_dir_entry * dir)
{
struct device_driver * drv = to_drv(dir);
get_driver(drv);
return 0;
}
static int
drv_attr_close(struct driver_dir_entry * dir)
{
struct device_driver * drv = to_drv(dir);
put_driver(drv);
return 0;
}
static ssize_t
drv_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_drv(dir);
ssize_t ret = 0;
if (drv_attr->show)
ret = drv_attr->show(drv,buf,count,off);
return ret;
}
static ssize_t
drv_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_drv(dir);
ssize_t ret = 0;
if (drv_attr->store)
ret = drv_attr->store(drv,buf,count,off);
return ret;
}
static struct driverfs_ops drv_attr_ops = {
.open = drv_attr_open,
.close = drv_attr_close,
.show = drv_attr_show,
.store = drv_attr_store,
};
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
{
int error;
if (get_driver(drv)) {
error = driverfs_create_file(&attr->attr,&drv->dir);
put_driver(drv);
} else
error = -EINVAL;
return error;
}
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
{
if (get_driver(drv)) {
driverfs_remove_file(&drv->dir,attr->attr.name);
put_driver(drv);
}
}
/**
* driver_make_dir - create a driverfs directory for a driver
* @drv: driver in question
*/
int driver_make_dir(struct device_driver * drv)
{
drv->dir.name = drv->name;
drv->dir.ops = &drv_attr_ops;
return device_create_dir(&drv->dir,&drv->bus->driver_dir);
}
void driver_remove_dir(struct device_driver * drv)
{
driverfs_remove_dir(&drv->dir);
}
EXPORT_SYMBOL(driver_create_file);
EXPORT_SYMBOL(driver_remove_file);
extern int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent);
int get_devpath_length(struct device * dev);
void fill_devpath(struct device * dev, char * path, int length);
......
/*
* intf.c - driverfs glue for device interfaces
*/
#include <linux/device.h>
#include <linux/slab.h>
#include "fs.h"
/**
* intf_dev_link - symlink from interface's directory to device's directory
*
*/
int intf_dev_link(struct intf_data * data)
{
char linkname[16];
char * path;
int length;
int error;
length = get_devpath_length(data->dev);
length += strlen("../../../root");
if (length > PATH_MAX)
return -ENAMETOOLONG;
if (!(path = kmalloc(length,GFP_KERNEL)))
return -ENOMEM;
memset(path,0,length);
strcpy(path,"../../../root");
fill_devpath(data->dev,path,length);
snprintf(linkname,16,"%u",data->intf_num);
error = driverfs_create_symlink(&data->intf->dir,linkname,path);
kfree(path);
return error;
}
void intf_dev_unlink(struct intf_data * data)
{
char linkname[16];
snprintf(linkname,16,"%u",data->intf_num);
driverfs_remove_file(&data->intf->dir,linkname);
}
void intf_remove_dir(struct device_interface * intf)
{
driverfs_remove_dir(&intf->dir);
}
int intf_make_dir(struct device_interface * intf)
{
intf->dir.name = intf->name;
return device_create_dir(&intf->dir,&intf->devclass->dir);
}
......@@ -88,8 +88,8 @@ device_write_power(struct device * dev, const char * buf, size_t count, loff_t o
static DEVICE_ATTR(power,S_IWUSR | S_IRUGO,
device_read_power,device_write_power);
struct device_attribute * device_default_files[] = {
&dev_attr_name,
&dev_attr_power,
struct attribute * dev_default_attrs[] = {
&dev_attr_name.attr,
&dev_attr_power.attr,
NULL,
};
......@@ -11,6 +11,26 @@
#define to_intf(node) container_of(node,struct device_interface,node)
/**
* intf_dev_link - symlink from interface's directory to device's directory
*
*/
static int intf_dev_link(struct intf_data * data)
{
char linkname[16];
snprintf(linkname,16,"%u",data->intf_num);
return sysfs_create_link(&data->intf->kobj,&data->dev->kobj,linkname);
}
static void intf_dev_unlink(struct intf_data * data)
{
char linkname[16];
snprintf(linkname,16,"%u",data->intf_num);
sysfs_remove_link(&data->intf->kobj,linkname);
}
int interface_register(struct device_interface * intf)
{
struct device_class * cls = intf->devclass;
......@@ -18,7 +38,11 @@ int interface_register(struct device_interface * intf)
if (cls) {
pr_debug("register interface '%s' with class '%s\n",
intf->name,cls->name);
intf_make_dir(intf);
kobject_init(&intf->kobj);
strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN);
intf->kobj.subsys = &cls->subsys;
kobject_register(&intf->kobj);
spin_lock(&device_lock);
list_add_tail(&intf->node,&cls->intf_list);
spin_unlock(&device_lock);
......@@ -31,11 +55,10 @@ void interface_unregister(struct device_interface * intf)
{
pr_debug("unregistering interface '%s' from class '%s'\n",
intf->name,intf->devclass->name);
kobject_unregister(&intf->kobj);
spin_lock(&device_lock);
list_del_init(&intf->node);
spin_unlock(&device_lock);
intf_remove_dir(intf);
}
int interface_add(struct device_class * cls, struct device * dev)
......
......@@ -252,14 +252,6 @@ struct seq_operations partitions_op = {
extern int blk_dev_init(void);
struct device_class disk_devclass = {
.name = "disk",
};
static struct bus_type disk_bus = {
name: "block",
};
static struct gendisk *base_probe(dev_t dev, int *part, void *data)
{
char name[20];
......@@ -268,6 +260,8 @@ static struct gendisk *base_probe(dev_t dev, int *part, void *data)
return NULL;
}
struct subsystem block_subsys;
int __init device_init(void)
{
struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
......@@ -280,23 +274,116 @@ int __init device_init(void)
for (i = 1; i < MAX_BLKDEV; i++)
probes[i] = base;
blk_dev_init();
devclass_register(&disk_devclass);
bus_register(&disk_bus);
subsystem_register(&block_subsys);
return 0;
}
__initcall(device_init);
subsys_initcall(device_init);
/*
* kobject & sysfs bindings for block devices
*/
#define to_disk(obj) container_of(obj,struct gendisk,kobj)
struct disk_attribute {
struct attribute attr;
ssize_t (*show)(struct gendisk *, char *, size_t, loff_t);
};
static ssize_t disk_attr_show(struct kobject * kobj, struct attribute * attr,
char * page, size_t count, loff_t off)
{
struct gendisk * disk = to_disk(kobj);
struct disk_attribute * disk_attr = container_of(attr,struct disk_attribute,attr);
ssize_t ret = 0;
if (disk_attr->show)
ret = disk_attr->show(disk,page,count,off);
return ret;
}
static struct sysfs_ops disk_sysfs_ops = {
.show = &disk_attr_show,
};
static ssize_t disk_dev_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
dev_t base = MKDEV(disk->major, disk->first_minor);
return off ? 0 : sprintf(page, "%04x\n",base);
}
static ssize_t disk_range_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf(page, "%d\n",disk->minors);
}
static ssize_t disk_size_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk));
}
static inline unsigned MSEC(unsigned x)
{
return x * 1000 / HZ;
}
static ssize_t disk_stat_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
disk_round_stats(disk);
return off ? 0 : sprintf(page,
"%8u %8u %8llu %8u "
"%8u %8u %8llu %8u "
"%8u %8u %8u"
"\n",
disk->reads, disk->read_merges, (u64)disk->read_sectors,
MSEC(disk->read_ticks),
disk->writes, disk->write_merges, (u64)disk->write_sectors,
MSEC(disk->write_ticks),
disk->in_flight, MSEC(disk->io_ticks),
MSEC(disk->time_in_queue));
}
static struct disk_attribute disk_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = disk_dev_read
};
static struct disk_attribute disk_attr_range = {
.attr = {.name = "range", .mode = S_IRUGO },
.show = disk_range_read
};
static struct disk_attribute disk_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = disk_size_read
};
static struct disk_attribute disk_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = disk_stat_read
};
EXPORT_SYMBOL(disk_devclass);
static struct attribute * default_attrs[] = {
&disk_attr_dev.attr,
&disk_attr_range.attr,
&disk_attr_size.attr,
&disk_attr_stat.attr,
NULL,
};
static void disk_release(struct device *dev)
static void disk_release(struct kobject * kobj)
{
struct gendisk *disk = dev->driver_data;
struct gendisk *disk = to_disk(kobj);
kfree(disk->random);
kfree(disk->part);
kfree(disk);
}
struct subsystem block_subsys = {
.kobj = { .name = "block" },
.release = disk_release,
.sysfs_ops = &disk_sysfs_ops,
.default_attrs = default_attrs,
};
struct gendisk *alloc_disk(int minors)
{
struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
......@@ -314,11 +401,9 @@ struct gendisk *alloc_disk(int minors)
disk->minors = minors;
while (minors >>= 1)
disk->minor_shift++;
kobject_init(&disk->kobj);
disk->kobj.subsys = &block_subsys;
INIT_LIST_HEAD(&disk->full_list);
disk->disk_dev.bus = &disk_bus;
disk->disk_dev.release = disk_release;
disk->disk_dev.driver_data = disk;
device_initialize(&disk->disk_dev);
}
rand_initialize_disk(disk);
return disk;
......@@ -332,14 +417,13 @@ struct gendisk *get_disk(struct gendisk *disk)
owner = disk->fops->owner;
if (owner && !try_inc_mod_count(owner))
return NULL;
atomic_inc(&disk->disk_dev.refcount);
return disk;
return to_disk(kobject_get(&disk->kobj));
}
void put_disk(struct gendisk *disk)
{
if (disk)
put_device(&disk->disk_dev);
kobject_put(&disk->kobj);
}
EXPORT_SYMBOL(alloc_disk);
......
......@@ -41,7 +41,7 @@ obj-$(CONFIG_QUOTACTL) += quota.o
obj-$(CONFIG_PROC_FS) += proc/
obj-y += partitions/
obj-y += driverfs/ sysfs/
obj-y += sysfs/
obj-y += devpts/
obj-$(CONFIG_PROFILING) += dcookies.o
......
#
# Makefile for the driverfs virtual filesystem.
#
export-objs := inode.o
obj-y := inode.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
......@@ -277,231 +277,147 @@ static void devfs_remove_partitions(struct gendisk *dev)
#endif
}
static ssize_t part_dev_read(struct device *dev,
char *page, size_t count, loff_t off)
/*
* sysfs bindings for partitions
*/
struct part_attribute {
struct attribute attr;
ssize_t (*show)(struct hd_struct *,char *,size_t,loff_t);
};
static ssize_t part_attr_show(struct kobject * kobj, struct attribute * attr,
char * page, size_t count, loff_t off)
{
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
ssize_t ret = 0;
if (part_attr->show)
part_attr->show(p,page,count,off);
return ret;
}
static struct sysfs_ops part_sysfs_ops = {
.show part_attr_show,
};
static ssize_t part_dev_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->parent->driver_data;
struct hd_struct *p = dev->driver_data;
struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
int part = p - disk->part + 1;
dev_t base = MKDEV(disk->major, disk->first_minor);
return off ? 0 : sprintf(page, "%04x\n",base + part);
}
static ssize_t part_start_read(struct device *dev,
char *page, size_t count, loff_t off)
static ssize_t part_start_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
}
static ssize_t part_size_read(struct device *dev,
char *page, size_t count, loff_t off)
static ssize_t part_size_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
}
static ssize_t part_stat_read(struct device *dev,
char *page, size_t count, loff_t off)
static ssize_t part_stat_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%8u %8llu %8u %8llu\n",
p->reads, (u64)p->read_sectors,
p->writes, (u64)p->write_sectors);
}
static struct device_attribute part_attr_dev = {
static struct part_attribute part_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = part_dev_read
};
static struct device_attribute part_attr_start = {
static struct part_attribute part_attr_start = {
.attr = {.name = "start", .mode = S_IRUGO },
.show = part_start_read
};
static struct device_attribute part_attr_size = {
static struct part_attribute part_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = part_size_read
};
static struct device_attribute part_attr_stat = {
static struct part_attribute part_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = part_stat_read
};
static struct attribute * default_attrs[] = {
&part_attr_dev.attr,
&part_attr_start.attr,
&part_attr_size.attr,
&part_attr_stat.attr,
NULL,
};
extern struct subsystem block_subsys;
static struct subsystem part_subsys = {
.kobj = { .name = "part" },
.parent = &block_subsys,
.default_attrs = default_attrs,
.sysfs_ops = &part_sysfs_ops,
};
static int __init part_subsys_init(void)
{
return subsystem_register(&part_subsys);
}
__initcall(part_subsys_init);
void delete_partition(struct gendisk *disk, int part)
{
struct hd_struct *p = disk->part + part - 1;
struct device *dev;
if (!p->nr_sects)
return;
p->start_sect = 0;
p->nr_sects = 0;
p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
devfs_unregister(p->de);
dev = p->hd_driverfs_dev;
p->hd_driverfs_dev = NULL;
if (dev) {
device_remove_file(dev, &part_attr_stat);
device_remove_file(dev, &part_attr_size);
device_remove_file(dev, &part_attr_start);
device_remove_file(dev, &part_attr_dev);
device_unregister(dev);
}
}
static void part_release(struct device *dev)
{
kfree(dev);
kobject_unregister(&p->kobj);
}
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
{
struct hd_struct *p = disk->part + part - 1;
struct device *parent = &disk->disk_dev;
struct device *dev;
p->start_sect = start;
p->nr_sects = len;
devfs_register_partition(disk, part);
dev = kmalloc(sizeof(struct device), GFP_KERNEL);
if (!dev)
return;
memset(dev, 0, sizeof(struct device));
dev->parent = parent;
sprintf(dev->bus_id, "p%d", part);
dev->release = part_release;
dev->driver_data = p;
device_register(dev);
device_create_file(dev, &part_attr_dev);
device_create_file(dev, &part_attr_start);
device_create_file(dev, &part_attr_size);
device_create_file(dev, &part_attr_stat);
p->hd_driverfs_dev = dev;
kobject_init(&p->kobj);
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->disk_name,part);
p->kobj.parent = &disk->kobj;
p->kobj.subsys = &part_subsys;
kobject_register(&p->kobj);
}
static ssize_t disk_dev_read(struct device *dev,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->driver_data;
dev_t base = MKDEV(disk->major, disk->first_minor);
return off ? 0 : sprintf(page, "%04x\n",base);
}
static ssize_t disk_range_read(struct device *dev,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->driver_data;
return off ? 0 : sprintf(page, "%d\n",disk->minors);
}
static ssize_t disk_size_read(struct device *dev,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->driver_data;
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk));
}
static inline unsigned MSEC(unsigned x)
static void disk_sysfs_symlinks(struct gendisk *disk)
{
return x * 1000 / HZ;
}
static ssize_t disk_stat_read(struct device *dev,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->driver_data;
disk_round_stats(disk);
return off ? 0 : sprintf(page,
"%8u %8u %8llu %8u "
"%8u %8u %8llu %8u "
"%8u %8u %8u"
"\n",
disk->reads, disk->read_merges, (u64)disk->read_sectors,
MSEC(disk->read_ticks),
disk->writes, disk->write_merges, (u64)disk->write_sectors,
MSEC(disk->write_ticks),
disk->in_flight, MSEC(disk->io_ticks),
MSEC(disk->time_in_queue));
}
static struct device_attribute disk_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = disk_dev_read
};
static struct device_attribute disk_attr_range = {
.attr = {.name = "range", .mode = S_IRUGO },
.show = disk_range_read
};
static struct device_attribute disk_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = disk_size_read
};
static struct device_attribute disk_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = disk_stat_read
};
static void disk_driverfs_symlinks(struct gendisk *disk)
{
struct device *target = disk->driverfs_dev;
struct device *dev = &disk->disk_dev;
struct device *p;
char *path;
char *s;
int length;
int depth;
if (!target)
return;
get_device(target);
length = get_devpath_length(target);
length += strlen("..");
if (length > PATH_MAX)
return;
if (!(path = kmalloc(length,GFP_KERNEL)))
return;
memset(path,0,length);
/* our relative position */
strcpy(path,"..");
fill_devpath(target, path, length);
driverfs_create_symlink(&dev->dir, "device", path);
kfree(path);
for (p = target, depth = 0; p; p = p->parent, depth++)
;
length = get_devpath_length(dev);
length += 3 * depth - 1;
if (length > PATH_MAX)
return;
if (!(path = kmalloc(length,GFP_KERNEL)))
return;
memset(path,0,length);
for (s = path; depth--; s += 3)
strcpy(s, "../");
fill_devpath(dev, path, length);
driverfs_create_symlink(&target->dir, "block", path);
kfree(path);
struct device *target = get_device(disk->driverfs_dev);
if (target) {
sysfs_create_link(&disk->kobj,&target->kobj,"device");
sysfs_create_link(&target->kobj,&disk->kobj,"block");
}
}
/* Not exported, helper to add_disk(). */
void register_disk(struct gendisk *disk)
{
struct device *dev = &disk->disk_dev;
struct parsed_partitions *state;
struct block_device *bdev;
char *s;
int j;
strcpy(dev->bus_id, disk->disk_name);
strncpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
/* ewww... some of these buggers have / in name... */
s = strchr(dev->bus_id, '/');
s = strchr(disk->kobj.name, '/');
if (s)
*s = '!';
device_add(dev);
device_create_file(dev, &disk_attr_dev);
device_create_file(dev, &disk_attr_range);
device_create_file(dev, &disk_attr_size);
device_create_file(dev, &disk_attr_stat);
disk_driverfs_symlinks(disk);
kobject_register(&disk->kobj);
disk_sysfs_symlinks(disk);
if (disk->flags & GENHD_FL_CD)
devfs_create_cdrom(disk);
......@@ -620,16 +536,12 @@ void del_gendisk(struct gendisk *disk)
disk->time_in_queue = 0;
disk->stamp = disk->stamp_idle = 0;
devfs_remove_partitions(disk);
device_remove_file(&disk->disk_dev, &disk_attr_dev);
device_remove_file(&disk->disk_dev, &disk_attr_range);
device_remove_file(&disk->disk_dev, &disk_attr_size);
device_remove_file(&disk->disk_dev, &disk_attr_stat);
driverfs_remove_file(&disk->disk_dev.dir, "device");
kobject_unregister(&disk->kobj);
sysfs_remove_link(&disk->kobj, "device");
if (disk->driverfs_dev) {
driverfs_remove_file(&disk->driverfs_dev->dir, "block");
sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
put_device(disk->driverfs_dev);
}
device_del(&disk->disk_dev);
}
struct dev_name {
......@@ -680,3 +592,4 @@ char *partition_name(dev_t dev)
return dname->name;
}
......@@ -28,7 +28,7 @@
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/driverfs_fs.h>
#include <linux/kobject.h>
#define DEVICE_NAME_SIZE 80
#define DEVICE_ID_SIZE 32
......@@ -65,14 +65,13 @@ struct bus_type {
atomic_t refcount;
u32 present;
struct subsystem subsys;
struct subsystem drvsubsys;
struct subsystem devsubsys;
struct list_head node;
struct list_head devices;
struct list_head drivers;
struct driver_dir_entry dir;
struct driver_dir_entry device_dir;
struct driver_dir_entry driver_dir;
int (*match)(struct device * dev, struct device_driver * drv);
struct device * (*add) (struct device * parent, char * bus_id);
int (*hotplug) (struct device *dev, char **envp,
......@@ -119,12 +118,11 @@ struct device_driver {
atomic_t refcount;
u32 present;
struct kobject kobj;
struct list_head bus_list;
struct list_head class_list;
struct list_head devices;
struct driver_dir_entry dir;
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);
......@@ -177,14 +175,13 @@ struct device_class {
u32 devnum;
struct subsystem subsys;
struct subsystem devsubsys;
struct subsystem drvsubsys;
struct list_head node;
struct list_head drivers;
struct list_head intf_list;
struct driver_dir_entry dir;
struct driver_dir_entry driver_dir;
struct driver_dir_entry device_dir;
int (*add_device)(struct device *);
void (*remove_device)(struct device *);
int (*hotplug)(struct device *dev, char **envp,
......@@ -232,9 +229,9 @@ struct device_interface {
char * name;
struct device_class * devclass;
struct kobject kobj;
struct list_head node;
struct list_head devices;
struct driver_dir_entry dir;
u32 devnum;
......@@ -275,6 +272,7 @@ struct device {
struct list_head intf_list;
struct device * parent;
struct kobject kobj;
char name[DEVICE_NAME_SIZE]; /* descriptive ascii string */
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
......@@ -285,8 +283,6 @@ struct device {
* persists for the right amount of time */
struct bus_type * bus; /* type of bus device is on */
struct driver_dir_entry dir;
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
......@@ -438,6 +434,11 @@ extern int device_suspend(u32 state, u32 level);
extern void device_resume(u32 level);
extern void device_shutdown(void);
/* drivrs/base/firmware.c */
extern int firmware_register(struct subsystem *);
extern void firmware_uregister(struct subsystem *);
/* debugging and troubleshooting/diagnostic helpers. */
#ifdef DEBUG
#define dev_dbg(dev, format, arg...) \
......
/*
* driverfs_fs.h - definitions for the device driver filesystem
*
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This is a simple, ram-based filesystem, which allows kernel
* callbacks for read/write of files.
*
* Please see Documentation/filesystems/driverfs.txt for more information.
*/
#ifndef _DRIVER_FS_H_
#define _DRIVER_FS_H_
struct driver_dir_entry;
struct attribute;
struct driverfs_ops {
int (*open)(struct driver_dir_entry *);
int (*close)(struct driver_dir_entry *);
ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t);
};
struct driver_dir_entry {
char * name;
struct dentry * dentry;
mode_t mode;
struct driverfs_ops * ops;
};
struct attribute {
char * name;
mode_t mode;
};
extern int
driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
extern void
driverfs_remove_dir(struct driver_dir_entry * entry);
extern int
driverfs_create_file(struct attribute * attr,
struct driver_dir_entry * parent);
extern int
driverfs_create_symlink(struct driver_dir_entry * parent,
char * name, char * target);
extern void
driverfs_remove_file(struct driver_dir_entry *, const char * name);
#endif /* _DDFS_H_ */
......@@ -62,7 +62,7 @@ struct hd_struct {
sector_t start_sect;
sector_t nr_sects;
devfs_handle_t de; /* primary (master) devfs entry */
struct device *hd_driverfs_dev; /* support driverfs hiearchy */
struct kobject kobj;
unsigned reads, read_sectors, writes, write_sectors;
int policy;
};
......@@ -93,7 +93,7 @@ struct gendisk {
devfs_handle_t de; /* more of the same */
devfs_handle_t disk_de; /* piled higher and deeper */
struct device *driverfs_dev;
struct device disk_dev;
struct kobject kobj;
struct timer_rand_state *random;
int policy;
......@@ -130,8 +130,6 @@ static inline void set_capacity(struct gendisk *disk, sector_t size)
disk->capacity = size;
}
extern struct device_class disk_devclass;
#endif /* __KERNEL__ */
#ifdef CONFIG_SOLARIS_X86_PARTITION
......
......@@ -12,8 +12,10 @@
#include <linux/rwsem.h>
#include <asm/atomic.h>
#define KOBJ_NAME_LEN 16
struct kobject {
char name[16];
char name[KOBJ_NAME_LEN];
atomic_t refcount;
struct list_head entry;
struct kobject * parent;
......
......@@ -9,20 +9,18 @@
#ifndef _SYSFS_H_
#define _SYSFS_H_
struct driver_dir_entry;
struct attribute;
struct kobject;
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t);
};
struct attribute {
char * name;
mode_t mode;
};
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t);
};
extern int
sysfs_create_dir(struct kobject *);
......
......@@ -101,7 +101,7 @@ static __init dev_t try_name(char *name, int part)
/* read device number from .../dev */
sprintf(path, "/sys/bus/block/devices/%s/dev", name);
sprintf(path, "/sys/block/%s/dev", name);
fd = open(path, 0, 0);
if (fd < 0)
goto fail;
......@@ -119,7 +119,7 @@ static __init dev_t try_name(char *name, int part)
return res;
/* otherwise read range from .../range */
sprintf(path, "/sys/bus/block/devices/%s/range", name);
sprintf(path, "/sys/block/%s/range", name);
fd = open(path, 0, 0);
if (fd < 0)
goto fail;
......@@ -166,7 +166,7 @@ __init dev_t name_to_dev_t(char *name)
int part;
sys_mkdir("/sys", 0700);
if (sys_mount("driverfs", "/sys", "driverfs", 0, NULL) < 0)
if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
goto out;
if (strncmp(name, "/dev/", 5) != 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment