废话不说了,直接说实现,想必用的人应该能看懂。
以下代码均为控制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 示例效果
[attach]32613[/attach]
二、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 示例效果
[attach]32614[/attach]
三、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 示例效果
[attach]32615[/attach]
欢迎光临 烽火社区 (http://bbs.cnecport.com/) | Powered by Discuz! X3.2 |