printf "\x01\x00\x00\x00" > /dev/qemu-io-intr
gic_poke_irq: mask=0x40000000, offset=0x200 (hwirq=94)
IO-INTR\] Interrupt triggered! (irq=27, count=12, cpu=0)
\[IO-INTR\] Trigger IRQ 27 pending state
/ #
/ #
/ #
/ # cat /proc/interrupts
CPU0
16: 162498 GIC 29 Edge twd
17: 6 GIC 34 Level timer
27: 12 GIC 94 Level qemu-io-intr
29: 0 GIC 47 Level eth0
32: 1065 GIC 41 Level mmci-pl18x (cmd)
33: 40749 GIC 42 Level mmci-pl18x (pio)
34: 8 GIC 44 Level kmi-pl050
35: 100 GIC 45 Level kmi-pl050
36: 241 GIC 37 Level uart-pl011
42: 0 GIC 36 Level rtc-pl031
IPI0: 0 CPU wakeup interrupts
IPI1: 0 Timer broadcast interrupts
IPI2: 0 Rescheduling interrupts
IPI3: 0 Function call interrupts
IPI4: 0 Single function call interrupts
IPI5: 0 CPU stop interrupts
IPI6: 0 IRQ work interrupts
IPI7: 0 completion interrupts
Err: 0
#if 1
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#include \
#define DEV_NAME "qemu-io-intr"
static int dev_major = 241;
#define VIRTUAL_IRQ 27 // 内核虚拟中断号
static int irq_count = 0; // 中断计数
static dev_t devno; // 设备号
static struct cdev cdev; // 字符设备结构体
static struct class \*io_intr_class;
static int test_irq_dev_id = 1; // 中断dev_id(必须和request_irq保持一致)
// 中断处理函数(自动ACK模式:仅计数+日志,内核自动处理ACK)
irqreturn_t io_intr_handler(int irq, void \*dev_id)
{
// 移除手动清除挂起位的代码,由内核自动ACK
irq_count++;
printk(KERN_INFO "\[IO-INTR\] Interrupt triggered! (irq=%d, count=%d, cpu=%d)\\n",
irq, irq_count, raw_smp_processor_id());
// 返回IRQ_HANDLED后,内核会自动完成中断应答和清除
return IRQ_HANDLED;
}
// write函数:仅触发中断,不手动处理ACK
ssize_t io_intr_write(struct file \*filp, const char __user \*buf, size_t len, loff_t \*off)
{
u32 val = 0;
int ret = 0;
if (len \< sizeof(u32)) {
return -EINVAL;
}
ret = copy_from_user(\&val, buf, sizeof(u32));
if (ret) {
return -EFAULT;
}
// 仅触发中断,内核自动处理ACK
if (val == 1) {
irq_set_irqchip_state(VIRTUAL_IRQ, IRQCHIP_STATE_PENDING, true);
printk(KERN_INFO "\[IO-INTR\] Trigger IRQ %d pending state\\n", VIRTUAL_IRQ);
}
return sizeof(u32);
}
// read函数:读取中断计数
ssize_t io_intr_read(struct file \*filp, char __user \*buf, size_t len, loff_t \*off)
{
u32 val = irq_count;
int ret = 0;
if (len \< sizeof(u32)) {
return -EINVAL;
}
ret = copy_to_user(buf, \&val, sizeof(u32));
if (ret) {
return -EFAULT;
}
return sizeof(u32);
}
// 字符设备操作集
static const struct file_operations io_intr_fops = {
.owner = THIS_MODULE,
.write = io_intr_write,
.read = io_intr_read,
.llseek = default_llseek,
};
// platform驱动probe函数(核心:恢复内核自动ACK流程)
static int io_intr_probe(struct platform_device \*pdev)
{
int ret;
// 申请中断:使用内核默认的处理流程(自动ACK)
// 关键:移除IRQF_TRIGGER_RISING,使用Level触发(匹配GIC默认),不手动切换handler
ret = request_irq(VIRTUAL_IRQ, // 中断号27
io_intr_handler, // 中断处理函数
IRQF_TRIGGER_HIGH \| IRQF_NO_SUSPEND, // Level高电平触发(内核自动ACK)
DEV_NAME, // 中断名称
\&test_irq_dev_id); // dev_id(和free_irq保持一致)
if (ret \< 0) {
printk(KERN_ERR "\[IO-INTR\] request_irq failed (ret=%d)\\n", ret);
return ret;
}
// 移除手动切换handler和clear_flags的代码:使用内核默认handler(自动ACK)
// 移除enable_irq:request_irq后内核自动使能中断,避免不平衡警告
printk(KERN_INFO "\[IO-INTR\] Request irq %d success (auto ACK mode)\\n", VIRTUAL_IRQ);
// 字符设备注册流程
if (dev_major) {
devno = MKDEV(dev_major, 0);
ret = register_chrdev_region(devno, 1, DEV_NAME);
} else {
ret = alloc_chrdev_region(\&devno, 0, 1, DEV_NAME);
dev_major = MAJOR(devno); // 动态分配时更新主设备号
}
if (ret \< 0) {
free_irq(VIRTUAL_IRQ, \&test_irq_dev_id); // 传匹配的dev_id
return ret;
}
cdev_init(\&cdev, \&io_intr_fops);
cdev.owner = THIS_MODULE;
ret = cdev_add(\&cdev, devno, 1);
if (ret \< 0) {
unregister_chrdev_region(devno, 1);
free_irq(VIRTUAL_IRQ, \&test_irq_dev_id);
return ret;
}
// 创建设备类和设备节点(自动生成/dev/qemu-io-intr)
io_intr_class = class_create(THIS_MODULE, DEV_NAME);
if (IS_ERR(io_intr_class)) {
ret = PTR_ERR(io_intr_class);
cdev_del(\&cdev);
unregister_chrdev_region(devno, 1);
free_irq(VIRTUAL_IRQ, \&test_irq_dev_id);
return ret;
}
device_create(io_intr_class, NULL, devno, NULL, DEV_NAME);
printk(KERN_INFO "\[IO-INTR\] Probed successfully! (irq=%d, major=%d)\\n",
VIRTUAL_IRQ, dev_major);
return 0;
}
// platform驱动remove函数(修正free_irq传参)
static int io_intr_remove(struct platform_device \*pdev)
{
// 清理设备节点
device_destroy(io_intr_class, devno);
class_destroy(io_intr_class);
cdev_del(\&cdev);
unregister_chrdev_region(devno, 1);
// 关键:free_irq的dev_id必须和request_irq一致(不能传NULL)
free_irq(VIRTUAL_IRQ, \&test_irq_dev_id);
printk(KERN_INFO "\[IO-INTR\] Removed successfully (irq_count=%d)\\n", irq_count);
return 0;
}
// 设备树匹配表
static const struct of_device_id io_intr_of_match\[\] = {
{ .compatible = "qemu,io-intr" },
{ },
};
MODULE_DEVICE_TABLE(of, io_intr_of_match);
// platform驱动结构体
static struct platform_driver io_intr_driver = {
.probe = io_intr_probe,
.remove = io_intr_remove,
.driver = {
.name = DEV_NAME,
.of_match_table = io_intr_of_match,
.owner = THIS_MODULE,
},
};
// 注册platform驱动
module_platform_driver(io_intr_driver);
module_param(dev_major, int, S_IRUGO);
MODULE_PARM_DESC(dev_major, "Major device number for qemu-io-intr (0=dynamic)");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiao dou AI");
#endif