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

news2025/1/17 0:54:10

             

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

一、字符设备

        字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、 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.coloradmin.cn/o/1016188.html

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

相关文章

MySQL注入绕安全狗脚本 -- MySQLByPassForSafeDog,以及端口爆破工具 -- PortBrute配置使用

工具介绍 此Tamper仅仅适用于MySQL数据库&#xff0c;在SQLMap使用过程中添加参数–tamperMySQLByPassForSafeDog。 安装与使用 1、安装网站安全狗Apache最新版 2、启用安全狗&#xff0c;不加MySQLByPassForSafeDog绕狗Tamper: python sqlmap.py -u "http://192.168.…

又一个Python调试利器

迷途小书童 读完需要 5分钟 速读仅需 2 分钟 1 简介 在编程过程中&#xff0c;几乎难以避免的会出现错误。事实上&#xff0c;程序员为了消除错误&#xff0c;要花费大量的时间在代码调试上。在调试过程中&#xff0c;使用 print() 语句来理解程序流程和发现意外行为无疑是最常…

iOS系统暗黑模式

系统暗黑模式&#xff1a; 暗黑模式颜色适配&#xff1a; 方式1&#xff1a; Assets配置&#xff1a;在Assets中配置好颜色后&#xff0c;可以通过colorNamed: 放大获取到动态颜色。 方式2&#xff1a;代码配置&#xff0c;通过代码colorWithDynamicProvider: 可以看出来生成…

C语言指针进阶(2)

大家好&#xff0c;我们今天继续来分享指针进阶的内容。 目录 5.函数指针 6.函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 5.函数指针 顾名思义函数指针里面存的就是函数的地址了。 那我们通过一段代码来理解函数指针&#xff1a; #include<stdio.h> int Add…

向日葵无法连接服务器(无法登录)

最近在使用向日葵过程中&#xff0c;突然就不能登录向日葵了&#xff0c;网上查了各种解决方案&#xff0c;比如说防火墙是不是把向日葵给拦截了&#xff1f;更换不同的版本等等&#xff0c;都无法解决&#xff0c;最后突然想到是不是电脑对向日葵原安装目录限制了&#xff1f;…

创建表

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 创建表 语法格式: create table 表名(列名1 数据类型,列名2 数据类型,... ,列名n, 数据类型 ); 练习:在czwbkl库中,创建一格test01表 跟大家说…

windows下C++的反射功能

概述 c/c如果在日志中查看某个结构体/类的每个变量名&#xff0c;变量值信息&#xff0c;只能通过printf逐个格式化&#xff0c;非常繁琐&#xff0c;如何做到类似protobuff转json的序列化功能呢&#xff1f;该dll库先通过分析pdb文件获取结构体/类的变量名称、变量地址&#…

WebGL 从0到1绘制一个立方体

目录 前言 组成立方体的面、三角形、顶点坐标和顶点颜色 通过顶点索引绘制物体 gl.drawElements(mode, count, type, offset) 函数规范 示例程序 彩色立方体&#xff08;HelloCube.js&#xff09; 代码详解 向缓冲区中写入顶点的坐标、颜色与索引 gl.ELEMENT_ARRAY_B…

RFID产线自动化升级改造管理方案

应用背景 在现代制造业中&#xff0c;产线管理是实现高效生产和优质产品的关键环节&#xff0c;产线管理涉及到生产过程的监控、物料管理、工艺控制、质量追溯等多个方面&#xff0c;有效的产线管理可以提高生产效率、降低成本、改善产品质量&#xff0c;并满足市场需求的变化…

elasticsearch1

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

iText实战--在现有PDF上工作

6.1 使用PdfReader读取PDF 检索文档和页面信息 D:/data/iText/inAction/chapter03/image_direct.pdf Number of pages: 1 Size of page 1: [0.0,0.0,283.0,416.0] Rotation of page 1: 0 Page size with rotation of page 1: Rectangle: 283.0x416.0 (rot: 0 degrees) Is reb…

重新认识架构—不只是软件设计

前言 什么是架构&#xff1f; 通常情况下&#xff0c;人们对架构的认知仅限于在软件工程中的定义&#xff1a;架构主要指软件系统的结构设计&#xff0c;比如常见的SOLID准则、DDD架构。一个良好的软件架构可以帮助团队更有效地进行软件开发&#xff0c;降低维护成本&#xff0…

C# 查找迷宫路径

1.导入图像&#xff0c;并且将图像转灰度 using var img new Image<Bgr, byte>(_path); using var grayImg img.Convert<Gray, byte>(); 2.自动二值化图像 using var inputGrayOut new Image<Gray, byte>(grayImg.Size); // 计算OTSU阈值 var threshol…

【图像处理】VS编译opencv源码,并调用编译生成的库

背景 有些时候我们需要修改opencv相关源码&#xff0c; 这里介绍怎么编译修改并调用修改后的库文件。 步骤 1、下载相关源码工具&#xff1a; 下载opencv4.8源码并解压 https://down.chinaz.com/soft/40730.htm 下载VS2019&#xff0c;社区版免费 https://visualstudio.micro…

【C++】动态规划题目总结(随做随更)

文章目录 一. 斐波那契数列模型1. 第 N 个泰波那契数2. 三步问题3. 使用最小花费爬楼梯解法一&#xff1a;从左往右填表解法二&#xff1a;从右往左填表 一. 斐波那契数列模型 解题步骤&#xff1a; 确定状态表示&#xff08;最重要&#xff09;&#xff1a;明确dp表里的值所…

用Jmeter进行压测详解

简介&#xff1a; 1.概述 一款工具&#xff0c;功能往往是很多的&#xff0c;细枝末节的地方也很多&#xff0c;实际的测试工作中&#xff0c;绝大多数场景会用到的也就是一些核心功能&#xff0c;根本不需要我们事无巨细的去掌握工具的所有功能。所以本文将用带价最小的方式讲…

RocketMQ的介绍和环境搭建

一、介绍 我也不知道是啥&#xff0c;知道有什么用、怎么用就行了&#xff0c;说到mq&#xff08;MessageQueue&#xff09;就是消息队列&#xff0c;队列是先进先出的一种数据结构&#xff0c;但是RocketMQ不一定是这样&#xff0c;简单的理解一下&#xff0c;就是临时存储的…

功率谱密度PSD(笔记)

能量守恒&#xff1a;时域能量等于频域能量 功率谱密度能够反映随机振动的功率关于频率的分布密度 功率谱密度&#xff08;PSD&#xff09;&#xff1a;单位是功率/Hz。针对功率有限信号(能量有限信号用能量谱密度)。表现为是单位频带内信号功率随频率的变换情况&#xff0c;…

【深度学习】Pytorch 系列教程(十一):PyTorch数据结构:3、变量(Variable)介绍

目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量&#xff08;Tensor&#xff09; 2、张量操作&#xff08;Tensor Operations&#xff09; 3、变量&#xff08;Variable&#xff09; 一、前言 ChatGPT&#xff1a; PyTorch是一个开源的机器学习框架&am…

Vulnhub系列靶机---Deathnote: 1死亡笔记

文章目录 信息收集主机发现端口扫描目录扫描dirsearchgobusterdirb扫描 漏洞利用wpscan扫描Hydra爆破 总结 靶机文档&#xff1a;Deathnote: 1 下载地址&#xff1a;Download (Mirror) 难易程度&#xff1a;so Easy 信息收集 主机发现 端口扫描 访问靶机的80端口&#xff0c;报…