Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * linux/drivers/char/misc.c
0004  *
0005  * Generic misc open routine by Johan Myreen
0006  *
0007  * Based on code from Linus
0008  *
0009  * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
0010  *   changes incorporated into 0.97pl4
0011  *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
0012  *   See busmouse.c for particulars.
0013  *
0014  * Made things a lot mode modular - easy to compile in just one or two
0015  * of the misc drivers, as they are now completely independent. Linus.
0016  *
0017  * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
0018  *
0019  * Fixed a failing symbol register to free the device registration
0020  *      Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
0021  *
0022  * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
0023  *
0024  * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
0025  *
0026  * Handling of mouse minor numbers for kerneld:
0027  *  Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
0028  *  adapted by Bjorn Ekwall <bj0rn@blox.se>
0029  *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
0030  *
0031  * Changes for kmod (from kerneld):
0032  *  Cyrus Durgin <cider@speakeasy.org>
0033  *
0034  * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au>  10-Jan-1998
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  * Head entry for the doubly linked miscdevice list
0056  */
0057 static LIST_HEAD(misc_list);
0058 static DEFINE_MUTEX(misc_mtx);
0059 
0060 /*
0061  * Assigned numbers, used for dynamic minors
0062  */
0063 #define DYNAMIC_MINORS 128 /* like dynamic majors */
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      * Place the miscdevice in the file's
0135      * private_data so it can be used by the
0136      * file operations, including f_op->open below
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  *  misc_register   -   register a miscellaneous device
0159  *  @misc: device structure
0160  *
0161  *  Register a miscellaneous device with the kernel. If the minor
0162  *  number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
0163  *  and placed in the minor field of the structure. For other cases
0164  *  the minor number requested is used.
0165  *
0166  *  The structure passed is linked into the kernel and may not be
0167  *  destroyed until it has been unregistered. By default, an open()
0168  *  syscall to the device sets file->private_data to point to the
0169  *  structure. Drivers don't need open in fops for this.
0170  *
0171  *  A zero is returned on success and a negative errno code for
0172  *  failure.
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      * Add it to the front, so that later devices can "override"
0224      * earlier defaults
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  *  misc_deregister - unregister a miscellaneous device
0235  *  @misc: device to unregister
0236  *
0237  *  Unregister a miscellaneous device that was previously
0238  *  successfully registered with misc_register().
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);