Linux学习第11天:字符设备驱动开发:一字一符总见情

             

本文是驱动开发的第一篇笔记。主要内容是字符设备驱动开发最基础的内容,主要包括字符设备的概念、开发步骤以及一个十分重要的概念:设备号。其思维导图能简单的显示本文的基本框架,如下:

一、字符设备

        字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、 IIC、 SPI,LCD 等等都是字符设备,这些设备的驱动就叫做字符设备驱动。

        在 Linux 内核文件 include/linux/fs.h 中有个叫做 file_operations 的结构体,此结构体就是 Linux 内核驱动操作函数集合。

二、字符设备驱动开发步骤

       ☆☆☆ Linux驱动开发的学习重点是学习其驱动框架。

1.驱动模块的加载和卸载

        将驱动编译为模块最大的好处就是方便开发。模块的加载和卸载函数如下:

module_init(xxx_init);  当使用insmod命令加载驱动时,xxx_init这个函数就会被调用。

module_exit(xxx_exit);当使用rmmod命令卸载驱动时,xxx_exit这个函数就会被调用。

        字符设备驱动模块加载和卸载模板如下所示:

1 /* 驱动入口函数 */
2 static int __init xxx_init(void)
3 {
4 /* 入口函数具体内容 */
5 return 0;
6 }
7 8
/* 驱动出口函数 */
9 static void __exit xxx_exit(void)
10 {
11 /* 出口函数具体内容 */
12 }
13
14 /* 将上面两个函数指定为驱动的入口和出口函数 */
15 module_init(xxx_init);
16 module_exit(xxx_exit);

        驱动编译完成以后扩展名为.ko

        insmod命令不能解决模块的依赖关系,所以推荐使用modprobe命令加载驱动模块。

2.字符设备的注册与注销

        字符设备的注册与注销函数原型如下:

static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)

        一般字符设备的注册在驱动模块的入口函数 xxx_init 中进行,字符设备的注销在驱动模块的出口函数 xxx_exit 中进行。实例如下所示:

1 static struct file_operations test_fops;
2 3
/* 驱动入口函数 */
4 static int __init xxx_init(void)
5 {
6 /* 入口函数具体内容 */
7 int retvalue = 0;
8 9
/* 注册字符设备驱动 */
10 retvalue = register_chrdev(200, "chrtest", &test_fops);
11 if(retvalue < 0){
12 /* 字符设备注册失败,自行处理 */
13 }
14 return 0;
15 }
16
17 /* 驱动出口函数 */
18 static void __exit xxx_exit(void)
19 {
20 /* 注销字符设备驱动 */
21 unregister_chrdev(200, "chrtest");
22 }
23
24 /* 将上面两个函数指定为驱动的入口和出口函数 */
25 module_init(xxx_init);
26 module_exit(xxx_exit);

3.实现设备的具体操作函数
 

        file_operation结构体就是设备的具体操作函数。

        实例有如下要求:

1.能够对chrtest进行打开和关闭操作。

2.对chrtest进行读写操作。

        明白需求以后,在其中加入test_fops这个结构体变量从初始化操作,内容如下:

