【Linux-驱动开发】

Linux-驱动开发

  • ■ Linux-应用程序对驱动程序的调用流程
  • ■ Linux-file_operations 结构体
  • ■ Linux-驱动模块的加载和卸载
    • ■ 1. 驱动编译进 Linux 内核中
    • ■ 2. 驱动编译成模块(Linux 下模块扩展名为.ko)
  • ■ Linux-
  • ■ Linux-
  • ■ Linux-设备号
    • ■ Linux-设备号-分配
      • ■ 静态分配设备号
      • ■ 动态分配设备号
  • ■ Linux-驱动分类
    • ■ 字符设备:
      • ■ 字符设备-注册与注销函数
      • ■ 字符设备-具体操作函数
      • ■ 字符设备-LICENSE 和作者信息
      • ■ 示例一:

■ Linux-应用程序对驱动程序的调用流程

在这里插入图片描述
在这里插入图片描述

■ Linux-file_operations 结构体

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

1588 struct file_operations {
1589 struct module *owner;        // 拥有该结构体的模块的指针,一般设置为 THIS_MODULE
1590 loff_t (*llseek) (struct file *, loff_t, int);  //llseek 函数用于修改文件当前的读写位置。
1591 ssize_t (*read) (struct file *, char __user *, size_t, loff_t*);  // read 函数用于读取设备文件。
1592 ssize_t (*write) (struct file *, const char __user *, size_t,loff_t *); //write 函数用于向设备文件写入(发送)数据。
1593 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
1594 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
1595 int (*iterate) (struct file *, struct dir_context *);
1596 unsigned int (*poll) (struct file *, struct poll_table_struct*);  //是个轮询函数,用于查询设备是否可以进行非阻塞的读写。
1597 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //unlocked_ioctl 函数提供对于设备的控制功能,与应用程序中的 ioctl 函数对应。
1598 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //compat_ioctl 函数与 unlocked_ioctl 函数功能一样,区别在于在 64 位系统上,
32 位的应用程序调用将会使用此函数。在 32 位的系统上运行 32 位的应用程序调用的是
unlocked_ioctl。
1599 int (*mmap) (struct file *, struct vm_area_struct *); //mmap 函数用于将设备的内存映射到进程空间中(也就是用户空间),一般帧缓
冲设备会使用此函数,比如 LCD 驱动的显存,将帧缓冲(LCD 显存)映射到用户空间中以后应用
程序就可以直接操作显存了,这样就不用在用户空间和内核空间之间来回复制。
1600 int (*mremap)(struct file *, struct vm_area_struct *);
1601 int (*open) (struct inode *, struct file *); //open 函数用于打开设备文件。
1602 int (*flush) (struct file *, fl_owner_t id);
1603 int (*release) (struct inode *, struct file *); //release 函数用于释放(关闭)设备文件,与应用程序中的 close 函数对应。
1604 int (*fsync) (struct file *, loff_t, loff_t, int datasync); //fasync 函数用于刷新待处理的数据,用于将缓冲区中的数据刷新到磁盘中
1605 int (*aio_fsync) (struct kiocb *, int datasync); //aio_fsync 函数与 fasync 函数的功能类似,只是 aio_fsync 是异步刷新待处理的
数据。
1606 int (*fasync) (int, struct file *, int);
1607 int (*lock) (struct file *, int, struct file_lock *);
1608 ssize_t (*sendpage) (struct file *, struct page *, int, size_t,loff_t *, int);
1609 unsigned long (*get_unmapped_area)(struct file *, unsigned long,unsigned long, unsigned long, unsigned long);
1610 int (*check_flags)(int);
1611 int (*flock) (struct file *, int, struct file_lock *);
1612 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,loff_t *, size_t, unsigned int);
1613 ssize_t (*splice_read)(struct file *, loff_t *, structpipe_inode_info *, size_t, unsigned int);
1614 int (*setlease)(struct file *, long, struct file_lock **, void**);
1615 long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
1617 void (*show_fdinfo)(struct seq_file *m, struct file *f);
1618 #ifndef CONFIG_MMU
1619 	unsigned (*mmap_capabilities)(struct file *);
1620 #endif
1621 };
序号描述
1驱动加载成功以后会在“/dev”目录下生成一个相应的文件
2比如现在有个叫做/dev/led 的驱动文件,此文件是 led 灯的驱动文件。应用程序使用 open 函数来打开文件/dev/led,使用完成以后使用close 函数关闭/dev/led 这 个文件。 open和 close 就是打开和关闭 led 驱动的函数,如果要点亮或关闭 led
3应用程序运行在用户空间,而 Linux 驱动属于内核的一部分,因此驱动运行于内核空间
4
5
6
7
8

