diff options
Diffstat (limited to 'fs/char_dev.c')
-rw-r--r-- | fs/char_dev.c | 113 |
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); |