ARM_Linux驱动开发——字符设备驱动开发(上)

news2024/9/27 4:39:24

 

目录

一、Linux驱动开发思维

二、Linux驱动开发分类

三、“ ARM_Linux驱动开发——字符设备驱动开发 ”

字符设备驱动简介


前言

在分享Linux驱动开发之前,我想带大家首先回顾一下裸机驱动开发和Linux驱动开发的区别。

1、运行环境和操作系统:

裸机驱动开发:在裸机开发中,通常是针对没有操作系统支持的嵌入式系统或特定的硬件平台开发驱动程序。这些系统通常直接操作硬件资源,没有操作系统的抽象层。

Linux驱动开发:Linux驱动开发则是针对运行Linux操作系统的计算机或嵌入式系统开发。Linux作为一个开源操作系统,提供了广泛的设备支持和抽象接口,开发者可以利用Linux内核提供的接口来开发设备驱动。

2、开发流程和工具链:

裸机驱动开发:开发者需要了解硬件的具体细节,通常使用特定的开发工具链(如ARM Cortex-M系列开发可以使用Keil、IAR等),编写底层的驱动代码,直接操作硬件寄存器和控制器。

Linux驱动开发:需要熟悉Linux内核的架构和API,使用C语言或者特定的Linux设备驱动框架(如Platform Driver、USB Driver等)进行开发。Linux提供了丰富的设备驱动开发文档和示例代码,以及调试工具。

3、硬件抽象层和接口标准化:

裸机驱动开发:由于没有操作系统提供的标准接口,开发者需要自行处理硬件之间的通信和资源管理。每种硬件平台的驱动开发可能具有很高的定制性和特定性。

Linux驱动开发:Linux内核提供了一套标准的设备驱动开发框架和API,开发者可以利用这些框架来开发驱动,这样的驱动通常更具有通用性和可移植性。

4、调试和测试:

裸机驱动开发:调试通常需要通过硬件调试器或者仿真器进行,对于实际硬件的测试需要特定的硬件平台。

Linux驱动开发:Linux内核提供了丰富的调试工具和接口,如printk日志、sysfs接口等,同时也可以使用标准的Linux调试工具(如gdb、strace等)来进行驱动调试和性能分析。

总之,裸机驱动开发更加依赖于具体的硬件平台和细节,开发的驱动程序更加定制化和特定化;而Linux驱动开发则更多依赖于操作系统提供的标准接口和抽象层,开发的驱动程序具有更好的可移植性和通用性。 

一、Linux驱动开发思维

1、首先需要跳出曾经的裸机开发思维,因为Linux下的驱动开发直接操作寄存器已经不现实了;

2、开发者需要根据Linux下的各种驱动框架进行开发。即必须满足驱动开发的框架;

3、驱动最终的执行形式就是:/dev/xxx文件、open、close、write、read……

4、新的驱动支持设备树,这是一个.dts文件,此文件描述的是设备信息。


二、Linux驱动开发分类

Linux驱动开发可以按照不同的分类进行归类,主要包括以下几类:

1、字符设备驱动(Character Device Drivers):

这类驱动程序处理以字符流方式进行数据传输的设备,如串口、终端、声音卡等。通常通过文件操作接口(open, read, write, close)来与用户空间进行通信。

2、块设备驱动(Block Device Drivers):

这类驱动程序用于管理块设备,如硬盘、闪存存储器等,它们以固定大小的块为单位进行数据传输。块设备驱动通常需要实现块设备的缓存、IO调度等功能。

3、网络设备驱动(Network Device Drivers):

网络设备驱动用于控制网络接口卡(NIC),如以太网卡。这类驱动程序处理网络数据包的收发、协议栈的处理等。

4、USB设备驱动(USB Device Drivers):

USB设备驱动用于控制连接到Linux系统的USB设备,如USB存储设备、USB网卡等。这类驱动程序需要处理USB协议栈、设备的插拔事件等。

5、文件系统驱动(Filesystem Drivers):

文件系统驱动用于支持特定类型的文件系统,如ext4、NTFS等。这类驱动程序负责管理存储设备上的文件和目录结构。

6、总线设备驱动(Bus Drivers):

总线设备驱动用于管理系统总线,如PCI总线、SPI总线、I2C总线等。这类驱动程序负责枚举、初始化和管理连接到总线上的设备。

7、平台设备驱动(Platform Drivers):

平台设备驱动用于支持特定硬件平台上的设备,如嵌入式系统中的特定传感器、LED控制器等。

8、虚拟设备驱动(Virtual Device Drivers):

