cregit-Linux how code gets into the kernel

Release 4.14 drivers/char/misc.c

Directory: drivers/char
// SPDX-License-Identifier: GPL-2.0
/*
 * linux/drivers/char/misc.c
 *
 * Generic misc open routine by Johan Myreen
 *
 * Based on code from Linus
 *
 * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
 *   changes incorporated into 0.97pl4
 *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
 *   See busmouse.c for particulars.
 *
 * Made things a lot mode modular - easy to compile in just one or two
 * of the misc drivers, as they are now completely independent. Linus.
 *
 * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
 *
 * Fixed a failing symbol register to free the device registration
 *              Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
 *
 * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
 *
 * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
 *
 * Handling of mouse minor numbers for kerneld:
 *  Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
 *  adapted by Bjorn Ekwall <bj0rn@blox.se>
 *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
 *
 * Changes for kmod (from kerneld):
 *      Cyrus Durgin <cider@speakeasy.org>
 *
 * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au>  10-Jan-1998
 */

#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

/*
 * Head entry for the doubly linked miscdevice list
 */
static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);

/*
 * Assigned numbers, used for dynamic minors
 */

#define DYNAMIC_MINORS 64 
/* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);

#ifdef CONFIG_PROC_FS

static void *misc_seq_start(struct seq_file *seq, loff_t *pos) { mutex_lock(&misc_mtx); return seq_list_start(&misc_list, *pos); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger1753.12%233.33%
Linus Torvalds (pre-git)825.00%233.33%
Pavel Emelyanov515.62%116.67%
Matthias Kaehlcke26.25%116.67%
Total32100.00%6100.00%


static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return seq_list_next(v, &misc_list, pos); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2683.87%150.00%
Pavel Emelyanov516.13%150.00%
Total31100.00%2100.00%


static void misc_seq_stop(struct seq_file *seq, void *v) { mutex_unlock(&misc_mtx); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger1990.48%150.00%
Matthias Kaehlcke29.52%150.00%
Total21100.00%2100.00%


static int misc_seq_show(struct seq_file *seq, void *v) { const struct miscdevice *p = list_entry(v, struct miscdevice, list); seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : ""); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2952.73%125.00%
Linus Torvalds (pre-git)1832.73%250.00%
Pavel Emelyanov814.55%125.00%
Total55100.00%4100.00%

static const struct seq_operations misc_seq_ops = { .start = misc_seq_start, .next = misc_seq_next, .stop = misc_seq_stop, .show = misc_seq_show, };
static int misc_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &misc_seq_ops); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2288.00%133.33%
Linus Torvalds (pre-git)312.00%266.67%
Total25100.00%3100.00%

static const struct file_operations misc_proc_fops = { .owner = THIS_MODULE, .open = misc_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; #endif
static int misc_open(struct inode *inode, struct file *file) { int minor = iminor(inode); struct miscdevice *c; int err = -ENODEV; const struct file_operations *new_fops = NULL; mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if (!new_fops) { mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if (!new_fops) goto fail; } /* * Place the miscdevice in the file's * private_data so it can be used by the * file operations, including f_op->open below */ file->private_data = c; err = 0; replace_fops(file, new_fops); if (file->f_op->open) err = file->f_op->open(inode, file); fail: mutex_unlock(&misc_mtx); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13870.77%1157.89%
Stephen Hemminger3216.41%15.26%
Matthias Kaehlcke84.10%15.26%
Tom Van Braeckel73.59%15.26%
Al Viro52.56%210.53%
Mikael Pettersson31.54%15.26%
Linus Torvalds10.51%15.26%
Arjan van de Ven10.51%15.26%
Total195100.00%19100.00%

