Linux驱动开发详细解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Linux驱动开发详细解析

Linux驱动开发详细解析

驱动概念

驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁。

  • 具体任务
  1. 读写设备寄存器(实现控制的方式)
  2. 完成设备的轮询、中断处理、DMA通信(CPU与外设通信的方式)
  3. 进行物理内存向虚拟内存的映射(在开启硬件MMU的情况下)
  • 说明:设备驱动的两个任务方向
  1. 操作硬件(向下)
  2. 将驱动程序通入内核,实现面向操作系统内核的接口内容,接口由操作系统实现(向上)
    驱动程序按照操作系统给出的独立于设备的接口设计应用程序使用操作系统统一的系统调用接口来访问设备)

Linux系统主要部分:内核、shell、文件系统、应用程序

  • 内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统
  • 分层设计的思想让程序间松耦合,有助于适配各种平台
  • 驱动的上面是系统调用下面是硬件

791ebfc135d842aebbccc4a99c2b2c16.png

驱动分类

Linux驱动分为三个基础大类:字符设备驱动,块设备驱动,网络设备驱动

  1. 字符设备(Char Device)
  • 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备。
  • 对字符设备发出读/写请求时,实际的硬件I/O操作一般紧接着发生。
  • 字符设备驱动程序通常至少要实现open、close、read和write系统调用。
  • 比如我们常见的lcd、触摸屏、键盘、led、串口等等,他们一般对应具体的硬件都是进行出具的采集、处理、传输。

2.块设备(Block Device)

  • 一个块设备驱动程序主要通过传输固定大小的数据(一般为512或1k)来访问设备。
  • 块设备通过buffer cache(内存缓冲区)访问,可以随机存取,即:任何块都可以读写,不必考虑它在设备的什么地方。
  • 块设备可以通过它们的设备特殊文件访问,但是更常见的是通过文件系统进行访问。
  • 只有一个块设备可以支持一个安装的文件系统。
  • 比如我们常见的电脑硬盘、SD卡、U盘、光盘等。

3.网络设备(Net Device)

  • 任何网络事务都经过一个网络接口形成,即一个能够和其他主机交换数据的设备。
  • 访问网络接口的方法仍然是给它们分配一个唯一的名字(比如eth0),但这个名字在文件系统中不存在对应的节点。
  • 内核和网络设备驱动程序间的通信,完全不同于内核和字符以及块驱动程序之间的通信,内核调用一套和数据包传输相关的函(socket函数)而不是read、write等。
  • 比如我们常见的网卡设备、蓝牙设备。

驱动程序的功能

  1. 对设备初始化和释放
  2. 把数据从内核传送到硬件和从硬件读取数据
  3. 读取应用程序传送给设备文件的数据和回送应用程序请求的数据
  4. 检测和处理设备出现的错误

四、驱动开发前提知识

4.1 内核态和用户态

  • Kernel Mode(内核态)
  • 内核模式下(执行内核空间的代码),代码具有对硬件的所有控制权限。可以执行所有CPU指令,可以访问任意地址的内存
  • User Mode(用户态)
  • 在用户模式下(执行用户空间的代码),代码没有对硬件的直接控制权限,也不能直接访问地址的内存。
  • 只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址。

Linux利用CPU实现内核态和用户态

  • ARM:内核态(svc模式),用户态(usr模式)
  • x86 : 内核态(ring 0 ),用户态(ring 3)// x86有ring 0 - ring3四种特权等级

Linux实现内核态和用户态切换

  • ARM Linux的系统调用实现原理是采用swi软中断从用户态切换至内核态
  • X86是通过int 0x80中断进入内核态

Linux只能通过系统调用硬件中断从用户空间进入内核空间

  • 执行系统调用的内核代码运行在进程上下文中,他代表调用进程执行操作,因此能够访问进程地址空间的所有数据
  • 处理硬件中断的内核代码运行在中断上下文中,他和进程是异步的,与任何一个特定进程无关通常,一个驱动程序模块中的某些函数作为系统调用的一部分,而其他函数负责中断处理

4.2 Linux下应用程序调用驱动程序流程


8a8809f6c68c40b2a28cde3585d01635.png

Linux下进行驱动开发,完全将驱动程序与应用程序隔开,中间通过C标准库函数以及系统调用完成驱动层和应用层的数据交换。

驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过对“/dev/xxx” (xxx 是具体的驱动文件名字) 的文件进行相应的操作即可实现对硬件的操作。

用户空间不能直接对内核进行操作,因此必须使用一个叫做 “系统调用”的方法 来实现从用户空间“陷入” 到内核空间,这样才能实现对底层驱动的操作

应用程序使用到的函数在具体驱动程序中都有与之对应的函数,比如应用程序中调用了 open 函数,那么在驱动程序中也得有一个名为 open 的函数。

每一个系统调用,在驱动中都有与之对应的一个驱动函数,在 Linux 内核文件 include/linux/fs.h 中有个叫做 file_operations 的结构体,此结构体就是 Linux 内核驱动操作函数集合。

395a4e9d8bcd4544824959a4f08454ab.png

4.3 内核模块

