字符设备驱动的另一种写法
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);
以上是关于字符设备驱动的另一种写法的主要内容,如果未能解决你的问题,请参考以下文章