Linux驱动|cdev_init、cdev_alloc区别
扫描二维码
随时随地手机看文章
nice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;">一、字符设备架构
下面我们以两个设备:LED、MPU6050为例来讲解字符设备的架构由上图所示:1、硬件
外设有MPU6050、LED两个设备,他们通过外设电路连接到SOC的对应的引脚上。程序要操作外设,就要通过设置soc中对应的SFR来与外设交互。2、驱动层
- 每一个字符设备都必须首先定义一个结构体变量struct cdev,并注册到内核中
- 所有的该变量在内核中会通过链表进程管理,其中成员list用于将所有链表串接起来
- 用于操作外设的功能函数全部被封装在struct file_operations中,包括read、write等
- 每一个字符设备都必须要有一个设备号,保存在成员dev中,
- 主、次设备号只能被分配一次
- 所有的字符设备号,都由数组chrdevs统一管理
- chrdevs是一个指针数组,成员类型为**struct char_device_struct ***,下标与字符设备号有一定的对应关系,
- **struct char_device_struct **中有成员:
unsigned int major;
struct cdev *cdev;
major : 是主设备号 cdev : 指向该字符设备号对应的cdev结构体3、应用层、VFS层
- 用户如果想操作硬件,必须调用内核中的struct file_operations中的操作函数,
- 那么如何才能找到该结构体呢?必须要依赖文件节点来查找,可以通过以下命令来创建
mknod /dev/led c 250 0
mknod 创建设备文件,可以使字符设备,也可以是块设备
/dev/led 设备文件名
c 字符设备
250 主设备号
0 次设备号
字符设备文件属性中最重要的属性就是字符设备号,该设备号和chedevs的下标有一定对应关系
- 通过mknod创建的文件,VFS层会分配一个结构体变量来维护该文件,类型为struct inode
- 每新建1个文件内核都会创建不同的结构体变量与之对应
- 应用程序要操作某个字符设备,那么必须先通过系统调用open()来打开该字符设备
- 该函数会返回一个唯一的整型文件描述符,同时内核中会分配结构体变量,类型为struct file,并与文件描述符一一对应,该结构体维护在struct task_struct中
- 每次打开某个文件,都会分配不同的文件描述符,所以需要用不同的变量来保存文件描述符
二、字符设备创建的流程
了解了架构之后,那么我们来看一下内核中完整的创建字符设备的流程及对应的函数调用关系:如下图所示,字符设备的创建主要包括以下三个步骤:- 申请设备号
- 初始化cdev
- 注册cdev 调用的函数见右侧
/*
*一口Linux
*2021.6.21
*version: 1.0.0
*/
#include
#include
#include
#include
#include
static int major = 237;
static int minor = 0;
static dev_t devno;
static struct cdev cdev;
static int hello_open (struct inode *inode, struct file *filep)
{
printk("hello_open()\n");
return 0;
}
static struct file_operations hello_ops =
{
.open = hello_open,
};
static int hello_init(void)
{
int result;
int error;
printk("hello_init \n");
devno = MKDEV(major,minor);
result = register_chrdev_region(devno, 1, "test");
if(result<0)
{
printk("register_chrdev_region fail \n");
return result;
}
cdev_init(