■ Linux-驱动模块的加载和卸载

■ 1. 驱动编译进 Linux 内核中

这样当 Linux 内核启动的时候就会自动运行驱动程序。

■ 2. 驱动编译成模块(Linux 下模块扩展名为.ko)

在Linux 内核启动以后使用“insmod”命令加载驱动模块。在调试驱动的时候一般都选择将其编译为模块,这样我们修改驱动以后只需要编译一下驱动代码即可,不需要编译整个 Linux 代码。

module_init(xxx_init); //注册模块加载函数 当使用“insmod”命令加载驱动的时候, xxx_init 这个函数就会被调用
module_exit(xxx_exit); //注册模块卸载函数 当使用“rmmod”命令卸载具体驱动的时候, xxx_exit 函数就会被调用。

示例一:
在这里插入图片描述
第15行,调用函数module_init 来声明 xxx_init 为驱动入口函数,当加载驱动的时候 xxx_init函数就会被调用。
第16行,调用函数module_exit来声明xxx_exit为驱动出口函数,当卸载驱动的时候xxx_exit函数就会被调用。

关键字功能作用说明
加载驱动insmodinsmod 是最简单的模块加载命令 例如 insmod drv.ko ,
insmod 命令不能解决模块的依赖关系,
比如 drv.ko 依赖 first.ko 这个模块,就必须先使用insmod 命令加载 first.ko 这个模块,然后再加载 drv.ko 这个模块。
加载驱动modprobemodprobe 会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中,
因此modprobe 命令相比 insmod 要智能一些。
推荐使用 modprobe 命令来加载驱动。
modprobe 命令默认会去/lib/modules/目录中查找模块,
卸载驱动modprobe -r例如 modprobe -r drv.ko
使用 modprobe 命令可以卸载掉驱动模块所依赖的其他模块,前提是这些依赖模块已经没有被其他模块所使用,否则就不能使用 modprobe 来卸载驱动模块。
卸载驱动rmmod例如 rmmod drv.ko
推荐使用 rmmod 命令。

■ Linux-

■ Linux-

■ Linux-设备号

Linux 中每个设备都有一个设备号,设备号由主设备号和次设备号两部分组成,
主设备号表示某一个具体的驱动,
次设备号表示使用这个驱动的各个设备。
dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。高 12 位为主设备号, 低 20 位为次设备号。

typedef unsigned int __u32;      
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;   dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。高 12 位为主设备号, 低 20 位为次设备号。

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

#define MINORBITS 20       宏 MINORBITS 表示次设备号位数,一共是 20 位。
#define MINORMASK ((1U << MINORBITS) - 1)         宏 MINORMASK 表示次设备号掩码。
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))  宏 MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))  宏 MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))   宏 MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号。

■ Linux-设备号-分配

■ 静态分配设备号

具体分配的内容可以查看文档 Documentation/devices.txt。
看硬件平台运行过程中有没有使用这个主设备号,使用“cat /proc/devices” 命令即可查看当前系统中所有已经使用了的设备号。

■ 动态分配设备号

静态分配设备号很容易带来冲突问题, Linux 社区推荐使用动态分配设备号,在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)  //用于申请设备号,dev:保存申请到的设备号。baseminor: 次设备号起始地址, alloc_chrdev_region 可以申请一段连续的多个设备号,这些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递增。一般 baseminor 为 0,也就是说次设备号从 0 开始。count: 要申请的设备号数量。name:设备名字。void unregister_chrdev_region(dev_t from, unsigned count)     //设备号释放函数from:要释放的设备号。count: 表示从 from 开始,要释放的设备号数量。

■ Linux-驱动分类

■ 字符设备:

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

■ 字符设备-注册与注销函数

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)major: 主设备号,
name:设备名字,指向一串字符串。
fops: 结构体 file_operations 类型指针,指向设备的操作函数集合变量。

■ 字符设备-具体操作函数

打开
关闭

写 操作

■ 字符设备-LICENSE 和作者信息

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

