aboutsummaryrefslogtreecommitdiff
path: root/fs/char_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/char_dev.c')
-rw-r--r--fs/char_dev.c113
1 files changed, 23 insertions, 90 deletions
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 21195c48163..f3418f7a6e9 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -15,10 +15,12 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/seq_file.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
+#include <linux/mutex.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -26,9 +28,7 @@
static struct kobj_map *cdev_map;
-#define MAX_PROBE_HASH 255 /* random */
-
-static DECLARE_MUTEX(chrdevs_lock);
+static DEFINE_MUTEX(chrdevs_lock);
static struct char_device_struct {
struct char_device_struct *next;
@@ -38,93 +38,29 @@ static struct char_device_struct {
char name[64];
struct file_operations *fops;
struct cdev *cdev; /* will die */
-} *chrdevs[MAX_PROBE_HASH];
+} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
/* index in the above */
static inline int major_to_index(int major)
{
- return major % MAX_PROBE_HASH;
+ return major % CHRDEV_MAJOR_HASH_SIZE;
}
-struct chrdev_info {
- int index;
- struct char_device_struct *cd;
-};
-
-void *get_next_chrdev(void *dev)
-{
- struct chrdev_info *info;
-
- if (dev == NULL) {
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- goto out;
- info->index=0;
- info->cd = chrdevs[info->index];
- if (info->cd)
- goto out;
- } else {
- info = dev;
- }
-
- while (info->index < ARRAY_SIZE(chrdevs)) {
- if (info->cd)
- info->cd = info->cd->next;
- if (info->cd)
- goto out;
- /*
- * No devices on this chain, move to the next
- */
- info->index++;
- info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
- chrdevs[info->index] : NULL;
- if (info->cd)
- goto out;
- }
-
-out:
- return info;
-}
+#ifdef CONFIG_PROC_FS
-void *acquire_chrdev_list(void)
-{
- down(&chrdevs_lock);
- return get_next_chrdev(NULL);
-}
-
-void release_chrdev_list(void *dev)
-{
- up(&chrdevs_lock);
- kfree(dev);
-}
-
-
-int count_chrdev_list(void)
+void chrdev_show(struct seq_file *f, off_t offset)
{
struct char_device_struct *cd;
- int i, count;
-
- count = 0;
- for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
- for (cd = chrdevs[i]; cd; cd = cd->next)
- count++;
+ if (offset < CHRDEV_MAJOR_HASH_SIZE) {
+ mutex_lock(&chrdevs_lock);
+ for (cd = chrdevs[offset]; cd; cd = cd->next)
+ seq_printf(f, "%3d %s\n", cd->major, cd->name);
+ mutex_unlock(&chrdevs_lock);
}
-
- return count;
}
-int get_chrdev_info(void *dev, int *major, char **name)
-{
- struct chrdev_info *info = dev;
-
- if (info->cd == NULL)
- return 1;
-
- *major = info->cd->major;
- *name = info->cd->name;
- return 0;
-}
+#endif /* CONFIG_PROC_FS */
/*
* Register a single major with a specified minor range.
@@ -145,13 +81,11 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
int ret = 0;
int i;
- cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
+ cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
if (cd == NULL)
return ERR_PTR(-ENOMEM);
- memset(cd, 0, sizeof(struct char_device_struct));
-
- down(&chrdevs_lock);
+ mutex_lock(&chrdevs_lock);
/* temporary */
if (major == 0) {
@@ -186,10 +120,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
}
cd->next = *cp;
*cp = cd;
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
return cd;
out:
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
@@ -200,7 +134,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
struct char_device_struct *cd = NULL, **cp;
int i = major_to_index(major);
- down(&chrdevs_lock);
+ mutex_lock(&chrdevs_lock);
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major == major &&
(*cp)->baseminor == baseminor &&
@@ -210,7 +144,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
cd = *cp;
*cp = cd->next;
}
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
return cd;
}
@@ -251,7 +185,7 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
}
int register_chrdev(unsigned int major, const char *name,
- struct file_operations *fops)
+ const struct file_operations *fops)
{
struct char_device_struct *cd;
struct cdev *cdev;
@@ -407,7 +341,7 @@ static void cdev_purge(struct cdev *cdev)
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
-struct file_operations def_chr_fops = {
+const struct file_operations def_chr_fops = {
.open = chrdev_open,
};
@@ -465,9 +399,8 @@ static struct kobj_type ktype_cdev_dynamic = {
struct cdev *cdev_alloc(void)
{
- struct cdev *p = kmalloc(sizeof(struct cdev), GFP_KERNEL);
+ struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
- memset(p, 0, sizeof(struct cdev));
p->kobj.ktype = &ktype_cdev_dynamic;
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj);
@@ -475,7 +408,7 @@ struct cdev *cdev_alloc(void)
return p;
}
-void cdev_init(struct cdev *cdev, struct file_operations *fops)
+void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);