在Linux内核驱动开发中,设备树(Device Tree)是一种描述硬件配置的数据结构,它允许内核在不修改代码的情况下支持多种硬件平台。本章将重点介绍如何从设备树节点中解析并获取虚拟的内存地址和中断号,这是驱动开发中的关键步骤。
设备树是一种树形数据结构,用于描述系统中的硬件设备。每个设备在设备树中都有一个节点,节点中包含设备的属性和资源信息。常见的资源包括内存地址和中断号。
在Linux内核驱动中,我们通常使用以下API来从设备树节点中获取资源:
of_iomap()
:用于获取设备的内存地址并映射到虚拟地址空间。irq_of_parse_and_map()
:用于解析设备的中断号。内存地址在设备树中通常通过reg
属性定义。使用of_iomap()
函数可以将物理地址映射到内核的虚拟地址空间,从而允许驱动访问设备寄存器。
#include <linux/of.h>
#include <linux/io.h>
void __iomem *base_addr;
static int my_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
if (!np) {
dev_err(&pdev->dev, "No device tree node found.\n");
return -ENODEV;
}
base_addr = of_iomap(np, 0);
if (!base_addr) {
dev_err(&pdev->dev, "Failed to map memory.\n");
return -ENOMEM;
}
// 现在可以使用 base_addr 访问设备寄存器
return 0;
}
中断号在设备树中通过interrupts
属性定义。使用irq_of_parse_and_map()
函数可以解析并获取中断号。
#include <linux/interrupt.h>
int irq_number;
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{
// 处理中断
return IRQ_HANDLED;
}
static int my_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
if (!np) {
dev_err(&pdev->dev, "No device tree node found.\n");
return -ENODEV;
}
irq_number = irq_of_parse_and_map(np, 0);
if (!irq_number) {
dev_err(&pdev->dev, "Failed to get IRQ number.\n");
return -EINVAL;
}
// 注册中断处理程序
if (request_irq(irq_number, my_interrupt_handler, 0, "my_device", NULL)) {
dev_err(&pdev->dev, "Failed to request IRQ.\n");
return -EIO;
}
return 0;
}
以下是一个简单的设备树节点示例,描述了一个虚拟设备的内存地址和中断信息:
my_device: my_device@1000000 {
compatible = "vendor,my-device";
reg = <0x1000000 0x1000>;
interrupts = <0 25 4>;
};
属性 | 描述 |
---|---|
compatible | 用于匹配驱动的字符串 |
reg | 设备的物理地址和大小 |
interrupts | 中断号、触发类型等 |
通过本章的学习,我们了解了如何从设备树节点中解析并获取虚拟的内存地址和中断号。这些是Linux内核驱动开发中的基本技能,掌握它们对于编写高效、可移植的驱动至关重要。