Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394
[pandora-kernel.git] / fs / char_dev.c
index 3b1b1ee..4e1b849 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
 #include <linux/cdev.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -28,14 +29,14 @@ 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;
        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];
@@ -46,34 +47,84 @@ static inline int major_to_index(int major)
        return major % MAX_PROBE_HASH;
 }
 
-/* get char device names in somewhat random order */
-int get_chrdev_list(char *page)
+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;
+}
+
+void *acquire_chrdev_list(void)
+{
+       mutex_lock(&chrdevs_lock);
+       return get_next_chrdev(NULL);
+}
+
+void release_chrdev_list(void *dev)
+{
+       mutex_unlock(&chrdevs_lock);
+       kfree(dev);
+}
+
+
+int count_chrdev_list(void)
 {
        struct char_device_struct *cd;
-       int i, len;
+       int i, count;
 
-       len = sprintf(page, "Character devices:\n");
+       count = 0;
 
-       down(&chrdevs_lock);
        for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-               for (cd = chrdevs[i]; cd; cd = cd->next) {
-                       /*
-                        * if the current name, plus the 5 extra characters
-                        * in the device line for this entry
-                        * would run us off the page, we're done
-                        */
-                       if ((len+strlen(cd->name) + 5) >= PAGE_SIZE)
-                               goto page_full;
-
-
-                       len += sprintf(page+len, "%3d %s\n",
-                                      cd->major, cd->name);
-               }
+               for (cd = chrdevs[i]; cd; cd = cd->next)
+                       count++;
        }
-page_full:
-       up(&chrdevs_lock);
 
-       return len;
+       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;
 }
 
 /*
@@ -95,13 +146,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) {
@@ -121,7 +170,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);
 
@@ -136,10 +185,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);
 }
@@ -150,7 +199,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 &&
@@ -160,7 +209,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
                cd = *cp;
                *cp = cd->next;
        }
-       up(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        return cd;
 }
 
@@ -201,7 +250,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;
@@ -357,7 +406,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,
 };
 
@@ -415,9 +464,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);
@@ -425,7 +473,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);