diff options
34 files changed, 732 insertions, 2330 deletions
diff --git a/Documentation/filesystems/driverfs.txt b/Documentation/filesystems/driverfs.txt deleted file mode 100644 index 15dedc22a8ba..000000000000 --- a/Documentation/filesystems/driverfs.txt +++ /dev/null @@ -1,336 +0,0 @@ - -driverfs - The Device Driver Filesystem - -Patrick Mochel <mochel@osdl.org> - -2 August 2002 - - -What it is: -~~~~~~~~~~~ -driverfs is a ram-based filesystem. It was created by copying -ramfs/inode.c to driverfs/inode.c and doing a little search-and-replace. - -driverfs is a means to export kernel data structures, their -attributes, and the linkages between them to userspace. - -driverfs provides a unified interface for exporting attributes to -userspace. Currently, this interface is available only to device and -bus drivers. - - -Using driverfs -~~~~~~~~~~~~~~ -driverfs is always compiled in. You can access it by doing something like: - - mount -t driverfs driverfs /devices - - -Top Level Directory Layout -~~~~~~~~~~~~~~~~~~~~~~~~~~ -The driverfs directory arrangement exposes the relationship of kernel -data structures. - -The top level driverfs diretory looks like: - -bus/ -root/ - -root/ contains a filesystem representation of the device tree. It maps -directly to the internal kernel device tree, which is a hierarchy of -struct device. - -bus/ contains flat directory layout of the various bus types in the -kernel. Each bus's directory contains two subdirectories: - - devices/ - drivers/ - -devices/ contains symlinks for each device discovered in the system -that point to the device's directory under root/. - -drivers/ contains a directory for each device driver that is loaded -for devices on that particular bus (this assmumes that drivers do not -span multiple bus types). - - -More information can device-model specific features can be found in -Documentation/device-model/. - - -Directory Contents -~~~~~~~~~~~~~~~~~~ -Each object that is represented in driverfs gets a directory, rather -than a file, to make it simple to export attributes of that object. -Attributes are exported via ASCII text files. The programming -interface is discussed below. - -Instead of having monolithic files that are difficult to parse, all -files are intended to export one attribute. The name of the attribute -is the name of the file. The value of the attribute are the contents -of the file. - -There should be few, if any, exceptions to this rule. You should not -violate it, for fear of public humilation. - - -The Two-Tier Model -~~~~~~~~~~~~~~~~~~ - -driverfs is a very simple, low-level interface. In order for kernel -objects to use it, there must be an intermediate layer in place for -each object type. - -All calls in driverfs are intended to be as type-safe as possible. -In order to extend driverfs to support multiple data types, a layer of -abstraction was required. This intermediate layer converts between the -generic calls and data structures of the driverfs core to the -subsystem-specific objects and calls. - - -The Subsystem Interface -~~~~~~~~~~~~~~~~~~~~~~~ - -The subsystems bear the responsibility of implementing driverfs -extensions for the objects they control. Fortunately, it's intended to -be really easy to do so. - -It's divided into three sections: directories, files, and operations. - - -Directories -~~~~~~~~~~~ - -struct driver_dir_entry { - char * name; - struct dentry * dentry; - mode_t mode; - struct driverfs_ops * ops; -}; - - -int -driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); - -void -driverfs_remove_dir(struct driver_dir_entry * entry); - -The directory structure should be statically allocated, and reside in -a subsystem-specific data structure: - -struct device { - ... - struct driver_dir_entry dir; -}; - -The subsystem is responsible for initializing the name, mode, and ops -fields of the directory entry. (More on struct driverfs_ops later) - - -Files -~~~~~ - -struct attribute { - char * name; - mode_t mode; -}; - - -int -driverfs_create_file(struct attribute * attr, struct driver_dir_entry * parent); - -void -driverfs_remove_file(struct driver_dir_entry *, const char * name); - - -The attribute structure is a simple, common token that the driverfs -core handles. It has little use on its own outside of the -core. Objects cannot use a plain struct attribute to export -attributes, since there are no callbacks for reading and writing data. - -Therefore, the subsystem is required to define a data structure that -encapsulates the attribute structure, and provides type-safe callbacks -for reading and writing data. - -An example looks like this: - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); -}; - - -Note that there is a struct attribute embedded in the structure. In -order to relieve pain in declaring attributes, the subsystem should -also define a macro, like: - -#define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = { \ - .attr = {.name = __stringify(_name) , .mode = _mode }, \ - .show = _show, \ - .store = _store, \ -}; - -This hides the initialization of the embedded struct, and in general, -the internals of each structure. It yields a structure by the name of -dev_attr_<name>. - -In order for objects to create files, the subsystem should create -wrapper functions, like this: - -int device_create_file(struct device *device, struct device_attribute * entry); -void device_remove_file(struct device * dev, struct device_attribute * attr); - -..and forward the call on to the driverfs functions. - -Note that there is no unique information in the attribute structures, -so the same structure can be used to describe files of several -different object instances. - - -Operations -~~~~~~~~~~ - -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); -}; - - -Subsystems are required to implement this set of callbacks. Their -purpose is to translate the generic data structures into the specific -objects, and operate on them. This can be done by defining macros like -this: - -#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) - -#define to_device(d) container_of(d, struct device, dir) - - -Since the directories are statically allocated in the object, you can -derive the pointer to the object that owns the file. Ditto for the -attribute structures. - -Current Interfaces -~~~~~~~~~~~~~~~~~~ - -The following interface layers currently exist in driverfs: - - -- devices (include/linux/device.h) ----------------------------------- -Structure: - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -DEVICE_ATTR(_name,_str,_mode,_show,_store); - -Creation/Removal: - -int device_create_file(struct device *device, struct device_attribute * entry); -void device_remove_file(struct device * dev, struct device_attribute * attr); - - -- bus drivers (include/linux/device.h) --------------------------------------- -Structure: - -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -BUS_ATTR(_name,_mode,_show,_store) - -Creation/Removal: - -int bus_create_file(struct bus_type *, struct bus_attribute *); -void bus_remove_file(struct bus_type *, struct bus_attribute *); - - -- device drivers (include/linux/device.h) ------------------------------------------ - -Structure: - -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -DRIVER_ATTR(_name,_mode,_show,_store) - -Creation/Removal: - -int driver_create_file(struct device_driver *, struct driver_attribute *); -void driver_remove_file(struct device_driver *, struct driver_attribute *); - - -Reading/Writing Data -~~~~~~~~~~~~~~~~~~~~ -The callback functionality is similar to the way procfs works. When a -user performs a read(2) or write(2) on the file, it first calls a -driverfs function. This calls to the subsystem, which then calls to -the object's show() or store() function. - -The buffer pointer, offset, and length should be passed to each -function. The downstream callback should fill the buffer and return -the number of bytes read/written. - - -What driverfs is not: -~~~~~~~~~~~~~~~~~~~~~ -It is not a replacement for either devfs or procfs. - -It does not handle device nodes, like devfs is intended to do. I think -this functionality is possible, but indeed think that integration of -the device nodes and control files should be done. Whether driverfs or -devfs, or something else, is the place to do it, I don't know. - -It is not intended to be a replacement for all of the procfs -functionality. I think that many of the driver files should be moved -out of /proc (and maybe a few other things as well ;). - - - -Limitations: -~~~~~~~~~~~~ -The driverfs functions assume that at most a page is being either read -or written each time. - -There is a race condition that is really, really hard to fix; if not -impossible. There exists a race between a driverfs file being opened -and the object that owns the file going away. During the driverfs -open() callback, the reference count for the owning object needs to be -incremented. - -For drivers, we can put a struct module * owner in struct driver_dir_entry -and do try_inc_mod_count() when we open a file. However, this won't -work for devices, that aren't tied to a module. And, it is still not -guaranteed to solve the race. - -I'm looking into fixing this, but it may not be doable without making -a separate filesystem instance for each object. It's fun stuff. Please -mail me with creative ideas that you know will work. - - -Possible bugs: -~~~~~~~~~~~~~~ -It may not deal with offsets and/or seeks very well, especially if -they cross a page boundary. - diff --git a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c index f178bdb1e125..94a7c4cac2e4 100644 --- a/arch/i386/kernel/edd.c +++ b/arch/i386/kernel/edd.c @@ -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); diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d4b67800a629..9311d367e96e 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -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 diff --git a/drivers/acpi/acpi_bus.h b/drivers/acpi/acpi_bus.h index 8ad14bfb7360..50c8374094e6 100644 --- a/drivers/acpi/acpi_bus.h +++ b/drivers/acpi/acpi_bus.h @@ -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 diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 3c89b289651c..12423b6d5d5c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -675,6 +675,9 @@ error0: 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) { diff --git a/drivers/acpi/driverfs.c b/drivers/acpi/driverfs.c deleted file mode 100644 index 0c61f97933b7..000000000000 --- a/drivers/acpi/driverfs.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c5b8a92514e6..7bc3fd86ac03 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -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); diff --git a/drivers/base/Makefile b/drivers/base/Makefile index a3e459cc1f6e..6fcb7331ddef 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -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 diff --git a/drivers/base/base.h b/drivers/base/base.h index 8fd09addc1f8..c6f4b2f47bf6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -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 *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 8d0bbb5c9256..08db6a58ead3 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -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); diff --git a/drivers/base/class.c b/drivers/base/class.c index e1e6081cf110..8a22d34d82d9 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -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); diff --git a/drivers/base/core.c b/drivers/base/core.c index 23ce66f60063..b68299c45c0b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -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); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 4bf4a005b918..f940cc4c5165 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -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); diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c new file mode 100644 index 000000000000..8e146ebfdd91 --- /dev/null +++ b/drivers/base/firmware.c @@ -0,0 +1,32 @@ +/* + * 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); diff --git a/drivers/base/fs/Makefile b/drivers/base/fs/Makefile index d4bcde25fda2..f94c734b258f 100644 --- a/drivers/base/fs/Makefile +++ b/drivers/base/fs/Makefile @@ -1,5 +1,5 @@ -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 diff --git a/drivers/base/fs/bus.c b/drivers/base/fs/bus.c deleted file mode 100644 index bd6b92442f81..000000000000 --- a/drivers/base/fs/bus.c +++ /dev/null @@ -1,123 +0,0 @@ -#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); diff --git a/drivers/base/fs/class.c b/drivers/base/fs/class.c deleted file mode 100644 index 1713000f0c37..000000000000 --- a/drivers/base/fs/class.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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); diff --git a/drivers/base/fs/device.c b/drivers/base/fs/device.c index 06984c469a18..faaf687507cb 100644 --- a/drivers/base/fs/device.c +++ b/drivers/base/fs/device.c @@ -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); diff --git a/drivers/base/fs/driver.c b/drivers/base/fs/driver.c deleted file mode 100644 index c70834d738fc..000000000000 --- a/drivers/base/fs/driver.c +++ /dev/null @@ -1,100 +0,0 @@ -#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); diff --git a/drivers/base/fs/fs.h b/drivers/base/fs/fs.h index c072bd604137..863c2cd5ab59 100644 --- a/drivers/base/fs/fs.h +++ b/drivers/base/fs/fs.h @@ -1,6 +1,4 @@ -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); diff --git a/drivers/base/fs/intf.c b/drivers/base/fs/intf.c deleted file mode 100644 index 151f60d42b73..000000000000 --- a/drivers/base/fs/intf.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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); -} diff --git a/drivers/base/interface.c b/drivers/base/interface.c index 8a5c6e6bc226..a6e0c73d043f 100644 --- a/drivers/base/interface.c +++ b/drivers/base/interface.c @@ -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, }; diff --git a/drivers/base/intf.c b/drivers/base/intf.c index f73a43a7567c..b025d53ee142 100644 --- a/drivers/base/intf.c +++ b/drivers/base/intf.c @@ -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) diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 955fa3dedf78..cac3b1acf103 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -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); diff --git a/fs/Makefile b/fs/Makefile index 38aa365a53c5..1a61b1b42cc2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -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 diff --git a/fs/driverfs/Makefile b/fs/driverfs/Makefile deleted file mode 100644 index 43c770cee388..000000000000 --- a/fs/driverfs/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the driverfs virtual filesystem. -# - -export-objs := inode.o - -obj-y := inode.o - -include $(TOPDIR)/Rules.make diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c deleted file mode 100644 index b4b5aa9f6a55..000000000000 --- a/fs/driverfs/inode.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * driverfs.c - The device driver file system - * - * 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. - */ - -#include <linux/list.h> -#include <linux/init.h> -#include <linux/pagemap.h> -#include <linux/stat.h> -#include <linux/fs.h> -#include <linux/dcache.h> -#include <linux/namei.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/backing-dev.h> -#include <linux/driverfs_fs.h> - -#include <asm/uaccess.h> - -#undef DEBUG - -#ifdef DEBUG -# define DBG(x...) printk(x) -#else -# define DBG(x...) -#endif - -/* Random magic number */ -#define DRIVERFS_MAGIC 0x42454552 - -static struct super_operations driverfs_ops; -static struct file_operations driverfs_file_operations; -static struct inode_operations driverfs_dir_inode_operations; -static struct address_space_operations driverfs_aops; - -static struct vfsmount *driverfs_mount; -static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; -static int mount_count = 0; - -static struct backing_dev_info driverfs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .memory_backed = 1, /* Does not contribute to dirty memory */ -}; - -static int driverfs_readpage(struct file *file, struct page * page) -{ - if (!PageUptodate(page)) { - void *kaddr = kmap_atomic(page, KM_USER0); - - memset(kaddr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - SetPageUptodate(page); - } - unlock_page(page); - return 0; -} - -static int driverfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) -{ - if (!PageUptodate(page)) { - void *kaddr = kmap_atomic(page, KM_USER0); - - memset(kaddr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - SetPageUptodate(page); - } - return 0; -} - -static int driverfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) -{ - struct inode *inode = page->mapping->host; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - - set_page_dirty(page); - if (pos > inode->i_size) - inode->i_size = pos; - return 0; -} - - -struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_mapping->a_ops = &driverfs_aops; - inode->i_mapping->backing_dev_info = &driverfs_backing_dev_info; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &driverfs_file_operations; - break; - case S_IFDIR: - inode->i_op = &driverfs_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; - break; - case S_IFLNK: - inode->i_op = &page_symlink_inode_operations; - break; - } - } - return inode; -} - -static int driverfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) -{ - struct inode *inode; - int error = -ENOSPC; - - if (dentry->d_inode) - return -EEXIST; - - /* only allow create if ->d_fsdata is not NULL (so we can assume it - * comes from the driverfs API below. */ - inode = driverfs_get_inode(dir->i_sb, mode, dev); - if (inode) { - d_instantiate(dentry, inode); - error = 0; - } - return error; -} - -static int driverfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int res; - mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR; - res = driverfs_mknod(dir, dentry, mode, 0); - if (!res) - dir->i_nlink++; - return res; -} - -static int driverfs_create(struct inode *dir, struct dentry *dentry, int mode) -{ - int res; - mode = (mode & S_IALLUGO) | S_IFREG; - res = driverfs_mknod(dir, dentry, mode, 0); - return res; -} - -static int driverfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) -{ - struct inode *inode; - int error = -ENOSPC; - - if (dentry->d_inode) - return -EEXIST; - - inode = driverfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); - if (inode) { - int l = strlen(symname)+1; - error = page_symlink(inode, symname, l); - if (!error) { - d_instantiate(dentry, inode); - dget(dentry); - } else - iput(inode); - } - return error; -} - -static inline int driverfs_positive(struct dentry *dentry) -{ - return (dentry->d_inode && !d_unhashed(dentry)); -} - -static int driverfs_empty(struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dcache_lock); - - list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_child); - if (driverfs_positive(de)) { - spin_unlock(&dcache_lock); - return 0; - } - } - - spin_unlock(&dcache_lock); - return 1; -} - -static int driverfs_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - down(&inode->i_sem); - dentry->d_inode->i_nlink--; - up(&inode->i_sem); - d_invalidate(dentry); - dput(dentry); - return 0; -} - -/** - * driverfs_read_file - "read" data from a file. - * @file: file pointer - * @buf: buffer to fill - * @count: number of bytes to read - * @ppos: starting offset in file - * - * Userspace wants data from a file. It is up to the creator of the file to - * provide that data. - * There is a struct device_attribute embedded in file->private_data. We - * obtain that and check if the read callback is implemented. If so, we call - * it, passing the data field of the file entry. - * Said callback is responsible for filling the buffer and returning the number - * of bytes it put in it. We update @ppos correctly. - */ -static ssize_t -driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct attribute * attr = file->f_dentry->d_fsdata; - struct driver_dir_entry * dir; - unsigned char *page; - ssize_t retval = 0; - - dir = file->f_dentry->d_parent->d_fsdata; - if (!dir->ops->show) - return 0; - - if (count > PAGE_SIZE) - count = PAGE_SIZE; - - page = (unsigned char*)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - while (count > 0) { - ssize_t len; - - len = dir->ops->show(dir,attr,page,count,*ppos); - - if (len <= 0) { - if (len < 0) - retval = len; - break; - } else if (len > count) - len = count; - - if (copy_to_user(buf,page,len)) { - retval = -EFAULT; - break; - } - - *ppos += len; - count -= len; - buf += len; - retval += len; - } - free_page((unsigned long)page); - return retval; -} - -/** - * driverfs_write_file - "write" to a file - * @file: file pointer - * @buf: data to write - * @count: number of bytes - * @ppos: starting offset - * - * Similarly to driverfs_read_file, we act essentially as a bit pipe. - * We check for a "write" callback in file->private_data, and pass - * @buffer, @count, @ppos, and the file entry's data to the callback. - * The number of bytes written is returned, and we handle updating - * @ppos properly. - */ -static ssize_t -driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - struct attribute * attr = file->f_dentry->d_fsdata; - struct driver_dir_entry * dir; - ssize_t retval = 0; - char * page; - - dir = file->f_dentry->d_parent->d_fsdata; - - page = (char *)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - if (count >= PAGE_SIZE) - count = PAGE_SIZE - 1; - if (copy_from_user(page,buf,count)) - goto done; - *(page + count) = '\0'; - - while (count > 0) { - ssize_t len; - - len = dir->ops->store(dir,attr,page + retval,count,*ppos); - - if (len <= 0) { - if (len < 0) - retval = len; - break; - } - retval += len; - count -= len; - *ppos += len; - buf += len; - } - done: - free_page((unsigned long)page); - return retval; -} - -static loff_t -driverfs_file_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t retval = -EINVAL; - - down(&file->f_dentry->d_inode->i_sem); - switch(orig) { - case 0: - if (offset > 0) { - file->f_pos = offset; - retval = file->f_pos; - } - break; - case 1: - if ((offset + file->f_pos) > 0) { - file->f_pos += offset; - retval = file->f_pos; - } - break; - default: - break; - } - up(&file->f_dentry->d_inode->i_sem); - return retval; -} - -static int driverfs_open_file(struct inode * inode, struct file * filp) -{ - struct driver_dir_entry * dir; - int error = 0; - - dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - if (dir) { - struct attribute * attr = filp->f_dentry->d_fsdata; - if (attr && dir->ops) { - if (dir->ops->open) - error = dir->ops->open(dir); - goto Done; - } - } - error = -EINVAL; - Done: - return error; -} - -static int driverfs_release(struct inode * inode, struct file * filp) -{ - struct driver_dir_entry * dir; - dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - if (dir->ops->close) - dir->ops->close(dir); - return 0; -} - -static struct file_operations driverfs_file_operations = { - .read = driverfs_read_file, - .write = driverfs_write_file, - .llseek = driverfs_file_lseek, - .open = driverfs_open_file, - .release = driverfs_release, -}; - -static struct inode_operations driverfs_dir_inode_operations = { - .lookup = simple_lookup, -}; - -static struct address_space_operations driverfs_aops = { - .readpage = driverfs_readpage, - .writepage = fail_writepage, - .prepare_write = driverfs_prepare_write, - .commit_write = driverfs_commit_write -}; - -static struct super_operations driverfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, -}; - -static int driverfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - struct dentry *root; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = DRIVERFS_MAGIC; - sb->s_op = &driverfs_ops; - inode = driverfs_get_inode(sb, S_IFDIR | 0755, 0); - - if (!inode) { - DBG("%s: could not get inode!\n",__FUNCTION__); - return -ENOMEM; - } - - root = d_alloc_root(inode); - if (!root) { - DBG("%s: could not get root dentry!\n",__FUNCTION__); - iput(inode); - return -ENOMEM; - } - sb->s_root = root; - return 0; -} - -static struct super_block *driverfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) -{ - return get_sb_single(fs_type, flags, data, driverfs_fill_super); -} - -static struct file_system_type driverfs_fs_type = { - .owner = THIS_MODULE, - .name = "driverfs", - .get_sb = driverfs_get_sb, - .kill_sb = kill_litter_super, -}; - -static int get_mount(void) -{ - struct vfsmount * mnt; - - spin_lock(&mount_lock); - if (driverfs_mount) { - mntget(driverfs_mount); - ++mount_count; - spin_unlock(&mount_lock); - goto go_ahead; - } - - spin_unlock(&mount_lock); - mnt = kern_mount(&driverfs_fs_type); - - if (IS_ERR(mnt)) { - printk(KERN_ERR "driverfs: could not mount!\n"); - return -ENODEV; - } - - spin_lock(&mount_lock); - if (!driverfs_mount) { - driverfs_mount = mnt; - ++mount_count; - spin_unlock(&mount_lock); - goto go_ahead; - } - - mntget(driverfs_mount); - ++mount_count; - spin_unlock(&mount_lock); - - go_ahead: - DBG("driverfs: mount_count = %d\n",mount_count); - return 0; -} - -static void put_mount(void) -{ - struct vfsmount * mnt; - - spin_lock(&mount_lock); - mnt = driverfs_mount; - --mount_count; - if (!mount_count) - driverfs_mount = NULL; - spin_unlock(&mount_lock); - mntput(mnt); - DBG("driverfs: mount_count = %d\n",mount_count); -} - -static int __init driverfs_init(void) -{ - return register_filesystem(&driverfs_fs_type); -} - -core_initcall(driverfs_init); - -static struct dentry * get_dentry(struct dentry * parent, const char * name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - -/** - * driverfs_create_dir - create a directory in the filesystem - * @entry: directory entry - * @parent: parent directory entry - */ -int -driverfs_create_dir(struct driver_dir_entry * entry, - struct driver_dir_entry * parent) -{ - struct dentry * dentry = NULL; - struct dentry * parent_dentry; - int error = 0; - - if (!entry) - return -EINVAL; - - get_mount(); - - parent_dentry = parent ? parent->dentry : NULL; - - if (!parent_dentry) - if (driverfs_mount && driverfs_mount->mnt_sb) - parent_dentry = driverfs_mount->mnt_sb->s_root; - - if (!parent_dentry) { - put_mount(); - return -EFAULT; - } - - down(&parent_dentry->d_inode->i_sem); - dentry = get_dentry(parent_dentry,entry->name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *) entry; - entry->dentry = dentry; - error = driverfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); - } else - error = PTR_ERR(dentry); - up(&parent_dentry->d_inode->i_sem); - - if (error) - put_mount(); - return error; -} - -/** - * driverfs_create_file - create a file - * @entry: structure describing the file - * @parent: directory to create it in - */ -int -driverfs_create_file(struct attribute * entry, - struct driver_dir_entry * parent) -{ - struct dentry * dentry; - int error = 0; - - if (!entry || !parent) - return -EINVAL; - - if (!parent->dentry) { - put_mount(); - return -EINVAL; - } - - down(&parent->dentry->d_inode->i_sem); - dentry = get_dentry(parent->dentry,entry->name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *)entry; - error = driverfs_create(parent->dentry->d_inode,dentry,entry->mode); - } else - error = PTR_ERR(dentry); - up(&parent->dentry->d_inode->i_sem); - return error; -} - -/** - * driverfs_create_symlink - make a symlink - * @parent: directory we're creating in - * @entry: entry describing link - * @target: place we're symlinking to - * - */ -int driverfs_create_symlink(struct driver_dir_entry * parent, - char * name, char * target) -{ - struct dentry * dentry; - int error = 0; - - if (!parent) - return -EINVAL; - - if (!parent->dentry) { - put_mount(); - return -EINVAL; - } - down(&parent->dentry->d_inode->i_sem); - dentry = get_dentry(parent->dentry,name); - if (!IS_ERR(dentry)) - error = driverfs_symlink(parent->dentry->d_inode,dentry,target); - else - error = PTR_ERR(dentry); - up(&parent->dentry->d_inode->i_sem); - return error; -} - -/** - * driverfs_remove_file - exported file removal - * @dir: directory the file supposedly resides in - * @name: name of the file - * - * Try and find the file in the dir's list. - * If it's there, call __remove_file() (above) for the dentry. - */ -void driverfs_remove_file(struct driver_dir_entry * dir, const char * name) -{ - struct dentry * dentry; - - if (!dir->dentry) - return; - - down(&dir->dentry->d_inode->i_sem); - dentry = get_dentry(dir->dentry,name); - if (!IS_ERR(dentry)) { - /* make sure dentry is really there */ - if (dentry->d_inode && - (dentry->d_parent->d_inode == dir->dentry->d_inode)) { - driverfs_unlink(dir->dentry->d_inode,dentry); - } - } - up(&dir->dentry->d_inode->i_sem); -} - -/** - * driverfs_remove_dir - exportable directory removal - * @dir: directory to remove - * - * To make sure we don't orphan anyone, first remove - * all the children in the list, then do clean up the directory. - */ -void driverfs_remove_dir(struct driver_dir_entry * dir) -{ - struct list_head * node, * next; - struct dentry * dentry = dir->dentry; - struct dentry * parent; - - if (!dentry) - goto done; - - parent = dget(dentry->d_parent); - down(&parent->d_inode->i_sem); - down(&dentry->d_inode->i_sem); - - list_for_each_safe(node,next,&dentry->d_subdirs) { - struct dentry * d = list_entry(node,struct dentry,d_child); - /* make sure dentry is still there */ - if (d->d_inode) - driverfs_unlink(dentry->d_inode,d); - } - - d_invalidate(dentry); - if (driverfs_empty(dentry)) { - dentry->d_inode->i_nlink -= 2; - dentry->d_inode->i_flags |= S_DEAD; - parent->d_inode->i_nlink--; - } - up(&dentry->d_inode->i_sem); - dput(dentry); - - up(&parent->d_inode->i_sem); - dput(parent); - done: - put_mount(); -} - -EXPORT_SYMBOL(driverfs_create_file); -EXPORT_SYMBOL(driverfs_create_symlink); -EXPORT_SYMBOL(driverfs_create_dir); -EXPORT_SYMBOL(driverfs_remove_file); -EXPORT_SYMBOL(driverfs_remove_dir); -MODULE_LICENSE("GPL"); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 068559518ba5..a414496bf6cf 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -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; } + diff --git a/include/linux/device.h b/include/linux/device.h index 2e0948e96d68..0bea391871ae 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -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...) \ diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h deleted file mode 100644 index b4270e947a1e..000000000000 --- a/include/linux/driverfs_fs.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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_ */ diff --git a/include/linux/genhd.h b/include/linux/genhd.h index ff1885251c12..548e477daa4b 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.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 diff --git a/include/linux/kobject.h b/include/linux/kobject.h index d2f0629a6189..40de16d0a227 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -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; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 7a46c9f0c308..29c3eb8d2c9e 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -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 *); diff --git a/init/do_mounts.c b/init/do_mounts.c index 2a8fb51550ca..040e8671d449 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -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) { |
