一. 字符设备结构体
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");