- 中断号 Linux 内核中使用一个 int 变量表示中断号
- request_irq 函数
irq:要申请中断的中断号。
handler:中断处理函数,
flags:中断标志,//在文件 include/linux/interrupt.h 里面查看所有的中断标志
上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时间的处理就可以放在上半部完成。
下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。
3、 free_irq 函数
4、中断处理函数
5、设备树中断信息节点
6、获取中断号
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#define IMX6UIRQ_CNT 1 /* 设备号个数 */
#define IMX6UIRQ_NAME "wei_imx6uirq" /* 名字 */
#define KEY0VALUE 0X01 /* KEY0按键值 */
#define INVAKEY 0XFF /* 无效的按键值 */
#define KEY_NUM 1 /* 按键数量 */
/* 中断IO描述结构体 */
struct irq_keydesc {
int gpio; /* gpio */
int irqnum; /* 中断号 */
unsigned char value; /* 按键对应的键值 */
char name; /* 名字 */
irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
};
/* imx6uirq设备结构体 */
struct imx6uirq_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct device_node *nd; /* 设备节点 */
struct timer_list timer;/* 定义一个定时器*/
struct irq_keydesc irqkeydesc; /* 按键描述数组 */
};
struct imx6uirq_dev imx6uirq; /* irq设备 */
void timer_function(unsigned long arg)
{
printk("触发\r\n");
}
static irqreturn_t key0_handler(int irq, void *dev_id)
{
// printk("haha\r\n");
mod_timer(&imx6uirq.timer, jiffies + msecs_to_jiffies(10));
return IRQ_RETVAL(IRQ_HANDLED);
}
static int irq_open(struct inode *inode, struct file *filp)
{
filp->private_data = &imx6uirq;
printk("open\r\n");
return 0;
}
static ssize_t irq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
// int value;
// value=gpio_get_value(imx6uirq.irqkeydesc.gpio);
// copy_to_user(buf, &value, sizeof(value));
//printk("key=%d\r\n",value);
return 0;
}
static ssize_t irq_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue;
unsigned char databuf[1];
unsigned char irqstat;
struct imx6uirq *dev = filp->private_data;
}
static int irq_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* 设备操作函数 */
static struct file_operations irq_fops = {
.owner = THIS_MODULE,
.open = irq_open,
.read = irq_read,
.write = irq_write,
.release = irq_release,
};
/*****************************************************************/
static int irq_remove(struct platform_device *dev)
{
// gpio_free(imx6uirq.irqkeydesc.gpio);
del_timer_sync(&imx6uirq.timer); /* 删除timer */
free_irq(imx6uirq.irqkeydesc.irqnum, &imx6uirq);
cdev_del(&imx6uirq.cdev);/* 删除cdev */
unregister_chrdev_region(imx6uirq.devid, 1); /* 注销设备号 */
device_destroy(imx6uirq.class, imx6uirq.devid);
class_destroy(imx6uirq.class);
return 0;
}
static int irq_probe(struct platform_device *dev)
{
int ret = 0;
imx6uirq.nd = of_find_node_by_path("/key");
if(imx6uirq.nd == NULL) {
printk("imx6uirq node not find!\r\n");
return -EINVAL;
} else {
printk("imx6uirq node find!\r\n");
}
imx6uirq.irqkeydesc.gpio=of_get_named_gpio(imx6uirq.nd,"key-gpio",0);
if(imx6uirq.irqkeydesc.gpio < 0) {
printk("can't get key-gpio");
return -EINVAL;
}
printk("key-gpio num = %d\r\n",imx6uirq.irqkeydesc.gpio);
ret=gpio_direction_input(imx6uirq.irqkeydesc.gpio);
if(ret < 0) {
printk("can't set gpio!\r\n");
}
//中断
//imx6uirq.irqkeydesc.irqnum = irq_of_parse_and_map(imx6uirq.nd,0);
imx6uirq.irqkeydesc.irqnum = gpio_to_irq(imx6uirq.irqkeydesc.gpio);
/* 申请中断 */
imx6uirq.irqkeydesc.handler = key0_handler;//中断处理函数
request_irq(imx6uirq.irqkeydesc.irqnum, imx6uirq.irqkeydesc.handler,
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, imx6uirq.irqkeydesc.name, &imx6uirq);
/*定时器的*/
init_timer(&imx6uirq.timer);
imx6uirq.timer.function = timer_function;
imx6uirq.timer.data = (unsigned long)(&imx6uirq);
// mod_timer(&imx6uirq.timer, jiffies + msecs_to_jiffies(10000));
alloc_chrdev_region(&imx6uirq.devid,0,1,IMX6UIRQ_NAME);
imx6uirq.cdev.owner = THIS_MODULE;
cdev_init(&imx6uirq.cdev,&irq_fops);
//cdev_add(&imx6uirq.cdev,imx6uirq.devid,1);
imx6uirq.class = class_create(THIS_MODULE,IMX6UIRQ_NAME);
imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL,IMX6UIRQ_NAME);
return 0;
}
/* 匹配列表 */
static const struct of_device_id irq_of_match[] = {
{ .compatible = "atkalpha-key" },
{ /* Sentinel */ }
};
/* platform驱动结构体 */
static struct platform_driver irq_driver = {
.driver = {
.name = "wei_dtsplatirq", /* 驱动名字,用于和设备匹配 */
.of_match_table = irq_of_match, /* 设备树匹配表 */
},
.probe = irq_probe,
.remove = irq_remove,
};
static int __init irq_init0(void)
{
return platform_driver_register(&irq_driver);
}
static void __exit irq_exit0(void)
{
platform_driver_unregister(&irq_driver);
}
module_init(irq_init0);
module_exit(irq_exit0);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wei");