一、什么是request_threaded_irq
request_threaded_irq是一个Linux内核函数,用于请求指定IRQ(Interrupt Request)并安装处理程序。它可以使设备驱动无需关心硬件IRQ号及中断处理函数,同时避免了中断处理时间过长导致的系统挂起。相比较request_irq函数,request_threaded_irq还增加了线程的支持,可以在一个独立的线程中处理中断。
二、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);
其中,参数的含义如下:
- irq:被请求的中断号
- handler:中断处理函数
- thread_fn:中断线程函数
- irqflags:中断处理标志
- devname:设备名称(不是必须的)
- dev_id:传递给中断处理函数的设备特定指针
三、handler和thread_fn函数
handler是具有如下原型的函数:
irqreturn_t (*irq_handler_t)(int irq, void *dev_id);
它接收两个参数:irq表示发生中断的IRQ号,dev_id是传递给request_threaded_irq函数的设备特定指针。handler函数应该迅速处理中断,然后返回IRQ_HANDLED(中断已处理)或IRQ_NONE(中断未处理)。
thread_fn函数是具有如下原型的函数:
irqreturn_t (*irq_handler_t)(int irq, void *dev_id);
它接收两个参数:irq表示发生中断的IRQ号,dev_id是传递给request_threaded_irq函数的设备特定指针。和handler一样,thread_fn函数应该迅速处理中断,然后返回IRQ_HANDLED(中断已处理)或IRQ_NONE(中断未处理)。线程函数通常用于完成一些占用时间较长的操作,例如接收网络数据等。
四、irqflags参数
irqflags参数用于设置中断处理标志,不同的标志会影响中断处理方式。常见的标志如下:
- IRQF_DISABLED:禁止中断(已弃用)
- IRQF_SAMPLE_RANDOM:用于实时时钟中断(fast path)
- IRQF_TRIGGER_NONE:不处理中断
- IRQF_TRIGGER_RISING:上升沿触发
- IRQF_TRIGGER_FALLING:下降沿触发
- IRQF_TRIGGER_HIGH:高电平触发
- IRQF_TRIGGER_LOW:低电平触发
- IRQF_TRIGGER_MASK:设置中断方式的掩码
- IRQF_ONESHOT:在第一次中断发生后禁用中断(line line)
- IRQF_SHARED:共享中断
- IRQF_PROBE_SHARED:检查中断是否可共享
五、指定设备名称和设备特定指针
request_threaded_irq函数还接收两个其他参数:devname和dev_id(通常设置为驱动程序使用的设备结构)。设备名称作为一个字符串传递,它不是必须的,当IRQ使用的具体硬件设备已知时,建议传递设备名称以便于调试。设备特定指针可以存储指向驱动程序使用的设备结构的指针,用于在中断处理程序中引用。
六、request_threaded_irq函数示例
下面是一个简单的request_threaded_irq函数的示例,它为IRQ 20安装了一个中断处理程序和线程函数:
#include <linux/irq.h> static int irq_number; //IRQ号码 irqreturn_t handler_func(int irq, void *dev_id) //中断处理函数 { printk(KERN_INFO "IRQ %d occurred\n", irq_number); return IRQ_HANDLED; } irqreturn_t thread_func(int irq, void *dev_id) //中断线程函数 { printk(KERN_INFO "IRQ %d thread is running\n", irq_number); return IRQ_HANDLED; } int init_module() { if (request_threaded_irq(irq_number, handler_func, thread_func, IRQF_SHARED, "my_device", NULL) == -EBUSY) { printk(KERN_ERR "Request IRQ %d failed\n", irq_number); return -EBUSY; } else { printk(KERN_INFO "Request IRQ %d succeeded\n", irq_number); return 0; } } void cleanup_module() { free_irq(irq_number, NULL); printk(KERN_INFO "Free IRQ %d succeeded\n", irq_number); }
在此示例中,中断处理函数和线程函数都输出到内核日志中,以便于调试。request_threaded_irq函数的返回值是0表示中断请求成功,-EBUSY表示IRQ已被占用。在模块卸载时,要使用free_irq函数释放IRQ号码。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/242150.html