Linux 驱动有两种运行方式

  • 驱动编译进 Linux 内核中,当 Linux 内核启动的时就会自动运行驱动程序。
  • 驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用相应命令加载驱动模块。
  • 内核模块是Linux内核向外部提供的一个插口
  • 内核模块是具有独立功能的程序,他可以被单独编译,但不能单独运行。他在运行时被链接到内核作为内核的一部分在内核空间运行
  • 内核模块便于驱动、文件系统等的二次开发

内核模块组成

  1. 模块加载函数
module_init(xxx_init);


  • module_init 函数用来向 Linux 内核注册一个模块加载函数,
  • 参数 xxx_init 就是需要注册的具体函数(理解是模块的构造函数)
  • 当加载驱动的时, xxx_init 这个函数就会被调用

模块卸载函数

module_exit(xxx_exit);


module_exit函数用来向 Linux 内核注册一个模块卸载函数,

参数 xxx_exit 就是需要注册的具体函数(理解是模块的析构函数)

当使用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用


模块许可证明

MODULE_LICENSE("GPL") //添加模块 LICENSE 信息 ,LICENSE 采用 GPL 协议


  1. 模块参数(可选)
    模块参数是一种内核空间与用户空间的交互方式,只不过是用户空间 --> 内核空间单向的,他对应模块内部的全局变量
  2. 模块信息(可选)
MODULE_AUTHOR("songwei") //添加模块作者信息

模块操作命令

  1. 加载模块
  • insmod XXX.ko
  • 为模块分配内核内存、将模块代码和数据装入内存、通过内核符号表解析模块中的内核引用、调用模块初始化函数(module_init)
  • insmod要加载的模块有依赖模块,且其依赖的模块尚未加载,那么该insmod操作将失败
  • modprobe XXX.ko
  • 加载模块时会同时加载该模块所依赖的其他模块

2.卸载模块

  • rmmod XXX.ko

3.查看模块信息

  • lsmod
  • 查看系统中加载的所有模块及模块间的依赖关系
  • modinfo (模块路径)
  • 查看详细信息,内核模块描述信息,编译系统信息

4.4 设备号

  • Linux 中每个设备都有一个设备号,设备号由主设备号和次设备号两部分组成
  • 主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备。
  • Linux 提供了一个名为 dev_t 的数据类型表示设备号其中高 12 位为主设备号, 低 20 位为次设备
  • 使用"cat /proc/devices"命令即可查看当前系统中所有已经使用了的设备号(主)
MAJOR // 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
MINOR //用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
MKDEV //用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号。



目录
打赏
0
0
0
0
5
分享
相关文章
通义灵码AI程序员实战:从零构建Python记账本应用的开发全解析
本文通过开发Python记账本应用的真实案例,展示通义灵码AI程序员2.0的代码生成能力。从需求分析到功能实现、界面升级及测试覆盖,AI程序员展现了需求转化、技术选型、测试驱动和代码可维护性等核心价值。文中详细解析了如何使用Python标准库和tkinter库实现命令行及图形化界面,并生成单元测试用例,确保应用的稳定性和可维护性。尽管AI工具显著提升开发效率,但用户仍需具备编程基础以进行调试和优化。
159 9
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
45 11
深入解析操作系统控制台:阿里云Alibaba Cloud Linux(Alinux)的运维利器
本文将详细介绍阿里云的Alibaba Cloud Linux操作系统控制台的功能和优势。
90 6
提升开发效率:看板方法的全面解析
随着软件开发复杂度提升,并行开发模式下面临资源分配不均、信息传递延迟及缺乏全局视图等瓶颈问题。看板工具通过任务状态实时可视化、流量效率监控和任务依赖管理,帮助团队直观展示和解决这些瓶颈。未来,结合AI预测和自动化优化,看板工具将更高效地支持并行开发,成为驱动协作与创新的核心支柱。
淘宝APP分类API接口:开发、运用与收益全解析
淘宝APP作为国内领先的购物平台,拥有丰富的商品资源和庞大的用户群体。分类API接口是实现商品分类管理、查询及个性化推荐的关键工具。通过开发和使用该接口,商家可以构建分类树、进行商品查询与搜索、提供个性化推荐,从而提高销售额、增加商品曝光、提升用户体验并降低运营成本。此外,它还能帮助拓展业务范围,满足用户的多样化需求,推动电商业务的发展和创新。
73 5
探索移动应用与系统:从开发到操作系统的深度解析
在数字化时代的浪潮中,移动应用和操作系统成为了我们日常生活的重要组成部分。本文将深入探讨移动应用的开发流程、关键技术和最佳实践,同时分析移动操作系统的核心功能、架构和安全性。通过实际案例和代码示例,我们将揭示如何构建高效、安全且用户友好的移动应用,并理解不同操作系统之间的差异及其对应用开发的影响。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解和知识。
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
移动应用与系统:从开发到优化的全面解析####
本文深入探讨了移动应用开发的全过程,从最初的构思到最终的发布,并详细阐述了移动操作系统对应用性能和用户体验的影响。通过分析当前主流移动操作系统的特性及差异,本文旨在为开发者提供一套全面的开发与优化指南,确保应用在不同平台上均能实现最佳表现。 ####
63 0
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
140 2