这类驱动程序不与物理硬件设备直接交互,而是创建虚拟设备,如虚拟网卡、虚拟磁盘等。

9、字符驱动和块驱动的子类:

这些驱动可能根据设备的特定需求进一步分类,例如音频设备驱动、输入设备驱动(键盘、鼠标)、显示设备驱动等。

Linux驱动开发涵盖了广泛的设备类型和功能,开发者根据具体的设备类型选择适合的驱动开发模块和接口。

三、“ ARM_Linux驱动开发——字符设备驱动开发 ”


字符设备驱动简介

字符设备就是一个一个字节,按照字节流来进行读写操作的设备,读写数据是分先后顺序的。常见的比如点灯、IIC、ISP……都是字符操作的设备,对于这些设备的驱动就叫做字符设备驱动。

了解字符设备驱动架构之前,我们可以先来看一下Linux下的应用程序是如何调用驱动程序的:

在Linux中,一切皆为文件。要实现对硬件的操作,需要应用程序对名为"/dev/xxx"的文件将进行操作。这个文件是由驱动加载成功后,会在"/dev"目录下生成相应的文件。

举一个简单的例子:如果你要操作点亮一个灯,你就可以使用open函数打开"/dev/Led"文件,使用完成以后用close函数关闭"/dev/Led"这个文件。需要点亮灯的话,则使用函数write函数来操作,即向此驱动写入数据,这个数据就是决定是否打开灯。如果要获取Led灯的状态,则使用read函数来从驱动中读取相应的状态。

应用程序是运行在用户空间,但是Linux驱动属于内核的一部分,所以驱动运行在内核空间。这样的话问题就来了,如果用户要直接对内核进行操作,直接通过用户空间来操作可行吗?

答案肯定是不行的!

用户空间是不能直接对内核进行操作的,他需要找一个中间人,这个中间人就是通过Linux驱动函数。即使用"系统调用"的方法来实现用户空间“侵入”到内核空间,这样才能实现对底层驱动的操作。

上面提到的open、close、write、read等这些驱动操作函数,都是由C库提供的。在Linux中,系统调用作为C库的一部分。

例如:调用open函数的时候流程如下:

(应用程序)step1:应用调用open()函数 ——> (C库)step2:C库中的open()函数 ——> (内核)step3:open()系统调用 ——> (具体驱动)step4: 驱动的open()函数

图片

那问题又来了,应用程序和具体的驱动又是如何联系起来的呢?

通过上面的讲解,我们能初步了解到应用程序使用到的函数在具体驱动程序中都有与之对应的函数, 比如应用程序中调用了 open 这个函数,那么在驱动程序中也得有一个名为 open 的函数。每一个系统调用,在驱动中都有与之对应的一个驱动函数,在 Linux 内核文件 include/linux/fs.h 中有个叫做 file_operations 的结构体,此结构体就是 Linux 内核驱动操作函数集合。

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	int (*iopoll)(struct kiocb *kiocb, bool spin);
	int (*iterate) (struct file *, struct dir_context *);
	int (*iterate_shared) (struct file *, struct dir_context *);
	__poll_t (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	unsigned long mmap_supported_flags;
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **, void **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
	unsigned (*mmap_capabilities)(struct file *);
#endif
	ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
			loff_t, size_t, unsigned int);
	loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
				   struct file *file_out, loff_t pos_out,
				   loff_t len, unsigned int remap_flags);
	int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;

下面我们对内核驱动操作函数进行初步解释:

  1. llseek:

    • 定义:文件定位函数,用于改变文件的读写位置。

    • 参数:struct file * 文件指针,loff_t 偏移量,int 偏移基准。

    • 返回值:loff_t 新的文件位置。

  2. read:

    • 定义:读取文件内容到用户空间。

    • 参数:struct file * 文件指针,char __user * 用户空间缓冲区,size_t 请求读取的字节数,loff_t * 读取位置的指针。

    • 返回值:ssize_t 实际读取的字节数,错误时返回负值。

  3. write:

    • 定义:将用户空间的数据写入文件。

    • 参数:struct file * 文件指针,const char __user * 用户空间缓冲区,size_t 请求写入的字节数,loff_t * 写入位置的指针。

    • 返回值:ssize_t 实际写入的字节数,错误时返回负值。

  4. read_iter:

    • 定义:迭代式地从文件读取数据到用户空间。

    • 参数:struct kiocb * 异步IO控制块,struct iov_iter * 数据迭代器。

    • 返回值:ssize_t 实际读取的字节数。

  5. write_iter:

    • 定义:迭代式地将用户空间的数据写入文件。

    • 参数:struct kiocb * 异步IO控制块,struct iov_iter * 数据迭代器。

    • 返回值:ssize_t 实际写入的字节数。

  6. iopoll:

    • 定义:用于异步IO中的轮询操作。

    • 参数:struct kiocb * 异步IO控制块,bool 是否自旋。

    • 返回值:int 操作结果。

  7. iterate:

    • 定义:在目录中迭代项。

    • 参数:struct file * 目录文件指针,struct dir_context * 目录上下文。

    • 返回值:int 操作结果。

  8. iterate_shared:

    • 定义:在共享目录中迭代项。

    • 参数:struct file * 目录文件指针,struct dir_context * 目录上下文。

    • 返回值:int 操作结果。

  9. poll:

    • 定义:注册文件的poll/epoll事件。

    • 参数:struct file * 文件指针,struct poll_table_struct * poll表。

    • 返回值:__poll_t 事件掩码。

