0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <linux/module.h>
0038
0039 #include <linux/fs.h>
0040 #include <linux/errno.h>
0041 #include <linux/miscdevice.h>
0042 #include <linux/kernel.h>
0043 #include <linux/major.h>
0044 #include <linux/mutex.h>
0045 #include <linux/proc_fs.h>
0046 #include <linux/seq_file.h>
0047 #include <linux/stat.h>
0048 #include <linux/init.h>
0049 #include <linux/device.h>
0050 #include <linux/tty.h>
0051 #include <linux/kmod.h>
0052 #include <linux/gfp.h>
0053
0054
0055
0056
0057 static LIST_HEAD(misc_list);
0058 static DEFINE_MUTEX(misc_mtx);
0059
0060
0061
0062
0063 #define DYNAMIC_MINORS 128
0064 static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
0065
0066 #ifdef CONFIG_PROC_FS
0067 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
0068 {
0069 mutex_lock(&misc_mtx);
0070 return seq_list_start(&misc_list, *pos);
0071 }
0072
0073 static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0074 {
0075 return seq_list_next(v, &misc_list, pos);
0076 }
0077
0078 static void misc_seq_stop(struct seq_file *seq, void *v)
0079 {
0080 mutex_unlock(&misc_mtx);
0081 }
0082
0083 static int misc_seq_show(struct seq_file *seq, void *v)
0084 {
0085 const struct miscdevice *p = list_entry(v, struct miscdevice, list);
0086
0087 seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
0088 return 0;
0089 }
0090
0091
0092 static const struct seq_operations misc_seq_ops = {
0093 .start = misc_seq_start,
0094 .next = misc_seq_next,
0095 .stop = misc_seq_stop,
0096 .show = misc_seq_show,
0097 };
0098 #endif
0099
0100 static int misc_open(struct inode *inode, struct file *file)
0101 {
0102 int minor = iminor(inode);
0103 struct miscdevice *c = NULL, *iter;
0104 int err = -ENODEV;
0105 const struct file_operations *new_fops = NULL;
0106
0107 mutex_lock(&misc_mtx);
0108
0109 list_for_each_entry(iter, &misc_list, list) {
0110 if (iter->minor != minor)
0111 continue;
0112 c = iter;
0113 new_fops = fops_get(iter->fops);
0114 break;
0115 }
0116
0117 if (!new_fops) {
0118 mutex_unlock(&misc_mtx);
0119 request_module("char-major-%d-%d", MISC_MAJOR, minor);
0120 mutex_lock(&misc_mtx);
0121
0122 list_for_each_entry(iter, &misc_list, list) {
0123 if (iter->minor != minor)
0124 continue;
0125 c = iter;
0126 new_fops = fops_get(iter->fops);
0127 break;
0128 }
0129 if (!new_fops)
0130 goto fail;
0131 }
0132
0133
0134
0135
0136
0137
0138 file->private_data = c;
0139
0140 err = 0;
0141 replace_fops(file, new_fops);
0142 if (file->f_op->open)
0143 err = file->f_op->open(inode, file);
0144 fail:
0145 mutex_unlock(&misc_mtx);
0146 return err;
0147 }
0148
0149 static struct class *misc_class;
0150
0151 static const struct file_operations misc_fops = {
0152 .owner = THIS_MODULE,
0153 .open = misc_open,
0154 .llseek = noop_llseek,
0155 };
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 int misc_register(struct miscdevice *misc)
0176 {
0177 dev_t dev;
0178 int err = 0;
0179 bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
0180
0181 INIT_LIST_HEAD(&misc->list);
0182
0183 mutex_lock(&misc_mtx);
0184
0185 if (is_dynamic) {
0186 int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
0187
0188 if (i >= DYNAMIC_MINORS) {
0189 err = -EBUSY;
0190 goto out;
0191 }
0192 misc->minor = DYNAMIC_MINORS - i - 1;
0193 set_bit(i, misc_minors);
0194 } else {
0195 struct miscdevice *c;
0196
0197 list_for_each_entry(c, &misc_list, list) {
0198 if (c->minor == misc->minor) {
0199 err = -EBUSY;
0200 goto out;
0201 }
0202 }
0203 }
0204
0205 dev = MKDEV(MISC_MAJOR, misc->minor);
0206
0207 misc->this_device =
0208 device_create_with_groups(misc_class, misc->parent, dev,
0209 misc, misc->groups, "%s", misc->name);
0210 if (IS_ERR(misc->this_device)) {
0211 if (is_dynamic) {
0212 int i = DYNAMIC_MINORS - misc->minor - 1;
0213
0214 if (i < DYNAMIC_MINORS && i >= 0)
0215 clear_bit(i, misc_minors);
0216 misc->minor = MISC_DYNAMIC_MINOR;
0217 }
0218 err = PTR_ERR(misc->this_device);
0219 goto out;
0220 }
0221
0222
0223
0224
0225
0226 list_add(&misc->list, &misc_list);
0227 out:
0228 mutex_unlock(&misc_mtx);
0229 return err;
0230 }
0231 EXPORT_SYMBOL(misc_register);
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 void misc_deregister(struct miscdevice *misc)
0242 {
0243 int i = DYNAMIC_MINORS - misc->minor - 1;
0244
0245 if (WARN_ON(list_empty(&misc->list)))
0246 return;
0247
0248 mutex_lock(&misc_mtx);
0249 list_del(&misc->list);
0250 device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
0251 if (i < DYNAMIC_MINORS && i >= 0)
0252 clear_bit(i, misc_minors);
0253 mutex_unlock(&misc_mtx);
0254 }
0255 EXPORT_SYMBOL(misc_deregister);
0256
0257 static char *misc_devnode(struct device *dev, umode_t *mode)
0258 {
0259 struct miscdevice *c = dev_get_drvdata(dev);
0260
0261 if (mode && c->mode)
0262 *mode = c->mode;
0263 if (c->nodename)
0264 return kstrdup(c->nodename, GFP_KERNEL);
0265 return NULL;
0266 }
0267
0268 static int __init misc_init(void)
0269 {
0270 int err;
0271 struct proc_dir_entry *ret;
0272
0273 ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
0274 misc_class = class_create(THIS_MODULE, "misc");
0275 err = PTR_ERR(misc_class);
0276 if (IS_ERR(misc_class))
0277 goto fail_remove;
0278
0279 err = -EIO;
0280 if (register_chrdev(MISC_MAJOR, "misc", &misc_fops))
0281 goto fail_printk;
0282 misc_class->devnode = misc_devnode;
0283 return 0;
0284
0285 fail_printk:
0286 pr_err("unable to get major %d for misc devices\n", MISC_MAJOR);
0287 class_destroy(misc_class);
0288 fail_remove:
0289 if (ret)
0290 remove_proc_entry("misc", NULL);
0291 return err;
0292 }
0293 subsys_initcall(misc_init);