TA的每日心情 | 奋斗 2022-9-16 05:52 |
---|
签到天数: 1368 天 连续签到: 1 天 [LV.10]以坛为家III
|
基于前面提到的最精简的框架,中断程序只是多了一个irq注册和响应的代码。
需要增加的函数有:
request_irq //请求注册irq
free_irq //释放请求
和一个自定义的irq响应函数。
当然,为了程序能够真正完成工作,还需要一个阻塞响应机制,以便用户程序能够等到中断的到达。
这里同样使用了最简单的方式,增加的函数:
DECLARE_COMPLETION(MSG); //linux内核定义好的宏,给一个变量名称即可
init_completion(&MSG); //初始化
wait_for_completion(&MSG); //阻塞函数
complete(&MSG); //打断阻塞的函数
下面上代码,对照之前的GPIO框架,可以很清晰地看出区别:- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/wait.h>
- #include <linux/delay.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <linux/interrupt.h>
- #include "../A10.h"
- /**********************************************************************/
- #define KEY_IRQ 28
-
- #define KEY_BACK 17
- #define KEY_HOME 19
- #define KEY_MENU 18
-
- #define KEY_BACK_BIT 0x20000 //(0x1 << 17)
- #define KEY_MENU_BIT 0x40000 //(0x1 << 18)
- #define KEY_HOME_BIT 0x80000 //(0x1 << 19)
-
- #define KEY_DOWN 0
- #define KEY_UP 1
- volatile static unsigned long* REG_PH_CFG2;
- volatile static unsigned long* REG_PH_PULL1;
- volatile static unsigned long* REG_PIO_INT_CFG2;
- volatile static unsigned long* REG_PIO_INT_CTL;
- volatile static unsigned long* REG_PIO_INT_STATUS;
- volatile static unsigned long* REG_PH_DAT;
-
- /*volatile static unsigned long* REG_INTC_IRQ_PEND_REG0;
- volatile static unsigned long* REG_INTC_IRQ_TYPE_SEL0;
- volatile static unsigned long* REG_INTC_EN_REG0;
- volatile static unsigned long* REG_INTC_MASK_REG0;*/
-
- static int Inited = 0;
- DECLARE_COMPLETION(MSG);
- static unsigned char KeyFlag = 0;
- static unsigned char KeyHL = 255;
-
- static irqreturn_t KEY_ISR(int irq, void* dev_id)
- {
- unsigned int State, Data;
- State = *REG_PIO_INT_STATUS;
- *REG_PIO_INT_STATUS |= (KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT); //Clear INT Pending
- mdelay(1);
- *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4)); //Input
- Data = *REG_PH_DAT;
- *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT
- //printk("IRQ State - %u ___ IRQ Data - %u\n", State, Data);
-
- if ((State & KEY_BACK_BIT) == KEY_BACK_BIT )
- {
- KeyFlag = KEY_BACK;
- if ((Data & KEY_BACK_BIT) == KEY_BACK_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
- }
- else
- if ((State & KEY_MENU_BIT) == KEY_MENU_BIT)
- {
- KeyFlag = KEY_MENU;
- if ((Data & KEY_MENU_BIT) == KEY_MENU_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
- }
- else
- if ((State & KEY_HOME_BIT) == KEY_HOME_BIT)
- {
- KeyFlag = KEY_HOME;
- if ((Data & KEY_HOME_BIT) == KEY_HOME_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
- }
-
- if ((KeyFlag != 0) && (KeyHL != 255)) complete(&MSG);
- return IRQ_HANDLED;
- }
- static int KEY_open(struct inode* n, struct file* f)
- {
- int Result = 0;
- Inited++;
- if (Inited > 1)
- {
- return 0;
- }
- REG_PH_CFG2 = (volatile unsigned long*) ioremap(PH_CFG2, 4);
- REG_PH_PULL1 = (volatile unsigned long*) ioremap(PH_PULL1, 4);
- REG_PIO_INT_CFG2 = (volatile unsigned long*) ioremap(PIO_INT_CFG2, 4);
- REG_PIO_INT_CTL= (volatile unsigned long*) ioremap(PIO_INT_CTL, 4);
- REG_PIO_INT_STATUS = (volatile unsigned long*) ioremap(PIO_INT_STATUS, 4);
- REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);
-
- /*REG_INTC_IRQ_PEND_REG0 = (volatile unsigned long*) ioremap(INTC_IRQ_PEND_REG0, 4);
- REG_INTC_IRQ_TYPE_SEL0 = (volatile unsigned long*) ioremap(INTC_IRQ_TYPE_SEL0, 4);
- REG_INTC_EN_REG0 = (volatile unsigned long*) ioremap(INTC_EN_REG0, 4);
- REG_INTC_MASK_REG0 = (volatile unsigned long*) ioremap(INTC_MASK_REG0, 4);*/
-
- *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4));
- *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT
- *REG_PH_PULL1 &= ~((0x3 << 6) + (0x3 << 4) + (0x3 << 2));
- *REG_PH_PULL1 |= ((0x1 << 6) + (0x1 << 4) + (0x1 << 2)); //Pull_UP
- *REG_PIO_INT_CFG2 &= ~((0xF << 12) + (0xF << 8) + (0xF << 4));
- *REG_PIO_INT_CFG2 |= ((0x4 << 12) + (0x4 << 8) + (0x4<< 4)); //Double Edge
- //*REG_PH_DAT |= KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT;
-
- //*REG_INTC_IRQ_TYPE_SEL0 &= ~((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Is IRQ, not FIQ
- //*REG_INTC_EN_REG0 |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT
-
- *REG_PIO_INT_CTL |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT
- Result = request_irq(KEY_IRQ, KEY_ISR, IRQF_DISABLED, "KEY", NULL);
- if (Result != 0)
- {
- //printk("Request IRQ file! ErrorCode: %d\n", Result);
- free_irq(KEY_IRQ, NULL);
- return Result;
- }
- init_completion(&MSG);
- //printk("Open Finished!\n");
- return Result;
- }
- static ssize_t KEY_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
- {
- unsigned char Buf[2];
-
- if (copy_from_user(&Buf, buf, len)) return -1;
- //printk("Write Finished!\n");
- return len;
- }
- static ssize_t KEY_read(struct file* f, char __user* buf, size_t len, loff_t* l)
- {
- unsigned char Buf[2];
- int Len = sizeof(Buf);
- wait_for_completion(&MSG);
- Buf[0] = KeyFlag;
- Buf[1] = KeyHL;
- if (copy_to_user(buf, &Buf, sizeof(Buf))) return 0;
- KeyFlag = 0;
- KeyHL = 255;
-
- //printk("Read Finished!\n");
- return Len;
- }
- static int KEY_close(struct inode* n, struct file* f)
- {
- Inited--;
- if (Inited > 0)
- {
- return 0;
- }
-
- free_irq(KEY_IRQ, NULL);
- //remove_wait_queue(&MSG);
-
- iounmap(REG_PH_CFG2);
- iounmap(REG_PH_PULL1);
- iounmap(REG_PIO_INT_CFG2);
- iounmap(REG_PIO_INT_STATUS);
- iounmap(REG_PH_DAT);
-
- /*iounmap(REG_INTC_IRQ_PEND_REG0);
- iounmap(REG_INTC_IRQ_TYPE_SEL0);
- iounmap(REG_INTC_EN_REG0);
- iounmap(REG_INTC_MASK_REG0);*/
- //printk("Close Finished!\n");
- return 0;
- }
- /**********************************************************************/
- #define DEV_NAME "KEY"
- #define DEV_COUNT 1
- static struct class* pClass;
- int major;
-
- static struct file_operations fops =
- {
- .owner = THIS_MODULE,
- .open = KEY_open,
- .write = KEY_write,
- .read = KEY_read,
- .release = KEY_close,
- };
- static int __init KEY_init(void)
- {
- major = register_chrdev(0, DEV_NAME, &fops);
- pClass = class_create(THIS_MODULE, DEV_NAME);
- if (pClass == NULL)
- {
- unregister_chrdev(major, DEV_NAME);
- return -1;
- }
- device_create(pClass, NULL, MKDEV(major, 0), NULL, DEV_NAME);
- //printk("Init Finished!\n");
- return 0;
- }
- static void __exit KEY_exit(void)
- {
- unregister_chrdev(major, DEV_NAME);
- if (pClass)
- {
- device_destroy(pClass, MKDEV(major, 0));
- class_destroy(pClass);
- }
- //printk("Exit Finished!\n");
- }
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("LiuYang");
- module_init(KEY_init);
- module_exit(KEY_exit);
复制代码 Makefile文件同前,改一下文件名.o即可。
测试程序:- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- int main(int argc, char **argv)
- {
- int f;
- int I;
- int Len;
- unsigned char Buf[2];
-
- f = open("/dev/KEY", O_RDWR);
- printf("File Handle: %d\n", f);
- if (f < 0)
- {
- printf("Open KEY fail!\n");
- return -1;
- }
- for (I = 0; I < 6; I++)
- {
- Len = read(f, &Buf, 2);
- printf("Len: %d -- Key: %d -- HL: %d\n", Len, Buf[0], Buf[1]);
- }
-
- close(f);
- return 0;
- }
复制代码 这样,测试程序在调用了read之后会阻塞在那里,等待驱动程序中中断的达到。每次按下按键后,程序就继续执行了。wait_for_completion有很多种,可以增加超时之类的来完成自己的要求。
顺便说一下,pcDuino已经占用了这个中断,测试的话,在启动后需要先rmmod sw_interrupt,以保证本程序的运行。
|
|