• Linux中miscdevice混杂设备驱动分析


    定义:字符设备的一种,它们共享一个主设备号(10),但次设备号不同,所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的miscdevice设备。

    例如:触摸屏,LED,按键,串口。

    即:为了节约主设备号,将某些设备用链表的形式连接在一起,最后通过查找次设备区分。这里用主设备无法匹配出设备驱动,只能找到链表,再通过次设备号,才能找到设备驱动。而之前所学的,一般字符设备,通过主设备号,就能找到设备驱动了。

    混杂设备驱动内置有自动创建设备节点的代码,所以编译好之后,能自动创建设备节点。

     

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

    1. #ifndef _LINUX_MISCDEVICE_H  
    2. #define _LINUX_MISCDEVICE_H  
    3. #include   
    4. #include   
    5.   
    6.   
    7.   
    8. #define PSMOUSE_MINOR           1  
    9. #define MS_BUSMOUSE_MINOR       2  
    10. #define ATIXL_BUSMOUSE_MINOR    3  
    11.   
    12. #define ATARIMOUSE_MINOR        5  
    13. #define SUN_MOUSE_MINOR         6  
    14. #define APOLLO_MOUSE_MINOR      7  
    15. #define PC110PAD_MINOR          9  
    16.   
    17. #define WATCHDOG_MINOR          130       
    18. #define TEMP_MINOR              131       
    19. #define RTC_MINOR               135  
    20. #define EFI_RTC_MINOR           136       
    21. #define SUN_OPENPROM_MINOR      139  
    22. #define DMAPI_MINOR             140       
    23. #define NVRAM_MINOR             144  
    24. #define SGI_MMTIMER             153  
    25. #define STORE_QUEUE_MINOR       155  
    26. #define I2O_MINOR               166  
    27. #define MICROCODE_MINOR         184  
    28. #define TUN_MINOR               200  
    29. #define MWAVE_MINOR             219       
    30. #define MPT_MINOR               220  
    31. #define MPT2SAS_MINOR           221  
    32. #define HPET_MINOR              228  
    33. #define FUSE_MINOR              229  
    34. #define KVM_MINOR               232  
    35. #define BTRFS_MINOR             234  
    36. #define AUTOFS_MINOR            235  
    37. #define MISC_DYNAMIC_MINOR      255  
    38.   
    39. struct device;  
    40.   
    41. struct miscdevice   
    42.         int minor;  //次设备号
    43.         const char *name;  //设备名
    44.         const struct file_operations *fops;//文件操作  
    45.         struct list_head list;  //形成链表
    46.         struct device *parent;  
    47.         struct device *this_device;  
    48.         const char *nodename;  
    49.         mode_t mode;  
    50. };  
    51.   
    52. extern int misc_register(struct miscdevice misc);  //混杂设备注册
    53. extern int misc_deregister(struct miscdevice *misc);  //混杂设备注销
    54.   
    55. #define MODULE_ALIAS_MISCDEV(minor)                               
    56.         MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)        
    57.         "-" __stringify(minor))  
    58. #endif  

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

     

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

       
        list_add(&misc->list, &misc_list);
     out:
        mutex_unlock(&misc_mtx);
        return err;
    }

     

    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 ", 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;
    }


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

  • 相关阅读:
    life
    Android通过XML来定义Menu
    Android通过XML来定义Menu
    Android开发之Menu:OptionMenu(选项菜单)、ContextMenu(上下文菜单)、SubMenu(子菜单)
    作为股权类投资人,我们的投资偏好和投资原则
    作为股权类投资人,我们的投资偏好和投资原则
    给TextView添加超链接的四种方式
    详解ExplosionField的使用,实现View的粉碎效果
    MySql中允许远程连接
    我的投资案例(3)-看好互联网和金融两大朝阳行业,参投入股垂直金融招聘平台"职业梦CareerDream.cn"
  • 原文地址:https://www.cnblogs.com/maxma/p/9169768.html
Copyright © 2020-2023  润新知