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

原文地址:https://www.cnblogs.com/maxma/p/9169768.html