■ 示例一:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>#define CHRDEVBASE_MAJOR      200           //主设备号
#define CHRDEVBASE_NAME     "chrdevbase"    //名字static char readbuf[100]; /*读缓冲 */
static char writebuf[100];  /* 写缓冲 */
static char kerneldata[] = {"kernel data!"};static int chrdevbase_open(struct inode *inode, struct file *filp)
{// printk("chrdevbase_open\r\n");return 0;
}static int chrdevbase_release(struct inode *inode, struct file *filp)
{// printk("chrdevbase_release\r\n");return 0;   
}static ssize_t chrdevbase_read(struct file *filp, __user char *buf, size_t count,loff_t *ppos)
{ int ret  = 0;//printk("chrdevbase_read\r\n");memcpy(readbuf, kerneldata, sizeof(kerneldata));ret = copy_to_user(buf, readbuf, count);if(ret == 0) {} else {}return 0;  
}static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{int ret = 0;//printk("chrdevbase_write\r\n");ret = copy_from_user(writebuf, buf, count);if(ret == 0) {printk("kernel recevdata:%s\r\n", writebuf);} else {}return 0; 
}/** 字符设备 操作集合*/
static struct file_operations chrdevbase_fops={.owner = THIS_MODULE,.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write,
};static int __init chrdevbase_init(void)
{int ret = 0;printk("chrdevbase_init\r\n");/* 注册字符设备 */ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(ret < 0) {printk("chrdevbase init failed!\r\n");}return 0;
}static void __exit chrdevbase_exit(void)
{printk("chrdevbase_exit\r\n");	/* 注销字符设备 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
}/*模块入口与出口
*/
module_init(chrdevbase_init);  /* 入口 */
module_exit(chrdevbase_exit);  /* 出口 */MODULE_LICENSE("GPL");      
MODULE_AUTHOR("zuozhongkai");

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

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

相关文章

家电维修上门维修小程序怎么搭建制作?

​在家庭生活中&#xff0c;家电的维修问题一直是人们关注的焦点。随着微信小程序的普及&#xff0c;家电维修服务行业也迎来了线上转型的机遇。一款便捷、高效的家电维修上门维修小程序&#xff0c;不仅能为维修服务商带来新的客户&#xff0c;也能为用户带来更便捷的服务体验…

[Algorithm][动态规划][路径问题][下降路径最小和][最小路径和][地下城游戏]详细讲解

目录 1.下降路径最小和1.题目链接2.算法原理详解3.代码实现 2.最小路径和1.题目链接2.算法原理详解3.代码实现 3.地下城游戏1.题目链接2.算法原理详解3.代码实现 1.下降路径最小和 1.题目链接 下降路径最小和 2.算法原理详解 思路&#xff1a; 确定状态表示 -> dp[i][j]的…

用WPS将多张图片生成一个pdf文档,注意参数设置

目录 1 新建一个docx格式的文档 2 向文档中插入图片 3 设置页边距 4 设置图片大小 5 导出为pdf格式 需要把十几张图片合并为一个pdf文件&#xff0c;本以为很简单&#xff0c;迅速从网上找到两个号称免费的在线工具&#xff0c;结果浪费了好几分钟时间&#xff0c;发现需要…

面试-软件工程与设计模式相关,Spring简介

面试-软件工程与设计模式相关&#xff0c;Spring简介 1.编程思想1.1 面向过程编程1.2 面向对象编程1.2.1 面向对象编程三大特征 1.3 面向切面编程1.3.1 原理1.3.2 大白话&#xff1f;1.3.3 名词解释1.3.4 实现 2. 耦合与内聚2.1 耦合性2.2 内聚性 3. 设计模式3.1 设计模型七大原…

【Nodejs-多进程之Cluster】

cluster 模块是 Node.js 提供的一个用于多进程的模块&#xff0c;它可以轻松地创建一组共享同一个服务器端口的子进程&#xff08;worker进程&#xff09;。通过使用 cluster 模块&#xff0c;可以充分利用多核系统&#xff0c;提高应用程序的性能和可靠性。 基本原理 cluste…

React开发环境配置详细讲解-04

React环境 前端随着规范化&#xff0c;可以说规范和环境插件配置满天飞&#xff0c;笔者最早接触的是jquery&#xff0c;那个开发非常简单&#xff0c;只要引入jquery就可以了&#xff0c;当时还写了一套UI框架&#xff0c;至今在做小型项目中还在使用&#xff0c;show一张效果…

一款颜值颇高的虚拟列表!差点就被埋没了,终于还是被我挖出来了

大家好&#xff0c;我是晓衡&#xff01; 今天&#xff0c;推荐一款颇有颜值的虚拟列表组件&#xff0c;不然真的被埋没就可惜了&#xff01; 我们先来看下效果&#xff1a; 感觉怎么样&#xff1f;还不错吧&#xff01; 为什么说这个资源差点被埋没呢&#xff1f;因为个朋友找…

用数据,简单点!奇点云2024 StartDT Day数智科技大会,直播见

在充满挑战的2024&#xff0c;企业如何以最小化的资源投入和试错成本&#xff0c;挖掘新的增长机会&#xff0c;实现确定性发展&#xff1f; “简单点”是当前商业环境的应对策略&#xff0c;也是奇点云2024 StartDT Day的核心理念。 5月28日&#xff0c;由奇点云主办的2024 S…

Linux —— 信号量

Linux —— 信号量 什么是信号量P操作&#xff08;Wait操作&#xff09;V操作&#xff08;Signal操作&#xff09;信号量的类型 一些接口POSIX 信号量接口&#xff1a;其他相关命令&#xff1a; 基于循环队列的生产者和消费者模型同步关系 多生产多消费 我们今天接着来学习信号…

【译】组复制和 Percona XtraDB 集群: 常见操作概述

原文地址&#xff1a;Group Replication and Percona XtraDB Cluster: Overview of Common Operations 在这篇博文中&#xff0c;我将概述使用 MySQL Group Replication 8.0.19&#xff08;又称 GR&#xff09;和 Percona XtraDB Cluster 8 (PXC)&#xff08;基于 Galera&…

Jetbrains插件AI Assistant,终于用上了

ai assistant激活成功后&#xff0c;如图 ai assistant获取&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 主要功能如下

计算机毕业设计hadoop+spark微博舆情大数据分析 微博爬虫可视化 微博数据分析 微博采集分析平台 机器学习(大屏+LSTM情感分析+爬虫)

电商数据建模 一、分析背景与目的 1.1 背景介绍 电商平台数据分析是最为典型的一个数据分析赛道&#xff0c;且电商数据分析有着比较成熟的数据分析模型&#xff0c;比如&#xff1a;人货场模型。此文中我将通过分析国内最大的电商平台——淘宝的用户行为&#xff0c;来巩固数…

算法打卡 Day13(栈与队列)-滑动窗口最大值 + 前 K 个高频元素 + 总结

文章目录 Leetcode 239-滑动窗口最大值题目描述解题思路 Leetcode 347-前 K 个高频元素题目描述解题思路 栈与队列总结 Leetcode 239-滑动窗口最大值 题目描述 https://leetcode.cn/problems/sliding-window-maximum/description/ 解题思路 在本题中我们使用自定义的单调队列…

C语言指针指针和数组笔试题(必看)

前言&#xff1a; 前面介绍了指针的大体内容&#xff0c;如果接下来能够把这些代码的含义搞得清清楚楚&#xff0c;那么你就是代码king&#xff01; 一维数组&#xff1a; int a[] {1,2,3,4}; printf("%d\n",sizeof(a)); printf("%d\n",sizeof(a0)); pr…

element-ui输入框和多行文字输入框字体不一样解决

element-ui的type"textarea"的字体样式与其他样式不同 <el-input type"textarea"></el-input> <el-input ></el-input>设置&#xff1a; .el-textarea__inner::placeholder {font-family: "Helvetica Neue", Helvetic…

删除MySQL中所有表的外键

方法一&#xff1a; 原理 查询schema中所有外键名称然后拼接生成删除语句 第一步&#xff1a; SELECT CONCAT(ALTER TABLE ,TABLE_SCHEMA,.,TABLE_NAME, DROP FOREIGN KEY ,CONSTRAINT_NAME, ;) FROM information_schema.TABLE_CONSTRAINTS c WHERE c.TABLE_SCHEMA数据库名…

Linux修炼之路之自动化构建工具,进度条,gdb调试器

目录 一&#xff1a;自动化构建工具make/makefile 生成内容&#xff1a; 清理内容&#xff1a; 对于多过程的&#xff1a; 对于多次make&#xff1a; 特殊符号&#xff1a; 二&#xff1a;小程序之进度条 三&#xff1a;git的简单介绍 四&#xff1a;Linux调试器gdb 接…

fpga 提高有什么进阶书推荐?

到FPGA中后期的时候就要开始接触&#xff0c;如&#xff1a;高速接口、光纤数字信号处理等项目实践了&#xff0c;那么我们可以读一些书进行提升&#xff0c;大家可以收藏下。 高速接口项目《嵌入式高速串行总线技术:基于FPGA实现与应用》作者&#xff1a;张锋 FPGA提升书籍推…

Go团队:Go是什么

2024年的Google I/O大会[1]如期而至。 这届大会的核心主旨毫无疑问是坚定不移的以AI为中心&#xff1a;Google先是发布了上下文长度将达到惊人的200万token的Gemini 1.5 Pro[2]&#xff0c;然后面对OpenAI GPT-4o的挑衅&#xff0c;谷歌在大会上直接甩出大杀器Project Astra[3]…

第七节 ConfigurationClassParser 源码分析

tips&#xff1a; ConfigurationClassParser 是 Springframework 中的重要类。 本章主要是源码理解&#xff0c;有难度和深度&#xff0c;也枯燥乏味&#xff0c;可以根据实际情况选择阅读。 位置&#xff1a;org.springframework.context.annotation.ConfigurationClassPars…