linux中的杂项设备所使用的misc_register()和 misc_deregister() 原理分析

 

相关的宏,定义在 kernel/include/linux/miscdevice.h

#ifndef _LINUX_MISCDEVICE_H
#define _LINUX_MISCDEVICE_H
#include <linux/module.h>
#include <linux/major.h>

/*
 *      These allocations are managed by [email protected]. If you use an
 *      entry that is not in assigned your entry may well be moved and
 *      reassigned, or set dynamic if a fixed value is not justified.
 */

#define PSMOUSE_MINOR           1
#define MS_BUSMOUSE_MINOR       2
#define ATIXL_BUSMOUSE_MINOR    3
/*#define AMIGAMOUSE_MINOR      4       FIXME OBSOLETE */
#define ATARIMOUSE_MINOR        5
#define SUN_MOUSE_MINOR         6
#define APOLLO_MOUSE_MINOR      7
#define PC110PAD_MINOR          9
/*#define ADB_MOUSE_MINOR       10      FIXME OBSOLETE */
#define WATCHDOG_MINOR          130     /* Watchdog timer     */
#define TEMP_MINOR              131     /* Temperature Sensor */
#define RTC_MINOR               135
#define EFI_RTC_MINOR           136     /* EFI Time services */
#define SUN_OPENPROM_MINOR      139
#define DMAPI_MINOR             140     /* DMAPI */
#define NVRAM_MINOR             144
#define SGI_MMTIMER             153
#define STORE_QUEUE_MINOR       155
#define I2O_MINOR               166
#define MICROCODE_MINOR         184
#define TUN_MINOR               200
#define MWAVE_MINOR             219     /* ACP/Mwave Modem */
#define MPT_MINOR               220
#define MPT2SAS_MINOR           221
#define HPET_MINOR              228
#define FUSE_MINOR              229
#define KVM_MINOR               232
#define BTRFS_MINOR             234
#define AUTOFS_MINOR            235
#define MISC_DYNAMIC_MINOR      255

struct device;

struct miscdevice  {
        int minor;
        const char *name;
        const struct file_operations *fops;
        struct list_head list;
        struct device *parent;
        struct device *this_device;
        const char *nodename;
        mode_t mode;
};

extern int misc_register(struct miscdevice * misc);
extern int misc_deregister(struct miscdevice *misc);

#define MODULE_ALIAS_MISCDEV(minor)                             \
        MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)      \
        "-" __stringify(minor))
#endif


 

 

 

杂项设备的核心函数的定义位于:kernel/drivers/char/misc.c

/**
 *  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.
 *
 *  A zero is returned on success and a negative errno code for
 *  failure.
 */

int misc_register(struct miscdevice * misc)
{
    struct miscdevice *c;
    dev_t dev;
    int err = 0;

    INIT_LIST_HEAD(&misc->list);

    mutex_lock(&misc_mtx);
    list_for_each_entry(c, &misc_list, list) {
        if (c->minor == misc->minor) {
            mutex_unlock(&misc_mtx);
            return -EBUSY;
        }
    }

    if (misc->minor == MISC_DYNAMIC_MINOR) {     //#define MISC_DYNAMIC_MINOR 255
        int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);    //#define DYNAMIC_MINORS 64 /* like dynamic majors */
        if (i >= DYNAMIC_MINORS) {
            mutex_unlock(&misc_mtx);
            return -EBUSY;
        }
        misc->minor = DYNAMIC_MINORS - i - 1;
        set_bit(i, misc_minors);
    }

    dev = MKDEV(MISC_MAJOR, misc->minor);     //#define MISC_MAJOR  10    // 在 kernel/include/linux/major.h   中定义。


    misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name);
    if (IS_ERR(misc->this_device)) {
        int i = DYNAMIC_MINORS - misc->minor - 1;
        if (i < DYNAMIC_MINORS && i >= 0)
            clear_bit(i, misc_minors);
        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;
}

/**
 *  misc_deregister - unregister a miscellaneous device
 *  @misc: device to unregister
 *
 *  Unregister a miscellaneous device that was previously
 *  successfully registered with misc_register(). Success
 *  is indicated by a zero return, a negative errno code
 *  indicates an error.
 */

int misc_deregister(struct miscdevice *misc)
{
    int i = DYNAMIC_MINORS - misc->minor - 1;

    if (list_empty(&misc->list))
        return -EINVAL;

    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);


EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);

 

static char *misc_devnode(struct device *dev, mode_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;
}

 

static int __init misc_init(void)
{
    int err;

#ifdef CONFIG_PROC_FS
    proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
    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:
    printk("unable to get major %d for misc devices\n", MISC_MAJOR);
    class_destroy(misc_class);
fail_remove:
    remove_proc_entry("misc", NULL);
    return err;

}

subsys_initcall(misc_init);

 

 

 "kernel/drivers/base/core.c"

struct device *device_create(struct class *class, struct device *parent,  dev_t devt, void *drvdata, const char *fmt, ...)
{
    va_list vargs;
    struct device *dev;

    va_start(vargs, fmt);
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    va_end(vargs);
    return dev;
}
EXPORT_SYMBOL_GPL(device_create);

static int __match_devt(struct device *dev, void *data)
{
    dev_t *devt = data;

    return dev->devt == *devt;
}

/**
 * device_destroy - removes a device that was created with device_create()
 * @class: pointer to the struct class that this device was registered with
 * @devt: the dev_t of the device that was previously registered
 *
 * This call unregisters and cleans up a device that was created with a
 * call to device_create().
 */
void device_destroy(struct class *class, dev_t devt)
{
    struct device *dev;

    dev = class_find_device(class, NULL, &devt, __match_devt);
    if (dev) {
        put_device(dev);
        device_unregister(dev);
    }
}
EXPORT_SYMBOL_GPL(device_destroy);

 

 

 

 

你可能感兴趣的:(linux中的杂项设备所使用的misc_register()和 misc_deregister() 原理分析)