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

2023-11-06

             

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

一、字符设备

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux学习第11天:字符设备驱动开发:一字一符总见情 的相关文章

  • Web 应用程序的带宽和流量模拟器?

    您能否建议如何创建一个测试环境来模拟 Web 应用程序中的各种类型的带宽和流量 或者也许是一个针对本地主机执行此操作的开源程序 我认为在编写网络应用程序时这是一个非常重要的主题 但这不是一个常见的主题 我能想象创建这种环境的唯一方法是在本地
  • C:如果文件描述符被删除,阻塞读取应该返回

    我正在以阻塞的方式从设备 文件描述符中读取 可能会发生这样的情况 在不同的线程中 设备被关闭并且文件描述符被删除 不幸的是 读取没有返回或注意到并且一直阻塞 作为一种解决方法 我可以使用 select 作为超时来执行 while 循环 如果
  • 如何将后台作业的输出分配给 bash 变量?

    我想在 bash 中运行后台作业并将其结果分配给一个变量 我不喜欢使用临时文件 并且希望同时运行多个类似的后台任务 root root var echo hello world root root echo var hello world
  • 在 Linux 上访问 main 之外的主要参数

    是否可以访问参数main在外面main 即在共享库构造函数中 在 Linux 上除了通过解析之外 proc self cmdline 您可以通过将构造函数放入 init array部分 功能在 init array 不像 init 使用相同
  • 如何访问 mmaped /dev/mem 而不导致 Linux 内核崩溃?

    我有一个简单的程序 尝试访问用户空间中的物理内存 其中内核存储第一个结构页 在 64 位机器上 该地址是 内核虚拟地址 ffffea0000000000 物理地址 0000620000000000 我正在尝试通过用户空间中的 mmap 访问
  • 从 Python 访问 802.11 无线管理帧

    我想从 Linux 上的 Python 嗅探 802 11 管理 探测请求 帧 这可以从 Scapy 中实现 如下所示 coding utf 8 from scapy all import def proc p if p haslayer
  • 错误:命令“c++”失败,退出状态为 1

    所以我尝试按照以下说明安装 Pyv8https andrewwilkinson wordpress com 2012 01 23 integrating python and javascript with pyv8 https andre
  • 使用 gcc 理解共享库

    我试图理解 C 中共享库的以下行为 机器一 cat one c include
  • 如何设置Java线程的CPU核心亲和力?

    我搜索了以前关于类似主题的帖子 但找不到合适的答案 因此提出这个问题 非常感谢您帮助回答 我知道在 Linux 中通过任务集命令设置进程与特定 CPU 核心的关联性 但我想设置 Java 线程与特定 cpu 核心的亲和力 以便属于同一进程的
  • 用于读取文件的 Bash 脚本

    不知道为什么最后一行没有从脚本中删除 bin bash FILENAME 1 while read line do cut d f2 echo line done lt FILENAME cat file 1 test 2 test 3 t
  • 如何在 Linux/OS X 上温和地终止 Firefox 进程

    我正在使用 Firefox 进行一些自动化操作 尽管我可以从 shell 打开 Firefox 窗口 但我无法正确终止它 如果我kill火狐进程与kill 3 or kill 2当我下次打开新的 Firefox 窗口时 命令会询问我是否要在
  • SMP 上如何处理中断?

    SMP 对称多处理器 多核 机器上如何处理中断 内存管理单元是只有一个还是多个 假设两个线程 A 和 B 运行在不同的内核上 同时 访问页表中不存在的内存页面 在这种情况下 将会出现页面错误 并从内存中引入新页面 将会发生的事件的顺序是什么
  • 运行 shell 命令并将输出发送到文件?

    我需要能够通过 php 脚本修改我的 openvpn 身份验证文件 我已将我的 http 用户设置为免通 sudoer 因为这台机器仅在我的家庭网络中可用 我目前有以下命令 echo shell exec sudo echo usernam
  • 如何在特定的Java版本上运行应用程序?

    如何运行具有特定 Java 版本的应用程序 我安装了三个 Java 版本 myuser mysystem sudo update alternatives config java There are 3 choices for the al
  • 了解 Linux oom-killer 日志

    我的应用程序被 oom killer 杀死了 它是在实时 USB 上运行的 Ubuntu 11 10 无需交换 PC 具有 1 Gig 的 RAM 唯一运行的应用程序 除了所有内置的 Ubuntu 东西 是我的程序 flasherav 请注
  • pthread_self() 返回的线程 ID 与调用 gettid(2) 返回的内核线程 ID 不同

    这句话来自于pthread self 的手册页 http linux die net man 3 pthread self 那么 我应该根据什么来决定是否应该使用pthread self or gettid确定哪个线程正在运行该函数 两者都
  • 查找并删除超过 x 天的文件或文件夹

    我想删除超过 7 天的文件和文件夹 所以我尝试了 17 07 14 email protected cdn cgi l email protection find tmp mindepth 1 maxdepth 1 ctime 7 exec
  • 如何指定配置脚本的包含目录

    我的工作场所有一个 Linux 系统 其中包含相当旧的软件包 并且没有 root 访问权限 我正在从源代码编译我需要的包 prefix somewhere in homedir 我的问题是我只是不知道如何说服配置在特定目录中查找头文件 源码
  • Unix 中的访问时间是多少

    我想知道访问时间是多少 我在网上搜索但得到了相同的定义 读 被改变 我知道与touch我们可以改变它 谁能用一个例子来解释一下它是如何改变的 有没有办法在unix中获取创建日期 时间 stat结构 The stat 2 结构跟踪所有文件日期
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判