1 /* 打开设备 */
2 static int chrtest_open(struct inode *inode, struct file *filp)
3 {
4 /* 用户实现具体功能 */
5 return 0;
6 }
7 8
/* 从设备读取 */
9 static ssize_t chrtest_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
10 {
11 /* 用户实现具体功能 */
12 return 0;
13 }
14
15 /* 向设备写数据 */
16 static ssize_t chrtest_write(struct file *filp,
const char __user *buf,
size_t cnt, loff_t *offt)
17 {
18 /* 用户实现具体功能 */
19 return 0;
20 }
21
22 /* 关闭/释放设备 */
23 static int chrtest_release(struct inode *inode, struct file *filp)
24 {
25 /* 用户实现具体功能 */
26 return 0;
27 }
28
29 static struct file_operations test_fops = {
30 .owner = THIS_MODULE,
31 .open = chrtest_open,
32 .read = chrtest_read,
33 .write = chrtest_write,
34 .release = chrtest_release,
35 };
36
37 /* 驱动入口函数 */
38 static int __init xxx_init(void)
39 {
40 /* 入口函数具体内容 */
41 int retvalue = 0;
42
43 /* 注册字符设备驱动 */
44 retvalue = register_chrdev(200, "chrtest", &test_fops);
45 if(retvalue < 0){
46 /* 字符设备注册失败,自行处理 */
47 }
48 return 0;
49 }
50
51 /* 驱动出口函数 */
52 static void __exit xxx_exit(void)
53 {
54 /* 注销字符设备驱动 */
55 unregister_chrdev(200, "chrtest");
56 }
57
58 /* 将上面两个函数指定为驱动的入口和出口函数 */
59 module_init(xxx_init);
60 module_exit(xxx_exit);

4.添加LICENSE和作者信息

        LICENSE必须添加,作者信息可以不添加。两种的添加使用如下两个函数:

MODULE_LICENSE()
MODULE_AUTHOR()
//添加模块 LICENSE 信息
//添加模块作者信息

内容如下:

1 /* 打开设备 */
2 static int chrtest_open(struct inode *inode, struct file *filp)
3 {
4 /* 用户实现具体功能 */
5 return 0;
6 }
......
57
58 /* 将上面两个函数指定为驱动的入口和出口函数 */
59 module_init(xxx_init);
60 module_exit(xxx_exit);
61
62 MODULE_LICENSE("GPL");
63 MODULE_AUTHOR("jia");

三、设备号

1.设备号的组成        

        Linux 中每个设备都有一个设备号,设备号由主设备号次设备号两部分组成,主设备号【12位】表示某一个具体的驱动次设备号【20位】表示使用这个驱动的各个设备。 Linux 提供了一个名为 dev_t 的数据类型表示设备号, dev_t 定义在文件include/linux/types.h 里面,定义如下:

12 typedef __u32 __kernel_dev_t;
......
15 typedef __kernel_dev_t dev_t;

_u32 类型的定义如下:

typedef unsigned int __u32;
include/linux/kdev_t.h提供了几个关于设备号的操作函数(本质是宏),如下所示:

6 #define MINORBITS 20//MINORMASK设备号
7 #define MINORMASK ((1U << MINORBITS) - 1)
8 
9#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))//宏MAJOR用于从dev_t中获取主设备号,将dev_t右移20位即可。
10 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))宏MINOR用于从dev_t中获取从设备号,取dev_t右移20位即可。
11 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))//宏MKDEV用于将给定的主设备号和次设备号的值组合成dev_t类型的设备号。

2.设备号的分配

1)、静态分配设备号

        cat/proc/devices命令可以查看当前系统中已经使用的设备号。

2)、动态分配设备号

        设备号的申请函数如下:

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

        注销掉字符设备后要释放掉设备号,设备号释放函数如下:

void unregister_chrdev_region(dev_t from,unsigned count)

四、chrdevbase字符设备驱动开发

1.实验程序编写

1)、创建VSCode工程

2)、添加头文件路径

3)、编写实验程序

2.编写测试APP

3.编译驱动程序和测试APP

1)、编译驱动程序

2)、编译测试APP

4.运行测试

1)、加载驱动模块

2)、创建设备节点文件

3)、chrdevbase字符设备操作测试

4)、卸载驱动模块

        作为初学者,我个人感觉重点还是重点关注驱动框架。所以在最后一部分,我没有过多的纠结实验中过多的细节,怕的就是一叶障目不见泰山,钻进某个细节里面不能自拔。

        总的来说,作为驱动开发最基础的一课,内容相对来说比较简单,希望以后的学习中能一步一个脚印,踏踏实实的走下去。因为,我相信一句话,这句话让我在工作两年后,没有选择放弃,没有自暴自弃,并最终考上了研究生,送给大家:坚持不懈,直到成功~


