interrupt-controller和interrupt-parent应用举例,要举一个完整的例子,包括设备树,驱动的代码,调用驱动的测试代码

以下是一个完整的例子,演示 interrupt-controller 和 interrupt-parent 的使用,包含设备树、驱动和测试代码:


1. 设备树 (DTS) 示例

/ {
    // 顶级中断控制器 (GIC)
    gic: interrupt-controller@8000000 {
        compatible = "arm,gic-v3";
        reg = <0x0 0x8000000 0x0 0x10000>;
        interrupt-controller;
        #interrupt-cells = <3>;  // 中断号格式: [SPI/PPI, 中断号, 触发方式]
    };

    // 子中断控制器 (GPIO控制器)
    gpio-ic: interrupt-controller@9000000 {
        compatible = "my-company,my-gpio-ic";
        reg = <0x0 0x9000000 0x0 0x1000>;
        interrupt-controller;
        #interrupt-cells = <2>;  // 中断号格式: [中断号, 触发方式]
        interrupt-parent = <&gic>;  // 指向上级控制器GIC
    };

    // 实际设备 (按键)
    button@9010000 {
        compatible = "my-company,my-button";
        reg = <0x0 0x9010000 0x0 0x100>;
        interrupt-parent = <&gpio-ic>;  // 指向GPIO中断控制器
        interrupts = <0 1>;             // 中断号0,触发方式1(假设1=上升沿)
    };
};

2. Linux 驱动代码

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>

static irqreturn_t button_irq_handler(int irq, void *dev_id) {
    printk(KERN_INFO "Button pressed! IRQ %d triggered\n", irq);
    return IRQ_HANDLED;
}

static int my_button_probe(struct platform_device *pdev) {
    struct device_node *np = pdev->dev.of_node;
    int irq_num;
    int ret;

    // 从设备树获取中断号
    irq_num = of_irq_get_byname(np, "button-irq");
    if (irq_num < 0) {
        dev_err(&pdev->dev, "Failed to get IRQ\n");
        return irq_num;
    }

    // 注册中断处理函数
    ret = devm_request_irq(&pdev->dev, irq_num, button_irq_handler,
                           IRQF_TRIGGER_RISING, "button-irq", NULL);
    if (ret) {
        dev_err(&pdev->dev, "Failed to request IRQ %d\n", irq_num);
        return ret;
    }

    printk(KERN_INFO "Button driver initialized, IRQ %d\n", irq_num);
    return 0;
}

static int my_button_remove(struct platform_device *pdev) {
    printk(KERN_INFO "Button driver removed\n");
    return 0;
}

static const struct of_device_id my_button_of_match[] = {
    { .compatible = "my-company,my-button" },
    { /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_button_of_match);

static struct platform_driver my_button_driver = {
    .probe = my_button_probe,
    .remove = my_button_remove,
    .driver = {
        .name = "my-button",
        .of_match_table = my_button_of_match,
    },
};

module_platform_driver(my_button_driver);
MODULE_LICENSE("GPL");

3. 测试代码 (用户空间)

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/poll.h>

int main() {
    int fd;
    char buf[10];
    struct pollfd pfd;

    // 打开设备节点(假设设备节点为 /dev/button0)
    fd = open("/dev/button0", O_RDONLY);
    if (fd < 0) {
        perror("Failed to open device");
        return 1;
    }

    // 使用 poll 等待中断事件
    pfd.fd = fd;
    pfd.events = POLLPRI;  // 优先数据可读(中断触发)

    printf("Waiting for button press...\n");
    while (1) {
        if (poll(&pfd, 1, -1) > 0) {
            lseek(fd, 0, SEEK_SET);  // 重置文件指针
            read(fd, buf, sizeof(buf));
            printf("Interrupt detected!\n");
        }
    }

    close(fd);
    return 0;
}

4. 关键步骤说明

  1. 设备树解析
    • gpio-ic 通过 interrupt-parent 指向 gic,形成中断路由链。
    • button 设备通过 interrupt-parent 指向 gpio-ic,并指定中断号 0 和触发方式 1
  2. 驱动逻辑
    • of_irq_get_byname 从设备树解析中断号。
    • devm_request_irq 注册中断处理函数,触发方式为 IRQF_TRIGGER_RISING(上升沿触发)。
  3. 测试流程
    • 用户程序通过 poll 等待中断事件。
    • 当按键按下时,驱动打印日志,用户程序检测到事件并输出。

5. 验证方法

  1. 编译驱动并加载:

    make -C /lib/modules/$(uname -r)/build M=$PWD modules
    insmod my_button.ko

  2. 编译测试程序:

    gcc test_button.c -o test_button
  3. 运行测试程序:

    ./test_button
  4. 按下硬件按键(或模拟中断),观察 dmesg 输出和测试程序响应。


6. 输出示例

[ 5.123456] Button driver initialized, IRQ 42
[ 6.789012] Button pressed! IRQ 42 triggered

此例子完整展示了从硬件定义到驱动实现的完整流程,通过 interrupt-controller 和 interrupt-parent 构建中断路由,并通过用户程序验证中断触发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值