当前位置: 首页 > news >正文

嵌入式linux内核驱动学习4——LED

一、驱动程序基础概念

驱动程序定义

  • 驱动程序是用于操作硬件的软件程序。
  • 驱动程序使设备能够被操作系统控制和使用。

驱动程序与操作系统的关系

  • 早期程序直接操作硬件,无操作系统参与。
  • 当前任务是将裸机程序整合进操作系统中作为驱动模块
  • 驱动程序属于操作系统内核的一部分,提供设备管理功能

计算机系统结构演变

  • 早期硬件复杂、体积大,软件简单。
  • 集成电路发展使硬件小型化、集成度提高。
  • 现代系统中软件规模和复杂性远超硬件。

二、设备驱动架构与分类

软件层次结构

  • 操作系统软件分为内核、根文件系统和应用层三部分。
  • 内核位于最底层,直接管理硬件资源。
  • Bootloader为一次性程序,启动内核后即退出运行。

设备与驱动对应关系

  • 每个硬件设备需有对应的驱动程序才能工作。
  • 驱动程序与硬件设备为一一对应关系。
  • 数据流向因设备类型而异:LED为控制输出,按键为状态读取,UART为双向通信。

驱动程序接口统一机制

  • Linux系统遵循“一切皆文件”原则。
  • 应用层通过标准文件操作接口(open、read、write、close)访问硬件。
  • 实际操作由内核将文件操作转换为具体驱动函数调用。

设备节点与路径

  • 所有设备在/dev目录下以设备节点形式存在。
  • 设备节点表现为特殊文件,用于用户空间与内核交互。
  • 设备节点名称如ttyUSB0代表具体硬件设备。

三、设备号与设备管理

设备号结构

  • 设备号为32位无符号整数,分为主设备号(高12位)和次设备号(低20位)。
  • 主设备号标识设备类别,次设备号标识同类设备中的具体实例。
  • 设备号用于内核内部唯一标识和管理驱动程序

设备号管理机制

  • 字符设备与块设备的设备号独立管理,允许相同编号存在于不同类型中。(cat /proc/devices 可以查看)
  • 网络设备不使用设备号,而是通过设备名进行管理。
  • 设备号与设备节点名称通过系统维护的映射表关联。

驱动(程序)分类

  • 字符设备驱动:按字节流顺序访问,典型如LED、按键、串口等。(百分之九十多)
  • 块设备驱动:按固定大小的数据块随机访问,典型如磁盘、存储设备。
  • 网络设备驱动:处理网络协议栈,支持复杂数据封装与解析,如网卡、Wi-Fi模块。

四、系统调用与函数注册机制

系统调用流程

  • 用户层调用open、read等函数时,经C库封装后触发系统调用。
  • 系统调用通过SWI指令陷入内核态,切换至SVC模式执行。
  • 不同系统调用由指令后缀数字区分,参数通过寄存器或内存传递。

文件描述符机制

  • open成功后返回文件描述符(如3、4),供后续read/write/close使用。
  • 内核维护进程级文件描述符表,关联设备ID与具体驱动操作函数。
  • read/write等操作基于文件描述符查找对应驱动函数执行。

驱动注册要素

  • 必须实现基本操作函数(open、read、write、release等)。
  • 需向内核注册驱动,使其知晓该驱动存在。
  • 需建立设备号与设备节点名称的映射关系。

五、内核开发环境与工具

内核编程限制

  • 驱动代码运行于内核空间,无法使用标准库头文件(如stdio.h)。
  • 开发依赖内核源码中的头文件,无man手册可用。
  • 函数查阅需通过源码定位声明与定义。

代码导航工具ctags

  • 使用ctags -R生成符号索引文件tags,记录函数、结构体等符号位置。
  • Vim中通过Ctrl+]跳转到符号定义,Ctrl+o返回原位置。
  • 支持跨文件函数追踪,提升内核代码阅读效率。
  • 每个项目目录需独立生成tags文件。

六、模块初始化与编译机制

