^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/drivers/char/misc.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Generic misc open routine by Johan Myreen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on code from Linus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * changes incorporated into 0.97pl4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * See busmouse.c for particulars.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Made things a lot mode modular - easy to compile in just one or two
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * of the misc drivers, as they are now completely independent. Linus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Fixed a failing symbol register to free the device registration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Handling of mouse minor numbers for kerneld:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * adapted by Bjorn Ekwall <bj0rn@blox.se>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * Changes for kmod (from kerneld):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Cyrus Durgin <cider@speakeasy.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au> 10-Jan-1998
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/kmod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Head entry for the doubly linked miscdevice list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static LIST_HEAD(misc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static DEFINE_MUTEX(misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * Assigned numbers, used for dynamic minors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define DYNAMIC_MINORS 128 /* like dynamic majors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) mutex_lock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return seq_list_start(&misc_list, *pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return seq_list_next(v, &misc_list, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static void misc_seq_stop(struct seq_file *seq, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) mutex_unlock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int misc_seq_show(struct seq_file *seq, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) const struct miscdevice *p = list_entry(v, struct miscdevice, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static const struct seq_operations misc_seq_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .start = misc_seq_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .next = misc_seq_next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .stop = misc_seq_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .show = misc_seq_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int misc_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int minor = iminor(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct miscdevice *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) const struct file_operations *new_fops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mutex_lock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) list_for_each_entry(c, &misc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (c->minor == minor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) new_fops = fops_get(c->fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (!new_fops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mutex_unlock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) request_module("char-major-%d-%d", MISC_MAJOR, minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) mutex_lock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) list_for_each_entry(c, &misc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (c->minor == minor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) new_fops = fops_get(c->fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!new_fops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * Place the miscdevice in the file's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * private_data so it can be used by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * file operations, including f_op->open below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) file->private_data = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) replace_fops(file, new_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (file->f_op->open)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) err = file->f_op->open(inode, file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) mutex_unlock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static struct class *misc_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static const struct file_operations misc_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .open = misc_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * misc_register - register a miscellaneous device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * @misc: device structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * Register a miscellaneous device with the kernel. If the minor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * and placed in the minor field of the structure. For other cases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * the minor number requested is used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * The structure passed is linked into the kernel and may not be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * destroyed until it has been unregistered. By default, an open()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * syscall to the device sets file->private_data to point to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * structure. Drivers don't need open in fops for this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * A zero is returned on success and a negative errno code for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int misc_register(struct miscdevice *misc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) dev_t dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) INIT_LIST_HEAD(&misc->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) mutex_lock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (is_dynamic) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (i >= DYNAMIC_MINORS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) misc->minor = DYNAMIC_MINORS - i - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) set_bit(i, misc_minors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct miscdevice *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) list_for_each_entry(c, &misc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (c->minor == misc->minor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) dev = MKDEV(MISC_MAJOR, misc->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) misc->this_device =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) device_create_with_groups(misc_class, misc->parent, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) misc, misc->groups, "%s", misc->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (IS_ERR(misc->this_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (is_dynamic) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int i = DYNAMIC_MINORS - misc->minor - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (i < DYNAMIC_MINORS && i >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) clear_bit(i, misc_minors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) misc->minor = MISC_DYNAMIC_MINOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) err = PTR_ERR(misc->this_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * Add it to the front, so that later devices can "override"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * earlier defaults
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) list_add(&misc->list, &misc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) mutex_unlock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) EXPORT_SYMBOL(misc_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * misc_deregister - unregister a miscellaneous device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * @misc: device to unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * Unregister a miscellaneous device that was previously
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * successfully registered with misc_register().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) void misc_deregister(struct miscdevice *misc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) int i = DYNAMIC_MINORS - misc->minor - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (WARN_ON(list_empty(&misc->list)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) mutex_lock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) list_del(&misc->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (i < DYNAMIC_MINORS && i >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) clear_bit(i, misc_minors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) mutex_unlock(&misc_mtx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) EXPORT_SYMBOL(misc_deregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static char *misc_devnode(struct device *dev, umode_t *mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) struct miscdevice *c = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (mode && c->mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) *mode = c->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (c->nodename)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return kstrdup(c->nodename, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static int __init misc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct proc_dir_entry *ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) misc_class = class_create(THIS_MODULE, "misc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) err = PTR_ERR(misc_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (IS_ERR(misc_class))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) goto fail_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (register_chrdev(MISC_MAJOR, "misc", &misc_fops))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto fail_printk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) misc_class->devnode = misc_devnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) fail_printk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) pr_err("unable to get major %d for misc devices\n", MISC_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) class_destroy(misc_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) fail_remove:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) remove_proc_entry("misc", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) subsys_initcall(misc_init);