threaded irq和irqreturn

irqreturn有以下几种:

 enum irqreturn {
         IRQ_NONE                = (0 << 0),    // 表示中断处理程序未处理该中断,或者没有发生中断
         IRQ_HANDLED             = (1 << 0),    // 表示中断已经被处理
         IRQ_WAKE_THREAD         = (1 << 1),    // 表示中断处理程序通知内核唤醒一个中断线程来处理中断
 };
request_threaded_irq 是 Linux 内核中用于注册中断处理程序的函数之一。它允许在中断处理过程中执行较长时间的操作,而不会阻塞其他重要的内核功能。以下是对
 

request_threaded_irq 函数如下:

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                         irq_handler_t thread_fn, unsigned long irqflags,
                         const char *devname, void *dev_id);

// 参数和返回值说明
unsigned int irq:要注册的中断号。
irq_handler_t handler:中断服务函数,即中断被触发时所调用的函数。这个函数应该返回一个 irqreturn_t 类型的值。
irq_handler_t thread_fn:中断线程服务函数,用于执行较长时间的操作。中断线程服务函数在中断服务函数之后执行。这个函数也应该返回一个 irqreturn_t 类型的值。
unsigned long irqflags:中断标志,控制中断的行为。常用的标志包括 IRQF_SHARED(允许共享中断)、IRQF_TRIGGER_*(中断触发方式,例如上升沿触发、下降沿触发等)等。
const char *devname:设备名称,用于标识中断请求所属的设备。
void *dev_id:设备标识符,将传递给中断服务函数和中断线程服务函数作为参数。
函数返回值为 0 表示注册成功,否则表示注册失败,返回的值是一个负数,表示出错原因。

 

 

request_threaded_irq 函数的工作流程如下:

  1. 检查中断号是否有效,以及指定的中断服务函数和中断线程服务函数是否为有效函数。
  2. 分配中断描述符,并为中断分配中断处理程序和中断线程处理程序。
  3. 将中断处理程序注册到内核,以便在中断被触发时调用。
  4. 将中断线程处理程序注册到内核,以便在中断被触发时调用。
在成功注册中断后,中断被触发时,首先会调用中断服务函数,然后再调用中断线程服务函数。这样可以确保中断服务函数尽快返回,而不会阻塞其他重要的内核功能,而长时间的处理操作可以在中断线程服务函数中执行。
 

request_threaded_irq driver demo:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/kthread.h> // 包含内核线程相关头文件

#define DEMO_IRQ_NUMBER 1

// 定义一个结构体,用于传递给中断处理函数和中断线程处理函数
struct demo_data {
    irq_handler_t irq_handler;
    struct task_struct *thread_task;
};

static irqreturn_t demo_interrupt_handler(int irq, void *dev_id)
{
    struct demo_data *data = (struct demo_data *)dev_id;

    // 处理中断
    printk(KERN_INFO "Demo interrupt handled\n");

    // 如果有中断线程处理函数,则唤醒线程
    if (data->thread_task) {
        wake_up_process(data->thread_task);
    }

    // 返回中断处理结果
    return IRQ_HANDLED;
}

static irqreturn_t demo_threaded_handler(int irq, void *dev_id)
{
    // 处理中断
    printk(KERN_INFO "Demo threaded interrupt handled\n");

    // 返回中断处理结果
    return IRQ_HANDLED;
}

static int demo_thread_fn(void *data)
{
    // 执行长时间的操作,例如复杂计算、文件操作等
    printk(KERN_INFO "Demo threaded handler executing long operation\n");
    msleep(1000); // 模拟长时间操作

    return 0;
}

static int __init demo_init(void)
{
    int ret;
    struct demo_data *data;

    // 分配内存并初始化数据结构
    data = kmalloc(sizeof(struct demo_data), GFP_KERNEL);
    if (!data) {
        printk(KERN_ERR "Failed to allocate memory for demo data\n");
        return -ENOMEM;
    }
    data->irq_handler = demo_interrupt_handler;
    data->thread_task = kthread_create(demo_thread_fn, NULL, "demo_thread_task");
    if (IS_ERR(data->thread_task)) {
        kfree(data);
        printk(KERN_ERR "Failed to create demo thread\n");
        return PTR_ERR(data->thread_task);
    }

    // 注册中断处理程序和中断线程处理程序
    ret = request_threaded_irq(DEMO_IRQ_NUMBER, demo_interrupt_handler, demo_threaded_handler, IRQF_SHARED, "demo_interrupt_threaded", (void *)data);
    if (ret) {
        printk(KERN_ERR "Failed to register threaded interrupt handler\n");
        kfree(data);
        return ret;
    }

    printk(KERN_INFO "Demo module initialized\n");
    return 0;
}

static void __exit demo_exit(void)
{
    struct demo_data *data = (struct demo_data *)free_irq(DEMO_IRQ_NUMBER, (void *)demo_interrupt_handler);

    // 释放中断资源
    if (data) {
        kfree(data);
    }
    printk(KERN_INFO "Demo module exited\n");
}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("lethe1203");
MODULE_DESCRIPTION("request_threaded_irq demo");

 

 
 
 
 
posted @ 2024-04-01 02:03  lethe1203  阅读(42)  评论(0编辑  收藏  举报