Linux学习第12天:基于API函数的字符设备驱动开发:一字一符总见情

本节学习的内容主要为基于LinuxAPI函数的字符设备驱动的开发,还包括在驱动模块加载的时候如何自动创建设备节点。总结的脑图如下:

一、驱动原理

1.分配和释放设备号

申请设备号函数:

cpp 复制代码
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

注册设备号函数:

cpp 复制代码
int reister_chrdev_region(dev_t from, unsigned count, const char *name)//rrom起始设备号 count数量 name设备名

设备释放函数:

cpp 复制代码
void unregister_chrdev_region(dev_t from, unsigned count)

设备号分配实例:

cpp 复制代码
1 int major; /* 主设备号 */
2 int minor; /* 次设备号 */
3 dev_t devid; /* 设备号 */
4 5
if (major) { /* 定义了主设备号 */
6 devid = MKDEV(major, 0); /* 大部分驱动次设备号都选择 0 */
7 register_chrdev_region(devid, 1, "test");
8 } else { /* 没有定义设备号 */
9 alloc_chrdev_region(&devid, 0, 1, "test"); /* 申请设备号 */
10 major = MAJOR(devid); /* 获取分配号的主设备号 */
11 minor = MINOR(devid); /* 获取分配号的次设备号 */
12 }

大部分次设备号都选择0

2.注册方法

1)、字符设备结构

cdev结构体在/include/linux/cdev.h中定义如下:

cpp 复制代码
1 struct cdev {
2 struct kobject kobj;
3 struct module *owner;
4 const struct file_operations *ops;//file_operations
5 struct list_head list;
6 dev_t dev;//cdev
7 unsigned int count;
8 };

编写字符设备驱动之前,需要定义一个cdev结构体变量,这个变量就表示一个字符设备。

cpp 复制代码
struct cdev test_cdev;

2)、cdev_init

初始化函数cdev_init内容如下:

cpp 复制代码
void cdev_init(struct cdev *cdev, const struct file_operations *fops)

使用cdev_init函数初始化cdev变量代码如下:

cpp 复制代码
1 struct cdev testcdev;
2 
3
/* 设备操作函数 */
4 static struct file_operations test_fops = {
5 .owner = THIS_MODULE,
6 /* 其他具体的初始项 */
7 };
8 
9
testcdev.owner = THIS_MODULE;
10 cdev_init(&testcdev, &test_fops); /* 初始化 cdev 结构体变量 */

3)、cdev_add

cdev_add函数原型:

cpp 复制代码
int cdev_add(struct cdev *p, dev_t dev, unsigned count)

注册字符设备代码段内容:

cpp 复制代码
1 struct cdev testcdev;
2 
3
/* 设备操作函数 */
4 static struct file_operations test_fops = {
5 .owner = THIS_MODULE,
6 /* 其他具体的初始项 */
7 };
8 
9testcdev.owner = THIS_MODULE;
10 cdev_init(&testcdev, &test_fops); /* 初始化 cdev 结构体变量 */
11 cdev_add(&testcdev, devid, 1); /* 添加字符设备 */

4)、cdev_del

cdev_del原型内容:

cpp 复制代码
void cdev(struct cdev *p)

二、自动创建设备节点

自动创建设备节点以后,使用modprobe加载驱动模块成功的话就会自动在/dev目录下创建对应的设备文件。

1.modev机制

udev程序实现设备文件的创建与删除。

2.创建和删除类

class_create是类创建函数,class_create是个宏定义,内容如下:

cpp 复制代码
1 #define class_create(owner, name) \//owner一般为THIS_MODULE name为类名字 返回值是指向结构体class的指针,也就是创建的类
2 ({ \
3 static struct lock_class_key __key; \
4 __class_create(owner, name, &__key); \
5 })
6 
7
struct class *__class_create(struct module *owner, const char *name,
8 struct lock_class_key *key)

卸载驱动函数的时候需要删除类,class_destroy函数原型如下:

cpp 复制代码
void class_destroy(struct class *cls)//cls就是要删除的类

3.创建设备

创建好类以后,还需要在类下面创建一个设备,才能实现自动创建设备节点。

device_create函数原型如下:

cpp 复制代码
struct device *device_create(struct class *class,//clasd  要创建的类
struct device *parent,//parent 父设备 一般为NULL
dev_t devt,//devt 设备号
void *drvdata,//drvdata 设备可能会使用的一些数据 一般为NULL
const char *fmt, ...)//fmt 设备名字 生成/dev/xxx

卸载时,需要删掉创建的设备。device_destroy函数原型如下:

cpp 复制代码
void device_destroy(struct class *class, dev_t devt)//class 删除的类 devt删除的设备号

三、设置文件私有数据

编写open函数的时候将设备结构体作为私有数据添加到设备文件中,如下:

cpp 复制代码
/* 设备结构体 */
1 struct test_dev{
2 dev_t devid; /* 设备号 */
3 struct cdev cdev; /* cdev */
4 struct class *class; /* 类 */
5 struct device *device; /* 设备 */
6 int major; /* 主设备号 */
7 int minor; /* 次设备号 */
8 };
9
10 struct test_dev testdev;
11
12 /* open 函数 */
13 static int test_open(struct inode *inode, struct file *filp)
14 {
15 filp->private_data = &testdev; /* 设置私有数据 */
16 return 0;
17 }

在open函数里面设置好私有数据以后,在write、read、close等函数中直接读取private_data即可得到设备结构体。

本节学习的内容看似就几个函数而已,但是要将其替换改动到原来的驱动函数中还是需要一定的代码功力的。切记戒骄戒躁,放平心态,一遍一遍不厌其烦的去调试,去总结。相信功夫不负有心人,铁棒总能磨成针......


Linux版本号4.1.15 芯片MX6ULL

本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

相关推荐
zhaowangji10 分钟前
ubuntu 20.04 安装中文输入法 (sougou pin yin)
linux·ubuntu
两斤半1 小时前
Debian TTY环境乱码
linux·debian
站在巨人肩膀上的码农2 小时前
全志T507 音频ALSA核心层注册流程分析
驱动开发·音视频·安卓·全志·alsa·声卡
X_StarX2 小时前
【Unity笔记02】订阅事件-自动开门
笔记·学习·unity·游戏引擎·游戏开发·大学生
MingYue_SSS2 小时前
开关电源抄板学习
经验分享·笔记·嵌入式硬件·学习
还是奇怪2 小时前
Linux - 安全排查 2
linux·运维·安全
玉树临风江流儿2 小时前
炸鸡派-定时器基础例程
单片机·嵌入式硬件
weixin_437398212 小时前
转Go学习笔记(2)进阶
服务器·笔记·后端·学习·架构·golang
慕y2743 小时前
Java学习第十六部分——JUnit框架
java·开发语言·学习
is08153 小时前
STM32的 syscalls.c 和 sysmem.c
c语言·stm32·嵌入式硬件