Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / fs / char_dev.c
index bbc17ee..f3418f7 100644 (file)
 #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>
 
 static struct kobj_map *cdev_map;
 
-#define MAX_PROBE_HASH 255     /* random */
-
-static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
+static DEFINE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
        struct char_device_struct *next;
        unsigned int major;
        unsigned int baseminor;
        int minorct;
-       const char *name;
+       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;
 }
 
-/* get char device names in somewhat random order */
-int get_chrdev_list(char *page)
+#ifdef CONFIG_PROC_FS
+
+void chrdev_show(struct seq_file *f, off_t offset)
 {
        struct char_device_struct *cd;
-       int i, len;
-
-       len = sprintf(page, "Character devices:\n");
 
-       read_lock(&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);
+       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);
        }
-       read_unlock(&chrdevs_lock);
-
-       return len;
 }
 
+#endif /* CONFIG_PROC_FS */
+
 /*
  * Register a single major with a specified minor range.
  *
@@ -84,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));
-
-       write_lock_irq(&chrdevs_lock);
+       mutex_lock(&chrdevs_lock);
 
        /* temporary */
        if (major == 0) {
@@ -110,7 +105,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        cd->major = major;
        cd->baseminor = baseminor;
        cd->minorct = minorct;
-       cd->name = name;
+       strncpy(cd->name,name, 64);
 
        i = major_to_index(major);
 
@@ -125,10 +120,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        }
        cd->next = *cp;
        *cp = cd;
-       write_unlock_irq(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        return cd;
 out:
-       write_unlock_irq(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        kfree(cd);
        return ERR_PTR(ret);
 }
@@ -139,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);
 
-       write_lock_irq(&chrdevs_lock);
+       mutex_lock(&chrdevs_lock);
        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
                if ((*cp)->major == major &&
                    (*cp)->baseminor == baseminor &&
@@ -149,11 +144,11 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
                cd = *cp;
                *cp = cd->next;
        }
-       write_unlock_irq(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        return cd;
 }
 
-int register_chrdev_region(dev_t from, unsigned count, char *name)
+int register_chrdev_region(dev_t from, unsigned count, const char *name)
 {
        struct char_device_struct *cd;
        dev_t to = from + count;
@@ -178,7 +173,8 @@ fail:
        return PTR_ERR(cd);
 }
 
-int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name)
+int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
+                       const char *name)
 {
        struct char_device_struct *cd;
        cd = __register_chrdev_region(0, baseminor, count, name);
@@ -189,7 +185,7 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *na
 }
 
 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;
@@ -206,8 +202,8 @@ int register_chrdev(unsigned int major, const char *name,
 
        cdev->owner = fops->owner;
        cdev->ops = fops;
-       strcpy(cdev->kobj.name, name);
-       for (s = strchr(cdev->kobj.name, '/'); s; s = strchr(s, '/'))
+       kobject_set_name(&cdev->kobj, "%s", name);
+       for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
                *s = '!';
                
        err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
@@ -247,7 +243,7 @@ int unregister_chrdev(unsigned int major, const char *name)
        return 0;
 }
 
-static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(cdev_lock);
 
 static struct kobject *cdev_get(struct cdev *p)
 {
@@ -265,8 +261,9 @@ static struct kobject *cdev_get(struct cdev *p)
 void cdev_put(struct cdev *p)
 {
        if (p) {
+               struct module *owner = p->owner;
                kobject_put(&p->kobj);
-               module_put(p->owner);
+               module_put(owner);
        }
 }
 
@@ -327,7 +324,7 @@ void cd_forget(struct inode *inode)
        spin_unlock(&cdev_lock);
 }
 
-void cdev_purge(struct cdev *cdev)
+static void cdev_purge(struct cdev *cdev)
 {
        spin_lock(&cdev_lock);
        while (!list_empty(&cdev->list)) {
@@ -344,7 +341,7 @@ 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,
 };
 
@@ -379,8 +376,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);
@@ -404,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);
@@ -414,8 +408,9 @@ 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);
        cdev->kobj.ktype = &ktype_cdev_default;
        kobject_init(&cdev->kobj);
@@ -432,13 +427,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);
 }