废话不说了,直接说实现,想必用的人应该能看懂。
以下代码均为控制P8.15引脚,即当该引脚的电平变化时,会触发中断响应函数。在Linux设备驱动程序中,对中断响应函数的实现,主要介绍了3种:直接响应,tasklet机制和workqueue机制。有兴趣的可查看Linux设备驱动第3版的第10章,下面是驱动代码和实现效果,makefile文件可参考上一节(主要修改下名字)。
一、直接响应中断函数
1 驱动代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"
static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
printk(KERN_ALERT"From Kernel P815n");
printk(KERN_ALERT"my_irq_handler workingn");
return IRQ_HANDLED;
}
static int __init mydev_init()
{
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk(KERN_ALERT"p8.15 dirver initn");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
irq = gpio_to_irq (GPIO_PIN_ADDRESS);
retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);//
irq_set_irq_type (irq, IRQF_TRIGGER_RISING);
/* Enable GPIO2 clock */
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
// Enable the IRQ ability for GPIO.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_RISINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit mydev_exit()
{
printk(KERN_ALERT"p8.15 dirver exitn");
free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
gpio_free (GPIO_PIN_ADDRESS);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");
2 示例效果
二、tasklet机制
1 驱动代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"
struct tasklet_struct dlp_tasklet; //定义tasklet结构体
void dlp_func(struct work_struct *work)
{
printk(KERN_ALERT"dlp_tasklet working!n");
}
static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
printk(KERN_ALERT"From Kernel P815n");
tasklet_schedule(&dlp_tasklet);
return IRQ_HANDLED;
}
static int __init mydev_init()
{
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk (KERN_ALERT "p8.15 dirver initn");
/*tasklet*/
tasklet_init(&dlp_tasklet, dlp_func, (unsigned long)123);
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
irq = gpio_to_irq (GPIO_PIN_ADDRESS);
retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);//
irq_set_irq_type (irq, IRQF_TRIGGER_RISING);
/* Enable GPIO2 clock */
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
// Enable the IRQ ability for GPIO.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_RISINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit mydev_exit()
{
printk(KERN_ALERT"p8.15 dirver exitn");
tasklet_kill(&dlp_tasklet);
free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
gpio_free (GPIO_PIN_ADDRESS);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");
2 示例效果
三、workqueue机制
1 驱动代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"
struct workqueue_struct *dlp_wq; //定义工作队列
struct work_struct dlp_work; //定义work结构体
void dlp_func(struct work_struct *work)
{
printk(KERN_ALERT"dlp_work working!n");
}
static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
printk(KERN_ALERT"From Kernel P815n");
queue_work(dlp_wq ,&dlp_work);
return IRQ_HANDLED;
}
static int __init mydev_init()
{
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk (KERN_ALERT "p8.15 dirver initn");
/*work*/
dlp_wq = create_workqueue("dlp");
INIT_WORK(&dlp_work, dlp_func);
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
irq = gpio_to_irq (GPIO_PIN_ADDRESS);
retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);
irq_set_irq_type (irq, IRQF_TRIGGER_RISING);
/**
* Enable GPIO2 clock
*/
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_RISINGDETECT);
iounmap (mem);
return 0;
}
static void __exit mydev_exit()
{
printk(KERN_ALERT"p8.15 dirver exitn");
flush_workqueue(dlp_wq);
destroy_workqueue(dlp_wq);
free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
gpio_free (GPIO_PIN_ADDRESS);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");
2 示例效果
|