Commit 1a8fca91 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/sparc-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 6f8efff7 15a586f0
......@@ -6,9 +6,16 @@ The EtherDrive (R) HOWTO for users of 2.6 kernels is found at ...
CREATING DEVICE NODES
Users of udev should find device nodes created automatically. Two
scripts are provided in Documentation/aoe as examples of static
device node creation for using the aoe driver.
Users of udev should find the block device nodes created
automatically, but to create all the necessary device nodes, use the
udev configuration rules provided in udev.txt (in this directory).
There is a udev-install.sh script that shows how to install these
rules on your system.
If you are not using udev, two scripts are provided in
Documentation/aoe as examples of static device node creation for
using the aoe driver.
rm -rf /dev/etherd
sh Documentation/aoe/mkdevs.sh /dev/etherd
......
......@@ -4,10 +4,13 @@
set -e
format="%8s\t%8s\t%8s\n"
me=`basename $0`
sysd=${sysfs_dir:-/sys}
# printf "$format" device mac netif state
test -z "`mount | grep sysfs`" && {
# Suse 9.1 Pro doesn't put /sys in /etc/mtab
#test -z "`mount | grep sysfs`" && {
test ! -d "$sysd/block" && {
echo "$me Error: sysfs is not mounted" 1>&2
exit 1
}
......@@ -16,7 +19,7 @@ test -z "`lsmod | grep '^aoe'`" && {
exit 1
}
for d in `ls -d /sys/block/etherd* 2>/dev/null | grep -v p` end; do
for d in `ls -d $sysd/block/etherd* 2>/dev/null | grep -v p` end; do
# maybe ls comes up empty, so we use "end"
test $d = end && continue
......
# install the aoe-specific udev rules from udev.txt into
# the system's udev configuration
#
me="`basename $0`"
# find udev.conf, often /etc/udev/udev.conf
# (or environment can specify where to find udev.conf)
#
if test -z "$conf"; then
if test -r /etc/udev/udev.conf; then
conf=/etc/udev/udev.conf
else
conf="`find /etc -type f -name udev.conf 2> /dev/null`"
if test -z "$conf" || test ! -r "$conf"; then
echo "$me Error: no udev.conf found" 1>&2
exit 1
fi
fi
fi
# find the directory where udev rules are stored, often
# /etc/udev/rules.d
#
rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`"
test "$rules_d" && sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules"
# These rules tell udev what device nodes to create for aoe support.
# They may be installed along the following lines (adjusted to what
# you see on your system).
#
# ecashin@makki ~$ su
# Password:
# bash# find /etc -type f -name udev.conf
# /etc/udev/udev.conf
# bash# grep udev_rules= /etc/udev/udev.conf
# udev_rules="/etc/udev/rules.d/"
# bash# ls /etc/udev/rules.d/
# 10-wacom.rules 50-udev.rules
# bash# cp /path/to/linux-2.6.xx/Documentation/aoe/udev.txt \
# /etc/udev/rules.d/60-aoe.rules
#
# aoe char devices
SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220"
SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220"
# aoe block devices
KERNEL="etherd*", NAME="%k", GROUP="disk"
......@@ -15,3 +15,20 @@ Why: It has been unmaintained for a number of years, has unfixable
against the LSB, and can be replaced by using udev.
Who: Greg Kroah-Hartman <greg@kroah.com>
---------------------------
What: /proc/sys/cpu/*, sysctl and /proc/cpufreq interfaces to cpufreq (2.4.x interfaces)
When: January 2005
Files: drivers/cpufreq/: cpufreq_userspace.c, proc_intf.c
Why: /proc/sys/cpu/* has been deprecated since inclusion of cpufreq into
the main kernel tree. It bloats /proc/ unnecessarily and doesn't work
well with the "governor"-based design of cpufreq.
/proc/cpufreq/* has also been deprecated for a long time and was only
meant for usage during 2.5. until the new sysfs-based interface became
ready. It has an inconsistent interface which doesn't work well with
userspace setting the frequency. The output from /proc/cpufreq/* can
be emulated using "cpufreq-info --proc" (cpufrequtils).
Both interfaces are superseded by the cpufreq interface in
/sys/devices/system/cpu/cpu%n/cpufreq/.
Who: Dominik Brodowski <linux@brodo.de>
......@@ -65,7 +65,7 @@ static struct sysfs_ops driver_sysfs_ops = {
static void driver_release(struct kobject * kobj)
{
struct device_driver * drv = to_driver(kobj);
up(&drv->unload_sem);
complete(&drv->unloaded);
}
static struct kobj_type ktype_driver = {
......@@ -465,6 +465,7 @@ int bus_add_device(struct device * dev)
up_write(&dev->bus->subsys.rwsem);
device_add_attrs(bus, dev);
sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
}
return error;
}
......@@ -481,6 +482,7 @@ int bus_add_device(struct device * dev)
void bus_remove_device(struct device * dev)
{
if (dev->bus) {
sysfs_remove_link(&dev->kobj, "bus");
sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
device_remove_attrs(dev->bus, dev);
down_write(&dev->bus->subsys.rwsem);
......
......@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kdev_t.h>
#include "base.h"
#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
......@@ -139,6 +140,7 @@ int class_register(struct class * cls)
INIT_LIST_HEAD(&cls->children);
INIT_LIST_HEAD(&cls->interfaces);
init_MUTEX(&cls->sem);
error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
if (error)
return error;
......@@ -195,33 +197,6 @@ void class_device_remove_bin_file(struct class_device *class_dev,
sysfs_remove_bin_file(&class_dev->kobj, attr);
}
static int class_device_dev_link(struct class_device * class_dev)
{
if (class_dev->dev)
return sysfs_create_link(&class_dev->kobj,
&class_dev->dev->kobj, "device");
return 0;
}
static void class_device_dev_unlink(struct class_device * class_dev)
{
sysfs_remove_link(&class_dev->kobj, "device");
}
static int class_device_driver_link(struct class_device * class_dev)
{
if ((class_dev->dev) && (class_dev->dev->driver))
return sysfs_create_link(&class_dev->kobj,
&class_dev->dev->driver->kobj, "driver");
return 0;
}
static void class_device_driver_unlink(struct class_device * class_dev)
{
sysfs_remove_link(&class_dev->kobj, "driver");
}
static ssize_t
class_device_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf)
......@@ -298,9 +273,9 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct class_device *class_dev = to_class_dev(kobj);
int retval = 0;
int i = 0;
int length = 0;
int retval = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
......@@ -313,26 +288,34 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
&length, "PHYSDEVPATH=%s", path);
kfree(path);
/* add bus name of physical device */
if (dev->bus)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
/* add driver name of physical device */
if (dev->driver)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", dev->driver->name);
}
if (MAJOR(class_dev->devt)) {
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MAJOR=%u", MAJOR(class_dev->devt));
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MINOR=%u", MINOR(class_dev->devt));
}
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;
if (class_dev->class->hotplug) {
/* have the bus specific function add its stuff */
retval = class_dev->class->hotplug (class_dev, envp, num_envp,
......@@ -388,6 +371,12 @@ static void class_device_remove_attrs(struct class_device * cd)
}
}
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
return print_dev_t(buf, class_dev->devt);
}
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
void class_device_initialize(struct class_device *class_dev)
{
kobj_set_kset_s(class_dev, class_obj_subsys);
......@@ -425,16 +414,21 @@ int class_device_add(struct class_device *class_dev)
/* now take care of our own registration */
if (parent) {
down_write(&parent->subsys.rwsem);
down(&parent->sem);
list_add_tail(&class_dev->node, &parent->children);
list_for_each_entry(class_intf, &parent->interfaces, node)
if (class_intf->add)
class_intf->add(class_dev);
up_write(&parent->subsys.rwsem);
up(&parent->sem);
}
if (MAJOR(class_dev->devt))
class_device_create_file(class_dev, &class_device_attr_dev);
class_device_add_attrs(class_dev);
class_device_dev_link(class_dev);
class_device_driver_link(class_dev);
if (class_dev->dev)
sysfs_create_link(&class_dev->kobj,
&class_dev->dev->kobj, "device");
register_done:
if (error && parent)
......@@ -455,16 +449,16 @@ void class_device_del(struct class_device *class_dev)
struct class_interface * class_intf;
if (parent) {
down_write(&parent->subsys.rwsem);
down(&parent->sem);
list_del_init(&class_dev->node);
list_for_each_entry(class_intf, &parent->interfaces, node)
if (class_intf->remove)
class_intf->remove(class_dev);
up_write(&parent->subsys.rwsem);
up(&parent->sem);
}
class_device_dev_unlink(class_dev);
class_device_driver_unlink(class_dev);
if (class_dev->dev)
sysfs_remove_link(&class_dev->kobj, "device");
class_device_remove_attrs(class_dev);
kobject_del(&class_dev->kobj);
......@@ -516,8 +510,8 @@ void class_device_put(struct class_device *class_dev)
int class_interface_register(struct class_interface *class_intf)
{
struct class * parent;
struct class_device * class_dev;
struct class *parent;
struct class_device *class_dev;
if (!class_intf || !class_intf->class)
return -ENODEV;
......@@ -526,14 +520,13 @@ int class_interface_register(struct class_interface *class_intf)
if (!parent)
return -EINVAL;
down_write(&parent->subsys.rwsem);
down(&parent->sem);
list_add_tail(&class_intf->node, &parent->interfaces);
if (class_intf->add) {
list_for_each_entry(class_dev, &parent->children, node)
class_intf->add(class_dev);
}
up_write(&parent->subsys.rwsem);
up(&parent->sem);
return 0;
}
......@@ -546,14 +539,13 @@ void class_interface_unregister(struct class_interface *class_intf)
if (!parent)
return;
down_write(&parent->subsys.rwsem);
down(&parent->sem);
list_del_init(&class_intf->node);
if (class_intf->remove) {
list_for_each_entry(class_dev, &parent->children, node)
class_intf->remove(class_dev);
}
up_write(&parent->subsys.rwsem);
up(&parent->sem);
class_put(parent);
}
......
......@@ -10,18 +10,15 @@
#include <linux/config.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/err.h>
struct class_simple {
struct class_device_attribute attr;
struct class class;
};
#define to_class_simple(d) container_of(d, struct class_simple, class)
struct simple_dev {
struct list_head node;
dev_t dev;
struct class_device class_dev;
};
#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev)
......@@ -35,12 +32,6 @@ static void release_simple_dev(struct class_device *class_dev)
kfree(s_dev);
}
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
struct simple_dev *s_dev = to_simple_dev(class_dev);
return print_dev_t(buf, s_dev->dev);
}
static void class_simple_release(struct class *class)
{
struct class_simple *cs = to_class_simple(class);
......@@ -75,12 +66,6 @@ struct class_simple *class_simple_create(struct module *owner, char *name)
cs->class.class_release = class_simple_release;
cs->class.release = release_simple_dev;
cs->attr.attr.name = "dev";
cs->attr.attr.mode = S_IRUGO;
cs->attr.attr.owner = owner;
cs->attr.show = show_dev;
cs->attr.store = NULL;
retval = class_register(&cs->class);
if (retval)
goto error;
......@@ -143,7 +128,7 @@ struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev,
}
memset(s_dev, 0x00, sizeof(*s_dev));
s_dev->dev = dev;
s_dev->class_dev.devt = dev;
s_dev->class_dev.dev = device;
s_dev->class_dev.class = &cs->class;
......@@ -154,8 +139,6 @@ struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev,
if (retval)
goto error;
class_device_create_file(&s_dev->class_dev, &cs->attr);
spin_lock(&simple_dev_list_lock);
list_add(&s_dev->node, &simple_dev_list);
spin_unlock(&simple_dev_list_lock);
......@@ -200,7 +183,7 @@ void class_simple_device_remove(dev_t dev)
spin_lock(&simple_dev_list_lock);
list_for_each_entry(s_dev, &simple_dev_list, node) {
if (s_dev->dev == dev) {
if (s_dev->class_dev.devt == dev) {
found = 1;
break;
}
......
......@@ -79,14 +79,14 @@ void put_driver(struct device_driver * drv)
* since most of the things we have to do deal with the bus
* structures.
*
* The one interesting aspect is that we initialize @drv->unload_sem
* to a locked state here. It will be unlocked when the driver
* reference count reaches 0.
* The one interesting aspect is that we setup @drv->unloaded
* as a completion that gets complete when the driver reference
* count reaches 0.
*/
int driver_register(struct device_driver * drv)
{
INIT_LIST_HEAD(&drv->devices);
init_MUTEX_LOCKED(&drv->unload_sem);
init_completion(&drv->unloaded);
return bus_add_driver(drv);
}
......@@ -97,7 +97,7 @@ int driver_register(struct device_driver * drv)
*
* Again, we pass off most of the work to the bus-level call.
*
* Though, once that is done, we attempt to take @drv->unload_sem.
* Though, once that is done, we wait until @drv->unloaded is completed.
* This will block until the driver refcount reaches 0, and it is
* released. Only modular drivers will call this function, and we
* have to guarantee that it won't complete, letting the driver
......@@ -107,8 +107,7 @@ int driver_register(struct device_driver * drv)
void driver_unregister(struct device_driver * drv)
{
bus_remove_driver(drv);
down(&drv->unload_sem);
up(&drv->unload_sem);
wait_for_completion(&drv->unloaded);
}
/**
......
......@@ -25,7 +25,7 @@ struct kobj_map {
int (*lock)(dev_t, void *);
void *data;
} *probes[255];
struct rw_semaphore *sem;
struct semaphore *sem;
};
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
......@@ -53,7 +53,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->range = range;
p->data = data;
}
down_write(domain->sem);
down(domain->sem);
for (i = 0, p -= n; i < n; i++, p++, index++) {
struct probe **s = &domain->probes[index % 255];
while (*s && (*s)->range < range)
......@@ -61,7 +61,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->next = *s;
*s = p;
}
up_write(domain->sem);
up(domain->sem);
return 0;
}
......@@ -75,7 +75,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
if (n > 255)
n = 255;
down_write(domain->sem);
down(domain->sem);
for (i = 0; i < n; i++, index++) {
struct probe **s;
for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
......@@ -88,7 +88,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
}
}
}
up_write(domain->sem);
up(domain->sem);
kfree(found);
}
......@@ -99,7 +99,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
unsigned long best = ~0UL;
retry:
down_read(domain->sem);
down(domain->sem);
for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
struct kobject *(*probe)(dev_t, int *, void *);
struct module *owner;
......@@ -120,7 +120,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
module_put(owner);
continue;
}
up_read(domain->sem);
up(domain->sem);
kobj = probe(dev, index, data);
/* Currently ->owner protects _only_ ->probe() itself. */
module_put(owner);
......@@ -128,12 +128,11 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
return kobj;
goto retry;
}
up_read(domain->sem);
up(domain->sem);
return NULL;
}
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe,
struct subsystem *s)
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
{
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
......@@ -151,6 +150,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe,
base->get = base_probe;
for (i = 0; i < 255; i++)
p->probes[i] = base;
p->sem = &s->rwsem;
p->sem = sem;
return p;
}
......@@ -131,7 +131,7 @@ int platform_device_register(struct platform_device * pdev)
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id);
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
......
......@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(sysdev_remove_file);
/*
* declare system_subsys
*/
decl_subsys(system, &ktype_sysdev, NULL);
static decl_subsys(system, &ktype_sysdev, NULL);
int sysdev_class_register(struct sysdev_class * cls)
{
......@@ -102,7 +102,8 @@ EXPORT_SYMBOL_GPL(sysdev_class_register);
EXPORT_SYMBOL_GPL(sysdev_class_unregister);
static LIST_HEAD(global_drivers);
static LIST_HEAD(sysdev_drivers);
static DECLARE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
......@@ -112,14 +113,14 @@ static LIST_HEAD(global_drivers);
* If @cls is valid, then @drv is inserted into @cls->drivers to be
* called on each operation on devices of that class. The refcount
* of @cls is incremented.
* Otherwise, @drv is inserted into global_drivers, and called for
* Otherwise, @drv is inserted into sysdev_drivers, and called for
* each device.
*/
int sysdev_driver_register(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
down_write(&system_subsys.rwsem);
down(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
......@@ -130,8 +131,8 @@ int sysdev_driver_register(struct sysdev_class * cls,
drv->add(dev);
}
} else
list_add_tail(&drv->entry, &global_drivers);
up_write(&system_subsys.rwsem);
list_add_tail(&drv->entry, &sysdev_drivers);
up(&sysdev_drivers_lock);
return 0;
}
......@@ -144,7 +145,7 @@ int sysdev_driver_register(struct sysdev_class * cls,
void sysdev_driver_unregister(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
down_write(&system_subsys.rwsem);
down(&sysdev_drivers_lock);
list_del_init(&drv->entry);
if (cls) {
if (drv->remove) {
......@@ -154,7 +155,7 @@ void sysdev_driver_unregister(struct sysdev_class * cls,
}
kset_put(&cls->kset);
}
up_write(&system_subsys.rwsem);
up(&sysdev_drivers_lock);
}
EXPORT_SYMBOL_GPL(sysdev_driver_register);
......@@ -193,13 +194,13 @@ int sysdev_register(struct sys_device * sysdev)
if (!error) {
struct sysdev_driver * drv;
down_write(&system_subsys.rwsem);
down(&sysdev_drivers_lock);
/* Generic notification is implicit, because it's that
* code that should have called us.
*/
/* Notify global drivers */
list_for_each_entry(drv, &global_drivers, entry) {
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->add)
drv->add(sysdev);
}
......@@ -209,7 +210,7 @@ int sysdev_register(struct sys_device * sysdev)
if (drv->add)
drv->add(sysdev);
}
up_write(&system_subsys.rwsem);
up(&sysdev_drivers_lock);
}
return error;
}
......@@ -218,8 +219,8 @@ void sysdev_unregister(struct sys_device * sysdev)
{
struct sysdev_driver * drv;
down_write(&system_subsys.rwsem);
list_for_each_entry(drv, &global_drivers, entry) {
down(&sysdev_drivers_lock);
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
}
......@@ -228,7 +229,7 @@ void sysdev_unregister(struct sys_device * sysdev)
if (drv->remove)
drv->remove(sysdev);
}
up_write(&system_subsys.rwsem);
up(&sysdev_drivers_lock);
kobject_unregister(&sysdev->kobj);
}
......@@ -255,7 +256,7 @@ void sysdev_shutdown(void)
pr_debug("Shutting Down System Devices\n");
down_write(&system_subsys.rwsem);
down(&sysdev_drivers_lock);
list_for_each_entry_reverse(cls, &system_subsys.kset.list,
kset.kobj.entry) {
struct sys_device * sysdev;
......@@ -268,7 +269,7 @@ void sysdev_shutdown(void)
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* Call global drivers first. */
list_for_each_entry(drv, &global_drivers, entry) {
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
}
......@@ -284,7 +285,7 @@ void sysdev_shutdown(void)
cls->shutdown(sysdev);
}
}
up_write(&system_subsys.rwsem);
up(&sysdev_drivers_lock);
}
......@@ -319,7 +320,7 @@ int sysdev_suspend(u32 state)
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* Call global drivers first. */
list_for_each_entry(drv, &global_drivers, entry) {
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->suspend)
drv->suspend(sysdev, state);
}
......@@ -375,7 +376,7 @@ int sysdev_resume(void)
}
/* Call global drivers. */
list_for_each_entry(drv, &global_drivers, entry) {
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->resume)
drv->resume(sysdev);
}
......
......@@ -143,7 +143,6 @@ void aoedisk_rm_sysfs(struct aoedev *d);
int aoechr_init(void);
void aoechr_exit(void);
void aoechr_error(char *);
void aoechr_hdump(char *, int len);
void aoecmd_work(struct aoedev *d);
void aoecmd_cfg(ushort, unsigned char);
......
......@@ -99,41 +99,6 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags);
up(&emsgs_sema);
}
#define PERLINE 16
void
aoechr_hdump(char *buf, int n)
{
int bufsiz;
char *fbuf;
int linelen;
char *p, *e, *fp;
bufsiz = n * 3; /* 2 hex digits and a space */
bufsiz += n / PERLINE + 1; /* the newline characters */
bufsiz += 1; /* the final '\0' */
fbuf = kmalloc(bufsiz, GFP_ATOMIC);
if (!fbuf) {
printk(KERN_INFO
"%s: cannot allocate memory\n",
__FUNCTION__);
return;
}
for (p = buf; n <= 0;) {
linelen = n > PERLINE ? PERLINE : n;
n -= linelen;
fp = fbuf;
for (e=p+linelen; p<e; p++)
fp += sprintf(fp, "%2.2X ", *p & 255);
sprintf(fp, "\n");
aoechr_error(fbuf);
}
kfree(fbuf);
}
static ssize_t
aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
{
......@@ -178,13 +143,13 @@ aoechr_rel(struct inode *inode, struct file *filp)
static ssize_t
aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
int n;
unsigned long n;
char *mp;
struct ErrMsg *em;
ssize_t len;
ulong flags;
n = (int) filp->private_data;
n = (unsigned long) filp->private_data;
switch (n) {
case MINOR_ERR:
spin_lock_irqsave(&emsgs_lock, flags);
......@@ -233,7 +198,7 @@ aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
}
}
struct file_operations aoe_fops = {
static struct file_operations aoe_fops = {
.write = aoechr_write,
.read = aoechr_read,
.open = aoechr_open,
......
......@@ -416,7 +416,9 @@ aoecmd_ata_rsp(struct sk_buff *skb)
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
"stat=%2.2Xh\n", ahout->cmdstat, ahin->cmdstat);
"stat=%2.2Xh from e%ld.%ld\n",
ahout->cmdstat, ahin->cmdstat,
d->aoemajor, d->aoeminor);
if (buf)
buf->flags |= BUFFL_FAIL;
} else {
......@@ -458,8 +460,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
if (buf) {
buf->nframesout -= 1;
if (buf->nframesout == 0 && buf->resid == 0) {
n = !(buf->flags & BUFFL_FAIL);
bio_endio(buf->bio, buf->bio->bi_size, 0);
n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
bio_endio(buf->bio, buf->bio->bi_size, n);
mempool_free(buf, d->bufpool);
}
}
......
......@@ -4370,6 +4370,10 @@ int __init floppy_init(void)
goto out_flush_work;
}
err = platform_device_register(&floppy_device);
if (err)
goto out_flush_work;
for (drive = 0; drive < N_DRIVE; drive++) {
if (!(allowed_drive_mask & (1 << drive)))
continue;
......@@ -4379,23 +4383,12 @@ int __init floppy_init(void)
disks[drive]->private_data = (void *)(long)drive;
disks[drive]->queue = floppy_queue;
disks[drive]->flags |= GENHD_FL_REMOVABLE;
disks[drive]->driverfs_dev = &floppy_device.dev;
add_disk(disks[drive]);
}
err = platform_device_register(&floppy_device);
if (err)
goto out_del_disk;
return 0;
out_del_disk:
for (drive = 0; drive < N_DRIVE; drive++) {
if (!(allowed_drive_mask & (1 << drive)))
continue;
if (fdc_state[FDC(drive)].version == FDC_NONE)
continue;
del_gendisk(disks[drive]);
}
out_flush_work:
flush_scheduled_work();
if (usage_count)
......@@ -4600,7 +4593,6 @@ void cleanup_module(void)
int drive;
init_completion(&device_release);
platform_device_unregister(&floppy_device);
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
unregister_blkdev(FLOPPY_MAJOR, "fd");
......@@ -4614,6 +4606,7 @@ void cleanup_module(void)
}
put_disk(disks[drive]);
}
platform_device_unregister(&floppy_device);
devfs_remove("floppy");
del_timer_sync(&fd_timeout);
......
......@@ -302,7 +302,7 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
static int __init genhd_device_init(void)
{
bdev_map = kobj_map_init(base_probe, &block_subsys);
bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
blk_dev_init();
subsystem_register(&block_subsys);
return 0;
......@@ -430,43 +430,58 @@ static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)
static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct device *dev = NULL;
struct kobj_type *ktype = get_ktype(kobj);
struct device *physdev;
struct gendisk *disk;
struct hd_struct *part;
int length = 0;
int i = 0;
/* get physical device backing disk or partition */
if (ktype == &ktype_block) {
struct gendisk *disk = container_of(kobj, struct gendisk, kobj);
dev = disk->driverfs_dev;
disk = container_of(kobj, struct gendisk, kobj);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u", disk->first_minor);
} else if (ktype == &ktype_part) {
struct gendisk *disk = container_of(kobj->parent, struct gendisk, kobj);
dev = disk->driverfs_dev;
}
disk = container_of(kobj->parent, struct gendisk, kobj);
part = container_of(kobj, struct hd_struct, kobj);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u",
disk->first_minor + part->partno);
} else
return 0;
if (dev) {
/* add physical device, backing this device */
char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length,
"MAJOR=%u", disk->major);
/* add physical device, backing this device */
physdev = disk->driverfs_dev;
if (physdev) {
char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path);
kfree(path);
/* add bus name of physical device */
if (dev->bus)
if (physdev->bus)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
"PHYSDEVBUS=%s",
physdev->bus->name);
/* add driver name of physical device */
if (dev->driver)
if (physdev->driver)
add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", dev->driver->name);
envp[i] = NULL;
"PHYSDEVDRIVER=%s",
physdev->driver->name);
}
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;
return 0;
}
......
......@@ -995,5 +995,7 @@ config MMTIMER
The mmtimer device allows direct userspace access to the
Altix system timer.
source "drivers/char/tpm/Kconfig"
endmenu
......@@ -89,7 +89,7 @@ obj-$(CONFIG_PCMCIA) += pcmcia/
obj-$(CONFIG_IPMI_HANDLER) += ipmi/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
......
#
# TPM device configuration
#
menu "TPM devices"
config TCG_TPM
tristate "TPM Hardware Support"
depends on EXPERIMENTAL
---help---
If you have a TPM security chip in your system, which
implements the Trusted Computing Group's specification,
say Yes and it will be accessible from within Linux. For
more information see <http://www.trustedcomputinggroup.org>.
An implementation of the Trusted Software Stack (TSS), the
userspace enablement piece of the specification, can be
obtained at: <http://sourceforge.net/projects/trousers>. To
compile this driver as a module, choose M here; the module
will be called tpm. If unsure, say N.
config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on TCG_TPM
---help---
If you have a TPM security chip from National Semicondutor
say Yes and it will be accessible from within Linux. To
compile this driver as a module, choose M here; the module
will be called tpm_nsc.
config TCG_ATMEL
tristate "Atmel TPM Interface"
depends on TCG_TPM
---help---
If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_atmel.
endmenu
#
# Makefile for the kernel tpm device drivers.
#
obj-$(CONFIG_TCG_TPM) += tpm.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
This diff is collapsed.
/*
* Copyright (C) 2004 IBM Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.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, version 2 of the
* License.
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#define TPM_TIMEOUT msecs_to_jiffies(5)
/* TPM addresses */
#define TPM_ADDR 0x4E
#define TPM_DATA 0x4F
struct tpm_chip;
struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
u16 base; /* TPM base address */
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
struct miscdevice miscdev;
};
struct tpm_chip {
struct pci_dev *pci_dev; /* PCI device stuff */
int dev_num; /* /dev/tpm# */
int num_opens; /* only one allowed */
int time_expired;
/* Data passed to and from the tpm via the read/write calls */
u8 *data_buffer;
atomic_t data_pending;
struct semaphore buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
struct semaphore tpm_mutex; /* tpm is processing */
struct timer_list device_timer; /* tpm is processing */
struct semaphore timer_manipulation_mutex;
struct tpm_vendor_specific *vendor;
struct list_head list;
};
static inline int tpm_read_index(int index)
{
outb(index, TPM_ADDR);
return inb(TPM_DATA) & 0xFF;
}
static inline void tpm_write_index(int index, int value)
{
outb(index, TPM_ADDR);
outb(value & 0xFF, TPM_DATA);
}
extern void tpm_time_expired(unsigned long);
extern int tpm_lpc_bus_init(struct pci_dev *, u16);
extern int tpm_register_hardware(struct pci_dev *,
struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
loff_t *);
extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
extern void __devexit tpm_remove(struct pci_dev *);
extern int tpm_pm_suspend(struct pci_dev *, u32);
extern int tpm_pm_resume(struct pci_dev *);
/*
* Copyright (C) 2004 IBM Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.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, version 2 of the
* License.
*
*/
#include "tpm.h"
/* Atmel definitions */
#define TPM_ATML_BASE 0x400
/* write status bits */
#define ATML_STATUS_ABORT 0x01
#define ATML_STATUS_LASTBYTE 0x04
/* read status bits */
#define ATML_STATUS_BUSY 0x01
#define ATML_STATUS_DATA_AVAIL 0x02
#define ATML_STATUS_REWRITE 0x04
static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
{
u8 status, *hdr = buf;
u32 size;
int i;
__be32 *native_size;
/* start reading header */
if (count < 6)
return -EIO;
for (i = 0; i < 6; i++) {
status = inb(chip->vendor->base + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(&chip->pci_dev->dev,
"error reading header\n");
return -EIO;
}
*buf++ = inb(chip->vendor->base);
}
/* size of the data received */
native_size = (__force __be32 *) (hdr + 2);
size = be32_to_cpu(*native_size);
if (count < size) {
dev_err(&chip->pci_dev->dev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
status = inb(chip->vendor->base + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(&chip->pci_dev->dev,
"error reading data\n");
return -EIO;
}
}
return -EIO;
}
/* read all the data available */
for (; i < size; i++) {
status = inb(chip->vendor->base + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(&chip->pci_dev->dev,
"error reading data\n");
return -EIO;
}
*buf++ = inb(chip->vendor->base);
}
/* make sure data available is gone */
status = inb(chip->vendor->base + 1);
if (status & ATML_STATUS_DATA_AVAIL) {
dev_err(&chip->pci_dev->dev, "data available is stuck\n");
return -EIO;
}
return size;
}
static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count)
{
int i;
dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: ");
for (i = 0; i < count; i++) {
dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]);
outb(buf[i], chip->vendor->base);
}
return count;
}
static void tpm_atml_cancel(struct tpm_chip *chip)
{
outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
}
static struct file_operations atmel_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
.read = tpm_read,
.write = tpm_write,
.release = tpm_release,
};
static struct tpm_vendor_specific tpm_atmel = {
.recv = tpm_atml_recv,
.send = tpm_atml_send,
.cancel = tpm_atml_cancel,
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
.req_complete_val = ATML_STATUS_DATA_AVAIL,
.base = TPM_ATML_BASE,
.miscdev = { .fops = &atmel_ops, },
};
static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
u8 version[4];
int rc = 0;
if (pci_enable_device(pci_dev))
return -EIO;
if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
rc = -ENODEV;
goto out_err;
}
/* verify that it is an Atmel part */
if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
|| tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
rc = -ENODEV;
goto out_err;
}
/* query chip for its version number */
if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
version[1] = tpm_read_index(0x01);
version[2] = tpm_read_index(0x02);
version[3] = tpm_read_index(0x03);
} else {
dev_info(&pci_dev->dev, "version query failed\n");
rc = -ENODEV;
goto out_err;
}
if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0)
goto out_err;
dev_info(&pci_dev->dev,
"Atmel TPM version %d.%d.%d.%d\n", version[0], version[1],
version[2], version[3]);
return 0;
out_err:
pci_disable_device(pci_dev);
return rc;
}
static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{0,}
};
MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
static struct pci_driver atmel_pci_driver = {
.name = "tpm_atmel",
.id_table = tpm_pci_tbl,
.probe = tpm_atml_init,
.remove = __devexit_p(tpm_remove),
.suspend = tpm_pm_suspend,
.resume = tpm_pm_resume,
};
static int __init init_atmel(void)
{
return pci_register_driver(&atmel_pci_driver);
}
static void __exit cleanup_atmel(void)
{
pci_unregister_driver(&atmel_pci_driver);
}
module_init(init_atmel);
module_exit(cleanup_atmel);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -108,13 +108,6 @@ static void return_i2c_dev(struct i2c_dev *i2c_dev)
spin_unlock(&i2c_dev_array_lock);
}
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
return print_dev_t(buf, MKDEV(I2C_MAJOR, i2c_dev->minor));
}
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
{
struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
......@@ -451,11 +444,11 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
else
i2c_dev->class_dev.dev = adap->dev.parent;
i2c_dev->class_dev.class = &i2c_dev_class;
i2c_dev->class_dev.devt = MKDEV(I2C_MAJOR, i2c_dev->minor);
snprintf(i2c_dev->class_dev.class_id, BUS_ID_SIZE, "i2c-%d", i2c_dev->minor);
retval = class_device_register(&i2c_dev->class_dev);
if (retval)
goto error;
class_device_create_file(&i2c_dev->class_dev, &class_device_attr_dev);
class_device_create_file(&i2c_dev->class_dev, &class_device_attr_name);
return 0;
error:
......
......@@ -46,15 +46,7 @@ static ssize_t show_name(struct class_device *cd, char *buf)
return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
}
static ssize_t show_dev(struct class_device *cd, char *buf)
{
struct video_device *vfd = container_of(cd, struct video_device, class_dev);
dev_t dev = MKDEV(VIDEO_MAJOR, vfd->minor);
return print_dev_t(buf,dev);
}
static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
struct video_device *video_device_alloc(void)
{
......@@ -347,12 +339,11 @@ int video_register_device(struct video_device *vfd, int type, int nr)
if (vfd->dev)
vfd->class_dev.dev = vfd->dev;
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
class_device_register(&vfd->class_dev);
class_device_create_file(&vfd->class_dev,
&class_device_attr_name);
class_device_create_file(&vfd->class_dev,
&class_device_attr_dev);
#if 1 /* needed until all drivers are fixed */
if (!vfd->release)
......
#
# Makefile for the SuperH specific drivers.
#
obj-$(CONFIG_SUPERHYWAY) += superhyway/
#
# Makefile for the SuperHyway bus drivers.
#
obj-$(CONFIG_SUPERHYWAY) += superhyway.o
obj-$(CONFIG_SYSFS) += superhyway-sysfs.o
/*
* drivers/sh/superhyway/superhyway-sysfs.c
*
* SuperHyway Bus sysfs interface
*
* Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/superhyway.h>
#define superhyway_ro_attr(name, fmt, field) \
static ssize_t name##_show(struct device *dev, char *buf) \
{ \
struct superhyway_device *s = to_superhyway_device(dev); \
return sprintf(buf, fmt, s->field); \
}
/* VCR flags */
superhyway_ro_attr(perr_flags, "0x%02x\n", vcr.perr_flags);
superhyway_ro_attr(merr_flags, "0x%02x\n", vcr.merr_flags);
superhyway_ro_attr(mod_vers, "0x%04x\n", vcr.mod_vers);
superhyway_ro_attr(mod_id, "0x%04x\n", vcr.mod_id);
superhyway_ro_attr(bot_mb, "0x%02x\n", vcr.bot_mb);
superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb);
/* Misc */
superhyway_ro_attr(resource, "0x%08lx\n", resource.start);
struct device_attribute superhyway_dev_attrs[] = {
__ATTR_RO(perr_flags),
__ATTR_RO(merr_flags),
__ATTR_RO(mod_vers),
__ATTR_RO(mod_id),
__ATTR_RO(bot_mb),
__ATTR_RO(top_mb),
__ATTR_RO(resource),
__ATTR_NULL,
};
/*
* drivers/sh/superhyway/superhyway.c
*
* SuperHyway Bus Driver
*
* Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/superhyway.h>
static int superhyway_devices;
static struct device superhyway_bus_device = {
.bus_id = "superhyway",
};
static void superhyway_device_release(struct device *dev)
{
kfree(to_superhyway_device(dev));
}
/**
* superhyway_add_device - Add a SuperHyway module
* @mod_id: Module ID (taken from MODULE.VCR.MOD_ID).
* @base: Physical address where module is mapped.
* @vcr: VCR value.
*
* This is responsible for adding a new SuperHyway module. This sets up a new
* struct superhyway_device for the module being added. Each one of @mod_id,
* @base, and @vcr are registered with the new device for further use
* elsewhere.
*
* Devices are initially added in the order that they are scanned (from the
* top-down of the memory map), and are assigned an ID based on the order that
* they are added. Any manual addition of a module will thus get the ID after
* the devices already discovered regardless of where it resides in memory.
*
* Further work can and should be done in superhyway_scan_bus(), to be sure
* that any new modules are properly discovered and subsequently registered.
*/
int superhyway_add_device(unsigned int mod_id, unsigned long base,
unsigned long long vcr)
{
struct superhyway_device *dev;
dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
memset(dev, 0, sizeof(struct superhyway_device));
dev->id.id = mod_id;
sprintf(dev->name, "SuperHyway device %04x", dev->id.id);
dev->vcr = *((struct vcr_info *)(&vcr));
dev->resource.name = dev->name;
dev->resource.start = base;
dev->resource.end = dev->resource.start + 0x01000000;
dev->dev.parent = &superhyway_bus_device;
dev->dev.bus = &superhyway_bus_type;
dev->dev.release = superhyway_device_release;
sprintf(dev->dev.bus_id, "%02x", superhyway_devices);
superhyway_devices++;
return device_register(&dev->dev);
}
static int __init superhyway_init(void)
{
device_register(&superhyway_bus_device);
return superhyway_scan_bus();
}
postcore_initcall(superhyway_init);
static const struct superhyway_device_id *
superhyway_match_id(const struct superhyway_device_id *ids,
struct superhyway_device *dev)
{
while (ids->id) {
if (ids->id == dev->id.id)
return ids;
ids++;
}
return NULL;
}
static int superhyway_device_probe(struct device *dev)
{
struct superhyway_device *shyway_dev = to_superhyway_device(dev);
struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
if (shyway_drv && shyway_drv->probe) {
const struct superhyway_device_id *id;
id = superhyway_match_id(shyway_drv->id_table, shyway_dev);
if (id)
return shyway_drv->probe(shyway_dev, id);
}
return -ENODEV;
}
static int superhyway_device_remove(struct device *dev)
{
struct superhyway_device *shyway_dev = to_superhyway_device(dev);
struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
if (shyway_drv && shyway_drv->remove) {
shyway_drv->remove(shyway_dev);
return 0;
}
return -ENODEV;
}
/**
* superhyway_register_driver - Register a new SuperHyway driver
* @drv: SuperHyway driver to register.
*
* This registers the passed in @drv. Any devices matching the id table will
* automatically be populated and handed off to the driver's specified probe
* routine.
*/
int superhyway_register_driver(struct superhyway_driver *drv)
{
drv->drv.name = drv->name;
drv->drv.bus = &superhyway_bus_type;
drv->drv.probe = superhyway_device_probe;
drv->drv.remove = superhyway_device_remove;
return driver_register(&drv->drv);
}
/**
* superhyway_unregister_driver - Unregister a SuperHyway driver
* @drv: SuperHyway driver to unregister.
*
* This cleans up after superhyway_register_driver(), and should be invoked in
* the exit path of any module drivers.
*/
void superhyway_unregister_driver(struct superhyway_driver *drv)
{
driver_unregister(&drv->drv);
}
static int superhyway_bus_match(struct device *dev, struct device_driver *drv)
{
struct superhyway_device *shyway_dev = to_superhyway_device(dev);
struct superhyway_driver *shyway_drv = to_superhyway_driver(drv);
const struct superhyway_device_id *ids = shyway_drv->id_table;
if (!ids)
return -EINVAL;
if (superhyway_match_id(ids, shyway_dev))
return 1;
return -ENODEV;
}
struct bus_type superhyway_bus_type = {
.name = "superhyway",
.match = superhyway_bus_match,
#ifdef CONFIG_SYSFS
.dev_attrs = superhyway_dev_attrs,
#endif
};
static int __init superhyway_bus_init(void)
{
return bus_register(&superhyway_bus_type);
}
static void __exit superhyway_bus_exit(void)
{
device_unregister(&superhyway_bus_device);
bus_unregister(&superhyway_bus_type);
}
core_initcall(superhyway_bus_init);
module_exit(superhyway_bus_exit);
EXPORT_SYMBOL(superhyway_bus_type);
EXPORT_SYMBOL(superhyway_add_device);
EXPORT_SYMBOL(superhyway_register_driver);
EXPORT_SYMBOL(superhyway_unregister_driver);
MODULE_LICENSE("GPL");
......@@ -66,16 +66,7 @@ static struct file_operations usb_fops = {
.open = usb_open,
};
static void release_usb_class_dev(struct class_device *class_dev)
{
dbg("%s - %s", __FUNCTION__, class_dev->class_id);
kfree(class_dev);
}
static struct class usb_class = {
.name = "usb",
.release = &release_usb_class_dev,
};
static struct class_simple *usb_class;
int usb_major_init(void)
{
......@@ -87,9 +78,9 @@ int usb_major_init(void)
goto out;
}
error = class_register(&usb_class);
if (error) {
err("class_register failed for usb devices");
usb_class = class_simple_create(THIS_MODULE, "usb");
if (IS_ERR(usb_class)) {
err("class_simple_create failed for usb devices");
unregister_chrdev(USB_MAJOR, "usb");
goto out;
}
......@@ -102,18 +93,11 @@ int usb_major_init(void)
void usb_major_cleanup(void)
{
class_unregister(&usb_class);
class_simple_destroy(usb_class);
devfs_remove("usb");
unregister_chrdev(USB_MAJOR, "usb");
}
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
int minor = (int)(long)class_get_devdata(class_dev);
return print_dev_t(buf, MKDEV(USB_MAJOR, minor));
}
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
/**
* usb_register_dev - register a USB device, and ask for a minor number
* @intf: pointer to the usb_interface that is being registered
......@@ -141,7 +125,6 @@ int usb_register_dev(struct usb_interface *intf,
int minor_base = class_driver->minor_base;
int minor = 0;
char name[BUS_ID_SIZE];
struct class_device *class_dev;
char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS
......@@ -181,22 +164,18 @@ int usb_register_dev(struct usb_interface *intf,
devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name);
/* create a usb class device for this usb interface */
class_dev = kmalloc(sizeof(*class_dev), GFP_KERNEL);
if (class_dev) {
memset(class_dev, 0x00, sizeof(struct class_device));
class_dev->class = &usb_class;
class_dev->dev = &intf->dev;
temp = strrchr(name, '/');
if (temp && (temp[1] != 0x00))
++temp;
else
temp = name;
snprintf(class_dev->class_id, BUS_ID_SIZE, "%s", temp);
class_set_devdata(class_dev, (void *)(long)intf->minor);
class_device_register(class_dev);
class_device_create_file(class_dev, &class_device_attr_dev);
intf->class_dev = class_dev;
temp = strrchr(name, '/');
if (temp && (temp[1] != 0x00))
++temp;
else
temp = name;
intf->class_dev = class_simple_device_add(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp);
if (IS_ERR(intf->class_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
devfs_remove (name);
retval = PTR_ERR(intf->class_dev);
}
exit:
return retval;
......@@ -239,11 +218,8 @@ void usb_deregister_dev(struct usb_interface *intf,
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
devfs_remove (name);
if (intf->class_dev) {
class_device_unregister(intf->class_dev);
intf->class_dev = NULL;
}
class_simple_device_remove(MKDEV(USB_MAJOR, intf->minor));
intf->class_dev = NULL;
intf->minor = -1;
}
EXPORT_SYMBOL(usb_deregister_dev);
......
......@@ -29,7 +29,7 @@ static struct kobj_map *cdev_map;
/* degrade to linked list for small systems */
#define MAX_PROBE_HASH (CONFIG_BASE_SMALL ? 1 : 255)
static DEFINE_RWLOCK(chrdevs_lock);
static DECLARE_MUTEX(chrdevs_lock);
static struct char_device_struct {
struct char_device_struct *next;
......@@ -55,13 +55,13 @@ int get_chrdev_list(char *page)
len = sprintf(page, "Character devices:\n");
read_lock(&chrdevs_lock);
down(&chrdevs_lock);
for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
for (cd = chrdevs[i]; cd; cd = cd->next)
len += sprintf(page+len, "%3d %s\n",
cd->major, cd->name);
}
read_unlock(&chrdevs_lock);
up(&chrdevs_lock);
return len;
}
......@@ -91,7 +91,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
memset(cd, 0, sizeof(struct char_device_struct));
write_lock_irq(&chrdevs_lock);
down(&chrdevs_lock);
/* temporary */
if (major == 0) {
......@@ -126,10 +126,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
}
cd->next = *cp;
*cp = cd;
write_unlock_irq(&chrdevs_lock);
up(&chrdevs_lock);
return cd;
out:
write_unlock_irq(&chrdevs_lock);
up(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
......@@ -140,7 +140,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
struct char_device_struct *cd = NULL, **cp;
int i = major_to_index(major);
write_lock_irq(&chrdevs_lock);
up(&chrdevs_lock);
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major == major &&
(*cp)->baseminor == baseminor &&
......@@ -150,7 +150,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
cd = *cp;
*cp = cd->next;
}
write_unlock_irq(&chrdevs_lock);
up(&chrdevs_lock);
return cd;
}
......@@ -381,8 +381,6 @@ void cdev_del(struct cdev *p)
}
static decl_subsys(cdev, NULL, NULL);
static void cdev_default_release(struct kobject *kobj)
{
struct cdev *p = container_of(kobj, struct cdev, kobj);
......@@ -435,13 +433,7 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
void __init chrdev_init(void)
{
/*
* Keep cdev_subsys around because (and only because) the kobj_map code
* depends on the rwsem it contains. We don't make it public in sysfs,
* however.
*/
subsystem_init(&cdev_subsys);
cdev_map = kobj_map_init(base_probe, &cdev_subsys);
cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
}
......
......@@ -52,7 +52,7 @@ static ssize_t read_file_##type(struct file *file, char __user *user_buf, \
char buf[32]; \
type *val = file->private_data; \
\
snprintf(buf, sizeof(buf), format, *val); \
snprintf(buf, sizeof(buf), format "\n", *val); \
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\
} \
static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\
......@@ -186,7 +186,7 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf,
char buf[3];
u32 *val = file->private_data;
if (val)
if (*val)
buf[0] = 'Y';
else
buf[0] = 'N';
......
......@@ -15,7 +15,6 @@
#include <linux/ioport.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pm.h>
......@@ -102,7 +101,7 @@ struct device_driver {
char * name;
struct bus_type * bus;
struct semaphore unload_sem;
struct completion unloaded;
struct kobject kobj;
struct list_head devices;
......@@ -148,6 +147,7 @@ struct class {
struct subsystem subsys;
struct list_head children;
struct list_head interfaces;
struct semaphore sem; /* locks both the children and interfaces lists */
struct class_attribute * class_attrs;
struct class_device_attribute * class_dev_attrs;
......@@ -184,6 +184,7 @@ struct class_device {
struct kobject kobj;
struct class * class; /* required */
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */
......
......@@ -7,6 +7,6 @@ int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *,
kobj_probe_t *, int (*)(dev_t, void *), void *);
void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct subsystem *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
#endif
......@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/kref.h>
#include <linux/kobject_uevent.h>
......@@ -102,6 +103,7 @@ struct kset {
struct subsystem * subsys;
struct kobj_type * ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_hotplug_ops * hotplug_ops;
};
......
......@@ -26,7 +26,7 @@ struct kref {
void kref_init(struct kref *kref);
void kref_get(struct kref *kref);
void kref_put(struct kref *kref, void (*release) (struct kref *kref));
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
#endif /* __KERNEL__ */
#endif /* _KREF_H_ */
......@@ -519,6 +519,7 @@
#define PCI_DEVICE_ID_AMD_OPUS_7449 0x7449
# define PCI_DEVICE_ID_AMD_VIPER_7449 PCI_DEVICE_ID_AMD_OPUS_7449
#define PCI_DEVICE_ID_AMD_8111_LAN 0x7462
#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a
#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b
......
/*
* include/linux/superhyway.h
*
* SuperHyway Bus definitions
*
* Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#ifndef __LINUX_SUPERHYWAY_H
#define __LINUX_SUPERHYWAY_H
#include <linux/device.h>
/*
* SuperHyway IDs
*/
#define SUPERHYWAY_DEVICE_ID_SH5_DMAC 0x0183
struct vcr_info {
u8 perr_flags; /* P-port Error flags */
u8 merr_flags; /* Module Error flags */
u16 mod_vers; /* Module Version */
u16 mod_id; /* Module ID */
u8 bot_mb; /* Bottom Memory block */
u8 top_mb; /* Top Memory block */
};
struct superhyway_device_id {
unsigned int id;
unsigned long driver_data;
};
struct superhyway_device;
extern struct bus_type superhyway_bus_type;
struct superhyway_driver {
char *name;
const struct superhyway_device_id *id_table;
struct device_driver drv;
int (*probe)(struct superhyway_device *dev, const struct superhyway_device_id *id);
void (*remove)(struct superhyway_device *dev);
};
#define to_superhyway_driver(d) container_of((d), struct superhyway_driver, drv)
struct superhyway_device {
char name[32];
struct device dev;
struct superhyway_device_id id;
struct superhyway_driver *drv;
struct resource resource;
struct vcr_info vcr;
};
#define to_superhyway_device(d) container_of((d), struct superhyway_device, dev)
#define superhyway_get_drvdata(d) dev_get_drvdata(&(d)->dev)
#define superhyway_set_drvdata(d,p) dev_set_drvdata(&(d)->dev, (p))
extern int superhyway_scan_bus(void);
/* drivers/sh/superhyway/superhyway.c */
int superhyway_register_driver(struct superhyway_driver *);
void superhyway_unregister_driver(struct superhyway_driver *);
int superhyway_add_device(unsigned int, unsigned long, unsigned long long);
/* drivers/sh/superhyway/superhyway-sysfs.c */
extern struct device_attribute superhyway_dev_attrs[];
#endif /* __LINUX_SUPERHYWAY_H */
......@@ -140,9 +140,9 @@ void kobject_init(struct kobject * kobj)
static void unlink(struct kobject * kobj)
{
if (kobj->kset) {
down_write(&kobj->kset->subsys->rwsem);
spin_lock(&kobj->kset->list_lock);
list_del_init(&kobj->entry);
up_write(&kobj->kset->subsys->rwsem);
spin_unlock(&kobj->kset->list_lock);
}
kobject_put(kobj);
}
......@@ -168,13 +168,13 @@ int kobject_add(struct kobject * kobj)
kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
if (kobj->kset) {
down_write(&kobj->kset->subsys->rwsem);
spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
list_add_tail(&kobj->entry,&kobj->kset->list);
up_write(&kobj->kset->subsys->rwsem);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
......@@ -380,6 +380,7 @@ void kset_init(struct kset * k)
{
kobject_init(&k->kobj);
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
......@@ -444,7 +445,7 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
struct list_head * entry;
struct kobject * ret = NULL;
down_read(&kset->subsys->rwsem);
spin_lock(&kset->list_lock);
list_for_each(entry,&kset->list) {
struct kobject * k = to_kobj(entry);
if (kobject_name(k) && !strcmp(kobject_name(k),name)) {
......@@ -452,7 +453,7 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
break;
}
}
up_read(&kset->subsys->rwsem);
spin_unlock(&kset->list_lock);
return ret;
}
......@@ -524,7 +525,6 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
}
}
EXPORT_SYMBOL(kobject_get_path);
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
......@@ -532,7 +532,6 @@ EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(kobject_add);
EXPORT_SYMBOL(kobject_del);
EXPORT_SYMBOL(kobject_rename);
EXPORT_SYMBOL(kset_register);
EXPORT_SYMBOL(kset_unregister);
......
......@@ -42,14 +42,21 @@ void kref_get(struct kref *kref)
* in as this function.
*
* Decrement the refcount, and if 0, call release().
* Return 1 if the object was removed, otherwise return 0. Beware, if this
* function returns 0, you still can not count on the kref from remaining in
* memory. Only use the return value if you want to see if the kref is now
* gone, not present.
*/
void kref_put(struct kref *kref, void (*release) (struct kref *kref))
int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
WARN_ON(release == NULL);
WARN_ON(release == (void (*)(struct kref *))kfree);
if (atomic_dec_and_test(&kref->refcount))
if (atomic_dec_and_test(&kref->refcount)) {
release(kref);
return 1;
}
return 0;
}
EXPORT_SYMBOL(kref_init);
......
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