This source file includes following definitions.
- misc_seq_start
- misc_seq_next
- misc_seq_stop
- misc_seq_show
- misc_open
- misc_register
- misc_deregister
- misc_devnode
- misc_init
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 #include <linux/module.h>
  38 
  39 #include <linux/fs.h>
  40 #include <linux/errno.h>
  41 #include <linux/miscdevice.h>
  42 #include <linux/kernel.h>
  43 #include <linux/major.h>
  44 #include <linux/mutex.h>
  45 #include <linux/proc_fs.h>
  46 #include <linux/seq_file.h>
  47 #include <linux/stat.h>
  48 #include <linux/init.h>
  49 #include <linux/device.h>
  50 #include <linux/tty.h>
  51 #include <linux/kmod.h>
  52 #include <linux/gfp.h>
  53 
  54 
  55 
  56 
  57 static LIST_HEAD(misc_list);
  58 static DEFINE_MUTEX(misc_mtx);
  59 
  60 
  61 
  62 
  63 #define DYNAMIC_MINORS 64 
  64 static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
  65 
  66 #ifdef CONFIG_PROC_FS
  67 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
  68 {
  69         mutex_lock(&misc_mtx);
  70         return seq_list_start(&misc_list, *pos);
  71 }
  72 
  73 static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  74 {
  75         return seq_list_next(v, &misc_list, pos);
  76 }
  77 
  78 static void misc_seq_stop(struct seq_file *seq, void *v)
  79 {
  80         mutex_unlock(&misc_mtx);
  81 }
  82 
  83 static int misc_seq_show(struct seq_file *seq, void *v)
  84 {
  85         const struct miscdevice *p = list_entry(v, struct miscdevice, list);
  86 
  87         seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
  88         return 0;
  89 }
  90 
  91 
  92 static const struct seq_operations misc_seq_ops = {
  93         .start = misc_seq_start,
  94         .next  = misc_seq_next,
  95         .stop  = misc_seq_stop,
  96         .show  = misc_seq_show,
  97 };
  98 #endif
  99 
 100 static int misc_open(struct inode *inode, struct file *file)
 101 {
 102         int minor = iminor(inode);
 103         struct miscdevice *c;
 104         int err = -ENODEV;
 105         const struct file_operations *new_fops = NULL;
 106 
 107         mutex_lock(&misc_mtx);
 108 
 109         list_for_each_entry(c, &misc_list, list) {
 110                 if (c->minor == minor) {
 111                         new_fops = fops_get(c->fops);
 112                         break;
 113                 }
 114         }
 115 
 116         if (!new_fops) {
 117                 mutex_unlock(&misc_mtx);
 118                 request_module("char-major-%d-%d", MISC_MAJOR, minor);
 119                 mutex_lock(&misc_mtx);
 120 
 121                 list_for_each_entry(c, &misc_list, list) {
 122                         if (c->minor == minor) {
 123                                 new_fops = fops_get(c->fops);
 124                                 break;
 125                         }
 126                 }
 127                 if (!new_fops)
 128                         goto fail;
 129         }
 130 
 131         
 132 
 133 
 134 
 135 
 136         file->private_data = c;
 137 
 138         err = 0;
 139         replace_fops(file, new_fops);
 140         if (file->f_op->open)
 141                 err = file->f_op->open(inode, file);
 142 fail:
 143         mutex_unlock(&misc_mtx);
 144         return err;
 145 }
 146 
 147 static struct class *misc_class;
 148 
 149 static const struct file_operations misc_fops = {
 150         .owner          = THIS_MODULE,
 151         .open           = misc_open,
 152         .llseek         = noop_llseek,
 153 };
 154 
 155 
 156 
 157 
 158 
 159 
 160 
 161 
 162 
 163 
 164 
 165 
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173 int misc_register(struct miscdevice *misc)
 174 {
 175         dev_t dev;
 176         int err = 0;
 177         bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
 178 
 179         INIT_LIST_HEAD(&misc->list);
 180 
 181         mutex_lock(&misc_mtx);
 182 
 183         if (is_dynamic) {
 184                 int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
 185 
 186                 if (i >= DYNAMIC_MINORS) {
 187                         err = -EBUSY;
 188                         goto out;
 189                 }
 190                 misc->minor = DYNAMIC_MINORS - i - 1;
 191                 set_bit(i, misc_minors);
 192         } else {
 193                 struct miscdevice *c;
 194 
 195                 list_for_each_entry(c, &misc_list, list) {
 196                         if (c->minor == misc->minor) {
 197                                 err = -EBUSY;
 198                                 goto out;
 199                         }
 200                 }
 201         }
 202 
 203         dev = MKDEV(MISC_MAJOR, misc->minor);
 204 
 205         misc->this_device =
 206                 device_create_with_groups(misc_class, misc->parent, dev,
 207                                           misc, misc->groups, "%s", misc->name);
 208         if (IS_ERR(misc->this_device)) {
 209                 if (is_dynamic) {
 210                         int i = DYNAMIC_MINORS - misc->minor - 1;
 211 
 212                         if (i < DYNAMIC_MINORS && i >= 0)
 213                                 clear_bit(i, misc_minors);
 214                         misc->minor = MISC_DYNAMIC_MINOR;
 215                 }
 216                 err = PTR_ERR(misc->this_device);
 217                 goto out;
 218         }
 219 
 220         
 221 
 222 
 223 
 224         list_add(&misc->list, &misc_list);
 225  out:
 226         mutex_unlock(&misc_mtx);
 227         return err;
 228 }
 229 EXPORT_SYMBOL(misc_register);
 230 
 231 
 232 
 233 
 234 
 235 
 236 
 237 
 238 
 239 void misc_deregister(struct miscdevice *misc)
 240 {
 241         int i = DYNAMIC_MINORS - misc->minor - 1;
 242 
 243         if (WARN_ON(list_empty(&misc->list)))
 244                 return;
 245 
 246         mutex_lock(&misc_mtx);
 247         list_del(&misc->list);
 248         device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
 249         if (i < DYNAMIC_MINORS && i >= 0)
 250                 clear_bit(i, misc_minors);
 251         mutex_unlock(&misc_mtx);
 252 }
 253 EXPORT_SYMBOL(misc_deregister);
 254 
 255 static char *misc_devnode(struct device *dev, umode_t *mode)
 256 {
 257         struct miscdevice *c = dev_get_drvdata(dev);
 258 
 259         if (mode && c->mode)
 260                 *mode = c->mode;
 261         if (c->nodename)
 262                 return kstrdup(c->nodename, GFP_KERNEL);
 263         return NULL;
 264 }
 265 
 266 static int __init misc_init(void)
 267 {
 268         int err;
 269         struct proc_dir_entry *ret;
 270 
 271         ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
 272         misc_class = class_create(THIS_MODULE, "misc");
 273         err = PTR_ERR(misc_class);
 274         if (IS_ERR(misc_class))
 275                 goto fail_remove;
 276 
 277         err = -EIO;
 278         if (register_chrdev(MISC_MAJOR, "misc", &misc_fops))
 279                 goto fail_printk;
 280         misc_class->devnode = misc_devnode;
 281         return 0;
 282 
 283 fail_printk:
 284         pr_err("unable to get major %d for misc devices\n", MISC_MAJOR);
 285         class_destroy(misc_class);
 286 fail_remove:
 287         if (ret)
 288                 remove_proc_entry("misc", NULL);
 289         return err;
 290 }
 291 subsys_initcall(misc_init);