第12章 Linux设备驱动的软件架构思想之设备驱动的分层思想(混杂设备驱动)

12.3.6 misc设备驱动

    Linux驱动倾向于分层设计,各个具体的设备都可以找到它归属的类型,从而套到它相应的架构里面去,并且只需要实现最底层的那一部分。但是,也有部分类似globalmem、globalfifo的字符设备,确实不知道它属于什么类型,一般推荐大家采用miscdevice框架结构。miscdevice本质上也是字符设备,在miscdevice核心层(drivers/char/misc.c)的misc_init()函数中,通过register_chrdev(MISC_MAJOR,"misc",&misc_fops)注册字符设备,具体miscdevice实例调用(drivers/char/misc.c)misc_register()函数又自动完成device_create()、获取动态次设备号的动作。

    miscdevice的主设备号是固定的,MISC_MAJOR定义为10,Linux内核中,大概找到200多处使用miscdevice框架结构的驱动。

    miscdevice结构体的定义如代码清单12.21所示。

linux/miscdevice.h

struct miscdevice  {

        /*minor为MISC_DYNAMIC_MINOR,miscdevice核心层会自动找一个空闲的次设
备号,否则用minor指定的次设备号。
*/

        int minor; 
        const char *name;/*设备的名称*/
        const struct file_operations *fops;
        struct list_head list;
        struct device *parent;
        struct device *this_device;
        const char *nodename;
        umode_t mode;

};

备注:miscdevice结构体内file_operations中的成员函数,实际上是由drivers/char/misc.c中misc驱动核心层的misc_fops成员函数间接调用的,比如misc_open()就会间接调用底层注册的miscdevice的fops->open

static int misc_open(struct inode * inode, struct file * file)
{
int minor = iminor(inode);
struct miscdevice *c;
int err = -ENODEV;
const struct file_operations *new_fops = NULL;

mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}

if (!new_fops) {
mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
mutex_lock(&misc_mtx);

list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops)
goto fail;
}

err = 0;
replace_fops(file, new_fops);
if (file->f_op->open) {
file->private_data = c;
err = file->f_op->open(inode,file);
}

fail:
mutex_unlock(&misc_mtx);
return err;

}

miscdevice驱动的注册和注销分别用下面两个API:
linux/miscdevice.h
extern int misc_register(struct miscdevice * misc);

extern int misc_deregister(struct miscdevice *misc);

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)
{
dev_t dev;
int err = 0;

INIT_LIST_HEAD(&misc->list);

mutex_lock(&misc_mtx);

if (misc->minor == MISC_DYNAMIC_MINOR) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) {
err = -EBUSY;
goto out;
}
misc->minor = DYNAMIC_MINORS - i - 1;
set_bit(i, misc_minors);
} else {
struct miscdevice *c;
list_for_each_entry(c, &misc_list, list) {
if (c->minor == misc->minor) {
err = -EBUSY;
goto out;
}
}
}

dev = MKDEV(MISC_MAJOR, misc->minor);

misc->this_device = device_create(misc_class, misc->parent, dev,
  misc, "%s", misc->name); /* 创建设备 */
if (IS_ERR(misc->this_device)) {
int i =

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值