static struct class *misc_class; static const struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, .llseek = noop_llseek, }; /** * misc_register - register a miscellaneous device * @misc: device structure * * Register a miscellaneous device with the kernel. If the minor * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * and placed in the minor field of the structure. For other cases * the minor number requested is used. * * The structure passed is linked into the kernel and may not be * destroyed until it has been unregistered. By default, an open() * syscall to the device sets file->private_data to point to the * structure. Drivers don't need open in fops for this. * * A zero is returned on success and a negative errno code for * failure. */
int misc_register(struct miscdevice *misc) { dev_t dev; int err = 0; bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR); INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); if (is_dynamic) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i >= DYNAMIC_MINORS) { err = -EBUSY; goto out; } misc->minor = DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); } else { struct miscdevice *c; list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { err = -EBUSY; goto out; } } } dev = MKDEV(MISC_MAJOR, misc->minor); misc->this_device = device_create_with_groups(misc_class, misc->parent, dev, misc, misc->groups, "%s", misc->name); if (IS_ERR(misc->this_device)) { if (is_dynamic) { int i = DYNAMIC_MINORS - misc->minor - 1; if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); misc->minor = MISC_DYNAMIC_MINOR; } err = PTR_ERR(misc->this_device); goto out; } /* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); out: mutex_unlock(&misc_mtx); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5220.47%521.74%
Thadeu Lima de Souza Cascardo4517.72%28.70%
Stephen Hemminger3614.17%28.70%
Dae S. Kim3212.60%14.35%
Greg Kroah-Hartman2710.63%521.74%
Vladimir Zapolskiy249.45%14.35%
Elad Wexler124.72%14.35%
Neil Horman83.15%14.35%
Robert Love62.36%14.35%
Takashi Iwai51.97%14.35%
Matthias Kaehlcke41.57%14.35%
Andrew Morton20.79%14.35%
Kay Sievers10.39%14.35%
Total254100.00%23100.00%

/** * misc_deregister - unregister a miscellaneous device * @misc: device to unregister * * Unregister a miscellaneous device that was previously * successfully registered with misc_register(). */
void misc_deregister(struct miscdevice *misc) { int i = DYNAMIC_MINORS - misc->minor - 1; if (WARN_ON(list_empty(&misc->list))) return; mutex_lock(&misc_mtx); list_del(&misc->list); device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); mutex_unlock(&misc_mtx); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4147.67%323.08%
Greg Kroah-Hartman1618.60%430.77%
Thadeu Lima de Souza Cascardo1112.79%215.38%
Stephen Hemminger1011.63%17.69%
Matthias Kaehlcke44.65%17.69%
Akinobu Mita33.49%17.69%
Rafael J. Wysocki11.16%17.69%
Total86100.00%13100.00%

EXPORT_SYMBOL(misc_register); EXPORT_SYMBOL(misc_deregister);
static char *misc_devnode(struct device *dev, umode_t *mode) { struct miscdevice *c = dev_get_drvdata(dev); if (mode && c->mode) *mode = c->mode; if (c->nodename) return kstrdup(c->nodename, GFP_KERNEL); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers5998.33%266.67%
Al Viro11.67%133.33%
Total60100.00%3100.00%


static int __init misc_init(void) { int err; struct proc_dir_entry *ret; ret = proc_create("misc", 0, NULL, &misc_proc_fops); misc_class = class_create(THIS_MODULE, "misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; err = -EIO; if (register_chrdev(MISC_MAJOR, "misc", &misc_fops)) goto fail_printk; misc_class->devnode = misc_devnode; return 0; fail_printk: pr_err("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: if (ret) remove_proc_entry("misc", NULL); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Denis V. Lunev3933.62%15.00%
Linus Torvalds (pre-git)3328.45%945.00%
Greg Kroah-Hartman1815.52%315.00%
Sudip Mukherjee119.48%15.00%
Kay Sievers65.17%210.00%
Chris Wright43.45%15.00%
Stephen Hemminger32.59%15.00%
Andrew Morton10.86%15.00%
Varsha Rao10.86%15.00%
Total116100.00%20100.00%

subsys_initcall(misc_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)36934.78%2738.03%
Stephen Hemminger26124.60%34.23%
Greg Kroah-Hartman736.88%811.27%
Kay Sievers666.22%22.82%
Thadeu Lima de Souza Cascardo615.75%22.82%
Denis V. Lunev393.68%11.41%
Dae S. Kim323.02%11.41%
Matthias Kaehlcke252.36%11.41%
Vladimir Zapolskiy242.26%11.41%
Pavel Emelyanov181.70%11.41%
Elad Wexler121.13%11.41%
Sudip Mukherjee111.04%11.41%
Neil Horman80.75%11.41%
Tom Van Braeckel70.66%11.41%
Andrew Morton70.66%22.82%
Al Viro60.57%34.23%
Robert Love60.57%11.41%
Takashi Iwai50.47%11.41%
Arnd Bergmann50.47%11.41%
Art Haas40.38%11.41%
Chris Wright40.38%11.41%
Akinobu Mita30.28%11.41%
Tejun Heo30.28%11.41%
Mikael Pettersson30.28%11.41%
Arjan van de Ven30.28%22.82%
Rafael J. Wysocki20.19%11.41%
James Morris10.09%11.41%
Varsha Rao10.09%11.41%
Tal Shorer10.09%11.41%
Linus Torvalds10.09%11.41%
Total1061100.00%71100.00%
Directory: drivers/char
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.