Linux版本号4.1.15   芯片MX6ULL

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/80840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wifi密码破解

文章目录 前言一、破解原理二、配置环境三、运行测试四、资源自取 前言 本文基于 python 实现了破解 wifi 密码的功能&#xff0c;采用的破解方式是穷举法&#xff0c;效率相对来说很低&#xff0c;对于设置密码简单的路由器来说比较适用。 一、破解原理 程序主要采用 python…

上海交通大学生存手册

强烈建议去看看《上海交通大学生存手册》&#xff0c;内容可能有点长&#xff0c;但讲得很好&#xff0c;说出了大学教育的本质。如果几年前我能看到它&#xff0c;也许我的大学生活可能会不一样。 只是&#xff0c;没有如果。 那么我把这本手册推荐给正在上大学或者是将要上…

[字符串和内存函数]strcpy和strncpy的区别

CPlus中对strcpy的介绍 /* strcpy example */ #include <stdio.h> #include <string.h>int main () {char str1[]"Sample string";char str2[40];char str3[40];strcpy (str2,str1);strcpy (str3,"copy successful");printf ("str1: %s\n…

YOLO目标检测——棉花病虫害数据集+已标注txt格式标签下载分享

实际项目应用&#xff1a;目标检测棉花病虫害数据集的应用场景涵盖了棉花病虫害的识别与监测、研究与防治策略制定、农业智能决策支持以及农业教育和培训等领域。这些应用场景可以帮助农业从业者更好地管理棉花病虫害&#xff0c;提高棉花产量和质量&#xff0c;推动农业的可持…

Nginx和Tomcat负载均衡实现session共享

以前的项目使用Nginx作为反向代理实现了多个Tomcat的负载均衡&#xff0c;为了实现多个Tomcat之间的session共享&#xff0c;使用了开源的Memcached-Session-Manager框架。 此框架的优势&#xff1a; 1、支持Tomcat6和Tomcat7 2、操作粘性或不黏性Session 3、没有单点故障 4、T…

Java 时间范围

前端使用Element-ui 时间范围组件 后端注意在Vo里面时间设置String类型不要设置Date类型 XMl组件字段映射成功性

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(四)

到目前为止&#xff0c;虽然基础的formdesigner部分已经完成&#xff0c;但流程用formdesigner提交与审批过程中的显示还有问题。 1、后端部分 其中FormConf修改如下&#xff1a; package com.ruoyi.flowable.core;import lombok.Data;import java.util.List; import java.uti…

Android 修复在 Settings 首页,按键盘方向键逐个单选

Android 修复在 Settings 首页&#xff0c;按键盘方向键逐个单选 问题现象问题分析解决办法 问题现象 在 Settings 主界面&#xff0c;按键盘方向键上下会直接整个选中&#xff0c;无法单条选中变色&#xff0c;而在二级页面中按方向键上下是正常的。 没有遥控器可以通过 adb…

flink的几种常见的执行模式

背景 在运行flink时&#xff0c;我们经常会有几种不同的执行模式&#xff0c;比如在IDE中启动时&#xff0c;通过提交到YARN上&#xff0c;还有通过Kebernates启动时&#xff0c;本文就来记录一下这几种模式 flink的几种执行模式 flink嵌入式模式&#xff1a; 这是一种我们在…

GDAL库学习

GDAL库学习 GDAL是一个操作栅格数据和矢量数据的库&#xff0c;对图像而言&#xff0c;可以进行包括读取、写入、转换、处理各种操作。 文章目录 GDAL库学习RasterIO()函数1. 添加引用2. 读取图像3. 获取图像基本信息4. 保存输出图像5. 释放 RasterIO()函数 RasterIO(GDALRWF…

