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

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

相关推荐
璞致电子5 小时前
基于 AD9361 (PZSDR‑P201Pro) 软件无线电实战综述:从板卡选型、硬件平台升级到 GNU Radio QPSK 完整收发链路
经验分享·嵌入式硬件·fpga开发·软件无线电·sdr·璞致电子
青梅味猪大肠6 小时前
【操作系统-26】进程互斥软件实现-Peterson算法
linux·运维·服务器
高斯的手稿08016 小时前
CS+中,全局变量的正确管理方式
嵌入式硬件
辣知6 小时前
辣知·化智68 半仙隐士渭水钓的不是鱼
学习
俊基科技6 小时前
喇叭 95dB、麦克风贴到 1cm,回音还能消干净?拆解 A-29P 的消回音设计
嵌入式硬件·硬件开发·ai降噪·回音消除·拾音降噪
wdfk_prog6 小时前
Wi-Fi Direct教程 01:在 Ubuntu 搭建双 mac80211_hwsim + wpa_supplicant 2.12
linux·运维·服务器·ubuntu·ros·wifi-direct
2401_862880826 小时前
LCD 显示与触控屏驱动开发
驱动开发·嵌入式硬件
传奇开心果编程6 小时前
【用案例学Material 3 Expressive】第1课:从一封邮件开始,感受安卓设计新语言的表现力
android·学习·ui·kotlin·android jetpack
sunoo-2296 小时前
【嵌入式 ARM 学习第十二天】SPI 裸机驱动 + I2C 触摸屏驱动 + 三大串行协议深度对比
arm开发·笔记·vscode·学习·imx6ull
墨心@7 小时前
第 4 章《工具》学习总结
学习·自然语言处理·prompt·agent·harness