开发者学堂课程【物联网开发 - Linux 驱动开发实操演练:字符设备驱动03】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/657/detail/10875
字符设备驱动03
内容介绍:
一、 回顾
二、 编写字符设备驱动
一、 回顾
在上节课中,讲了最后设备的一个重要结构体,就是 CDEV 结构体的分析类。接下来,就是讲围绕 CDEV 结构体,应该如何去往内核里注册一个 CDEV,注册一个字符设备,然后,字符设备驱动的一个框架是什么样,将详细分析。
在 CDEV 结构体中描述了字符设备的通用信息, 较为重要的是设备号和操作方法集。
二、 编写字符设备驱动
要编写一个字符设备驱动,设备驱动,都是由内核统一管理的,所以在写设备驱动时,一定得遵循内核提供的一个设备驱动的一个框架。同样的字符设备,也要遵循字符设备驱动一个框架,首先它是围绕 CDEV 结构体来完成字符设备驱动的编写的。
1、 CDEV 结构体分配内存空间。
在内核中提供了一个分配内存空间的函数。
代码:
void cdev_init(struct cday *,const struct file_operations*);
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
我们所关心此函数有三点以下内容:
功能:为 CDEV 结构体分配空间
参数:void
返回值: 结构体指针。(成功返回分配到的结构体地址,失败返回 NULL)
Struct cdev *cdev_alloc(void)
函数的实现:
函数如果是调用成功以后,返回的是 CDEV 结构体指针,如果失败就返回一个空值。
代码:
struct cdev *cdev_alloc(void)
{
struct cdev *p =kzallod(sizeof(struct cdev),GFP_KERNEL);
if (p){
INIT_LIST_HEAD(&p->List);
kobject_init(&p->kobj,&ktype_cdev_dynamic);
}
return p;
}
实际上调用了内核的分配函数 kzalloc 来分配空间。
2、 初始化 cdev 结构体
将 CDEV 结构体每个成员变量进行初始化进行赋值
代码:
Void cdev_int(struct cdev *cde, const struct file_operations *fops)
{
memset(cdev,0,sizeof *cdev);
INIT_LIST_HEAD(&cdev->List);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops fops;
}
初始化函数 cdev_init
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
分析其特点:功能,参数,返回值
功能:初始化 cdev 结构体
参数:void
@fops 操作方法集的指针
@cdev CDEV 结构体指针
返回值:void
不需要去判断它的返回值,而对于这个 CDEV INIT 来说,是不需要传参,但是,必须判断它的返回值,如果成功,我们才能接下来去对它进行数字化,进行使用注册。那如果分配失败,只能分配到一个空的,比如:分配到零地址,零地址,是不允许去读写的。
3、 添加字符设备到内核中,由内核同意管理
要将现在的具体的实例注册给内核,让内核统一来管理驱动设备。
添加到内核的函数:
代码:
Int cdev_add(struct cdev *p,dev_t dev,unsigned count)
{
p->dev = dev;
p->count = count:
Cdev_add
Int cdev_add(struct cdev *p, dev_t dev, unsigned count)
功能:添加字符设备到内核中,由内核同意管理
参数:
@cdev CDEV 结构体指针
@dev 设备号
@count 设备个数(同时驱动的设备个数)
返回值:
代码:
Int cdev_add(struct cdev *p,dev_t dev,unsigned count)
{
p->dev = dev;
p->count = count:
Cdev_add
返回值为 int 类型。
在失败时会返回一个错误的内码
警告:
A negative error code is returned on failure.
成功返回零
4、 删除(注销)字符设备
代码:
Void cdev_del(struct cdev *p)
{
Cdev_unmap(p-dev, p->count);
Kobject_put(&p->kobj);
}
Void cdev_del(struct cdev *p)
当驱动不用的时候,就应该从内核里删除掉。内核的这个内核空间就内存空间,所以当不用的时候,一定要去删除掉。
应写在内核模块退出或卸载函数里
内核模块是非常重要的,那同样写字符设备驱动,这些内容,也是放在内核模块儿框架里去完成的。
注意:
设备号为内核的一个资源,要想使用设备号,必须分配设备号或者申请设备号。