字符设备驱动的另一种写法

Posted jasontian996

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符设备驱动的另一种写法相关的知识,希望对你有一定的参考价值。

字符设备驱动的另一种写法

在Linux2.6内核中,使用cdev结构体描述一个字符设备;

cdev结构体(include/linux/cdev.h)定义如下:

struct cdev 
    struct kobject kobj;               /* 内嵌的kobject对象 */
    struct module *owner;              /* 所属模块 */
    const struct file_operations *ops; /* 文件操作结构体 */
    struct list_head list;
    dev_t dev;                         /* 设备号 */
    unsigned int count;
;

cdev结构体中的dev成员定义了设备号,为32位,其中12位主设备号,20位次设备号;

使用下列宏可以从dev获得主设备号和次设备号,以及通过主设备号和次设备号生成dev_t,定义如下:

#define MINORBITS   20
#define MINORMASK   ((1U << MINORBITS) - 1)

#define MAJOR(dev)  ((unsigned int) ((dev) >> MINORBITS)) /* 获取主设备号 */
#define MINOR(dev)  ((unsigned int) ((dev) & MINORMASK))  /* 获取次设备号 */
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))      /* 根据主次设备号生成dev*/

cdev结构体中的另一个重要成员file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数;

Linux2.6内核提供了一组函数用于操作cdev结构体,定义如下:

/* 用于初始化cdev的成员,并建立cdev和file_operation之间的连接 */
void cdev_init(struct cdev *, const struct file_operations *);
/* 用于动态申请一个cdev内存 */
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
/* 向系统添加一个cdev,完成字符设备的注册 */
int cdev_add(struct cdev *, dev_t, unsigned);
/* 向系统删除一个cdev,完成字符设备的注销 */
void cdev_del(struct cdev *);

对于cdev_add()函数的调用通常发生在字符设备驱动模块加载函数中,向系统注册一个字符设备,在此之前应首先调用如下函数向系统申请设备号:

/* 用于已知起始设备的设备号的情况 */
int register_chrdev_region(dev_t from, unsigned count, const char *name);
或者:
/* 用于设备号未知,向系统动态申请未被占用的设备号的情况 */
/* 调用该函数成功后,会把得到的设备号放入第一个参数dev中 */
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
            const char *name);

对于cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号;

具体使用如下:

/* 定义一个dev_t类型变量 */
dev_t dev_id;

static struct cdev xxx_cdev;
static int major;
static const struct file_operations xxx_fops = 
    .owner  = THIS_MODULE,
    .write  = xxx_write,
    .read   = xxx_read,
    .open   = xxx_open
;

/* 设备驱动模块加载函数 */
static int __init xxx_init(void)

    if (major)  /* 如果已知主设备号 */
        dev_id = MKDEV(major, 0);
        retval = register_chrdev_region(dev_id, 1, DEV_NAME);
     else 
        retval = alloc_chrdev_region(&dev_id, 0, 1, DEV_NAME);
        major = MAJOR(dev_id);
    
    cdev_init(&xxx_cdev, &xxx_fops);
    cdev_add(&xxx_cdev, dev_id, 1);


/* 设备驱动模块卸载函数 */
static void __exit xxx_exit(void)

    cdev_del(&xxx_cdev);
    unregister_chrdev_region(dev_id, 1);

以上是关于字符设备驱动的另一种写法的主要内容,如果未能解决你的问题,请参考以下文章

字符设备驱动另一种写法—mmap方法操作LED

for循环的另一种写法

在>=win10 17134枚举驱动的另一种方法

在>=win10 17134枚举驱动的另一种方法

显性等待的另一种写法

PowerShell-自定义函数 Function的另一种写法