模块加载与卸载

  • module_init宏标记驱动初始化函数,内核启动时自动执行。
  • module_exit宏标记清理函数,关机或卸载模块时调用。
  • 这两个宏构成驱动模块的入口与出口。

宏展开与链接机制

  • module_init宏最终展开为__initcall函数指针声明。
  • 该指针被放置在特定链接段(.initcall6.init)中。
  • 内核启动时遍历该段所有函数指针并依次执行,完成模块初始化。

数据类型命名规范

  • u32表示32位无符号整数,s16表示16位有符号短整型。
  • 类型命名体现符号性与位宽,便于开发者识别。
  • 此类命名广泛用于内核代码及嵌入式开发中。

七、驱动开发实践准备

结构体与函数定义

  • 使用struct file_operations定义操作函数集合。
  • 该结构体包含open、read、write、release等函数指针成员。
  • 驱动需实现这些函数并将地址赋值给对应指针。

八、驱动程序基础架构

设备号管理

  • 使用主设备号和次设备号组合生成设备号,主设备号通常取255或以下以保持兼容性。
  • 通过MAKEDEV宏将主次设备号合并为完整的设备号。

文件操作接口定义

  • 定义file_operations结构体,包含open、read、write、release等函数指针。
  • 函数参数理解:文件指针、缓冲区、数据长度、偏移量等。

内核打印与浮点运算限制

  • 使用printk进行内核空间打印,用法类似printf。
  • 避免在内核中使用浮点数运算,因老式处理器可能不支持硬件浮点且影响效率。

九、字符设备注册流程

cdev结构体初始化

  • 定义struct cdev结构体作为字符设备的核心数据结构。
  • 包含设备号、操作函数集、引用计数和内核对象等成员。

设备注册接口调用

  • 使用cdev_init初始化cdev结构体,关联file_operations。
  • 通过cdev_add将设备添加到系统,register_chrdev_region注册设备号。

资源清理与注销

  • 在模块卸载时调用unregister_chrdev_region释放设备号。
  • 使用cdev_del删除cdev结构体,确保资源正确释放。

三、应用程序交互与设备节点

设备节点手动创建

  • 使用mknod命令在/dev目录下创建设备节点。
  • 指定设备名称、类型(c表示字符设备)、主设备号和次设备号。

应用程序开发

  • 编写简单应用程序通过open、read、write、close系统调用与驱动交互。
  • 应用程序编译后在开发板上运行验证驱动功能。

根文件系统挂载问题

  • 驱动在内核启动时加载,但/dev目录在根文件系统挂载后才存在。
  • 因此需要手动创建设备节点,无法自动出现在/dev目录中。

十、错误处理与代码优化

返回值检查

  • 对内核API调用返回值进行检查,及时处理错误情况。
  • 错误码如-ENOMEM表示内存不足,-ENODEV表示无此设备等。

goto错误处理模式

  • 采用goto语句集中处理错误退出,避免代码冗余。
  • 按相反顺序撤销已分配的资源,确保正确清理。

代码简洁性考虑

  • goto方式使错误处理代码更紧凑,便于维护和扩展。
  • 尽管会牺牲部分精确错误信息,但提高了整体代码质量。
驱动程序编写完成后
1. 编译生成新的zImage
2. 拷贝zImagetftp服务目录下
3. 重新启动(开发板)内核
4. 在开发板执行 mknod /dev/demo c 255 0 创建一个设备节点
mknod (手动)创建设备节点
/dev/demo 设备节点名
c 字符设备
255 主设备号
0 次设备号
5. 编写并编译应用程序 ----因为开发板的根目录挂载在ubuntunfs下,所以 在ubuntunfs下编译的程序在开发板的根目录下可以直接运行
6. 在开发板端运行应用程序调用驱动接口

十一、硬件控制与地址映射

物理地址访问

  • 用户空间地址为虚拟地址,内核需获取实际物理地址才能操作硬件寄存器。
  • 使用ioremap将物理地址映射到内核可访问的虚拟地址空间。

寄存器操作

  • 定义硬件寄存器的物理地址,通过指针操作实现读写。
  • 包括引脚功能配置、方向设置和数据寄存器操作。

