aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/misc.c')
-rw-r--r--drivers/char/misc.c88
1 files changed, 45 insertions, 43 deletions
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 999aa779c08..ffa97d261cf 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -40,7 +40,6 @@
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
-#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -49,7 +48,7 @@
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
-#include <linux/smp_lock.h>
+#include <linux/gfp.h>
/*
* Head entry for the doubly linked miscdevice list
@@ -61,9 +60,7 @@ static DEFINE_MUTEX(misc_mtx);
* Assigned numbers, used for dynamic minors
*/
#define DYNAMIC_MINORS 64 /* like dynamic majors */
-static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-
-extern int pmu_device_init(void);
+static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -91,7 +88,7 @@ static int misc_seq_show(struct seq_file *seq, void *v)
}
-static struct seq_operations misc_seq_ops = {
+static const struct seq_operations misc_seq_ops = {
.start = misc_seq_start,
.next = misc_seq_next,
.stop = misc_seq_stop,
@@ -117,9 +114,8 @@ static int misc_open(struct inode * inode, struct file * file)
int minor = iminor(inode);
struct miscdevice *c;
int err = -ENODEV;
- const struct file_operations *old_fops, *new_fops = NULL;
-
- lock_kernel();
+ const struct file_operations *new_fops = NULL;
+
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
@@ -145,19 +141,13 @@ static int misc_open(struct inode * inode, struct file * file)
}
err = 0;
- old_fops = file->f_op;
- file->f_op = new_fops;
+ replace_fops(file, new_fops);
if (file->f_op->open) {
- err=file->f_op->open(inode,file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
+ file->private_data = c;
+ err = file->f_op->open(inode,file);
}
- fops_put(old_fops);
fail:
mutex_unlock(&misc_mtx);
- unlock_kernel();
return err;
}
@@ -166,9 +156,9 @@ static struct class *misc_class;
static const struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
+ .llseek = noop_llseek,
};
-
/**
* misc_register - register a miscellaneous device
* @misc: device structure
@@ -187,39 +177,40 @@ static const struct file_operations misc_fops = {
int misc_register(struct miscdevice * misc)
{
- struct miscdevice *c;
dev_t dev;
int err = 0;
INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx);
- list_for_each_entry(c, &misc_list, list) {
- if (c->minor == misc->minor) {
- mutex_unlock(&misc_mtx);
- return -EBUSY;
- }
- }
if (misc->minor == MISC_DYNAMIC_MINOR) {
- int i = DYNAMIC_MINORS;
- while (--i >= 0)
- if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
- break;
- if (i<0) {
- mutex_unlock(&misc_mtx);
- return -EBUSY;
+ int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
+ if (i >= DYNAMIC_MINORS) {
+ err = -EBUSY;
+ goto out;
+ }
+ misc->minor = DYNAMIC_MINORS - i - 1;
+ set_bit(i, misc_minors);
+ } else {
+ struct miscdevice *c;
+
+ list_for_each_entry(c, &misc_list, list) {
+ if (c->minor == misc->minor) {
+ err = -EBUSY;
+ goto out;
+ }
}
- misc->minor = i;
}
- if (misc->minor < DYNAMIC_MINORS)
- misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
dev = MKDEV(MISC_MAJOR, misc->minor);
- misc->this_device = device_create_drvdata(misc_class, misc->parent,
- dev, NULL, "%s", misc->name);
+ misc->this_device = device_create(misc_class, misc->parent, dev,
+ misc, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
+ int i = DYNAMIC_MINORS - misc->minor - 1;
+ if (i < DYNAMIC_MINORS && i >= 0)
+ clear_bit(i, misc_minors);
err = PTR_ERR(misc->this_device);
goto out;
}
@@ -246,17 +237,16 @@ int misc_register(struct miscdevice * misc)
int misc_deregister(struct miscdevice *misc)
{
- int i = misc->minor;
+ int i = DYNAMIC_MINORS - misc->minor - 1;
- if (list_empty(&misc->list))
+ if (WARN_ON(list_empty(&misc->list)))
return -EINVAL;
mutex_lock(&misc_mtx);
list_del(&misc->list);
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
- if (i < DYNAMIC_MINORS && i>0) {
- misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
- }
+ if (i < DYNAMIC_MINORS && i >= 0)
+ clear_bit(i, misc_minors);
mutex_unlock(&misc_mtx);
return 0;
}
@@ -264,6 +254,17 @@ int misc_deregister(struct miscdevice *misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
+static char *misc_devnode(struct device *dev, umode_t *mode)
+{
+ struct miscdevice *c = dev_get_drvdata(dev);
+
+ if (mode && c->mode)
+ *mode = c->mode;
+ if (c->nodename)
+ return kstrdup(c->nodename, GFP_KERNEL);
+ return NULL;
+}
+
static int __init misc_init(void)
{
int err;
@@ -279,6 +280,7 @@ static int __init misc_init(void)
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
goto fail_printk;
+ misc_class->devnode = misc_devnode;
return 0;
fail_printk: