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

嵌入式Linux驱动开发:设备树与平台设备驱动

嵌入式Linux驱动开发:设备树与平台设备驱动

引言

本笔记旨在详细记录嵌入式Linux驱动开发中设备树(Device Tree)和平台设备驱动(Platform Driver)的核心概念与实现。通过分析提供的代码与设备树文件,我们将深入理解如何在i.MX6ULL平台上使用设备树来描述硬件,并通过平台设备驱动来管理这些硬件资源。本文档将结合代码实例,详细解释每个关键部分的作用与实现细节。

设备树(Device Tree)

设备树是一种数据结构,用于描述硬件的配置和连接方式,使得操作系统可以在不硬编码硬件信息的情况下初始化和使用硬件。设备树文件通常以.dts为扩展名,编译后生成.dtb文件,由引导加载程序传递给内核。

设备树文件结构

设备树文件由一系列节点(node)和属性(property)组成。每个节点代表一个硬件设备或子系统,属性则描述该设备的具体配置。

根节点

设备树的根节点用/表示,包含全局属性和子节点。

/dts-v1/;
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"/ {model = "Freescale i.MX6 ULL 14x14 EVK Board";compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";...
};
  • model:描述开发板的型号。
  • compatible:指定设备的兼容性,用于匹配驱动程序。
子节点

子节点描述具体的硬件设备,如内存、外设等。

memory {reg = <0x80000000 0x20000000>;
};
  • memory节点描述系统的物理内存布局,reg属性指定内存的起始地址和大小。

设备树源文件(DTSI)

设备树源文件(.dtsi)类似于C语言的头文件,包含多个.dts文件共享的通用定义。通过#include指令引入。

#include "imx6ull.dtsi"

设备树编译

设备树文件需要编译成二进制格式(.dtb),通常使用dtc(Device Tree Compiler)工具完成。

dtc -I dts -O dtb -o imx6ull-alientek-emmc.dtb imx6ull-alientek-emmc.dts

平台设备驱动

平台设备驱动是Linux内核中用于管理平台特定设备的一种机制。它通过设备树描述硬件资源,并在驱动程序中解析这些资源。

平台设备(Platform Device)

平台设备由platform_device结构体表示,包含设备的名称、资源和私有数据。

资源定义

资源定义了设备所需的内存、中断等硬件资源。

static struct resource led_resources[] = {[0] = {.start = CCM_CCGR1_BASE,.end = CCM_CCGR1_BASE + REGISTER_LNE - 1,.flags = IORESOURCE_MEM,},...
};
  • startend:资源的起始和结束地址。
  • flags:资源类型,如IORESOURCE_MEM表示内存资源。
平台设备注册

平台设备通过platform_device_register函数注册到内核。

static struct platform_device leddevice = {.name = "imx6ull-led",.id = -1,.dev = {.release = leddevice_realease,},.num_resources = ARRAY_SIZE(led_resources),.resource = led_resources,
};static int __init leddevice_init(void)
{platform_device_register(&leddevice);return 0;
}

平台驱动(Platform Driver)

平台驱动由platform_driver结构体表示,包含驱动的名称、匹配表、探测和移除函数。

匹配表

匹配表用于将驱动与设备树中的节点关联。

struct of_device_id led_of_match[] = {{.compatible = "alientek,gpioled"},{/* sentinel */}
};
  • compatible:与设备树中节点的compatible属性匹配。
探测函数

探测函数在设备与驱动匹配成功后调用,用于初始化设备。

static int led_probe(struct platform_device *dev)
{gpioled.nd = of_find_node_by_path("/gpioled");if (gpioled.nd == NULL) {printk("gpioled node not find!\r\n");return -EINVAL;}gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpios", 0);if (gpioled.led_gpio < 0) {printk("can't get led-gpio");return -EINVAL;}ret = gpio_direction_output(gpioled.led_gpio, 1);if (ret < 0) {printk("can't set gpio!\r\n");}// 注册字符设备驱动...return 0;
}
  • of_find_node_by_path:根据路径查找设备树节点。
  • of_get_named_gpio:从设备树节点中获取GPIO编号。
  • gpio_direction_output:设置GPIO为输出模式。
移除函数

移除函数在设备卸载时调用,用于释放资源。

static int led_remove(struct platform_device *dev)
{cdev_del(&gpioled.cdev);unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);device_destroy(gpioled.class, gpioled.devid);class_destroy(gpioled.class);return 0;
}

字符设备驱动

字符设备驱动通过file_operations结构体定义设备的操作函数。

static struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};
  • open:打开设备。
  • read:读取设备数据。
  • write:写入设备数据。
  • release:关闭设备。

应用程序

应用程序通过系统调用与驱动程序交互,控制硬件设备。

int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char databuf[1];if (argc != 3) {printf("Error Usage!\r\n");return -1;}filename = argv[1];fd = open(filename, O_RDWR);if (fd < 0) {printf("file %s open failed!\r\n", argv[1]);return -1;}databuf[0] = atoi(argv[2]);retvalue = write(fd, databuf, sizeof(databuf));if (retvalue < 0) {printf("LED Control Failed!\r\n");close(fd);return -1;}close(fd);return 0;
}
  • open:打开设备文件。
  • write:向设备写入数据,控制LED状态。
  • close:关闭设备文件。

参考资料

  • 源码仓库
http://www.dtcms.com/a/357248.html

相关文章:

  • 2023年12月GESP5级C++真题解析,包括选择判断和编程
  • 嵌入式-定时器的输入捕获,超声波获距实验-Day23
  • 如何使用 Vector 连接 Easysearch
  • 【实时Linux实战系列】实时环境监控系统的架构与实现
  • PPT处理控件Aspose.Slides教程:使用 C# 编程将 PPTX 转换为 XML
  • 【实时Linux实战系列】基于实时Linux的虚拟现实应用开发
  • 趣味学Rust基础篇(所有权)
  • 【DeepSeek】公司内网部署离线deepseek+docker+ragflow本地模型实战
  • 《跳出“技术堆砌”陷阱,构建可演进的软件系统》
  • 【PyTorch】神经风格迁移项目
  • 每周资讯 | 《恋与深空》获科隆游戏展2025“最佳移动游戏奖”;8月173个版号下发
  • 【小白笔记】访问GitHub 账户的权限英文单词解释
  • nvm使用和node使用
  • 【前端教程】用 JavaScript 实现4个常用时间与颜色交互功能
  • centos8部署miniconda、nodejs
  • webpack升级
  • 飞牛Nas每天定时加密数据备份到网盘,基于restic的Backrest笔记分享
  • linux和RTOS架构区别
  • 通过 KafkaMQ 接入Skywalking 数据最佳实践
  • JAVA:Spring Boot 集成 Easy Rules 实现规则引擎
  • 滚珠导轨如何赋能精密制造?
  • 【数据分享】省级人工智能发展水平综合指标体系(2011-2022)
  • 安卓开发---BaseAdapter(定制ListView的界面)
  • 基于SpringBoot和Thymeleaf开发的英语学习网站
  • 笔记本电脑频繁出现 vcomp140.dll丢失怎么办?结合移动设备特性,提供适配性强的修复方案
  • C#连接SQL-Server数据库超详细讲解以及防SQL注入
  • LSTM实战:回归 - 实现交通流预测
  • 保护海外服务器免受黑客攻击的方法
  • WebSocket功能完整解析
  • Linux系统——EXT2 文件系统