IO重映射管理

  • ioremap用于建立物理地址到虚拟地址的映射。
  • iounmap在模块卸载时解除映射,释放资源。

十二、用户空间数据安全访问

空间隔离原则

  • 内核空间与用户空间应保持隔离,避免直接访问用户数据。
  • 直接访问可能导致安全漏洞或系统崩溃。

安全数据拷贝

  • 使用copy_from_user从用户空间安全拷贝数据到内核空间。
  • 使用copy_to_user将数据从内核空间拷贝到用户空间。

边界检查与长度控制

  • 拷贝长度取用户请求长度和缓冲区大小的较小值,防止越界。
  • 必须检查copy_from_user返回值,处理拷贝失败情况。

十三、驱动模板与最佳实践

模块初始化与退出

  • 使用__init标记初始化函数,加载后可释放其占用的内存。
  • 使用__exit标记退出函数,确保正确清理资源。

static关键字作用

  • 使用static限制函数作用域,避免不同驱动间的命名冲突。
  • 允许多个驱动使用相同的open、read等通用函数名。

驱动开发模板

  • 总结出包含设备号、操作函数集、cdev结构体的标准驱动框架。
  • 大部分字符设备驱动都遵循这一基本结构。
字符设备驱动模板:
dev_t dev; //设备号 由主设备号及次设备号组成
struct file_operations fops; //操作方法, open read write close
struct cdev cdev; //字符设备结构 设备号及操作方法的组合
static int_init demo_init(void) // __init 初始化函数的标识,执行完成后释放非必要的空间
{
MKDEV();
cdev_init();
cdev_add();
register_chrdev_region();
class_create();
device_create();
ioremap();
}
static void_exit demo_exit(void)
{
iounmap();
device_destroy();
class_destroy();
unregister_chrdev_region();
cdev_del();
}
module_init(demo_init); //驱动程序入口 module_init修饰的函数在系统启动时自动执行
module_exit(demo_exit); //驱动程序出口
copy_to_user(); //内核到用户空间
copy_from_user(); //用户到内核空间
http://www.dtcms.com/a/442784.html

相关文章:

  • 建设银行人力资源招聘网站建筑行业教育培训平台
  • 蚌埠网站制作网站开发好找工作吗
  • Spring Boot 整合 MyBatis
  • 【C++实战(70)】C++ 跨平台开发:CMake构建实战指南
  • algorithm <B> data manipulation in huffman algorithm 4/99
  • 三网合一网站建设福建省建设执业资格注册中心网站
  • Rokid JSAR 技术开发全指南+实战演练
  • 昆明做网站哪家便宜计算机网络课程设计
  • 《网页设计与网站建设》A卷答案成都o2o网站建设
  • 建筑工程网官网入口商丘seo教程
  • 求解子网掩码
  • 网站 转成 微信小程序西城上海网站建设
  • 【AI论文】SLA:通过精细可调的稀疏线性注意力机制突破扩散变换器中的稀疏性局限
  • 博客自定义网站服饰 视频 网站建设
  • SSM创新实践学分管理系统08a30(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 太原建设网站制作WordPress手机号验证登录
  • SSM大学教务管理系统61dy9(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 连云港市建设工程安全监督站网站青岛平台网站建设
  • 缓存锁(Cache Lock)是什么?
  • linux建设网站php打开提示404申请一个域名可以建设一个网站吗
  • 人工智能开发工具全景指南:从编码辅助到模型部署的全链路实践
  • 做一个宣传网站要多少钱wordpress 要加上
  • mysql学习
  • 爬坑 10 年!爱回收询价接口实战:从型号匹配、分页续传到数据完整性校验
  • 人工智能领域、图欧科技、IMYAI智能助手2025年9月更新月报
  • 怎么利用网站开发app中海园林建设有限公司网站
  • Python Access:删除数据库中指定的表和查询
  • 苏州设计网页网站珠宝行业做网站的好处
  • 设备管理系统网站模板什么网站比较容易做
  • 动漫人物做羞羞事的网站镇江专业网站制作