虛擬中斷控制器代碼:
#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>
#include<linux/of_irq.h>static struct irq_domain *virt_intc_domain;
static u32 upper_hwirq_base;static void virt_intc_irq_ack(struct irq_data *d)
{printk("%s %d\n", __FUNCTION__, __LINE__);irq_chip_ack_parent(d);
}static void virt_intc_irq_mask(struct irq_data *d)
{printk("%s %d\n", __FUNCTION__, __LINE__);irq_chip_mask_parent(d);
}static void virt_intc_irq_mask_ack(struct irq_data *d)
{printk("%s %d\n", __FUNCTION__, __LINE__);
}static void virt_intc_unmask(struct irq_data *d)
{printk("%s %d\n", __FUNCTION__, __LINE__);irq_chip_unmask_parent(d);
}static void virt_intc_irq_eoi(struct irq_data *d)
{printk("%s %d\n", __FUNCTION__, __LINE__);irq_chip_eoi_parent(d);
}/*在回調函數里加打印觀察調用順序,理解調用過程*/
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,.irq_eoi = virt_intc_irq_eoi,
};//利用改函數解析設備樹
static int virt_intc_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,unsigned long *out_hwirq, unsigned int *out_type)
{if(is_of_node(fwspec->fwnode)) {if(fwspec->param_count != 2)return -EINVAL;*out_hwirq = fwspec->param[0]; //硬件中斷號*out_type = fwspec->param[1]; //觸發類型printk("param[0] = %d, param[1] = %d\n", fwspec->param[0], fwspec->param[1]);return 0;}return -EINVAL;
}//這個虛擬中斷控制器的alloc函數主要設置irq_domain里的啥?
static int virt_intc_domain_alloc(struct irq_domain *domain, unsigned int virq,unsigned int nr_irqs, void *data)
{struct irq_fwspec *fwspec = data;struct irq_fwspec parent_fwspec;irq_hw_number_t hwirq;int i;//這里的參數domain指的是virt_intc_domainhwirq = fwspec->param[0];printk("virq = %d, hwirq = %ld, nr_irqs = %d, domain = %px\n", virq, hwirq, nr_irqs, domain);for(i = 0; i < nr_irqs; i++)//設置irq_desc[virq].irq_data的相關變量. handle_irq不設置嗎?(不需要)irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &virt_intc_irq_chip, NULL);//virt的domain的父domainparent_fwspec.fwnode = domain->parent->fwnode; //gic中斷信息parent_fwspec.param_count = 3;//描述層級關系是如何對應的parent_fwspec.param[0] = GIC_SPI;parent_fwspec.param[1] = fwspec->param[0] + upper_hwirq_base;parent_fwspec.param[2] = fwspec->param[1];/*1:函數會根據傳入的參數,找到對應的父中斷控制器,并在父中斷控制器中為這些中斷分配irq號2:配置父控制器的irq_desc(包括handle_irq和irq_chip)3:完成中斷鏈路的配置(子控制器中斷能夠通過父控制器進行處理)//調用domain->parent的alloc函數繼續設置*/return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec);
}static const struct irq_domain_ops virt_intc_domain_ops = {.translate = virt_intc_domain_translate, .alloc = virt_intc_domain_alloc,
};static int virt_intc_probe(struct platform_device *pdev)
{struct device_node *parent_node;struct irq_domain *parent_domain;of_property_read_u32(node, "upper_hwirq_base", &upper_hwirq_base);printk("%s %d upper_hwirq_base = %d\n", __FUNCTION__, __LINE__, upper_hwirq_base);parent_node = of_irq_find_parent(pdev->dev.of_node);parent_domain = irq_find_host(parent_node);virt_intc_domain = irq_domain_add_hierarchy(parent_domain, 0, 4, pdev->dev.of_node, &virt_intc_domain_ops, NULL);printk("parent_domain = %px, virt_intc_domain = %px\n", parent_domain, virt_intc_domain);return 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 = "hvirt_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");
/*
//虛擬中斷控制器設備樹(層級)
virt_intc:virt_intc {compatible = "hvirt_intc";interrupt-controller;#interrupt-cells = <2>;interrupt-parent = <&gic>; //intc有irq_domainupper_hwirq_base = <210>;
};參考:gpc.c arch\arm\mach-imx
*/
虛擬按鍵代碼
#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