动态的中秋爱心演示送女友用python生成爱心软件文末附c++语言写法

用python生成爱心软件 用python生成动态爱心软件 目录 用python生成爱心软件 完整代码 代码解释 逐句解释 效果展示&#xff1a; 如何打包 c写法 完整代码 import turtledef draw_heart():love turtle.Turtle()love.getscreen().bgcolor("black")love.…

WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)

Websocket和Server-Sent Events 对比推送数据给前端及各自的实现 二者对比WebSocket&#xff1a;Server-Sent Events (SSE)&#xff1a;选择 WebSocket 还是 SSE&#xff1a; Websocket 实现使用原生 WebSocket API&#xff1a;使用 Netty 创建 WebSocket&#xff1a;总结和选择…

SVN 和 GIT 命令对比

参考 https://blog.csdn.net/justry_deng/article/details/82259470 # TortoiseSVN打分支、合并分支、切换分支 https://www.huliujia.com/blog/802a64152bbbe877c95c84ef2fdf3857a056b536/ # 版本控制&#xff1a;Git与Svn的命令对应关系 TortoiseSVN打分支、合并分支、切换…

达梦数据库修改最大连接数

达梦数据库修改最大连接数 推荐配置修改最大连接数INI参数管理 推荐配置 达梦数据库的最大连接数推荐配置与服务器内存有关。不应设置得过大&#xff0c;否则容易导致出现OOM。 对应关系大致如下&#xff1a; 服务器内存MAX_SESSIONS范围8G50~10016G100~20032G200~30064G300…

unity 实现双击物体让其隐藏,单击物体让其显示

unity 实现双击物体让其隐藏&#xff0c;单击物体让其显示 private float tapThreshold 0.25f; private float tapTimer 0.0f; private bool tap false; private void Update() { if (Input.GetMouseButtonDown(0)) { if (Time.time < this.tapTimer this.tapThreshold)…

【深度学习-注意力机制attention 在seq2seq中应用】

注意力机制 为什么需要注意力机制attention机制的架构总体设计一、attention本身实现评分函数 attention在网络模型的应用-Bahdanau 注意力加性注意力代码实现 为什么需要注意力机制 这是一个普通的seq2seq结构&#xff0c;用以实现机器对话&#xff0c;Encoder需要把一个输入的…

初识React.js

引言&#xff1a; React是一种流行的JavaScript库&#xff0c;用于构建用户界面。无论您是新手还是有一些前端开发经验&#xff0c;本文将带您了解React框架的学习过程&#xff0c;并通过具体的例子来帮助您更好地理解和应用React。 1. 背景起源&#xff1a; React是由Faceb…

Selenium+python怎么搭建自动化测试框架、执行自动化测试用例、生成自动化测试报告、发送测试报告邮件

本人在网上查找了很多做自动化的教程和实例&#xff0c;偶然的一个机会接触到了selenium&#xff0c;觉得非常好用。后来就在网上查阅各种selenium的教程&#xff0c;但是网上的东西真的是太多了&#xff0c;以至于很多东西参考完后无法系统的学习和应用。 以下整理的只是书中…

5.11.Webrtc接口的设计原理

在上节课中呢&#xff0c;我向你介绍了web rtc的接口宏&#xff0c;那有很多同学会产生疑问啊&#xff0c;那觉得web rtc为什么要把接口设计的这么复杂&#xff1f;还非要通过宏来实现一个代理类&#xff0c;再通过代理类来调用到web rtc内部。 那为什么要这么设计呢&#xf…

java微服务项目整合skywalking链路追踪框架

skywalking官网网址&#xff1a;Apache SkyWalking 目录 1、安装skywalking 2、微服务接入skywalking 3、skywalking数据持久化 1、安装skywalking 下载skywalking&#xff0c;本篇文章使用的skywalking版本是8.5.0 Index of /dist/skywalkinghttps://archive.apache.org/…