linux字符设备驱动

一. 字符设备结构体

struct cdev {
	struct kobject kobj;		//kobject对象
	struct module *owner;		//模块所有者
	const struct file_operations *ops;	//文件操作函数集
	struct list_head list;		//链表头
	dev_t dev;			//设备号
	unsigned int count;		//引用次数
};

二. 分配字符设备结构体

struct cdev *cdev_alloc(void)
{
	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);	//分配内存
	if (p) {
		INIT_LIST_HEAD(&p->list);
		kobject_init(&p->kobj, &ktype_cdev_dynamic);
	}
	return p;
}

三. 字符设备初始化 

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
	memset(cdev, 0, sizeof *cdev);	//初始化cdev结构体
	INIT_LIST_HEAD(&cdev->list);	//初始化链表头
	kobject_init(&cdev->kobj, &ktype_cdev_default);	//初始化kobject对象
	cdev->ops = fops;			//指定文件操作函数集
}

四. 添加字符设备

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
	p->dev = dev;			//指定设备号
	p->count = count;			//设置引用计数
	return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}

五. 删除字符设备

void cdev_del(struct cdev *p)
{
	cdev_unmap(p->dev, p->count);
	kobject_put(&p->kobj);
}

六. 设备号的分配与释放

1.静态分配 register_chrdev_region

int register_chrdev_region(dev_t from, unsigned count, const char *name)		//参数:起始主设备号,设备个数,设备名
{
	struct char_device_struct *cd;
	dev_t to = from + count;
	dev_t n, next;

	for (n = from; n < to; n = next) {
		next = MKDEV(MAJOR(n)+1, 0);
		if (next > to)
			next = to;
		cd = __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name);
		if (IS_ERR(cd))
			goto fail;
	}
	return 0;
fail:
	to = n;
	for (n = from; n < to; n = next) {
		next = MKDEV(MAJOR(n)+1, 0);
		kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
	}
	return PTR_ERR(cd);
}

2.动态分配 alloc_chrdev_region

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
{
	struct char_device_struct *cd;
	cd = __register_chrdev_region(0, baseminor, count, name);
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	*dev = MKDEV(cd->major, cd->baseminor);
	return 0;
}

 

3.释放设备号 unregister_chrdev_region

void unregister_chrdev_region(dev_t from, unsigned count)
{
	dev_t to = from + count;
	dev_t n, next;

	for (n = from; n < to; n = next) {
		next = MKDEV(MAJOR(n)+1, 0);
		if (next > to)
			next = to;
		kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
	}
}


七. 简单字符设备例子

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/cdev.h>

int test_major;
dev_t test_dev;
struct cdev *my_cdev;

static int test_open(struct inode * inode, struct file * filp)
{
	return 0;
}

static const struct file_operations test_fops = {	//操作函数集
	.owner = THIS_MODULE,
	.open  = test_open,
};

static int __init test_init(void)
{
	int ret=0;
	my_cdev=cdev_alloc();		//分配字符设备结构体

	if(test_major){				//分配设备号
		test_dev=MKDEV(test_major,0);
		register_chrdev_region(test_dev,0,"test");
	}
	else{
		ret=alloc_chrdev_region(&test_dev,0,0,"test");
		test_major=MAJOR(test_dev);
	}
	cdev_init(my_cdev,&test_fops);	//初始化字符设备,捆绑操作函数集
	cdev_add(my_cdev,test_dev,0);	//添加字符设备,捆绑主设备号
	return ret;
}

static void __exit  test_exit(void)
{
	cdev_del(my_cdev);
	unregister_chrdev_region(MKDEV(test_major,0),0);
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");



 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值