miscdevice混杂设备驱动

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

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

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

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

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

[cpp]  view plain copy
  1. #ifndef _LINUX_MISCDEVICE_H  
  2. #define _LINUX_MISCDEVICE_H  
  3. #include <linux/module.h>  
  4. #include <linux/major.h>  
  5.   
  6. /* 
  7.  *      These allocations are managed by device@lanana.org. If you use an 
  8.  *      entry that is not in assigned your entry may well be moved and 
  9.  *      reassigned, or set dynamic if a fixed value is not justified. 
  10.  */  
  11.   
  12. #define PSMOUSE_MINOR           1  
  13. #define MS_BUSMOUSE_MINOR       2  
  14. #define ATIXL_BUSMOUSE_MINOR    3  
  15. /*#define AMIGAMOUSE_MINOR      4       FIXME OBSOLETE */  
  16. #define ATARIMOUSE_MINOR        5  
  17. #define SUN_MOUSE_MINOR         6  
  18. #define APOLLO_MOUSE_MINOR      7  
  19. #define PC110PAD_MINOR          9  
  20. /*#define ADB_MOUSE_MINOR       10      FIXME OBSOLETE */  
  21. #define WATCHDOG_MINOR          130     /* Watchdog timer     */  
  22. #define TEMP_MINOR              131     /* Temperature Sensor */  
  23. #define RTC_MINOR               135  
  24. #define EFI_RTC_MINOR           136     /* EFI Time services */  
  25. #define SUN_OPENPROM_MINOR      139  
  26. #define DMAPI_MINOR             140     /* DMAPI */  
  27. #define NVRAM_MINOR             144  
  28. #define SGI_MMTIMER             153  
  29. #define STORE_QUEUE_MINOR       155  
  30. #define I2O_MINOR               166  
  31. #define MICROCODE_MINOR         184  
  32. #define TUN_MINOR               200  
  33. #define MWAVE_MINOR             219     /* ACP/Mwave Modem */  
  34. #define MPT_MINOR               220  
  35. #define MPT2SAS_MINOR           221  
  36. #define HPET_MINOR              228  
  37. #define FUSE_MINOR              229  
  38. #define KVM_MINOR               232  
  39. #define BTRFS_MINOR             234  
  40. #define AUTOFS_MINOR            235  
  41. #define MISC_DYNAMIC_MINOR      255  
  42.   
  43. struct device;  
  44.   
  45. struct miscdevice  {  
  46.         int minor;  //次设备号
  47.         const char *name;  //设备名
  48.         const struct file_operations *fops;//文件操作  
  49.         struct list_head list;  //形成链表
  50.         struct device *parent;  
  51.         struct device *this_device;  
  52.         const char *nodename;  
  53.         mode_t mode;  
  54. };  
  55.   
  56. extern int misc_register(struct miscdevice * misc);  //混杂设备注册
  57. extern int misc_deregister(struct miscdevice *misc);  //混杂设备注销
  58.   
  59. #define MODULE_ALIAS_MISCDEV(minor)                             \  
  60.         MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)      \  
  61.         "-" __stringify(minor))  
  62. #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);

 转载至:http://blog.csdn.net/duanlove/article/details/8225624#

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值