关于字符设备驱动开发步骤,敬请关注下文更新——《ARM_Linux驱动开发——字符设备驱动开发(下)》!

 

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

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

相关文章

淘宝扭蛋机小程序:互联网下的潮玩新增速

近些年,潮玩成为了年轻一代的新宠,吸引了无数的年轻消费者,尤其是扭蛋机行业!扭蛋机具有价格低、商品丰富等特点,性价比非常高,受众群体遍布到了各个年龄层。扭蛋机商品具有非常高的观赏性和收藏性&#xf…

C语言学习笔记[23]:循环语句while①

C语言除了顺序结构和选择结构还有循环结构 whilefordo...while while循环 //while 语法结构 while(表达式)循环语句; 表达式的结果为真&#xff0c;则执行循环语句&#xff0c;否则循环停止 例如&#xff1a;打印1~10 #include <stdio.h>int main() {int i 1;whil…

浅析文件如何生成二维码,以及文件二维码的广泛应用

随着智能手机的普及和移动互联网的飞速发展&#xff0c;二维码已经深入到人们生活的各个领域&#xff0c;为人们的生活带来了极大的便利。文件二维码具有信息容量大、编码范围广、容错能力强、译码可靠性高、可引入加密措施、成本低、易制作、持久耐用等优点。因此&#xff0c;…

L2 LangGraph_Components

参考自https://www.deeplearning.ai/short-courses/ai-agents-in-langgraph&#xff0c;以下为代码的实现。 这里用LangGraph把L1的ReAct_Agent实现&#xff0c;可以看出用LangGraph流程化了很多。 LangGraph Components import os from dotenv import load_dotenv, find_do…

uniapp微信小程序分享教程

文章目录 导文当前页面未设置分享&#xff1f;配置在代码中开启分享转发按钮 点击按钮转发怎么写微信小程序转发官网文档地址&#xff1a;uniapp转发官网文档地址&#xff1a; 导文 uniapp 微信小程序 当前页面未设置分享&#xff1f; uniapp 微信小程序分享到好友怎么写&#…

力扣-排序算法

排序算法&#xff0c;一般都可以使用std&#xff1a;&#xff1a;sort&#xff08;&#xff09;来快速排序。 这里介绍一些相关的算法&#xff0c;巩固记忆。 快速排序 跟二分查找有一丢丢像。 首先选择一个基准元素&#xff0c;一般就直接选择第一个。然后两个指针&#xff0c…

绝区玖--人工智能物料清单 (AI BOM)

前言 AI BOM 涵盖了从输入模型的数据到为模型提供支持的基础设施以及将 AI 从概念转化为生产的过程的一切。 但为什么我们需要人工智能物料清单&#xff1f;答案在于当今世界人工智能/Gen AI系统的复杂性和关键性&#xff1a; 透明度和可重复性&#xff1a;AI BOM 提供所有组件…

MES系统在装备制造行业核心应用场景介绍

MES软件在企业中有着广泛的应用场景&#xff0c;主要包括生产计划排程、生产过程监控、质量管理、设备管理、库存管理、数据分析等领域。 通过实时监控生产过程、收集数据、进行分析&#xff0c;MES软件可以帮助企业实现生产过程可视化、透明化&#xff0c;提高生产效率&#…

开源项目有哪些机遇与挑战

目录 1.概述 2.开源项目的发展趋势 2.1. 开源项目的发展现状 2.2. 开源社区的活跃度 2.3. 开源项目在技术创新中的作用 3.参与开源的经验分享 3.1. 选择开源项目 3.2. 理解项目结构和文档 3.3. 贡献代码 3.4. 与开源社区的合作 3.5. 学习和成长 4.开源项目的挑战 …

