Commit 8a9af19f authored by Patrick Mochel's avatar Patrick Mochel

Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin

into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
parents 77b3055a 43524309
...@@ -11,11 +11,11 @@ structures, most of the binding can take place using common code. ...@@ -11,11 +11,11 @@ structures, most of the binding can take place using common code.
Bus Bus
~~~ ~~~
The bus type structure contains a list of all devices that on that bus The bus type structure contains a list of all devices that are on that bus
type in the system. When device_register is called for a device, it is type in the system. When device_register is called for a device, it is
inserted into the end of this list. The bus object also contains a inserted into the end of this list. The bus object also contains a
list of all drivers of that bus type. When driver_register is called list of all drivers of that bus type. When driver_register is called
for a driver, it is inserted into the end of this list. These are the for a driver, it is inserted at the end of this list. These are the
two events which trigger driver binding. two events which trigger driver binding.
...@@ -42,7 +42,7 @@ Device Class ...@@ -42,7 +42,7 @@ Device Class
~~~~~~~~~~~~ ~~~~~~~~~~~~
Upon the successful completion of probe, the device is registered with Upon the successful completion of probe, the device is registered with
the class to which it belongs. Device drivers belong to one and only the class to which it belongs. Device drivers belong to one and only one
class, and that is set in the driver's devclass field. class, and that is set in the driver's devclass field.
devclass_add_device is called to enumerate the device within the class devclass_add_device is called to enumerate the device within the class
and actually register it with the class, which happens with the and actually register it with the class, which happens with the
...@@ -61,7 +61,7 @@ driver's list of devices. ...@@ -61,7 +61,7 @@ driver's list of devices.
sysfs sysfs
~~~~~~~~ ~~~~~
A symlink is created in the bus's 'devices' directory that points to A symlink is created in the bus's 'devices' directory that points to
the device's directory in the physical hierarchy. the device's directory in the physical hierarchy.
......
...@@ -58,7 +58,7 @@ match(): Attaching Drivers to Devices ...@@ -58,7 +58,7 @@ match(): Attaching Drivers to Devices
The format of device ID structures and the semantics for comparing The format of device ID structures and the semantics for comparing
them are inherently bus-specific. Drivers typically declare an array them are inherently bus-specific. Drivers typically declare an array
of device IDs of device they support that reside in a bus-specific of device IDs of devices they support that reside in a bus-specific
driver structure. driver structure.
The purpose of the match callback is provide the bus an opportunity to The purpose of the match callback is provide the bus an opportunity to
...@@ -153,7 +153,7 @@ directory: ...@@ -153,7 +153,7 @@ directory:
|-- agpgart |-- agpgart
`-- e100 `-- e100
Each device that is discovered a bus of that type gets a symlink in Each device that is discovered on a bus of that type gets a symlink in
the bus's devices directory to the device's directory in the physical the bus's devices directory to the device's directory in the physical
hierarchy: hierarchy:
......
...@@ -105,7 +105,7 @@ default subdirectories: ...@@ -105,7 +105,7 @@ default subdirectories:
Drivers registered with the class get a symlink in the drivers/ directory Drivers registered with the class get a symlink in the drivers/ directory
that points the driver's directory (under its bus directory): that points to the driver's directory (under its bus directory):
class/ class/
`-- input `-- input
......
...@@ -47,11 +47,13 @@ intf_list: List of intf_data. There is one structure allocated for ...@@ -47,11 +47,13 @@ intf_list: List of intf_data. There is one structure allocated for
children: List of child devices. children: List of child devices.
parent: *** FIXME ***
name: ASCII description of device. name: ASCII description of device.
Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
bus_id: ASCII representation of device's bus position. This bus_id: ASCII representation of device's bus position. This
field should a name unique across all devices on the field should be a name unique across all devices on the
bus type the device belongs to. bus type the device belongs to.
Example: PCI bus_ids are in the form of Example: PCI bus_ids are in the form of
...@@ -66,12 +68,12 @@ bus: Pointer to struct bus_type that device belongs to. ...@@ -66,12 +68,12 @@ bus: Pointer to struct bus_type that device belongs to.
dir: Device's sysfs directory. dir: Device's sysfs directory.
class_num: Class-enumerated value of the device.
driver: Pointer to struct device_driver that controls the device. driver: Pointer to struct device_driver that controls the device.
driver_data: Driver-specific data. driver_data: Driver-specific data.
class_num: Class-enumerated value of the device.
platform_data: Platform data specific to the device. platform_data: Platform data specific to the device.
current_state: Current power state of the device. current_state: Current power state of the device.
...@@ -108,7 +110,7 @@ get_device() will return a pointer to the struct device passed to it ...@@ -108,7 +110,7 @@ get_device() will return a pointer to the struct device passed to it
if the reference is not already 0 (if it's in the process of being if the reference is not already 0 (if it's in the process of being
removed already). removed already).
A driver can take use the lock in the device structure using: A driver can access the lock in the device structure using:
void lock_device(struct device * dev); void lock_device(struct device * dev);
void unlock_device(struct device * dev); void unlock_device(struct device * dev);
......
...@@ -63,9 +63,9 @@ Most drivers will not be able to be converted completely to the new ...@@ -63,9 +63,9 @@ Most drivers will not be able to be converted completely to the new
model because the bus they belong to has a bus-specific structure with model because the bus they belong to has a bus-specific structure with
bus-specific fields that cannot be generalized. bus-specific fields that cannot be generalized.
The most common example this are device ID structures. A driver The most common example of this are device ID structures. A driver
typically defines an array of device IDs that it supports. The format typically defines an array of device IDs that it supports. The format
of this structure and the semantics for comparing device IDs is of these structures and the semantics for comparing device IDs are
completely bus-specific. Defining them as bus-specific entities would completely bus-specific. Defining them as bus-specific entities would
sacrifice type-safety, so we keep bus-specific structures around. sacrifice type-safety, so we keep bus-specific structures around.
...@@ -77,8 +77,8 @@ struct pci_driver { ...@@ -77,8 +77,8 @@ struct pci_driver {
struct device_driver driver; struct device_driver driver;
}; };
A definition that included bus-specific fields would look something A definition that included bus-specific fields would look like
like (using the eepro100 driver again): (using the eepro100 driver again):
static struct pci_driver eepro100_driver = { static struct pci_driver eepro100_driver = {
.id_table = eepro100_pci_tbl, .id_table = eepro100_pci_tbl,
...@@ -109,7 +109,7 @@ struct device_driver object. ...@@ -109,7 +109,7 @@ struct device_driver object.
Most drivers, however, will have a bus-specific structure and will Most drivers, however, will have a bus-specific structure and will
need to register with the bus using something like pci_driver_register. need to register with the bus using something like pci_driver_register.
It is important that drivers register their drivers as early as It is important that drivers register their driver structure as early as
possible. Registration with the core initializes several fields in the possible. Registration with the core initializes several fields in the
struct device_driver object, including the reference count and the struct device_driver object, including the reference count and the
lock. These fields are assumed to be valid at all times and may be lock. These fields are assumed to be valid at all times and may be
...@@ -148,7 +148,7 @@ accesses it. ...@@ -148,7 +148,7 @@ accesses it.
sysfs sysfs
~~~~~~~~ ~~~~~
When a driver is registered, a sysfs directory is created in its When a driver is registered, a sysfs directory is created in its
bus's directory. In this directory, the driver can export an interface bus's directory. In this directory, the driver can export an interface
...@@ -205,7 +205,7 @@ management based on the requirements of the system and the ...@@ -205,7 +205,7 @@ management based on the requirements of the system and the
user-defined policy. user-defined policy.
SUSPEND_NOTIFY notifies the device that a suspend transition is about SUSPEND_NOTIFY notifies the device that a suspend transition is about
to happen. This happens on system power state transition to verify to happen. This happens on system power state transitions to verify
that all devices can successfully suspend. that all devices can successfully suspend.
A driver may choose to fail on this call, which should cause the A driver may choose to fail on this call, which should cause the
......
...@@ -82,7 +82,7 @@ Devices are enumerated within the interface. This happens in interface_add_data( ...@@ -82,7 +82,7 @@ Devices are enumerated within the interface. This happens in interface_add_data(
and the enumerated value is stored in the struct intf_data for that device. and the enumerated value is stored in the struct intf_data for that device.
sysfs sysfs
~~~~~~~~ ~~~~~
Each interface is given a directory in the directory of the device Each interface is given a directory in the directory of the device
class it belongs to: class it belongs to:
...@@ -120,10 +120,10 @@ device interface. ...@@ -120,10 +120,10 @@ device interface.
Many interfaces have a major number associated with them and each Many interfaces have a major number associated with them and each
device gets a minor number. Or, multiple interfaces might share one device gets a minor number. Or, multiple interfaces might share one
major number, and each get receive a range of minor numbers (like in major number, and each will receive a range of minor numbers (like in
the case of input devices). the case of input devices).
These major and minor numbers could be stored in the interface These major and minor numbers could be stored in the interface
structure. Major and minor allocation could happen when the interface structure. Major and minor allocations could happen when the interface
is registered with the class, or via a helper function. is registered with the class, or via a helper function.
...@@ -9,7 +9,7 @@ Overview ...@@ -9,7 +9,7 @@ Overview
~~~~~~~~ ~~~~~~~~
This driver model is a unification of all the current, disparate driver models This driver model is a unification of all the current, disparate driver models
that are currently in the kernel. It is intended is to augment the that are currently in the kernel. It is intended to augment the
bus-specific drivers for bridges and devices by consolidating a set of data bus-specific drivers for bridges and devices by consolidating a set of data
and operations into globally accessible data structures. and operations into globally accessible data structures.
...@@ -23,7 +23,7 @@ tree as well as its local tree. In fact, the local tree becomes just a subset ...@@ -23,7 +23,7 @@ tree as well as its local tree. In fact, the local tree becomes just a subset
of the global tree. of the global tree.
Common data fields can also be moved out of the local bus models into the Common data fields can also be moved out of the local bus models into the
global model. Some of the manipulation of these fields can also be global model. Some of the manipulations of these fields can also be
consolidated. Most likely, manipulation functions will become a set consolidated. Most likely, manipulation functions will become a set
of helper functions, which the bus drivers wrap around to include any of helper functions, which the bus drivers wrap around to include any
bus-specific items. bus-specific items.
...@@ -71,7 +71,7 @@ fields of struct device unless there is a strong compelling reason to do so. ...@@ -71,7 +71,7 @@ fields of struct device unless there is a strong compelling reason to do so.
This abstraction is prevention of unnecessary pain during transitional phases. This abstraction is prevention of unnecessary pain during transitional phases.
If the name of the field changes or is removed, then every downstream driver If the name of the field changes or is removed, then every downstream driver
will break. On the other hand, if only the bus layer (and not the device will break. On the other hand, if only the bus layer (and not the device
layer) accesses struct device, it is only those that need to change. layer) accesses struct device, it is only that layer that needs to change.
User Interface User Interface
...@@ -96,9 +96,9 @@ Whenever a device is inserted into the tree, a directory is created for it. ...@@ -96,9 +96,9 @@ Whenever a device is inserted into the tree, a directory is created for it.
This directory may be populated at each layer of discovery - the global layer, This directory may be populated at each layer of discovery - the global layer,
the bus layer, or the device layer. the bus layer, or the device layer.
The global layer currently creates two files - name and 'power'. The The global layer currently creates two files - 'name' and 'power'. The
former only reports the name of the device. The latter reports the former only reports the name of the device. The latter reports the
current power state of the device. It also be used to set the current current power state of the device. It will also be used to set the current
power state. power state.
The bus layer may also create files for the devices it finds while probing the The bus layer may also create files for the devices it finds while probing the
......
...@@ -10,9 +10,9 @@ host bridges to peripheral buses. ...@@ -10,9 +10,9 @@ host bridges to peripheral buses.
Platform drivers Platform drivers
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
Drivers for platform devices have typically very simple and Drivers for platform devices are typically very simple and
unstructured. Either the device was present at a particular I/O port unstructured. Either the device was present at a particular I/O port
and the driver was loaded, or there was not. There was no possibility and the driver was loaded, or it was not. There was no possibility
of hotplugging or alternative discovery besides probing at a specific of hotplugging or alternative discovery besides probing at a specific
I/O address and expecting a specific response. I/O address and expecting a specific response.
...@@ -49,7 +49,7 @@ devices that it discovers via the bus's add() callback: ...@@ -49,7 +49,7 @@ devices that it discovers via the bus's add() callback:
Bus IDs Bus IDs
~~~~~~~ ~~~~~~~
Bus IDs are the canonical name for the device. There is no globally Bus IDs are the canonical names for the devices. There is no globally
standard addressing mechanism for legacy devices. In the IA-32 world, standard addressing mechanism for legacy devices. In the IA-32 world,
we have Pnp IDs to use, as well as the legacy I/O ports. However, we have Pnp IDs to use, as well as the legacy I/O ports. However,
neither tell what the device really is or have any meaning on other neither tell what the device really is or have any meaning on other
...@@ -62,7 +62,7 @@ within the scope of the kernel). ...@@ -62,7 +62,7 @@ within the scope of the kernel).
For example, a serial driver might find a device at I/O 0x3f8. The For example, a serial driver might find a device at I/O 0x3f8. The
ACPI firmware might also discover a device with PnP ID (_HID) ACPI firmware might also discover a device with PnP ID (_HID)
PNP0501. Both correspond to the same device should be mapped to the PNP0501. Both correspond to the same device and should be mapped to the
canonical name 'serial'. canonical name 'serial'.
The bus_id field should be a concatenation of the canonical name and The bus_id field should be a concatenation of the canonical name and
...@@ -88,7 +88,7 @@ Driver Binding ...@@ -88,7 +88,7 @@ Driver Binding
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
Legacy drivers assume they are bound to the device once they start up Legacy drivers assume they are bound to the device once they start up
and probe an I/O port. Divorcing them from this will be a difficult and probe an I/O port. Divorcing them from this will be a difficult
process. However, that shouldn't prevent us from impelementing process. However, that shouldn't prevent us from implementing
firmware-based enumeration. firmware-based enumeration.
The firmware should notify the platform bus about devices before the The firmware should notify the platform bus about devices before the
......
...@@ -128,7 +128,7 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj) ...@@ -128,7 +128,7 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
The bus_id is an ASCII string that contains the device's address on The bus_id is an ASCII string that contains the device's address on
the bus. The format of this string is bus-specific. This is the bus. The format of this string is bus-specific. This is
necessary for representing device in sysfs. necessary for representing devices in sysfs.
parent is the physical parent of the device. It is important that parent is the physical parent of the device. It is important that
the bus driver sets this field correctly. the bus driver sets this field correctly.
...@@ -286,7 +286,7 @@ parameters. ...@@ -286,7 +286,7 @@ parameters.
It would be difficult and tedious to force every driver on a bus to It would be difficult and tedious to force every driver on a bus to
simultaneously convert their drivers to generic format. Instead, the simultaneously convert their drivers to generic format. Instead, the
bus driver should define single instances of the generic methods that bus driver should define single instances of the generic methods that
forward calls to the bus-specific drivers. For instance: forward call to the bus-specific drivers. For instance:
static int pci_device_remove(struct device * dev) static int pci_device_remove(struct device * dev)
...@@ -330,8 +330,8 @@ registered with the bus at any time. When registration happens, ...@@ -330,8 +330,8 @@ registered with the bus at any time. When registration happens,
devices must be bound to a driver, or drivers must be bound to all devices must be bound to a driver, or drivers must be bound to all
devices that it supports. devices that it supports.
Drivers typically contain a list of device IDs that it supports. The A driver typically contains a list of device IDs that it supports. The
bus driver compares this ID to the ID of devices registered with it. bus driver compares these IDs to the IDs of devices registered with it.
The format of the device IDs, and the semantics for comparing them are The format of the device IDs, and the semantics for comparing them are
bus-specific, so the generic model does attempt to generalize them. bus-specific, so the generic model does attempt to generalize them.
...@@ -396,7 +396,7 @@ This is called immediately before /sbin/hotplug is executed. ...@@ -396,7 +396,7 @@ This is called immediately before /sbin/hotplug is executed.
Step 7: Cleaning up the bus driver. Step 7: Cleaning up the bus driver.
The generic bus, device, and driver structures provide several fields The generic bus, device, and driver structures provide several fields
that can replace those define privately to the bus driver. that can replace those defined privately to the bus driver.
- Device list. - Device list.
......
...@@ -9,7 +9,7 @@ Patrick Mochel <mochel@osdl.org> ...@@ -9,7 +9,7 @@ Patrick Mochel <mochel@osdl.org>
The kobject infrastructure performs basic object management that larger The kobject infrastructure performs basic object management that larger
data structures and subsystems can leverage, rather than reimplement data structures and subsystems can leverage, rather than reimplement
similar functionality. This functionality consists primarily concerns: similar functionality. This functionality primarily concerns:
- Object reference counting. - Object reference counting.
- Maintaining lists (sets) of objects. - Maintaining lists (sets) of objects.
...@@ -45,7 +45,7 @@ and allows kobjects and ksets to be used without being registered ...@@ -45,7 +45,7 @@ and allows kobjects and ksets to be used without being registered
struct kobject is a simple data type that provides a foundation for struct kobject is a simple data type that provides a foundation for
more complex object types. It provides a set of basic fields that more complex object types. It provides a set of basic fields that
almost all complex data types share. kobjects are intended to be almost all complex data types share. kobjects are intended to be
embedded in larger data structures and replace fields it duplicates. embedded in larger data structures and replace fields they duplicate.
1.2 Defintion 1.2 Defintion
...@@ -77,7 +77,7 @@ using kobject_register() and kobject_unregister(). Registration ...@@ -77,7 +77,7 @@ using kobject_register() and kobject_unregister(). Registration
includes inserting the kobject in the list of its dominant kset and includes inserting the kobject in the list of its dominant kset and
creating a directory for it in sysfs. creating a directory for it in sysfs.
Alternatively, one may use a kobject without adding to its kset's list Alternatively, one may use a kobject without adding it to its kset's list
or exporting it via sysfs, by simply calling kobject_init(). An or exporting it via sysfs, by simply calling kobject_init(). An
initialized kobject may later be added to the object hierarchy by initialized kobject may later be added to the object hierarchy by
calling kobject_add(). An initialized kobject may be used for calling kobject_add(). An initialized kobject may be used for
...@@ -87,8 +87,8 @@ Note: calling kobject_init(), then kobject_add() is functionally ...@@ -87,8 +87,8 @@ Note: calling kobject_init(), then kobject_add() is functionally
equivalent to calling kobject_register(). equivalent to calling kobject_register().
When a kobject is unregistered, it is removed from its kset's list, When a kobject is unregistered, it is removed from its kset's list,
removed from the sysfs filesystem, and its reference decremented. List removed from the sysfs filesystem, and its reference count is decremented.
and sysfs removal happen in kobject_del(), and may be called List and sysfs removal happen in kobject_del(), and may be called
manually. kobject_put() decrements the reference count, and may also manually. kobject_put() decrements the reference count, and may also
be called manually. be called manually.
...@@ -98,8 +98,8 @@ kobject_put(). An object's reference count may only be incremented if ...@@ -98,8 +98,8 @@ kobject_put(). An object's reference count may only be incremented if
it is already positive. it is already positive.
When a kobject's reference count reaches 0, the method struct When a kobject's reference count reaches 0, the method struct
ktype::release() (which the kobject's kset points to) is called. This kobj_type::release() (which the kobject's kset points to) is called.
allows any memory allocated for the object to be freed. This allows any memory allocated for the object to be freed.
1.4 sysfs 1.4 sysfs
...@@ -118,7 +118,7 @@ happen for kobjects that are embedded in a struct subsystem. ...@@ -118,7 +118,7 @@ happen for kobjects that are embedded in a struct subsystem.
2. ksets 2. ksets
2.1 Desecription 2.1 Description
A kset is a set of kobjects that are embedded in the same type. A kset is a set of kobjects that are embedded in the same type.
...@@ -163,9 +163,9 @@ following code snippet illustrates how to properly express this. ...@@ -163,9 +163,9 @@ following code snippet illustrates how to properly express this.
kset_register(&disk->kset); kset_register(&disk->kset);
- The kset that the disk's embedded object belongs to is the - The kset that the disk's embedded object belongs to is the
block_kset, and is pointed to disk->kset.kobj.kset. block_kset, and is pointed to by disk->kset.kobj.kset.
- The type of object of the disk's _subordinate_ list are partitions, - The type of objects on the disk's _subordinate_ list are partitions,
and is set in disk->kset.ktype. and is set in disk->kset.ktype.
- The kset is then registered, which handles initializing and adding - The kset is then registered, which handles initializing and adding
...@@ -218,13 +218,13 @@ the object-specific fields, which include: ...@@ -218,13 +218,13 @@ the object-specific fields, which include:
- sysfs_ops: Provides conversion functions for sysfs access. Please - sysfs_ops: Provides conversion functions for sysfs access. Please
see the sysfs documentation for more information. see the sysfs documentation for more information.
- default_attrs: Default attributes to exported via sysfs when the - default_attrs: Default attributes to be exported via sysfs when the
object is registered. object is registered.
Instances of struct kobj_type are not registered; only referenced by Instances of struct kobj_type are not registered; only referenced by
the kset. A kobj_type may be referenced by an arbitrary number of the kset. A kobj_type may be referenced by an arbitrary number of
ksets, as their may be disparate sets of identical objects. ksets, as there may be disparate sets of identical objects.
......
extern struct semaphore device_sem;
extern int bus_add_device(struct device * dev); extern int bus_add_device(struct device * dev);
extern void bus_remove_device(struct device * dev); extern void bus_remove_device(struct device * dev);
......
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL;
DECLARE_MUTEX(device_sem);
/* /*
* sysfs bindings for devices. * sysfs bindings for devices.
*/ */
...@@ -180,6 +177,7 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) ...@@ -180,6 +177,7 @@ void device_remove_file(struct device * dev, struct device_attribute * attr)
void device_initialize(struct device *dev) void device_initialize(struct device *dev)
{ {
kobj_set_kset_s(dev,devices_subsys);
kobject_init(&dev->kobj); kobject_init(&dev->kobj);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
...@@ -214,7 +212,6 @@ int device_add(struct device *dev) ...@@ -214,7 +212,6 @@ int device_add(struct device *dev)
/* first, register with generic layer. */ /* first, register with generic layer. */
strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN); strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN);
kobj_set_kset_s(dev,devices_subsys);
if (parent) if (parent)
dev->kobj.parent = &parent->kobj; dev->kobj.parent = &parent->kobj;
...@@ -222,11 +219,11 @@ int device_add(struct device *dev) ...@@ -222,11 +219,11 @@ int device_add(struct device *dev)
goto register_done; goto register_done;
/* now take care of our own registration */ /* now take care of our own registration */
if (parent) {
down(&device_sem); down_write(&devices_subsys.rwsem);
if (parent)
list_add_tail(&dev->node,&parent->children); list_add_tail(&dev->node,&parent->children);
up(&device_sem); up_write(&devices_subsys.rwsem);
}
bus_add_device(dev); bus_add_device(dev);
...@@ -304,11 +301,10 @@ void device_del(struct device * dev) ...@@ -304,11 +301,10 @@ void device_del(struct device * dev)
{ {
struct device * parent = dev->parent; struct device * parent = dev->parent;
if (parent) { down_write(&devices_subsys.rwsem);
down(&device_sem); if (parent)
list_del_init(&dev->node); list_del_init(&dev->node);
up(&device_sem); up_write(&devices_subsys.rwsem);
}
/* Notify the platform of the removal, in case they /* Notify the platform of the removal, in case they
* need to do anything... * need to do anything...
......
...@@ -2,170 +2,118 @@ ...@@ -2,170 +2,118 @@
* bin.c - binary file operations for sysfs. * bin.c - binary file operations for sysfs.
*/ */
#include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/module.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "sysfs.h" #include "sysfs.h"
static struct file_operations bin_fops; static int
fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
static int fill_read(struct file * file, struct sysfs_bin_buffer * buffer)
{ {
struct bin_attribute * attr = file->f_dentry->d_fsdata; struct bin_attribute * attr = dentry->d_fsdata;
struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; struct kobject * kobj = dentry->d_parent->d_fsdata;
if (!buffer->data) return attr->read(kobj, buffer, off, count);
attr->read(kobj,buffer);
return buffer->size ? 0 : -ENOENT;
}
static int flush_read(struct file * file, char * userbuf,
struct sysfs_bin_buffer * buffer)
{
return copy_to_user(userbuf,buffer->data + buffer->offset,buffer->count) ?
-EFAULT : 0;
} }
static ssize_t static ssize_t
read(struct file * file, char * userbuf, size_t count, loff_t * off) read(struct file * file, char * userbuf, size_t count, loff_t * off)
{ {
struct sysfs_bin_buffer * buffer = file->private_data; char *buffer = file->private_data;
struct dentry *dentry = file->f_dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
int ret; int ret;
ret = fill_read(file,buffer); if (offs > size)
if (ret) return 0;
goto Done; if (offs + count > size)
count = size - offs;
buffer->offset = *off; ret = fill_read(dentry, buffer, offs, count);
if (ret < 0)
goto Done;
count = ret;
if (count > (buffer->size - *off)) ret = -EFAULT;
count = buffer->size - *off; if (copy_to_user(userbuf, buffer + offs, count) != 0)
goto Done;
buffer->count = count; *off = offs + count;
ret = count;
ret = flush_read(file,userbuf,buffer);
if (!ret) {
*off += count;
ret = count;
}
Done: Done:
if (buffer && buffer->data) {
kfree(buffer->data);
buffer->data = NULL;
}
return ret; return ret;
} }
int alloc_buf_data(struct sysfs_bin_buffer * buffer) static int
flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
{ {
buffer->data = kmalloc(buffer->count,GFP_KERNEL); struct bin_attribute *attr = dentry->d_fsdata;
if (buffer->data) { struct kobject *kobj = dentry->d_parent->d_fsdata;
memset(buffer->data,0,buffer->count);
return 0;
} else
return -ENOMEM;
}
static int fill_write(struct file * file, const char * userbuf, return attr->write(kobj, buffer, offset, count);
struct sysfs_bin_buffer * buffer)
{
return copy_from_user(buffer->data,userbuf,buffer->count) ?
-EFAULT : 0;
}
static int flush_write(struct file * file, const char * userbuf,
struct sysfs_bin_buffer * buffer)
{
struct bin_attribute * attr = file->f_dentry->d_fsdata;
struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
return attr->write(kobj,buffer);
} }
static ssize_t write(struct file * file, const char * userbuf, static ssize_t write(struct file * file, const char * userbuf,
size_t count, loff_t * off) size_t count, loff_t * off)
{ {
struct sysfs_bin_buffer * buffer = file->private_data; char *buffer = file->private_data;
struct dentry *dentry = file->f_dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
int ret; int ret;
if (count > PAGE_SIZE) if (offs > size)
count = PAGE_SIZE; return 0;
buffer->count = count; if (offs + count > size)
count = size - offs;
ret = alloc_buf_data(buffer);
if (ret)
goto Done;
ret = fill_write(file,userbuf,buffer); ret = -EFAULT;
if (ret) if (copy_from_user(buffer + offs, userbuf, count))
goto Done; goto Done;
ret = flush_write(file,userbuf,buffer); count = flush_write(dentry, buffer, offs, count);
if (ret > 0) if (count > 0)
*off += count; *off = offs + count;
ret = 0;
Done: Done:
if (buffer->data) {
kfree(buffer->data);
buffer->data = NULL;
}
return ret; return ret;
} }
static int check_perm(struct inode * inode, struct file * file) static int open(struct inode * inode, struct file * file)
{ {
struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata); struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
struct bin_attribute * attr = file->f_dentry->d_fsdata; struct bin_attribute * attr = file->f_dentry->d_fsdata;
struct sysfs_bin_buffer * buffer; int error = -EINVAL;
int error = 0;
if (!kobj || !attr) if (!kobj || !attr)
goto Einval; goto Done;
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
*/
if (file->f_mode & FMODE_WRITE) {
if (!(inode->i_mode & S_IWUGO) || !attr->write)
goto Eaccess;
}
/* File needs read support.
* The inode's perms must say it's ok, and we there
* must be a show method for it.
*/
if (file->f_mode & FMODE_READ) {
if (!(inode->i_mode & S_IRUGO) || !attr->read)
goto Eaccess;
}
buffer = kmalloc(sizeof(struct sysfs_bin_buffer),GFP_KERNEL);
if (buffer) {
memset(buffer,0,sizeof(struct sysfs_bin_buffer));
file->private_data = buffer;
} else
error = -ENOMEM;
goto Done;
Einval:
error = -EINVAL;
goto Done;
Eaccess:
error = -EACCES; error = -EACCES;
if ((file->f_mode & FMODE_WRITE) && !attr->write)
goto Done;
if ((file->f_mode & FMODE_READ) && !attr->read)
goto Done;
error = -ENOMEM;
file->private_data = kmalloc(attr->size, GFP_KERNEL);
if (!file->private_data)
goto Done;
error = 0;
Done: Done:
if (error && kobj) if (error && kobj)
kobject_put(kobj); kobject_put(kobj);
return error; return error;
} }
static int open(struct inode * inode, struct file * file)
{
return check_perm(inode,file);
}
static int release(struct inode * inode, struct file * file) static int release(struct inode * inode, struct file * file)
{ {
struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
...@@ -173,8 +121,7 @@ static int release(struct inode * inode, struct file * file) ...@@ -173,8 +121,7 @@ static int release(struct inode * inode, struct file * file)
if (kobj) if (kobj)
kobject_put(kobj); kobject_put(kobj);
if (buffer) kfree(buffer);
kfree(buffer);
return 0; return 0;
} }
......
...@@ -29,13 +29,14 @@ ...@@ -29,13 +29,14 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/ioport.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#define DEVICE_NAME_SIZE 50 #define DEVICE_NAME_SIZE 50
#define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */ #define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */
#define DEVICE_ID_SIZE 32 #define DEVICE_ID_SIZE 32
#define BUS_ID_SIZE 20 #define BUS_ID_SIZE KOBJ_NAME_LEN
enum { enum {
...@@ -388,6 +389,8 @@ struct platform_device { ...@@ -388,6 +389,8 @@ struct platform_device {
char * name; char * name;
u32 id; u32 id;
struct device dev; struct device dev;
struct resource res;
unsigned int irq;
}; };
extern int platform_device_register(struct platform_device *); extern int platform_device_register(struct platform_device *);
......
...@@ -16,18 +16,11 @@ struct attribute { ...@@ -16,18 +16,11 @@ struct attribute {
mode_t mode; mode_t mode;
}; };
struct sysfs_bin_buffer {
u8 * data;
size_t size;
size_t count;
loff_t offset;
};
struct bin_attribute { struct bin_attribute {
struct attribute attr; struct attribute attr;
size_t size; size_t size;
ssize_t (*read)(struct kobject *, struct sysfs_bin_buffer *); ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
ssize_t (*write)(struct kobject *, struct sysfs_bin_buffer *); ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
}; };
struct sysfs_ops { struct sysfs_ops {
......
...@@ -290,7 +290,11 @@ int kobject_register(struct kobject * kobj) ...@@ -290,7 +290,11 @@ int kobject_register(struct kobject * kobj)
if (kobj) { if (kobj) {
kobject_init(kobj); kobject_init(kobj);
error = kobject_add(kobj); error = kobject_add(kobj);
WARN_ON(error); if (error) {
printk("kobject_register failed for %s (%d)\n",
kobj->name,error);
dump_stack();
}
} else } else
error = -EINVAL; error = -EINVAL;
return error; return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment