本课程将指导您如何在QEMU虚拟环境中为PCI设备或平台设备编写简单的中断处理程序。中断是硬件与操作系统通信的重要机制,掌握中断编程对理解系统底层运作至关重要。
在Linux内核中,中断处理涉及以下关键概念:
以下是一个简单的PCI设备中断处理程序示例:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
// 假设我们的设备使用IRQ 11
#define MY_IRQ 11
// 中断处理函数
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{
// 检查是否真的是我们的设备产生的中断
if (irq != MY_IRQ) {
return IRQ_NONE; // 不是我们的中断,立即返回
}
printk(KERN_INFO "中断已触发! IRQ: %d\n", irq);
// 处理硬件中断...
// 通常包括读取设备状态寄存器、清除中断标志等
return IRQ_HANDLED; // 中断已处理
}
// 设备初始化函数
static int __init my_device_init(void)
{
int ret;
printk(KERN_INFO "初始化PCI设备驱动\n");
// 注册中断处理程序
ret = request_irq(MY_IRQ, my_interrupt_handler,
IRQF_SHARED, "my_pci_device", NULL);
if (ret) {
printk(KERN_ERR "无法注册中断处理程序: %d\n", ret);
return ret;
}
printk(KERN_INFO "中断处理程序注册成功,IRQ: %d\n", MY_IRQ);
return 0;
}
// 设备清理函数
static void __exit my_device_exit(void)
{
// 释放中断处理程序
free_irq(MY_IRQ, NULL);
printk(KERN_INFO "PCI设备驱动已卸载\n");
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("嵌入式系统课");
MODULE_DESCRIPTION("简单的PCI设备中断处理示例");
注意:在实际应用中,您需要根据具体硬件修改IRQ号码和处理逻辑。共享中断需要使用IRQF_SHARED标志,并且需要正确识别中断来源。
对于平台设备,中断处理略有不同:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
static int irq_number;
// 中断处理函数
static irqreturn_t my_platform_interrupt(int irq, void *dev_id)
{
printk(KERN_INFO "平台设备中断已触发! IRQ: %d\n", irq);
// 处理中断...
return IRQ_HANDLED;
}
// 平台设备探测函数
static int my_platform_probe(struct platform_device *pdev)
{
int ret;
// 获取设备树中定义的中断
irq_number = platform_get_irq(pdev, 0);
if (irq_number < 0) {
dev_err(&pdev->dev, "无法获取IRQ号码\n");
return irq_number;
}
// 注册中断处理程序
ret = devm_request_irq(&pdev->dev, irq_number, my_platform_interrupt,
0, "my_platform_device", NULL);
if (ret) {
dev_err(&pdev->dev, "无法注册中断: %d\n", ret);
return ret;
}
dev_info(&pdev->dev, "平台设备中断处理程序注册成功,IRQ: %d\n", irq_number);
return 0;
}
// 平台设备驱动结构
static struct platform_driver my_platform_driver = {
.driver = {
.name = "my_platform_device",
.owner = THIS_MODULE,
},
.probe = my_platform_probe,
};
module_platform_driver(my_platform_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("嵌入式系统课");
MODULE_DESCRIPTION("简单的平台设备中断处理示例");
函数 | 描述 | 参数说明 |
---|---|---|
request_irq() | 注册中断处理程序 | IRQ号码、处理函数、标志、设备名、设备ID |
free_irq() | 释放中断处理程序 | IRQ号码、设备ID |
devm_request_irq() | 设备资源管理版本的中断注册 | 设备指针、IRQ号码、处理函数、标志、设备名、设备ID |
platform_get_irq() | 从平台设备获取IRQ号码 | 平台设备指针、索引号 |
在QEMU环境中测试中断处理程序,可以按照以下步骤:
cat /proc/interrupts
查看中断统计提示:在开发过程中,可以使用printk
输出调试信息,但要注意在生产代码中减少使用,以免影响性能。