1.中断基础知识
中断对于学习过微机以及单片机并不陌生,下面就中断的基础知识做一下简单介绍。
中断是指CPU 在执行程序的过程中,出现突发事件去处理,CPU 需要停止当前程序的执行,转去处理突发事件,处理完成之后再返回原程序部分。(相关信息翻阅微机原理等)
2.中断编程流程
linux中的中断在使用前,都需要申请。中断申请函数是“request_irq”,在linux目录中,使用命令”vim inlcude/linux/interrupt.h”:
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
其中函数入口参数:irq是中断号;handler是向系统登记的处理函数;flags是触发标志位;name是中断名称,可以通过注册之后可以通过”cat /proc/interrupts”查看。dev是设备。和上面中断对应的中断函数是free_irq,卸载驱动的时候需要调用。
extern void free_irq(unsigned int, void *);
产生中断之后,会调用中断处理函数irqreturn_t,这个函数也是在头文件”include/linux/interrupt.h”:
extern irqreturn_t no_action(int cpl, void *dev_id);
中断函数类型为irqreturn_t;参数int cpl:中断号;参数void *dev_id:设备。
3.程序清单
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#define IRQ_DEBUG
#ifdef IRQ_DEBUG
#define DPRINTK(x...) printk("IRQ_CTL DEBUG:" x)
#else
#define DPRINTK(x...)
#endif
#define DRIVER_NAME "intrp"
static irqreturn_t eint9_interrupt(int irq, void *dev_id) {
printk("%s(%d)\n", __FUNCTION__, __LINE__);
return IRQ_HANDLED;
}
static irqreturn_t eint10_interrupt(int irq, void *dev_id) {
printk("%s(%d)\n", __FUNCTION__, __LINE__);
return IRQ_HANDLED;
}
static int irq_probe(struct platform_device *pdev)
{
int ret;
char *banner = "intrp Initialize\n";
printk(banner);
ret = gpio_request(EXYNOS4_GPX1(1), "EINT9");
if (ret) {
printk("%s: request GPIO %d for EINT9 failed, ret = %d\n", DRIVER_NAME,
EXYNOS4_GPX1(1), ret);
return ret;
}
s3c_gpio_cfgpin(EXYNOS4_GPX1(1), S3C_GPIO_SFN(0xF));
s3c_gpio_setpull(EXYNOS4_GPX1(1), S3C_GPIO_PULL_UP);
gpio_free(EXYNOS4_GPX1(1));
ret = gpio_request(EXYNOS4_GPX1(2), "EINT10");
if (ret) {
printk("%s: request GPIO %d for EINT10 failed, ret = %d\n", DRIVER_NAME,
EXYNOS4_GPX1(2), ret);
return ret;
}
s3c_gpio_cfgpin(EXYNOS4_GPX1(2), S3C_GPIO_SFN(0xF));
s3c_gpio_setpull(EXYNOS4_GPX1(2), S3C_GPIO_PULL_UP);
gpio_free(EXYNOS4_GPX1(2));
ret = request_irq(IRQ_EINT(9), eint9_interrupt,
IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "eint9", pdev);
if (ret < 0) {
printk("Request IRQ %d failed, %d\n", IRQ_EINT(9), ret);
goto exit;
}
ret = request_irq(IRQ_EINT(10), eint10_interrupt,
IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "eint10", pdev);
if (ret < 0) {
printk("Request IRQ %d failed, %d\n", IRQ_EINT(10), ret);
goto exit;
}
return 0;
exit:
return ret;
}
static int irq_remove (struct platform_device *pdev)
{
free_irq(IRQ_EINT(9),pdev);
free_irq(IRQ_EINT(10),pdev);
return 0;
}
static int irq_suspend (struct platform_device *pdev, pm_message_t state)
{
DPRINTK("irq suspend:power off!\n");
return 0;
}
static int irq_resume (struct platform_device *pdev)
{
DPRINTK("irq resume:power on!\n");
return 0;
}
static struct platform_driver irq_driver = {
.probe = irq_probe,
.remove = irq_remove,
.suspend = irq_suspend,
.resume = irq_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static void __exit intrp_exit(void)
{
platform_driver_unregister(&irq_driver);
}
static int
__init intrp_init(void)
{
return platform_driver_register(&irq_driver);
}
module_init(intrp_init);
module_exit(intrp_exit);
MODULE_LICENSE("Dual BSD/GPL");