直接贴代码了:
虚拟中断控制器代码,chained_virt.c
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/clk.h>
#include<linux/err.h>
#include<linux/init.h>
#include<linux/interrupt.h>
#include<linux/io.h>
#include<linux/irq.h>
#include<linux/irqdomain.h>
#include<linux/of.h>
#include<linux/gpio.h>
#include<linux/platform_device.h>
#include<linux/of_device.h>
#include<linux/irqchip/chained_irq.h>static struct irq_domain *virt_intc_domain;static void virt_intc_irq_ack(struct irq_data *d)
{//ffff800080b68be0, ffff000101d37100, ffff800080717500printk("irq = %d, hwirq = %ld, %px, %px, %px\n", d->irq, d->hwirq, d->chip, d->domain, d->domain->ops);printk("%s %d\n", __FUNCTION__, __LINE__);
}static void virt_intc_irq_mask(struct irq_data *d)
{printk("irq = %d, hwirq = %ld, %px, %px, %px\n", d->irq, d->hwirq, d->chip, d->domain, d->domain->ops);printk("%s %d\n", __FUNCTION__, __LINE__);
}static void virt_intc_irq_mask_ack(struct irq_data *d)
{printk("irq = %d, hwirq = %ld, %px, %px, %px\n", d->irq, d->hwirq, d->chip, d->domain, d->domain->ops);printk("%s %d\n", __FUNCTION__, __LINE__);
}static void virt_intc_unmask(struct irq_data *d)
{//ffff800080b68be0, ffff000101d37100, ffff800080717500printk("irq = %d, hwirq = %ld, %px, %px, %px\n", d->irq, d->hwirq, d->chip, d->domain, d->domain->ops);printk("%s %d\n", __FUNCTION__, __LINE__);
}/*在回调函数里加打印观察调用顺序,理解调用过程*/
static struct irq_chip virt_intc_irq_chip = {.name = "virt_intc",.irq_ack = virt_intc_irq_ack,.irq_mask = virt_intc_irq_mask,.irq_mask_ack = virt_intc_irq_mask_ack,.irq_unmask = virt_intc_unmask,
};/*
为virq(irq_desc)设置irq chip, highlevel irq-events handle和irq chip data*/
static int virt_intc_irq_map(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq)
{irq_set_chip_data(virq, domain->host_data);/*给virq提供处理函数,给irq_chip提供ops处理集,handle_level_irq里会调用request_irq注册的函数()*/irq_set_chip_and_handler(virq, &virt_intc_irq_chip, handle_edge_irq);/* 调用过程如下:handle_level_irq->handle_irq_event->handle_irq_event_percpu->__handle_irq_event_percpu->action->handler(irq, action->dev_id);*///irq_set_nested_thread(virq, 1);//irq_set_noprobe(virq); //domain -> ffff000101d37100printk("%s %d, virq = %d, hwirq = %ld, doamin = %px\n", __FUNCTION__, __LINE__, virq, hwirq, domain);return 0;
}static const struct irq_domain_ops virt_intc_domain_ops = {.xlate = irq_domain_xlate_onecell, //解析设备树,得到硬件中断号和触发类型.map = virt_intc_irq_map, //调用时机。创建或者更新hw_irq和virq关系时(创建irq_domain)
};static u8 virt_intc_get_hwirq(void)
{return get_random_u8() % 0x3;
}static void virt_intc_irq_handler(struct irq_desc *desc) //发生200号中断时对应的15->irq_desc
{int hwirq;struct irq_chip *chip = irq_desc_get_chip(desc);printk("desc = %px, chip = %px\n", desc, chip);//gic mask/ack 200号中断 调用gic的chip提供的回调函数处理chained_irq_enter(chip, desc); //链式处理函数的入口函数//分便是哪一个中断(随机数产生)hwirq = virt_intc_get_hwirq(); //下一级的设备树解析得到的是0,1,2,3//ffff80008070e810printk("%s %d, hwirq = %d, %px\n", __FUNCTION__, __LINE__, hwirq, chip);/*根据gpio hwirq找到对应的virq, 依靠注册的域virt_intc_domain调用其对应的handle_irq(handleC), 这里的handle应该是下一级提供的*/generic_handle_irq(irq_find_mapping(virt_intc_domain, hwirq)); //这里调用的就是virt_intc_irq_map函数里设置的handle_edge_irq//gic unmask 200号中断 调用gic的chip提供的回调函数处理chained_irq_exit(chip, desc); //链式处理函数的退出函数
}static int virt_intc_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;int irq_to_parent;/*上一级是gic, 根据gic里irq_domain的ops解析设备树得到hwirq和type并分配/找到irq_desc得到virq*/irq_to_parent = platform_get_irq(pdev, 0); //上一级是gic所以用gic的irq_domain_ops函数解析printk("irq_to_parent = %d\n", irq_to_parent); //15 hwirq = 200//为irq_desc[irq_to_parent].handle_irq设置回调函数(handleB)irq_set_chained_handler_and_data(irq_to_parent, virt_intc_irq_handler, NULL); //highlevel irq-events handler -> virt_intc_irq_handler#if 0//注册virt_intc_domain时需要irq_base参数,这里先进行分配,返回的是描述符的下标(连续的4个)int irq_base = irq_alloc_descs(-1, 0, 4, numa_node_id());//为virt_intc_domain,irq_base(相当于virq和desc),hwirq(np里面有硬件中断号描述信息)形成映射关系virt_intc_domain = irq_domain_add_legacy(np, 4, irq_base, 0, &virt_intc_domain_ops, NULL); //ffff000101d37100printk("%s %d virt_intc_domain = %px, irq_base = %d\n", __FUNCTION__, __LINE__, virt_intc_domain, irq_base);
#else/*Usage:a. dts:定义使用那个hwirqb. 内核解析设备树时分配irq_des, 得到virqc. (hwirq, virq) =>存入domain下一级使用到interrupt-parent = <&virt_intc>时,使用virt_intc_domain_ops里的xlate函数解析设备树*/virt_intc_domain = irq_domain_add_linear(np, 4, &virt_intc_domain_ops, NULL);
#endifreturn 0;
}static void virt_intc_remove(struct platform_device *pdev)
{printk("%s %d\n", __FUNCTION__, __LINE__);
}static const struct of_device_id virt_intc_of_match[] = {{ .compatible = "virt_intc", },{ },
};static struct platform_driver virt_intc_driver = {.probe = virt_intc_probe,.remove = virt_intc_remove,.driver = {.name = "virt_intc",.of_match_table = of_match_ptr(virt_intc_of_match),}
};static int __init virt_intc_init(void)
{printk("%s %d\n", __FUNCTION__, __LINE__);return platform_driver_register(&virt_intc_driver);
}static void __exit virt_intc_exit(void)
{printk("%s %d\n", __FUNCTION__, __LINE__);platform_driver_unregister(&virt_intc_driver);
}module_init(virt_intc_init);
module_exit(virt_intc_exit);MODULE_AUTHOR("Tan xujia");
MODULE_LICENSE("Dual BSD/GPL");
//devmem 0xf0001218 w 0x00000100
/*
//虚拟中断控制器设备树(链式)
virt_intc:virt_intc {compatible = "virt_intc";interrupt-controller;#interrupt-cells = <2>;interrupt-parent = <&gic>; //intc有irq_domaininterrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; //对应的gic中断号就是200
};产生中断的外设需定义:
1:interrupt-parent
2:interrupts中断控制器需定义:
1:interrupt-controller
2:#interrupt-cells
*//*
对应关系:
irq_desc[15].handle_irq = virt_intc_irq_handler;
irq_desc[15].irq_data.chip = gic_irq_chip;
irq_desc[15].irq_data.domain = gic_domain;
irq_desc[15].irq_data.domain.ops = gic_domain_ops;
irq_desc[15].irq_data.hwirq = 200;
irq_desc[15].irq_data.irq = 15;irq_desc[16].handle_irq = handle_edge_irq;
irq_desc[16].irq_data.chip = virt_intc_irq_chip;
irq_desc[16].irq_data.domain = virt_intc_domain;
irq_desc[16].irq_data.domain.ops = virt_intc_domain_ops;
irq_desc[16].irq_data.hwirq = 0;
irq_desc[16].irq_data.irq = 16;irq_desc[17].handle_irq = handle_edge_irq;
irq_desc[17].irq_data.chip = virt_intc_irq_chip;
irq_desc[17].irq_data.domain = virt_intc_domain;
irq_desc[17].irq_data.domain.ops = virt_intc_domain_ops;
irq_desc[17].irq_data.hwirq = 1;
irq_desc[17].irq_data.irq = 17;irq_desc[18].handle_irq = handle_edge_irq;
irq_desc[18].irq_data.chip = virt_intc_irq_chip;
irq_desc[18].irq_data.domain = virt_intc_domain;
irq_desc[18].irq_data.domain.ops = virt_intc_domain_ops;
irq_desc[18].irq_data.hwirq = 2;
irq_desc[18].irq_data.irq = 18;irq_desc[19].handle_irq = handle_edge_irq;
irq_desc[19].irq_data.chip = virt_intc_irq_chip;
irq_desc[19].irq_data.domain = virt_intc_domain;
irq_desc[19].irq_data.domain.ops = virt_intc_domain_ops;
irq_desc[19].irq_data.hwirq = 3;
irq_desc[19].irq_data.irq = 19;
*/
gpio按键代码:gpio_key.c
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/init.h>
#include<linux/major.h>
#include<linux/irq.h>
#include<linux/interrupt.h>
#include<linux/kernel.h>
#include<linux/of_irq.h>
#include<linux/of_gpio.h>
#include<linux/gpio/consumer.h>
#include<linux/platform_device.h>
#include<linux/slab.h>struct gpio_key {int irq;int cnt;char name[20];
};static struct gpio_key gpio_keys[4];static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{struct gpio_key *g_key = dev_id;printk("%s %d name = %s, cnt = %d\n", __FUNCTION__, __LINE__, g_key->name, g_key->cnt++);return IRQ_HANDLED;
}static int gpio_key_probe(struct platform_device *pdev)
{//struct device_node *node = pdev->dev.of_node;int irq, err, i = 0;while(1) {//根据设备树这里能获取到4个虚拟中断号irq = platform_get_irq(pdev, i); //0-3, i等于4时退出if(irq < 0)break;//将虚拟中断号保存在这里gpio_keys[i].irq = irq;sprintf(gpio_keys[i].name, "gpio_key-%d", i);//注册中断err = devm_request_irq(&pdev->dev, gpio_keys[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpio_keys[i].name, &gpio_keys[i]);printk("err = %d, irq = %d\n", err, irq); /*16-19*/i++;}printk("%s %d\n", __FUNCTION__, __LINE__);return 0;
}static void gpio_key_remove(struct platform_device *pdev)
{printk("%s %d\n", __FUNCTION__, __LINE__);
}static const struct of_device_id gpio_key_of_match[] = {{ .compatible = "gpio_key", },{ },
};static struct platform_driver gpio_key_driver = {.probe = gpio_key_probe,.remove = gpio_key_remove,.driver = {.name = "gpio_key",.of_match_table = of_match_ptr(gpio_key_of_match),}
};static int __init gpio_key_init(void)
{printk("%s %d\n", __FUNCTION__, __LINE__);return platform_driver_register(&gpio_key_driver);
}static void __exit gpio_key_exit(void)
{printk("%s %d\n", __FUNCTION__, __LINE__);platform_driver_unregister(&gpio_key_driver);
}module_init(gpio_key_init);
module_exit(gpio_key_exit);MODULE_AUTHOR("Tan xujia");
MODULE_LICENSE("Dual BSD/GPL");
//虚拟按键设备树(链式和层级)
/*
gpio_keys:gpio_keys {compatible = "gpio_key";interrupt-parent = <&virt_intc>; //virt_intc有irq_domaininterrupts = <0 IRQ_TYPE_LEVEL_HIGH>,<1 IRQ_TYPE_LEVEL_HIGH>,<2 IRQ_TYPE_LEVEL_HIGH>,<3 IRQ_TYPE_LEVEL_HIGH>;
};
*/
参考:https://blog.csdn.net/caiji0169/article/details/143862261