随机推荐

  • vue高级特性

    Vue是一款流行的JavaScript框架 它可以帮助我们构建高效 可维护的Web应用程序 本篇文章中 我将给大家分享三个Vue的高级技术 并且详细地讲解它们的实现原理 动态组件 动态组件是Vue中非常有用的一项功能 它允许我们在不同的组件
  • 07:STM32----ADC模数转化器

    目录 1 简历 2 逐次逼近型ADC 3 ADC基本结构 4 输入通道 5 规则组的4种转换模式 1 单次转化 非扫描模式 2 连续转化 非扫描模式 3 单次转化 扫描模式 4 单次转化 扫描模式 6 触发控制 7 数据对齐 8 转化时间
  • Unity面试题:热更新篇

    请简要介绍Unity热更新的原理和实现方式 答 Unity热更新的原理是通过将游戏的资源和代码分离 将代码部分放置在服务器端 游戏启动时通过网络下载更新的代码并动态加载 以达到实现热更新的目的 实现方式包括AssetBundle ILRun
  • 查看是否有主键_详解MySQL数据库主键信息及无主键表

    概述 总结一下MySQL数据库查看无主键表的一些sql 一起来看看吧 1 查看表主键信息 查看表主键信息 SELECT t TABLE NAME t CONSTRAINT TYPE c COLUMN NAME c ORDINAL POSIT
  • 弱网测试出现的问题解决思路

    摘自弱网测试时碰到的问题和解决方案再加上自己的一些遇到的解决 1 没进入到后台 可以在前端请求开始时候加个定时器 在请求完毕 或者一定时间 删除定时器 2 现象 用户登录应用时下载初始化数据 下载过程中因网速太慢点击取消并重新登录 数据初始
  • Pytorch 基础之张量索引

    本次将介绍一下 Tensor 张量常用的索引与切片的方法 1 index 索引 index 索引值表示相应维度值的对应索引 a torch rand 4 3 28 28 print a 0 shape 返回维度一的第 0 索引 tensor
  • jfinal-admin 后台框架永久开源

    jfinal admin 是什么 jfinal admin是一个基于jfinal的后台管理开发框架 能帮助你使用很少的时间和代码量开发出功能完备的管理后台 最新代码请切换到 develop 分支 集组织机构管理 用户管理 角色管理 菜单管理
  • C语言【判断一个整数是否为素数】

    include
  • U-Boot命令大全(功能参数及用法)

    本文转载至 http www cnblogs com farsight2011 p 3301126 html U Boot上电启动后 按任意键可以退出自动启动状态 进入命令行 U Boot 2010 03 Sep 25 2011 16 18
  • NZ系列工具NZ02:VBA读取PDF使用说明

    分享成果 随喜正能量 时光绽放并蒂莲 更是一份殷殷嘱托 更是一份诚挚祝福 是一份时光馈赠 又是一份时光陪伴 我的教程一共九套及VBA汉英手册一部 分为初级 中级 高级三大部分 是对VBA的系统讲解 从简单的入门 到数据库 到字典 到高级的网
  • Java学习日记10——Java中的变量及其传递

    Java学习日记10 变量及其传递 引用类型和基本类型变量的传递区别 变量的定义在前面已经讲解过了 点击这里 可以查看原文 这里的分类会略微不通过与之前 这里的变量主要分为字段变量和局部变量 1 在存储角度来看 字段变量是对象的一部分 存放
  • 【K8S】kubernetes集群架构与组件

    文章目录 K8S kubernetes集群架构与组件 kubernetes 组件 master组件 node组件 整体流程 POD终止过程 K8S kubernetes集群架构与组件 kubernetes 组件 K8S是属于主从设备模型 M
  • 华为OD机试真题 Java 实现【记票统计】【牛客练习题】

    一 题目描述 请实现一个计票统计系统 你会收到很多投票 其中有合法的也有不合法的 请统计每个候选人得票的数量以及不合法的票数 注 不合法的投票指的是投票的名字不存在n个候选人的名字中 数据范围 每组输入中候选人数量满足 1 n 100 总票
  • 一个将字符串转驼峰式的函数

    function camelCase str return str split map v gt v replace b w g function fl return fl toUpperCase jion camelCase hello
  • MediaScannerService研究

    2019独角兽企业重金招聘Python工程师标准 gt gt gt MediaScannerService研究 侯 亮 本文以Android 5 1为准 1 概述 MediaScannerService是Android平台提供的一个用于扫描
  • 通过navigator判断运行环境

    一 Navigator是什么 Navigator 对象包含有关浏览器的信息 二 参数 1 用户代理 navigator userAgent 用户代理 Mozilla 5 0 Windows NT 10 0 WOW64 AppleWebKit
  • eggjs&sequelize使用教程一(环境搭建)

    前言 原来想写express sequelize的 但是公司现在放弃了express 转战eggjs 所以这个的教程就以egg为基础 安装egg 官方有完整的教程 需要安装的模块 package js zengwe zengwe PC eg
  • 关于activiti流程通过、驳回、会签、转办、中止、挂起等核心操作功能的封装

    package com famousPro process service impl import java util ArrayList import java util HashMap import java util List imp
  • linux内网穿透(内外网服务器端口映射)

    1 安装sshpass CentOS7 rpm ivh sshpass 1 06 1 el7 x86 64 rpm 若内网无法连接网络 可下载后 在上传至内网服务器 下载地址 https centos pkgs org 7 epel x86
  • Linux学习第11天:字符设备驱动开发:一字一符总见情

    本文是驱动开发的第一篇笔记 主要内容是字符设备驱动开发最基础的内容 主要包括字符设备的概念 开发步骤以及一个十分重要的概念 设备号 其思维导图能简单的显示本文的基本框架 如下 一 字符设备 字符设备就是一个一个字节 按照字节流进行读写操作的