CSS【详解】文本相关样式(含 font 系列样式,文本颜色 color,三种颜色表示法,文本排版-含最佳实战范例,文本装饰,分散对齐,渐变色文本等)

文本风格 font-style font-style:italic 值描述normal默认值。浏览器显示一个标准的字体样式。italic加载对应字体的斜体字体文件&#xff0c;若找不到斜体字体文件&#xff0c;则进行物理上的倾斜。 标签默认font-style:italicoblique浏览器会显示一个倾斜的字体样式。 文本粗…

华为HCIP Datacom H12-821 卷33

1.判断题 缺省情况下&#xff0c;华为AR路由器的VRRP运行在抢占模式下 A、对 B、错 正确答案&#xff1a; A 解析&#xff1a; 无 2.判断题 一个Route-Policy下可以有多个节点&#xff0c;不同的节点号用节点号标识&#xff0c;不同节点之间的关系是"或"的关…

什么是 C 语言中的宏定义?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; &#x1f4d9;C 语言百万年薪修炼课程 通俗易懂&#xff0c;深入浅出&#xff0c;匠心打磨&#xff0c;死磕细节&#xff0c;6年迭代&#xff0c;看过的人都说好。 文章目…

告别缓慢下载,Cloudflare带你体验极速Docker镜像加速

背景 国内的Docker镜像服务似乎突然进入了寒冬&#xff0c;不仅Docker镜像服务受到了影响&#xff0c;连NPM镜像也可能面临下架的风险。这对依赖这些服务的开发者们来说&#xff0c;无疑是一个不小的困扰。 近日&#xff0c;SJTUG&#xff08;上海交通大学Linux用户组&#x…

Apache Hadoop之历史服务器日志聚集配置

上篇介绍了Apache Hadoop的分布式集群环境搭建&#xff0c;并测试了MapReduce分布式计算案例。但集群历史做了哪些任务&#xff0c;任务执行日志等信息还需要配置历史服务器和日志聚集才能更好的查看。 配置历史服务器 在Yarn中运行的任务产生的日志数据不能查看&#xff0c;…

30. 01背包问题 二维,01背包问题 一维,416.分割等和子集

背包问题分类&#xff1a; 1、确定dp数组以及下标的含义对于背包问题&#xff0c;有一种写法&#xff0c; 是使用二维数组&#xff0c;即dp[i][j] 表示从下标为[0-i]的物品里任意取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大是多少。2、确定递推公式&#xff0c;…

硅谷甄选二(登录)

一、登录路由静态组件 src\views\login\index.vue <template><div class"login_container"><!-- Layout 布局 --><el-row><el-col :span"12" :xs"0"></el-col><el-col :span"12" :xs"2…

Qt基础控件总结—多页面切换(QStackWidget类、QTabBar类和QTabWidget类)

QStackedWidget 类 QStackedWidget 类是在 QStackedLayout 之上构造的一个便利的部件,其使用方法与步骤和 QStackedLayout 是一样的。QStackedWidget 类的成员函数与 QStackedLayout 类也基本上是一致的,使用该类就和使用 QStackedLayout 一样。 使用该类可以参考QStackedL…

施罗德数列SQL实现

在组合数学中,施罗德数用来描述从(0,0)到(n,n)的格路中,只能使用(1,0)、(0,1)、(1,1)三种移动方式,始终位于对角线下方且不越过对角线的路径数 DECLARE n INT 10 DECLARE i INT DECLARE rst INT DECLARE old INT1CREATE TABLE #rst (i INT ,rst int )INSERT INTO #rst values(…

Python 中创建当前日期和时间的文件名技巧详解

概要 在日常开发中,经常需要创建带有当前日期和时间的文件名,以便进行日志记录、数据备份或版本控制等操作。Python 提供了丰富的库和函数,可以方便地获取当前日期和时间,并将其格式化为字符串,用于生成文件名。本文将详细介绍如何使用 Python 创建带有当前日期和时间的文…

springboot大学生竞赛管理系统-计算机毕业设计源码37276

摘 要 随着教育信息化的不断发展&#xff0c;大学生竞赛已成为高校教育的重要组成部分。传统的竞赛组织和管理方式存在着诸多问题&#xff0c;如信息不透明、效率低下、管理不便等。为了解决这些问题&#xff0c;提高竞赛组织和管理效率&#xff0c;本文设计并实现了一个基于Sp…