Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (31 commits) driver core: Display error codes when class suspend fails Driver core: Add section count to memory_block struct Driver core: Add mutex for adding/removing memory blocks Driver core: Move find_memory_block routine hpilo: Despecificate driver from iLO generation driver core: Convert link_mem_sections to use find_memory_block_hinted. driver core: Introduce find_memory_block_hinted which utilizes kset_find_obj_hinted. kobject: Introduce kset_find_obj_hinted. driver core: fix build for CONFIG_BLOCK not enabled driver-core: base: change to new flag variable sysfs: only access bin file vm_ops with the active lock sysfs: Fail bin file mmap if vma close is implemented. FW_LOADER: fix kconfig dependency warning on HOTPLUG uio: Statically allocate uio_class and use class .dev_attrs. uio: Support 2^MINOR_BITS minors uio: Cleanup irq handling. uio: Don't clear driver data uio: Fix lack of locking in init_uio_class SYSFS: Allow boot time switching between deprecated and modern sysfs layout driver core: remove CONFIG_SYSFS_DEPRECATED_V2 but keep it for block devices ...
This commit is contained in:
@@ -23,9 +23,10 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uio_driver.h>
|
||||
|
||||
#define UIO_MAX_DEVICES 255
|
||||
#define UIO_MAX_DEVICES (1U << MINORBITS)
|
||||
|
||||
struct uio_device {
|
||||
struct module *owner;
|
||||
@@ -41,15 +42,10 @@ struct uio_device {
|
||||
};
|
||||
|
||||
static int uio_major;
|
||||
static struct cdev *uio_cdev;
|
||||
static DEFINE_IDR(uio_idr);
|
||||
static const struct file_operations uio_fops;
|
||||
|
||||
/* UIO class infrastructure */
|
||||
static struct uio_class {
|
||||
struct kref kref;
|
||||
struct class *class;
|
||||
} *uio_class;
|
||||
|
||||
/* Protect idr accesses */
|
||||
static DEFINE_MUTEX(minor_lock);
|
||||
|
||||
@@ -232,45 +228,34 @@ static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct uio_device *idev = dev_get_drvdata(dev);
|
||||
if (idev)
|
||||
return sprintf(buf, "%s\n", idev->info->name);
|
||||
else
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%s\n", idev->info->name);
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static ssize_t show_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct uio_device *idev = dev_get_drvdata(dev);
|
||||
if (idev)
|
||||
return sprintf(buf, "%s\n", idev->info->version);
|
||||
else
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%s\n", idev->info->version);
|
||||
}
|
||||
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
|
||||
|
||||
static ssize_t show_event(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct uio_device *idev = dev_get_drvdata(dev);
|
||||
if (idev)
|
||||
return sprintf(buf, "%u\n",
|
||||
(unsigned int)atomic_read(&idev->event));
|
||||
else
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event));
|
||||
}
|
||||
static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
|
||||
|
||||
static struct attribute *uio_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_version.attr,
|
||||
&dev_attr_event.attr,
|
||||
NULL,
|
||||
static struct device_attribute uio_class_attributes[] = {
|
||||
__ATTR(name, S_IRUGO, show_name, NULL),
|
||||
__ATTR(version, S_IRUGO, show_version, NULL),
|
||||
__ATTR(event, S_IRUGO, show_event, NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct attribute_group uio_attr_grp = {
|
||||
.attrs = uio_attrs,
|
||||
/* UIO class infrastructure */
|
||||
static struct class uio_class = {
|
||||
.name = "uio",
|
||||
.dev_attrs = uio_class_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -287,10 +272,6 @@ static int uio_dev_add_attributes(struct uio_device *idev)
|
||||
struct uio_port *port;
|
||||
struct uio_portio *portio;
|
||||
|
||||
ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
|
||||
if (ret)
|
||||
goto err_group;
|
||||
|
||||
for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
|
||||
mem = &idev->info->mem[mi];
|
||||
if (mem->size == 0)
|
||||
@@ -358,8 +339,6 @@ err_map:
|
||||
kobject_put(&map->kobj);
|
||||
}
|
||||
kobject_put(idev->map_dir);
|
||||
sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
|
||||
err_group:
|
||||
dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -385,8 +364,6 @@ static void uio_dev_del_attributes(struct uio_device *idev)
|
||||
kobject_put(&port->portio->kobj);
|
||||
}
|
||||
kobject_put(idev->portio_dir);
|
||||
|
||||
sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
|
||||
}
|
||||
|
||||
static int uio_get_minor(struct uio_device *idev)
|
||||
@@ -525,7 +502,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait)
|
||||
struct uio_listener *listener = filep->private_data;
|
||||
struct uio_device *idev = listener->dev;
|
||||
|
||||
if (idev->info->irq == UIO_IRQ_NONE)
|
||||
if (!idev->info->irq)
|
||||
return -EIO;
|
||||
|
||||
poll_wait(filep, &idev->wait, wait);
|
||||
@@ -543,7 +520,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
|
||||
ssize_t retval;
|
||||
s32 event_count;
|
||||
|
||||
if (idev->info->irq == UIO_IRQ_NONE)
|
||||
if (!idev->info->irq)
|
||||
return -EIO;
|
||||
|
||||
if (count != sizeof(s32))
|
||||
@@ -591,7 +568,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
|
||||
ssize_t retval;
|
||||
s32 irq_on;
|
||||
|
||||
if (idev->info->irq == UIO_IRQ_NONE)
|
||||
if (!idev->info->irq)
|
||||
return -EIO;
|
||||
|
||||
if (count != sizeof(s32))
|
||||
@@ -745,68 +722,72 @@ static const struct file_operations uio_fops = {
|
||||
|
||||
static int uio_major_init(void)
|
||||
{
|
||||
uio_major = register_chrdev(0, "uio", &uio_fops);
|
||||
if (uio_major < 0)
|
||||
return uio_major;
|
||||
return 0;
|
||||
static const char name[] = "uio";
|
||||
struct cdev *cdev = NULL;
|
||||
dev_t uio_dev = 0;
|
||||
int result;
|
||||
|
||||
result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
result = -ENOMEM;
|
||||
cdev = cdev_alloc();
|
||||
if (!cdev)
|
||||
goto out_unregister;
|
||||
|
||||
cdev->owner = THIS_MODULE;
|
||||
cdev->ops = &uio_fops;
|
||||
kobject_set_name(&cdev->kobj, "%s", name);
|
||||
|
||||
result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES);
|
||||
if (result)
|
||||
goto out_put;
|
||||
|
||||
uio_major = MAJOR(uio_dev);
|
||||
uio_cdev = cdev;
|
||||
result = 0;
|
||||
out:
|
||||
return result;
|
||||
out_put:
|
||||
kobject_put(&cdev->kobj);
|
||||
out_unregister:
|
||||
unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void uio_major_cleanup(void)
|
||||
{
|
||||
unregister_chrdev(uio_major, "uio");
|
||||
unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES);
|
||||
cdev_del(uio_cdev);
|
||||
}
|
||||
|
||||
static int init_uio_class(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (uio_class != NULL) {
|
||||
kref_get(&uio_class->kref);
|
||||
goto exit;
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* This is the first time in here, set everything up properly */
|
||||
ret = uio_major_init();
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
|
||||
if (!uio_class) {
|
||||
ret = -ENOMEM;
|
||||
goto err_kzalloc;
|
||||
}
|
||||
|
||||
kref_init(&uio_class->kref);
|
||||
uio_class->class = class_create(THIS_MODULE, "uio");
|
||||
if (IS_ERR(uio_class->class)) {
|
||||
ret = IS_ERR(uio_class->class);
|
||||
printk(KERN_ERR "class_create failed for uio\n");
|
||||
goto err_class_create;
|
||||
ret = class_register(&uio_class);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "class_register failed for uio\n");
|
||||
goto err_class_register;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_class_create:
|
||||
kfree(uio_class);
|
||||
uio_class = NULL;
|
||||
err_kzalloc:
|
||||
err_class_register:
|
||||
uio_major_cleanup();
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_uio_class(struct kref *kref)
|
||||
static void release_uio_class(void)
|
||||
{
|
||||
/* Ok, we cheat as we know we only have one uio_class */
|
||||
class_destroy(uio_class->class);
|
||||
kfree(uio_class);
|
||||
class_unregister(&uio_class);
|
||||
uio_major_cleanup();
|
||||
uio_class = NULL;
|
||||
}
|
||||
|
||||
static void uio_class_destroy(void)
|
||||
{
|
||||
if (uio_class)
|
||||
kref_put(&uio_class->kref, release_uio_class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -829,10 +810,6 @@ int __uio_register_device(struct module *owner,
|
||||
|
||||
info->uio_dev = NULL;
|
||||
|
||||
ret = init_uio_class();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
idev = kzalloc(sizeof(*idev), GFP_KERNEL);
|
||||
if (!idev) {
|
||||
ret = -ENOMEM;
|
||||
@@ -848,7 +825,7 @@ int __uio_register_device(struct module *owner,
|
||||
if (ret)
|
||||
goto err_get_minor;
|
||||
|
||||
idev->dev = device_create(uio_class->class, parent,
|
||||
idev->dev = device_create(&uio_class, parent,
|
||||
MKDEV(uio_major, idev->minor), idev,
|
||||
"uio%d", idev->minor);
|
||||
if (IS_ERR(idev->dev)) {
|
||||
@@ -863,9 +840,9 @@ int __uio_register_device(struct module *owner,
|
||||
|
||||
info->uio_dev = idev;
|
||||
|
||||
if (idev->info->irq >= 0) {
|
||||
ret = request_irq(idev->info->irq, uio_interrupt,
|
||||
idev->info->irq_flags, idev->info->name, idev);
|
||||
if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) {
|
||||
ret = request_irq(info->irq, uio_interrupt,
|
||||
info->irq_flags, info->name, idev);
|
||||
if (ret)
|
||||
goto err_request_irq;
|
||||
}
|
||||
@@ -875,13 +852,12 @@ int __uio_register_device(struct module *owner,
|
||||
err_request_irq:
|
||||
uio_dev_del_attributes(idev);
|
||||
err_uio_dev_add_attributes:
|
||||
device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
|
||||
device_destroy(&uio_class, MKDEV(uio_major, idev->minor));
|
||||
err_device_create:
|
||||
uio_free_minor(idev);
|
||||
err_get_minor:
|
||||
kfree(idev);
|
||||
err_kzalloc:
|
||||
uio_class_destroy();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__uio_register_device);
|
||||
@@ -902,15 +878,13 @@ void uio_unregister_device(struct uio_info *info)
|
||||
|
||||
uio_free_minor(idev);
|
||||
|
||||
if (info->irq >= 0)
|
||||
if (info->irq && (info->irq != UIO_IRQ_CUSTOM))
|
||||
free_irq(info->irq, idev);
|
||||
|
||||
uio_dev_del_attributes(idev);
|
||||
|
||||
dev_set_drvdata(idev->dev, NULL);
|
||||
device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
|
||||
device_destroy(&uio_class, MKDEV(uio_major, idev->minor));
|
||||
kfree(idev);
|
||||
uio_class_destroy();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -918,11 +892,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device);
|
||||
|
||||
static int __init uio_init(void)
|
||||
{
|
||||
return 0;
|
||||
return init_uio_class();
|
||||
}
|
||||
|
||||
static void __exit uio_exit(void)
|
||||
{
|
||||
release_uio_class();
|
||||
}
|
||||
|
||||
module_init(uio_init)
|
||||
|
Reference in New Issue
Block a user